├── README.md ├── LICENSE ├── loratest.ino ├── rf95_server └── rf95_server.ino ├── rf95_client └── rf95_client.ino └── rf95_ping └── rf95_ping.ino /README.md: -------------------------------------------------------------------------------- 1 | # loratest 2 | Arduino project for a transmitter and receiver using the RadioHead library with RFM95W modules 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Bertrik Sikken 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /loratest.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple test application, sends a ASCII sentence using an RFM95 module. 3 | * 4 | * The sentence is sent with parameters that allow it to be received using 5 | * the LoRa plugin in sdrangelove. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | // Singleton instance of the radio driver 12 | static RH_RF95 rf95; 13 | 14 | void setup() 15 | { 16 | Serial.begin(9600); 17 | Serial.println("LoRa test application"); 18 | if (!rf95.init()) { 19 | Serial.println("RF95 init failed!"); 20 | } 21 | 22 | rf95.setFrequency(869.850); 23 | const RH_RF95::ModemConfig cfg = { 24 | // Register 0x1D: 25 | // BW CR 1=implicit 26 | (0 << 4) | (2 << 1) | (1 << 0), 27 | // Register 0x1E: 28 | // SF 29 | (8 << 4), 30 | // Register 0x26: 31 | // bit3 = LowDataRateOptimization 32 | (1 << 3) 33 | }; 34 | rf95.setModemRegisters(&cfg); 35 | rf95.setPreambleLength(8); 36 | rf95.setTxPower(0); 37 | } 38 | 39 | void loop() 40 | { 41 | // send the LoRa message 42 | char data[] = "Hello World!"; 43 | unsigned long txstart = millis(); 44 | Serial.print("Sending: "); 45 | Serial.println(data); 46 | rf95.send((uint8_t *)data, sizeof(data)); 47 | rf95.waitPacketSent(); 48 | 49 | // wait some time 50 | unsigned long waittime = 10L * (millis() - txstart); 51 | delay(waittime); 52 | } 53 | 54 | -------------------------------------------------------------------------------- /rf95_server/rf95_server.ino: -------------------------------------------------------------------------------- 1 | // rf95_server.pde 2 | // -*- mode: C++ -*- 3 | // Example sketch showing how to create a simple messageing server 4 | // with the RH_RF95 class. RH_RF95 class does not provide for addressing or 5 | // reliability, so you should only use RH_RF95 if you do not need the higher 6 | // level messaging abilities. 7 | // It is designed to work with the other example rf95_client 8 | // Tested with Anarduino MiniWirelessLoRa 9 | 10 | 11 | #include 12 | #include 13 | 14 | // Singleton instance of the radio driver 15 | RH_RF95 rf95; 16 | 17 | void setup() 18 | { 19 | Serial.begin(9600); 20 | Serial.println("Hello World from Server!"); 21 | if (!rf95.init()) 22 | Serial.println("init failed"); 23 | // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on 24 | rf95.setFrequency(869.525); 25 | const RH_RF95::ModemConfig cfg = {0x88, 0xB4, 0x00}; 26 | rf95.setModemRegisters(&cfg); 27 | // rf95.setModemConfig(RH_RF95::Bw125Cr48Sf4096); 28 | } 29 | 30 | void loop() 31 | { 32 | if (rf95.available()) 33 | { 34 | // Should be a message for us now 35 | uint8_t buf[RH_RF95_MAX_MESSAGE_LEN]; 36 | uint8_t len = sizeof(buf); 37 | if (rf95.recv(buf, &len)) 38 | { 39 | RH_RF95::printBuffer("request: ", buf, len); 40 | Serial.print("got request: "); 41 | Serial.println((char*)buf); 42 | Serial.print("RSSI: "); 43 | Serial.println(rf95.lastRssi(), DEC); 44 | 45 | // Send a reply 46 | uint8_t data[] = "Oh HI!"; 47 | rf95.send(data, sizeof(data)); 48 | rf95.waitPacketSent(); 49 | Serial.println("Sent a reply"); 50 | } 51 | else 52 | { 53 | Serial.println("recv failed"); 54 | } 55 | } 56 | } 57 | 58 | 59 | -------------------------------------------------------------------------------- /rf95_client/rf95_client.ino: -------------------------------------------------------------------------------- 1 | // rf95_client.pde 2 | // -*- mode: C++ -*- 3 | // Example sketch showing how to create a simple messageing client 4 | // with the RH_RF95 class. RH_RF95 class does not provide for addressing or 5 | // reliability, so you should only use RH_RF95 if you do not need the higher 6 | // level messaging abilities. 7 | // It is designed to work with the other example rf95_server 8 | // Tested with Anarduino MiniWirelessLoRa 9 | 10 | #include 11 | #include 12 | 13 | // Singleton instance of the radio driver 14 | RH_RF95 rf95; 15 | 16 | void setup() 17 | { 18 | Serial.begin(9600); 19 | Serial.println("Hello World from Client!"); 20 | if (!rf95.init()) 21 | Serial.println("init failed"); 22 | // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on 23 | rf95.setFrequency(869.525); 24 | const RH_RF95::ModemConfig cfg = {0x88, 0xB4, 0x00}; 25 | rf95.setModemRegisters(&cfg); 26 | // rf95.setModemConfig(RH_RF95::Bw125Cr48Sf4096); 27 | } 28 | 29 | void loop() 30 | { 31 | Serial.println("Sending to rf95_server"); 32 | // Send a message to rf95_server 33 | uint8_t data[] = "Hello World!"; 34 | rf95.send(data, sizeof(data)); 35 | 36 | rf95.waitPacketSent(); 37 | 38 | // Now wait for a reply 39 | uint8_t buf[RH_RF95_MAX_MESSAGE_LEN]; 40 | uint8_t len = sizeof(buf); 41 | 42 | if (rf95.waitAvailableTimeout(5000)) 43 | { 44 | // Should be a reply message for us now 45 | if (rf95.recv(buf, &len)) 46 | { 47 | Serial.print("got reply: "); 48 | Serial.println((char*)buf); 49 | Serial.print("RSSI: "); 50 | Serial.println(rf95.lastRssi(), DEC); 51 | } 52 | else 53 | { 54 | Serial.println("recv failed"); 55 | } 56 | } 57 | else 58 | { 59 | Serial.println("No reply, is rf95_server running?"); 60 | } 61 | delay(2000); 62 | } 63 | 64 | 65 | -------------------------------------------------------------------------------- /rf95_ping/rf95_ping.ino: -------------------------------------------------------------------------------- 1 | // rf95_server.pde 2 | // -*- mode: C++ -*- 3 | // Example sketch showing how to create a simple messageing server 4 | // with the RH_RF95 class. RH_RF95 class does not provide for addressing or 5 | // reliability, so you should only use RH_RF95 if you do not need the higher 6 | // level messaging abilities. 7 | // It is designed to work with the other example rf95_client 8 | // Tested with Anarduino MiniWirelessLoRa 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | typedef struct { 15 | uint8_t type; 16 | uint8_t count; // counter 17 | uint8_t initiator, replier; 18 | int rssi; // signal strength 19 | } pingpong_t; 20 | 21 | // Singleton instance of the radio driver 22 | static RH_RF95 rf95; 23 | static pingpong_t ping; 24 | static pingpong_t pong; 25 | 26 | #define T_PING 1 27 | #define T_PONG 2 28 | 29 | void genId(const bool update) { 30 | const bool validMarker = EEPROM.read(1) == 123; 31 | 32 | if (validMarker && !update) 33 | ping.initiator = EEPROM.read(0); 34 | else { 35 | Serial.println(F("Update/set ID")); 36 | ping.initiator = rand(); 37 | if (!validMarker) 38 | EEPROM.write(1, 123); 39 | EEPROM.write(0, ping.initiator); 40 | delay(5); 41 | EEPROM.read(1); 42 | EEPROM.read(0); 43 | } 44 | } 45 | 46 | void setup() { 47 | Serial.begin(115200); 48 | Serial.println(F("Init LoRa test")); 49 | 50 | if (!rf95.init()) 51 | Serial.println(F("init failed")); 52 | // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on 53 | rf95.setFrequency(869.525); 54 | rf95.setModemConfig(RH_RF95::Bw125Cr48Sf4096); 55 | 56 | int r; 57 | for(uint8_t i=A0; i<=A7; i++) 58 | r ^= analogRead(i); 59 | srandom(r); 60 | srand(~r); 61 | 62 | // rf95.setTxPower(20); 63 | 64 | // init ping 65 | genId(false); 66 | ping.type = T_PING; 67 | ping.count = 0; 68 | ping.rssi = 0; 69 | pong.replier = -1; 70 | 71 | Serial.print(F("Hello World from ")); 72 | Serial.println(ping.initiator); 73 | 74 | pong.initiator = -1; 75 | pong.replier = ping.initiator; 76 | } 77 | 78 | static char line[128]; 79 | static uint8_t buf[RH_RF95_MAX_MESSAGE_LEN]; 80 | 81 | void loop() 82 | { 83 | // send a ping 84 | ping.count++; 85 | 86 | sprintf(line, "Sending PING(%d,%d) ...", ping.count, ping.rssi); 87 | Serial.println(line); 88 | 89 | rf95.send((uint8_t *)&ping, sizeof(ping)); 90 | rf95.waitPacketSent(); 91 | 92 | // wait some random time in reception mode 93 | unsigned long wait = random(1000, 5000); 94 | sprintf(line, "Listening for %lu ms ...", wait); 95 | Serial.println(line); 96 | 97 | unsigned long now = millis(); 98 | while (millis() - now < wait) { 99 | uint8_t len = sizeof buf; 100 | 101 | if (rf95.available()) { 102 | memset(buf, 0x00, sizeof buf); 103 | rf95.recv(buf, &len); 104 | 105 | if (len == sizeof(pong)) { 106 | memcpy(&pong, buf, sizeof(pong)); 107 | 108 | bool col = false; 109 | if (pong.type == T_PING) { 110 | col = pong.initiator == ping.initiator; 111 | // got ping 112 | sprintf(line, "Recv PING(%d,%d,%d)", pong.count, pong.rssi, pong.initiator); 113 | Serial.println(line); 114 | // send pong 115 | pong.type = T_PONG; 116 | pong.rssi = rf95.lastRssi(); 117 | pong.replier = ping.initiator; 118 | sprintf(line, "Send PONG(%d,%d,%d)", pong.count, pong.rssi, pong.replier); 119 | Serial.println(line); 120 | rf95.send((uint8_t *)&pong, sizeof(pong)); 121 | rf95.waitPacketSent(); 122 | } 123 | else if (pong.type == T_PONG) { 124 | col = pong.replier == ping.initiator; 125 | // got pong, print stats 126 | sprintf(line, "Got PONG(%d,%d,%d)", pong.count, pong.rssi, pong.replier); 127 | Serial.println(line); 128 | } 129 | else { 130 | sprintf(line, "???(%d,%d,%d,%d,%d)", pong.count, pong.rssi, pong.initiator, pong.replier, pong.type); 131 | Serial.println(line); 132 | } 133 | 134 | if (col) { 135 | sprintf(line, "ID COL: %d,%d", pong.initiator, pong.replier); 136 | if (pong.initiator == ping.initiator) { 137 | Serial.println(F("ID collision, force new")); 138 | genId(true); 139 | Serial.print(F("New ID:")); 140 | Serial.println(ping.initiator); 141 | } 142 | } 143 | } else { 144 | Serial.println(F("Got spurious message: ")); 145 | for(uint8_t i=0; i