// Sample RFM69 sender/node sketch, with ACK and optional encryption, and Automatic Transmission Control // Sends periodic messages of increasing length to gateway (id=1) // It also looks for an onboard FLASH chip, if present // ********************************************************************************** // Copyright Felix Rusu 2018, http://www.LowPowerLab.com/contact // ********************************************************************************** // License // ********************************************************************************** // This program is free software; you can redistribute it // and/or modify it under the terms of the GNU General // Public License as published by the Free Software // Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will // be useful, but WITHOUT ANY WARRANTY; without even the // implied warranty of MERCHANTABILITY or FITNESS FOR A // PARTICULAR PURPOSE. See the GNU General Public // License for more details. // // Licence can be viewed at // http://www.gnu.org/licenses/gpl-3.0.txt // // Please maintain this license information along with authorship // and copyright notices in any redistribution of this code // ********************************************************************************** #include //get it here: https://www.github.com/lowpowerlab/rfm69 #include //get it here: https://www.github.com/lowpowerlab/rfm69 #include //get it here: https://www.github.com/lowpowerlab/spiflash //********************************************************************************************* //************ IMPORTANT SETTINGS - YOU MUST CHANGE/CONFIGURE TO FIT YOUR HARDWARE ************ //********************************************************************************************* // Address IDs are 10bit, meaning usable ID range is 1..1023 // Address 0 is special (broadcast), messages to address 0 are received by all *listening* nodes (ie. active RX mode) // Gateway ID should be kept at ID=1 for simplicity, although this is not a hard constraint //********************************************************************************************* #define NODEID 2 // keep UNIQUE for each node on same network #define NETWORKID 100 // keep IDENTICAL on all nodes that talk to each other #define GATEWAYID 1 // "central" node //********************************************************************************************* // Frequency should be set to match the radio module hardware tuned frequency, // otherwise if say a "433mhz" module is set to work at 915, it will work but very badly. // Moteinos and RF modules from LowPowerLab are marked with a colored dot to help identify their tuned frequency band, // see this link for details: https://lowpowerlab.com/guide/moteino/transceivers/ // The below examples are predefined "center" frequencies for the radio's tuned "ISM frequency band". // You can always set the frequency anywhere in the "frequency band", ex. the 915mhz ISM band is 902..928mhz. //********************************************************************************************* //#define FREQUENCY RF69_433MHZ //#define FREQUENCY RF69_868MHZ #define FREQUENCY RF69_915MHZ //#define FREQUENCY_EXACT 916000000 // you may define an exact frequency/channel in Hz #define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes! #define IS_RFM69HW_HCW //uncomment only for RFM69HW/HCW! Leave out if you have RFM69W/CW! //********************************************************************************************* //Auto Transmission Control - dials down transmit power to save battery //Usually you do not need to always transmit at max output power //By reducing TX power even a little you save a significant amount of battery power //This setting enables this gateway to work with remote nodes that have ATC enabled to //dial their power down to only the required level (ATC_RSSI) #define ENABLE_ATC //comment out this line to disable AUTO TRANSMISSION CONTROL #define ATC_RSSI -80 //********************************************************************************************* #define SERIAL_BAUD 115200 #if defined (MOTEINO_M0) && defined(SERIAL_PORT_USBVIRTUAL) #define Serial SERIAL_PORT_USBVIRTUAL // Required for Serial on Zero based boards #endif int TRANSMITPERIOD = 200; //transmit a packet to gateway so often (in ms) char payload[] = "123 ABCDEFGHIJKLMNOPQRSTUVWXYZ"; char buff[20]; byte sendSize=0; boolean requestACK = false; SPIFlash flash(SS_FLASHMEM, 0xEF30); //EF30 for 4mbit Windbond chip (W25X40CL) #ifdef ENABLE_ATC RFM69_ATC radio; #else RFM69 radio; #endif void setup() { Serial.begin(SERIAL_BAUD); radio.initialize(FREQUENCY,NODEID,NETWORKID); #ifdef IS_RFM69HW_HCW radio.setHighPower(); //must include this only for RFM69HW/HCW! #endif #ifdef ENCRYPTKEY radio.encrypt(ENCRYPTKEY); #endif #ifdef FREQUENCY_EXACT radio.setFrequency(FREQUENCY_EXACT); //set frequency to some custom frequency #endif //Auto Transmission Control - dials down transmit power to save battery (-100 is the noise floor, -90 is still pretty good) //For indoor nodes that are pretty static and at pretty stable temperatures (like a MotionMote) -90dBm is quite safe //For more variable nodes that can expect to move or experience larger temp drifts a lower margin like -70 to -80 would probably be better //Always test your ATC mote in the edge cases in your own environment to ensure ATC will perform as you expect #ifdef ENABLE_ATC radio.enableAutoPower(ATC_RSSI); #endif char buff[50]; sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); Serial.println(buff); if (flash.initialize()) { Serial.print("SPI Flash Init OK ... UniqueID (MAC): "); flash.readUniqueId(); for (byte i=0;i<8;i++) { Serial.print(flash.UNIQUEID[i], HEX); Serial.print(' '); } Serial.println(); } else Serial.println("SPI Flash MEM not found (is chip soldered?)..."); #ifdef ENABLE_ATC Serial.println("RFM69_ATC Enabled (Auto Transmission Control)\n"); #endif } void Blink(byte PIN, int DELAY_MS) { pinMode(PIN, OUTPUT); digitalWrite(PIN,HIGH); delay(DELAY_MS); digitalWrite(PIN,LOW); } long lastPeriod = 0; void loop() { //process any serial input if (Serial.available() > 0) { char input = Serial.read(); if (input >= 48 && input <= 57) //[0,9] { TRANSMITPERIOD = 100 * (input-48); if (TRANSMITPERIOD == 0) TRANSMITPERIOD = 1000; Serial.print("\nChanging delay to "); Serial.print(TRANSMITPERIOD); Serial.println("ms\n"); } if (input == 'r') //d=dump register values radio.readAllRegs(); //if (input == 'E') //E=enable encryption // radio.encrypt(KEY); //if (input == 'e') //e=disable encryption // radio.encrypt(null); if (input == 'd') //d=dump flash area { Serial.println("Flash content:"); uint16_t counter = 0; Serial.print("0-256: "); while(counter<=256){ Serial.print(flash.readByte(counter++), HEX); Serial.print('.'); } while(flash.busy()); Serial.println(); } if (input == 'e') { Serial.print("Erasing Flash chip ... "); flash.chipErase(); while(flash.busy()); Serial.println("DONE"); } if (input == 'i') { Serial.print("DeviceID: "); word jedecid = flash.readDeviceId(); Serial.println(jedecid, HEX); } } //check for any received packets if (radio.receiveDone()) { Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] "); for (byte i = 0; i < radio.DATALEN; i++) Serial.print((char)radio.DATA[i]); Serial.print(" [RX_RSSI:");Serial.print(radio.RSSI);Serial.print("]"); if (radio.ACKRequested()) { radio.sendACK(); Serial.print(" - ACK sent"); } Blink(LED_BUILTIN,3); Serial.println(); } int currPeriod = millis()/TRANSMITPERIOD; if (currPeriod != lastPeriod) { lastPeriod=currPeriod; //send FLASH id if(sendSize==0) { sprintf(buff, "FLASH_MEM_ID:0x%X", flash.readDeviceId()); byte buffLen=strlen(buff); if (radio.sendWithRetry(GATEWAYID, buff, buffLen)) Serial.print(" ok!"); else Serial.print(" nothing..."); //sendSize = (sendSize + 1) % 31; } else { Serial.print("Sending["); Serial.print(sendSize); Serial.print("]: "); for(byte i = 0; i < sendSize; i++) Serial.print((char)payload[i]); if (radio.sendWithRetry(GATEWAYID, payload, sendSize)) Serial.print(" ok!"); else Serial.print(" nothing..."); } sendSize = (sendSize + 1) % 31; Serial.println(); Blink(LED_BUILTIN,3); } }