diff --git a/examples/SodaqExplorer-p2p/SodaqExplorer-p2p.ino b/examples/SodaqExplorer-p2p/SodaqExplorer-p2p.ino new file mode 100644 index 0000000..09e6888 --- /dev/null +++ b/examples/SodaqExplorer-p2p/SodaqExplorer-p2p.ino @@ -0,0 +1,134 @@ +/* + * Basic sketch for connecting + * a Sodaq Explorer to another Sodaq Explorer + * + * Author: Dennis Ruigrok + */ + +#include + +// Explorer Serial port definitions. +#define debugSerial SerialUSB +#define loraSerial Serial2 + + +// create an instance of the Library. +rn2xx3 myLora(loraSerial); + + +void setup() +{ + // built_in led + pinMode(LED_BUILTIN, OUTPUT); + led_on(); + + // make sure usb serial connection is available, + // or after 10s go on anyway for 'headless' use of the + // node. + while ((!debugSerial) && (millis() < 10000)); + + // beginning serial connections. + debugSerial.begin(57600); + loraSerial.begin(57600); + + // + debugSerial.println(F("--------------------------------")); + debugSerial.println(F("Basic sketch for communicating ")); + debugSerial.println(F("with another Sodaq Explorer")); + debugSerial.println(F("--------------------------------")); + led_off(); + + initialize_radio(); + +} + +void initialize_radio() +{ + + myLora.autobaud(); + + debugSerial.println("DevEUI? ");debugSerial.print(F("> ")); + debugSerial.println(myLora.hweui()); + debugSerial.println("Version?");debugSerial.print(F("> ")); + debugSerial.println(myLora.sysver()); + debugSerial.println(F("--------------------------------")); + + debugSerial.println(F("Setting up for listening for another explorer")); + bool join_result = false; + + + // point to point + join_result = myLora.initP2P(); + + + debugSerial.println("\u2713 Successfully Activated radio 2 radio"); + + +} + + + + +void loop() +{ + debugSerial.print("TXing"); + myLora.txCnf("Can you hear me???"); //one byte, blocking function + + switch(myLora.txCnf("!")) //one byte, blocking function + { + case TX_FAIL: + { + debugSerial.println("TX unsuccessful or not acknowledged"); + break; + } + case TX_SUCCESS: + { + debugSerial.println("TX successful and acknowledged"); + break; + } + case TX_WITH_RX: + { + String received = myLora.getRx(); + received = myLora.base16decode(received); + debugSerial.print("Received downlink immediately: " + received); + break; + } + default: + { + debugSerial.println("Unknown response from TX function"); + } + } + + led_off(); + + for(int i = 0; i < 15000/500; i++) // 15 second listen then send ^ + switch(myLora.listenP2P()) { + case TX_WITH_RX: + { + String received = myLora.getRx(); + received = myLora.base16decode(received); + debugSerial.print("Received downlink: " + received); + break; + } + case RADIO_LISTEN_WITHOUT_RX: + { + debugSerial.println("Listened timeout but no downlink"); + break; + } + + + } + + +} + + +void led_on() +{ + digitalWrite(LED_BUILTIN, 1); +} + +void led_off() +{ + digitalWrite(LED_BUILTIN, 0); +} diff --git a/src/rn2xx3.cpp b/src/rn2xx3.cpp index 0e7aaad..e48a29d 100644 --- a/src/rn2xx3.cpp +++ b/src/rn2xx3.cpp @@ -92,6 +92,9 @@ String rn2xx3::deveui() bool rn2xx3::init() { + if(_radio2radio)sendRawCommand(F("mac resume")); + _radio2radio = false; + if(_appskey=="0") //appskey variable is set by both OTAA and ABP { return false; @@ -323,6 +326,85 @@ bool rn2xx3::initABP(String devAddr, String AppSKey, String NwkSKey) } } +bool rn2xx3::initP2P() { + sendRawCommand(F("sys reset")); + _radio2radio = true; + + String receivedData; + + //clear serial buffer + while(_serial.available()) + _serial.read(); + + configureModuleType(); + + sendRawCommand(F("mac pause")); + + sendRawCommand(F("radio set mod lora")); + + switch (_moduleType) { + case RN2903: + sendRawCommand(F("radio set freq 869100000")); + break; + case RN2483: + sendRawCommand(F("radio set freq 868000000")); + + break; + default: + // we shouldn't go forward with the init + return false; + } + + sendRawCommand(F("radio set pwr 14")); + + sendRawCommand(F("radio set sf sf7")); + + sendRawCommand(F("radio set afcbw 41.7")); + + sendRawCommand(F("radio set rxbw 125")); + + sendRawCommand(F("radio set prlen 8")); + + sendRawCommand(F("radio set crc on")); + + sendRawCommand(F("radio set iqi off")); + + sendRawCommand(F("radio set cr 4/5")); + + sendRawCommand(F("radio set sync 12")); + + sendRawCommand(F("radio set bw 125")); + + sendRawCommand(F("radio set wdt 500")); + + return true; +} + +TX_RETURN_TYPE rn2xx3::listenP2P() { + String receivedData; + bool mustStop = false; + + receivedData = sendRawCommand(F("radio rx 0")); // don't put this in receiveddata we want to ignore the first ok + while(!mustStop) { + receivedData = _serial.readStringUntil('\n'); + + if(receivedData.startsWith("radio_err")) { + return RADIO_LISTEN_WITHOUT_RX; // timeout + } else if(receivedData.startsWith("busy")) { + // just wait + } else if(receivedData.startsWith("radio_rx")) { + //example: radio_rx 54657374696E6720313233 + _rxMessenge = receivedData.substring(receivedData.indexOf(' ', 9)+1); + initP2P(); // to remove last messenge because it keeps repeating + return TX_WITH_RX; + } + + } + + + +} + TX_RETURN_TYPE rn2xx3::tx(String data) { return txUncnf(data); //we are unsure which mode we're in. Better not to wait for acks. @@ -371,10 +453,18 @@ TX_RETURN_TYPE rn2xx3::txCommand(String command, String data, bool shouldEncode) return TX_FAIL; } - _serial.print(command); + if(_radio2radio) { + command.replace("mac", "radio"); + command.replace("uncnf 1 ", ""); + command.replace("cnf 1 ", ""); + } + + + + _serial.print(command); if(shouldEncode) { - sendEncoded(data); + sendEncoded(data); } else { @@ -384,7 +474,9 @@ TX_RETURN_TYPE rn2xx3::txCommand(String command, String data, bool shouldEncode) String receivedData = _serial.readStringUntil('\n'); //TODO: Debug print on receivedData - + + + if(receivedData.startsWith("ok")) { _serial.setTimeout(30000); @@ -422,14 +514,23 @@ TX_RETURN_TYPE rn2xx3::txCommand(String command, String data, bool shouldEncode) else if(receivedData.startsWith("radio_tx_ok")) { + //SUCCESS!! send_success = true; return TX_SUCCESS; } - + else if(receivedData.startsWith("radio_rx")) { + //example: radio_rx 54657374696E6720313233 + _rxMessenge = receivedData.substring(receivedData.indexOf(' ', 9)+1); + send_success = true; + return TX_WITH_RX; + } + else if(receivedData.startsWith("radio_err")) { //This should never happen. If it does, something major is wrong. + // or someone added radio 2 radio support and did it wrong ;-) + init(); } @@ -439,6 +540,12 @@ TX_RETURN_TYPE rn2xx3::txCommand(String command, String data, bool shouldEncode) //init(); } } + else if(receivedData.startsWith("radio_rx")) { + //example: radio_rx 54657374696E6720313233 + _rxMessenge = receivedData.substring(receivedData.indexOf(' ', 9)+1); + send_success = true; + return TX_WITH_RX; + } else if(receivedData.startsWith("invalid_param")) { @@ -546,7 +653,8 @@ String rn2xx3::base16encode(String input) } String rn2xx3::getRx() { - return _rxMessenge; + + return _rxMessenge; } int rn2xx3::getSNR() @@ -564,6 +672,7 @@ String rn2xx3::base16decode(String input) input.toCharArray(charsIn, input.length()+1); unsigned i = 0; + for(i = 0; i 0) { + uint8_t* bytesOut = (uint8_t*) malloc(input.length() * sizeof(uint8_t)); + + char charsIn[input.length()+1]; + + input.trim(); + input.toCharArray(charsIn, input.length()+1); + + unsigned i = 0; + for(i = 0; i=0 && dr<=5) diff --git a/src/rn2xx3.h b/src/rn2xx3.h index 9cd4940..ac90e4c 100644 --- a/src/rn2xx3.h +++ b/src/rn2xx3.h @@ -33,8 +33,10 @@ enum TX_RETURN_TYPE { TX_SUCCESS = 1, // The transmission was successful. // Also the case when a confirmed message was acked. - TX_WITH_RX = 2 // A downlink message was received after the transmission. + TX_WITH_RX = 2, // A downlink message was received after the transmission. // This also implies that a confirmed message is acked. + RADIO_LISTEN_WITHOUT_RX = 3 // listened to radio 2 radio but nothing came back + }; class rn2xx3 @@ -136,6 +138,17 @@ class rn2xx3 * DevEui: Device EUI as a uint8_t buffer (optional - set to 0 to use Hardware EUI) */ bool initOTAA(uint8_t * AppEUI, uint8_t * AppKey, uint8_t * DevEui); + + /* + * Sets the rn2xx3 to listen/send transmissions from/to other rn2xx3's + */ + + bool initP2P(); + + /* + * Listen to + */ + TX_RETURN_TYPE listenP2P(); /* * Transmit the provided data. The data is hex-encoded by this library, @@ -233,12 +246,20 @@ class rn2xx3 * string received from the RN2xx3. */ String base16decode(String); + /* + * Decode a HEX string to an Byte array. Useful to receive + * bytes from the RN2xx3. + */ + uint8_t * base16decodeBytes(String); private: Stream& _serial; RN2xx3_t _moduleType = RN_NA; + // mac pause and radio to radio transmissions + bool _radio2radio = false; + //Flags to switch code paths. Default is to use OTAA. bool _otaa = true; diff --git a/src/src.ino b/src/src.ino new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/src.ino @@ -0,0 +1 @@ +