diff --git a/examples/SX127x_ReceiveInterrupt/SX127x_ReceiveInterrupt.ino b/examples/SX127x_ReceiveInterrupt/SX127x_ReceiveInterrupt.ino new file mode 100644 index 00000000..c6f2927b --- /dev/null +++ b/examples/SX127x_ReceiveInterrupt/SX127x_ReceiveInterrupt.ino @@ -0,0 +1,143 @@ +/* + KiteLib Receive with Inerrupts Example + + This example listens for LoRa transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. To successfully receive data, the following + settings have to be the same on both transmitter + and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + + Other modules from SX127x family can also be used. + SX1272 lora = Kite.ModuleA; + SX1273 lora = Kite.ModuleA; + SX1276 lora = Kite.ModuleA; + SX1277 lora = Kite.ModuleA; + SX1279 lora = Kite.ModuleA; +*/ + +// include the library +#include + +// SX1278 module is in slot A on the shield +SX1278 lora = Kite.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("Initializing ... ")); + // carrier frequency: 434.0 MHz + // bandwidth: 125.0 kHz + // spreading factor: 9 + // coding rate: 7 + // sync word: 0x12 + // output power: 17 dBm + int state = lora.begin(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when new packet is received + lora.onReceive(setFlag); + + // start listening for LoRa packets + Serial.print(F("Starting to listen ... ")); + state = lora.listen(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, 'listen' mode can be disabled by calling + // any of the following methods: + // + // lora.standby() + // lora.sleep() + // lora.transmit(); + // lora.receive(); + // lora.scanChannel(); +} + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// disable interrupt when it's not needed +volatile bool enableInterrupt = true; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +void setFlag(void) { + // check if the interrupt is enabled + if(!enableInterrupt) { + return; + } + + // we got a packet, set the flag + receivedFlag = true; +} + +void loop() { + // check if the flag is set + if(receivedFlag) { + // disable the interrupt service routine while + // processing the data + enableInterrupt = false; + + // reset flag + receivedFlag = false; + + // you can read received data as an Arduino String + String str; + int state = lora.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + int state = lora.receive(byteArr, 8); + */ + + if (state == ERR_NONE) { + // packet was successfully received + Serial.println("Received packet!"); + + // print data of the packet + Serial.print("Data:\t\t"); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print("RSSI:\t\t"); + Serial.print(lora.lastPacketRSSI); + Serial.println(" dBm"); + + // print SNR (Signal-to-Noise Ratio) + Serial.print("SNR:\t\t"); + Serial.print(lora.lastPacketSNR); + Serial.println(" dBm"); + + } else if (state == ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println("CRC error!"); + + } + + // we're ready to receive more packets, + // enable interrupt service routine + enableInterrupt = true; + } + +} diff --git a/keywords.txt b/keywords.txt index 6f5756d9..7e68f4ad 100644 --- a/keywords.txt +++ b/keywords.txt @@ -50,6 +50,9 @@ setCodingRate KEYWORD2 setFrequency KEYWORD2 setSyncWord KEYWORD2 setOutputPower KEYWORD2 +listen KEYWORD2 +onReceive KEYWORD2 +readData KEYWORD2 # RF69-specific setBitRate KEYWORD2 diff --git a/src/modules/SX1272.cpp b/src/modules/SX1272.cpp index 7f4b859c..e4048be8 100644 --- a/src/modules/SX1272.cpp +++ b/src/modules/SX1272.cpp @@ -150,7 +150,7 @@ int16_t SX1272::setCodingRate(uint8_t cr) { int16_t SX1272::setOutputPower(int8_t power) { // check allowed power range - if((power < -1) || (power > 20)) { + if(!(((power >= -1) && (power <= 17)) || (power == 20))) { return(ERR_INVALID_OUTPUT_POWER); } @@ -158,20 +158,20 @@ int16_t SX1272::setOutputPower(int8_t power) { SX127x::standby(); int16_t state; - if(power < 15) { - // power is less than 15 dBm, enable PA0 on RFIO + if(power < 2) { + // power is less than 2 dBm, enable PA0 on RFIO state = _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_RFO, 7, 7); - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, power + 1, 3, 0); + state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, (power + 1), 3, 0); state |= _mod->SPIsetRegValue(SX1272_REG_PA_DAC, SX127X_PA_BOOST_OFF, 2, 0); - } else if((power >= 15) && (power < 18)) { - // power is 15 - 17 dBm, enable PA1 + PA2 on PA_BOOST + } else if((power >= 2) && (power <= 17)) { + // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST state = _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST, 7, 7); - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, power - 2, 3, 0); + state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, (power - 2), 3, 0); state |= _mod->SPIsetRegValue(SX1272_REG_PA_DAC, SX127X_PA_BOOST_OFF, 2, 0); - } else if(power >= 18) { - // power is 18 - 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power control + } else if(power == 20) { + // power is 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power control state = _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST, 7, 7); - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, power - 5, 3, 0); + state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, (power - 5), 3, 0); state |= _mod->SPIsetRegValue(SX1272_REG_PA_DAC, SX127X_PA_BOOST_ON, 2, 0); } diff --git a/src/modules/SX1278.cpp b/src/modules/SX1278.cpp index 8c9209f6..a267c682 100644 --- a/src/modules/SX1278.cpp +++ b/src/modules/SX1278.cpp @@ -223,7 +223,7 @@ int16_t SX1278::setCodingRate(uint8_t cr) { } int16_t SX1278::setOutputPower(int8_t power) { - if((power < -3) || (power > 20)) { + if(!(((power >= -3) && (power <= 17)) || (power == 20))) { return(ERR_INVALID_OUTPUT_POWER); } @@ -231,20 +231,20 @@ int16_t SX1278::setOutputPower(int8_t power) { SX127x::standby(); int16_t state; - if(power < 13) { - // power is less than 12 dBm, enable PA on RFO + if(power < 2) { + // power is less than 2 dBm, enable PA on RFO state = _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_RFO, 7, 7); state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX1278_LOW_POWER | (power + 3), 6, 0); state |= _mod->SPIsetRegValue(SX1278_REG_PA_DAC, SX127X_PA_BOOST_OFF, 2, 0); - } else if((power >= 13) && (power < 18)) { - // power is 13 - 17 dBm, enable PA1 + PA2 on PA_BOOST + } else if((power >= 2) && (power <= 17)) { + // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST state = _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST, 7, 7); - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX1278_MAX_POWER | (power + 2), 6, 0); + state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX1278_MAX_POWER | (power - 2), 6, 0); state |= _mod->SPIsetRegValue(SX1278_REG_PA_DAC, SX127X_PA_BOOST_OFF, 2, 0); - } else if(power >= 18) { - // power is 18 - 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power mode + } else if(power == 20) { + // power is 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power mode state = _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST, 7, 7); - state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX1278_MAX_POWER | (power + 2), 6, 0); + state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX1278_MAX_POWER | (power - 5), 6, 0); state |= _mod->SPIsetRegValue(SX1278_REG_PA_DAC, SX127X_PA_BOOST_ON, 2, 0); } diff --git a/src/modules/SX127x.cpp b/src/modules/SX127x.cpp index cd488e83..cbdb598a 100644 --- a/src/modules/SX127x.cpp +++ b/src/modules/SX127x.cpp @@ -49,6 +49,14 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord) { return(ERR_NONE); } +int16_t SX127x::transmit(String& str) { + return(SX127x::transmit(str.c_str())); +} + +int16_t SX127x::transmit(const char* str) { + return(SX127x::transmit((uint8_t*)str, strlen(str))); +} + int16_t SX127x::transmit(uint8_t* data, size_t len) { // check packet length if(len >= 256) { @@ -92,12 +100,16 @@ int16_t SX127x::transmit(uint8_t* data, size_t len) { // wait for packet transmission or timeout uint32_t start = millis(); - while(!_mod->getInt0State()) { + while(!digitalRead(_mod->int0())) { if(millis() - start > timeout) { clearIRQFlags(); return(ERR_TX_TIMEOUT); } } + uint32_t elapsed = millis() - start; + + // update data rate + dataRate = (len*8.0)/((float)elapsed/1000.0); // clear interrupt flags clearIRQFlags(); @@ -105,12 +117,18 @@ int16_t SX127x::transmit(uint8_t* data, size_t len) { return(ERR_NONE); } -int16_t SX127x::transmit(const char* str) { - return(SX127x::transmit((uint8_t*)str, strlen(str))); -} - -int16_t SX127x::transmit(String& str) { - return(SX127x::transmit(str.c_str())); +int16_t SX127x::receive(String& str, size_t len) { + // create temporary array to store received data + char* data = new char[len]; + int16_t state = SX127x::receive((uint8_t*)data, len); + + // if packet was received successfully, copy data into String + if(state == ERR_NONE) { + str = String(data); + } + + delete[] data; + return(state); } int16_t SX127x::receive(uint8_t* data, size_t len) { @@ -132,13 +150,12 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { // wait for packet reception or timeout uint32_t start = millis(); - while(!_mod->getInt0State()) { - if(_mod->getInt1State()) { + while(!digitalRead(_mod->int0())) { + if(digitalRead(_mod->int1())) { clearIRQFlags(); return(ERR_RX_TIMEOUT); } } - uint32_t elapsed = millis() - start; // check integrity CRC if(_mod->SPIgetRegValue(SX127X_REG_IRQ_FLAGS, 5, 5) == SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) { @@ -165,8 +182,7 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { data[length] = 0; } - // update data rate, RSSI and SNR - dataRate = (length*8.0)/((float)elapsed/1000.0); + // update RSSI and SNR lastPacketRSSI = -157 + _mod->SPIgetRegValue(SX127X_REG_PKT_RSSI_VALUE); int8_t rawSNR = (int8_t)_mod->SPIgetRegValue(SX127X_REG_PKT_SNR_VALUE); lastPacketSNR = rawSNR / 4.0; @@ -177,20 +193,6 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { return(ERR_NONE); } -int16_t SX127x::receive(String& str, size_t len) { - // create temporary array to store received data - char* data = new char[len]; - int16_t state = SX127x::receive((uint8_t*)data, len); - - // if packet was received successfully, copy data into String - if(state == ERR_NONE) { - str = String(data); - } - - delete[] data; - return(state); -} - int16_t SX127x::scanChannel() { // set mode to standby setMode(SX127X_STANDBY); @@ -203,8 +205,8 @@ int16_t SX127x::scanChannel() { setMode(SX127X_CAD); // wait for channel activity detected or timeout - while(!_mod->getInt0State()) { - if(_mod->getInt1State()) { + while(!digitalRead(_mod->int0())) { + if(digitalRead(_mod->int1())) { clearIRQFlags(); return(PREAMBLE_DETECTED); } @@ -226,6 +228,30 @@ int16_t SX127x::standby() { return(setMode(SX127X_STANDBY)); } +int16_t SX127x::listen() { + // set mode to standby + int16_t state = setMode(SX127X_STANDBY); + + // set DIO pin mapping + state |= _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_RX_DONE | SX127X_DIO1_RX_TIMEOUT, 7, 4); + if(state != ERR_NONE) { + return(state); + } + + // clear interrupt flags + clearIRQFlags(); + + // set FIFO pointers + state = _mod->SPIsetRegValue(SX127X_REG_FIFO_RX_BASE_ADDR, SX127X_FIFO_RX_BASE_ADDR_MAX); + state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_RX_BASE_ADDR_MAX); + if(state != ERR_NONE) { + return(state); + } + + // set mode to continuous reception + return(setMode(SX127X_RXCONTINUOUS)); +} + int16_t SX127x::setSyncWord(uint8_t syncWord) { // set mode to standby setMode(SX127X_STANDBY); @@ -250,6 +276,61 @@ int16_t SX127x::setFrequencyRaw(float newFreq) { return(state); } +void SX127x::onReceive(void (*func)(void)) { + attachInterrupt(digitalPinToInterrupt(_mod->int0()), func, RISING); +} + +int16_t SX127x::readData(String& str, size_t len) { + // create temporary array to store received data + char* data = new char[len]; + int16_t state = SX127x::readData((uint8_t*)data, len); + + // if packet was received successfully, copy data into String + if(state == ERR_NONE) { + str = String(data); + } + + delete[] data; + return(state); +} + +int16_t SX127x::readData(uint8_t* data, size_t len) { + // check integrity CRC + if(_mod->SPIgetRegValue(SX127X_REG_IRQ_FLAGS, 5, 5) == SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) { + return(ERR_CRC_MISMATCH); + } + + // get packet length + size_t length = len; + if(_sf != 6) { + length = _mod->SPIgetRegValue(SX127X_REG_RX_NB_BYTES); + } + + // read packet data + if(len == 0) { + // argument len equal to zero indicates String call, which means dynamically allocated data array + // dispose of the original and create a new one + delete[] data; + data = new uint8_t[length]; + } + _mod->SPIreadRegisterBurst(SX127X_REG_FIFO, length, data); + + // add terminating null + if(len == 0) { + data[length] = 0; + } + + // update RSSI and SNR + lastPacketRSSI = -157 + _mod->SPIgetRegValue(SX127X_REG_PKT_RSSI_VALUE); + int8_t rawSNR = (int8_t)_mod->SPIgetRegValue(SX127X_REG_PKT_SNR_VALUE); + lastPacketSNR = rawSNR / 4.0; + + // clear interrupt flags + clearIRQFlags(); + + return(ERR_NONE); +} + int16_t SX127x::config() { // set mode to SLEEP int16_t state = setMode(SX127X_SLEEP); @@ -295,8 +376,7 @@ int16_t SX127x::config() { } int16_t SX127x::setMode(uint8_t mode) { - _mod->SPIsetRegValue(SX127X_REG_OP_MODE, mode, 2, 0); - return(ERR_NONE); + return(_mod->SPIsetRegValue(SX127X_REG_OP_MODE, mode, 2, 0)); } void SX127x::clearIRQFlags() { diff --git a/src/modules/SX127x.h b/src/modules/SX127x.h index b5c34421..e2d3d272 100644 --- a/src/modules/SX127x.h +++ b/src/modules/SX127x.h @@ -174,14 +174,20 @@ class SX127x { // basic methods int16_t begin(uint8_t chipVersion, uint8_t syncWord); - int16_t transmit(uint8_t* data, size_t len); - int16_t transmit(const char* str); int16_t transmit(String& str); - int16_t receive(uint8_t* data, size_t len); + int16_t transmit(const char* str); + int16_t transmit(uint8_t* data, size_t len); int16_t receive(String& str, size_t len = 0); + int16_t receive(uint8_t* data, size_t len); int16_t scanChannel(); int16_t sleep(); int16_t standby(); + int16_t listen(); + + // interrupt methods + int16_t readData(String& str, size_t len = 0); + int16_t readData(uint8_t* data, size_t len); + void onReceive(void (*func)(void)); // configuration methods int16_t setSyncWord(uint8_t syncWord);