├── Gateway └── Gateway.ino ├── README.md ├── SensorNode └── SensorNode.ino ├── SimpleMonitorNode ├── SimpleMonitorNode.ino └── readme.md └── piGateway ├── Gateway.c ├── GatewaydService ├── Makefile ├── SenderReceiver.c ├── networkconfig.h ├── readme.md ├── rfm69.cpp ├── rfm69.h └── rfm69registers.h /Gateway/Gateway.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Based on work from author: Eric Tsai 3 | Gateway ncorporating both the RFM69 and the ethernet part 4 | Revised by Alexandre Bouillot 5 | 6 | License: CC-BY-SA, https://creativecommons.org/licenses/by-sa/2.0/ 7 | Date: 10-23-2014 8 | File: Gateway.ino 9 | This sketch receives RFM wireless data and forwards it to Mosquitto relay 10 | 11 | Modifications Needed: 12 | 1) Update encryption string "ENCRYPTKEY" 13 | 2) Adjust SS - Chip Select - for RFM69 14 | 3) Adjust MQTT server address 15 | */ 16 | 17 | /* 18 | RFM69 Pinout: 19 | MOSI = 11 20 | MISO = 12 21 | SCK = 13 22 | SS = 8 23 | */ 24 | 25 | /* 26 | Ethernet Pinout: 27 | MOSI = 11 28 | MISO = 12 29 | SCK = 13 30 | SS = 10 31 | */ 32 | 33 | //general -------------------------------- 34 | #define SERIAL_BAUD 115200 35 | #if 0 36 | #define DEBUG1(expression) Serial.print(expression) 37 | #define DEBUG2(expression, arg) Serial.print(expression, arg) 38 | #define DEBUGLN1(expression) Serial.println(expression) 39 | #else 40 | #define DEBUG1(expression) 41 | #define DEBUG2(expression, arg) 42 | #define DEBUGLN1(expression) 43 | #endif 44 | //RFM69 ---------------------------------- 45 | #include 46 | #include 47 | #define NODEID 1 //unique for each node on same network 48 | #define NETWORKID 101 //the same on all nodes that talk to each other 49 | #define FREQUENCY RF69_433MHZ 50 | //#define FREQUENCY RF69_868MHZ 51 | //#define FREQUENCY RF69_915MHZ 52 | #define ENCRYPTKEY "xxxxxxxxxxxxxxxx" //exactly the same 16 characters/bytes on all nodes! 53 | #define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! 54 | #define ACK_TIME 30 // max # of ms to wait for an ack 55 | #define RFM69_SS 8 56 | RFM69 radio(RFM69_SS); 57 | bool promiscuousMode = false; //set to 'true' to sniff all packets on the same network 58 | 59 | #include 60 | 61 | //Ethernet 62 | byte mac[] = { 63 | 0x90, 0xA2, 0xDA, 0x0D, 0x11, 0x11 }; 64 | byte server[] = { 65 | 192, 168, 0, 50 }; 66 | 67 | IPAddress ip(192,168,0,61); 68 | EthernetClient ethClient; 69 | #define DHCP_RETRY 500 70 | 71 | // Mosquitto--------------- 72 | #include 73 | PubSubClient client(server, 1883, callback, ethClient); 74 | #define MQTT_CLIENT_ID "arduinoClient" 75 | #define MQTT_RETRY 500 76 | int sendMQTT = 0; 77 | 78 | void MQTTSendInt(PubSubClient* _client, int node, int sensor, int var, int val); 79 | void MQTTSendULong(PubSubClient* _client, int node, int sensor, int var, unsigned long val); 80 | void MQTTSendFloat(PubSubClient* _client, int node, int sensor, int var, float val); 81 | 82 | //use LED for indicating MQTT connection status. 83 | int led = 13; 84 | 85 | typedef struct { 86 | int nodeID; 87 | int sensorID; 88 | unsigned long var1_usl; 89 | float var2_float; 90 | float var3_float; 91 | } 92 | Payload; 93 | Payload theData; 94 | 95 | volatile struct 96 | { 97 | int nodeID; 98 | int sensorID; 99 | unsigned long var1_usl; 100 | float var2_float; 101 | float var3_float; // 102 | int var4_int; 103 | } 104 | SensorNode; 105 | 106 | void setup() 107 | { 108 | Serial.begin(SERIAL_BAUD); 109 | 110 | //Ethernet ------------------------- 111 | //Ethernet.begin(mac, ip); 112 | 113 | //wait for IP address 114 | while (Ethernet.begin(mac) != 1) { 115 | DEBUGLN1("Error getting IP address via DHCP, trying again..."); 116 | delay(DHCP_RETRY); 117 | } 118 | 119 | DEBUGLN1("ethernet OK"); 120 | // print your local IP address: 121 | DEBUGLN1("My IP address: "); 122 | for (byte thisByte = 0; thisByte < 4; thisByte++) { 123 | // print the value of each byte of the IP address: 124 | DEBUG2(Ethernet.localIP()[thisByte], DEC); 125 | DEBUG1("."); 126 | } 127 | DEBUGLN1(); 128 | 129 | // Mosquitto ------------------------------ 130 | while (client.connect(MQTT_CLIENT_ID) != 1) { 131 | DEBUGLN1("Error connecting to MQTT"); 132 | delay(MQTT_RETRY); 133 | } 134 | 135 | //RFM69 --------------------------- 136 | radio.initialize(FREQUENCY,NODEID,NETWORKID); 137 | #ifdef IS_RFM69HW 138 | radio.setHighPower(); //uncomment only for RFM69HW! 139 | #endif 140 | radio.encrypt(ENCRYPTKEY); 141 | radio.promiscuous(promiscuousMode); 142 | char buff[50]; 143 | sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); 144 | DEBUGLN1(buff); 145 | 146 | DEBUGLN1("setup complete"); 147 | } // end of setup 148 | 149 | byte ackCount=0; 150 | long watchdogInterval = 2000; 151 | long watchdog = 0; 152 | 153 | void loop() { 154 | 155 | // calling client.loop too often block the system at some point quite early (~up to 5 loop) 156 | // Here is a temporized call to it on a regular interval 157 | // This need to be as fast as the fastest sensor received 158 | if (millis() > watchdog) { 159 | // Serial.print("loop "); 160 | // Serial.println(millis()); 161 | watchdog += watchdogInterval; 162 | //client.loop needs to run every iteration. Previous version did not. Big opps. 163 | client.loop(); 164 | } 165 | 166 | if (radio.receiveDone()) { 167 | DEBUG1('['); 168 | DEBUG2(radio.SENDERID, DEC); 169 | DEBUG1("] "); 170 | if (promiscuousMode) { 171 | DEBUG1("to ["); 172 | DEBUG2(radio.TARGETID, DEC); 173 | DEBUG1("] "); 174 | } 175 | DEBUGLN1(); 176 | 177 | if (radio.DATALEN != sizeof(Payload)) 178 | Serial.println(F("Invalid payload received, not matching Payload struct!")); 179 | else { 180 | theData = *(Payload*)radio.DATA; //assume radio.DATA actually contains our struct and not something else 181 | 182 | //save it for i2c: 183 | SensorNode.nodeID = theData.nodeID; 184 | SensorNode.sensorID = theData.sensorID; 185 | SensorNode.var1_usl = theData.var1_usl; 186 | SensorNode.var2_float = theData.var2_float; 187 | SensorNode.var3_float = theData.var3_float; 188 | SensorNode.var4_int = radio.RSSI; 189 | 190 | DEBUG1("Received Device ID = "); 191 | DEBUGLN1(SensorNode.sensorID); 192 | DEBUG1 (" Time = "); 193 | DEBUGLN1 (SensorNode.var1_usl); 194 | DEBUG1 (" var2_float "); 195 | DEBUGLN1 (SensorNode.var2_float); 196 | DEBUG1 (" var3_float "); 197 | DEBUGLN1 (SensorNode.var3_float); 198 | DEBUG1 (" RSSI "); 199 | DEBUGLN1 (SensorNode.var4_int); 200 | 201 | sendMQTT = 1; 202 | } 203 | 204 | 205 | if (radio.ACK_REQUESTED) 206 | { 207 | byte theNodeID = radio.SENDERID; 208 | radio.sendACK(); 209 | 210 | // When a node requests an ACK, respond to the ACK 211 | // and also send a packet requesting an ACK (every 3rd one only) 212 | // This way both TX/RX NODE functions are tested on 1 end at the GATEWAY 213 | if (ackCount++%3==0) 214 | { 215 | //Serial.print(" Pinging node "); 216 | //Serial.print(theNodeID); 217 | //Serial.print(" - ACK..."); 218 | //delay(3); //need this when sending right after reception .. ? 219 | //if (radio.sendWithRetry(theNodeID, "ACK TEST", 8, 0)) // 0 = only 1 attempt, no retries 220 | // Serial.print("ok!"); 221 | //else Serial.print("nothing"); 222 | } 223 | }//end if radio.ACK_REQESTED 224 | } //end if radio.receive 225 | 226 | if (sendMQTT == 1) { 227 | DEBUGLN1("starting MQTT send"); 228 | 229 | if (!client.connected()) { 230 | while (client.connect(MQTT_CLIENT_ID) != 1) 231 | { 232 | digitalWrite(led, LOW); 233 | DEBUGLN1("Error connecting to MQTT"); 234 | delay(500); 235 | digitalWrite(led, HIGH); 236 | } 237 | client.publish("outTopic","hello world"); 238 | } 239 | 240 | digitalWrite(led, HIGH); 241 | 242 | int varnum; 243 | char buff_topic[6]; 244 | char buff_message[12]; 245 | 246 | /* 247 | //send var1_usl 248 | varnum = 2; 249 | buff_topic[6]; 250 | buff_message[12]; 251 | sprintf(buff_topic, "%02d%01d%01d", SensorNode.nodeID, SensorNode.sensorID, varnum); 252 | Serial.println(buff_topic); 253 | dtostrf (SensorNode.var1_usl, 10, 1, buff_message); 254 | client.publish(buff_topic, buff_message); 255 | */ 256 | 257 | //send var1_usl 258 | MQTTSendULong(&client, SensorNode.nodeID, SensorNode.sensorID, 1, SensorNode.var1_usl); 259 | 260 | //send var2_float 261 | MQTTSendFloat(&client, SensorNode.nodeID, SensorNode.sensorID, 2, SensorNode.var2_float); 262 | 263 | //send var3_float 264 | MQTTSendFloat(&client, SensorNode.nodeID, SensorNode.sensorID, 3, SensorNode.var3_float); 265 | 266 | //send var4_int, RSSI 267 | MQTTSendInt(&client, SensorNode.nodeID, SensorNode.sensorID, 4, SensorNode.var4_int); 268 | 269 | sendMQTT = 0; 270 | DEBUGLN1("finished MQTT send"); 271 | digitalWrite(led, LOW); 272 | }//end if sendMQTT 273 | }//end loop 274 | 275 | void MQTTSendInt(PubSubClient* _client, int node, int sensor, int var, int val) { 276 | char buff_topic[6]; 277 | char buff_message[7]; 278 | 279 | sprintf(buff_topic, "%02d%01d%01d", node, sensor, var); 280 | sprintf(buff_message, "%04d%", val); 281 | _client->publish(buff_topic, buff_message); 282 | } 283 | 284 | void MQTTSendULong(PubSubClient* _client, int node, int sensor, int var, unsigned long val) { 285 | char buff_topic[6]; 286 | char buff_message[12]; 287 | 288 | sprintf(buff_topic, "%02d%01d%01d", node, sensor, var); 289 | sprintf(buff_message, "%u", val); 290 | _client->publish(buff_topic, buff_message); 291 | } 292 | 293 | void MQTTSendFloat(PubSubClient* _client, int node, int sensor, int var, float val) { 294 | char buff_topic[6]; 295 | char buff_message[12]; 296 | 297 | sprintf(buff_topic, "%02d%01d%01d", node, sensor, var); 298 | dtostrf (val, 2, 1, buff_message); 299 | _client->publish(buff_topic, buff_message); 300 | } 301 | 302 | // Handing of Mosquitto messages 303 | void callback(char* topic, byte* payload, unsigned int length) { 304 | // handle message arrived 305 | DEBUGLN1(F("Mosquitto Callback")); 306 | } 307 | 308 | 309 | 310 | 311 | 312 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | HomeAutomation 2 | ============== 3 | 4 | Home Automation repository 5 | 6 | Work initialy started with the Uber Home Automation Project found on: 7 | http://www.instructables.com/id/Uber-Home-Automation 8 | and various other places on the internet 9 | 10 | The format of the messages has been changed to be more Mosquitto friendly and conssitent in both directions 11 | RFM///up/ message from the node to the gateway 12 | RFM///down/ message from the gateway to the node 13 | 14 | 15 | Two way communication can be performed thru MQTT messages. 16 | 17 | Basic setup for the sample sensorNode on network 101, node 14 18 | Connect RGB pin on pins 8, 6 and 4. 19 | 20 | in the openHab config items file, add: 21 | ``` 22 | Switch LivingLedRedSwitch {mqtt=">[rfmPiMosquitto:RFM/101/14/down/7:command:OFF:0,0,0],>[rfmPiMosquitto:RFM/101/14/down/7:command:ON:0,1,0"} 23 | Switch LivingLedBlueSwitch {mqtt=">[rfmPiMosquitto:RFM/101/14/down/7:command:OFF:0,0,0],>[rfmPiMosquitto:RFM/101/14/down/7:command:ON:1,0,0"} 24 | Switch LivingLedGreenSwitch {mqtt=">[rfmPiMosquitto:RFM/101/14/down/7:command:OFF:0,0,0],>[rfmPiMosquitto:RFM/101/14/down/7:command:ON:0,0,1"} 25 | ``` 26 | 27 | in the appropriate frame section of the config sitemap file, add: 28 | ``` 29 | Frame label="Living temp" { 30 | Frame label="RGB Led" { 31 | Switch item=LivingLedRedSwitch label="Toggle Red Switch" 32 | Switch item=LivingLedBlueSwitch label="Toggle Blue Switch" 33 | Switch item=LivingLedGreenSwitch label="Toggle Green Switch" 34 | } 35 | ``` 36 | 37 | Actionning the switch from openHab web page will trigger the appropriate message to the node. 38 | 39 | For debug, look at the node serial output, where you should see the incoming messages and theirs decoding: 40 | ``` 41 | Received Device ID = 7 42 | Time = 1 43 | var2_float 1.00 44 | var3_float 1.00 45 | ``` 46 | 47 | In the `/var/log/messages` the outgoint messages are logged: 48 | ``` 49 | Jan 14 15:52:20 rfmPi Gatewayd[14115]: -- got message @ RFM/101/14/down/7: (5, QoS 0, !r) '0,1,0' 50 | Jan 14 15:52:20 rfmPi Gatewayd[14115]: Received message for Node ID = 14 Device ID = 7 Time = 0 var2 = 1.000000 var3 = 0.000000 51 | Jan 14 15:52:20 rfmPi Gatewayd[14115]: Message sent to node 14 ACK 52 | ``` 53 | 54 | You can send manualy the message with the command: 55 | ``` 56 | mosquitto_pub -m 1,0,0 -t RFM/101/14/down/7 57 | ``` 58 | -------------------------------------------------------------------------------- /SensorNode/SensorNode.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Author: Alexandre Bouillot 3 | Based on work from: Eric Tsai 4 | License: CC-BY-SA, https://creativecommons.org/licenses/by-sa/2.0/ 5 | Date: 2014/04/13 6 | File: SensorNode.ino 7 | This sketch is for a wired Arduino w/ RFM69 wireless transceiver 8 | Sends sensor data (temp/humidity) back to gateway. 9 | Receive sensor messages from the gateway 10 | */ 11 | 12 | 13 | /* sensor 14 | node = 13 15 | device ID 16 | 2 = 1222 = smoke or not 17 | 3 = 1232 = flame detected or not 18 | 4 = 1242 = human motion present or not 19 | 5 = 1252 = barking or not 20 | 6 = 1262, 1263 = temperature, humidity 21 | 22 | */ 23 | 24 | 25 | 26 | //general -------------------------------- 27 | #define SERIAL_BAUD 115200 28 | #if 1 29 | #define DEBUG1(expression) Serial.print(expression) 30 | #define DEBUG2(expression, arg) Serial.print(expression, arg) 31 | #define DEBUGLN1(expression) Serial.println(expression) 32 | #else 33 | #define DEBUG1(expression) 34 | #define DEBUG2(expression, arg) 35 | #define DEBUGLN1(expression) 36 | #endif 37 | //RFM69 -------------------------------------------------------------------------------------------------- 38 | #include 39 | #include 40 | #define NODEID 13 //unique for each node on same network 41 | #define NETWORKID 101 //the same on all nodes that talk to each other 42 | #define GATEWAYID 1 43 | //Match frequency to the hardware version of the radio on your Moteino (uncomment one): 44 | #define FREQUENCY RF69_433MHZ 45 | //#define FREQUENCY RF69_868MHZ 46 | //#define FREQUENCY RF69_915MHZ 47 | #define ENCRYPTKEY "xxxxxxxxxxxxxxxx" //exactly the same 16 characters/bytes on all nodes! 48 | #define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! 49 | #define ACK_TIME 30 // max # of ms to wait for an ack 50 | #define LED 9 // Moteinos have LEDs on D9 51 | #define SERIAL_BAUD 115200 //must be 9600 for GPS, use whatever if no GPS 52 | 53 | boolean debug = 0; 54 | 55 | //struct for wireless data transmission 56 | typedef struct { 57 | int nodeID; //node ID (1xx, 2xx, 3xx); 1xx = basement, 2xx = main floor, 3xx = outside 58 | int deviceID; //sensor ID (2, 3, 4, 5) 59 | unsigned long var1_usl; //uptime in ms 60 | float var2_float; //sensor data? 61 | float var3_float; //battery condition? 62 | } 63 | Payload; 64 | Payload theData; 65 | 66 | char buff[20]; 67 | byte sendSize=0; 68 | boolean requestACK = false; 69 | RFM69 radio; 70 | 71 | //end RFM69 ------------------------------------------ 72 | 73 | 74 | //temperature / humidity ===================================== 75 | #include 76 | #define DHTPIN 7 // digital pin we're connected to 77 | //#define DHTTYPE DHT11 // DHT 11 (AM2302) blue one 78 | //#define TEMP_INTERVAL 6000 79 | #define TEMP_INTERVAL 3000 80 | #define DHTTYPE DHT22 // DHT 21 (AM2302) white one 81 | //structure holding DHT data 82 | dht DHT; 83 | 84 | 85 | // RGB LED 86 | #define REDPIN 6 87 | #define BLUEPIN 4 88 | #define GREENPIN 8 89 | 90 | // 1 = 1211, 1212 = transmission ack count 91 | // 6 = 1262, 1263 = temperature, humidity 92 | // 7 = 1371, 1372, 1373 PWM for led 93 | 94 | 95 | // timings 96 | unsigned long temperature_time; 97 | 98 | unsigned long frameSent = 0; 99 | unsigned long ackMissed = 0; 100 | unsigned long ackReceived = 0; 101 | boolean statOut; 102 | 103 | // Anarduino led is on pin D9 104 | int led = 9; 105 | 106 | void setup() 107 | { 108 | Serial.begin(SERIAL_BAUD); // setup serial 109 | DEBUG1("starting"); 110 | 111 | //RFM69------------------------------------------- 112 | radio.initialize(FREQUENCY,NODEID,NETWORKID); 113 | #ifdef IS_RFM69HW 114 | radio.setHighPower(); //uncomment only for RFM69HW! 115 | #endif 116 | radio.encrypt(ENCRYPTKEY); 117 | char buff[50]; 118 | sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); 119 | DEBUGLN1(buff); 120 | theData.nodeID = NODEID; //this node id should be the same for all devices in this node 121 | //end RFM-------------------------------------------- 122 | 123 | //initialize times 124 | temperature_time = millis(); 125 | 126 | pinMode(led, OUTPUT); 127 | pinMode(REDPIN, OUTPUT); 128 | pinMode(BLUEPIN, OUTPUT); 129 | pinMode(GREENPIN, OUTPUT); 130 | } 131 | 132 | long blinkInterval = 1000; 133 | long blinkNext = 0; 134 | 135 | void loop() 136 | { 137 | if (millis() > blinkNext) 138 | { 139 | digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level) 140 | delay(100); // wait for a second 141 | digitalWrite(led, LOW); // turn the LED off by making the voltage LOW 142 | blinkNext = millis() + blinkInterval; 143 | } 144 | 145 | //check for any received packets 146 | if (radio.receiveDone()) 147 | { 148 | Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] "); 149 | if (radio.DATALEN == 8) { // ACK TEST 150 | for (byte i = 0; i < radio.DATALEN; i++) 151 | DEBUG1((char)radio.DATA[i]); 152 | } 153 | else if(radio.DATALEN == sizeof(Payload)) { 154 | for (byte i = 0; i < radio.DATALEN; i++) { 155 | DEBUG2((char)radio.DATA[i], HEX); 156 | DEBUG1("."); 157 | } 158 | DEBUGLN1(); 159 | theData = *(Payload*)radio.DATA; //assume radio.DATA actually contains our struct and not something else 160 | 161 | DEBUG1("Received Device ID = "); 162 | DEBUGLN1(theData.deviceID); 163 | DEBUG1 (" Time = "); 164 | DEBUGLN1 (theData.var1_usl); 165 | DEBUG1 (" var2_float "); 166 | DEBUGLN1 (theData.var2_float); 167 | DEBUG1 (" var3_float "); 168 | DEBUGLN1 (theData.var3_float); 169 | 170 | if (theData.deviceID == 7) { 171 | digitalWrite(BLUEPIN, theData.var1_usl == 0 ? LOW : HIGH); 172 | digitalWrite(REDPIN, theData.var2_float == 0 ? LOW : HIGH); 173 | digitalWrite(GREENPIN, theData.var3_float == 0 ? LOW : HIGH); 174 | } 175 | } 176 | else { 177 | Serial.print("Invalid data "); 178 | for (byte i = 0; i < radio.DATALEN; i++) { 179 | DEBUG2((char)radio.DATA[i], HEX); 180 | DEBUG1("."); 181 | } 182 | } 183 | 184 | DEBUG1(" [RX_RSSI:");DEBUG1(radio.RSSI);DEBUG1("]"); 185 | 186 | if (radio.ACKRequested()) 187 | { 188 | radio.sendACK(); 189 | DEBUG1(" - ACK sent"); 190 | } 191 | DEBUGLN1(); 192 | } 193 | 194 | if (frameSent%20 == 0) { 195 | //send data 196 | theData.deviceID = 1; 197 | theData.var1_usl = millis(); 198 | theData.var2_float = frameSent; 199 | theData.var3_float = ackMissed; 200 | frameSent++; 201 | if (radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData))) { 202 | ackReceived++; 203 | DEBUGLN1("ACK received"); 204 | } else { 205 | ackMissed++; 206 | } 207 | } 208 | 209 | if (frameSent%10 == 0) { 210 | if (statOut == 0) { 211 | statOut = 1; 212 | DEBUG1("Frames "); 213 | DEBUG1(frameSent); 214 | DEBUG1(" missed: "); 215 | DEBUG1(ackMissed); 216 | DEBUG1(" ACKnowledge: "); 217 | DEBUG1(ackReceived); 218 | } 219 | } else { statOut = 0; } 220 | 221 | unsigned long time_passed = 0; 222 | 223 | //=================================================================== 224 | //device #6 225 | //temperature / humidity 226 | time_passed = millis() - temperature_time; 227 | if (time_passed < 0) { 228 | temperature_time = millis(); 229 | } 230 | 231 | if (time_passed > TEMP_INTERVAL) { 232 | int chk = DHT.read21(DHTPIN); 233 | 234 | switch (chk) 235 | { 236 | case DHTLIB_OK: 237 | DEBUG1("OK,\t"); 238 | break; 239 | case DHTLIB_ERROR_CHECKSUM: 240 | DEBUG1("Checksum error,\t"); 241 | break; 242 | case DHTLIB_ERROR_TIMEOUT: 243 | DEBUG1("Time out error,\t"); 244 | break; 245 | case DHTLIB_ERROR_CONNECT: 246 | Serial.print("Connect error,\t"); 247 | break; 248 | case DHTLIB_ERROR_ACK_L: 249 | DEBUG1("Ack Low error,\t"); 250 | break; 251 | case DHTLIB_ERROR_ACK_H: 252 | DEBUG1("Ack High error,\t"); 253 | break; 254 | default: 255 | DEBUG1("Unknown error,\t"); 256 | break; 257 | } 258 | 259 | double h = DHT.humidity; 260 | // Read temperature as Celsius 261 | double t = DHT.temperature; 262 | 263 | DEBUG1("Humidity="); 264 | DEBUG1(h); 265 | DEBUG1(" Temp="); 266 | DEBUG1(t); 267 | DEBUG1("°C"); 268 | temperature_time = millis(); 269 | 270 | //send data 271 | theData.deviceID = 6; 272 | theData.var1_usl = millis(); 273 | theData.var2_float = t; 274 | theData.var3_float = h; 275 | frameSent++; 276 | if (radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData))) { 277 | ackReceived++; 278 | DEBUGLN1(" ACK received"); 279 | } else { 280 | ackMissed++; 281 | } 282 | delay(100); 283 | } 284 | }//end loop 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | -------------------------------------------------------------------------------- /SimpleMonitorNode/SimpleMonitorNode.ino: -------------------------------------------------------------------------------- 1 | // Simple Sensor node framework 2 | // Minimize power consumption to run on battery 3 | // copyright 2016 Alexandre Bouillot - FLTM @abouillot 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | // RTC 10 | #include 11 | #include 12 | #include 13 | 14 | // Flash memory 15 | #include 16 | #include //get it here: https://www.github.com/lowpowerlab/spiflash 17 | 18 | // Radio 19 | #include // get it here https://www.github.com/lowpowerlab/rfm69 20 | 21 | // FOTA 22 | //#include //get it here: https://github.com/LowPowerLab/WirelessProgramming/tree/master/WirelessHEX69 23 | 24 | // DHT - temperature sensor 25 | #include //get it here: http://arduino.cc/playground/Main/DHTLib 26 | 27 | 28 | 29 | //general -------------------------------- 30 | #define SERIAL_BAUD 115200 31 | #if 1 32 | #define DEBUGSTART() Serial.begin(SERIAL_BAUD) 33 | #define DEBUGSTOP() Serial.end() 34 | #define DEBUGFLUSH() Serial.flush(); 35 | #define DEBUG1(expression) Serial.print(expression) 36 | #define DEBUG2(expression, arg) Serial.print(expression, arg) 37 | #define DEBUGLN1(expression) Serial.println(expression) 38 | #else 39 | #define DEBUGSTART() 40 | #define DEBUGSTOP() 41 | #define DEBUGFLUSH() Serial.flush(); 42 | #define DEBUG1(expression) 43 | #define DEBUG2(expression, arg) 44 | #define DEBUGLN1(expression) 45 | #endif 46 | 47 | #define ONESECOND (1000L) 48 | #define FIVESECONDS (ONESECOND * 5) 49 | #define FIFTEENSECONDS (ONESECOND * 15) 50 | #define THIRTYSECONDS (ONESECOND * 30) 51 | #define HALFMINUTE (ONESECOND * 30) 52 | #define ONEMINUTE (ONESECOND * 60) 53 | #define TWOMINUTES (ONEMINUTE * 2) 54 | #define FIVEMINUTES (ONEMINUTE * 5) 55 | #define TENMINUTES (ONEMINUTE * 10) 56 | 57 | #define FOREVER 0xFFFFFFFF 58 | 59 | // RFM69 60 | #define NODEID 20 //unique for each node on same network 61 | #define NETWORKID 101 //the same on all nodes that talk to each other 62 | #define GATEWAYID 1 63 | //Match frequency to the hardware version of the radio on your Moteino (uncomment one): 64 | #define FREQUENCY RF69_433MHZ 65 | //#define FREQUENCY RF69_868MHZ 66 | //#define FREQUENCY RF69_915MHZ 67 | #define ENCRYPTKEY "xxxxxxxxxxxxxxxx" //exactly the same 16 characters/bytes on all nodes! 68 | #define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W! 69 | //#define RFM_INT 2 //RTC Interrupt connected on pin D2 (INT0) 70 | //#define DEVICE_CLASS_A // Device wil lsend data and then put radio to sleep 71 | #define DEVICE_CLASS_B // Device will send data and then wait CLASS_B_DELAY second before putting rasio to sleep 72 | //#define DEVICE_CLASS_C // Device will keep it radio on all the tile 73 | #define CLASS_B_DELAY FIVESECONDS 74 | 75 | //struct for wireless data transmission 76 | typedef struct { 77 | int nodeID; //node ID (1xx, 2xx, 3xx); 1xx = basement, 2xx = main floor, 3xx = outside 78 | int deviceID; //sensor ID (2, 3, 4, 5) 79 | unsigned long var1_usl; //uptime in ms 80 | float var2_float; //sensor data? 81 | float var3_float; //battery condition? 82 | } 83 | Payload; 84 | Payload theData; 85 | 86 | char buff[20]; 87 | byte sendSize = 0; 88 | boolean requestACK = false; 89 | RFM69 radio; 90 | //end RFM69 ------------------------------------------ 91 | 92 | // RTC 93 | MCP7940RTC *pRTC; 94 | #define RTC_INT 3 //RTC Interrupt connected on pin D3 (INT1) 95 | 96 | // SPI flash 97 | // Anarduino: Flash SPI_CS = 5, ID = 0x.... (Winbond 4Mbit flash) 98 | // SPIFlash flash(5, 0x0120); // flash(SPI_CS, MANUFACTURER_ID) 99 | SPIFlash flash(5); // Flash memory CS on pin 5 100 | 101 | //LED 102 | #define LED 9 // Pin 9 on Anarduino 103 | 104 | //http://interface.khm.de/index.php/lab/interfaces-advanced/sleep_watchdog_battery/ 105 | 106 | 107 | /// Low-power utility code using the Watchdog Timer (WDT). Requires a WDT 108 | /// interrupt handler, e.g. EMPTY_INTERRUPT(WDT_vect); 109 | class Sleepy { 110 | public: 111 | /// start the watchdog timer (or disable it if mode < 0) 112 | /// @param mode Enable watchdog trigger after "16 << mode" milliseconds 113 | /// (mode 0..9), or disable it (mode < 0). 114 | /// @note If you use this function, you MUST included a definition of a WDT 115 | /// interrupt handler in your code. The simplest is to include this line: 116 | /// 117 | /// ISR(WDT_vect) { Sleepy::watchdogEvent(); } 118 | /// 119 | /// This will get called when the watchdog fires. 120 | static void watchdogInterrupts (char mode); 121 | 122 | /// enter low-power mode, wake up with watchdog, INT0/1, or pin-change 123 | static void powerDown (); 124 | 125 | /// Spend some time in low-power mode, the timing is only approximate. 126 | /// @param msecs Number of milliseconds to sleep, in range 0..65535. 127 | /// @returns 1 if all went normally, or 0 if some other interrupt occurred 128 | /// @note If you use this function, you MUST included a definition of a WDT 129 | /// interrupt handler in your code. The simplest is to include this line: 130 | /// 131 | /// ISR(WDT_vect) { Sleepy::watchdogEvent(); } 132 | /// 133 | /// This will get called when the watchdog fires. 134 | static byte loseSomeTime (word msecs); 135 | 136 | /// This must be called from your watchdog interrupt code. 137 | static void watchdogEvent(); 138 | }; 139 | 140 | // Interupt routine called by watchdog 141 | ISR(WDT_vect) { 142 | Sleepy::watchdogEvent(); 143 | } 144 | 145 | 146 | static volatile byte watchdogCounter; 147 | 148 | void Sleepy::watchdogEvent() { 149 | ++watchdogCounter; 150 | } 151 | // chk 152 | void Sleepy::watchdogInterrupts (char mode) { 153 | /* In order to change WDE or the prescaler, we need to 154 | * set WDCE (This will allow updates for 4 clock cycles). 155 | */ 156 | word wdp = mode; 157 | // correct for the fact that WDP3 is *not* in bit position 3! 158 | if (wdp & bit(3)) 159 | wdp ^= bit(3) | bit(WDP3); 160 | // Serial.print("wdp ");Serial.print(wdp, BIN); Serial.print(" mode ");Serial.print(mode,BIN); Serial.println(); Serial.flush(); 161 | // if mode == -1, set WDT in reset mode, otherwise, clear the RESET and enable the interrupt 162 | byte wdtcsr = wdp >= 0 ? bit(WDIE) | wdp : 0; 163 | 164 | // Clear the Watchdog Reset flag 165 | MCUSR &= ~(1 << WDRF); 166 | 167 | // Ensure the following cannot be interrupted by other int 168 | ATOMIC_BLOCK(ATOMIC_FORCEON) { 169 | #ifndef WDTCSR // This is probably a XXX chip, where this doesn't exist under this name 170 | #define WDTCSR WDTCR // substitute the right namr 171 | #endif 172 | WDTCSR |= (1 << WDCE) | (1 << WDE); // timed sequence 173 | // Set the new watchdog timeout prescaler value 174 | WDTCSR = wdtcsr; 175 | } 176 | } 177 | 178 | /// @see http://www.nongnu.org/avr-libc/user-manual/group__avr__sleep.html 179 | void Sleepy::powerDown () { 180 | DEBUGFLUSH(); 181 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); 182 | /* 318 µA */ 183 | 184 | noInterrupts(); 185 | sleep_enable(); 186 | 187 | // turn off brown-out enable in software // save ~25 µA 188 | MCUCR = bit (BODS) | bit (BODSE); // turn on brown-out enable select 189 | MCUCR = bit (BODS); // this must be done within 4 clock cycles of above 190 | interrupts (); // guarantees next instruction executed 191 | 192 | sleep_cpu (); // sleep within 3 clock cycles of above 193 | 194 | /* The program will continue from here after the WDT timeout*/ 195 | sleep_disable(); /* First thing to do is disable sleep. */ 196 | 197 | /* Re-enable the peripherals. */ 198 | power_all_enable(); 199 | } 200 | 201 | // chk 202 | byte Sleepy::loseSomeTime (word msecs) { 203 | byte ok = 1; 204 | // msleft is updated thru the loop to keep track of ms required under 'deep sleep' 205 | // initialy, this is equal to the time requested 206 | word msleft = msecs; 207 | 208 | // only slow down for periods longer than the watchdog granularity 209 | while (msleft >= 16) { 210 | char wdp = 0; // wdp 0..9 corresponds to roughly 16..8192 ms 211 | // calc wdp as log2(msleft/16), i.e. loop & inc while next value is ok 212 | for (word m = msleft; m >= 32; m >>= 1) { 213 | // limit is the factor 9 (~8s) 214 | if (++wdp >= 9) 215 | break; 216 | } 217 | 218 | // reset the counter, so we will know if we exit thru the watchdog, or thru other means 219 | watchdogCounter = 0; 220 | 221 | // Prepare the watchdog registers 222 | watchdogInterrupts(wdp); 223 | 224 | // sleep for good 225 | powerDown(); 226 | 227 | // Stop the watchdog interrupts 228 | watchdogInterrupts(-1); // off 229 | 230 | // watchdogCounter hasn't been set by the watchdog interrupt - other mean has been used for waking up 231 | if (watchdogCounter == 0) { 232 | // when interrupted, our best guess is that half the time has passed 233 | msleft -= 8 << wdp; 234 | ok = 0; // lost some time, but got interrupted 235 | break; 236 | } 237 | else { 238 | msleft -= 0x10 << wdp; 239 | } 240 | } 241 | 242 | // adjust the milli ticks, since we will have missed several 243 | #if defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny85__) || defined (__AVR_ATtiny44__) || defined (__AVR_ATtiny45__) 244 | extern volatile unsigned long millis_timer_millis; 245 | millis_timer_millis += msecs - msleft; 246 | #else 247 | extern volatile unsigned long timer0_millis; 248 | timer0_millis += msecs - msleft; 249 | #endif 250 | return ok; 251 | } 252 | 253 | 254 | class Active { 255 | public: 256 | virtual unsigned long Run() = 0; 257 | 258 | protected: 259 | typedef enum { 260 | Uninitialized = -1, Init, Standby, PowerOn, Stabilize, Read, Transmit, PowerOff, LastCoreState 261 | } 262 | ActiveState; 263 | ActiveState State; 264 | unsigned long NextTime; 265 | }; 266 | 267 | class RadioActive : 268 | public Active { 269 | public: 270 | void SendData(const uint8_t node, const void *data, const uint8_t length); 271 | int ReceiveData(); 272 | unsigned long Run(); 273 | 274 | private: 275 | boolean active; 276 | }; 277 | 278 | class Led : 279 | public Active { 280 | public: 281 | void RequestBlink(int blinkRequested); 282 | unsigned long Run(); 283 | 284 | private: 285 | int remainingBlink; 286 | static const int blinkPeriod = 16; // set to a full cycle of power off 287 | }; 288 | 289 | class DHT : 290 | public Active { 291 | public: 292 | unsigned long Run(); 293 | private: 294 | #define DHTTYPE DHT22 // DHT 22 (AM2302) white one 295 | #define TEMP_READ_DELAY ONEMINUTE 296 | #define TEMP_STABILIZE_DELAY ONESECOND 297 | #define DHTPIN 7 // digital pin we're connected to 298 | #define DHTPOWERPIN 8 // Pin powering DHT Sensor 299 | dht DHT; 300 | 301 | double h; 302 | double t; 303 | int chk; 304 | }; 305 | 306 | class Battery : 307 | public Active { 308 | public: 309 | unsigned long Run(); 310 | private: 311 | #define BATT_READ_DELAY FIVEMINUTES 312 | #define BATTPIN A0 // digital pin we're connected to 313 | float volts; 314 | }; 315 | 316 | 317 | Led led; 318 | DHT dht; 319 | Battery battery; 320 | RadioActive radioSend; 321 | 322 | 323 | ///////////////////////////// 324 | // RadioActive 325 | ///////////////////////////// 326 | void RadioActive::SendData(const uint8_t node, const void* data, const uint8_t length) { 327 | DEBUG1("Send Data "); 328 | DEBUG1(node); 329 | DEBUG1(" "); 330 | DEBUG1(length); 331 | int i; 332 | unsigned char *p = (unsigned char *)data; 333 | if (radio.sendWithRetry(node, (const void*)(data), length/*, 2, 100*/)) { 334 | // ackReceived++; 335 | DEBUGLN1(" ACK received"); 336 | } 337 | else { 338 | // ackMissed++; 339 | DEBUGLN1(" ACK missed"); 340 | } 341 | radio.receiveDone(); 342 | State = Transmit; 343 | 344 | #if defined (DEVICE_CLASS_A) 345 | NextTime = millis(); 346 | #elif defined (DEVICE_CLASS_B) 347 | NextTime = millis() + CLASS_B_DELAY; 348 | #elif defined (DEVICE_CLASS_C) 349 | NextTime = FOREVER; 350 | #else 351 | #error "No radio Class Defined" 352 | #endif 353 | led.RequestBlink(1); 354 | } 355 | 356 | int RadioActive::ReceiveData() { 357 | //check for any received packets 358 | if (radio.receiveDone()) { 359 | // CheckForWirelessHEX(radio, flash); 360 | 361 | DEBUG1('['); 362 | DEBUG2(radio.SENDERID, DEC); 363 | DEBUG1("] to ["); 364 | DEBUG2(radio.TARGETID, DEC); 365 | DEBUG1("] "); 366 | for (byte i = 0; i < radio.DATALEN; i++) { 367 | DEBUG2((unsigned char)radio.DATA[i], HEX); 368 | DEBUG1('.'); 369 | } 370 | DEBUG1(" [RX_RSSI:"); 371 | DEBUG1(radio.RSSI); 372 | DEBUG1("]"); 373 | DEBUGLN1(); 374 | 375 | if (radio.ACKRequested() 376 | && radio.TARGETID == NODEID 377 | ) { 378 | delay(3); // Pause needed when sending right after receiving 379 | radio.sendACK(); 380 | DEBUGLN1(" - ACK sent"); 381 | } 382 | led.RequestBlink(1); 383 | } 384 | } 385 | 386 | unsigned long RadioActive::Run() { 387 | // do not check radio when it is in standby state. This in order to save battery, as any call to radio, when asleep, will power it back again 388 | if (State != Standby) { 389 | ReceiveData(); 390 | } 391 | 392 | if (millis() < NextTime) { 393 | // we haven't yet reached a time where we have some state transition to happen, return imediately 394 | return NextTime; 395 | } 396 | 397 | switch (State) { 398 | case Transmit: 399 | 400 | #if defined (DEVICE_CLASS_A) || defined (DEVICE_CLASS_B) 401 | DEBUGLN1("Switch off radio"); 402 | NextTime = FOREVER; 403 | radio.sleep(); 404 | #elif defined(DEVICE_CLASS_C) 405 | #else 406 | #error "No radio Class Defined" 407 | #endif 408 | State = Standby; 409 | break; 410 | } 411 | return NextTime; 412 | } 413 | 414 | ///////////////////////////// 415 | // LED 416 | ///////////////////////////// 417 | void Led::RequestBlink(int blinkRequested) { 418 | remainingBlink = blinkRequested; 419 | State = PowerOn; 420 | NextTime = millis() + 1; 421 | } 422 | 423 | unsigned long Led::Run() { 424 | if (millis() < NextTime) { 425 | // we haven't yet reached a time where we have some state transition to happen, return imediately 426 | return NextTime; 427 | } 428 | switch (State) { 429 | case Init: 430 | pinMode(LED, OUTPUT); 431 | NextTime = FOREVER; 432 | break; 433 | case Standby: 434 | NextTime = FOREVER; 435 | break; 436 | case PowerOn: 437 | digitalWrite(LED, 1); 438 | NextTime = millis() + blinkPeriod; 439 | State = PowerOff; 440 | break; 441 | case PowerOff: 442 | digitalWrite(LED, 0); 443 | NextTime = millis() + blinkPeriod; 444 | if (--remainingBlink) { 445 | State = PowerOn; 446 | } 447 | else { 448 | State = Standby; 449 | } 450 | break; 451 | } 452 | return NextTime; 453 | } 454 | 455 | ///////////////////////////// 456 | // TEMP Sensor 457 | ///////////////////////////// 458 | unsigned long DHT::Run() { 459 | if (millis() < NextTime) { 460 | // we haven't yet reached a time where we have some state transition to happen, return imediately 461 | return NextTime; 462 | } 463 | switch (State) { 464 | case Init: 465 | NextTime = millis() + TEMP_READ_DELAY; 466 | State = Standby; 467 | break; 468 | case Standby: 469 | State = PowerOn; 470 | break; 471 | case PowerOn: 472 | DEBUGLN1("Power on DHT"); 473 | pinMode(DHTPIN, INPUT_PULLUP); 474 | pinMode(DHTPOWERPIN, OUTPUT); 475 | digitalWrite(DHTPOWERPIN, 1); 476 | State = Stabilize; 477 | NextTime = millis() + TEMP_STABILIZE_DELAY; 478 | break; 479 | case Stabilize: 480 | // if (millis() > temperatureTime) { 481 | State = Read; 482 | // } 483 | break; 484 | case Read: 485 | chk = DHT.read21(DHTPIN); 486 | 487 | DEBUGLN1("Power off DHT"); 488 | pinMode(DHTPOWERPIN, INPUT); 489 | digitalWrite(DHTPOWERPIN, 0); 490 | pinMode(DHTPIN, INPUT); 491 | digitalWrite(DHTPIN, 0); //ensure no consumption on 492 | 493 | State = PowerOff; 494 | switch (chk) 495 | { 496 | case DHTLIB_OK: 497 | DEBUG1("OK,\t"); 498 | State = Transmit; 499 | break; 500 | case DHTLIB_ERROR_CHECKSUM: 501 | DEBUG1("Checksum error,\t"); 502 | break; 503 | case DHTLIB_ERROR_TIMEOUT: 504 | DEBUG1("Time out error,\t"); 505 | break; 506 | case DHTLIB_ERROR_CONNECT: 507 | DEBUG1("Connect error,\t"); 508 | break; 509 | case DHTLIB_ERROR_ACK_L: 510 | DEBUG1("Ack Low error,\t"); 511 | break; 512 | case DHTLIB_ERROR_ACK_H: 513 | DEBUG1("Ack High error,\t"); 514 | break; 515 | default: 516 | DEBUG1("Unknown error,\t"); 517 | break; 518 | } 519 | 520 | h = DHT.humidity; 521 | // Read temperature as Celsius 522 | t = DHT.temperature; 523 | 524 | DEBUG1("Humidity="); 525 | DEBUG1(h); 526 | DEBUG1(" Temp="); 527 | DEBUG1(t); 528 | DEBUG1("°C"); 529 | DEBUGLN1(); 530 | break; 531 | case Transmit: 532 | //send data 533 | theData.deviceID = 6; 534 | theData.var1_usl = millis(); 535 | theData.var2_float = t; 536 | theData.var3_float = h; 537 | // frameSent++; 538 | radioSend.SendData(GATEWAYID, (const void*)(&theData), sizeof(theData)); 539 | 540 | State = PowerOff; 541 | break; 542 | case PowerOff: 543 | State = Standby; 544 | NextTime = millis() + TEMP_READ_DELAY; 545 | break; 546 | } 547 | return NextTime; 548 | } 549 | 550 | ///////////////////////// 551 | // 552 | // Battery monitoring 553 | // 554 | ///////////////////////// 555 | static const float referenceVolts = 3.3; 556 | static const float R1 = 926; // 926K for a 1M - from V+ to point of measure 557 | static const float R2 = 989; // 989K for a 1M - from GND to point of measure 558 | static const float resistorFactor = 255 / (R2 / (R1 + R2)); 559 | static const int batteryPin = A0; // where battery is connected 560 | 561 | unsigned long Battery::Run() { 562 | if (millis() < NextTime) { 563 | // we haven't yet reached a time where we have some state transition to happen, return imediately 564 | return NextTime; 565 | } 566 | int val; 567 | switch (State) { 568 | case Init: 569 | pinMode(BATTPIN, INPUT); 570 | NextTime = millis(); // immediate read 571 | State = Standby; 572 | break; 573 | case Standby: 574 | State = Stabilize; 575 | break; 576 | case Stabilize: 577 | State = Read; 578 | power_adc_enable(); 579 | analogRead(0); // consume first read 580 | break; 581 | case Read: 582 | volts = ((analogRead(0) / resistorFactor) * referenceVolts); 583 | power_adc_disable(); 584 | DEBUGLN1(volts); 585 | State = Transmit; 586 | break; 587 | case Transmit: 588 | //send data 589 | theData.deviceID = 7; 590 | theData.var1_usl = millis(); 591 | theData.var2_float = volts; 592 | theData.var3_float = 0; 593 | radioSend.SendData(GATEWAYID, (const void*)(&theData), sizeof(theData)); 594 | State = PowerOff; 595 | break; 596 | case PowerOff: 597 | State = Standby; 598 | NextTime = millis() + BATT_READ_DELAY; 599 | break; 600 | } 601 | return NextTime; 602 | } 603 | 604 | void setup() { 605 | DEBUGSTART(); 606 | Serial.println(__FILE__); 607 | Serial.print("Network "); 608 | Serial.println(NETWORKID); 609 | Serial.print("Node "); 610 | Serial.println(NODEID); 611 | Serial.print("Gateway "); 612 | Serial.println(GATEWAYID); 613 | Serial.println(); 614 | 615 | // Set all pin as output and low to minimize consumption. 616 | for (byte i = 0; i <= A7; i++) { 617 | pinMode (i, INPUT); 618 | digitalWrite (i, LOW); 619 | } 620 | 621 | // disable the LED 622 | digitalWrite(LED, 0); 623 | 624 | // configure RTC chip 625 | pinMode(RTC_INT, INPUT); 626 | 627 | pRTC = new MCP7940RTC(); 628 | pRTC->set(1387798395); 629 | pRTC->setTimeRTC(1388534400); // 2014-01-01 00:00:00 630 | 631 | // configure Flash memory chip 632 | // put flash memory to sleep 633 | // Anarduino: Flash SPI_CS = 5, ID = 0xEF30 (Winbond 4Mbit flash) 634 | // SPIFlash flash(5, 0x0120); // flash(SPI_CS, MANUFACTURER_ID) 635 | // SPIFlash flash(5); // flash(SPI_CS, MANUFACTURER_ID) 636 | if (flash.initialize()) { 637 | DEBUGLN1("Flash Init OK!"); 638 | flash.sleep(); // put flash (if it exists) into low power mode 639 | DEBUGLN1("Flash sleep"); 640 | } 641 | else { 642 | DEBUGLN1("Flash Init FAIL!"); 643 | } 644 | // Configure Radio module 645 | radio.initialize(FREQUENCY, NODEID, NETWORKID); 646 | #ifdef IS_RFM69HW 647 | radio.setHighPower(); //uncomment only for RFM69HW! 648 | #endif 649 | radio.setPowerLevel(31); 650 | radio.encrypt(ENCRYPTKEY); 651 | char buff[50]; 652 | sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY == RF69_433MHZ ? 433 : FREQUENCY == RF69_868MHZ ? 868 : 915); 653 | DEBUGLN1(buff); 654 | theData.nodeID = NODEID; //this node id should be the same for all devices in this node 655 | // radio.promiscuous(true); 656 | radio.promiscuous(false); 657 | radio.sleep(); 658 | } 659 | 660 | void loop() { 661 | uint32_t nextRun = FOREVER; 662 | nextRun = min(nextRun, led.Run()); 663 | nextRun = min(nextRun, dht.Run()); 664 | nextRun = min(nextRun, battery.Run()); 665 | nextRun = min(nextRun, radioSend.Run()); 666 | 667 | long suspend = nextRun - millis(); 668 | if (suspend > 0 ) { 669 | Sleepy::loseSomeTime(suspend); 670 | } 671 | } -------------------------------------------------------------------------------- /SimpleMonitorNode/readme.md: -------------------------------------------------------------------------------- 1 | This repo contain a sample node sketch. This code is trying to minimize the power consumption, allowing to use energy harvesting/battery supply. 2 | 3 | The sketch is based on Anarduino Miniwireless board, with a DHT22 connected and a resistor bridge to measure the battery voltage. It shut down the peripherals when not used (DHT, Radio, Flash...) and goes to sleep when nothng to do. 4 | 5 | The DHT22 is connected to the pin 7 for the data and pin 8 for the power supply. The GN is connected on GND pin. 6 | 7 | The battery consist of 2 resistors connected in serial, from GND to VIN with the middle point being connected to A0. The values of the resistor must be changed in the sketch to have acurate conversion. 8 | 9 | The Node can work in 3 modes, depending the usage/ 10 | * Class A, the rado is shut off just after the data transmission 11 | * Class B, the radio is kept on few seconds in order to receive messages from gateway, after transmitting 12 | * Class C, the radio is always on. More useful for actuator but will consume more energy 13 | -------------------------------------------------------------------------------- /piGateway/Gateway.c: -------------------------------------------------------------------------------- 1 | /* 2 | RFM69 Gateway RFM69 pushing the data to the mosquitto server 3 | by Alexandre Bouillot 4 | 5 | License: CC-BY-SA, https://creativecommons.org/licenses/by-sa/2.0/ 6 | Date: 2016/11/24 7 | File: Gateway.c 8 | 9 | This sketch receives RFM wireless data and forwards it to Mosquitto relay 10 | 11 | The messages are published with the format RFM///up/ 12 | It also subscripe to Mosquitto Topics starting with RFM///down/ 13 | 14 | The message is parsed and put back to the same payload structure as the one received from the nodes 15 | 16 | 17 | Adjust network configuration to your setup in the file networkconfig.h 18 | */ 19 | 20 | //general -------------------------------- 21 | #define SERIAL_BAUD 115200 22 | #ifdef DAEMON 23 | #define LOG(...) do { syslog(LOG_INFO, __VA_ARGS__); } while (0) 24 | #define LOG_E(...) do { syslog(LOG_ERR, __VA_ARGS__); } while (0) 25 | #else 26 | #ifdef DEBUG 27 | #define DEBUG1(expression) fprintf(stderr, expression) 28 | #define DEBUG2(expression, arg) fprintf(stderr, expression, arg) 29 | #define DEBUGLN1(expression) 30 | #define LOG(...) do { printf(__VA_ARGS__); } while (0) 31 | #define LOG_E(...) do { printf(__VA_ARGS__); } while (0) 32 | #else 33 | #define DEBUG1(expression) 34 | #define DEBUG2(expression, arg) 35 | #define DEBUGLN1(expression) 36 | #define LOG(...) 37 | #define LOG_E(...) 38 | #endif 39 | #endif 40 | 41 | //RFM69 ---------------------------------- 42 | #include "rfm69.h" 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | 58 | #include "networkconfig.h" 59 | 60 | RFM69 *rfm69; 61 | 62 | typedef struct { 63 | unsigned long messageWatchdog; 64 | unsigned long messageSent; 65 | unsigned long messageReceived; 66 | unsigned long ackRequested; 67 | 68 | unsigned long ackReceived; 69 | unsigned long ackMissed; 70 | 71 | unsigned long ackCount; 72 | } 73 | Stats; 74 | Stats theStats; 75 | 76 | typedef struct { 77 | uint8_t networkId; 78 | uint8_t nodeId; 79 | uint8_t frequency; // RF69_433MHZ RF69_868MHZ RF69_915MHZ 80 | uint8_t keyLength; // set to 0 for no encryption 81 | char key[16]; 82 | bool isRFM69HW; 83 | bool promiscuousMode; 84 | unsigned long messageWatchdogDelay; // maximum time between two message before restarting radio module 85 | } 86 | Config; 87 | Config theConfig; 88 | 89 | // Mosquitto--------------- 90 | #include 91 | 92 | /* How many seconds the broker should wait between sending out 93 | * keep-alive messages. */ 94 | #define KEEPALIVE_SECONDS 60 95 | /* Hostname and port for the MQTT broker. */ 96 | #define BROKER_HOSTNAME "localhost" 97 | #define BROKER_PORT 1883 98 | 99 | #define MQTT_ROOT "RFM" 100 | #define MQTT_CLIENT_ID "arduinoClient" 101 | #define MQTT_RETRY 500 102 | 103 | int sendMQTT = 0; 104 | 105 | typedef struct { 106 | short nodeID; 107 | short sensorID; 108 | unsigned long var1_usl; 109 | float var2_float; 110 | float var3_float; 111 | } 112 | Payload; 113 | Payload theData; 114 | 115 | typedef struct { 116 | short nodeID; 117 | short sensorID; 118 | unsigned long var1_usl; 119 | float var2_float; 120 | float var3_float; // 121 | int var4_int; 122 | } 123 | SensorNode; 124 | SensorNode sensorNode; 125 | 126 | static void die(const char *msg); 127 | static long millis(void); 128 | static void hexDump (char *desc, void *addr, int len, int bloc); 129 | 130 | static int initRfm(RFM69 *rfm); 131 | 132 | static bool set_callbacks(struct mosquitto *m); 133 | static bool connect(struct mosquitto *m); 134 | static int run_loop(struct mosquitto *m); 135 | 136 | static void MQTTSendInt(struct mosquitto * _client, int node, int sensor, int var, int val); 137 | static void MQTTSendULong(struct mosquitto* _client, int node, int sensor, int var, unsigned long val); 138 | static void MQTTSendFloat(struct mosquitto* _client, int node, int sensor, int var, float val); 139 | 140 | static void uso(void) { 141 | fprintf(stderr, "Use:\n Simply use it without args :D\n"); 142 | exit(1); 143 | } 144 | 145 | int main(int argc, char* argv[]) { 146 | if (argc != 1) uso(); 147 | 148 | #ifdef DAEMON 149 | //Adapted from http://www.netzmafia.de/skripten/unix/linux-daemon-howto.html 150 | pid_t pid, sid; 151 | 152 | openlog("Gatewayd", LOG_PID, LOG_USER); 153 | 154 | pid = fork(); 155 | if (pid < 0) { 156 | LOG_E("fork failed"); 157 | exit(EXIT_FAILURE); 158 | } 159 | /* If we got a good PID, then 160 | we can exit the parent process. */ 161 | if (pid > 0) { 162 | LOG("Child spawned, pid %d\n", pid); 163 | exit(EXIT_SUCCESS); 164 | } 165 | 166 | /* Change the file mode mask */ 167 | umask(0); 168 | 169 | /* Create a new SID for the child process */ 170 | sid = setsid(); 171 | if (sid < 0) { 172 | LOG_E("setsid failed"); 173 | exit(EXIT_FAILURE); 174 | } 175 | 176 | /* Change the current working directory */ 177 | if ((chdir("/")) < 0) { 178 | LOG_E("chdir failed"); 179 | exit(EXIT_FAILURE); 180 | } 181 | 182 | /* Close out the standard file descriptors */ 183 | close(STDIN_FILENO); 184 | close(STDOUT_FILENO); 185 | close(STDERR_FILENO); 186 | #endif //DAEMON 187 | 188 | // Mosquitto ---------------------- 189 | struct mosquitto *m = mosquitto_new(MQTT_CLIENT_ID, true, null); 190 | if (m == NULL) { die("init() failure\n"); } 191 | 192 | if (!set_callbacks(m)) { die("set_callbacks() failure\n"); } 193 | if (!connect(m)) { die("connect() failure\n"); } 194 | 195 | //RFM69 --------------------------- 196 | theConfig.networkId = NWC_NETWORK_ID; 197 | theConfig.nodeId = NWC_NODE_ID; 198 | theConfig.frequency = NWC_FREQUENCY; 199 | theConfig.keyLength = NWC_KEY_LENGTH; 200 | memcpy(theConfig.key, NWC_KEY, NWC_KEY_LENGTH); 201 | theConfig.isRFM69HW = NWC_RFM69H; 202 | theConfig.promiscuousMode = NWC_PROMISCUOUS_MODE; 203 | theConfig.messageWatchdogDelay = NWC_WATCHDOG_DELAY; // 1800 seconds (30 minutes) between two messages 204 | 205 | rfm69 = new RFM69(); 206 | rfm69->initialize(theConfig.frequency,theConfig.nodeId,theConfig.networkId); 207 | initRfm(rfm69); 208 | 209 | // Mosquitto subscription --------- 210 | char subsciptionMask[128]; 211 | sprintf(subsciptionMask, "%s/%03d/#/down", MQTT_ROOT, theConfig.networkId); 212 | LOG("Subscribe to Mosquitto topic: %s\n", subsciptionMask); 213 | mosquitto_subscribe(m, NULL, subsciptionMask, 0); 214 | 215 | LOG("setup complete\n"); 216 | return run_loop(m); 217 | } // end of setup 218 | 219 | /* Loop until it is explicitly halted or the network is lost, then clean up. */ 220 | static int run_loop(struct mosquitto *m) { 221 | int res; 222 | long lastMess; 223 | for (;;) { 224 | res = mosquitto_loop(m, 10, 1); 225 | 226 | // No messages have been received withing MESSAGE_WATCHDOG interval 227 | if (millis() > lastMess + theConfig.messageWatchdogDelay) { 228 | LOG("=== Message WatchDog ===\n"); 229 | theStats.messageWatchdog++; 230 | // re-initialise the radio 231 | initRfm(rfm69); 232 | // reset watchdog 233 | lastMess = millis(); 234 | } 235 | 236 | if (rfm69->receiveDone()) { 237 | // record last message received time - to compute radio watchdog 238 | lastMess = millis(); 239 | theStats.messageReceived++; 240 | 241 | // store the received data localy, so they can be overwited 242 | // This will allow to send ACK immediately after 243 | uint8_t data[RF69_MAX_DATA_LEN]; // recv/xmit buf, including header & crc bytes 244 | uint8_t dataLength = rfm69->DATALEN; 245 | memcpy(data, (void *)rfm69->DATA, dataLength); 246 | uint8_t theNodeID = rfm69->SENDERID; 247 | uint8_t targetID = rfm69->TARGETID; // should match _address 248 | uint8_t PAYLOADLEN = rfm69->PAYLOADLEN; 249 | uint8_t ACK_REQUESTED = rfm69->ACK_REQUESTED; 250 | uint8_t ACK_RECEIVED = rfm69->ACK_RECEIVED; // should be polled immediately after sending a packet with ACK request 251 | int16_t RSSI = rfm69->RSSI; // most accurate RSSI during reception (closest to the reception) 252 | 253 | if (ACK_REQUESTED && targetID == theConfig.nodeId) { 254 | // When a node requests an ACK, respond to the ACK 255 | // but only if the Node ID is correct 256 | theStats.ackRequested++; 257 | rfm69->sendACK(); 258 | 259 | if (theStats.ackCount++%3==0) { 260 | // and also send a packet requesting an ACK (every 3rd one only) 261 | // This way both TX/RX NODE functions are tested on 1 end at the GATEWAY 262 | 263 | usleep(3000); //need this when sending right after reception .. ? 264 | theStats.messageSent++; 265 | if (rfm69->sendWithRetry(theNodeID, "ACK TEST", 8)) { // 3 retry, over 200ms delay each 266 | theStats.ackReceived++; 267 | LOG("Pinging node %d - ACK - ok!", theNodeID); 268 | } 269 | else { 270 | theStats.ackMissed++; 271 | LOG("Pinging node %d - ACK - nothing!", theNodeID); 272 | } 273 | } 274 | }//end if radio.ACK_REQESTED 275 | 276 | LOG("[%d] to [%d] ", theNodeID, targetID); 277 | 278 | if (dataLength != sizeof(Payload)) { 279 | LOG("Invalid payload received, not matching Payload struct! %d - %d\r\n", dataLength, sizeof(Payload)); 280 | hexDump(NULL, data, dataLength, 16); 281 | } else { 282 | theData = *(Payload*)data; //assume radio.DATA actually contains our struct and not something else 283 | 284 | //save it for mosquitto: 285 | sensorNode.nodeID = theData.nodeID; 286 | sensorNode.sensorID = theData.sensorID; 287 | sensorNode.var1_usl = theData.var1_usl; 288 | sensorNode.var2_float = theData.var2_float; 289 | sensorNode.var3_float = theData.var3_float; 290 | sensorNode.var4_int = RSSI; 291 | 292 | LOG("Received Node ID = %d Device ID = %d Time = %d RSSI = %d var2 = %f var3 = %f\n", 293 | sensorNode.nodeID, 294 | sensorNode.sensorID, 295 | sensorNode.var1_usl, 296 | sensorNode.var4_int, 297 | sensorNode.var2_float, 298 | sensorNode.var3_float 299 | ); 300 | if (sensorNode.nodeID == theNodeID) 301 | sendMQTT = 1; 302 | else { 303 | hexDump(NULL, data, dataLength, 16); 304 | } 305 | } 306 | } //end if radio.receive 307 | 308 | if (sendMQTT == 1) { 309 | //send var1_usl 310 | MQTTSendULong(m, sensorNode.nodeID, sensorNode.sensorID, 1, sensorNode.var1_usl); 311 | 312 | //send var2_float 313 | MQTTSendFloat(m, sensorNode.nodeID, sensorNode.sensorID, 2, sensorNode.var2_float); 314 | 315 | //send var3_float 316 | MQTTSendFloat(m, sensorNode.nodeID, sensorNode.sensorID, 3, sensorNode.var3_float); 317 | 318 | //send var4_int, RSSI 319 | MQTTSendInt(m, sensorNode.nodeID, sensorNode.sensorID, 4, sensorNode.var4_int); 320 | 321 | sendMQTT = 0; 322 | }//end if sendMQTT 323 | } 324 | 325 | mosquitto_destroy(m); 326 | (void)mosquitto_lib_cleanup(); 327 | 328 | if (res == MOSQ_ERR_SUCCESS) { 329 | return 0; 330 | } else { 331 | return 1; 332 | } 333 | } 334 | 335 | static int initRfm(RFM69 *rfm) { 336 | rfm->restart(theConfig.frequency,theConfig.nodeId,theConfig.networkId); 337 | if (theConfig.isRFM69HW) 338 | rfm->setHighPower(); //uncomment only for RFM69HW! 339 | if (theConfig.keyLength) 340 | rfm->encrypt(theConfig.key); 341 | rfm->promiscuous(theConfig.promiscuousMode); 342 | LOG("Listening at %d Mhz...\n", theConfig.frequency==RF69_433MHZ ? 433 : theConfig.frequency==RF69_868MHZ ? 868 : 915); 343 | } 344 | 345 | /* Fail with an error message. */ 346 | static void die(const char *msg) { 347 | fprintf(stderr, "%s", msg); 348 | exit(1); 349 | } 350 | 351 | static long millis(void) { 352 | struct timeval tv; 353 | 354 | gettimeofday(&tv, NULL); 355 | 356 | return ((tv.tv_sec) * 1000 + tv.tv_usec/1000.0) + 0.5; 357 | } 358 | 359 | 360 | /* Binary Dump utility function */ 361 | #define MAX_BLOC 16 362 | const unsigned char hex_asc[] = "0123456789abcdef"; 363 | static void hexDump (char *desc, void *addr, int len, int bloc) { 364 | int i, lx, la, l, line; 365 | long offset = 0; 366 | unsigned char hexbuf[MAX_BLOC * 3 + 1]; // Hex part of the data (2 char + 1 space) 367 | unsigned char ascbuf[MAX_BLOC + 1]; // ASCII part of the data 368 | unsigned char *pc = (unsigned char*)addr; 369 | unsigned char ch; 370 | 371 | // nothing to output 372 | if (!len) 373 | return; 374 | 375 | // Limit the line length to MAX_BLOC 376 | if (bloc > MAX_BLOC) 377 | bloc = MAX_BLOC; 378 | 379 | // Output description if given. 380 | if (desc != NULL) 381 | LOG("%s:\n", desc); 382 | 383 | line = 0; 384 | do 385 | { 386 | l = len - (line * bloc); 387 | if (l > bloc) 388 | l = bloc; 389 | 390 | for (i=0, lx = 0, la = 0; i < l; i++) { 391 | ch = pc[i]; 392 | hexbuf[lx++] = hex_asc[((ch) & 0xF0) >> 4]; 393 | hexbuf[lx++] = hex_asc[((ch) & 0xF)]; 394 | hexbuf[lx++] = ' '; 395 | 396 | ascbuf[la++] = (ch > 0x20 && ch < 0x7F) ? ch : '.'; 397 | } 398 | 399 | for (; i < bloc; i++) { 400 | hexbuf[lx++] = ' '; 401 | hexbuf[lx++] = ' '; 402 | hexbuf[lx++] = ' '; 403 | } 404 | // nul terminate both buffer 405 | hexbuf[lx++] = 0; 406 | ascbuf[la++] = 0; 407 | 408 | // output buffers 409 | LOG("%04x %s %s\n", line * bloc, hexbuf, ascbuf); 410 | 411 | line++; 412 | pc += bloc; 413 | } 414 | while (line * bloc < len); 415 | } 416 | 417 | static void MQTTSendInt(struct mosquitto * _client, int node, int sensor, int var, int val) { 418 | char buff_topic[128]; 419 | char buff_message[128]; 420 | 421 | sprintf(buff_topic, "%s/%03d/%02d/up/%01d%01d", MQTT_ROOT, theConfig.networkId, node, sensor, var); 422 | sprintf(buff_message, "%04d%", val); 423 | // LOG("%s %s", buff_topic, buff_message); 424 | mosquitto_publish(_client, 0, &buff_topic[0], strlen(buff_message), buff_message, 0, false); 425 | } 426 | 427 | static void MQTTSendULong(struct mosquitto* _client, int node, int sensor, int var, unsigned long val) { 428 | char buff_topic[128]; 429 | char buff_message[128]; 430 | 431 | sprintf(buff_topic, "%s/%03d/%02d/up/%01d%01d", MQTT_ROOT, theConfig.networkId, node, sensor, var); 432 | sprintf(buff_message, "%u", val); 433 | // LOG("%s %s", buff_topic, buff_message); 434 | mosquitto_publish(_client, 0, &buff_topic[0], strlen(buff_message), buff_message, 0, false); 435 | } 436 | 437 | static void MQTTSendFloat(struct mosquitto* _client, int node, int sensor, int var, float val) { 438 | char buff_topic[128]; 439 | char buff_message[128]; 440 | 441 | sprintf(buff_topic, "%s/%03d/%02d/up/%01d%01d", MQTT_ROOT, theConfig.networkId, node, sensor, var); 442 | snprintf(buff_message, 12, "%f", val); 443 | // LOG("%s %s", buff_topic, buff_message); 444 | mosquitto_publish(_client, 0, buff_topic, strlen(buff_message), buff_message, 0, false); 445 | 446 | } 447 | 448 | // Handing of Mosquitto messages 449 | void callback(char* topic, uint8_t* payload, unsigned int length) { 450 | // handle message arrived 451 | LOG("Mosquitto Callback\n"); 452 | } 453 | 454 | 455 | /* Connect to the network. */ 456 | static bool connect(struct mosquitto *m) { 457 | int res = mosquitto_connect(m, BROKER_HOSTNAME, BROKER_PORT, KEEPALIVE_SECONDS); 458 | LOG("Connect return %d\n", res); 459 | return res == MOSQ_ERR_SUCCESS; 460 | } 461 | 462 | /* Callback for successful connection: add subscriptions. */ 463 | static void on_connect(struct mosquitto *m, void *udata, int res) { 464 | if (res == 0) { /* success */ 465 | LOG("Connect succeed\n"); 466 | } else { 467 | die("connection refused\n"); 468 | } 469 | } 470 | 471 | /* Handle a message that just arrived via one of the subscriptions. */ 472 | static void on_message(struct mosquitto *m, void *udata, 473 | const struct mosquitto_message *msg) { 474 | if (msg == NULL) { return; } 475 | LOG("-- got message @ %s: (%d, QoS %d, %s) '%s'\n", 476 | msg->topic, msg->payloadlen, msg->qos, msg->retain ? "R" : "!r", 477 | msg->payload); 478 | 479 | if (strlen((const char *)msg->topic) < strlen(MQTT_ROOT) + 2 + 3 + 1) {return; } // message is smaller than "RFM/xxx/x" so likey invalid 480 | 481 | Payload data; 482 | uint8_t network; 483 | 484 | sscanf(msg->topic, "RFM/%d/%d/%d", &network, &data.nodeID, &data.sensorID); 485 | if (strncmp(msg->topic, MQTT_ROOT, strlen(MQTT_ROOT)) == 0 && network == theConfig.networkId) { 486 | 487 | // extract the target network and the target node from the topic 488 | sscanf(msg->topic, "RFM/%d/%d/%d", &network, &data.nodeID, &data.sensorID); 489 | 490 | if (network == theConfig.networkId) { 491 | // only process the messages to our network 492 | 493 | sscanf((const char *)msg->payload, "%ld,%f,%f", &data.var1_usl, &data.var2_float, &data.var3_float); 494 | 495 | LOG("Received message for Node ID = %d Device ID = %d Time = %d var2 = %f var3 = %f\n", 496 | data.nodeID, 497 | data.sensorID, 498 | data.var1_usl, 499 | data.var2_float, 500 | data.var3_float 501 | ); 502 | 503 | theStats.messageSent++; 504 | if (rfm69->sendWithRetry(data.nodeID,(const void*)(&data),sizeof(data))) { 505 | LOG("Message sent to node %d ACK", data.nodeID); 506 | theStats.ackReceived++; 507 | } 508 | else { 509 | LOG("Message sent to node %d NAK", data.nodeID); 510 | theStats.ackMissed++; 511 | } 512 | } 513 | } 514 | } 515 | 516 | /* A message was successfully published. */ 517 | static void on_publish(struct mosquitto *m, void *udata, int m_id) { 518 | // LOG(" -- published successfully\n"); 519 | } 520 | 521 | /* Successful subscription hook. */ 522 | static void on_subscribe(struct mosquitto *m, void *udata, int mid, 523 | int qos_count, const int *granted_qos) { 524 | // LOG(" -- subscribed successfully\n"); 525 | } 526 | 527 | /* Register the callbacks that the mosquitto connection will use. */ 528 | static bool set_callbacks(struct mosquitto *m) { 529 | mosquitto_connect_callback_set(m, on_connect); 530 | mosquitto_publish_callback_set(m, on_publish); 531 | mosquitto_subscribe_callback_set(m, on_subscribe); 532 | mosquitto_message_callback_set(m, on_message); 533 | return true; 534 | } 535 | 536 | -------------------------------------------------------------------------------- /piGateway/GatewaydService: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # /etc/init.d/Gatewayd 3 | 4 | ### BEGIN INIT INFO 5 | # Provides: Gatewayd 6 | # Required-Start: $all 7 | # Required-Stop: $all 8 | # Should-Start: 9 | # Should-Stop: 10 | # Default-Start: 2 3 4 5 11 | # Default-Stop: 0 1 6 12 | # X-Start-Before: 13 | # X-Start-After: openhab 14 | # Short-Description: RFM Gateway daemon 15 | # Description: Poll the SPI for data from an RFM69 wireless transceiver 16 | ### END INIT INFO 17 | 18 | # Adapted from noip2 (http://www.togaware.com/linux/survivor/No_IP_Manual.html) 19 | 20 | # Using the lsb functions to perform the operations. 21 | . /lib/lsb/init-functions 22 | DAEMON=/usr/local/bin/Gatewayd 23 | NAME=Gatewayd 24 | PIDFILE=/var/run/Gatewayd.pid 25 | 26 | test -x $DAEMON || exit 0 27 | 28 | case "$1" in 29 | start) 30 | echo -n "Starting RFM Gateway: " 31 | start-stop-daemon --start --exec $DAEMON --pidfile $PIDFILE --name $NAME 32 | echo $NAME 33 | ;; 34 | stop) 35 | echo -n "Stopping RFM Gateway daemon: " 36 | start-stop-daemon --stop --oknodo --retry 30 --exec $DAEMON --name $NAME 37 | echo $NAME 38 | ;; 39 | 40 | restart) 41 | echo -n "Restarting RFM Gateway daemon: " 42 | start-stop-daemon --stop --oknodo --retry 30 --exec $DAEMON 43 | start-stop-daemon --start --exec $DAEMON 44 | echo $NAME 45 | ;; 46 | *) 47 | echo "Usage: $0 start|stop|restart" 48 | exit 1 49 | ;; 50 | esac 51 | 52 | exit 0 53 | -------------------------------------------------------------------------------- /piGateway/Makefile: -------------------------------------------------------------------------------- 1 | install : Gatewayd 2 | cp Gatewayd /usr/local/bin 3 | cp GatewaydService /etc/init.d/Gatewayd 4 | chmod +x /etc/init.d/Gatewayd 5 | update-rc.d Gatewayd defaults 6 | service Gatewayd start 7 | 8 | 9 | uninstall: 10 | service Gatewayd stop 11 | update-rc.d -f Gatewayd remove 12 | rm /etc/init.d/Gatewayd 13 | rm /usr/local/bin/Gatewayd 14 | 15 | Gatewayd : Gateway.c rfm69.cpp rfm69.h rfm69registers.h networkconfig.h 16 | g++ Gateway.c rfm69.cpp -o Gatewayd -lwiringPi -lmosquitto -DRASPBERRY -DDAEMON 17 | 18 | Gateway : Gateway.c rfm69.cpp rfm69.h rfm69registers.h networkconfig.h 19 | g++ Gateway.c rfm69.cpp -o Gateway -lwiringPi -lmosquitto -DRASPBERRY 20 | 21 | SenderReceiver : SenderReceiver.c rfm69.cpp rfm69.h rfm69registers.h networkconfig.h 22 | g++ SenderReceiver.c rfm69.cpp -o SenderReceiver -lwiringPi -DRASPBERRY 23 | 24 | -------------------------------------------------------------------------------- /piGateway/SenderReceiver.c: -------------------------------------------------------------------------------- 1 | /* 2 | RFM69 Sender Reciever Test 3 | by Alexandre Bouillot 4 | adapted for a simple send/receive by Christian van der Leeden 5 | 6 | License: CC-BY-SA, https://creativecommons.org/licenses/by-sa/2.0/ 7 | Date: 2015-12-03 8 | File: SenderReciever.c 9 | 10 | Define the RFM Frequency of the chip used, your network id (pick one) and the encryption key 11 | */ 12 | 13 | //general -------------------------------- 14 | #define LOG(...) do { printf(__VA_ARGS__); } while (0) 15 | 16 | /* CONFIGURATION, please adapt */ 17 | #include "networkconfig.h" 18 | 19 | 20 | //RFM69 ---------------------------------- 21 | #include "rfm69.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | 38 | 39 | RFM69 *rfm69; 40 | 41 | typedef struct { 42 | uint8_t networkId; 43 | uint8_t nodeId; 44 | uint8_t frequency; // RF69_433MHZ RF69_868MHZ RF69_915MHZ 45 | uint8_t keyLength; // set to 0 for no encryption 46 | char key[16]; 47 | bool isRFM69HW; 48 | bool promiscuousMode; 49 | } 50 | Config; 51 | Config theConfig; 52 | 53 | typedef struct { 54 | short nodeID; 55 | short sensorID; 56 | unsigned long var1_usl; 57 | float var2_float; 58 | float var3_float; 59 | } 60 | Payload; 61 | Payload theData; 62 | 63 | 64 | static void die(const char *msg); 65 | static long millis(void); 66 | static void hexDump (char *desc, void *addr, int len, int bloc); 67 | 68 | static int initRfm(RFM69 *rfm); 69 | static void send_message(); 70 | static int run_loop(); 71 | 72 | static int RECEIVER_ID = 10; 73 | static int SENDER_ID = 11; 74 | static int NODE_ID; 75 | static int GATEWAY_ID; 76 | 77 | enum Mode { 78 | sender, 79 | receiver 80 | }; 81 | enum Mode mode; 82 | 83 | 84 | static void uso(void) { 85 | fprintf(stderr, "Use:\n -s for sender, -r for receiver \n"); 86 | exit(1); 87 | } 88 | 89 | int main(int argc, char* argv[]) { 90 | if (argc != 2) uso(); 91 | if (strcmp(argv[1], "-r") == 0 ) { 92 | mode = receiver; 93 | NODE_ID = RECEIVER_ID; 94 | GATEWAY_ID = SENDER_ID; // not really needed... 95 | } else if (strcmp(argv[1], "-s") == 0) { 96 | mode = sender; 97 | NODE_ID = SENDER_ID; 98 | GATEWAY_ID = RECEIVER_ID; 99 | } else { 100 | fprintf(stderr, "invalid arguments"); 101 | uso(); 102 | } 103 | 104 | 105 | //RFM69 --------------------------- 106 | theConfig.networkId = NWC_NETWORK_ID; 107 | theConfig.nodeId = NODE_ID; 108 | theConfig.frequency = NWC_FREQUENCY; 109 | theConfig.keyLength = NWC_KEY_LENGTH; 110 | memcpy(theConfig.key, NWC_KEY, NWC_KEY_LENGTH); 111 | theConfig.isRFM69HW = NWC_RFM69H; 112 | theConfig.promiscuousMode = NWC_PROMISCUOUS_MODE; 113 | 114 | LOG("NETWORK %d NODE_ID %d FREQUENCY %d\n", theConfig.networkId, theConfig.nodeId, theConfig.frequency); 115 | 116 | rfm69 = new RFM69(); 117 | rfm69->initialize(theConfig.frequency,theConfig.nodeId,theConfig.networkId); 118 | initRfm(rfm69); 119 | 120 | LOG("setup complete\n"); 121 | return run_loop(); 122 | } 123 | 124 | int counter = 0; 125 | 126 | /* Loop until it is explicitly halted or the network is lost, then clean up. */ 127 | static int run_loop() { 128 | for (;;) { 129 | if (mode == receiver && rfm69->receiveDone()) { 130 | LOG("Received something...\n"); 131 | // store the received data localy, so they can be overwited 132 | // This will allow to send ACK immediately after 133 | uint8_t data[RF69_MAX_DATA_LEN]; // recv/xmit buf, including header & crc bytes 134 | uint8_t dataLength = rfm69->DATALEN; 135 | memcpy(data, (void *)rfm69->DATA, dataLength); 136 | uint8_t theNodeID = rfm69->SENDERID; 137 | uint8_t targetID = rfm69->TARGETID; // should match _address 138 | uint8_t PAYLOADLEN = rfm69->PAYLOADLEN; 139 | uint8_t ACK_REQUESTED = rfm69->ACK_REQUESTED; 140 | uint8_t ACK_RECEIVED = rfm69->ACK_RECEIVED; // should be polled immediately after sending a packet with ACK request 141 | int16_t RSSI = rfm69->RSSI; // most accurate RSSI during reception (closest to the reception) 142 | LOG("ACK REQUESTED: %d, targetID %d, theConfig.nodeId %d\n", ACK_REQUESTED, targetID, theConfig.nodeId); 143 | if (ACK_REQUESTED && targetID == theConfig.nodeId) { 144 | // When a node requests an ACK, respond to the ACK 145 | // but only if the Node ID is correct 146 | rfm69->sendACK(); 147 | }//end if radio.ACK_REQESTED 148 | 149 | LOG("[%d] to [%d] ", theNodeID, targetID); 150 | 151 | if (dataLength != sizeof(Payload)) { 152 | LOG("Invalid payload received, not matching Payload struct! %d - %d\r\n", dataLength, sizeof(Payload)); 153 | hexDump(NULL, data, dataLength, 16); 154 | } else { 155 | theData = *(Payload*)data; //assume radio.DATA actually contains our struct and not something else 156 | 157 | LOG("Received Node ID = %d Device ID = %d Time = %d RSSI = %d var2 = %f var3 = %f\n", 158 | theData.nodeID, 159 | theData.sensorID, 160 | theData.var1_usl, 161 | RSSI, 162 | theData.var2_float, 163 | theData.var3_float 164 | ); 165 | } 166 | } //end if radio.receive 167 | 168 | if (mode == sender) { 169 | counter = counter + 1; 170 | if (counter % 20 == 0) { 171 | LOG("Sending test message\n"); 172 | send_message(); 173 | } else { 174 | usleep(100*1000); 175 | } 176 | } 177 | 178 | } 179 | 180 | } 181 | 182 | static int initRfm(RFM69 *rfm) { 183 | rfm->restart(theConfig.frequency,theConfig.nodeId,theConfig.networkId); 184 | if (theConfig.isRFM69HW) 185 | rfm->setHighPower(); //uncomment only for RFM69HW! 186 | if (theConfig.keyLength) 187 | rfm->encrypt(theConfig.key); 188 | rfm->promiscuous(theConfig.promiscuousMode); 189 | LOG("Listening at %d Mhz...\n", theConfig.frequency==RF69_433MHZ ? 433 : theConfig.frequency==RF69_868MHZ ? 868 : 915); 190 | } 191 | 192 | /* Fail with an error message. */ 193 | static void die(const char *msg) { 194 | fprintf(stderr, "%s", msg); 195 | exit(1); 196 | } 197 | 198 | static long millis(void) { 199 | struct timeval tv; 200 | 201 | gettimeofday(&tv, NULL); 202 | 203 | return ((tv.tv_sec) * 1000 + tv.tv_usec/1000.0) + 0.5; 204 | } 205 | 206 | 207 | /* Binary Dump utility function */ 208 | #define MAX_BLOC 16 209 | const unsigned char hex_asc[] = "0123456789abcdef"; 210 | static void hexDump (char *desc, void *addr, int len, int bloc) { 211 | int i, lx, la, l, line; 212 | long offset = 0; 213 | unsigned char hexbuf[MAX_BLOC * 3 + 1]; // Hex part of the data (2 char + 1 space) 214 | unsigned char ascbuf[MAX_BLOC + 1]; // ASCII part of the data 215 | unsigned char *pc = (unsigned char*)addr; 216 | unsigned char ch; 217 | 218 | // nothing to output 219 | if (!len) 220 | return; 221 | 222 | // Limit the line length to MAX_BLOC 223 | if (bloc > MAX_BLOC) 224 | bloc = MAX_BLOC; 225 | 226 | // Output description if given. 227 | if (desc != NULL) 228 | LOG("%s:\n", desc); 229 | 230 | line = 0; 231 | do 232 | { 233 | l = len - (line * bloc); 234 | if (l > bloc) 235 | l = bloc; 236 | 237 | for (i=0, lx = 0, la = 0; i < l; i++) { 238 | ch = pc[i]; 239 | hexbuf[lx++] = hex_asc[((ch) & 0xF0) >> 4]; 240 | hexbuf[lx++] = hex_asc[((ch) & 0xF)]; 241 | hexbuf[lx++] = ' '; 242 | 243 | ascbuf[la++] = (ch > 0x20 && ch < 0x7F) ? ch : '.'; 244 | } 245 | 246 | for (; i < bloc; i++) { 247 | hexbuf[lx++] = ' '; 248 | hexbuf[lx++] = ' '; 249 | hexbuf[lx++] = ' '; 250 | } 251 | // nul terminate both buffer 252 | hexbuf[lx++] = 0; 253 | ascbuf[la++] = 0; 254 | 255 | // output buffers 256 | LOG("%04x %s %s\n", line * bloc, hexbuf, ascbuf); 257 | 258 | line++; 259 | pc += bloc; 260 | } 261 | while (line * bloc < len); 262 | } 263 | 264 | 265 | 266 | static void send_message() { 267 | uint8_t retries = 0; 268 | uint8_t wait_time = 255; 269 | Payload data; 270 | uint8_t network; 271 | data.nodeID = GATEWAY_ID; 272 | data.sensorID = 10; 273 | data.var1_usl = 1000; 274 | data.var2_float = 99.0; 275 | data.var3_float = 101.0; 276 | 277 | LOG("Will Send message to Node ID = %d Device ID = %d Time = %d var2 = %f var3 = %f\n", 278 | data.nodeID, 279 | data.sensorID, 280 | data.var1_usl, 281 | data.var2_float, 282 | data.var3_float 283 | ); 284 | 285 | if (rfm69->sendWithRetry(data.nodeID,(const void*)(&data),sizeof(data), retries, wait_time)) { 286 | LOG("\n\nOK: Message sent to node %d ACK\n\n", data.nodeID); 287 | } 288 | else { 289 | LOG("\n\nERROR: essage sent to node %d NAK \n\n", data.nodeID); 290 | } 291 | } 292 | 293 | -------------------------------------------------------------------------------- /piGateway/networkconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | RFM69 Gateway RFM69 pushing the data to the mosquitto server 3 | by Alexandre Bouillot 4 | 5 | License: CC-BY-SA, https://creativecommons.org/licenses/by-sa/2.0/ 6 | Date: 2015-06-12 7 | File: Gateway.c 8 | 9 | This file hold the network configuration 10 | */ 11 | 12 | #define NWC_NETWORK_ID 101 13 | #define NWC_NODE_ID 1 14 | // Frequency should be one of RF69_433MHZ RF69_868MHZ RF69_915MHZ 15 | #define NWC_FREQUENCY RF69_433MHZ 16 | // Set to 0 to disable encryption 17 | #define NWC_KEY_LENGTH 16 18 | // Must contain 16 characters 19 | #define NWC_KEY "xxxxxxxxxxxxxxxx" 20 | // Set to true is the RFM69 is high power, false otherwise 21 | #define NWC_RFM69H true 22 | // Set to true if you want to listen to all messages on the network, even if for different nodes 23 | #define NWC_PROMISCUOUS_MODE true 24 | // Set the delay before reinitializing the RFM69 module if no message received in the interval 25 | #define NWC_WATCHDOG_DELAY 1800000 26 | -------------------------------------------------------------------------------- /piGateway/readme.md: -------------------------------------------------------------------------------- 1 | This repo contain a port of LowPowerLab RFM69 library, initially targeted at Arduino, to Raspberry Pi. 2 | The Gateway code is a 1:1 replacement from Eric Tsai one to be run dirrectly on Raspberry, removing the need of a dedicated Arduino with Ethernet shield 3 | 4 | Connect the RFM69 to the Raspberry PI 5 | 6 | Using SPI part of Raspberry expantion port, with the IRQ connected to the pin 22 (GPIO_25) 7 | 8 | ``` 9 | 3.3V 17 10 | GND 20 11 | SLCK 23 12 | MISO 21 13 | MOSI 19 14 | NSS 24 15 | DID0 22 16 | ``` 17 | 18 | The layout of the connection header is described at http://www.megaleecher.net/Raspberry_Pi_GPIO_Pinout_Helper 19 | ![Alt Text](http://www.megaleecher.net/sites/default/files/images/raspberry-pi-rev2-gpio-pinout.jpg "Raspberry Pinout") 20 | 21 | Install Git core, if not already done 22 | ``` 23 | sudo apt-get install git-core 24 | ``` 25 | Download the WiringPi latest version 26 | ``` 27 | git clone git://git.drogon.net/wiringPi 28 | ``` 29 | A script is provided to easily build it 30 | ``` 31 | cd wiringPi 32 | ./build 33 | ``` 34 | :warning: Ensure you properly setup the SPI interface, using `raspi-config` 35 | 36 | 37 | Install Mosquitto and the development libraries - based on http://mosquitto.org/2013/01/mosquitto-debian-repository 38 | 39 | ``` 40 | wget http://repo.mosquitto.org/debian/mosquitto-repo.gpg.key 41 | sudo apt-key add mosquitto-repo.gpg.key 42 | cd /etc/apt/sources.list.d/ 43 | sudo wget http://repo.mosquitto.org/debian/mosquitto-wheezy.list 44 | sudo apt-get update 45 | sudo apt-get install mosquitto mosquitto-clients libmosquitto-dev libmosquittopp-dev 46 | ``` 47 | 48 | Grab the gateway 49 | ``` 50 | git clone git://github.com/abouillot/HomeAutomation 51 | ``` 52 | Compile the gateway 53 | ``` 54 | cd HomeAutomation/piGateway 55 | g++ Gateway.c rfm69.cpp -o Gateway -lwiringPi -lmosquitto -DRASPBERRY -DDEBUG 56 | ``` 57 | 58 | You can omit the -DDEBUG part, if you don't want the debug output to be produced 59 | 60 | Launch the gateway 61 | ``` 62 | sudo ./Gateway 63 | ``` 64 | sudo is required as some of the WiringPi library need it 65 | 66 | 67 | ### Daemon 68 | The Gateway can also be run as a daemon 69 | 70 | To build it you can use 71 | ``` 72 | make Gatewayd 73 | ``` 74 | 75 | To intsall the Gateway as a service and run it 76 | ``` 77 | sudo make install 78 | ``` 79 | This will build it as well, if not already done. The service will be lauch at every startup of the system. 80 | 81 | To remove the service you can use the command 82 | ``` 83 | sudo make uninstall 84 | ``` 85 | 86 | 87 | ### Send Receive Test 88 | Since I ran into the problem that I couldn't send/receive from my setup, I have added a SenderReceiver script: 89 | 90 | compile with 91 | ``` 92 | make SenderReceiver 93 | ``` 94 | 95 | Run with 96 | ``` 97 | SenderReceiver -s 98 | ``` 99 | will send the packets 100 | 101 | ``` 102 | SenderReceiver -r 103 | ``` 104 | 105 | Will receive the packets. 106 | -------------------------------------------------------------------------------- /piGateway/rfm69.cpp: -------------------------------------------------------------------------------- 1 | // ********************************************************************************** 2 | // Driver definition for HopeRF RFM69W/RFM69HW/RFM69CW/RFM69HCW, Semtech SX1231/1231H 3 | // ********************************************************************************** 4 | // Copyright Felix Rusu (2014), felix@lowpowerlab.com 5 | // http://lowpowerlab.com/ 6 | // Raspberry Pi port by Alexandre Bouillot (2014) @abouillot on twitter 7 | // ********************************************************************************** 8 | // License 9 | // ********************************************************************************** 10 | // This program is free software; you can redistribute it 11 | // and/or modify it under the terms of the GNU General 12 | // Public License as published by the Free Software 13 | // Foundation; either version 3 of the License, or 14 | // (at your option) any later version. 15 | // 16 | // This program is distributed in the hope that it will 17 | // be useful, but WITHOUT ANY WARRANTY; without even the 18 | // implied warranty of MERCHANTABILITY or FITNESS FOR A 19 | // PARTICULAR PURPOSE. See the GNU General Public 20 | // License for more details. 21 | // 22 | // You should have received a copy of the GNU General 23 | // Public License along with this program. 24 | // If not, see . 25 | // 26 | // Licence can be viewed at 27 | // http://www.gnu.org/licenses/gpl-3.0.txt 28 | // 29 | // Please maintain this license information along with authorship 30 | // and copyright notices in any redistribution of this code 31 | // ********************************************************************************** 32 | #include "rfm69.h" 33 | #include "rfm69registers.h" 34 | #ifdef RASPBERRY 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include //usleep 42 | #define MICROSLEEP_LENGTH 15 43 | 44 | #else 45 | #include 46 | #endif 47 | 48 | volatile uint8_t RFM69::DATA[RF69_MAX_DATA_LEN]; 49 | volatile uint8_t RFM69::_mode; // current transceiver state 50 | volatile uint8_t RFM69::DATALEN; 51 | volatile uint8_t RFM69::SENDERID; 52 | volatile uint8_t RFM69::TARGETID; // should match _address 53 | volatile uint8_t RFM69::PAYLOADLEN; 54 | volatile uint8_t RFM69::ACK_REQUESTED; 55 | volatile uint8_t RFM69::ACK_RECEIVED; // should be polled immediately after sending a packet with ACK request 56 | volatile int16_t RFM69::RSSI; // most accurate RSSI during reception (closest to the reception) 57 | RFM69* RFM69::selfPointer; 58 | 59 | uint16_t intCount = 0; 60 | 61 | bool RFM69::initialize(uint8_t freqBand, uint8_t nodeID, uint8_t networkID) 62 | { 63 | const uint8_t CONFIG[][2] = 64 | { 65 | /* 0x01 */ { REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_OFF | RF_OPMODE_STANDBY }, 66 | /* 0x02 */ { REG_DATAMODUL, RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONTYPE_FSK | RF_DATAMODUL_MODULATIONSHAPING_00 }, // no shaping 67 | /* 0x03 */ { REG_BITRATEMSB, RF_BITRATEMSB_55555}, // default: 4.8 KBPS 68 | /* 0x04 */ { REG_BITRATELSB, RF_BITRATELSB_55555}, 69 | /* 0x05 */ { REG_FDEVMSB, RF_FDEVMSB_50000}, // default: 5KHz, (FDEV + BitRate / 2 <= 500KHz) 70 | /* 0x06 */ { REG_FDEVLSB, RF_FDEVLSB_50000}, 71 | 72 | /* 0x07 */ { REG_FRFMSB, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFMSB_315 : (freqBand==RF69_433MHZ ? RF_FRFMSB_433 : (freqBand==RF69_868MHZ ? RF_FRFMSB_868 : RF_FRFMSB_915))) }, 73 | /* 0x08 */ { REG_FRFMID, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFMID_315 : (freqBand==RF69_433MHZ ? RF_FRFMID_433 : (freqBand==RF69_868MHZ ? RF_FRFMID_868 : RF_FRFMID_915))) }, 74 | /* 0x09 */ { REG_FRFLSB, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFLSB_315 : (freqBand==RF69_433MHZ ? RF_FRFLSB_433 : (freqBand==RF69_868MHZ ? RF_FRFLSB_868 : RF_FRFLSB_915))) }, 75 | 76 | // looks like PA1 and PA2 are not implemented on RFM69W, hence the max output power is 13dBm 77 | // +17dBm and +20dBm are possible on RFM69HW 78 | // +13dBm formula: Pout = -18 + OutputPower (with PA0 or PA1**) 79 | // +17dBm formula: Pout = -14 + OutputPower (with PA1 and PA2)** 80 | // +20dBm formula: Pout = -11 + OutputPower (with PA1 and PA2)** and high power PA settings (section 3.3.7 in datasheet) 81 | ///* 0x11 */ { REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | RF_PALEVEL_OUTPUTPOWER_11111}, 82 | ///* 0x13 */ { REG_OCP, RF_OCP_ON | RF_OCP_TRIM_95 }, // over current protection (default is 95mA) 83 | 84 | // RXBW defaults are { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_5} (RxBw: 10.4KHz) 85 | /* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_16 | RF_RXBW_EXP_2 }, // (BitRate < 2 * RxBw) 86 | //for BR-19200: /* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_3 }, 87 | /* 0x25 */ { REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01 }, // DIO0 is the only IRQ we're using 88 | /* 0x26 */ { REG_DIOMAPPING2, RF_DIOMAPPING2_CLKOUT_OFF }, // DIO5 ClkOut disable for power saving 89 | /* 0x28 */ { REG_IRQFLAGS2, RF_IRQFLAGS2_FIFOOVERRUN }, // writing to this bit ensures that the FIFO & status flags are reset 90 | /* 0x29 */ { REG_RSSITHRESH, 220 }, // must be set to dBm = (-Sensitivity / 2), default is 0xE4 = 228 so -114dBm 91 | ///* 0x2D */ { REG_PREAMBLELSB, RF_PREAMBLESIZE_LSB_VALUE } // default 3 preamble bytes 0xAAAAAA 92 | /* 0x2E */ { REG_SYNCCONFIG, RF_SYNC_ON | RF_SYNC_FIFOFILL_AUTO | RF_SYNC_SIZE_2 | RF_SYNC_TOL_0 }, 93 | /* 0x2F */ { REG_SYNCVALUE1, 0x2D }, // attempt to make this compatible with sync1 byte of RFM12B lib 94 | /* 0x30 */ { REG_SYNCVALUE2, networkID }, // NETWORK ID 95 | /* 0x37 */ { REG_PACKETCONFIG1, RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_OFF | RF_PACKET1_CRC_ON | RF_PACKET1_CRCAUTOCLEAR_ON | RF_PACKET1_ADRSFILTERING_OFF }, 96 | /* 0x38 */ { REG_PAYLOADLENGTH, 66 }, // in variable length mode: the max frame size, not used in TX 97 | ///* 0x39 */ { REG_NODEADRS, nodeID }, // turned off because we're not using address filtering 98 | /* 0x3C */ { REG_FIFOTHRESH, RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY | RF_FIFOTHRESH_VALUE }, // TX on FIFO not empty 99 | /* 0x3D */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_2BITS | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, // RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent) 100 | //for BR-19200: /* 0x3D */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_NONE | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, // RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent) 101 | /* 0x6F */ { REG_TESTDAGC, RF_DAGC_IMPROVED_LOWBETA0 }, // run DAGC continuously in RX mode for Fading Margin Improvement, recommended default for AfcLowBetaOn=0 102 | {255, 0} 103 | }; 104 | 105 | #ifdef RASPBERRY 106 | // Initialize SPI device 0 107 | if(wiringPiSPISetup(SPI_DEVICE, SPI_SPEED) < 0) { 108 | fprintf(stderr, "Unable to open SPI device\n\r"); 109 | exit(1); 110 | } 111 | #else 112 | digitalWrite(_slaveSelectPin, HIGH); 113 | pinMode(_slaveSelectPin, OUTPUT); 114 | SPI.begin(); 115 | #endif 116 | unsigned long start = millis(); 117 | uint8_t timeout = 50; 118 | do writeReg(REG_SYNCVALUE1, 0xAA); while (readReg(REG_SYNCVALUE1) != 0xaa && millis()-start < timeout); 119 | start = millis(); 120 | do writeReg(REG_SYNCVALUE1, 0x55); while (readReg(REG_SYNCVALUE1) != 0x55 && millis()-start < timeout); 121 | 122 | for (uint8_t i = 0; CONFIG[i][0] != 255; i++) 123 | writeReg(CONFIG[i][0], CONFIG[i][1]); 124 | 125 | // Encryption is persistent between resets and can trip you up during debugging. 126 | // Disable it during initialization so we always start from a known state. 127 | encrypt(0); 128 | 129 | setHighPower(_isRFM69HW); // called regardless if it's a RFM69W or RFM69HW 130 | setMode(RF69_MODE_STANDBY); 131 | start = millis(); 132 | while (((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00) && millis()-start < timeout); // wait for ModeReady 133 | if (millis()-start >= timeout) 134 | return false; 135 | #ifdef RASPBERRY 136 | // Attach the Interupt 137 | wiringPiSetup(); 138 | wiringPiISR(6, INT_EDGE_RISING, RFM69::isr0); 139 | #else 140 | attachInterrupt(_interruptNum, RFM69::isr0, RISING); 141 | #endif 142 | selfPointer = this; 143 | _address = nodeID; 144 | return true; 145 | } 146 | 147 | bool RFM69::restart(uint8_t freqBand, uint8_t nodeID, uint8_t networkID) { 148 | const uint8_t CONFIG[][2] = 149 | { 150 | /* 0x01 */ { REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_OFF | RF_OPMODE_STANDBY }, 151 | /* 0x02 */ { REG_DATAMODUL, RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONTYPE_FSK | RF_DATAMODUL_MODULATIONSHAPING_00 }, // no shaping 152 | /* 0x03 */ { REG_BITRATEMSB, RF_BITRATEMSB_55555}, // default: 4.8 KBPS 153 | /* 0x04 */ { REG_BITRATELSB, RF_BITRATELSB_55555}, 154 | /* 0x05 */ { REG_FDEVMSB, RF_FDEVMSB_50000}, // default: 5KHz, (FDEV + BitRate / 2 <= 500KHz) 155 | /* 0x06 */ { REG_FDEVLSB, RF_FDEVLSB_50000}, 156 | 157 | /* 0x07 */ { REG_FRFMSB, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFMSB_315 : (freqBand==RF69_433MHZ ? RF_FRFMSB_433 : (freqBand==RF69_868MHZ ? RF_FRFMSB_868 : RF_FRFMSB_915))) }, 158 | /* 0x08 */ { REG_FRFMID, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFMID_315 : (freqBand==RF69_433MHZ ? RF_FRFMID_433 : (freqBand==RF69_868MHZ ? RF_FRFMID_868 : RF_FRFMID_915))) }, 159 | /* 0x09 */ { REG_FRFLSB, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFLSB_315 : (freqBand==RF69_433MHZ ? RF_FRFLSB_433 : (freqBand==RF69_868MHZ ? RF_FRFLSB_868 : RF_FRFLSB_915))) }, 160 | 161 | // looks like PA1 and PA2 are not implemented on RFM69W, hence the max output power is 13dBm 162 | // +17dBm and +20dBm are possible on RFM69HW 163 | // +13dBm formula: Pout = -18 + OutputPower (with PA0 or PA1**) 164 | // +17dBm formula: Pout = -14 + OutputPower (with PA1 and PA2)** 165 | // +20dBm formula: Pout = -11 + OutputPower (with PA1 and PA2)** and high power PA settings (section 3.3.7 in datasheet) 166 | ///* 0x11 */ { REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | RF_PALEVEL_OUTPUTPOWER_11111}, 167 | ///* 0x13 */ { REG_OCP, RF_OCP_ON | RF_OCP_TRIM_95 }, // over current protection (default is 95mA) 168 | 169 | // RXBW defaults are { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_5} (RxBw: 10.4KHz) 170 | /* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_16 | RF_RXBW_EXP_2 }, // (BitRate < 2 * RxBw) 171 | //for BR-19200: /* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_3 }, 172 | /* 0x25 */ { REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01 }, // DIO0 is the only IRQ we're using 173 | /* 0x26 */ { REG_DIOMAPPING2, RF_DIOMAPPING2_CLKOUT_OFF }, // DIO5 ClkOut disable for power saving 174 | /* 0x28 */ { REG_IRQFLAGS2, RF_IRQFLAGS2_FIFOOVERRUN }, // writing to this bit ensures that the FIFO & status flags are reset 175 | /* 0x29 */ { REG_RSSITHRESH, 220 }, // must be set to dBm = (-Sensitivity / 2), default is 0xE4 = 228 so -114dBm 176 | ///* 0x2D */ { REG_PREAMBLELSB, RF_PREAMBLESIZE_LSB_VALUE } // default 3 preamble bytes 0xAAAAAA 177 | /* 0x2E */ { REG_SYNCCONFIG, RF_SYNC_ON | RF_SYNC_FIFOFILL_AUTO | RF_SYNC_SIZE_2 | RF_SYNC_TOL_0 }, 178 | /* 0x2F */ { REG_SYNCVALUE1, 0x2D }, // attempt to make this compatible with sync1 byte of RFM12B lib 179 | /* 0x30 */ { REG_SYNCVALUE2, networkID }, // NETWORK ID 180 | /* 0x37 */ { REG_PACKETCONFIG1, RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_OFF | RF_PACKET1_CRC_ON | RF_PACKET1_CRCAUTOCLEAR_ON | RF_PACKET1_ADRSFILTERING_OFF }, 181 | /* 0x38 */ { REG_PAYLOADLENGTH, 66 }, // in variable length mode: the max frame size, not used in TX 182 | ///* 0x39 */ { REG_NODEADRS, nodeID }, // turned off because we're not using address filtering 183 | /* 0x3C */ { REG_FIFOTHRESH, RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY | RF_FIFOTHRESH_VALUE }, // TX on FIFO not empty 184 | /* 0x3D */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_2BITS | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, // RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent) 185 | //for BR-19200: /* 0x3D */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_NONE | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, // RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent) 186 | /* 0x6F */ { REG_TESTDAGC, RF_DAGC_IMPROVED_LOWBETA0 }, // run DAGC continuously in RX mode for Fading Margin Improvement, recommended default for AfcLowBetaOn=0 187 | {255, 0} 188 | }; 189 | 190 | do writeReg(REG_SYNCVALUE1, 0xAA); while (readReg(REG_SYNCVALUE1) != 0xAA); 191 | do writeReg(REG_SYNCVALUE1, 0x55); while (readReg(REG_SYNCVALUE1) != 0x55); 192 | 193 | for (uint8_t i = 0; CONFIG[i][0] != 255; i++) 194 | writeReg(CONFIG[i][0], CONFIG[i][1]); 195 | 196 | // Encryption is persistent between resets and can trip you up during debugging. 197 | // Disable it during initialization so we always start from a known state. 198 | encrypt(0); 199 | 200 | setHighPower(_isRFM69HW); // called regardless if it's a RFM69W or RFM69HW 201 | setMode(RF69_MODE_STANDBY); 202 | while ((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // wait for ModeReady 203 | 204 | selfPointer = this; 205 | _address = nodeID; 206 | return true; 207 | } 208 | 209 | // return the frequency (in Hz) 210 | uint32_t RFM69::getFrequency() 211 | { 212 | return RF69_FSTEP * (((uint32_t) readReg(REG_FRFMSB) << 16) + ((uint16_t) readReg(REG_FRFMID) << 8) + readReg(REG_FRFLSB)); 213 | } 214 | 215 | // set the frequency (in Hz) 216 | void RFM69::setFrequency(uint32_t freqHz) 217 | { 218 | uint8_t oldMode = _mode; 219 | if (oldMode == RF69_MODE_TX) { 220 | setMode(RF69_MODE_RX); 221 | } 222 | freqHz /= RF69_FSTEP; // divide down by FSTEP to get FRF 223 | writeReg(REG_FRFMSB, freqHz >> 16); 224 | writeReg(REG_FRFMID, freqHz >> 8); 225 | writeReg(REG_FRFLSB, freqHz); 226 | if (oldMode == RF69_MODE_RX) { 227 | setMode(RF69_MODE_SYNTH); 228 | } 229 | setMode(oldMode); 230 | } 231 | 232 | void RFM69::setMode(uint8_t newMode) 233 | { 234 | if (newMode == _mode) 235 | return; 236 | 237 | switch (newMode) { 238 | case RF69_MODE_TX: 239 | writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_TRANSMITTER); 240 | if (_isRFM69HW) setHighPowerRegs(true); 241 | break; 242 | case RF69_MODE_RX: 243 | writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_RECEIVER); 244 | if (_isRFM69HW) setHighPowerRegs(false); 245 | break; 246 | case RF69_MODE_SYNTH: 247 | writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SYNTHESIZER); 248 | break; 249 | case RF69_MODE_STANDBY: 250 | writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_STANDBY); 251 | break; 252 | case RF69_MODE_SLEEP: 253 | writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SLEEP); 254 | break; 255 | default: 256 | return; 257 | } 258 | 259 | // we are using packet mode, so this check is not really needed 260 | // but waiting for mode ready is necessary when going from sleep because the FIFO may not be immediately available from previous mode 261 | while (_mode == RF69_MODE_SLEEP && (readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // wait for ModeReady 262 | 263 | _mode = newMode; 264 | } 265 | 266 | //put transceiver in sleep mode to save battery - to wake or resume receiving just call receiveDone() 267 | void RFM69::sleep() { 268 | setMode(RF69_MODE_SLEEP); 269 | } 270 | 271 | //set this node's address 272 | void RFM69::setAddress(uint8_t addr) 273 | { 274 | _address = addr; 275 | writeReg(REG_NODEADRS, _address); 276 | } 277 | 278 | //set this node's network id 279 | void RFM69::setNetwork(uint8_t networkID) 280 | { 281 | writeReg(REG_SYNCVALUE2, networkID); 282 | } 283 | 284 | // set *transmit/TX* output power: 0=min, 31=max 285 | // this results in a "weaker" transmitted signal, and directly results in a lower RSSI at the receiver 286 | // the power configurations are explained in the SX1231H datasheet (Table 10 on p21; RegPaLevel p66): http://www.semtech.com/images/datasheet/sx1231h.pdf 287 | // valid powerLevel parameter values are 0-31 and result in a directly proportional effect on the output/transmission power 288 | // this function implements 2 modes as follows: 289 | // - for RFM69W the range is from 0-31 [-18dBm to 13dBm] (PA0 only on RFIO pin) 290 | // - for RFM69HW the range is from 0-31 [5dBm to 20dBm] (PA1 & PA2 on PA_BOOST pin & high Power PA settings - see section 3.3.7 in datasheet, p22) 291 | void RFM69::setPowerLevel(uint8_t powerLevel) 292 | { 293 | _powerLevel = (powerLevel > 31 ? 31 : powerLevel); 294 | if (_isRFM69HW) _powerLevel /= 2; 295 | writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0xE0) | _powerLevel); 296 | } 297 | 298 | bool RFM69::canSend() 299 | { 300 | // printf("mode %d, payload %d, rssi %d %d\n", _mode, PAYLOADLEN, readRSSI(), CSMA_LIMIT); 301 | if (_mode == RF69_MODE_RX && PAYLOADLEN == 0 && readRSSI() < CSMA_LIMIT) // if signal stronger than -100dBm is detected assume channel activity 302 | { 303 | setMode(RF69_MODE_STANDBY); 304 | return true; 305 | } 306 | return false; 307 | } 308 | 309 | void RFM69::send(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK) 310 | { 311 | writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks 312 | uint32_t now = millis(); 313 | while (!canSend() && millis() - now < RF69_CSMA_LIMIT_MS) receiveDone(); 314 | sendFrame(toAddress, buffer, bufferSize, requestACK, false); 315 | } 316 | 317 | // to increase the chance of getting a packet across, call this function instead of send 318 | // and it handles all the ACK requesting/retrying for you :) 319 | // The only twist is that you have to manually listen to ACK requests on the other side and send back the ACKs 320 | // The reason for the semi-automaton is that the lib is interrupt driven and 321 | // requires user action to read the received data and decide what to do with it 322 | // replies usually take only 5..8ms at 50kbps@915MHz 323 | bool RFM69::sendWithRetry(uint8_t toAddress, const void* buffer, uint8_t bufferSize, uint8_t retries, uint8_t retryWaitTime) { 324 | uint32_t sentTime; 325 | for (uint8_t i = 0; i <= retries; i++) 326 | { 327 | send(toAddress, buffer, bufferSize, true); 328 | sentTime = millis(); 329 | while (millis() - sentTime < retryWaitTime) 330 | { 331 | if (ACKReceived(toAddress)) 332 | { 333 | //Serial.print(" ~ms:"); Serial.print(millis() - sentTime); 334 | return true; 335 | } 336 | } 337 | //Serial.print(" RETRY#"); Serial.println(i + 1); 338 | } 339 | return false; 340 | } 341 | 342 | // should be polled immediately after sending a packet with ACK request 343 | bool RFM69::ACKReceived(uint8_t fromNodeID) { 344 | if (receiveDone()) 345 | return (SENDERID == fromNodeID || fromNodeID == RF69_BROADCAST_ADDR) && ACK_RECEIVED; 346 | return false; 347 | } 348 | 349 | // check whether an ACK was requested in the last received packet (non-broadcasted packet) 350 | bool RFM69::ACKRequested() { 351 | return ACK_REQUESTED && (TARGETID != RF69_BROADCAST_ADDR); 352 | } 353 | 354 | // should be called immediately after reception in case sender wants ACK 355 | void RFM69::sendACK(const void* buffer, uint8_t bufferSize) { 356 | ACK_REQUESTED = 0; // TWS added to make sure we don't end up in a timing race and infinite loop sending Acks 357 | uint8_t sender = SENDERID; 358 | int16_t _RSSI = RSSI; // save payload received RSSI value 359 | writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks 360 | uint32_t now = millis(); 361 | while (!canSend() && millis() - now < RF69_CSMA_LIMIT_MS) { delayMicroseconds(MICROSLEEP_LENGTH); /* printf(".");*/ receiveDone();} 362 | sendFrame(sender, buffer, bufferSize, false, true); 363 | RSSI = _RSSI; // restore payload RSSI 364 | } 365 | 366 | // internal function 367 | void RFM69::sendFrame(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK, bool sendACK) 368 | { 369 | setMode(RF69_MODE_STANDBY); // turn off receiver to prevent reception while filling fifo 370 | while ((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // wait for ModeReady 371 | writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_00); // DIO0 is "Packet Sent" 372 | if (bufferSize > RF69_MAX_DATA_LEN) bufferSize = RF69_MAX_DATA_LEN; 373 | 374 | // control byte 375 | uint8_t CTLbyte = 0x00; 376 | if (sendACK) 377 | CTLbyte = RFM69_CTL_SENDACK; 378 | else if (requestACK) 379 | CTLbyte = RFM69_CTL_REQACK; 380 | 381 | #ifdef RASPBERRY 382 | unsigned char thedata[63]; 383 | uint8_t i; 384 | for(i = 0; i < 63; i++) thedata[i] = 0; 385 | 386 | thedata[0] = REG_FIFO | 0x80; 387 | thedata[1] = bufferSize + 3; 388 | thedata[2] = toAddress; 389 | thedata[3] = _address; 390 | thedata[4] = CTLbyte; 391 | 392 | // write to FIFO 393 | for(i = 0; i < bufferSize; i++) { 394 | thedata[i + 5] = ((char*)buffer)[i]; 395 | } 396 | wiringPiSPIDataRW(SPI_DEVICE, thedata, bufferSize + 5); 397 | #else 398 | // write to FIFO 399 | select(); 400 | SPI.transfer(REG_FIFO | 0x80); 401 | SPI.transfer(bufferSize + 3); 402 | SPI.transfer(toAddress); 403 | SPI.transfer(_address); 404 | SPI.transfer(CTLbyte); 405 | 406 | for (uint8_t i = 0; i < bufferSize; i++) 407 | SPI.transfer(((uint8_t*) buffer)[i]); 408 | unselect(); 409 | #endif 410 | // no need to wait for transmit mode to be ready since its handled by the radio 411 | setMode(RF69_MODE_TX); 412 | uint32_t txStart = millis(); 413 | while (digitalRead(_interruptPin) == 0 && millis() - txStart < RF69_TX_LIMIT_MS); // wait for DIO0 to turn HIGH signalling transmission finish 414 | //while (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PACKETSENT == 0x00); // wait for ModeReady 415 | setMode(RF69_MODE_STANDBY); 416 | } 417 | 418 | // internal function - interrupt gets called when a packet is received 419 | void RFM69::interruptHandler() { 420 | 421 | #ifdef RASPBERRY 422 | unsigned char thedata[67]; 423 | char i; 424 | for(i = 0; i < 67; i++) thedata[i] = 0; 425 | // printf("interruptHandler %d\n", intCount); 426 | #endif 427 | 428 | //pinMode(4, OUTPUT); 429 | //digitalWrite(4, 1); 430 | if (_mode == RF69_MODE_RX && (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY)) 431 | { 432 | //RSSI = readRSSI(); 433 | setMode(RF69_MODE_STANDBY); 434 | #ifdef RASPBERRY 435 | thedata[0] = REG_FIFO & 0x7F; 436 | thedata[1] = 0; // PAYLOADLEN 437 | thedata[2] = 0; // TargetID 438 | wiringPiSPIDataRW(SPI_DEVICE, thedata, 3); 439 | delayMicroseconds(MICROSLEEP_LENGTH); 440 | 441 | PAYLOADLEN = thedata[1]; 442 | PAYLOADLEN = PAYLOADLEN > 66 ? 66 : PAYLOADLEN; // precaution 443 | TARGETID = thedata[2]; 444 | #else 445 | select(); 446 | SPI.transfer(REG_FIFO & 0x7F); 447 | PAYLOADLEN = SPI.transfer(0); 448 | PAYLOADLEN = PAYLOADLEN > 66 ? 66 : PAYLOADLEN; // precaution 449 | TARGETID = SPI.transfer(0); 450 | #endif 451 | if(!(_promiscuousMode || TARGETID == _address || TARGETID == RF69_BROADCAST_ADDR) // match this node's address, or broadcast address or anything in promiscuous mode 452 | || PAYLOADLEN < 3) // address situation could receive packets that are malformed and don't fit this libraries extra fields 453 | { 454 | PAYLOADLEN = 0; 455 | unselect(); 456 | receiveBegin(); 457 | //digitalWrite(4, 0); 458 | return; 459 | } 460 | #ifdef RASPBERRY 461 | DATALEN = PAYLOADLEN - 3; 462 | thedata[0] = REG_FIFO & 0x77; 463 | thedata[1] = 0; //SENDERID 464 | thedata[2] = 0; //CTLbyte; 465 | for(i = 0; i< DATALEN; i++) { 466 | thedata[i+3] = 0; 467 | } 468 | 469 | wiringPiSPIDataRW(SPI_DEVICE, thedata, DATALEN + 3); 470 | 471 | SENDERID = thedata[1]; 472 | uint8_t CTLbyte = thedata[2]; 473 | 474 | ACK_RECEIVED = CTLbyte & 0x80; //extract ACK-requested flag 475 | ACK_REQUESTED = CTLbyte & 0x40; //extract ACK-received flag 476 | for (i= 0; i < DATALEN; i++) 477 | { 478 | DATA[i] = thedata[i+3]; 479 | } 480 | #else 481 | DATALEN = PAYLOADLEN - 3; 482 | SENDERID = SPI.transfer(0); 483 | uint8_t CTLbyte = SPI.transfer(0); 484 | 485 | ACK_RECEIVED = CTLbyte & RFM69_CTL_SENDACK; // extract ACK-received flag 486 | ACK_REQUESTED = CTLbyte & RFM69_CTL_REQACK; // extract ACK-requested flag 487 | 488 | interruptHook(CTLbyte); // TWS: hook to derived class interrupt function 489 | for (uint8_t i = 0; i < DATALEN; i++) 490 | { 491 | DATA[i] = SPI.transfer(0); 492 | } 493 | #endif 494 | if (DATALEN < RF69_MAX_DATA_LEN) DATA[DATALEN] = 0; // add null at end of string 495 | unselect(); 496 | setMode(RF69_MODE_RX); 497 | } 498 | RSSI = readRSSI(); 499 | //digitalWrite(4, 0); 500 | 501 | } 502 | 503 | // internal function 504 | void RFM69::isr0() { 505 | // printf (" Isr0 %d ", intCount); 506 | if (intCount++ > 0) { 507 | // printf("+++***==== Dual Interupt handling ====*** %d+++\n", intCount); 508 | } 509 | else 510 | selfPointer->interruptHandler(); 511 | intCount--; 512 | // printf(" Isr0 exit "); 513 | } 514 | 515 | // internal function 516 | void RFM69::receiveBegin() { 517 | DATALEN = 0; 518 | SENDERID = 0; 519 | TARGETID = 0; 520 | PAYLOADLEN = 0; 521 | ACK_REQUESTED = 0; 522 | ACK_RECEIVED = 0; 523 | RSSI = 0; 524 | if (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY) 525 | writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks 526 | writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01); // set DIO0 to "PAYLOADREADY" in receive mode 527 | setMode(RF69_MODE_RX); 528 | } 529 | 530 | // checks if a packet was received and/or puts transceiver in receive (ie RX or listen) mode 531 | bool RFM69::receiveDone() { 532 | //ATOMIC_BLOCK(ATOMIC_FORCEON) 533 | //{ 534 | #ifndef RASPBERRY 535 | noInterrupts(); // re-enabled in unselect() via setMode() or via receiveBegin() 536 | #endif 537 | if (_mode == RF69_MODE_RX && PAYLOADLEN > 0) 538 | { 539 | setMode(RF69_MODE_STANDBY); // enables interrupts 540 | return true; 541 | } 542 | else if (_mode == RF69_MODE_RX) // already in RX no payload yet 543 | { 544 | #ifndef RASPBERRY 545 | interrupts(); // explicitly re-enable interrupts 546 | #endif 547 | return false; 548 | } 549 | receiveBegin(); 550 | return false; 551 | //} 552 | } 553 | 554 | // To enable encryption: radio.encrypt("ABCDEFGHIJKLMNOP"); 555 | // To disable encryption: radio.encrypt(null) or radio.encrypt(0) 556 | // KEY HAS TO BE 16 bytes !!! 557 | void RFM69::encrypt(const char* key) { 558 | #ifdef RASPBERRY 559 | unsigned char thedata[17]; 560 | char i; 561 | 562 | setMode(RF69_MODE_STANDBY); 563 | if (key!=0) { 564 | thedata[0] = REG_AESKEY1 | 0x80; 565 | for(i = 1; i < 17; i++) { 566 | thedata[i] = key[i-1]; 567 | } 568 | 569 | wiringPiSPIDataRW(SPI_DEVICE, thedata, 17); 570 | delayMicroseconds(MICROSLEEP_LENGTH); 571 | } 572 | 573 | writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFE) | (key ? 1 : 0)); 574 | #else 575 | setMode(RF69_MODE_STANDBY); 576 | if (key != 0) 577 | { 578 | select(); 579 | SPI.transfer(REG_AESKEY1 | 0x80); 580 | for (uint8_t i = 0; i < 16; i++) 581 | SPI.transfer(key[i]); 582 | unselect(); 583 | } 584 | writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFE) | (key ? 1 : 0)); 585 | #endif 586 | } 587 | 588 | // get the received signal strength indicator (RSSI) 589 | int16_t RFM69::readRSSI(bool forceTrigger) { 590 | int16_t rssi = 0; 591 | if (forceTrigger) 592 | { 593 | // RSSI trigger not needed if DAGC is in continuous mode 594 | writeReg(REG_RSSICONFIG, RF_RSSI_START); 595 | while ((readReg(REG_RSSICONFIG) & RF_RSSI_DONE) == 0x00); // wait for RSSI_Ready 596 | } 597 | rssi = -readReg(REG_RSSIVALUE); 598 | rssi >>= 1; 599 | return rssi; 600 | } 601 | 602 | uint8_t RFM69::readReg(uint8_t addr) 603 | { 604 | #ifdef RASPBERRY 605 | unsigned char thedata[2]; 606 | thedata[0] = addr & 0x7F; 607 | thedata[1] = 0; 608 | 609 | wiringPiSPIDataRW(SPI_DEVICE, thedata, 2); 610 | delayMicroseconds(MICROSLEEP_LENGTH); 611 | 612 | //printf("%x %x\n", addr, thedata[1]); 613 | return thedata[1]; 614 | #else 615 | select(); 616 | SPI.transfer(addr & 0x7F); 617 | uint8_t regval = SPI.transfer(0); 618 | unselect(); 619 | return regval; 620 | #endif 621 | } 622 | 623 | void RFM69::writeReg(uint8_t addr, uint8_t value) 624 | { 625 | #if RASPBERRY 626 | //printf("%x %x\n", addr, value); 627 | unsigned char thedata[2]; 628 | thedata[0] = addr | 0x80; 629 | thedata[1] = value; 630 | 631 | wiringPiSPIDataRW(SPI_DEVICE, thedata, 2); 632 | delayMicroseconds(MICROSLEEP_LENGTH); 633 | #else 634 | select(); 635 | SPI.transfer(addr | 0x80); 636 | SPI.transfer(value); 637 | unselect(); 638 | #endif 639 | } 640 | 641 | // select the RFM69 transceiver (save SPI settings, set CS low) 642 | void RFM69::select() { 643 | // printf(" diable Int "); 644 | #ifndef RASPBERRY 645 | noInterrupts(); 646 | // save current SPI settings 647 | _SPCR = SPCR; 648 | _SPSR = SPSR; 649 | // set RFM69 SPI settings 650 | SPI.setDataMode(SPI_MODE0); 651 | SPI.setBitOrder(MSBFIRST); 652 | SPI.setClockDivider(SPI_CLOCK_DIV4); // decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present 653 | digitalWrite(_slaveSelectPin, LOW); 654 | #endif 655 | } 656 | 657 | // unselect the RFM69 transceiver (set CS high, restore SPI settings) 658 | void RFM69::unselect() { 659 | #ifndef RASPBERRY 660 | digitalWrite(_slaveSelectPin, HIGH); 661 | // restore SPI settings to what they were before talking to RFM69 662 | SPCR = _SPCR; 663 | SPSR = _SPSR; 664 | interrupts(); 665 | #endif 666 | // printf(" EI "); 667 | } 668 | 669 | // true = disable filtering to capture all frames on network 670 | // false = enable node/broadcast filtering to capture only frames sent to this/broadcast address 671 | void RFM69::promiscuous(bool onOff) { 672 | _promiscuousMode = onOff; 673 | //writeReg(REG_PACKETCONFIG1, (readReg(REG_PACKETCONFIG1) & 0xF9) | (onOff ? RF_PACKET1_ADRSFILTERING_OFF : RF_PACKET1_ADRSFILTERING_NODEBROADCAST)); 674 | } 675 | 676 | // for RFM69HW only: you must call setHighPower(true) after initialize() or else transmission won't work 677 | void RFM69::setHighPower(bool onOff) { 678 | _isRFM69HW = onOff; 679 | writeReg(REG_OCP, _isRFM69HW ? RF_OCP_OFF : RF_OCP_ON); 680 | if (_isRFM69HW) // turning ON 681 | writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0x1F) | RF_PALEVEL_PA1_ON | RF_PALEVEL_PA2_ON); // enable P1 & P2 amplifier stages 682 | else 683 | writeReg(REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | _powerLevel); // enable P0 only 684 | } 685 | 686 | // internal function 687 | void RFM69::setHighPowerRegs(bool onOff) { 688 | writeReg(REG_TESTPA1, onOff ? 0x5D : 0x55); 689 | writeReg(REG_TESTPA2, onOff ? 0x7C : 0x70); 690 | } 691 | 692 | // set the slave select (CS) pin 693 | void RFM69::setCS(uint8_t newSPISlaveSelect) { 694 | _slaveSelectPin = newSPISlaveSelect; 695 | digitalWrite(_slaveSelectPin, HIGH); 696 | pinMode(_slaveSelectPin, OUTPUT); 697 | } 698 | 699 | // Serial.print all the RFM69 register values 700 | void RFM69::readAllRegs() 701 | { 702 | #ifdef RASPBERRY 703 | char thedata[2]; 704 | int i; 705 | thedata[1] = 0; 706 | 707 | for(i = 1; i <= 0x4F; i++) { 708 | printf("%i - %i\n\r", i, readReg(i)); 709 | } 710 | #else 711 | uint8_t regVal; 712 | 713 | for (uint8_t regAddr = 1; regAddr <= 0x4F; regAddr++) 714 | { 715 | select(); 716 | SPI.transfer(regAddr & 0x7F); // send address + r/w bit 717 | regVal = SPI.transfer(0); 718 | unselect(); 719 | 720 | Serial.print(regAddr, HEX); 721 | Serial.print(" - "); 722 | Serial.print(regVal,HEX); 723 | Serial.print(" - "); 724 | Serial.println(regVal,BIN); 725 | } 726 | unselect(); 727 | #endif 728 | } 729 | 730 | uint8_t RFM69::readTemperature(uint8_t calFactor) // returns centigrade 731 | { 732 | setMode(RF69_MODE_STANDBY); 733 | writeReg(REG_TEMP1, RF_TEMP1_MEAS_START); 734 | while ((readReg(REG_TEMP1) & RF_TEMP1_MEAS_RUNNING)); 735 | return ~readReg(REG_TEMP2) + COURSE_TEMP_COEF + calFactor; // 'complement' corrects the slope, rising temp = rising val 736 | } // COURSE_TEMP_COEF puts reading in the ballpark, user can add additional correction 737 | 738 | void RFM69::rcCalibration() 739 | { 740 | writeReg(REG_OSC1, RF_OSC1_RCCAL_START); 741 | while ((readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE) == 0x00); 742 | } 743 | -------------------------------------------------------------------------------- /piGateway/rfm69.h: -------------------------------------------------------------------------------- 1 | // ********************************************************************************** 2 | // Driver definition for HopeRF RFM69W/RFM69HW/RFM69CW/RFM69HCW, Semtech SX1231/1231H 3 | // ********************************************************************************** 4 | // Copyright Felix Rusu (2014), felix@lowpowerlab.com 5 | // http://lowpowerlab.com/ 6 | // Raspberry Pi port by Alexandre Bouillot (2014-2015) @abouillot on twitter 7 | // ********************************************************************************** 8 | // License 9 | // ********************************************************************************** 10 | // This program is free software; you can redistribute it 11 | // and/or modify it under the terms of the GNU General 12 | // Public License as published by the Free Software 13 | // Foundation; either version 3 of the License, or 14 | // (at your option) any later version. 15 | // 16 | // This program is distributed in the hope that it will 17 | // be useful, but WITHOUT ANY WARRANTY; without even the 18 | // implied warranty of MERCHANTABILITY or FITNESS FOR A 19 | // PARTICULAR PURPOSE. See the GNU General Public 20 | // License for more details. 21 | // 22 | // You should have received a copy of the GNU General 23 | // Public License along with this program. 24 | // If not, see . 25 | // 26 | // Licence can be viewed at 27 | // http://www.gnu.org/licenses/gpl-3.0.txt 28 | // 29 | // Please maintain this license information along with authorship 30 | // and copyright notices in any redistribution of this code 31 | // ********************************************************************************** 32 | #ifndef RFM69_h 33 | #define RFM69_h 34 | #ifdef RASPBERRY 35 | #include 36 | 37 | #define RF69_MAX_DATA_LEN 61 // to take advantage of the built in AES/CRC we want to limit the frame size to the internal FIFO size (66 bytes - 3 bytes overhead - 2 bytes crc) 38 | 39 | #define RF69_SPI_CS 0 // SS is the SPI slave select pin, for instance D10 on atmega328 40 | #define RF69_IRQ_PIN 6 41 | #define RF69_IRQ_NUM 0 42 | 43 | #define SPI_SPEED 500000 44 | #define SPI_DEVICE 0 45 | #else 46 | #include //assumes Arduino IDE v1.0 or greater 47 | 48 | #define RF69_MAX_DATA_LEN 61 // to take advantage of the built in AES/CRC we want to limit the frame size to the internal FIFO size (66 bytes - 3 bytes overhead - 2 bytes crc) 49 | #define RF69_SPI_CS SS // SS is the SPI slave select pin, for instance D10 on ATmega328 50 | 51 | // INT0 on AVRs should be connected to RFM69's DIO0 (ex on ATmega328 it's D2, on ATmega644/1284 it's D2) 52 | #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) 53 | #define RF69_IRQ_PIN 2 54 | #define RF69_IRQ_NUM 0 55 | #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) 56 | #define RF69_IRQ_PIN 2 57 | #define RF69_IRQ_NUM 2 58 | #elif defined(__AVR_ATmega32U4__) 59 | #define RF69_IRQ_PIN 3 60 | #define RF69_IRQ_NUM 0 61 | #else 62 | #define RF69_IRQ_PIN 2 63 | #define RF69_IRQ_NUM 0 64 | #endif 65 | #endif 66 | 67 | #define CSMA_LIMIT -90 // upper RX signal sensitivity threshold in dBm for carrier sense access 68 | #define RF69_MODE_SLEEP 0 // XTAL OFF 69 | #define RF69_MODE_STANDBY 1 // XTAL ON 70 | #define RF69_MODE_SYNTH 2 // PLL ON 71 | #define RF69_MODE_RX 3 // RX MODE 72 | #define RF69_MODE_TX 4 // TX MODE 73 | 74 | // available frequency bands 75 | #define RF69_315MHZ 31 // non trivial values to avoid misconfiguration 76 | #define RF69_433MHZ 43 77 | #define RF69_868MHZ 86 78 | #define RF69_915MHZ 91 79 | 80 | #define null 0 81 | #define COURSE_TEMP_COEF -90 // puts the temperature reading in the ballpark, user can fine tune the returned value 82 | #define RF69_BROADCAST_ADDR 255 83 | #define RF69_CSMA_LIMIT_MS 1000 84 | #define RF69_TX_LIMIT_MS 1000 85 | #define RF69_FSTEP 61.03515625 // == FXOSC / 2^19 = 32MHz / 2^19 (p13 in datasheet) 86 | 87 | // TWS: define CTLbyte bits 88 | #define RFM69_CTL_SENDACK 0x80 89 | #define RFM69_CTL_REQACK 0x40 90 | 91 | class RFM69 { 92 | public: 93 | static volatile uint8_t DATA[RF69_MAX_DATA_LEN]; // recv/xmit buf, including header & crc bytes 94 | static volatile uint8_t DATALEN; 95 | static volatile uint8_t SENDERID; 96 | static volatile uint8_t TARGETID; // should match _address 97 | static volatile uint8_t PAYLOADLEN; 98 | static volatile uint8_t ACK_REQUESTED; 99 | static volatile uint8_t ACK_RECEIVED; // should be polled immediately after sending a packet with ACK request 100 | static volatile int16_t RSSI; // most accurate RSSI during reception (closest to the reception) 101 | static volatile uint8_t _mode; // should be protected? 102 | 103 | RFM69(uint8_t slaveSelectPin=RF69_SPI_CS, uint8_t interruptPin=RF69_IRQ_PIN, bool isRFM69HW=false, uint8_t interruptNum=RF69_IRQ_NUM) { 104 | _slaveSelectPin = slaveSelectPin; 105 | _interruptPin = interruptPin; 106 | _interruptNum = interruptNum; 107 | _mode = RF69_MODE_STANDBY; 108 | _promiscuousMode = false; 109 | _powerLevel = 31; 110 | _isRFM69HW = isRFM69HW; 111 | } 112 | 113 | bool initialize(uint8_t freqBand, uint8_t ID, uint8_t networkID=1); 114 | bool restart(uint8_t freqBand, uint8_t ID, uint8_t networkID=1); 115 | void setAddress(uint8_t addr); 116 | void setNetwork(uint8_t networkID); 117 | bool canSend(); 118 | virtual void send(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK=false); 119 | virtual bool sendWithRetry(uint8_t toAddress, const void* buffer, uint8_t bufferSize, uint8_t retries=2, uint8_t retryWaitTime=40); // 40ms roundtrip req for 61byte packets 120 | virtual bool receiveDone(); 121 | bool ACKReceived(uint8_t fromNodeID); 122 | bool ACKRequested(); 123 | virtual void sendACK(const void* buffer = "", uint8_t bufferSize=0); 124 | uint32_t getFrequency(); 125 | void setFrequency(uint32_t freqHz); 126 | void encrypt(const char* key); 127 | void setCS(uint8_t newSPISlaveSelect); 128 | int16_t readRSSI(bool forceTrigger=false); 129 | void promiscuous(bool onOff=true); 130 | virtual void setHighPower(bool onOFF=true); // has to be called after initialize() for RFM69HW 131 | virtual void setPowerLevel(uint8_t level); // reduce/increase transmit power level 132 | void sleep(); 133 | uint8_t readTemperature(uint8_t calFactor=0); // get CMOS temperature (8bit) 134 | void rcCalibration(); // calibrate the internal RC oscillator for use in wide temperature variations - see datasheet section [4.3.5. RC Timer Accuracy] 135 | 136 | // allow hacking registers by making these public 137 | uint8_t readReg(uint8_t addr); 138 | void writeReg(uint8_t addr, uint8_t val); 139 | void readAllRegs(); 140 | 141 | protected: 142 | static void isr0(); 143 | void virtual interruptHandler(); 144 | virtual void interruptHook(uint8_t CTLbyte) {}; 145 | virtual void sendFrame(uint8_t toAddress, const void* buffer, uint8_t size, bool requestACK=false, bool sendACK=false); 146 | 147 | static RFM69* selfPointer; 148 | uint8_t _slaveSelectPin; 149 | uint8_t _interruptPin; 150 | uint8_t _interruptNum; 151 | uint8_t _address; 152 | bool _promiscuousMode; 153 | uint8_t _powerLevel; 154 | bool _isRFM69HW; 155 | uint8_t _SPCR; 156 | uint8_t _SPSR; 157 | 158 | virtual void receiveBegin(); 159 | virtual void setMode(uint8_t mode); 160 | virtual void setHighPowerRegs(bool onOff); 161 | virtual void select(); 162 | virtual void unselect(); 163 | }; 164 | 165 | #endif 166 | -------------------------------------------------------------------------------- /piGateway/rfm69registers.h: -------------------------------------------------------------------------------- 1 | // ********************************************************************************** 2 | // Registers used in driver definition for HopeRF RFM69W/RFM69HW, Semtech SX1231/1231H 3 | // ********************************************************************************** 4 | // Copyright Felix Rusu (2015), felix@lowpowerlab.com 5 | // http://lowpowerlab.com/ 6 | // ********************************************************************************** 7 | // License 8 | // ********************************************************************************** 9 | // This program is free software; you can redistribute it 10 | // and/or modify it under the terms of the GNU General 11 | // Public License as published by the Free Software 12 | // Foundation; either version 2 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // This program is distributed in the hope that it will 16 | // be useful, but WITHOUT ANY WARRANTY; without even the 17 | // implied warranty of MERCHANTABILITY or FITNESS FOR A 18 | // PARTICULAR PURPOSE. See the GNU General Public 19 | // License for more details. 20 | // 21 | // You should have received a copy of the GNU General 22 | // Public License along with this program; if not, write 23 | // to the Free Software Foundation, Inc., 24 | // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 | // 26 | // Licence can be viewed at 27 | // http://www.fsf.org/licenses/gpl.txt 28 | // 29 | // Please maintain this license information along with authorship 30 | // and copyright notices in any redistribution of this code 31 | // ********************************************************************************** 32 | // RFM69/SX1231 Internal registers addresses 33 | //************************************************** 34 | #define REG_FIFO 0x00 35 | #define REG_OPMODE 0x01 36 | #define REG_DATAMODUL 0x02 37 | #define REG_BITRATEMSB 0x03 38 | #define REG_BITRATELSB 0x04 39 | #define REG_FDEVMSB 0x05 40 | #define REG_FDEVLSB 0x06 41 | #define REG_FRFMSB 0x07 42 | #define REG_FRFMID 0x08 43 | #define REG_FRFLSB 0x09 44 | #define REG_OSC1 0x0A 45 | #define REG_AFCCTRL 0x0B 46 | #define REG_LOWBAT 0x0C 47 | #define REG_LISTEN1 0x0D 48 | #define REG_LISTEN2 0x0E 49 | #define REG_LISTEN3 0x0F 50 | #define REG_VERSION 0x10 51 | #define REG_PALEVEL 0x11 52 | #define REG_PARAMP 0x12 53 | #define REG_OCP 0x13 54 | #define REG_AGCREF 0x14 // not present on RFM69/SX1231 55 | #define REG_AGCTHRESH1 0x15 // not present on RFM69/SX1231 56 | #define REG_AGCTHRESH2 0x16 // not present on RFM69/SX1231 57 | #define REG_AGCTHRESH3 0x17 // not present on RFM69/SX1231 58 | #define REG_LNA 0x18 59 | #define REG_RXBW 0x19 60 | #define REG_AFCBW 0x1A 61 | #define REG_OOKPEAK 0x1B 62 | #define REG_OOKAVG 0x1C 63 | #define REG_OOKFIX 0x1D 64 | #define REG_AFCFEI 0x1E 65 | #define REG_AFCMSB 0x1F 66 | #define REG_AFCLSB 0x20 67 | #define REG_FEIMSB 0x21 68 | #define REG_FEILSB 0x22 69 | #define REG_RSSICONFIG 0x23 70 | #define REG_RSSIVALUE 0x24 71 | #define REG_DIOMAPPING1 0x25 72 | #define REG_DIOMAPPING2 0x26 73 | #define REG_IRQFLAGS1 0x27 74 | #define REG_IRQFLAGS2 0x28 75 | #define REG_RSSITHRESH 0x29 76 | #define REG_RXTIMEOUT1 0x2A 77 | #define REG_RXTIMEOUT2 0x2B 78 | #define REG_PREAMBLEMSB 0x2C 79 | #define REG_PREAMBLELSB 0x2D 80 | #define REG_SYNCCONFIG 0x2E 81 | #define REG_SYNCVALUE1 0x2F 82 | #define REG_SYNCVALUE2 0x30 83 | #define REG_SYNCVALUE3 0x31 84 | #define REG_SYNCVALUE4 0x32 85 | #define REG_SYNCVALUE5 0x33 86 | #define REG_SYNCVALUE6 0x34 87 | #define REG_SYNCVALUE7 0x35 88 | #define REG_SYNCVALUE8 0x36 89 | #define REG_PACKETCONFIG1 0x37 90 | #define REG_PAYLOADLENGTH 0x38 91 | #define REG_NODEADRS 0x39 92 | #define REG_BROADCASTADRS 0x3A 93 | #define REG_AUTOMODES 0x3B 94 | #define REG_FIFOTHRESH 0x3C 95 | #define REG_PACKETCONFIG2 0x3D 96 | #define REG_AESKEY1 0x3E 97 | #define REG_AESKEY2 0x3F 98 | #define REG_AESKEY3 0x40 99 | #define REG_AESKEY4 0x41 100 | #define REG_AESKEY5 0x42 101 | #define REG_AESKEY6 0x43 102 | #define REG_AESKEY7 0x44 103 | #define REG_AESKEY8 0x45 104 | #define REG_AESKEY9 0x46 105 | #define REG_AESKEY10 0x47 106 | #define REG_AESKEY11 0x48 107 | #define REG_AESKEY12 0x49 108 | #define REG_AESKEY13 0x4A 109 | #define REG_AESKEY14 0x4B 110 | #define REG_AESKEY15 0x4C 111 | #define REG_AESKEY16 0x4D 112 | #define REG_TEMP1 0x4E 113 | #define REG_TEMP2 0x4F 114 | #define REG_TESTLNA 0x58 115 | #define REG_TESTPA1 0x5A // only present on RFM69HW/SX1231H 116 | #define REG_TESTPA2 0x5C // only present on RFM69HW/SX1231H 117 | #define REG_TESTDAGC 0x6F 118 | 119 | //****************************************************** 120 | // RF69/SX1231 bit control definition 121 | //****************************************************** 122 | 123 | // RegOpMode 124 | #define RF_OPMODE_SEQUENCER_OFF 0x80 125 | #define RF_OPMODE_SEQUENCER_ON 0x00 // Default 126 | 127 | #define RF_OPMODE_LISTEN_ON 0x40 128 | #define RF_OPMODE_LISTEN_OFF 0x00 // Default 129 | 130 | #define RF_OPMODE_LISTENABORT 0x20 131 | 132 | #define RF_OPMODE_SLEEP 0x00 133 | #define RF_OPMODE_STANDBY 0x04 // Default 134 | #define RF_OPMODE_SYNTHESIZER 0x08 135 | #define RF_OPMODE_TRANSMITTER 0x0C 136 | #define RF_OPMODE_RECEIVER 0x10 137 | 138 | 139 | // RegDataModul 140 | #define RF_DATAMODUL_DATAMODE_PACKET 0x00 // Default 141 | #define RF_DATAMODUL_DATAMODE_CONTINUOUS 0x40 142 | #define RF_DATAMODUL_DATAMODE_CONTINUOUSNOBSYNC 0x60 143 | 144 | #define RF_DATAMODUL_MODULATIONTYPE_FSK 0x00 // Default 145 | #define RF_DATAMODUL_MODULATIONTYPE_OOK 0x08 146 | 147 | #define RF_DATAMODUL_MODULATIONSHAPING_00 0x00 // Default 148 | #define RF_DATAMODUL_MODULATIONSHAPING_01 0x01 149 | #define RF_DATAMODUL_MODULATIONSHAPING_10 0x02 150 | #define RF_DATAMODUL_MODULATIONSHAPING_11 0x03 151 | 152 | 153 | // RegBitRate (bits/sec) example bit rates 154 | #define RF_BITRATEMSB_1200 0x68 155 | #define RF_BITRATELSB_1200 0x2B 156 | #define RF_BITRATEMSB_2400 0x34 157 | #define RF_BITRATELSB_2400 0x15 158 | #define RF_BITRATEMSB_4800 0x1A // Default 159 | #define RF_BITRATELSB_4800 0x0B // Default 160 | #define RF_BITRATEMSB_9600 0x0D 161 | #define RF_BITRATELSB_9600 0x05 162 | #define RF_BITRATEMSB_19200 0x06 163 | #define RF_BITRATELSB_19200 0x83 164 | #define RF_BITRATEMSB_38400 0x03 165 | #define RF_BITRATELSB_38400 0x41 166 | 167 | #define RF_BITRATEMSB_38323 0x03 168 | #define RF_BITRATELSB_38323 0x43 169 | 170 | #define RF_BITRATEMSB_34482 0x03 171 | #define RF_BITRATELSB_34482 0xA0 172 | 173 | #define RF_BITRATEMSB_76800 0x01 174 | #define RF_BITRATELSB_76800 0xA1 175 | #define RF_BITRATEMSB_153600 0x00 176 | #define RF_BITRATELSB_153600 0xD0 177 | #define RF_BITRATEMSB_57600 0x02 178 | #define RF_BITRATELSB_57600 0x2C 179 | #define RF_BITRATEMSB_115200 0x01 180 | #define RF_BITRATELSB_115200 0x16 181 | #define RF_BITRATEMSB_12500 0x0A 182 | #define RF_BITRATELSB_12500 0x00 183 | #define RF_BITRATEMSB_25000 0x05 184 | #define RF_BITRATELSB_25000 0x00 185 | #define RF_BITRATEMSB_50000 0x02 186 | #define RF_BITRATELSB_50000 0x80 187 | #define RF_BITRATEMSB_100000 0x01 188 | #define RF_BITRATELSB_100000 0x40 189 | #define RF_BITRATEMSB_150000 0x00 190 | #define RF_BITRATELSB_150000 0xD5 191 | #define RF_BITRATEMSB_200000 0x00 192 | #define RF_BITRATELSB_200000 0xA0 193 | #define RF_BITRATEMSB_250000 0x00 194 | #define RF_BITRATELSB_250000 0x80 195 | #define RF_BITRATEMSB_300000 0x00 196 | #define RF_BITRATELSB_300000 0x6B 197 | #define RF_BITRATEMSB_32768 0x03 198 | #define RF_BITRATELSB_32768 0xD1 199 | // custom bit rates 200 | #define RF_BITRATEMSB_55555 0x02 201 | #define RF_BITRATELSB_55555 0x40 202 | #define RF_BITRATEMSB_200KBPS 0x00 203 | #define RF_BITRATELSB_200KBPS 0xa0 204 | 205 | 206 | // RegFdev - frequency deviation (Hz) 207 | #define RF_FDEVMSB_2000 0x00 208 | #define RF_FDEVLSB_2000 0x21 209 | #define RF_FDEVMSB_5000 0x00 // Default 210 | #define RF_FDEVLSB_5000 0x52 // Default 211 | #define RF_FDEVMSB_7500 0x00 212 | #define RF_FDEVLSB_7500 0x7B 213 | #define RF_FDEVMSB_10000 0x00 214 | #define RF_FDEVLSB_10000 0xA4 215 | #define RF_FDEVMSB_15000 0x00 216 | #define RF_FDEVLSB_15000 0xF6 217 | #define RF_FDEVMSB_20000 0x01 218 | #define RF_FDEVLSB_20000 0x48 219 | #define RF_FDEVMSB_25000 0x01 220 | #define RF_FDEVLSB_25000 0x9A 221 | #define RF_FDEVMSB_30000 0x01 222 | #define RF_FDEVLSB_30000 0xEC 223 | #define RF_FDEVMSB_35000 0x02 224 | #define RF_FDEVLSB_35000 0x3D 225 | #define RF_FDEVMSB_40000 0x02 226 | #define RF_FDEVLSB_40000 0x8F 227 | #define RF_FDEVMSB_45000 0x02 228 | #define RF_FDEVLSB_45000 0xE1 229 | #define RF_FDEVMSB_50000 0x03 230 | #define RF_FDEVLSB_50000 0x33 231 | #define RF_FDEVMSB_55000 0x03 232 | #define RF_FDEVLSB_55000 0x85 233 | #define RF_FDEVMSB_60000 0x03 234 | #define RF_FDEVLSB_60000 0xD7 235 | #define RF_FDEVMSB_65000 0x04 236 | #define RF_FDEVLSB_65000 0x29 237 | #define RF_FDEVMSB_70000 0x04 238 | #define RF_FDEVLSB_70000 0x7B 239 | #define RF_FDEVMSB_75000 0x04 240 | #define RF_FDEVLSB_75000 0xCD 241 | #define RF_FDEVMSB_80000 0x05 242 | #define RF_FDEVLSB_80000 0x1F 243 | #define RF_FDEVMSB_85000 0x05 244 | #define RF_FDEVLSB_85000 0x71 245 | #define RF_FDEVMSB_90000 0x05 246 | #define RF_FDEVLSB_90000 0xC3 247 | #define RF_FDEVMSB_95000 0x06 248 | #define RF_FDEVLSB_95000 0x14 249 | #define RF_FDEVMSB_100000 0x06 250 | #define RF_FDEVLSB_100000 0x66 251 | #define RF_FDEVMSB_110000 0x07 252 | #define RF_FDEVLSB_110000 0x0A 253 | #define RF_FDEVMSB_120000 0x07 254 | #define RF_FDEVLSB_120000 0xAE 255 | #define RF_FDEVMSB_130000 0x08 256 | #define RF_FDEVLSB_130000 0x52 257 | #define RF_FDEVMSB_140000 0x08 258 | #define RF_FDEVLSB_140000 0xF6 259 | #define RF_FDEVMSB_150000 0x09 260 | #define RF_FDEVLSB_150000 0x9A 261 | #define RF_FDEVMSB_160000 0x0A 262 | #define RF_FDEVLSB_160000 0x3D 263 | #define RF_FDEVMSB_170000 0x0A 264 | #define RF_FDEVLSB_170000 0xE1 265 | #define RF_FDEVMSB_180000 0x0B 266 | #define RF_FDEVLSB_180000 0x85 267 | #define RF_FDEVMSB_190000 0x0C 268 | #define RF_FDEVLSB_190000 0x29 269 | #define RF_FDEVMSB_200000 0x0C 270 | #define RF_FDEVLSB_200000 0xCD 271 | #define RF_FDEVMSB_210000 0x0D 272 | #define RF_FDEVLSB_210000 0x71 273 | #define RF_FDEVMSB_220000 0x0E 274 | #define RF_FDEVLSB_220000 0x14 275 | #define RF_FDEVMSB_230000 0x0E 276 | #define RF_FDEVLSB_230000 0xB8 277 | #define RF_FDEVMSB_240000 0x0F 278 | #define RF_FDEVLSB_240000 0x5C 279 | #define RF_FDEVMSB_250000 0x10 280 | #define RF_FDEVLSB_250000 0x00 281 | #define RF_FDEVMSB_260000 0x10 282 | #define RF_FDEVLSB_260000 0xA4 283 | #define RF_FDEVMSB_270000 0x11 284 | #define RF_FDEVLSB_270000 0x48 285 | #define RF_FDEVMSB_280000 0x11 286 | #define RF_FDEVLSB_280000 0xEC 287 | #define RF_FDEVMSB_290000 0x12 288 | #define RF_FDEVLSB_290000 0x8F 289 | #define RF_FDEVMSB_300000 0x13 290 | #define RF_FDEVLSB_300000 0x33 291 | 292 | 293 | // RegFrf (MHz) - carrier frequency 294 | // 315Mhz band 295 | #define RF_FRFMSB_314 0x4E 296 | #define RF_FRFMID_314 0x80 297 | #define RF_FRFLSB_314 0x00 298 | #define RF_FRFMSB_315 0x4E 299 | #define RF_FRFMID_315 0xC0 300 | #define RF_FRFLSB_315 0x00 301 | #define RF_FRFMSB_316 0x4F 302 | #define RF_FRFMID_316 0x00 303 | #define RF_FRFLSB_316 0x00 304 | // 433mhz band 305 | #define RF_FRFMSB_433 0x6C 306 | #define RF_FRFMID_433 0x40 307 | #define RF_FRFLSB_433 0x00 308 | #define RF_FRFMSB_434 0x6C 309 | #define RF_FRFMID_434 0x80 310 | #define RF_FRFLSB_434 0x00 311 | #define RF_FRFMSB_435 0x6C 312 | #define RF_FRFMID_435 0xC0 313 | #define RF_FRFLSB_435 0x00 314 | // 868Mhz band 315 | #define RF_FRFMSB_863 0xD7 316 | #define RF_FRFMID_863 0xC0 317 | #define RF_FRFLSB_863 0x00 318 | #define RF_FRFMSB_864 0xD8 319 | #define RF_FRFMID_864 0x00 320 | #define RF_FRFLSB_864 0x00 321 | #define RF_FRFMSB_865 0xD8 322 | #define RF_FRFMID_865 0x40 323 | #define RF_FRFLSB_865 0x00 324 | #define RF_FRFMSB_866 0xD8 325 | #define RF_FRFMID_866 0x80 326 | #define RF_FRFLSB_866 0x00 327 | #define RF_FRFMSB_867 0xD8 328 | #define RF_FRFMID_867 0xC0 329 | #define RF_FRFLSB_867 0x00 330 | #define RF_FRFMSB_868 0xD9 331 | #define RF_FRFMID_868 0x00 332 | #define RF_FRFLSB_868 0x00 333 | #define RF_FRFMSB_869 0xD9 334 | #define RF_FRFMID_869 0x40 335 | #define RF_FRFLSB_869 0x00 336 | #define RF_FRFMSB_870 0xD9 337 | #define RF_FRFMID_870 0x80 338 | #define RF_FRFLSB_870 0x00 339 | // 915Mhz band 340 | #define RF_FRFMSB_902 0xE1 341 | #define RF_FRFMID_902 0x80 342 | #define RF_FRFLSB_902 0x00 343 | #define RF_FRFMSB_903 0xE1 344 | #define RF_FRFMID_903 0xC0 345 | #define RF_FRFLSB_903 0x00 346 | #define RF_FRFMSB_904 0xE2 347 | #define RF_FRFMID_904 0x00 348 | #define RF_FRFLSB_904 0x00 349 | #define RF_FRFMSB_905 0xE2 350 | #define RF_FRFMID_905 0x40 351 | #define RF_FRFLSB_905 0x00 352 | #define RF_FRFMSB_906 0xE2 353 | #define RF_FRFMID_906 0x80 354 | #define RF_FRFLSB_906 0x00 355 | #define RF_FRFMSB_907 0xE2 356 | #define RF_FRFMID_907 0xC0 357 | #define RF_FRFLSB_907 0x00 358 | #define RF_FRFMSB_908 0xE3 359 | #define RF_FRFMID_908 0x00 360 | #define RF_FRFLSB_908 0x00 361 | #define RF_FRFMSB_909 0xE3 362 | #define RF_FRFMID_909 0x40 363 | #define RF_FRFLSB_909 0x00 364 | #define RF_FRFMSB_910 0xE3 365 | #define RF_FRFMID_910 0x80 366 | #define RF_FRFLSB_910 0x00 367 | #define RF_FRFMSB_911 0xE3 368 | #define RF_FRFMID_911 0xC0 369 | #define RF_FRFLSB_911 0x00 370 | #define RF_FRFMSB_912 0xE4 371 | #define RF_FRFMID_912 0x00 372 | #define RF_FRFLSB_912 0x00 373 | #define RF_FRFMSB_913 0xE4 374 | #define RF_FRFMID_913 0x40 375 | #define RF_FRFLSB_913 0x00 376 | #define RF_FRFMSB_914 0xE4 377 | #define RF_FRFMID_914 0x80 378 | #define RF_FRFLSB_914 0x00 379 | #define RF_FRFMSB_915 0xE4 // Default 380 | #define RF_FRFMID_915 0xC0 // Default 381 | #define RF_FRFLSB_915 0x00 // Default 382 | #define RF_FRFMSB_916 0xE5 383 | #define RF_FRFMID_916 0x00 384 | #define RF_FRFLSB_916 0x00 385 | #define RF_FRFMSB_917 0xE5 386 | #define RF_FRFMID_917 0x40 387 | #define RF_FRFLSB_917 0x00 388 | #define RF_FRFMSB_918 0xE5 389 | #define RF_FRFMID_918 0x80 390 | #define RF_FRFLSB_918 0x00 391 | #define RF_FRFMSB_919 0xE5 392 | #define RF_FRFMID_919 0xC0 393 | #define RF_FRFLSB_919 0x00 394 | #define RF_FRFMSB_920 0xE6 395 | #define RF_FRFMID_920 0x00 396 | #define RF_FRFLSB_920 0x00 397 | #define RF_FRFMSB_921 0xE6 398 | #define RF_FRFMID_921 0x40 399 | #define RF_FRFLSB_921 0x00 400 | #define RF_FRFMSB_922 0xE6 401 | #define RF_FRFMID_922 0x80 402 | #define RF_FRFLSB_922 0x00 403 | #define RF_FRFMSB_923 0xE6 404 | #define RF_FRFMID_923 0xC0 405 | #define RF_FRFLSB_923 0x00 406 | #define RF_FRFMSB_924 0xE7 407 | #define RF_FRFMID_924 0x00 408 | #define RF_FRFLSB_924 0x00 409 | #define RF_FRFMSB_925 0xE7 410 | #define RF_FRFMID_925 0x40 411 | #define RF_FRFLSB_925 0x00 412 | #define RF_FRFMSB_926 0xE7 413 | #define RF_FRFMID_926 0x80 414 | #define RF_FRFLSB_926 0x00 415 | #define RF_FRFMSB_927 0xE7 416 | #define RF_FRFMID_927 0xC0 417 | #define RF_FRFLSB_927 0x00 418 | #define RF_FRFMSB_928 0xE8 419 | #define RF_FRFMID_928 0x00 420 | #define RF_FRFLSB_928 0x00 421 | 422 | 423 | // RegOsc1 424 | #define RF_OSC1_RCCAL_START 0x80 425 | #define RF_OSC1_RCCAL_DONE 0x40 426 | 427 | 428 | // RegAfcCtrl 429 | #define RF_AFCCTRL_LOWBETA_OFF 0x00 // Default 430 | #define RF_AFCCTRL_LOWBETA_ON 0x20 431 | 432 | 433 | // RegLowBat 434 | #define RF_LOWBAT_MONITOR 0x10 435 | #define RF_LOWBAT_ON 0x08 436 | #define RF_LOWBAT_OFF 0x00 // Default 437 | 438 | #define RF_LOWBAT_TRIM_1695 0x00 439 | #define RF_LOWBAT_TRIM_1764 0x01 440 | #define RF_LOWBAT_TRIM_1835 0x02 // Default 441 | #define RF_LOWBAT_TRIM_1905 0x03 442 | #define RF_LOWBAT_TRIM_1976 0x04 443 | #define RF_LOWBAT_TRIM_2045 0x05 444 | #define RF_LOWBAT_TRIM_2116 0x06 445 | #define RF_LOWBAT_TRIM_2185 0x07 446 | 447 | 448 | // RegListen1 449 | #define RF_LISTEN1_RESOL_64 0x50 450 | #define RF_LISTEN1_RESOL_4100 0xA0 // Default 451 | #define RF_LISTEN1_RESOL_262000 0xF0 452 | 453 | #define RF_LISTEN1_RESOL_IDLE_64 0x40 454 | #define RF_LISTEN1_RESOL_IDLE_4100 0x80 // Default 455 | #define RF_LISTEN1_RESOL_IDLE_262000 0xC0 456 | 457 | #define RF_LISTEN1_RESOL_RX_64 0x10 458 | #define RF_LISTEN1_RESOL_RX_4100 0x20 // Default 459 | #define RF_LISTEN1_RESOL_RX_262000 0x30 460 | 461 | #define RF_LISTEN1_CRITERIA_RSSI 0x00 // Default 462 | #define RF_LISTEN1_CRITERIA_RSSIANDSYNC 0x08 463 | 464 | #define RF_LISTEN1_END_00 0x00 465 | #define RF_LISTEN1_END_01 0x02 // Default 466 | #define RF_LISTEN1_END_10 0x04 467 | 468 | 469 | // RegListen2 470 | #define RF_LISTEN2_COEFIDLE_VALUE 0xF5 // Default 471 | 472 | 473 | // RegListen3 474 | #define RF_LISTEN3_COEFRX_VALUE 0x20 // Default 475 | 476 | 477 | // RegVersion 478 | #define RF_VERSION_VER 0x24 // Default 479 | 480 | 481 | // RegPaLevel 482 | #define RF_PALEVEL_PA0_ON 0x80 // Default 483 | #define RF_PALEVEL_PA0_OFF 0x00 484 | #define RF_PALEVEL_PA1_ON 0x40 485 | #define RF_PALEVEL_PA1_OFF 0x00 // Default 486 | #define RF_PALEVEL_PA2_ON 0x20 487 | #define RF_PALEVEL_PA2_OFF 0x00 // Default 488 | 489 | #define RF_PALEVEL_OUTPUTPOWER_00000 0x00 490 | #define RF_PALEVEL_OUTPUTPOWER_00001 0x01 491 | #define RF_PALEVEL_OUTPUTPOWER_00010 0x02 492 | #define RF_PALEVEL_OUTPUTPOWER_00011 0x03 493 | #define RF_PALEVEL_OUTPUTPOWER_00100 0x04 494 | #define RF_PALEVEL_OUTPUTPOWER_00101 0x05 495 | #define RF_PALEVEL_OUTPUTPOWER_00110 0x06 496 | #define RF_PALEVEL_OUTPUTPOWER_00111 0x07 497 | #define RF_PALEVEL_OUTPUTPOWER_01000 0x08 498 | #define RF_PALEVEL_OUTPUTPOWER_01001 0x09 499 | #define RF_PALEVEL_OUTPUTPOWER_01010 0x0A 500 | #define RF_PALEVEL_OUTPUTPOWER_01011 0x0B 501 | #define RF_PALEVEL_OUTPUTPOWER_01100 0x0C 502 | #define RF_PALEVEL_OUTPUTPOWER_01101 0x0D 503 | #define RF_PALEVEL_OUTPUTPOWER_01110 0x0E 504 | #define RF_PALEVEL_OUTPUTPOWER_01111 0x0F 505 | #define RF_PALEVEL_OUTPUTPOWER_10000 0x10 506 | #define RF_PALEVEL_OUTPUTPOWER_10001 0x11 507 | #define RF_PALEVEL_OUTPUTPOWER_10010 0x12 508 | #define RF_PALEVEL_OUTPUTPOWER_10011 0x13 509 | #define RF_PALEVEL_OUTPUTPOWER_10100 0x14 510 | #define RF_PALEVEL_OUTPUTPOWER_10101 0x15 511 | #define RF_PALEVEL_OUTPUTPOWER_10110 0x16 512 | #define RF_PALEVEL_OUTPUTPOWER_10111 0x17 513 | #define RF_PALEVEL_OUTPUTPOWER_11000 0x18 514 | #define RF_PALEVEL_OUTPUTPOWER_11001 0x19 515 | #define RF_PALEVEL_OUTPUTPOWER_11010 0x1A 516 | #define RF_PALEVEL_OUTPUTPOWER_11011 0x1B 517 | #define RF_PALEVEL_OUTPUTPOWER_11100 0x1C 518 | #define RF_PALEVEL_OUTPUTPOWER_11101 0x1D 519 | #define RF_PALEVEL_OUTPUTPOWER_11110 0x1E 520 | #define RF_PALEVEL_OUTPUTPOWER_11111 0x1F // Default 521 | 522 | 523 | // RegPaRamp 524 | #define RF_PARAMP_3400 0x00 525 | #define RF_PARAMP_2000 0x01 526 | #define RF_PARAMP_1000 0x02 527 | #define RF_PARAMP_500 0x03 528 | #define RF_PARAMP_250 0x04 529 | #define RF_PARAMP_125 0x05 530 | #define RF_PARAMP_100 0x06 531 | #define RF_PARAMP_62 0x07 532 | #define RF_PARAMP_50 0x08 533 | #define RF_PARAMP_40 0x09 // Default 534 | #define RF_PARAMP_31 0x0A 535 | #define RF_PARAMP_25 0x0B 536 | #define RF_PARAMP_20 0x0C 537 | #define RF_PARAMP_15 0x0D 538 | #define RF_PARAMP_12 0x0E 539 | #define RF_PARAMP_10 0x0F 540 | 541 | 542 | // RegOcp 543 | #define RF_OCP_OFF 0x0F 544 | #define RF_OCP_ON 0x1A // Default 545 | 546 | #define RF_OCP_TRIM_45 0x00 547 | #define RF_OCP_TRIM_50 0x01 548 | #define RF_OCP_TRIM_55 0x02 549 | #define RF_OCP_TRIM_60 0x03 550 | #define RF_OCP_TRIM_65 0x04 551 | #define RF_OCP_TRIM_70 0x05 552 | #define RF_OCP_TRIM_75 0x06 553 | #define RF_OCP_TRIM_80 0x07 554 | #define RF_OCP_TRIM_85 0x08 555 | #define RF_OCP_TRIM_90 0x09 556 | #define RF_OCP_TRIM_95 0x0A // Default 557 | #define RF_OCP_TRIM_100 0x0B 558 | #define RF_OCP_TRIM_105 0x0C 559 | #define RF_OCP_TRIM_110 0x0D 560 | #define RF_OCP_TRIM_115 0x0E 561 | #define RF_OCP_TRIM_120 0x0F 562 | 563 | 564 | // RegAgcRef - not present on RFM69/SX1231 565 | #define RF_AGCREF_AUTO_ON 0x40 // Default 566 | #define RF_AGCREF_AUTO_OFF 0x00 567 | 568 | #define RF_AGCREF_LEVEL_MINUS80 0x00 // Default 569 | #define RF_AGCREF_LEVEL_MINUS81 0x01 570 | #define RF_AGCREF_LEVEL_MINUS82 0x02 571 | #define RF_AGCREF_LEVEL_MINUS83 0x03 572 | #define RF_AGCREF_LEVEL_MINUS84 0x04 573 | #define RF_AGCREF_LEVEL_MINUS85 0x05 574 | #define RF_AGCREF_LEVEL_MINUS86 0x06 575 | #define RF_AGCREF_LEVEL_MINUS87 0x07 576 | #define RF_AGCREF_LEVEL_MINUS88 0x08 577 | #define RF_AGCREF_LEVEL_MINUS89 0x09 578 | #define RF_AGCREF_LEVEL_MINUS90 0x0A 579 | #define RF_AGCREF_LEVEL_MINUS91 0x0B 580 | #define RF_AGCREF_LEVEL_MINUS92 0x0C 581 | #define RF_AGCREF_LEVEL_MINUS93 0x0D 582 | #define RF_AGCREF_LEVEL_MINUS94 0x0E 583 | #define RF_AGCREF_LEVEL_MINUS95 0x0F 584 | #define RF_AGCREF_LEVEL_MINUS96 0x10 585 | #define RF_AGCREF_LEVEL_MINUS97 0x11 586 | #define RF_AGCREF_LEVEL_MINUS98 0x12 587 | #define RF_AGCREF_LEVEL_MINUS99 0x13 588 | #define RF_AGCREF_LEVEL_MINUS100 0x14 589 | #define RF_AGCREF_LEVEL_MINUS101 0x15 590 | #define RF_AGCREF_LEVEL_MINUS102 0x16 591 | #define RF_AGCREF_LEVEL_MINUS103 0x17 592 | #define RF_AGCREF_LEVEL_MINUS104 0x18 593 | #define RF_AGCREF_LEVEL_MINUS105 0x19 594 | #define RF_AGCREF_LEVEL_MINUS106 0x1A 595 | #define RF_AGCREF_LEVEL_MINUS107 0x1B 596 | #define RF_AGCREF_LEVEL_MINUS108 0x1C 597 | #define RF_AGCREF_LEVEL_MINUS109 0x1D 598 | #define RF_AGCREF_LEVEL_MINUS110 0x1E 599 | #define RF_AGCREF_LEVEL_MINUS111 0x1F 600 | #define RF_AGCREF_LEVEL_MINUS112 0x20 601 | #define RF_AGCREF_LEVEL_MINUS113 0x21 602 | #define RF_AGCREF_LEVEL_MINUS114 0x22 603 | #define RF_AGCREF_LEVEL_MINUS115 0x23 604 | #define RF_AGCREF_LEVEL_MINUS116 0x24 605 | #define RF_AGCREF_LEVEL_MINUS117 0x25 606 | #define RF_AGCREF_LEVEL_MINUS118 0x26 607 | #define RF_AGCREF_LEVEL_MINUS119 0x27 608 | #define RF_AGCREF_LEVEL_MINUS120 0x28 609 | #define RF_AGCREF_LEVEL_MINUS121 0x29 610 | #define RF_AGCREF_LEVEL_MINUS122 0x2A 611 | #define RF_AGCREF_LEVEL_MINUS123 0x2B 612 | #define RF_AGCREF_LEVEL_MINUS124 0x2C 613 | #define RF_AGCREF_LEVEL_MINUS125 0x2D 614 | #define RF_AGCREF_LEVEL_MINUS126 0x2E 615 | #define RF_AGCREF_LEVEL_MINUS127 0x2F 616 | #define RF_AGCREF_LEVEL_MINUS128 0x30 617 | #define RF_AGCREF_LEVEL_MINUS129 0x31 618 | #define RF_AGCREF_LEVEL_MINUS130 0x32 619 | #define RF_AGCREF_LEVEL_MINUS131 0x33 620 | #define RF_AGCREF_LEVEL_MINUS132 0x34 621 | #define RF_AGCREF_LEVEL_MINUS133 0x35 622 | #define RF_AGCREF_LEVEL_MINUS134 0x36 623 | #define RF_AGCREF_LEVEL_MINUS135 0x37 624 | #define RF_AGCREF_LEVEL_MINUS136 0x38 625 | #define RF_AGCREF_LEVEL_MINUS137 0x39 626 | #define RF_AGCREF_LEVEL_MINUS138 0x3A 627 | #define RF_AGCREF_LEVEL_MINUS139 0x3B 628 | #define RF_AGCREF_LEVEL_MINUS140 0x3C 629 | #define RF_AGCREF_LEVEL_MINUS141 0x3D 630 | #define RF_AGCREF_LEVEL_MINUS142 0x3E 631 | #define RF_AGCREF_LEVEL_MINUS143 0x3F 632 | 633 | 634 | // RegAgcThresh1 - not present on RFM69/SX1231 635 | #define RF_AGCTHRESH1_SNRMARGIN_000 0x00 636 | #define RF_AGCTHRESH1_SNRMARGIN_001 0x20 637 | #define RF_AGCTHRESH1_SNRMARGIN_010 0x40 638 | #define RF_AGCTHRESH1_SNRMARGIN_011 0x60 639 | #define RF_AGCTHRESH1_SNRMARGIN_100 0x80 640 | #define RF_AGCTHRESH1_SNRMARGIN_101 0xA0 // Default 641 | #define RF_AGCTHRESH1_SNRMARGIN_110 0xC0 642 | #define RF_AGCTHRESH1_SNRMARGIN_111 0xE0 643 | 644 | #define RF_AGCTHRESH1_STEP1_0 0x00 645 | #define RF_AGCTHRESH1_STEP1_1 0x01 646 | #define RF_AGCTHRESH1_STEP1_2 0x02 647 | #define RF_AGCTHRESH1_STEP1_3 0x03 648 | #define RF_AGCTHRESH1_STEP1_4 0x04 649 | #define RF_AGCTHRESH1_STEP1_5 0x05 650 | #define RF_AGCTHRESH1_STEP1_6 0x06 651 | #define RF_AGCTHRESH1_STEP1_7 0x07 652 | #define RF_AGCTHRESH1_STEP1_8 0x08 653 | #define RF_AGCTHRESH1_STEP1_9 0x09 654 | #define RF_AGCTHRESH1_STEP1_10 0x0A 655 | #define RF_AGCTHRESH1_STEP1_11 0x0B 656 | #define RF_AGCTHRESH1_STEP1_12 0x0C 657 | #define RF_AGCTHRESH1_STEP1_13 0x0D 658 | #define RF_AGCTHRESH1_STEP1_14 0x0E 659 | #define RF_AGCTHRESH1_STEP1_15 0x0F 660 | #define RF_AGCTHRESH1_STEP1_16 0x10 // Default 661 | #define RF_AGCTHRESH1_STEP1_17 0x11 662 | #define RF_AGCTHRESH1_STEP1_18 0x12 663 | #define RF_AGCTHRESH1_STEP1_19 0x13 664 | #define RF_AGCTHRESH1_STEP1_20 0x14 665 | #define RF_AGCTHRESH1_STEP1_21 0x15 666 | #define RF_AGCTHRESH1_STEP1_22 0x16 667 | #define RF_AGCTHRESH1_STEP1_23 0x17 668 | #define RF_AGCTHRESH1_STEP1_24 0x18 669 | #define RF_AGCTHRESH1_STEP1_25 0x19 670 | #define RF_AGCTHRESH1_STEP1_26 0x1A 671 | #define RF_AGCTHRESH1_STEP1_27 0x1B 672 | #define RF_AGCTHRESH1_STEP1_28 0x1C 673 | #define RF_AGCTHRESH1_STEP1_29 0x1D 674 | #define RF_AGCTHRESH1_STEP1_30 0x1E 675 | #define RF_AGCTHRESH1_STEP1_31 0x1F 676 | 677 | 678 | // RegAgcThresh2 - not present on RFM69/SX1231 679 | #define RF_AGCTHRESH2_STEP2_0 0x00 680 | #define RF_AGCTHRESH2_STEP2_1 0x10 681 | #define RF_AGCTHRESH2_STEP2_2 0x20 682 | #define RF_AGCTHRESH2_STEP2_3 0x30 // XXX wrong -- Default 683 | #define RF_AGCTHRESH2_STEP2_4 0x40 684 | #define RF_AGCTHRESH2_STEP2_5 0x50 685 | #define RF_AGCTHRESH2_STEP2_6 0x60 686 | #define RF_AGCTHRESH2_STEP2_7 0x70 // default 687 | #define RF_AGCTHRESH2_STEP2_8 0x80 688 | #define RF_AGCTHRESH2_STEP2_9 0x90 689 | #define RF_AGCTHRESH2_STEP2_10 0xA0 690 | #define RF_AGCTHRESH2_STEP2_11 0xB0 691 | #define RF_AGCTHRESH2_STEP2_12 0xC0 692 | #define RF_AGCTHRESH2_STEP2_13 0xD0 693 | #define RF_AGCTHRESH2_STEP2_14 0xE0 694 | #define RF_AGCTHRESH2_STEP2_15 0xF0 695 | 696 | #define RF_AGCTHRESH2_STEP3_0 0x00 697 | #define RF_AGCTHRESH2_STEP3_1 0x01 698 | #define RF_AGCTHRESH2_STEP3_2 0x02 699 | #define RF_AGCTHRESH2_STEP3_3 0x03 700 | #define RF_AGCTHRESH2_STEP3_4 0x04 701 | #define RF_AGCTHRESH2_STEP3_5 0x05 702 | #define RF_AGCTHRESH2_STEP3_6 0x06 703 | #define RF_AGCTHRESH2_STEP3_7 0x07 704 | #define RF_AGCTHRESH2_STEP3_8 0x08 705 | #define RF_AGCTHRESH2_STEP3_9 0x09 706 | #define RF_AGCTHRESH2_STEP3_10 0x0A 707 | #define RF_AGCTHRESH2_STEP3_11 0x0B // Default 708 | #define RF_AGCTHRESH2_STEP3_12 0x0C 709 | #define RF_AGCTHRESH2_STEP3_13 0x0D 710 | #define RF_AGCTHRESH2_STEP3_14 0x0E 711 | #define RF_AGCTHRESH2_STEP3_15 0x0F 712 | 713 | 714 | // RegAgcThresh3 - not present on RFM69/SX1231 715 | #define RF_AGCTHRESH3_STEP4_0 0x00 716 | #define RF_AGCTHRESH3_STEP4_1 0x10 717 | #define RF_AGCTHRESH3_STEP4_2 0x20 718 | #define RF_AGCTHRESH3_STEP4_3 0x30 719 | #define RF_AGCTHRESH3_STEP4_4 0x40 720 | #define RF_AGCTHRESH3_STEP4_5 0x50 721 | #define RF_AGCTHRESH3_STEP4_6 0x60 722 | #define RF_AGCTHRESH3_STEP4_7 0x70 723 | #define RF_AGCTHRESH3_STEP4_8 0x80 724 | #define RF_AGCTHRESH3_STEP4_9 0x90 // Default 725 | #define RF_AGCTHRESH3_STEP4_10 0xA0 726 | #define RF_AGCTHRESH3_STEP4_11 0xB0 727 | #define RF_AGCTHRESH3_STEP4_12 0xC0 728 | #define RF_AGCTHRESH3_STEP4_13 0xD0 729 | #define RF_AGCTHRESH3_STEP4_14 0xE0 730 | #define RF_AGCTHRESH3_STEP4_15 0xF0 731 | 732 | #define RF_AGCTHRESH3_STEP5_0 0x00 733 | #define RF_AGCTHRESH3_STEP5_1 0x01 734 | #define RF_AGCTHRESH3_STEP5_2 0x02 735 | #define RF_AGCTHRESH3_STEP5_3 0x03 736 | #define RF_AGCTHRESH3_STEP5_4 0x04 737 | #define RF_AGCTHRESH3_STEP5_5 0x05 738 | #define RF_AGCTHRESH3_STEP5_6 0x06 739 | #define RF_AGCTHRESH3_STEP5_7 0x07 740 | #define RF_AGCTHRES33_STEP5_8 0x08 741 | #define RF_AGCTHRESH3_STEP5_9 0x09 742 | #define RF_AGCTHRESH3_STEP5_10 0x0A 743 | #define RF_AGCTHRESH3_STEP5_11 0x0B // Default 744 | #define RF_AGCTHRESH3_STEP5_12 0x0C 745 | #define RF_AGCTHRESH3_STEP5_13 0x0D 746 | #define RF_AGCTHRESH3_STEP5_14 0x0E 747 | #define RF_AGCTHRESH3_STEP5_15 0x0F 748 | 749 | 750 | // RegLna 751 | #define RF_LNA_ZIN_50 0x00 // Reset value 752 | #define RF_LNA_ZIN_200 0x80 // Recommended default 753 | 754 | #define RF_LNA_LOWPOWER_OFF 0x00 // Default 755 | #define RF_LNA_LOWPOWER_ON 0x40 756 | 757 | #define RF_LNA_CURRENTGAIN 0x08 758 | 759 | #define RF_LNA_GAINSELECT_AUTO 0x00 // Default 760 | #define RF_LNA_GAINSELECT_MAX 0x01 761 | #define RF_LNA_GAINSELECT_MAXMINUS6 0x02 762 | #define RF_LNA_GAINSELECT_MAXMINUS12 0x03 763 | #define RF_LNA_GAINSELECT_MAXMINUS24 0x04 764 | #define RF_LNA_GAINSELECT_MAXMINUS36 0x05 765 | #define RF_LNA_GAINSELECT_MAXMINUS48 0x06 766 | 767 | 768 | // RegRxBw 769 | #define RF_RXBW_DCCFREQ_000 0x00 770 | #define RF_RXBW_DCCFREQ_001 0x20 771 | #define RF_RXBW_DCCFREQ_010 0x40 // Recommended default 772 | #define RF_RXBW_DCCFREQ_011 0x60 773 | #define RF_RXBW_DCCFREQ_100 0x80 // Reset value 774 | #define RF_RXBW_DCCFREQ_101 0xA0 775 | #define RF_RXBW_DCCFREQ_110 0xC0 776 | #define RF_RXBW_DCCFREQ_111 0xE0 777 | 778 | #define RF_RXBW_MANT_16 0x00 // Reset value 779 | #define RF_RXBW_MANT_20 0x08 780 | #define RF_RXBW_MANT_24 0x10 // Recommended default 781 | 782 | #define RF_RXBW_EXP_0 0x00 783 | #define RF_RXBW_EXP_1 0x01 784 | #define RF_RXBW_EXP_2 0x02 785 | #define RF_RXBW_EXP_3 0x03 786 | #define RF_RXBW_EXP_4 0x04 787 | #define RF_RXBW_EXP_5 0x05 // Recommended default 788 | #define RF_RXBW_EXP_6 0x06 // Reset value 789 | #define RF_RXBW_EXP_7 0x07 790 | 791 | 792 | // RegAfcBw 793 | #define RF_AFCBW_DCCFREQAFC_000 0x00 794 | #define RF_AFCBW_DCCFREQAFC_001 0x20 795 | #define RF_AFCBW_DCCFREQAFC_010 0x40 796 | #define RF_AFCBW_DCCFREQAFC_011 0x60 797 | #define RF_AFCBW_DCCFREQAFC_100 0x80 // Default 798 | #define RF_AFCBW_DCCFREQAFC_101 0xA0 799 | #define RF_AFCBW_DCCFREQAFC_110 0xC0 800 | #define RF_AFCBW_DCCFREQAFC_111 0xE0 801 | 802 | #define RF_AFCBW_MANTAFC_16 0x00 803 | #define RF_AFCBW_MANTAFC_20 0x08 // Default 804 | #define RF_AFCBW_MANTAFC_24 0x10 805 | 806 | #define RF_AFCBW_EXPAFC_0 0x00 807 | #define RF_AFCBW_EXPAFC_1 0x01 808 | #define RF_AFCBW_EXPAFC_2 0x02 // Reset value 809 | #define RF_AFCBW_EXPAFC_3 0x03 // Recommended default 810 | #define RF_AFCBW_EXPAFC_4 0x04 811 | #define RF_AFCBW_EXPAFC_5 0x05 812 | #define RF_AFCBW_EXPAFC_6 0x06 813 | #define RF_AFCBW_EXPAFC_7 0x07 814 | 815 | 816 | // RegOokPeak 817 | #define RF_OOKPEAK_THRESHTYPE_FIXED 0x00 818 | #define RF_OOKPEAK_THRESHTYPE_PEAK 0x40 // Default 819 | #define RF_OOKPEAK_THRESHTYPE_AVERAGE 0x80 820 | 821 | #define RF_OOKPEAK_PEAKTHRESHSTEP_000 0x00 // Default 822 | #define RF_OOKPEAK_PEAKTHRESHSTEP_001 0x08 823 | #define RF_OOKPEAK_PEAKTHRESHSTEP_010 0x10 824 | #define RF_OOKPEAK_PEAKTHRESHSTEP_011 0x18 825 | #define RF_OOKPEAK_PEAKTHRESHSTEP_100 0x20 826 | #define RF_OOKPEAK_PEAKTHRESHSTEP_101 0x28 827 | #define RF_OOKPEAK_PEAKTHRESHSTEP_110 0x30 828 | #define RF_OOKPEAK_PEAKTHRESHSTEP_111 0x38 829 | 830 | #define RF_OOKPEAK_PEAKTHRESHDEC_000 0x00 // Default 831 | #define RF_OOKPEAK_PEAKTHRESHDEC_001 0x01 832 | #define RF_OOKPEAK_PEAKTHRESHDEC_010 0x02 833 | #define RF_OOKPEAK_PEAKTHRESHDEC_011 0x03 834 | #define RF_OOKPEAK_PEAKTHRESHDEC_100 0x04 835 | #define RF_OOKPEAK_PEAKTHRESHDEC_101 0x05 836 | #define RF_OOKPEAK_PEAKTHRESHDEC_110 0x06 837 | #define RF_OOKPEAK_PEAKTHRESHDEC_111 0x07 838 | 839 | 840 | // RegOokAvg 841 | #define RF_OOKAVG_AVERAGETHRESHFILT_00 0x00 842 | #define RF_OOKAVG_AVERAGETHRESHFILT_01 0x40 843 | #define RF_OOKAVG_AVERAGETHRESHFILT_10 0x80 // Default 844 | #define RF_OOKAVG_AVERAGETHRESHFILT_11 0xC0 845 | 846 | 847 | // RegOokFix 848 | #define RF_OOKFIX_FIXEDTHRESH_VALUE 0x06 // Default 849 | 850 | 851 | // RegAfcFei 852 | #define RF_AFCFEI_FEI_DONE 0x40 853 | #define RF_AFCFEI_FEI_START 0x20 854 | #define RF_AFCFEI_AFC_DONE 0x10 855 | #define RF_AFCFEI_AFCAUTOCLEAR_ON 0x08 856 | #define RF_AFCFEI_AFCAUTOCLEAR_OFF 0x00 // Default 857 | 858 | #define RF_AFCFEI_AFCAUTO_ON 0x04 859 | #define RF_AFCFEI_AFCAUTO_OFF 0x00 // Default 860 | 861 | #define RF_AFCFEI_AFC_CLEAR 0x02 862 | #define RF_AFCFEI_AFC_START 0x01 863 | 864 | 865 | // RegRssiConfig 866 | #define RF_RSSI_FASTRX_ON 0x08 // not present on RFM69/SX1231 867 | #define RF_RSSI_FASTRX_OFF 0x00 // Default 868 | 869 | #define RF_RSSI_DONE 0x02 870 | #define RF_RSSI_START 0x01 871 | 872 | 873 | // RegDioMapping1 874 | #define RF_DIOMAPPING1_DIO0_00 0x00 // Default 875 | #define RF_DIOMAPPING1_DIO0_01 0x40 876 | #define RF_DIOMAPPING1_DIO0_10 0x80 877 | #define RF_DIOMAPPING1_DIO0_11 0xC0 878 | 879 | #define RF_DIOMAPPING1_DIO1_00 0x00 // Default 880 | #define RF_DIOMAPPING1_DIO1_01 0x10 881 | #define RF_DIOMAPPING1_DIO1_10 0x20 882 | #define RF_DIOMAPPING1_DIO1_11 0x30 883 | 884 | #define RF_DIOMAPPING1_DIO2_00 0x00 // Default 885 | #define RF_DIOMAPPING1_DIO2_01 0x04 886 | #define RF_DIOMAPPING1_DIO2_10 0x08 887 | #define RF_DIOMAPPING1_DIO2_11 0x0C 888 | 889 | #define RF_DIOMAPPING1_DIO3_00 0x00 // Default 890 | #define RF_DIOMAPPING1_DIO3_01 0x01 891 | #define RF_DIOMAPPING1_DIO3_10 0x02 892 | #define RF_DIOMAPPING1_DIO3_11 0x03 893 | 894 | 895 | // RegDioMapping2 896 | #define RF_DIOMAPPING2_DIO4_00 0x00 // Default 897 | #define RF_DIOMAPPING2_DIO4_01 0x40 898 | #define RF_DIOMAPPING2_DIO4_10 0x80 899 | #define RF_DIOMAPPING2_DIO4_11 0xC0 900 | 901 | #define RF_DIOMAPPING2_DIO5_00 0x00 // Default 902 | #define RF_DIOMAPPING2_DIO5_01 0x10 903 | #define RF_DIOMAPPING2_DIO5_10 0x20 904 | #define RF_DIOMAPPING2_DIO5_11 0x30 905 | 906 | #define RF_DIOMAPPING2_CLKOUT_32 0x00 907 | #define RF_DIOMAPPING2_CLKOUT_16 0x01 908 | #define RF_DIOMAPPING2_CLKOUT_8 0x02 909 | #define RF_DIOMAPPING2_CLKOUT_4 0x03 910 | #define RF_DIOMAPPING2_CLKOUT_2 0x04 911 | #define RF_DIOMAPPING2_CLKOUT_1 0x05 // Reset value 912 | #define RF_DIOMAPPING2_CLKOUT_RC 0x06 913 | #define RF_DIOMAPPING2_CLKOUT_OFF 0x07 // Recommended default 914 | 915 | 916 | // RegIrqFlags1 917 | #define RF_IRQFLAGS1_MODEREADY 0x80 918 | #define RF_IRQFLAGS1_RXREADY 0x40 919 | #define RF_IRQFLAGS1_TXREADY 0x20 920 | #define RF_IRQFLAGS1_PLLLOCK 0x10 921 | #define RF_IRQFLAGS1_RSSI 0x08 922 | #define RF_IRQFLAGS1_TIMEOUT 0x04 923 | #define RF_IRQFLAGS1_AUTOMODE 0x02 924 | #define RF_IRQFLAGS1_SYNCADDRESSMATCH 0x01 925 | 926 | 927 | // RegIrqFlags2 928 | #define RF_IRQFLAGS2_FIFOFULL 0x80 929 | #define RF_IRQFLAGS2_FIFONOTEMPTY 0x40 930 | #define RF_IRQFLAGS2_FIFOLEVEL 0x20 931 | #define RF_IRQFLAGS2_FIFOOVERRUN 0x10 932 | #define RF_IRQFLAGS2_PACKETSENT 0x08 933 | #define RF_IRQFLAGS2_PAYLOADREADY 0x04 934 | #define RF_IRQFLAGS2_CRCOK 0x02 935 | #define RF_IRQFLAGS2_LOWBAT 0x01 // not present on RFM69/SX1231 936 | 937 | 938 | // RegRssiThresh 939 | #define RF_RSSITHRESH_VALUE 0xE4 // Default 940 | 941 | 942 | // RegRxTimeout1 943 | #define RF_RXTIMEOUT1_RXSTART_VALUE 0x00 // Default 944 | 945 | 946 | // RegRxTimeout2 947 | #define RF_RXTIMEOUT2_RSSITHRESH_VALUE 0x00 // Default 948 | 949 | 950 | // RegPreamble 951 | #define RF_PREAMBLESIZE_MSB_VALUE 0x00 // Default 952 | #define RF_PREAMBLESIZE_LSB_VALUE 0x03 // Default 953 | 954 | 955 | // RegSyncConfig 956 | #define RF_SYNC_ON 0x80 // Default 957 | #define RF_SYNC_OFF 0x00 958 | 959 | #define RF_SYNC_FIFOFILL_AUTO 0x00 // Default -- when sync interrupt occurs 960 | #define RF_SYNC_FIFOFILL_MANUAL 0x40 961 | 962 | #define RF_SYNC_SIZE_1 0x00 963 | #define RF_SYNC_SIZE_2 0x08 964 | #define RF_SYNC_SIZE_3 0x10 965 | #define RF_SYNC_SIZE_4 0x18 // Default 966 | #define RF_SYNC_SIZE_5 0x20 967 | #define RF_SYNC_SIZE_6 0x28 968 | #define RF_SYNC_SIZE_7 0x30 969 | #define RF_SYNC_SIZE_8 0x38 970 | 971 | #define RF_SYNC_TOL_0 0x00 // Default 972 | #define RF_SYNC_TOL_1 0x01 973 | #define RF_SYNC_TOL_2 0x02 974 | #define RF_SYNC_TOL_3 0x03 975 | #define RF_SYNC_TOL_4 0x04 976 | #define RF_SYNC_TOL_5 0x05 977 | #define RF_SYNC_TOL_6 0x06 978 | #define RF_SYNC_TOL_7 0x07 979 | 980 | 981 | // RegSyncValue1-8 982 | #define RF_SYNC_BYTE1_VALUE 0x00 // Default 983 | #define RF_SYNC_BYTE2_VALUE 0x00 // Default 984 | #define RF_SYNC_BYTE3_VALUE 0x00 // Default 985 | #define RF_SYNC_BYTE4_VALUE 0x00 // Default 986 | #define RF_SYNC_BYTE5_VALUE 0x00 // Default 987 | #define RF_SYNC_BYTE6_VALUE 0x00 // Default 988 | #define RF_SYNC_BYTE7_VALUE 0x00 // Default 989 | #define RF_SYNC_BYTE8_VALUE 0x00 // Default 990 | 991 | 992 | // RegPacketConfig1 993 | #define RF_PACKET1_FORMAT_FIXED 0x00 // Default 994 | #define RF_PACKET1_FORMAT_VARIABLE 0x80 995 | 996 | #define RF_PACKET1_DCFREE_OFF 0x00 // Default 997 | #define RF_PACKET1_DCFREE_MANCHESTER 0x20 998 | #define RF_PACKET1_DCFREE_WHITENING 0x40 999 | 1000 | #define RF_PACKET1_CRC_ON 0x10 // Default 1001 | #define RF_PACKET1_CRC_OFF 0x00 1002 | 1003 | #define RF_PACKET1_CRCAUTOCLEAR_ON 0x00 // Default 1004 | #define RF_PACKET1_CRCAUTOCLEAR_OFF 0x08 1005 | 1006 | #define RF_PACKET1_ADRSFILTERING_OFF 0x00 // Default 1007 | #define RF_PACKET1_ADRSFILTERING_NODE 0x02 1008 | #define RF_PACKET1_ADRSFILTERING_NODEBROADCAST 0x04 1009 | 1010 | 1011 | // RegPayloadLength 1012 | #define RF_PAYLOADLENGTH_VALUE 0x40 // Default 1013 | 1014 | 1015 | // RegBroadcastAdrs 1016 | #define RF_BROADCASTADDRESS_VALUE 0x00 1017 | 1018 | 1019 | // RegAutoModes 1020 | #define RF_AUTOMODES_ENTER_OFF 0x00 // Default 1021 | #define RF_AUTOMODES_ENTER_FIFONOTEMPTY 0x20 1022 | #define RF_AUTOMODES_ENTER_FIFOLEVEL 0x40 1023 | #define RF_AUTOMODES_ENTER_CRCOK 0x60 1024 | #define RF_AUTOMODES_ENTER_PAYLOADREADY 0x80 1025 | #define RF_AUTOMODES_ENTER_SYNCADRSMATCH 0xA0 1026 | #define RF_AUTOMODES_ENTER_PACKETSENT 0xC0 1027 | #define RF_AUTOMODES_ENTER_FIFOEMPTY 0xE0 1028 | 1029 | #define RF_AUTOMODES_EXIT_OFF 0x00 // Default 1030 | #define RF_AUTOMODES_EXIT_FIFOEMPTY 0x04 1031 | #define RF_AUTOMODES_EXIT_FIFOLEVEL 0x08 1032 | #define RF_AUTOMODES_EXIT_CRCOK 0x0C 1033 | #define RF_AUTOMODES_EXIT_PAYLOADREADY 0x10 1034 | #define RF_AUTOMODES_EXIT_SYNCADRSMATCH 0x14 1035 | #define RF_AUTOMODES_EXIT_PACKETSENT 0x18 1036 | #define RF_AUTOMODES_EXIT_RXTIMEOUT 0x1C 1037 | 1038 | #define RF_AUTOMODES_INTERMEDIATE_SLEEP 0x00 // Default 1039 | #define RF_AUTOMODES_INTERMEDIATE_STANDBY 0x01 1040 | #define RF_AUTOMODES_INTERMEDIATE_RECEIVER 0x02 1041 | #define RF_AUTOMODES_INTERMEDIATE_TRANSMITTER 0x03 1042 | 1043 | 1044 | // RegFifoThresh 1045 | #define RF_FIFOTHRESH_TXSTART_FIFOTHRESH 0x00 // Reset value 1046 | #define RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY 0x80 // Recommended default 1047 | 1048 | #define RF_FIFOTHRESH_VALUE 0x0F // Default 1049 | 1050 | 1051 | // RegPacketConfig2 1052 | #define RF_PACKET2_RXRESTARTDELAY_1BIT 0x00 // Default 1053 | #define RF_PACKET2_RXRESTARTDELAY_2BITS 0x10 1054 | #define RF_PACKET2_RXRESTARTDELAY_4BITS 0x20 1055 | #define RF_PACKET2_RXRESTARTDELAY_8BITS 0x30 1056 | #define RF_PACKET2_RXRESTARTDELAY_16BITS 0x40 1057 | #define RF_PACKET2_RXRESTARTDELAY_32BITS 0x50 1058 | #define RF_PACKET2_RXRESTARTDELAY_64BITS 0x60 1059 | #define RF_PACKET2_RXRESTARTDELAY_128BITS 0x70 1060 | #define RF_PACKET2_RXRESTARTDELAY_256BITS 0x80 1061 | #define RF_PACKET2_RXRESTARTDELAY_512BITS 0x90 1062 | #define RF_PACKET2_RXRESTARTDELAY_1024BITS 0xA0 1063 | #define RF_PACKET2_RXRESTARTDELAY_2048BITS 0xB0 1064 | #define RF_PACKET2_RXRESTARTDELAY_NONE 0xC0 1065 | #define RF_PACKET2_RXRESTART 0x04 1066 | 1067 | #define RF_PACKET2_AUTORXRESTART_ON 0x02 // Default 1068 | #define RF_PACKET2_AUTORXRESTART_OFF 0x00 1069 | 1070 | #define RF_PACKET2_AES_ON 0x01 1071 | #define RF_PACKET2_AES_OFF 0x00 // Default 1072 | 1073 | 1074 | // RegAesKey1-16 1075 | #define RF_AESKEY1_VALUE 0x00 // Default 1076 | #define RF_AESKEY2_VALUE 0x00 // Default 1077 | #define RF_AESKEY3_VALUE 0x00 // Default 1078 | #define RF_AESKEY4_VALUE 0x00 // Default 1079 | #define RF_AESKEY5_VALUE 0x00 // Default 1080 | #define RF_AESKEY6_VALUE 0x00 // Default 1081 | #define RF_AESKEY7_VALUE 0x00 // Default 1082 | #define RF_AESKEY8_VALUE 0x00 // Default 1083 | #define RF_AESKEY9_VALUE 0x00 // Default 1084 | #define RF_AESKEY10_VALUE 0x00 // Default 1085 | #define RF_AESKEY11_VALUE 0x00 // Default 1086 | #define RF_AESKEY12_VALUE 0x00 // Default 1087 | #define RF_AESKEY13_VALUE 0x00 // Default 1088 | #define RF_AESKEY14_VALUE 0x00 // Default 1089 | #define RF_AESKEY15_VALUE 0x00 // Default 1090 | #define RF_AESKEY16_VALUE 0x00 // Default 1091 | 1092 | 1093 | // RegTemp1 1094 | #define RF_TEMP1_MEAS_START 0x08 1095 | #define RF_TEMP1_MEAS_RUNNING 0x04 1096 | // not present on RFM69/SX1231 1097 | #define RF_TEMP1_ADCLOWPOWER_ON 0x01 // Default 1098 | #define RF_TEMP1_ADCLOWPOWER_OFF 0x00 1099 | 1100 | 1101 | // RegTestLna 1102 | #define RF_TESTLNA_NORMAL 0x1B 1103 | #define RF_TESTLNA_HIGH_SENSITIVITY 0x2D 1104 | 1105 | 1106 | // RegTestDagc 1107 | #define RF_DAGC_NORMAL 0x00 // Reset value 1108 | #define RF_DAGC_IMPROVED_LOWBETA1 0x20 1109 | #define RF_DAGC_IMPROVED_LOWBETA0 0x30 // Recommended default 1110 | --------------------------------------------------------------------------------