Coragem update
Dependents: Coragem_all_sensors Lora_SX1272_Coragem
Diff: SX1272.cpp
- Revision:
- 0:d974bcee4f69
- Child:
- 1:5d57c6a92509
diff -r 000000000000 -r d974bcee4f69 SX1272.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SX1272.cpp Sun Nov 05 14:30:04 2017 +0000 @@ -0,0 +1,7160 @@ +/* + * Library for LoRa 868 / 915MHz SX1272 LoRa module + * + * Copyright (C) Libelium Comunicaciones Distribuidas S.L. + * http://www.libelium.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + * Version: 1.1 + * Design: David Gascón + * Implementation: Covadonga Albiñana & Victor Boria + */ + +//**********************************************************************/ +// Includes +//**********************************************************************/ +#include "mbed.h" +#include "SX1272.h" +#include <SPI.h> + +/* CHANGE LOGS by C. Pham + * June, 22th, 2017 + * - setPowerDBM(uint8_t dbm) calls setPower('X') when dbm is set to 20 + * Apr, 21th, 2017 + * - change the way timeout are detected: exitTime=millis()+(unsigned long)wait; then millis() < exitTime; + * Mar, 26th, 2017 + * - insert delay(100) before setting radio module to sleep mode. Remove unstability issue + * - (proposed by escyes - https://github.com/CongducPham/LowCostLoRaGw/issues/53#issuecomment-289237532) + * Jan, 11th, 2017 + * - fix bug in getRSSIpacket() when SNR < 0 thanks to John Rohde from Aarhus University + * Dec, 17th, 2016 + * - fix bug making -DPABOOST in radio.makefile inoperant + * Dec, 1st, 2016 + * - add RSSI computation while performing CAD with doCAD() + * - WARNING: the SX1272 lib for gateway (Raspberry) does not have this functionality + * Nov, 26th, 2016 + * - add preliminary support for ToA limitation + * - when in "production" mode, uncomment #define LIMIT_TOA + * Nov, 16th, 2016 + * - provide better power management mechanisms + * - manage PA_BOOST and dBm setting + * Jan, 23rd, 2016 + * - the packet format at transmission does not use the original Libelium format anymore + * * the retry field is removed therefore all operations using retry will probably not work well, not tested though + * - therefore DO NOT use sendPacketTimeoutACKRetries() + * - the reason is that we do not want to have a reserved byte after the payload + * * the length field is removed because it is much better to get the packet length at the reception side + * * after the dst field, we inserted a packet type field to better identify the packet type: DATA, ACK, encryption, app key,... + * - the format is now dst(1B) ptype(1B) src(1B) seq(1B) payload(xB) + * - ptype is decomposed in 2 parts type(4bits) flags(4bits) + * - type can take current value of DATA=0001 and ACK=0010 + * - the flags are from left to right: ack_requested|encrypted|with_appkey|is_binary + * - ptype can be set with setPacketType(), see constant defined in SX1272.h + * - the header length is then 4 instead of 5 + * Jan, 16th, 2016 + * - add support for SX1276, automatic detect + * - add LF/HF calibaration copied from LoRaMAC-Node. Don't know if it is really necessary though + * - change various radio settings + * Dec, 10th, 2015 + * - add SyncWord for test with simple LoRaWAN + * - add mode 11 that have BW=125, CR=4/5, SF=7 on channel 868.1MHz + * - use following in your code if (loraMode==11) { e = sx1272.setChannel(CH_18_868); } + * Nov, 13th, 2015 + * - add CarrierSense() to perform some Listen Before Talk procedure + * - add dynamic ACK suport + * - compile with W_REQUESTED_ACK, retry field is used to indicate at the receiver + * that an ACK should be sent + * - receiveWithTimeout() has been modified to send an ACK if retry is 1 + * - at sender side, sendPacketTimeoutACK() has been modified to indicate + * whether retry should be set to 1 or not in setPacket() + * - receiver should always use receiveWithTimeout() while sender decides to use + * sendPacketTimeout() or sendPacketTimeoutACK() + * Jun, 2015 + * - Add time on air computation and CAD features +*/ + +// Added by C. Pham +// based on SIFS=3CAD +uint8_t sx1272_SIFS_value[11]={0, 183, 94, 44, 47, 23, 24, 12, 12, 7, 4}; +uint8_t sx1272_CAD_value[11]={0, 62, 31, 16, 16, 8, 9, 5, 3, 1, 1}; + +//#define LIMIT_TOA +// 0.1% for testing +//#define MAX_DUTY_CYCLE_PER_HOUR 3600L +// 1%, regular mode +#define MAX_DUTY_CYCLE_PER_HOUR 36000L +// normally 1 hour, set to smaller value for testing +#define DUTYCYCLE_DURATION 3600000L +// 4 min for testing +//#define DUTYCYCLE_DURATION 240000L + +// end + +//ajoute par C.DUPATY +//Serial pc(USBTX, USBRX); // tx, rx +SPI spi(SPI_MOSI,SPI_MISO,SPI_SCK);; // mosi, miso, sclk +DigitalOut ss(SPI_CS); +DigitalOut rst(PA_8); + +//**********************************************************************/ +// Public functions. +//**********************************************************************/ + +SX1272::SX1272() +{ +//ajoute par C.DUPATY +us_ticker_init(); +srand(time(NULL)); +// ajoute parC.Dupaty +// A VERIFIER !!!!!!!!!!!!!!!!!!!!!!! + spi.format(8,0); // spi 8 bits mode 0 + spi.frequency(2000000); // spi clock 200KHz a l origine + + // Initialize class variables + _bandwidth = BW_125; + _codingRate = CR_5; + _spreadingFactor = SF_7; + _channel = CH_12_900; + _header = HEADER_ON; + _CRC = CRC_OFF; + _modem = FSK; + _power = 15; + _packetNumber = 0; + _reception = CORRECT_PACKET; + _retries = 0; + // added by C. Pham + _defaultSyncWord=0x12; + _rawFormat=false; + _extendedIFS=true; + _RSSIonSend=true; + // disabled by default + _enableCarrierSense=false; + // DIFS by default + _send_cad_number=9; +#ifdef PABOOST + _needPABOOST=true; +#else + _needPABOOST=false; +#endif + _limitToA=false; + _startToAcycle=millis(); + _remainingToA=MAX_DUTY_CYCLE_PER_HOUR; + _endToAcycle=_startToAcycle+DUTYCYCLE_DURATION; +#ifdef W_REQUESTED_ACK + _requestACK = 0; +#endif +#ifdef W_NET_KEY + _my_netkey[0] = net_key_0; + _my_netkey[1] = net_key_1; +#endif + // end + _maxRetries = 3; + packet_sent.retry = _retries; +}; + +// added by C. Pham +// copied from LoRaMAC-Node +/*! + * Performs the Rx chain calibration for LF and HF bands + * \remark Must be called just after the reset so all registers are at their + * default values + */ +void SX1272::RxChainCalibration() +{ + if (_board==SX1276Chip) { + + printf("SX1276 LF/HF calibration\r"); + + // Cut the PA just in case, RFO output, power = -1 dBm + writeRegister( REG_PA_CONFIG, 0x00 ); + + // Launch Rx chain calibration for LF band + writeRegister( REG_IMAGE_CAL, ( readRegister( REG_IMAGE_CAL ) & RF_IMAGECAL_IMAGECAL_MASK ) | RF_IMAGECAL_IMAGECAL_START ); + while( ( readRegister( REG_IMAGE_CAL ) & RF_IMAGECAL_IMAGECAL_RUNNING ) == RF_IMAGECAL_IMAGECAL_RUNNING ) + { + } + + // Sets a Frequency in HF band + setChannel(CH_17_868); + + // Launch Rx chain calibration for HF band + writeRegister( REG_IMAGE_CAL, ( readRegister( REG_IMAGE_CAL ) & RF_IMAGECAL_IMAGECAL_MASK ) | RF_IMAGECAL_IMAGECAL_START ); + while( ( readRegister( REG_IMAGE_CAL ) & RF_IMAGECAL_IMAGECAL_RUNNING ) == RF_IMAGECAL_IMAGECAL_RUNNING ) + { + } + } +} + + +/* + Function: Sets the module ON. + Returns: uint8_t setLORA state +*/ +uint8_t SX1272::ON() +{ + uint8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'ON'\n"); +#endif + + // Powering the module +// pinMode(SX1272_SS,OUTPUT); +// digitalWrite(SX1272_SS,HIGH); + ss=1; + wait_ms(100); + + //#define USE_SPI_SETTINGS +/* +#ifdef USE_SPI_SETTINGS + SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0)); +#else + //Configure the MISO, MOSI, CS, SPCR. + SPI.begin(); + //Set Most significant bit first + SPI.setBitOrder(MSBFIRST); +#ifdef _VARIANT_ARDUINO_DUE_X_ + // for the DUE, set to 4MHz + SPI.setClockDivider(42); +#else + // for the MEGA, set to 2MHz + SPI.setClockDivider(SPI_CLOCK_DIV8); +#endif + //Set data mode + SPI.setDataMode(SPI_MODE0); +#endif +*/ + wait_ms(100); + +/* // added by C. Pham + pinMode(SX1272_RST,OUTPUT); + digitalWrite(SX1272_RST,HIGH); + wait_ms(100); + digitalWrite(SX1272_RST,LOW); + wait_ms(100); + */ + + rst=1; + wait_ms(100); + rst=0; + + // from single_chan_pkt_fwd by Thomas Telkamp + uint8_t version = readRegister(REG_VERSION); + + if (version == 0x22) { + // sx1272 + printf("SX1272 detected, starting\n"); + _board = SX1272Chip; + } else { + // sx1276? + // digitalWrite(SX1272_RST, LOW); + rst=0; + wait_ms(100); + // digitalWrite(SX1272_RST, HIGH); + rst=1; + wait_ms(100); + version = readRegister(REG_VERSION); + if (version == 0x12) { + // sx1276 + printf("SX1276 detected, starting\n"); + _board = SX1276Chip; + } else { + printf("Unrecognized transceiver\n"); + } + } + // end from single_chan_pkt_fwd by Thomas Telkamp + + // added by C. Pham + RxChainCalibration(); + + setMaxCurrent(0x1B); +#if (SX1272_debug_mode > 1) + printf("## Setting ON with maximum current supply ##"); + printf("\n"); +#endif + + // set LoRa mode + state = setLORA(); + + // Added by C. Pham for ToA computation + getPreambleLength(); +#ifdef W_NET_KEY + //#if (SX1272_debug_mode > 1) + printf("## SX1272 layer has net key##"); + //#endif +#endif + +#ifdef W_INITIALIZATION + // CAUTION + // doing initialization as proposed by Libelium seems not to work for the SX1276 + // so we decided to leave the default value of the SX127x, then configure the radio when + // setting to LoRa mode + + //Set initialization values + writeRegister(0x0,0x0); + // comment by C. Pham + // still valid for SX1276 + writeRegister(0x1,0x81); + // end + writeRegister(0x2,0x1A); + writeRegister(0x3,0xB); + writeRegister(0x4,0x0); + writeRegister(0x5,0x52); + writeRegister(0x6,0xD8); + writeRegister(0x7,0x99); + writeRegister(0x8,0x99); + // modified by C. Pham + // added by C. Pham + if (_board==SX1272Chip) + // RFIO_pin RFU OutputPower + // 0 000 0000 + writeRegister(0x9,0x0); + else + // RFO_pin MaxP OutputPower + // 0 100 1111 + // set MaxPower to 0x4 and OutputPower to 0 + writeRegister(0x9,0x40); + + writeRegister(0xA,0x9); + writeRegister(0xB,0x3B); + + // comment by C. Pham + // still valid for SX1276 + writeRegister(0xC,0x23); + + // REG_RX_CONFIG + writeRegister(0xD,0x1); + + writeRegister(0xE,0x80); + writeRegister(0xF,0x0); + writeRegister(0x10,0x0); + writeRegister(0x11,0x0); + writeRegister(0x12,0x0); + writeRegister(0x13,0x0); + writeRegister(0x14,0x0); + writeRegister(0x15,0x0); + writeRegister(0x16,0x0); + writeRegister(0x17,0x0); + writeRegister(0x18,0x10); + writeRegister(0x19,0x0); + writeRegister(0x1A,0x0); + writeRegister(0x1B,0x0); + writeRegister(0x1C,0x0); + + // added by C. Pham + if (_board==SX1272Chip) { + // comment by C. Pham + // 0x4A = 01 001 0 1 0 + // BW=250 CR=4/5 ImplicitH_off RxPayloadCrcOn_on LowDataRateOptimize_off + writeRegister(0x1D,0x4A); + // 1001 0 1 11 + // SF=9 TxContinuous_off AgcAutoOn SymbTimeOut + writeRegister(0x1E,0x97); + } + else { + // 1000 001 0 + // BW=250 CR=4/5 ImplicitH_off + writeRegister(0x1D,0x82); + // 1001 0 1 11 + // SF=9 TxContinuous_off RxPayloadCrcOn_on SymbTimeOut + writeRegister(0x1E,0x97); + } + // end + + writeRegister(0x1F,0xFF); + writeRegister(0x20,0x0); + writeRegister(0x21,0x8); + writeRegister(0x22,0xFF); + writeRegister(0x23,0xFF); + writeRegister(0x24,0x0); + writeRegister(0x25,0x0); + + // added by C. Pham + if (_board==SX1272Chip) + writeRegister(0x26,0x0); + else + // 0000 0 1 00 + // reserved LowDataRateOptimize_off AgcAutoOn reserved + writeRegister(0x26,0x04); + + // REG_SYNC_CONFIG + writeRegister(0x27,0x0); + + writeRegister(0x28,0x0); + writeRegister(0x29,0x0); + writeRegister(0x2A,0x0); + writeRegister(0x2B,0x0); + writeRegister(0x2C,0x0); + writeRegister(0x2D,0x50); + writeRegister(0x2E,0x14); + writeRegister(0x2F,0x40); + writeRegister(0x30,0x0); + writeRegister(0x31,0x3); + writeRegister(0x32,0x5); + writeRegister(0x33,0x27); + writeRegister(0x34,0x1C); + writeRegister(0x35,0xA); + writeRegister(0x36,0x0); + writeRegister(0x37,0xA); + writeRegister(0x38,0x42); + writeRegister(0x39,0x12); + //writeRegister(0x3A,0x65); + //writeRegister(0x3B,0x1D); + //writeRegister(0x3C,0x1); + //writeRegister(0x3D,0xA1); + //writeRegister(0x3E,0x0); + //writeRegister(0x3F,0x0); + //writeRegister(0x40,0x0); + //writeRegister(0x41,0x0); + // commented by C. Pham + // since now we handle also the SX1276 + //writeRegister(0x42,0x22); +#endif + // added by C. Pham + // default sync word for non-LoRaWAN + setSyncWord(_defaultSyncWord); + getSyncWord(); + _defaultSyncWord=_syncWord; + +#ifdef LIMIT_TOA + uint16_t remainingToA=limitToA(); + printf("## Limit ToA ON ##"); + printf("cycle begins at "); + Serial.print(_startToAcycle); + printf(" cycle ends at "); + Serial.print(_endToAcycle); + printf(" remaining ToA is "); + Serial.print(remainingToA); + printf("\n"); +#endif + //end + + return state; +} + +/* + Function: Sets the module OFF. + Returns: Nothing +*/ +void SX1272::OFF() +{ +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'OFF'\n"); +#endif + +// ajoute par C.Dupaty + //SPI.end(); + + // Powering the module + // pinMode(SX1272_SS,OUTPUT); + // digitalWrite(SX1272_SS,LOW); + ss=0; // ????? !!!!!!!!!!!!!!!!! +#if (SX1272_debug_mode > 1) + printf("## Setting OFF ##"); + printf("\n"); +#endif +} + +/* + Function: Reads the indicated register. + Returns: The content of the register + Parameters: + address: address register to read from +*/ +byte SX1272::readRegister(byte address) +{ + byte value = 0x00; + + //digitalWrite(SX1272_SS,LOW); + ss=0; + bitClear(address, 7); // Bit 7 cleared to write in registers + // SPI.transfer(address); + spi.write(address); + //value = SPI.transfer(0x00); + value = spi.write(0x00); + //digitalWrite(SX1272_SS,HIGH); + ss=1; + +#if (SX1272_debug_mode > 1) + printf("## Reading: "); + printf("Register 0x%02X : 0x%02X\n",address,value); + // Serial.print(address, HEX); + // printf(": "); + // Serial.print(value, HEX); + // printf("\n"); +#endif + + return value; +} + +/* + Function: Writes on the indicated register. + Returns: Nothing + Parameters: + address: address register to write in + data : value to write in the register +*/ +void SX1272::writeRegister(byte address, byte data) +{ + //digitalWrite(SX1272_SS,LOW); + ss=0; + bitSet(address, 7); // Bit 7 set to read from registers + //SPI.transfer(address); + //SPI.transfer(data); + spi.write(address); + spi.write(data); + // digitalWrite(SX1272_SS,HIGH); + ss=1; + +#if (SX1272_debug_mode > 1) + printf("## Writing: Register "); + bitClear(address, 7); + printf("0x%02X : 0x%02X\n",address,data); + // Serial.print(address, HEX); + // printf(": "); + // Serial.print(data, HEX); + // printf("\n"); +#endif + +} + +/* + Function: Clears the interruption flags + Returns: Nothing +*/ +void SX1272::clearFlags() +{ + byte st0; + + st0 = readRegister(REG_OP_MODE); // Save the previous status + + if( _modem == LORA ) + { // LoRa mode + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); // Stdby mode to write in registers + writeRegister(REG_IRQ_FLAGS, 0xFF); // LoRa mode flags register + writeRegister(REG_OP_MODE, st0); // Getting back to previous status +#if (SX1272_debug_mode > 1) + printf("## LoRa flags cleared ##\n"); +#endif + } + else + { // FSK mode + writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Stdby mode to write in registers + writeRegister(REG_IRQ_FLAGS1, 0xFF); // FSK mode flags1 register + writeRegister(REG_IRQ_FLAGS2, 0xFF); // FSK mode flags2 register + writeRegister(REG_OP_MODE, st0); // Getting back to previous status +#if (SX1272_debug_mode > 1) + printf("## FSK flags cleared ##"); +#endif + } +} + +/* + Function: Sets the module in LoRa mode. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::setLORA() +{ + uint8_t state = 2; + byte st0; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setLORA'\n"); +#endif + + // modified by C. Pham + uint8_t retry=0; + + do { + wait_ms(200); + writeRegister(REG_OP_MODE, FSK_SLEEP_MODE); // Sleep mode (mandatory to set LoRa mode) + writeRegister(REG_OP_MODE, LORA_SLEEP_MODE); // LoRa sleep mode + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); + wait_ms(50+retry*10); + st0 = readRegister(REG_OP_MODE); + printf("..."); + + if ((retry % 2)==0) + if (retry==20) + retry=0; + else + retry++; + /* + if (st0!=LORA_STANDBY_MODE) { + pinMode(SX1272_RST,OUTPUT); + digitalWrite(SX1272_RST,HIGH); + wait_ms(100); + digitalWrite(SX1272_RST,LOW); + } + */ + + } while (st0!=LORA_STANDBY_MODE); // LoRa standby mode + + if( st0 == LORA_STANDBY_MODE) + { // LoRa mode + _modem = LORA; + state = 0; +#if (SX1272_debug_mode > 1) + printf("## LoRa set with success ##"); + printf("\n"); +#endif + } + else + { // FSK mode + _modem = FSK; + state = 1; +#if (SX1272_debug_mode > 1) + printf("** There has been an error while setting LoRa **"); + printf("\n"); +#endif + } + return state; +} + +/* + Function: Sets the module in FSK mode. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::setFSK() +{ + uint8_t state = 2; + byte st0; + byte config1; + + if (_board==SX1276Chip) + printf("Warning: FSK has not been tested on SX1276!"); + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setFSK'\n"); +#endif + + writeRegister(REG_OP_MODE, FSK_SLEEP_MODE); // Sleep mode (mandatory to change mode) + writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // FSK standby mode + config1 = readRegister(REG_PACKET_CONFIG1); + config1 = config1 & 0B01111101; // clears bits 8 and 1 from REG_PACKET_CONFIG1 + config1 = config1 | 0B00000100; // sets bit 2 from REG_PACKET_CONFIG1 + writeRegister(REG_PACKET_CONFIG1,config1); // AddressFiltering = NodeAddress + BroadcastAddress + writeRegister(REG_FIFO_THRESH, 0x80); // condition to start packet tx + config1 = readRegister(REG_SYNC_CONFIG); + config1 = config1 & 0B00111111; + writeRegister(REG_SYNC_CONFIG,config1); + + wait_ms(100); + + st0 = readRegister(REG_OP_MODE); // Reading config mode + if( st0 == FSK_STANDBY_MODE ) + { // FSK mode + _modem = FSK; + state = 0; +#if (SX1272_debug_mode > 1) + printf("## FSK set with success ##"); + printf("\n"); +#endif + } + else + { // LoRa mode + _modem = LORA; + state = 1; +#if (SX1272_debug_mode > 1) + printf("** There has been an error while setting FSK **"); + printf("\n"); +#endif + } + return state; +} + +/* + Function: Gets the bandwidth, coding rate and spreading factor of the LoRa modulation. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::getMode() +{ + byte st0; + int8_t state = 2; + byte value = 0x00; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getMode'\n"); +#endif + + st0 = readRegister(REG_OP_MODE); // Save the previous status + if( _modem == FSK ) + { + setLORA(); // Setting LoRa mode + } + value = readRegister(REG_MODEM_CONFIG1); + // added by C. Pham + if (_board==SX1272Chip) { + _bandwidth = (value >> 6); // Storing 2 MSB from REG_MODEM_CONFIG1 (=_bandwidth) + // added by C. Pham + // convert to common bandwidth values used by both SX1272 and SX1276 + _bandwidth += 7; + } + else + _bandwidth = (value >> 4); // Storing 4 MSB from REG_MODEM_CONFIG1 (=_bandwidth) + + if (_board==SX1272Chip) + _codingRate = (value >> 3) & 0x07; // Storing third, forth and fifth bits from + else + _codingRate = (value >> 1) & 0x07; // Storing 3-1 bits REG_MODEM_CONFIG1 (=_codingRate) + + value = readRegister(REG_MODEM_CONFIG2); + _spreadingFactor = (value >> 4) & 0x0F; // Storing 4 MSB from REG_MODEM_CONFIG2 (=_spreadingFactor) + state = 1; + + if( isBW(_bandwidth) ) // Checking available values for: + { // _bandwidth + if( isCR(_codingRate) ) // _codingRate + { // _spreadingFactor + if( isSF(_spreadingFactor) ) + { + state = 0; + } + } + } + +#if (SX1272_debug_mode > 1) + printf("## Parameters from configuration mode are:"); + printf("Bandwidth: %X\n",_bandwidth); + // Serial.print(_bandwidth, HEX); + // printf("\n"); + printf("\t Coding Rate: %X\n",_codingRate); + // Serial.print(_codingRate, HEX); + // printf("\n"); + printf("\t Spreading Factor: %X\n",_spreadingFactor); + // Serial.print(_spreadingFactor, HEX); + printf(" ##"); + printf("\n"); +#endif + + writeRegister(REG_OP_MODE, st0); // Getting back to previous status + wait_ms(100); + return state; +} + +/* + Function: Sets the bandwidth, coding rate and spreading factor of the LoRa modulation. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden command for this protocol + Parameters: + mode: mode number to set the required BW, SF and CR of LoRa modem. +*/ +int8_t SX1272::setMode(uint8_t mode) +{ + int8_t state = 2; + byte st0; + byte config1 = 0x00; + byte config2 = 0x00; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setMode'\n"); +#endif + + st0 = readRegister(REG_OP_MODE); // Save the previous status + + if( _modem == FSK ) + { + setLORA(); + } + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); // LoRa standby mode + + switch (mode) + { + // mode 1 (better reach, medium time on air) + case 1: + setCR(CR_5); // CR = 4/5 + setSF(SF_12); // SF = 12 + setBW(BW_125); // BW = 125 KHz + break; + + // mode 2 (medium reach, less time on air) + case 2: + setCR(CR_5); // CR = 4/5 + setSF(SF_12); // SF = 12 + setBW(BW_250); // BW = 250 KHz + break; + + // mode 3 (worst reach, less time on air) + case 3: + setCR(CR_5); // CR = 4/5 + setSF(SF_10); // SF = 10 + setBW(BW_125); // BW = 125 KHz + break; + + // mode 4 (better reach, low time on air) + case 4: + setCR(CR_5); // CR = 4/5 + setSF(SF_12); // SF = 12 + setBW(BW_500); // BW = 500 KHz + break; + + // mode 5 (better reach, medium time on air) + case 5: + setCR(CR_5); // CR = 4/5 + setSF(SF_10); // SF = 10 + setBW(BW_250); // BW = 250 KHz + break; + + // mode 6 (better reach, worst time-on-air) + case 6: + setCR(CR_5); // CR = 4/5 + setSF(SF_11); // SF = 11 + setBW(BW_500); // BW = 500 KHz + break; + + // mode 7 (medium-high reach, medium-low time-on-air) + case 7: + setCR(CR_5); // CR = 4/5 + setSF(SF_9); // SF = 9 + setBW(BW_250); // BW = 250 KHz + break; + + // mode 8 (medium reach, medium time-on-air) + case 8: + setCR(CR_5); // CR = 4/5 + setSF(SF_9); // SF = 9 + setBW(BW_500); // BW = 500 KHz + break; + + // mode 9 (medium-low reach, medium-high time-on-air) + case 9: + setCR(CR_5); // CR = 4/5 + setSF(SF_8); // SF = 8 + setBW(BW_500); // BW = 500 KHz + break; + + // mode 10 (worst reach, less time_on_air) + case 10: + setCR(CR_5); // CR = 4/5 + setSF(SF_7); // SF = 7 + setBW(BW_500); // BW = 500 KHz + break; + + // added by C. Pham + // test for LoRaWAN channel + case 11: + setCR(CR_5); // CR = 4/5 + setSF(SF_12); // SF = 12 + setBW(BW_125); // BW = 125 KHz + // set the sync word to the LoRaWAN sync word which is 0x34 + setSyncWord(0x34); + printf("** Using sync word of 0x%X\n",_syncWord); + // Serial.println(_syncWord, HEX); + break; + + default: state = -1; // The indicated mode doesn't exist + + }; + + if( state == -1 ) // if state = -1, don't change its value + { +#if (SX1272_debug_mode > 1) + printf("** The indicated mode doesn't exist, "); + printf("please select from 1 to 10 **"); +#endif + } + else + { + printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> verifications \n"); + state = 1; + config1 = readRegister(REG_MODEM_CONFIG1); + switch (mode) + { // Different way to check for each mode: + // (config1 >> 3) ---> take out bits 7-3 from REG_MODEM_CONFIG1 (=_bandwidth & _codingRate together) + // (config2 >> 4) ---> take out bits 7-4 from REG_MODEM_CONFIG2 (=_spreadingFactor) + + // mode 1: BW = 125 KHz, CR = 4/5, SF = 12. + case 1: + + //modified by C. Pham + if (_board==SX1272Chip) { + //////////////////////////////////////////////possible pb sur config1 qui vaut 0 + if( (config1 >> 3) == 0x01 ) + state=0; + } + else { + // (config1 >> 1) ---> take out bits 7-1 from REG_MODEM_CONFIG1 (=_bandwidth & _codingRate together) + if( (config1 >> 1) == 0x39 ) + state=0; + } + + if( state==0) { + state = 1; + config2 = readRegister(REG_MODEM_CONFIG2); + + if( (config2 >> 4) == SF_12 ) + { + state = 0; + } + } + break; + + + // mode 2: BW = 250 KHz, CR = 4/5, SF = 12. + case 2: + + //modified by C. Pham + if (_board==SX1272Chip) { + if( (config1 >> 3) == 0x09 ) + state=0; + } + else { + // (config1 >> 1) ---> take out bits 7-1 from REG_MODEM_CONFIG1 (=_bandwidth & _codingRate together) + if( (config1 >> 1) == 0x41 ) + state=0; + } + + if( state==0) { + state = 1; + config2 = readRegister(REG_MODEM_CONFIG2); + + if( (config2 >> 4) == SF_12 ) + { + state = 0; + } + } + break; + + // mode 3: BW = 125 KHz, CR = 4/5, SF = 10. + case 3: + + //modified by C. Pham + if (_board==SX1272Chip) { + if( (config1 >> 3) == 0x01 ) + state=0; + } + else { + // (config1 >> 1) ---> take out bits 7-1 from REG_MODEM_CONFIG1 (=_bandwidth & _codingRate together) + if( (config1 >> 1) == 0x39 ) + state=0; + } + + if( state==0) { + state = 1; + config2 = readRegister(REG_MODEM_CONFIG2); + + if( (config2 >> 4) == SF_10 ) + { + state = 0; + } + } + break; + + // mode 4: BW = 500 KHz, CR = 4/5, SF = 12. + case 4: + + //modified by C. Pham + if (_board==SX1272Chip) { + if( (config1 >> 3) == 0x11 ) + state=0; + } + else { + // (config1 >> 1) ---> take out bits 7-1 from REG_MODEM_CONFIG1 (=_bandwidth & _codingRate together) + if( (config1 >> 1) == 0x49 ) + state=0; + } + + if( state==0) { + state = 1; + config2 = readRegister(REG_MODEM_CONFIG2); + + if( (config2 >> 4) == SF_12 ) + { + state = 0; + } + } + break; + + // mode 5: BW = 250 KHz, CR = 4/5, SF = 10. + case 5: + + //modified by C. Pham + if (_board==SX1272Chip) { + if( (config1 >> 3) == 0x09 ) + state=0; + } + else { + // (config1 >> 1) ---> take out bits 7-1 from REG_MODEM_CONFIG1 (=_bandwidth & _codingRate together) + if( (config1 >> 1) == 0x41 ) + state=0; + } + + if( state==0) { + state = 1; + config2 = readRegister(REG_MODEM_CONFIG2); + + if( (config2 >> 4) == SF_10 ) + { + state = 0; + } + } + break; + + // mode 6: BW = 500 KHz, CR = 4/5, SF = 11. + case 6: + + //modified by C. Pham + if (_board==SX1272Chip) { + if( (config1 >> 3) == 0x11 ) + state=0; + } + else { + // (config1 >> 1) ---> take out bits 7-1 from REG_MODEM_CONFIG1 (=_bandwidth & _codingRate together) + if( (config1 >> 1) == 0x49 ) + state=0; + } + + if( state==0) { + state = 1; + config2 = readRegister(REG_MODEM_CONFIG2); + + if( (config2 >> 4) == SF_11 ) + { + state = 0; + } + } + break; + + // mode 7: BW = 250 KHz, CR = 4/5, SF = 9. + case 7: + + //modified by C. Pham + if (_board==SX1272Chip) { + if( (config1 >> 3) == 0x09 ) + state=0; + } + else { + // (config1 >> 1) ---> take out bits 7-1 from REG_MODEM_CONFIG1 (=_bandwidth & _codingRate together) + if( (config1 >> 1) == 0x41 ) + state=0; + } + + if( state==0) { + state = 1; + config2 = readRegister(REG_MODEM_CONFIG2); + + if( (config2 >> 4) == SF_9 ) + { + state = 0; + } + } + break; + + // mode 8: BW = 500 KHz, CR = 4/5, SF = 9. + case 8: + + //modified by C. Pham + if (_board==SX1272Chip) { + if( (config1 >> 3) == 0x11 ) + state=0; + } + else { + // (config1 >> 1) ---> take out bits 7-1 from REG_MODEM_CONFIG1 (=_bandwidth & _codingRate together) + if( (config1 >> 1) == 0x49 ) + state=0; + } + + if( state==0) { + state = 1; + config2 = readRegister(REG_MODEM_CONFIG2); + + if( (config2 >> 4) == SF_9 ) + { + state = 0; + } + } + break; + + // mode 9: BW = 500 KHz, CR = 4/5, SF = 8. + case 9: + + //modified by C. Pham + if (_board==SX1272Chip) { + if( (config1 >> 3) == 0x11 ) + state=0; + } + else { + // (config1 >> 1) ---> take out bits 7-1 from REG_MODEM_CONFIG1 (=_bandwidth & _codingRate together) + if( (config1 >> 1) == 0x49 ) + state=0; + } + + if( state==0) { + state = 1; + config2 = readRegister(REG_MODEM_CONFIG2); + + if( (config2 >> 4) == SF_8 ) + { + state = 0; + } + } + break; + + // mode 10: BW = 500 KHz, CR = 4/5, SF = 7. + case 10: + + //modified by C. Pham + if (_board==SX1272Chip) { + if( (config1 >> 3) == 0x11 ) + state=0; + } + else { + // (config1 >> 1) ---> take out bits 7-1 from REG_MODEM_CONFIG1 (=_bandwidth & _codingRate together) + if( (config1 >> 1) == 0x49 ) + state=0; + } + + if( state==0) { + state = 1; + config2 = readRegister(REG_MODEM_CONFIG2); + + if( (config2 >> 4) == SF_7 ) + { + state = 0; + } + } + break; + + // added by C. Pham + // test of LoRaWAN channel + // mode 11: BW = 125 KHz, CR = 4/5, SF = 12. + case 11: + + //modified by C. Pham + if (_board==SX1272Chip) { + if( (config1 >> 3) == 0x01 ) + state=0; + } + else { + // (config1 >> 1) ---> take out bits 7-1 from REG_MODEM_CONFIG1 (=_bandwidth & _codingRate together) + if( (config1 >> 1) == 0x39 ) + state=0; + } + + if( state==0) { + state = 1; + config2 = readRegister(REG_MODEM_CONFIG2); + + if( (config2 >> 4) == SF_12 ) + { + state = 0; + } + } + break; + }// end switch + + if (mode!=11) { + setSyncWord(_defaultSyncWord); +#if (SX1272_debug_mode > 1) + printf("*** Using sync word of 0x%X\n",_defaultSyncWord); + // Serial.println(_defaultSyncWord, HEX); +#endif + } + } + // added by C. Pham + if (state == 0) + _loraMode=mode; + +#if (SX1272_debug_mode > 1) + + if( state == 0 ) + { + printf("## Mode %d ",mode); + // Serial.print(mode, DEC); + printf(" configured with success ##"); + } + else + { + printf("** There has been an error while configuring mode %d ",mode); + // Serial.print(mode, DEC); + printf(". **\n"); + } +#endif + + writeRegister(REG_OP_MODE, st0); // Getting back to previous status + wait_ms(100); + return state; +} + +/* + Function: Indicates if module is configured in implicit or explicit header mode. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::getHeader() +{ + int8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getHeader'\n"); +#endif + + // added by C. Pham + uint8_t theHeaderBit; + + if (_board==SX1272Chip) + theHeaderBit=2; + else + theHeaderBit=0; + + // take out bit 2 from REG_MODEM_CONFIG1 indicates ImplicitHeaderModeOn + if( bitRead(REG_MODEM_CONFIG1, theHeaderBit) == 0 ) + { // explicit header mode (ON) + _header = HEADER_ON; + state = 1; + } + else + { // implicit header mode (OFF) + _header = HEADER_OFF; + state = 1; + } + + state = 0; + + if( _modem == FSK ) + { // header is not available in FSK mode +#if (SX1272_debug_mode > 1) + printf("## Notice that FSK mode packets hasn't header ##"); + printf("\n"); +#endif + } + else + { // header in LoRa mode +#if (SX1272_debug_mode > 1) + printf("## Header is "); + if( _header == HEADER_ON ) + { + printf("in explicit header mode ##"); + } + else + { + printf("in implicit header mode ##"); + } + printf("\n"); +#endif + } + return state; +} + +/* + Function: Sets the module in explicit header mode (header is sent). + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden command for this protocol +*/ +int8_t SX1272::setHeaderON() +{ + int8_t state = 2; + byte config1; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setHeaderON'\n"); +#endif + + if( _modem == FSK ) + { + state = -1; // header is not available in FSK mode +#if (SX1272_debug_mode > 1) + printf("## FSK mode packets hasn't header ##"); + printf("\n"); +#endif + } + else + { + config1 = readRegister(REG_MODEM_CONFIG1); // Save config1 to modify only the header bit + if( _spreadingFactor == 6 ) + { + state = -1; // Mandatory headerOFF with SF = 6 +#if (SX1272_debug_mode > 1) + printf("## Mandatory implicit header mode with spreading factor = 6 ##"); +#endif + } + else + { + // added by C. Pham + if (_board==SX1272Chip) + config1 = config1 & 0B11111011; // clears bit 2 from config1 = headerON + else + config1 = config1 & 0B11111110; // clears bit 0 from config1 = headerON + + writeRegister(REG_MODEM_CONFIG1,config1); // Update config1 + } + + // added by C. Pham + uint8_t theHeaderBit; + + if (_board==SX1272Chip) + theHeaderBit=2; + else + theHeaderBit=0; + + if( _spreadingFactor != 6 ) + { // checking headerON taking out bit 2 from REG_MODEM_CONFIG1 + config1 = readRegister(REG_MODEM_CONFIG1); + // modified by C. Pham + if( bitRead(config1, theHeaderBit) == HEADER_ON ) + { + state = 0; + _header = HEADER_ON; +#if (SX1272_debug_mode > 1) + printf("## Header has been activated ##"); + printf("\n"); +#endif + } + else + { + state = 1; + } + } + // modifie par C.Dupaty + //return state; + } + return state; +} + +/* + Function: Sets the module in implicit header mode (header is not sent). + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden command for this protocol +*/ +int8_t SX1272::setHeaderOFF() +{ + int8_t state = 2; + byte config1; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setHeaderOFF'\n"); +#endif + + if( _modem == FSK ) + { // header is not available in FSK mode + state = -1; +#if (SX1272_debug_mode > 1) + printf("## Notice that FSK mode packets hasn't header ##"); + printf("\n"); +#endif + } + else + { + config1 = readRegister(REG_MODEM_CONFIG1); // Save config1 to modify only the header bit + + // modified by C. Pham + if (_board==SX1272Chip) + config1 = config1 | 0B00000100; // sets bit 2 from REG_MODEM_CONFIG1 = headerOFF + else + config1 = config1 | 0B00000001; // sets bit 0 from REG_MODEM_CONFIG1 = headerOFF + + writeRegister(REG_MODEM_CONFIG1,config1); // Update config1 + + config1 = readRegister(REG_MODEM_CONFIG1); + + // added by C. Pham + uint8_t theHeaderBit; + + if (_board==SX1272Chip) + theHeaderBit=2; + else + theHeaderBit=0; + + if( bitRead(config1, theHeaderBit) == HEADER_OFF ) + { // checking headerOFF taking out bit 2 from REG_MODEM_CONFIG1 + state = 0; + _header = HEADER_OFF; + +#if (SX1272_debug_mode > 1) + printf("## Header has been desactivated ##"); + printf("\n"); +#endif + } + else + { + state = 1; +#if (SX1272_debug_mode > 1) + printf("** Header hasn't been desactivated ##"); + printf("\n"); +#endif + } + } + return state; +} + +/* + Function: Indicates if module is configured with or without checking CRC. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::getCRC() +{ + int8_t state = 2; + byte value; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getCRC'\n"); +#endif + + if( _modem == LORA ) + { // LoRa mode + + // added by C. Pham + uint8_t theRegister; + uint8_t theCrcBit; + + if (_board==SX1272Chip) { + theRegister=REG_MODEM_CONFIG1; + theCrcBit=1; + } + else { + theRegister=REG_MODEM_CONFIG2; + theCrcBit=2; + } + + // take out bit 1 from REG_MODEM_CONFIG1 indicates RxPayloadCrcOn + value = readRegister(theRegister); + if( bitRead(value, theCrcBit) == CRC_OFF ) + { // CRCoff + _CRC = CRC_OFF; +#if (SX1272_debug_mode > 1) + printf("## CRC is desactivated ##"); + printf("\n"); +#endif + state = 0; + } + else + { // CRCon + _CRC = CRC_ON; +#if (SX1272_debug_mode > 1) + printf("## CRC is activated ##"); + printf("\n"); +#endif + state = 0; + } + } + else + { // FSK mode + + // take out bit 2 from REG_PACKET_CONFIG1 indicates CrcOn + value = readRegister(REG_PACKET_CONFIG1); + if( bitRead(value, 4) == CRC_OFF ) + { // CRCoff + _CRC = CRC_OFF; +#if (SX1272_debug_mode > 1) + printf("## CRC is desactivated ##"); + printf("\n"); +#endif + state = 0; + } + else + { // CRCon + _CRC = CRC_ON; +#if (SX1272_debug_mode > 1) + printf("## CRC is activated ##"); + printf("\n"); +#endif + state = 0; + } + } + if( state != 0 ) + { + state = 1; +#if (SX1272_debug_mode > 1) + printf("** There has been an error while getting configured CRC **"); + printf("\n"); +#endif + } + return state; +} + +/* + Function: Sets the module with CRC on. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::setCRC_ON() +{ + uint8_t state = 2; + byte config1; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setCRC_ON'\n"); +#endif + + if( _modem == LORA ) + { // LORA mode + + // added by C. Pham + uint8_t theRegister; + uint8_t theCrcBit; + + if (_board==SX1272Chip) { + theRegister=REG_MODEM_CONFIG1; + theCrcBit=1; + } + else { + theRegister=REG_MODEM_CONFIG2; + theCrcBit=2; + } + + config1 = readRegister(theRegister); // Save config1 to modify only the CRC bit + + if (_board==SX1272Chip) + config1 = config1 | 0B00000010; // sets bit 1 from REG_MODEM_CONFIG1 = CRC_ON + else + config1 = config1 | 0B00000100; // sets bit 2 from REG_MODEM_CONFIG2 = CRC_ON + + writeRegister(theRegister,config1); + + state = 1; + + config1 = readRegister(theRegister); + + if( bitRead(config1, theCrcBit) == CRC_ON ) + { // take out bit 1 from REG_MODEM_CONFIG1 indicates RxPayloadCrcOn + state = 0; + _CRC = CRC_ON; +#if (SX1272_debug_mode > 1) + printf("## CRC has been activated ##"); + printf("\n"); +#endif + } + } + else + { // FSK mode + config1 = readRegister(REG_PACKET_CONFIG1); // Save config1 to modify only the CRC bit + config1 = config1 | 0B00010000; // set bit 4 and 3 from REG_MODEM_CONFIG1 = CRC_ON + writeRegister(REG_PACKET_CONFIG1,config1); + + state = 1; + + config1 = readRegister(REG_PACKET_CONFIG1); + if( bitRead(config1, 4) == CRC_ON ) + { // take out bit 4 from REG_PACKET_CONFIG1 indicates CrcOn + state = 0; + _CRC = CRC_ON; +#if (SX1272_debug_mode > 1) + printf("## CRC has been activated ##"); + printf("\n"); +#endif + } + } + if( state != 0 ) + { + state = 1; +#if (SX1272_debug_mode > 1) + printf("** There has been an error while setting CRC ON **"); + printf("\n"); +#endif + } + return state; +} + +/* + Function: Sets the module with CRC off. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::setCRC_OFF() +{ + int8_t state = 2; + byte config1; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setCRC_OFF'\n"); +#endif + + if( _modem == LORA ) + { // LORA mode + + // added by C. Pham + uint8_t theRegister; + uint8_t theCrcBit; + + if (_board==SX1272Chip) { + theRegister=REG_MODEM_CONFIG1; + theCrcBit=1; + } + else { + theRegister=REG_MODEM_CONFIG2; + theCrcBit=2; + } + + config1 = readRegister(theRegister); // Save config1 to modify only the CRC bit + if (_board==SX1272Chip) + config1 = config1 & 0B11111101; // clears bit 1 from config1 = CRC_OFF + else + config1 = config1 & 0B11111011; // clears bit 2 from config1 = CRC_OFF + + writeRegister(theRegister,config1); + + config1 = readRegister(theRegister); + if( (bitRead(config1, theCrcBit)) == CRC_OFF ) + { // take out bit 1 from REG_MODEM_CONFIG1 indicates RxPayloadCrcOn + state = 0; + _CRC = CRC_OFF; +#if (SX1272_debug_mode > 1) + printf("## CRC has been desactivated ##"); + printf("\n"); +#endif + } + } + else + { // FSK mode + config1 = readRegister(REG_PACKET_CONFIG1); // Save config1 to modify only the CRC bit + config1 = config1 & 0B11101111; // clears bit 4 from config1 = CRC_OFF + writeRegister(REG_PACKET_CONFIG1,config1); + + config1 = readRegister(REG_PACKET_CONFIG1); + if( bitRead(config1, 4) == CRC_OFF ) + { // take out bit 4 from REG_PACKET_CONFIG1 indicates RxPayloadCrcOn + state = 0; + _CRC = CRC_OFF; +#if (SX1272_debug_mode > 1) + printf("## CRC has been desactivated ##"); + printf("\n"); +#endif + } + } + if( state != 0 ) + { + state = 1; +#if (SX1272_debug_mode > 1) + printf("** There has been an error while setting CRC OFF **"); + printf("\n"); +#endif + } + return state; +} + +/* + Function: Checks if SF is a valid value. + Returns: Boolean that's 'true' if the SF value exists and + it's 'false' if the SF value does not exist. + Parameters: + spr: spreading factor value to check. +*/ +boolean SX1272::isSF(uint8_t spr) +{ +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'isSF'\n"); +#endif + + // Checking available values for _spreadingFactor + switch(spr) + { + case SF_6: + case SF_7: + case SF_8: + case SF_9: + case SF_10: + case SF_11: + case SF_12: + return true; + //break; + + default: + return false; + } +#if (SX1272_debug_mode > 1) + printf("## Finished 'isSF' ##"); + printf("\n"); +#endif +} + +/* + Function: Gets the SF within the module is configured. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden command for this protocol +*/ +int8_t SX1272::getSF() +{ + int8_t state = 2; + byte config2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getSF'\n"); +#endif + + if( _modem == FSK ) + { + state = -1; // SF is not available in FSK mode +#if (SX1272_debug_mode > 1) + printf("** FSK mode hasn't spreading factor **"); + printf("\n"); +#endif + } + else + { + // take out bits 7-4 from REG_MODEM_CONFIG2 indicates _spreadingFactor + config2 = (readRegister(REG_MODEM_CONFIG2)) >> 4; + _spreadingFactor = config2; + state = 1; + + if( (config2 == _spreadingFactor) && isSF(_spreadingFactor) ) + { + state = 0; +#if (SX1272_debug_mode > 1) + printf("## Spreading factor is %X",_spreadingFactor); + // Serial.print(_spreadingFactor,HEX); + printf(" ##"); + printf("\n"); +#endif + } + } + return state; +} + +/* + Function: Sets the indicated SF in the module. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + Parameters: + spr: spreading factor value to set in LoRa modem configuration. +*/ +uint8_t SX1272::setSF(uint8_t spr) +{ + byte st0; + int8_t state = 2; + byte config1; + byte config2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setSF'\n"); +#endif + + st0 = readRegister(REG_OP_MODE); // Save the previous status + + if( _modem == FSK ) + { +#if (SX1272_debug_mode > 1) + printf("## Notice that FSK hasn't Spreading Factor parameter, "); + printf("so you are configuring it in LoRa mode ##"); +#endif + state = setLORA(); // Setting LoRa mode + } + else + { // LoRa mode + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); // LoRa standby mode + config2 = (readRegister(REG_MODEM_CONFIG2)); // Save config2 to modify SF value (bits 7-4) + switch(spr) + { + case SF_6: config2 = config2 & 0B01101111; // clears bits 7 & 4 from REG_MODEM_CONFIG2 + config2 = config2 | 0B01100000; // sets bits 6 & 5 from REG_MODEM_CONFIG2 + setHeaderOFF(); // Mandatory headerOFF with SF = 6 + break; + case SF_7: config2 = config2 & 0B01111111; // clears bits 7 from REG_MODEM_CONFIG2 + config2 = config2 | 0B01110000; // sets bits 6, 5 & 4 + break; + case SF_8: config2 = config2 & 0B10001111; // clears bits 6, 5 & 4 from REG_MODEM_CONFIG2 + config2 = config2 | 0B10000000; // sets bit 7 from REG_MODEM_CONFIG2 + break; + case SF_9: config2 = config2 & 0B10011111; // clears bits 6, 5 & 4 from REG_MODEM_CONFIG2 + config2 = config2 | 0B10010000; // sets bits 7 & 4 from REG_MODEM_CONFIG2 + break; + case SF_10: config2 = config2 & 0B10101111; // clears bits 6 & 4 from REG_MODEM_CONFIG2 + config2 = config2 | 0B10100000; // sets bits 7 & 5 from REG_MODEM_CONFIG2 + break; + case SF_11: config2 = config2 & 0B10111111; // clears bit 6 from REG_MODEM_CONFIG2 + config2 = config2 | 0B10110000; // sets bits 7, 5 & 4 from REG_MODEM_CONFIG2 + getBW(); + + // modified by C. Pham + if( _bandwidth == BW_125) + { // LowDataRateOptimize (Mandatory with SF_11 if BW_125) + if (_board==SX1272Chip) { + config1 = (readRegister(REG_MODEM_CONFIG1)); // Save config1 to modify only the LowDataRateOptimize + config1 = config1 | 0B00000001; + writeRegister(REG_MODEM_CONFIG1,config1); + } + else { + byte config3=readRegister(REG_MODEM_CONFIG3); + config3 = config3 | 0B00001000; + writeRegister(REG_MODEM_CONFIG3,config3); + } + } + break; + case SF_12: config2 = config2 & 0B11001111; // clears bits 5 & 4 from REG_MODEM_CONFIG2 + config2 = config2 | 0B11000000; // sets bits 7 & 6 from REG_MODEM_CONFIG2 + if( _bandwidth == BW_125) + { // LowDataRateOptimize (Mandatory with SF_12 if BW_125) + // modified by C. Pham + if (_board==SX1272Chip) { + config1 = (readRegister(REG_MODEM_CONFIG1)); // Save config1 to modify only the LowDataRateOptimize + config1 = config1 | 0B00000001; + writeRegister(REG_MODEM_CONFIG1,config1); + } + else { + byte config3=readRegister(REG_MODEM_CONFIG3); + config3 = config3 | 0B00001000; + writeRegister(REG_MODEM_CONFIG3,config3); + } + } + break; + } + + // Check if it is neccesary to set special settings for SF=6 + if( spr == SF_6 ) + { + // Mandatory headerOFF with SF = 6 (Implicit mode) + setHeaderOFF(); + + // Set the bit field DetectionOptimize of + // register RegLoRaDetectOptimize to value "0b101". + writeRegister(REG_DETECT_OPTIMIZE, 0x05); + + // Write 0x0C in the register RegDetectionThreshold. + writeRegister(REG_DETECTION_THRESHOLD, 0x0C); + } + else + { + // added by C. Pham + setHeaderON(); + + // LoRa detection Optimize: 0x03 --> SF7 to SF12 + writeRegister(REG_DETECT_OPTIMIZE, 0x03); + + // LoRa detection threshold: 0x0A --> SF7 to SF12 + writeRegister(REG_DETECTION_THRESHOLD, 0x0A); + } + + // added by C. Pham + if (_board==SX1272Chip) { + // comment by C. Pham + // bit 9:8 of SymbTimeout are then 11 + // single_chan_pkt_fwd uses 00 and then 00001000 + // why? + // sets bit 2-0 (AgcAutoOn and SymbTimout) for any SF value + //config2 = config2 | 0B00000111; + // modified by C. Pham + config2 = config2 | 0B00000100; + writeRegister(REG_MODEM_CONFIG1, config1); // Update config1 + } + else { + // set the AgcAutoOn in bit 2 of REG_MODEM_CONFIG3 + uint8_t config3 = (readRegister(REG_MODEM_CONFIG3)); + config3=config3 | 0B00000100; + writeRegister(REG_MODEM_CONFIG3, config3); + } + + // here we write the new SF + writeRegister(REG_MODEM_CONFIG2, config2); // Update config2 + + wait_ms(100); + + // added by C. Pham + byte configAgc; + uint8_t theLDRBit; + + if (_board==SX1272Chip) { + config1 = (readRegister(REG_MODEM_CONFIG1)); // Save config1 to check update + config2 = (readRegister(REG_MODEM_CONFIG2)); // Save config2 to check update + // comment by C. Pham + // (config2 >> 4) ---> take out bits 7-4 from REG_MODEM_CONFIG2 (=_spreadingFactor) + // bitRead(config1, 0) ---> take out bits 1 from config1 (=LowDataRateOptimize) + // config2 is only for the AgcAutoOn + configAgc=config2; + theLDRBit=0; + } + else { + config1 = (readRegister(REG_MODEM_CONFIG3)); // Save config1 to check update + config2 = (readRegister(REG_MODEM_CONFIG2)); + // LowDataRateOptimize is in REG_MODEM_CONFIG3 + // AgcAutoOn is in REG_MODEM_CONFIG3 + configAgc=config1; + theLDRBit=3; + } + + + switch(spr) + { + case SF_6: if( ((config2 >> 4) == spr) + && (bitRead(configAgc, 2) == 1) + && (_header == HEADER_OFF)) + { + state = 0; + } + break; + case SF_7: if( ((config2 >> 4) == 0x07) + && (bitRead(configAgc, 2) == 1)) + { + state = 0; + } + break; + case SF_8: if( ((config2 >> 4) == 0x08) + && (bitRead(configAgc, 2) == 1)) + { + state = 0; + } + break; + case SF_9: if( ((config2 >> 4) == 0x09) + && (bitRead(configAgc, 2) == 1)) + { + state = 0; + } + break; + case SF_10: if( ((config2 >> 4) == 0x0A) + && (bitRead(configAgc, 2) == 1)) + { + state = 0; + } + break; + case SF_11: if( ((config2 >> 4) == 0x0B) + && (bitRead(configAgc, 2) == 1) + && (bitRead(config1, theLDRBit) == 1)) + { + state = 0; + } + break; + case SF_12: if( ((config2 >> 4) == 0x0C) + && (bitRead(configAgc, 2) == 1) + && (bitRead(config1, theLDRBit) == 1)) + { + state = 0; + } + break; + default: state = 1; + } + } + + writeRegister(REG_OP_MODE, st0); // Getting back to previous status + wait_ms(100); + + if( isSF(spr) ) + { // Checking available value for _spreadingFactor + state = 0; + _spreadingFactor = spr; +#if (SX1272_debug_mode > 1) + printf("## Spreading factor %d ",_spreadingFactor); + // Serial.print(_spreadingFactor, DEC); + printf(" has been successfully set ##"); + printf("\n"); +#endif + } + else + { + if( state != 0 ) + { +#if (SX1272_debug_mode > 1) + printf("** There has been an error while setting the spreading factor **"); + printf("\n"); +#endif + } + } + return state; +} + +/* + Function: Checks if BW is a valid value. + Returns: Boolean that's 'true' if the BW value exists and + it's 'false' if the BW value does not exist. + Parameters: + band: bandwidth value to check. +*/ +boolean SX1272::isBW(uint16_t band) +{ +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'isBW'\n"); +#endif + + // Checking available values for _bandwidth + // added by C. Pham + if (_board==SX1272Chip) { + switch(band) + { + case BW_125: + case BW_250: + case BW_500: + return true; + //break; + + default: + return false; + } + } + else { + switch(band) + { + case BW_7_8: + case BW_10_4: + case BW_15_6: + case BW_20_8: + case BW_31_25: + case BW_41_7: + case BW_62_5: + case BW_125: + case BW_250: + case BW_500: + return true; + //break; + + default: + return false; + } + } + +#if (SX1272_debug_mode > 1) + printf("## Finished 'isBW' ##"); + printf("\n"); +#endif +} + +/* + Function: Gets the BW within the module is configured. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden command for this protocol +*/ +int8_t SX1272::getBW() +{ + int8_t state = 2; + byte config1; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getBW'\n"); +#endif + + if( _modem == FSK ) + { + state = -1; // BW is not available in FSK mode +#if (SX1272_debug_mode > 1) + printf("** FSK mode hasn't bandwidth **"); + printf("\n"); +#endif + } + else + { + // added by C. Pham + if (_board==SX1272Chip) { + // take out bits 7-6 from REG_MODEM_CONFIG1 indicates _bandwidth + config1 = (readRegister(REG_MODEM_CONFIG1)) >> 6; + } + else { + // take out bits 7-4 from REG_MODEM_CONFIG1 indicates _bandwidth + config1 = (readRegister(REG_MODEM_CONFIG1)) >> 4; + } + + _bandwidth = config1; + + if( (config1 == _bandwidth) && isBW(_bandwidth) ) + { + state = 0; +#if (SX1272_debug_mode > 1) + printf("## Bandwidth is %X ",_bandwidth); + // Serial.print(_bandwidth,HEX); + printf(" ##"); + printf("\n"); +#endif + } + else + { + state = 1; +#if (SX1272_debug_mode > 1) + printf("** There has been an error while getting bandwidth **"); + printf("\n"); +#endif + } + } + return state; +} + +/* + Function: Sets the indicated BW in the module. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + Parameters: + band: bandwith value to set in LoRa modem configuration. +*/ +int8_t SX1272::setBW(uint16_t band) +{ + byte st0; + int8_t state = 2; + byte config1; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setBW'\n"); +#endif + + if(!isBW(band) ) + { + state = 1; +#if (SX1272_debug_mode > 1) + printf("** Bandwidth %X ",band); + // Serial.print(band, HEX); + printf(" is not a correct value **"); + printf("\n"); +#endif + return state; + } + + st0 = readRegister(REG_OP_MODE); // Save the previous status + + if( _modem == FSK ) + { +#if (SX1272_debug_mode > 1) + printf("## Notice that FSK hasn't Bandwidth parameter, "); + printf("so you are configuring it in LoRa mode ##"); +#endif + state = setLORA(); + } + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); // LoRa standby mode + config1 = (readRegister(REG_MODEM_CONFIG1)); // Save config1 to modify only the BW + + // added by C. Pham for SX1276 + if (_board==SX1272Chip) { + switch(band) + { + case BW_125: config1 = config1 & 0B00111111; // clears bits 7 & 6 from REG_MODEM_CONFIG1 + getSF(); + if( _spreadingFactor == 11 ) + { // LowDataRateOptimize (Mandatory with BW_125 if SF_11) + config1 = config1 | 0B00000001; + } + if( _spreadingFactor == 12 ) + { // LowDataRateOptimize (Mandatory with BW_125 if SF_12) + config1 = config1 | 0B00000001; + } + break; + case BW_250: config1 = config1 & 0B01111111; // clears bit 7 from REG_MODEM_CONFIG1 + config1 = config1 | 0B01000000; // sets bit 6 from REG_MODEM_CONFIG1 + break; + case BW_500: config1 = config1 & 0B10111111; //clears bit 6 from REG_MODEM_CONFIG1 + config1 = config1 | 0B10000000; //sets bit 7 from REG_MODEM_CONFIG1 + break; + } + } + else { + // SX1276 + config1 = config1 & 0B00001111; // clears bits 7 - 4 from REG_MODEM_CONFIG1 + switch(band) + { + case BW_125: + // 0111 + config1 = config1 | 0B01110000; + getSF(); + if( _spreadingFactor == 11 || _spreadingFactor == 12) + { // LowDataRateOptimize (Mandatory with BW_125 if SF_11 or SF_12) + byte config3=readRegister(REG_MODEM_CONFIG3); + config3 = config3 | 0B00001000; + writeRegister(REG_MODEM_CONFIG3,config3); + } + break; + case BW_250: + // 1000 + config1 = config1 | 0B10000000; + break; + case BW_500: + // 1001 + config1 = config1 | 0B10010000; + break; + } + } + // end + + writeRegister(REG_MODEM_CONFIG1,config1); // Update config1 + + wait_ms(100); + + config1 = (readRegister(REG_MODEM_CONFIG1)); + + // added by C. Pham + if (_board==SX1272Chip) { + // (config1 >> 6) ---> take out bits 7-6 from REG_MODEM_CONFIG1 (=_bandwidth) + switch(band) + { + case BW_125: if( (config1 >> 6) == SX1272_BW_125 ) + { + state = 0; + if( _spreadingFactor == 11 ) + { + if( bitRead(config1, 0) == 1 ) + { // LowDataRateOptimize + state = 0; + } + else + { + state = 1; + } + } + if( _spreadingFactor == 12 ) + { + if( bitRead(config1, 0) == 1 ) + { // LowDataRateOptimize + state = 0; + } + else + { + state = 1; + } + } + } + break; + case BW_250: if( (config1 >> 6) == SX1272_BW_250 ) + { + state = 0; + } + break; + case BW_500: if( (config1 >> 6) == SX1272_BW_500 ) + { + state = 0; + } + break; + } + } + else { + // (config1 >> 4) ---> take out bits 7-4 from REG_MODEM_CONFIG1 (=_bandwidth) + switch(band) + { + case BW_125: if( (config1 >> 4) == BW_125 ) + { + state = 0; + + byte config3 = (readRegister(REG_MODEM_CONFIG3)); + + if( _spreadingFactor == 11 ) + { + if( bitRead(config3, 3) == 1 ) + { // LowDataRateOptimize + state = 0; + } + else + { + state = 1; + } + } + if( _spreadingFactor == 12 ) + { + if( bitRead(config3, 3) == 1 ) + { // LowDataRateOptimize + state = 0; + } + else + { + state = 1; + } + } + } + break; + case BW_250: if( (config1 >> 4) == BW_250 ) + { + state = 0; + } + break; + case BW_500: if( (config1 >> 4) == BW_500 ) + { + state = 0; + } + break; + } + } + + if(state==0) + { + _bandwidth = band; +#if (SX1272_debug_mode > 1) + printf("## Bandwidth %X ",band); + // Serial.print(band, HEX); + printf(" has been successfully set ##"); + printf("\n"); +#endif + } + writeRegister(REG_OP_MODE, st0); // Getting back to previous status + wait_ms(100); + return state; +} + +/* + Function: Checks if CR is a valid value. + Returns: Boolean that's 'true' if the CR value exists and + it's 'false' if the CR value does not exist. + Parameters: + cod: coding rate value to check. +*/ +boolean SX1272::isCR(uint8_t cod) +{ +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'isCR'\n"); +#endif + + // Checking available values for _codingRate + switch(cod) + { + case CR_5: + case CR_6: + case CR_7: + case CR_8: + return true; + //break; + + default: + return false; + } +#if (SX1272_debug_mode > 1) + printf("## Finished 'isCR' ##"); + printf("\n"); +#endif +} + +/* + Function: Indicates the CR within the module is configured. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden command for this protocol +*/ +int8_t SX1272::getCR() +{ + int8_t state = 2; + byte config1; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getCR'\n"); +#endif + + if( _modem == FSK ) + { + state = -1; // CR is not available in FSK mode +#if (SX1272_debug_mode > 1) + printf("** FSK mode hasn't coding rate **"); + printf("\n"); +#endif + } + else + { + // added by C. Pham + if (_board==SX1272Chip) { + // take out bits 7-3 from REG_MODEM_CONFIG1 indicates _bandwidth & _codingRate + config1 = (readRegister(REG_MODEM_CONFIG1)) >> 3; + config1 = config1 & 0B00000111; // clears bits 7-3 ---> clears _bandwidth + } + else { + // take out bits 7-1 from REG_MODEM_CONFIG1 indicates _bandwidth & _codingRate + config1 = (readRegister(REG_MODEM_CONFIG1)) >> 1; + config1 = config1 & 0B00000111; // clears bits 7-3 ---> clears _bandwidth + } + + _codingRate = config1; + state = 1; + + if( (config1 == _codingRate) && isCR(_codingRate) ) + { + state = 0; +#if (SX1272_debug_mode > 1) + printf("## Coding rate is %X ",_codingRate); + // Serial.print(_codingRate, HEX); + printf(" ##"); + printf("\n"); +#endif + } + } + return state; +} + +/* + Function: Sets the indicated CR in the module. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden command for this protocol + Parameters: + cod: coding rate value to set in LoRa modem configuration. +*/ +int8_t SX1272::setCR(uint8_t cod) +{ + byte st0; + int8_t state = 2; + byte config1; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setCR'\n"); +#endif + + st0 = readRegister(REG_OP_MODE); // Save the previous status + + if( _modem == FSK ) + { +#if (SX1272_debug_mode > 1) + printf("## Notice that FSK hasn't Coding Rate parameter, "); + printf("so you are configuring it in LoRa mode ##"); +#endif + state = setLORA(); + } + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); // Set Standby mode to write in registers + + config1 = readRegister(REG_MODEM_CONFIG1); // Save config1 to modify only the CR + + // added by C. Pham + if (_board==SX1272Chip) { + switch(cod) + { + case CR_5: config1 = config1 & 0B11001111; // clears bits 5 & 4 from REG_MODEM_CONFIG1 + config1 = config1 | 0B00001000; // sets bit 3 from REG_MODEM_CONFIG1 + break; + case CR_6: config1 = config1 & 0B11010111; // clears bits 5 & 3 from REG_MODEM_CONFIG1 + config1 = config1 | 0B00010000; // sets bit 4 from REG_MODEM_CONFIG1 + break; + case CR_7: config1 = config1 & 0B11011111; // clears bit 5 from REG_MODEM_CONFIG1 + config1 = config1 | 0B00011000; // sets bits 4 & 3 from REG_MODEM_CONFIG1 + break; + case CR_8: config1 = config1 & 0B11100111; // clears bits 4 & 3 from REG_MODEM_CONFIG1 + config1 = config1 | 0B00100000; // sets bit 5 from REG_MODEM_CONFIG1 + break; + } + } + else { + // SX1276 + config1 = config1 & 0B11110001; // clears bits 3 - 1 from REG_MODEM_CONFIG1 + switch(cod) + { + case CR_5: + config1 = config1 | 0B00000010; + break; + case CR_6: + config1 = config1 | 0B00000100; + break; + case CR_7: + config1 = config1 | 0B00000110; + break; + case CR_8: + config1 = config1 | 0B00001000; + break; + } + } + writeRegister(REG_MODEM_CONFIG1, config1); // Update config1 + + wait_ms(100); + + config1 = readRegister(REG_MODEM_CONFIG1); + + // added by C. Pham + uint8_t nshift=3; + + // only 1 right shift for SX1276 + if (_board==SX1276Chip) + nshift=1; + + // ((config1 >> 3) & 0B0000111) ---> take out bits 5-3 from REG_MODEM_CONFIG1 (=_codingRate) + switch(cod) + { + case CR_5: if( ((config1 >> nshift) & 0B0000111) == 0x01 ) + { + state = 0; + } + break; + case CR_6: if( ((config1 >> nshift) & 0B0000111) == 0x02 ) + { + state = 0; + } + break; + case CR_7: if( ((config1 >> nshift) & 0B0000111) == 0x03 ) + { + state = 0; + } + break; + case CR_8: if( ((config1 >> nshift) & 0B0000111) == 0x04 ) + { + state = 0; + } + break; + } + + + if( isCR(cod) ) + { + _codingRate = cod; +#if (SX1272_debug_mode > 1) + printf("## Coding Rate %X ",cod); + // Serial.print(cod, HEX); + printf(" has been successfully set ##"); + printf("\n"); +#endif + } + else + { + state = 1; +#if (SX1272_debug_mode > 1) + printf("** There has been an error while configuring Coding Rate parameter **"); + printf("\n"); +#endif + } + writeRegister(REG_OP_MODE,st0); // Getting back to previous status + wait_ms(100); + return state; +} + +/* + Function: Checks if channel is a valid value. + Returns: Boolean that's 'true' if the CR value exists and + it's 'false' if the CR value does not exist. + Parameters: + ch: frequency channel value to check. +*/ +boolean SX1272::isChannel(uint32_t ch) +{ +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'isChannel'\n"); +#endif + + // Checking available values for _channel + switch(ch) + { + //added by C. Pham + case CH_04_868: + case CH_05_868: + case CH_06_868: + case CH_07_868: + case CH_08_868: + case CH_09_868: + //end + case CH_10_868: + case CH_11_868: + case CH_12_868: + case CH_13_868: + case CH_14_868: + case CH_15_868: + case CH_16_868: + case CH_17_868: + //added by C. Pham + case CH_18_868: + //end + case CH_00_900: + case CH_01_900: + case CH_02_900: + case CH_03_900: + case CH_04_900: + case CH_05_900: + case CH_06_900: + case CH_07_900: + case CH_08_900: + case CH_09_900: + case CH_10_900: + case CH_11_900: + //added by C. Pham + case CH_12_900: + case CH_00_433: + case CH_01_433: + case CH_02_433: + case CH_03_433: + //end + return true; + //break; + + default: + return false; + } +#if (SX1272_debug_mode > 1) + printf("## Finished 'isChannel' ##"); + printf("\n"); +#endif +} + +/* + Function: Indicates the frequency channel within the module is configured. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::getChannel() +{ + uint8_t state = 2; + uint32_t ch; + uint8_t freq3; + uint8_t freq2; + uint8_t freq1; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getChannel'\n"); +#endif + + freq3 = readRegister(REG_FRF_MSB); // frequency channel MSB + freq2 = readRegister(REG_FRF_MID); // frequency channel MID + freq1 = readRegister(REG_FRF_LSB); // frequency channel LSB + ch = ((uint32_t)freq3 << 16) + ((uint32_t)freq2 << 8) + (uint32_t)freq1; + _channel = ch; // frequency channel + + if( (_channel == ch) && isChannel(_channel) ) + { + state = 0; +#if (SX1272_debug_mode > 1) + printf("## Frequency channel is %d ", _channel); + // Serial.print(_channel, HEX); + printf(" ##"); + printf("\n"); +#endif + } + else + { + state = 1; + } + return state; +} + +/* + Function: Sets the indicated channel in the module. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden command for this protocol + Parameters: + ch: frequency channel value to set in configuration. +*/ +int8_t SX1272::setChannel(uint32_t ch) +{ + byte st0; + int8_t state = 2; + unsigned int freq3; + unsigned int freq2; + uint8_t freq1; + uint32_t freq; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setChannel'\n"); +#endif + + // added by C. Pham + _starttime=millis(); + + st0 = readRegister(REG_OP_MODE); // Save the previous status + if( _modem == LORA ) + { + // LoRa Stdby mode in order to write in registers + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); + } + else + { + // FSK Stdby mode in order to write in registers + writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); + } + + freq3 = ((ch >> 16) & 0x0FF); // frequency channel MSB + freq2 = ((ch >> 8) & 0x0FF); // frequency channel MIB + freq1 = (ch & 0xFF); // frequency channel LSB + + writeRegister(REG_FRF_MSB, freq3); + writeRegister(REG_FRF_MID, freq2); + writeRegister(REG_FRF_LSB, freq1); + + // added by C. Pham + _stoptime=millis(); + + wait_ms(100); + + // storing MSB in freq channel value + freq3 = (readRegister(REG_FRF_MSB)); + freq = (freq3 << 8) & 0xFFFFFF; + + // storing MID in freq channel value + freq2 = (readRegister(REG_FRF_MID)); + freq = (freq << 8) + ((freq2 << 8) & 0xFFFFFF); + + // storing LSB in freq channel value + freq = freq + ((readRegister(REG_FRF_LSB)) & 0xFFFFFF); + + if( freq == ch ) + { + state = 0; + _channel = ch; +#if (SX1272_debug_mode > 1) + printf("## Frequency channel %X ",ch); + // Serial.print(ch, HEX); + printf(" has been successfully set ##"); + printf("\n"); +#endif + } + else + { + state = 1; + } + + // commented by C. Pham to avoid adding new channel each time + // besides, the test above is sufficient + /* + if(!isChannel(ch) ) + { + state = -1; +#if (SX1272_debug_mode > 1) + printf("** Frequency channel "); + Serial.print(ch, HEX); + printf("is not a correct value **"); + printf("\n"); +#endif + } + */ + + writeRegister(REG_OP_MODE, st0); // Getting back to previous status + wait_ms(100); + return state; +} + +/* + Function: Gets the signal power within the module is configured. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::getPower() +{ + uint8_t state = 2; + int8_t value = 0x00; // modifie par C.Dupaty type byte a l'origine + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getPower'\n"); +#endif + + value = readRegister(REG_PA_CONFIG); + state = 1; + + // modified by C. Pham + // get only the OutputPower + _power = value & 0B00001111; + + if( (value > -1) & (value < 16) ) + { + state = 0; +#if (SX1272_debug_mode > 1) + printf("## Output power is %X ",_power); + // Serial.print(_power, HEX); + printf(" ##"); + printf("\n"); +#endif + } + + return state; +} + +/* + Function: Sets the signal power indicated in the module. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden command for this protocol + Parameters: + p: power option to set in configuration. +*/ +int8_t SX1272::setPower(char p) +{ + byte st0; + int8_t state = 2; + byte value = 0x00; + + byte RegPaDacReg=(_board==SX1272Chip)?0x5A:0x4D; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setPower'\n"); +#endif + + st0 = readRegister(REG_OP_MODE); // Save the previous status + if( _modem == LORA ) + { // LoRa Stdby mode to write in registers + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); + } + else + { // FSK Stdby mode to write in registers + writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); + } + + switch (p) + { + // L = Low. On SX1272/76: PA0 on RFO setting + // H = High. On SX1272/76: PA0 on RFO setting + // M = MAX. On SX1272/76: PA0 on RFO setting + + // x = extreme; added by C. Pham. On SX1272/76: PA1&PA2 PA_BOOST setting + // X = eXtreme; added by C. Pham. On SX1272/76: PA1&PA2 PA_BOOST setting + 20dBm settings + + // added by C. Pham + // + case 'x': + case 'X': + case 'M': value = 0x0F; + // SX1272/76: 14dBm + break; + + // modified by C. Pham, set to 0x03 instead of 0x00 + case 'L': value = 0x03; + // SX1272/76: 2dBm + break; + + case 'H': value = 0x07; + // SX1272/76: 6dBm + break; + + default: state = -1; + break; + } + + // 100mA + setMaxCurrent(0x0B); + + if (p=='x') { + // we set only the PA_BOOST pin + // limit to 14dBm + value = 0x0C; + value = value & 0B10000000; + // set RegOcp for OcpOn and OcpTrim + // 130mA + setMaxCurrent(0x10); + } + + if (p=='X') { + // normally value = 0x0F; + // we set the PA_BOOST pin + value = value & 0B10000000; + // and then set the high output power config with register REG_PA_DAC + writeRegister(RegPaDacReg, 0x87); + // set RegOcp for OcpOn and OcpTrim + // 150mA + setMaxCurrent(0x12); + } + else { + // disable high power output in all other cases + writeRegister(RegPaDacReg, 0x84); + } + + // added by C. Pham + if (_board==SX1272Chip) { + // Pout = -1 + _power[3:0] on RFO + // Pout = 2 + _power[3:0] on PA_BOOST + // so: L=2dBm; H=6dBm, M=14dBm, x=14dBm (PA), X=20dBm(PA+PADAC) + writeRegister(REG_PA_CONFIG, value); // Setting output power value + } + else { + // for the SX1276 + + // set MaxPower to 7 -> Pmax=10.8+0.6*MaxPower [dBm] = 15 + value = value & 0B01110000; + + // then Pout = Pmax-(15-_power[3:0]) if PaSelect=0 (RFO pin for +14dBm) + // so L=3dBm; H=7dBm; M=15dBm (but should be limited to 14dBm by RFO pin) + + // and Pout = 17-(15-_power[3:0]) if PaSelect=1 (PA_BOOST pin for +14dBm) + // so x= 14dBm (PA); + // when p=='X' for 20dBm, value is 0x0F and RegPaDacReg=0x87 so 20dBm is enabled + + writeRegister(REG_PA_CONFIG, value); + } + + _power=value; + + value = readRegister(REG_PA_CONFIG); + + if( value == _power ) + { + state = 0; +#if (SX1272_debug_mode > 1) + printf("## Output power has been successfully set ##"); + printf("\n"); +#endif + } + else + { + state = 1; + } + + writeRegister(REG_OP_MODE, st0); // Getting back to previous status + wait_ms(100); + return state; +} + +/* + Function: Sets the signal power indicated in the module. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden command for this protocol + Parameters: + p: power option to set in configuration. +*/ +int8_t SX1272::setPowerNum(uint8_t pow) +{ + byte st0; + int8_t state = 2; + byte value = 0x00; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setPower'\n"); +#endif + + st0 = readRegister(REG_OP_MODE); // Save the previous status + if( _modem == LORA ) + { // LoRa Stdby mode to write in registers + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); + } + else + { // FSK Stdby mode to write in registers + writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); + } + + // Modifie par C.Dupaty + // if ( (pow >= 0) & (pow < 15) ) + if (pow < 15) + { + _power = pow; + } + else + { + state = -1; +#if (SX1272_debug_mode > 1) + printf("## Power value is not valid ##"); + printf("\n"); +#endif + } + + // added by C. Pham + if (_board==SX1276Chip) { + value=readRegister(REG_PA_CONFIG); + // clear OutputPower, but keep current value of PaSelect and MaxPower + value=value & 0B11110000; + value=value + _power; + _power=value; + } + writeRegister(REG_PA_CONFIG, _power); // Setting output power value + value = readRegister(REG_PA_CONFIG); + + if( value == _power ) + { + state = 0; +#if (SX1272_debug_mode > 1) + printf("## Output power has been successfully set ##"); + printf("\n"); +#endif + } + else + { + state = 1; + } + + writeRegister(REG_OP_MODE, st0); // Getting back to previous status + wait_ms(100); + return state; +} + + +/* + Function: Gets the preamble length from the module. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::getPreambleLength() +{ + int8_t state = 2; + uint8_t p_length; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getPreambleLength'\n"); +#endif + + state = 1; + if( _modem == LORA ) + { // LORA mode + p_length = readRegister(REG_PREAMBLE_MSB_LORA); + // Saving MSB preamble length in LoRa mode + _preamblelength = (p_length << 8) & 0xFFFF; + p_length = readRegister(REG_PREAMBLE_LSB_LORA); + // Saving LSB preamble length in LoRa mode + _preamblelength = _preamblelength + (p_length & 0xFFFF); +#if (SX1272_debug_mode > 1) + printf("## Preamble length configured is %X ",_preamblelength); + // Serial.print(_preamblelength, HEX); + printf(" ##"); + printf("\n"); +#endif + } + else + { // FSK mode + p_length = readRegister(REG_PREAMBLE_MSB_FSK); + // Saving MSB preamble length in FSK mode + _preamblelength = (p_length << 8) & 0xFFFF; + p_length = readRegister(REG_PREAMBLE_LSB_FSK); + // Saving LSB preamble length in FSK mode + _preamblelength = _preamblelength + (p_length & 0xFFFF); +#if (SX1272_debug_mode > 1) + printf("## Preamble length configured is %X ",_preamblelength); + // Serial.print(_preamblelength, HEX); + printf(" ##"); + printf("\n"); +#endif + } + state = 0; + return state; +} + +/* + Function: Sets the preamble length in the module + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + Parameters: + l: length value to set as preamble length. +*/ +uint8_t SX1272::setPreambleLength(uint16_t l) +{ + byte st0; + uint8_t p_length; + int8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setPreambleLength'\n"); +#endif + + st0 = readRegister(REG_OP_MODE); // Save the previous status + state = 1; + if( _modem == LORA ) + { // LoRa mode + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); // Set Standby mode to write in registers + p_length = ((l >> 8) & 0x0FF); + // Storing MSB preamble length in LoRa mode + writeRegister(REG_PREAMBLE_MSB_LORA, p_length); + p_length = (l & 0x0FF); + // Storing LSB preamble length in LoRa mode + writeRegister(REG_PREAMBLE_LSB_LORA, p_length); + } + else + { // FSK mode + writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Set Standby mode to write in registers + p_length = ((l >> 8) & 0x0FF); + // Storing MSB preamble length in FSK mode + writeRegister(REG_PREAMBLE_MSB_FSK, p_length); + p_length = (l & 0x0FF); + // Storing LSB preamble length in FSK mode + writeRegister(REG_PREAMBLE_LSB_FSK, p_length); + } + + state = 0; +#if (SX1272_debug_mode > 1) + printf("## Preamble length %X ",l); + // Serial.print(l, HEX); + printf(" has been successfully set ##"); + printf("\n"); +#endif + + writeRegister(REG_OP_MODE, st0); // Getting back to previous status + wait_ms(100); + return state; +} + +/* + Function: Gets the payload length from the module. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::getPayloadLength() +{ + uint8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getPayloadLength'\n"); +#endif + + if( _modem == LORA ) + { // LORA mode + // Saving payload length in LoRa mode + _payloadlength = readRegister(REG_PAYLOAD_LENGTH_LORA); + state = 1; + } + else + { // FSK mode + // Saving payload length in FSK mode + _payloadlength = readRegister(REG_PAYLOAD_LENGTH_FSK); + state = 1; + } + +#if (SX1272_debug_mode > 1) + printf("## Payload length configured is %X ",_payloadlength); + // Serial.print(_payloadlength, HEX); + printf(" ##"); + printf("\n"); +#endif + + state = 0; + return state; +} + +/* + Function: Sets the packet length in the module. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden command for this protocol +*/ +int8_t SX1272::setPacketLength() +{ + uint16_t length; + + // added by C. Pham + // if gateway is in rawFormat mode for packet reception, it will also send in rawFormat + // unless we switch it back to normal format just for transmission, e.g. for downlink transmission + if (_rawFormat) + length = _payloadlength; + else + length = _payloadlength + OFFSET_PAYLOADLENGTH; + + return setPacketLength(length); +} + +/* + Function: Sets the packet length in the module. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden command for this protocol + Parameters: + l: length value to set as payload length. +*/ +int8_t SX1272::setPacketLength(uint8_t l) +{ + byte st0; + byte value = 0x00; + int8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setPacketLength'\n"); +#endif + + st0 = readRegister(REG_OP_MODE); // Save the previous status + packet_sent.length = l; + + if( _modem == LORA ) + { // LORA mode + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); // Set LoRa Standby mode to write in registers + writeRegister(REG_PAYLOAD_LENGTH_LORA, packet_sent.length); + // Storing payload length in LoRa mode + value = readRegister(REG_PAYLOAD_LENGTH_LORA); + } + else + { // FSK mode + writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Set FSK Standby mode to write in registers + writeRegister(REG_PAYLOAD_LENGTH_FSK, packet_sent.length); + // Storing payload length in FSK mode + value = readRegister(REG_PAYLOAD_LENGTH_FSK); + } + + if( packet_sent.length == value ) + { + state = 0; +#if (SX1272_debug_mode > 1) + printf("## Packet length %d ",packet_sent.length); + // Serial.print(packet_sent.length, DEC); + printf(" has been successfully set ##"); + printf("\n"); +#endif + } + else + { + state = 1; + } + + writeRegister(REG_OP_MODE, st0); // Getting back to previous status + // comment by C. Pham + // this delay is included in the send delay overhead + // TODO: do we really need this delay? + wait_ms(250); + return state; +} + +/* + Function: Gets the node address in the module. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::getNodeAddress() +{ + byte st0 = 0; + uint8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getNodeAddress'\n"); +#endif + + if( _modem == LORA ) + { // LoRa mode + st0 = readRegister(REG_OP_MODE); // Save the previous status + // Allowing access to FSK registers while in LoRa standby mode + writeRegister(REG_OP_MODE, LORA_STANDBY_FSK_REGS_MODE); + } + + // Saving node address + _nodeAddress = readRegister(REG_NODE_ADRS); + state = 1; + + if( _modem == LORA ) + { + writeRegister(REG_OP_MODE, st0); // Getting back to previous status + } + + state = 0; +#if (SX1272_debug_mode > 1) + printf("## Node address configured is %d ", _nodeAddress); + // Serial.print(_nodeAddress); + printf(" ##"); + printf("\n"); +#endif + return state; +} + +/* + Function: Sets the node address in the module. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden command for this protocol + Parameters: + addr: address value to set as node address. +*/ +int8_t SX1272::setNodeAddress(uint8_t addr) +{ + byte st0; + uint8_t value; // type byte a l origine. Modifie par C.Dupaty + int8_t state = 2; // type uint_8 a l origine + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setNodeAddress'\n"); +#endif + + if( addr > 255 ) + { + state = -1; +#if (SX1272_debug_mode > 1) + printf("** Node address must be less than 255 **"); + printf("\n"); +#endif + } + else + { + // Saving node address + _nodeAddress = addr; + st0 = readRegister(REG_OP_MODE); // Save the previous status + + if( _modem == LORA ) + { // Allowing access to FSK registers while in LoRa standby mode + writeRegister(REG_OP_MODE, LORA_STANDBY_FSK_REGS_MODE); + } + else + { //Set FSK Standby mode to write in registers + writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); + } + + // Storing node and broadcast address + writeRegister(REG_NODE_ADRS, addr); + writeRegister(REG_BROADCAST_ADRS, BROADCAST_0); + + value = readRegister(REG_NODE_ADRS); + writeRegister(REG_OP_MODE, st0); // Getting back to previous status + + if( value == _nodeAddress ) + { + state = 0; +#if (SX1272_debug_mode > 1) + printf("## Node address %d ",addr); + // Serial.print(addr); + printf(" has been successfully set ##"); + printf("\n"); +#endif + } + else + { + state = 1; +#if (SX1272_debug_mode > 1) + printf("** There has been an error while setting address ##"); + printf("\n"); +#endif + } + } + return state; +} + +/* + Function: Gets the SNR value in LoRa mode. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden command for this protocol +*/ +int8_t SX1272::getSNR() +{ // getSNR exists only in LoRa mode + int8_t state = 2; + byte value; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getSNR'\n"); +#endif + + if( _modem == LORA ) + { // LoRa mode + state = 1; + value = readRegister(REG_PKT_SNR_VALUE); + _rawSNR = value; + + if( value & 0x80 ) // The SNR sign bit is 1 + { + // Invert and divide by 4 + value = ( ( ~value + 1 ) & 0xFF ) >> 2; + _SNR = -value; + } + else + { + // Divide by 4 + _SNR = ( value & 0xFF ) >> 2; + } + state = 0; +#if (SX1272_debug_mode > 0) + printf("## SNR value is %d\n",_SNR); + // Serial.print(_SNR, DEC); + printf(" ##"); + printf("\n"); +#endif + } + else + { // forbidden command if FSK mode + state = -1; +#if (SX1272_debug_mode > 0) + printf("** SNR does not exist in FSK mode **"); + printf("\n"); +#endif + } + return state; +} + +/* + Function: Gets the current value of RSSI. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::getRSSI() +{ + uint8_t state = 2; + int rssi_mean = 0; + int total = 5; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getRSSI'\n"); +#endif + + if( _modem == LORA ) + { + /// LoRa mode + // get mean value of RSSI + for(int i = 0; i < total; i++) + { + // modified by C. Pham + // with SX1276 we have to add 18 to OFFSET_RSSI to obtain -157 + _RSSI = -(OFFSET_RSSI+(_board==SX1276Chip?18:0)) + readRegister(REG_RSSI_VALUE_LORA); + rssi_mean += _RSSI; + } + + rssi_mean = rssi_mean / total; + _RSSI = rssi_mean; + + state = 0; +#if (SX1272_debug_mode > 0) + printf("## RSSI value is %d",_RSSI); + // Serial.print(_RSSI, DEC); + printf(" ##"); + printf("\n"); +#endif + } + else + { + /// FSK mode + // get mean value of RSSI + for(int i = 0; i < total; i++) + { + _RSSI = (readRegister(REG_RSSI_VALUE_FSK) >> 1); + rssi_mean += _RSSI; + } + rssi_mean = rssi_mean / total; + _RSSI = rssi_mean; + + state = 0; + +#if (SX1272_debug_mode > 0) + printf("## RSSI value is %d ",_RSSI); + //Serial.print(_RSSI); + printf(" ##"); + printf("\n"); +#endif + } + return state; +} + +/* + Function: Gets the RSSI of the last packet received in LoRa mode. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden command for this protocol +*/ +int16_t SX1272::getRSSIpacket() +{ // RSSIpacket only exists in LoRa + int8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getRSSIpacket'\n"); +#endif + + state = 1; + if( _modem == LORA ) + { // LoRa mode + state = getSNR(); + if( state == 0 ) + { + // added by C. Pham + _RSSIpacket = readRegister(REG_PKT_RSSI_VALUE); + + if( _SNR < 0 ) + { + // commented by C. Pham + //_RSSIpacket = -NOISE_ABSOLUTE_ZERO + 10.0 * SignalBwLog[_bandwidth] + NOISE_FIGURE + ( double )_SNR; + + // added by C. Pham, using Semtech SX1272 rev3 March 2015 + // for SX1272 we use -139, for SX1276, we use -157 + // then for SX1276 when using low-frequency (i.e. 433MHz) then we use -164 + _RSSIpacket = -(OFFSET_RSSI+(_board==SX1276Chip?18:0)+(_channel<CH_04_868?7:0)) + (double)_RSSIpacket + (double)_rawSNR*0.25; + state = 0; + } + else + { + // commented by C. Pham + //_RSSIpacket = readRegister(REG_PKT_RSSI_VALUE); + _RSSIpacket = -(OFFSET_RSSI+(_board==SX1276Chip?18:0)+(_channel<CH_04_868?7:0)) + (double)_RSSIpacket; + //end + state = 0; + } +#if (SX1272_debug_mode > 0) + printf("## RSSI packet value is %d",_RSSIpacket); + // Serial.print(_RSSIpacket, DEC); + printf(" ##"); + printf("\n"); +#endif + } + } + else + { // RSSI packet doesn't exist in FSK mode + state = -1; +#if (SX1272_debug_mode > 0) + printf("** RSSI packet does not exist in FSK mode **"); + printf("\n"); +#endif + } + return state; +} + +/* + Function: It sets the maximum number of retries. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> +*/ +uint8_t SX1272::setRetries(uint8_t ret) +{ + int8_t state = 2; // uint8_t a l origine + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setRetries'\n"); +#endif + + state = 1; + if( ret > MAX_RETRIES ) + { + state = -1; +#if (SX1272_debug_mode > 1) + printf("** Retries value can't be greater than %d ",MAX_RETRIES ); + // Serial.print(MAX_RETRIES, DEC); + printf(" **"); + printf("\n"); +#endif + } + else + { + _maxRetries = ret; + state = 0; +#if (SX1272_debug_mode > 1) + printf("## Maximum retries value = %d ",_maxRetries); + // Serial.print(_maxRetries, DEC); + printf(" ##"); + printf("\n"); +#endif + } + return state; +} + +/* + Function: Gets the current supply limit of the power amplifier, protecting battery chemistries. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + Parameters: + rate: value to compute the maximum current supply. Maximum current is 45+5*'rate' [mA] +*/ +uint8_t SX1272::getMaxCurrent() +{ + int8_t state = 2; + byte value; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getMaxCurrent'\n"); +#endif + + state = 1; + _maxCurrent = readRegister(REG_OCP); + + // extract only the OcpTrim value from the OCP register + _maxCurrent &= 0B00011111; + + if( _maxCurrent <= 15 ) + { + value = (45 + (5 * _maxCurrent)); + } + else if( _maxCurrent <= 27 ) + { + value = (-30 + (10 * _maxCurrent)); + } + else + { + value = 240; + } + + _maxCurrent = value; +#if (SX1272_debug_mode > 1) + printf("## Maximum current supply configured is %d ",value); + // Serial.print(value, DEC); + printf(" mA ##"); + printf("\n"); +#endif + state = 0; + return state; +} + +/* + Function: Limits the current supply of the power amplifier, protecting battery chemistries. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden parameter value for this function + Parameters: + rate: value to compute the maximum current supply. Maximum current is 45+5*'rate' [mA] +*/ +int8_t SX1272::setMaxCurrent(uint8_t rate) +{ + int8_t state = 2; + byte st0; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setMaxCurrent'\n"); +#endif + + // Maximum rate value = 0x1B, because maximum current supply = 240 mA + if (rate > 0x1B) + { + state = -1; +#if (SX1272_debug_mode > 1) + printf("** Maximum current supply is 240 mA, "); + printf("so maximum parameter value must be 27 (DEC) or 0x1B (HEX) **"); + printf("\n"); +#endif + } + else + { + // Enable Over Current Protection + rate |= 0B00100000; + + state = 1; + st0 = readRegister(REG_OP_MODE); // Save the previous status + if( _modem == LORA ) + { // LoRa mode + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); // Set LoRa Standby mode to write in registers + } + else + { // FSK mode + writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Set FSK Standby mode to write in registers + } + writeRegister(REG_OCP, rate); // Modifying maximum current supply + writeRegister(REG_OP_MODE, st0); // Getting back to previous status + state = 0; + } + return state; +} + +/* + Function: Gets the content of different registers. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::getRegs() +{ + int8_t state = 2; + uint8_t state_f = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getRegs'\n"); +#endif + + state_f = 1; + state = getMode(); // Stores the BW, CR and SF. + if( state == 0 ) + { + state = getPower(); // Stores the power. + } + else + { + state_f = 1; +#if (SX1272_debug_mode > 1) + printf("** Error getting mode **"); +#endif + } + if( state == 0 ) + { + state = getChannel(); // Stores the channel. + } + else + { + state_f = 1; +#if (SX1272_debug_mode > 1) + printf("** Error getting power **"); +#endif + } + if( state == 0 ) + { + state = getCRC(); // Stores the CRC configuration. + } + else + { + state_f = 1; +#if (SX1272_debug_mode > 1) + printf("** Error getting channel **"); +#endif + } + if( state == 0 ) + { + state = getHeader(); // Stores the header configuration. + } + else + { + state_f = 1; +#if (SX1272_debug_mode > 1) + printf("** Error getting CRC **"); +#endif + } + if( state == 0 ) + { + state = getPreambleLength(); // Stores the preamble length. + } + else + { + state_f = 1; +#if (SX1272_debug_mode > 1) + printf("** Error getting header **"); +#endif + } + if( state == 0 ) + { + state = getPayloadLength(); // Stores the payload length. + } + else + { + state_f = 1; +#if (SX1272_debug_mode > 1) + printf("** Error getting preamble length **"); +#endif + } + if( state == 0 ) + { + state = getNodeAddress(); // Stores the node address. + } + else + { + state_f = 1; +#if (SX1272_debug_mode > 1) + printf("** Error getting payload length **"); +#endif + } + if( state == 0 ) + { + state = getMaxCurrent(); // Stores the maximum current supply. + } + else + { + state_f = 1; +#if (SX1272_debug_mode > 1) + printf("** Error getting node address **"); +#endif + } + if( state == 0 ) + { + state_f = getTemp(); // Stores the module temperature. + } + else + { + state_f = 1; +#if (SX1272_debug_mode > 1) + printf("** Error getting maximum current supply **"); +#endif + } + if( state_f != 0 ) + { +#if (SX1272_debug_mode > 1) + printf("** Error getting temperature **"); + printf("\n"); +#endif + } + return state_f; +} + +/* + Function: It truncs the payload length if it is greater than 0xFF. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::truncPayload(uint16_t length16) +{ + uint8_t state = 2; + + state = 1; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'truncPayload'\n"); +#endif + + if( length16 > MAX_PAYLOAD ) + { + _payloadlength = MAX_PAYLOAD; + } + else + { + _payloadlength = (length16 & 0xFF); + } + state = 0; + + return state; +} + +/* + Function: It sets an ACK in FIFO in order to send it. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::setACK() +{ + uint8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setACK'\n"); +#endif + + // added by C. Pham + // check for enough remaining ToA + // when operating under duty-cycle mode + if (_limitToA) { + if (getRemainingToA() - getToA(ACK_LENGTH) < 0) { + printf("## not enough ToA for ACK at %d",millis()); + // Serial.println(millis()); + return SX1272_ERROR_TOA; + } + } + + // delay(1000); + + clearFlags(); // Initializing flags + + if( _modem == LORA ) + { // LoRa mode + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); // Stdby LoRa mode to write in FIFO + } + else + { // FSK mode + writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Stdby FSK mode to write in FIFO + } + + // Setting ACK length in order to send it + state = setPacketLength(ACK_LENGTH); + if( state == 0 ) + { + // Setting ACK + ACK.dst = packet_received.src; // ACK destination is packet source + ACK.type = PKT_TYPE_ACK; + ACK.src = packet_received.dst; // ACK source is packet destination + ACK.packnum = packet_received.packnum; // packet number that has been correctly received + ACK.length = 2; + ACK.data[0] = _reception; // CRC of the received packet + // added by C. Pham + // store the SNR + ACK.data[1]= readRegister(REG_PKT_SNR_VALUE); + + // Setting address pointer in FIFO data buffer + writeRegister(REG_FIFO_ADDR_PTR, 0x80); + + state = 1; + + // Writing ACK to send in FIFO + writeRegister(REG_FIFO, ACK.dst); // Writing the destination in FIFO + writeRegister(REG_FIFO, ACK.type); + writeRegister(REG_FIFO, ACK.src); // Writing the source in FIFO + writeRegister(REG_FIFO, ACK.packnum); // Writing the packet number in FIFO + writeRegister(REG_FIFO, ACK.length); // Writing the packet length in FIFO + writeRegister(REG_FIFO, ACK.data[0]); // Writing the ACK in FIFO + writeRegister(REG_FIFO, ACK.data[1]); // Writing the ACK in FIFO + + //#if (SX1272_debug_mode > 0) + printf("## ACK set and written in FIFO ##\n"); + // Print the complete ACK if debug_mode + printf("## ACK to send:\n"); + printf("Destination: %d\n",ACK.dst); + // Serial.println(ACK.dst); // Printing destination + printf("Source: %d\n",ACK.src); + // Serial.println(ACK.src); // Printing source + printf("ACK number: %d\n",ACK.packnum); + // Serial.println(ACK.packnum); // Printing ACK number + printf("ACK length: %d\n",ACK.length); + // Serial.println(ACK.length); // Printing ACK length + printf("ACK payload: %d\n",ACK.data[0]); + // Serial.println(ACK.data[0]); // Printing ACK payload + printf("ACK SNR last rcv pkt: %d\n",_SNR); + // Serial.println(_SNR); + printf("##\n"); + printf("\n"); + //#endif + + state = 0; + _reception = CORRECT_PACKET; // Updating value to next packet + + // comment by C. Pham + // TODO: do we really need this delay? + wait_ms(500); + } + return state; +} + +/* + Function: Configures the module to receive information. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::receive() +{ + uint8_t state = 1; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'receive'\n"); +#endif + + // Initializing packet_received struct + memset( &packet_received, 0x00, sizeof(packet_received) ); + + // Setting Testmode + // commented by C. Pham + //writeRegister(0x31,0x43); + + // Set LowPnTxPllOff + // modified by C. Pham from 0x09 to 0x08 + writeRegister(REG_PA_RAMP, 0x08); + + //writeRegister(REG_LNA, 0x23); // Important in reception + // modified by C. Pham + writeRegister(REG_LNA, LNA_MAX_GAIN); + writeRegister(REG_FIFO_ADDR_PTR, 0x00); // Setting address pointer in FIFO data buffer + // change RegSymbTimeoutLsb + // comment by C. Pham + // single_chan_pkt_fwd uses 00 00001000 + // why here we have 11 11111111 + // change RegSymbTimeoutLsb + //writeRegister(REG_SYMB_TIMEOUT_LSB, 0xFF); + + // modified by C. Pham + if (_spreadingFactor == SF_10 || _spreadingFactor == SF_11 || _spreadingFactor == SF_12) { + writeRegister(REG_SYMB_TIMEOUT_LSB,0x05); + } else { + writeRegister(REG_SYMB_TIMEOUT_LSB,0x08); + } + //end + + writeRegister(REG_FIFO_RX_BYTE_ADDR, 0x00); // Setting current value of reception buffer pointer + //clearFlags(); // Initializing flags + //state = 1; + if( _modem == LORA ) + { // LoRa mode + state = setPacketLength(MAX_LENGTH); // With MAX_LENGTH gets all packets with length < MAX_LENGTH + writeRegister(REG_OP_MODE, LORA_RX_MODE); // LORA mode - Rx +#if (SX1272_debug_mode > 1) + printf("## Receiving LoRa mode activated with success ##"); + printf("\n"); +#endif + } + else + { // FSK mode + state = setPacketLength(); + writeRegister(REG_OP_MODE, FSK_RX_MODE); // FSK mode - Rx +#if (SX1272_debug_mode > 1) + printf("## Receiving FSK mode activated with success ##"); + printf("\n"); +#endif + } + return state; +} + +/* + Function: Configures the module to receive information. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::receivePacketMAXTimeout() +{ + return receivePacketTimeout(MAX_TIMEOUT); +} + +/* + Function: Configures the module to receive information. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::receivePacketTimeout() +{ + setTimeout(); + return receivePacketTimeout(_sendTime); +} + +/* + Function: Configures the module to receive information. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +#ifdef W_REQUESTED_ACK + +// added by C. Pham +// receiver always use receivePacketTimeout() +// sender should either use sendPacketTimeout() or sendPacketTimeoutACK() + +uint8_t SX1272::receivePacketTimeout(uint16_t wait) +{ + uint8_t state = 2; + uint8_t state_f = 2; + + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'receivePacketTimeout'\n"); +#endif + + state = receive(); + if( state == 0 ) + { + if( availableData(wait) ) + { + state = getPacket(); + } + else + { + state = 1; + state_f = 3; // There is no packet received + } + } + else + { + state = 1; + state_f = 1; // There has been an error with the 'receive' function + } + + if( (state == 0) || (state == 3) || (state == 5) ) + { + if( _reception == INCORRECT_PACKET ) + { + state_f = 4; // The packet has been incorrectly received + } + else + { + state_f = 0; // The packet has been correctly received + // added by C. Pham + // we get the SNR and RSSI of the received packet for future usage + getSNR(); + getRSSIpacket(); + } + + // need to send an ACK + if ( state == 5 && state_f == 0) { + + state = setACK(); + + if( state == 0 ) + { + state = sendWithTimeout(); + if( state == 0 ) + { + state_f = 0; +#if (SX1272_debug_mode > 1) + printf("This last packet was an ACK, so ..."); + printf("ACK successfully sent"); + printf("\n"); +#endif + } + else + { + state_f = 1; // There has been an error with the 'sendWithTimeout' function + } + } + else + { + state_f = 1; // There has been an error with the 'setACK' function + } + } + } + else + { + // we need to conserve state_f=3 to indicate that no packet has been received after timeout + //state_f = 1; + } + return state_f; +} +#else + +uint8_t SX1272::receivePacketTimeout(uint16_t wait) +{ + uint8_t state = 2; + uint8_t state_f = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'receivePacketTimeout'\n"); +#endif + + state = receive(); + if( state == 0 ) + { + if( availableData(wait) ) + { + // If packet received, getPacket + state_f = getPacket(); + } + else + { + state_f = 1; + } + } + else + { + state_f = state; + } + return state_f; +} +#endif + +/* + Function: Configures the module to receive information and send an ACK. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::receivePacketMAXTimeoutACK() +{ + return receivePacketTimeoutACK(MAX_TIMEOUT); +} + +/* + Function: Configures the module to receive information and send an ACK. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::receivePacketTimeoutACK() +{ + setTimeout(); + return receivePacketTimeoutACK(_sendTime); +} + +/* + Function: Configures the module to receive information and send an ACK. + Returns: Integer that determines if there has been any error + state = 4 --> The command has been executed but the packet received is incorrect + state = 3 --> The command has been executed but there is no packet received + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::receivePacketTimeoutACK(uint16_t wait) +{ + // commented by C. Pham because not used + /* + uint8_t state = 2; + uint8_t state_f = 2; + + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'receivePacketTimeoutACK'"); +#endif + + state = receive(); + if( state == 0 ) + { + if( availableData(wait) ) + { + state = getPacket(); + } + else + { + state = 1; + state_f = 3; // There is no packet received + } + } + else + { + state = 1; + state_f = 1; // There has been an error with the 'receive' function + } + if( (state == 0) || (state == 3) ) + { + if( _reception == INCORRECT_PACKET ) + { + state_f = 4; // The packet has been incorrectly received + } + else + { + state_f = 1; // The packet has been correctly received + } + state = setACK(); + if( state == 0 ) + { + state = sendWithTimeout(); + if( state == 0 ) + { + state_f = 0; +#if (SX1272_debug_mode > 1) + printf("This last packet was an ACK, so ..."); + printf("ACK successfully sent"); + printf("\n"); +#endif + } + else + { + state_f = 1; // There has been an error with the 'sendWithTimeout' function + } + } + else + { + state_f = 1; // There has been an error with the 'setACK' function + } + } + else + { + state_f = 1; + } + return state_f; + */ + // ajoute par C.Dupaty + return 0; +} + +/* + Function: Configures the module to receive all the information on air, before MAX_TIMEOUT expires. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::receiveAll() +{ + return receiveAll(MAX_TIMEOUT); +} + +/* + Function: Configures the module to receive all the information on air. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::receiveAll(uint16_t wait) +{ + uint8_t state = 2; + byte config1; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'receiveAll'\n"); +#endif + + if( _modem == FSK ) + { // FSK mode + writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Setting standby FSK mode + config1 = readRegister(REG_PACKET_CONFIG1); + config1 = config1 & 0B11111001; // clears bits 2-1 from REG_PACKET_CONFIG1 + writeRegister(REG_PACKET_CONFIG1, config1); // AddressFiltering = None + } +#if (SX1272_debug_mode > 1) + printf("## Address filtering desactivated ##"); + printf("\n"); +#endif + state = receive(); // Setting Rx mode + if( state == 0 ) + { + state = getPacket(wait); // Getting all packets received in wait + } + return state; +} + +/* + Function: If a packet is received, checks its destination. + Returns: Boolean that's 'true' if the packet is for the module and + it's 'false' if the packet is not for the module. +*/ +boolean SX1272::availableData() +{ + return availableData(MAX_TIMEOUT); +} + +/* + Function: If a packet is received, checks its destination. + Returns: Boolean that's 'true' if the packet is for the module and + it's 'false' if the packet is not for the module. + Parameters: + wait: time to wait while there is no a valid header received. +*/ +boolean SX1272::availableData(uint16_t wait) +{ + byte value; + byte header = 0; + boolean forme = false; + boolean _hreceived = false; + //unsigned long previous; + unsigned long exitTime; + + +#if (SX1272_debug_mode > 0) + printf("\n"); + printf("Starting 'availableData'\n"); +#endif + + exitTime=millis()+(unsigned long)wait; + + //previous = millis(); + if( _modem == LORA ) + { // LoRa mode + value = readRegister(REG_IRQ_FLAGS); + // Wait to ValidHeader interrupt + //while( (bitRead(value, 4) == 0) && (millis() - previous < (unsigned long)wait) ) + while( (bitRead(value, 4) == 0) && (millis() < exitTime) ) + { + value = readRegister(REG_IRQ_FLAGS); + // Condition to avoid an overflow (DO NOT REMOVE) + //if( millis() < previous ) + //{ + // previous = millis(); + //} + } // end while (millis) + + if( bitRead(value, 4) == 1 ) + { // header received +#if (SX1272_debug_mode > 0) + printf("## Valid Header received in LoRa mode ##"); +#endif + _hreceived = true; + +#ifdef W_NET_KEY + // actually, need to wait until 3 bytes have been received + //while( (header < 3) && (millis() - previous < (unsigned long)wait) ) + while( (header < 3) && (millis() < exitTime) ) +#else + //while( (header == 0) && (millis() - previous < (unsigned long)wait) ) + while( (header == 0) && (millis() < exitTime) ) +#endif + { // Waiting to read first payload bytes from packet + header = readRegister(REG_FIFO_RX_BYTE_ADDR); + // Condition to avoid an overflow (DO NOT REMOVE) + //if( millis() < previous ) + //{ + // previous = millis(); + //} + } + + if( header != 0 ) + { // Reading first byte of the received packet +#ifdef W_NET_KEY + // added by C. Pham + // if we actually wait for an ACK, there is no net key before ACK data + if (_requestACK==0) { + _the_net_key_0 = readRegister(REG_FIFO); + _the_net_key_1 = readRegister(REG_FIFO); + } +#endif + _destination = readRegister(REG_FIFO); + } + } + else + { + forme = false; + _hreceived = false; +#if (SX1272_debug_mode > 0) + printf("** The timeout has expired **"); + printf("\n"); +#endif + } + } + else + { // FSK mode + value = readRegister(REG_IRQ_FLAGS2); + // Wait to Payload Ready interrupt + //while( (bitRead(value, 2) == 0) && (millis() - previous < wait) ) + while( (bitRead(value, 2) == 0) && (millis() < exitTime) ) + { + value = readRegister(REG_IRQ_FLAGS2); + // Condition to avoid an overflow (DO NOT REMOVE) + //if( millis() < previous ) + //{ + // previous = millis(); + //} + }// end while (millis) + + if( bitRead(value, 2) == 1 ) // something received + { + _hreceived = true; +#if (SX1272_debug_mode > 0) + printf("## Valid Preamble detected in FSK mode ##"); +#endif + // Reading first byte of the received packet + _destination = readRegister(REG_FIFO); + } + else + { + forme = false; + _hreceived = false; +#if (SX1272_debug_mode > 0) + printf("** The timeout has expired **"); + printf("\n"); +#endif + } + } + // We use _hreceived because we need to ensure that _destination value is correctly + // updated and is not the _destination value from the previously packet + if( _hreceived == true ) + { // Checking destination +#if (SX1272_debug_mode > 0) + printf("## Checking destination ##"); +#endif + + // added by C. Pham +#ifdef W_NET_KEY + forme=true; + + // if we wait for an ACK, then we do not check for net key + if (_requestACK==0) + if (_the_net_key_0!=_my_netkey[0] || _the_net_key_1!=_my_netkey[1]) { + //#if (SX1272_debug_mode > 0) + printf("## Wrong net key ##"); + //#endif + forme=false; + } + else + { + //#if (SX1272_debug_mode > 0) + printf("## Good net key ##"); + //#endif + } + + + if( forme && ((_destination == _nodeAddress) || (_destination == BROADCAST_0)) ) +#else + // modified by C. Pham + // if _rawFormat, accept all + if( (_destination == _nodeAddress) || (_destination == BROADCAST_0) || _rawFormat) +#endif + { // LoRa or FSK mode + forme = true; +#if (SX1272_debug_mode > 0) + printf("## Packet received is for me ##"); +#endif + } + else + { + forme = false; +#if (SX1272_debug_mode > 0) + printf("## Packet received is not for me ##"); + printf("\n"); +#endif + if( _modem == LORA ) // STANDBY PARA MINIMIZAR EL CONSUMO + { // LoRa mode + //writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); // Setting standby LoRa mode + } + else + { // FSK mode + writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Setting standby FSK mode + } + } + } + //----else + // { + // } + return forme; +} + +/* + Function: It gets and stores a packet if it is received before MAX_TIMEOUT expires. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::getPacketMAXTimeout() +{ + return getPacket(MAX_TIMEOUT); +} + +/* + Function: It gets and stores a packet if it is received. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +int8_t SX1272::getPacket() +{ + return getPacket(MAX_TIMEOUT); +} + +/* + Function: It gets and stores a packet if it is received before ending 'wait' time. + Returns: Integer that determines if there has been any error + // added by C. Pham + state = 5 --> The command has been executed with no errors and an ACK is requested + state = 3 --> The command has been executed but packet has been incorrectly received + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden parameter value for this function + Parameters: + wait: time to wait while there is no a valid header received. +*/ +int8_t SX1272::getPacket(uint16_t wait) +{ + int8_t state = 2; // uint8_t a l origine + byte value = 0x00; + //unsigned long previous; + unsigned long exitTime; + boolean p_received = false; + +#if (SX1272_debug_mode > 0) + printf("\n"); + printf("Starting 'getPacket'\n"); +#endif + + //previous = millis(); + exitTime = millis() + (unsigned long)wait; + if( _modem == LORA ) + { // LoRa mode + value = readRegister(REG_IRQ_FLAGS); + // Wait until the packet is received (RxDone flag) or the timeout expires + //while( (bitRead(value, 6) == 0) && (millis() - previous < (unsigned long)wait) ) + while( (bitRead(value, 6) == 0) && (millis() < exitTime) ) + { + value = readRegister(REG_IRQ_FLAGS); + // Condition to avoid an overflow (DO NOT REMOVE) + //if( millis() < previous ) + //{ + // previous = millis(); + //} + } // end while (millis) + + if( (bitRead(value, 6) == 1) && (bitRead(value, 5) == 0) ) + { // packet received & CRC correct + p_received = true; // packet correctly received + _reception = CORRECT_PACKET; +#if (SX1272_debug_mode > 0) + printf("## Packet correctly received in LoRa mode ##"); +#endif + } + else + { + if( bitRead(value, 5) != 0 ) + { // CRC incorrect + _reception = INCORRECT_PACKET; + state = 3; +#if (SX1272_debug_mode > 0) + printf("** The CRC is incorrect **"); + printf("\n"); +#endif + } + } + //writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); // Setting standby LoRa mode + } + else + { // FSK mode + value = readRegister(REG_IRQ_FLAGS2); + //while( (bitRead(value, 2) == 0) && (millis() - previous < wait) ) + while( (bitRead(value, 2) == 0) && (millis() < exitTime) ) + { + value = readRegister(REG_IRQ_FLAGS2); + // Condition to avoid an overflow (DO NOT REMOVE) + //if( millis() < previous ) + //{ + // previous = millis(); + //} + } // end while (millis) + + if( bitRead(value, 2) == 1 ) + { // packet received + if( bitRead(value, 1) == 1 ) + { // CRC correct + _reception = CORRECT_PACKET; + p_received = true; +#if (SX1272_debug_mode > 0) + printf("## Packet correctly received in FSK mode ##"); +#endif + } + else + { // CRC incorrect + _reception = INCORRECT_PACKET; + state = 3; + p_received = false; +#if (SX1272_debug_mode > 0) + printf("## Packet incorrectly received in FSK mode ##"); +#endif + } + } + else + { +#if (SX1272_debug_mode > 0) + printf("** The timeout has expired **"); + printf("\n"); +#endif + } + writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Setting standby FSK mode + } + if( p_received == true ) + { + // Store the packet + if( _modem == LORA ) + { + // comment by C. Pham + // set the FIFO addr to 0 to read again all the bytes + writeRegister(REG_FIFO_ADDR_PTR, 0x00); // Setting address pointer in FIFO data buffer + +#ifdef W_NET_KEY + // added by C. Pham + packet_received.netkey[0]=readRegister(REG_FIFO); + packet_received.netkey[1]=readRegister(REG_FIFO); +#endif + //modified by C. Pham + if (!_rawFormat) + packet_received.dst = readRegister(REG_FIFO); // Storing first byte of the received packet + else + packet_received.dst = 0; + } + else + { + value = readRegister(REG_PACKET_CONFIG1); + if( (bitRead(value, 2) == 0) && (bitRead(value, 1) == 0) ) + { + packet_received.dst = readRegister(REG_FIFO); // Storing first byte of the received packet + } + else + { + packet_received.dst = _destination; // Storing first byte of the received packet + } + } + + // modified by C. Pham + if (!_rawFormat) { + packet_received.type = readRegister(REG_FIFO); // Reading second byte of the received packet + packet_received.src = readRegister(REG_FIFO); // Reading second byte of the received packet + packet_received.packnum = readRegister(REG_FIFO); // Reading third byte of the received packet + //packet_received.length = readRegister(REG_FIFO); // Reading fourth byte of the received packet + } + else { + packet_received.type = 0; + packet_received.src = 0; + packet_received.packnum = 0; + } + + packet_received.length = readRegister(REG_RX_NB_BYTES); + + if( _modem == LORA ) + { + if (_rawFormat) { + _payloadlength=packet_received.length; + } + else + _payloadlength = packet_received.length - OFFSET_PAYLOADLENGTH; + } + if( packet_received.length > (MAX_LENGTH + 1) ) + { +#if (SX1272_debug_mode > 0) + printf("Corrupted packet, length must be less than 256"); +#endif + } + else + { + for(unsigned int i = 0; i < _payloadlength; i++) + { + packet_received.data[i] = readRegister(REG_FIFO); // Storing payload + } + + // commented by C. Pham + //packet_received.retry = readRegister(REG_FIFO); + + // Print the packet if debug_mode +#if (SX1272_debug_mode > 0) + printf("## Packet received:\n"); + printf("Destination: %d\n",packet_received.dst); + // Serial.println(packet_received.dst); // Printing destination + printf("Type: %d\n",packet_received.type); + // Serial.println(packet_received.type); // Printing source + printf("Source: %d\n",packet_received.src); + // Serial.println(packet_received.src); // Printing source + printf("Packet number: %d\n",packet_received.packnum); + // Serial.println(packet_received.packnum); // Printing packet number + //printf("Packet length: "); + //Serial.println(packet_received.length); // Printing packet length + printf("Data: "); + for(unsigned int i = 0; i < _payloadlength; i++) + { + //Serial.print((char)packet_received.data[i]); // Printing payload + printf("%c",packet_received.data[i]); + } + printf("\n"); + //printf("Retry number: "); + //Serial.println(packet_received.retry); // Printing number retry + printf("##"); + printf("\n"); +#endif + state = 0; + +#ifdef W_REQUESTED_ACK + // added by C. Pham + // need to send an ACK + if (packet_received.type & PKT_FLAG_ACK_REQ) { + state = 5; + _requestACK_indicator=1; + } + else + _requestACK_indicator=0; +#endif + } + } + else + { + state = 1; + if( (_reception == INCORRECT_PACKET) && (_retries < _maxRetries) ) + { + // comment by C. Pham + // what is the purpose of incrementing retries here? + // bug? not needed? + _retries++; +#if (SX1272_debug_mode > 0) + printf("## Retrying to send the last packet ##"); + printf("\n"); +#endif + } + } + if( _modem == LORA ) + { + writeRegister(REG_FIFO_ADDR_PTR, 0x00); // Setting address pointer in FIFO data buffer + } + clearFlags(); // Initializing flags + if( wait > MAX_WAIT ) + { + state = -1; +#if (SX1272_debug_mode > 0) + printf("** The timeout must be smaller than 12.5 seconds **"); + printf("\n"); +#endif + } + + return state; +} + +/* + Function: It sets the packet destination. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + Parameters: + dest: destination value of the packet sent. +*/ +int8_t SX1272::setDestination(uint8_t dest) +{ + int8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setDestination'\n"); +#endif + + state = 1; + _destination = dest; // Storing destination in a global variable + packet_sent.dst = dest; // Setting destination in packet structure + packet_sent.src = _nodeAddress; // Setting source in packet structure + packet_sent.packnum = _packetNumber; // Setting packet number in packet structure + _packetNumber++; + state = 0; + +#if (SX1272_debug_mode > 1) + printf("## Destination %X\n",_destination); +// Serial.print(_destination, HEX); + printf(" successfully set ##"); + printf("## Source %d\n",packet_sent.src); +// Serial.print(packet_sent.src, DEC); + printf(" successfully set ##"); + printf("## Packet number %d\n",packet_sent.packnum); + // Serial.print(packet_sent.packnum, DEC); + printf(" successfully set ##"); + printf("\n"); +#endif + return state; +} + +/* + Function: It sets the timeout according to the configured mode. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::setTimeout() +{ + uint8_t state = 2; +// retire par C.Dupaty + // uint16_t delay; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setTimeout'\n"); +#endif + + state = 1; + + // changed by C. Pham + // we always use MAX_TIMEOUT + _sendTime = MAX_TIMEOUT; + + /* + if( _modem == LORA ) + { + switch(_spreadingFactor) + { // Choosing Spreading Factor + case SF_6: switch(_bandwidth) + { // Choosing bandwidth + case BW_125: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 335; + break; + case CR_6: _sendTime = 352; + break; + case CR_7: _sendTime = 368; + break; + case CR_8: _sendTime = 386; + break; + } + break; + case BW_250: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 287; + break; + case CR_6: _sendTime = 296; + break; + case CR_7: _sendTime = 305; + break; + case CR_8: _sendTime = 312; + break; + } + break; + case BW_500: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 242; + break; + case CR_6: _sendTime = 267; + break; + case CR_7: _sendTime = 272; + break; + case CR_8: _sendTime = 276; + break; + } + break; + } + break; + + case SF_7: switch(_bandwidth) + { // Choosing bandwidth + case BW_125: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 408; + break; + case CR_6: _sendTime = 438; + break; + case CR_7: _sendTime = 468; + break; + case CR_8: _sendTime = 497; + break; + } + break; + case BW_250: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 325; + break; + case CR_6: _sendTime = 339; + break; + case CR_7: _sendTime = 355; + break; + case CR_8: _sendTime = 368; + break; + } + break; + case BW_500: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 282; + break; + case CR_6: _sendTime = 290; + break; + case CR_7: _sendTime = 296; + break; + case CR_8: _sendTime = 305; + break; + } + break; + } + break; + + case SF_8: switch(_bandwidth) + { // Choosing bandwidth + case BW_125: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 537; + break; + case CR_6: _sendTime = 588; + break; + case CR_7: _sendTime = 640; + break; + case CR_8: _sendTime = 691; + break; + } + break; + case BW_250: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 388; + break; + case CR_6: _sendTime = 415; + break; + case CR_7: _sendTime = 440; + break; + case CR_8: _sendTime = 466; + break; + } + break; + case BW_500: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 315; + break; + case CR_6: _sendTime = 326; + break; + case CR_7: _sendTime = 340; + break; + case CR_8: _sendTime = 352; + break; + } + break; + } + break; + + case SF_9: switch(_bandwidth) + { // Choosing bandwidth + case BW_125: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 774; + break; + case CR_6: _sendTime = 864; + break; + case CR_7: _sendTime = 954; + break; + case CR_8: _sendTime = 1044; + break; + } + break; + case BW_250: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 506; + break; + case CR_6: _sendTime = 552; + break; + case CR_7: _sendTime = 596; + break; + case CR_8: _sendTime = 642; + break; + } + break; + case BW_500: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 374; + break; + case CR_6: _sendTime = 396; + break; + case CR_7: _sendTime = 418; + break; + case CR_8: _sendTime = 441; + break; + } + break; + } + break; + + case SF_10: switch(_bandwidth) + { // Choosing bandwidth + case BW_125: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 1226; + break; + case CR_6: _sendTime = 1388; + break; + case CR_7: _sendTime = 1552; + break; + case CR_8: _sendTime = 1716; + break; + } + break; + case BW_250: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 732; + break; + case CR_6: _sendTime = 815; + break; + case CR_7: _sendTime = 896; + break; + case CR_8: _sendTime = 977; + break; + } + break; + case BW_500: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 486; + break; + case CR_6: _sendTime = 527; + break; + case CR_7: _sendTime = 567; + break; + case CR_8: _sendTime = 608; + break; + } + break; + } + break; + + case SF_11: switch(_bandwidth) + { // Choosing bandwidth + case BW_125: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 2375; + break; + case CR_6: _sendTime = 2735; + break; + case CR_7: _sendTime = 3095; + break; + case CR_8: _sendTime = 3456; + break; + } + break; + case BW_250: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 1144; + break; + case CR_6: _sendTime = 1291; + break; + case CR_7: _sendTime = 1437; + break; + case CR_8: _sendTime = 1586; + break; + } + break; + case BW_500: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 691; + break; + case CR_6: _sendTime = 766; + break; + case CR_7: _sendTime = 838; + break; + case CR_8: _sendTime = 912; + break; + } + break; + } + break; + + case SF_12: switch(_bandwidth) + { // Choosing bandwidth + case BW_125: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 4180; + break; + case CR_6: _sendTime = 4836; + break; + case CR_7: _sendTime = 5491; + break; + case CR_8: _sendTime = 6146; + break; + } + break; + case BW_250: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 1965; + break; + case CR_6: _sendTime = 2244; + break; + case CR_7: _sendTime = 2521; + break; + case CR_8: _sendTime = 2800; + break; + } + break; + case BW_500: + switch(_codingRate) + { // Choosing coding rate + case CR_5: _sendTime = 1102; + break; + case CR_6: _sendTime = 1241; + break; + case CR_7: _sendTime = 1381; + break; + case CR_8: _sendTime = 1520; + break; + } + break; + } + break; + default: _sendTime = MAX_TIMEOUT; + } + } + else + { + _sendTime = MAX_TIMEOUT; + } + delay = ((0.1*_sendTime) + 1); + _sendTime = (uint16_t) ((_sendTime * 1.2) + (rand()%delay)); + + */ +#if (SX1272_debug_mode > 1) + printf("Timeout to send/receive is: %d\n",_sendTime); + // Serial.println(_sendTime, DEC); +#endif + state = 0; + return state; +} + +/* + Function: It sets a char array payload packet in a packet struct. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::setPayload(char *payload) +{ + uint8_t state = 2; + uint8_t state_f = 2; + uint16_t length16; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setPayload'\n"); +#endif + + state = 1; + length16 = (uint16_t)strlen(payload); + state = truncPayload(length16); + if( state == 0 ) + { + // fill data field until the end of the string + for(unsigned int i = 0; i < _payloadlength; i++) + { + packet_sent.data[i] = payload[i]; + } + } + else + { + state_f = state; + } + if( ( _modem == FSK ) && ( _payloadlength > MAX_PAYLOAD_FSK ) ) + { + _payloadlength = MAX_PAYLOAD_FSK; + state = 1; +#if (SX1272_debug_mode > 1) + printf("In FSK, payload length must be less than 60 bytes."); + printf("\n"); +#endif + } + // set length with the actual counter value + state_f = setPacketLength(); // Setting packet length in packet structure + return state_f; +} + +/* + Function: It sets an uint8_t array payload packet in a packet struct. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::setPayload(uint8_t *payload) +{ + uint8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setPayload'\n"); +#endif + + state = 1; + if( ( _modem == FSK ) && ( _payloadlength > MAX_PAYLOAD_FSK ) ) + { + _payloadlength = MAX_PAYLOAD_FSK; + state = 1; +#if (SX1272_debug_mode > 1) + printf("In FSK, payload length must be less than 60 bytes."); + printf("\n"); +#endif + } + for(unsigned int i = 0; i < _payloadlength; i++) + { + packet_sent.data[i] = payload[i]; // Storing payload in packet structure + } + // set length with the actual counter value + state = setPacketLength(); // Setting packet length in packet structure + return state; +} + +/* + Function: It sets a packet struct in FIFO in order to send it. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::setPacket(uint8_t dest, char *payload) +{ + int8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setPacket'\n"); +#endif + + // added by C. Pham + // check for enough remaining ToA + // when operating under duty-cycle mode + if (_limitToA) { + uint16_t length16 = (uint16_t)strlen(payload); + + if (!_rawFormat) + length16 = length16 + OFFSET_PAYLOADLENGTH; + + if (getRemainingToA() - getToA(length16) < 0) { + printf("## not enough ToA at %d\n",millis()); + // Serial.println(millis()); + return SX1272_ERROR_TOA; + } + } + + clearFlags(); // Initializing flags + + if( _modem == LORA ) + { // LoRa mode + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); // Stdby LoRa mode to write in FIFO + } + else + { // FSK mode + writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Stdby FSK mode to write in FIFO + } + + _reception = CORRECT_PACKET; // Updating incorrect value + if( _retries == 0 ) + { // Updating this values only if is not going to re-send the last packet + state = setDestination(dest); // Setting destination in packet structure + packet_sent.retry = _retries; + if( state == 0 ) + { + state = setPayload(payload); + } + } + else + { + // comment by C. Pham + // why to increase the length here? + // bug? + if( _retries == 1 ) + { + packet_sent.length++; + } + state = setPacketLength(); + packet_sent.retry = _retries; +#if (SX1272_debug_mode > 0) + printf("** Retrying to send last packet %d\n",_retries); + // Serial.print(_retries, DEC); + printf(" time **"); +#endif + } + + // added by C. Pham + // set the type to be a data packet + packet_sent.type |= PKT_TYPE_DATA; + +#ifdef W_REQUESTED_ACK + // added by C. Pham + // indicate that an ACK should be sent by the receiver + if (_requestACK) + packet_sent.type |= PKT_FLAG_ACK_REQ; +#endif + + writeRegister(REG_FIFO_ADDR_PTR, 0x80); // Setting address pointer in FIFO data buffer + if( state == 0 ) + { + state = 1; + // Writing packet to send in FIFO +#ifdef W_NET_KEY + // added by C. Pham + packet_sent.netkey[0]=_my_netkey[0]; + packet_sent.netkey[1]=_my_netkey[1]; + //#if (SX1272_debug_mode > 0) + printf("## Setting net key ##"); + //#endif + writeRegister(REG_FIFO, packet_sent.netkey[0]); + writeRegister(REG_FIFO, packet_sent.netkey[1]); +#endif + // added by C. Pham + // we can skip the header for instance when we want to generate + // at a higher layer a LoRaWAN packet + if (!_rawFormat) { + writeRegister(REG_FIFO, packet_sent.dst); // Writing the destination in FIFO + // added by C. Pham + writeRegister(REG_FIFO, packet_sent.type); // Writing the packet type in FIFO + writeRegister(REG_FIFO, packet_sent.src); // Writing the source in FIFO + writeRegister(REG_FIFO, packet_sent.packnum); // Writing the packet number in FIFO + } + // commented by C. Pham + //writeRegister(REG_FIFO, packet_sent.length); // Writing the packet length in FIFO + for(unsigned int i = 0; i < _payloadlength; i++) + { + writeRegister(REG_FIFO, packet_sent.data[i]); // Writing the payload in FIFO + } + // commented by C. Pham + //writeRegister(REG_FIFO, packet_sent.retry); // Writing the number retry in FIFO + state = 0; +#if (SX1272_debug_mode > 0) + printf("## Packet set and written in FIFO ##"); + // Print the complete packet if debug_mode + printf("## Packet to send: \n"); + printf("Destination: %d\n",packet_sent.dst); + // Serial.println(packet_sent.dst); // Printing destination + printf("Packet type: %d\n",packet_sent.type); + // Serial.println(packet_sent.type); // Printing packet type + printf("Source: %d\n",packet_sent.src); + // Serial.println(packet_sent.src); // Printing source + printf("Packet number: %d\n",packet_sent.packnum); + // Serial.println(packet_sent.packnum); // Printing packet number + printf("Packet length: %d\n",packet_sent.length); + // Serial.println(packet_sent.length); // Printing packet length + printf("Data: "); + for(unsigned int i = 0; i < _payloadlength; i++) + { + // Serial.print((char)packet_sent.data[i]); // Printing payload + printf("%c",packet_sent.data[i]); + } + printf("\n"); + //printf("Retry number: "); + //Serial.println(packet_sent.retry); // Printing retry number + printf("##"); +#endif + } + + return state; +} + +/* + Function: It sets a packet struct in FIFO in order to sent it. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::setPacket(uint8_t dest, uint8_t *payload) +{ + int8_t state = 2; + byte st0; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setPacket'\n"); +#endif + + // added by C. Pham + // check for enough remaining ToA + // when operating under duty-cycle mode + if (_limitToA) { + // here truncPayload() should have been called before in + // sendPacketTimeout(uint8_t dest, uint8_t *payload, uint16_t length16) + uint16_t length16 = _payloadlength; + + if (!_rawFormat) + length16 = length16 + OFFSET_PAYLOADLENGTH; + + if (getRemainingToA() - getToA(length16) < 0) { + printf("## not enough ToA at %d\n",millis()); + // Serial.println(millis()); + return SX1272_ERROR_TOA; + } + } + + st0 = readRegister(REG_OP_MODE); // Save the previous status + clearFlags(); // Initializing flags + + if( _modem == LORA ) + { // LoRa mode + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); // Stdby LoRa mode to write in FIFO + } + else + { // FSK mode + writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Stdby FSK mode to write in FIFO + } + + _reception = CORRECT_PACKET; // Updating incorrect value to send a packet (old or new) + if( _retries == 0 ) + { // Sending new packet + state = setDestination(dest); // Setting destination in packet structure + packet_sent.retry = _retries; + if( state == 0 ) + { + state = setPayload(payload); + } + } + else + { + // comment by C. Pham + // why to increase the length here? + // bug? + if( _retries == 1 ) + { + packet_sent.length++; + } + state = setPacketLength(); + packet_sent.retry = _retries; +#if (SX1272_debug_mode > 0) + printf("** Retrying to send last packet %d\n",_retries); + // Serial.print(_retries, DEC); + printf(" time **"); +#endif + } + + // added by C. Pham + // set the type to be a data packet + packet_sent.type |= PKT_TYPE_DATA; + +#ifdef W_REQUESTED_ACK + // added by C. Pham + // indicate that an ACK should be sent by the receiver + if (_requestACK) + packet_sent.type |= PKT_FLAG_ACK_REQ; +#endif + + writeRegister(REG_FIFO_ADDR_PTR, 0x80); // Setting address pointer in FIFO data buffer + if( state == 0 ) + { + state = 1; + // Writing packet to send in FIFO +#ifdef W_NET_KEY + // added by C. Pham + packet_sent.netkey[0]=_my_netkey[0]; + packet_sent.netkey[1]=_my_netkey[1]; + //#if (SX1272_debug_mode > 0) + printf("## Setting net key ##"); + //#endif + writeRegister(REG_FIFO, packet_sent.netkey[0]); + writeRegister(REG_FIFO, packet_sent.netkey[1]); +#endif + // added by C. Pham + // we can skip the header for instance when we want to generate + // at a higher layer a LoRaWAN packet + if (!_rawFormat) { + writeRegister(REG_FIFO, packet_sent.dst); // Writing the destination in FIFO + // added by C. Pham + writeRegister(REG_FIFO, packet_sent.type); // Writing the packet type in FIFO + writeRegister(REG_FIFO, packet_sent.src); // Writing the source in FIFO + writeRegister(REG_FIFO, packet_sent.packnum); // Writing the packet number in FIFO + } + // commented by C. Pham + //writeRegister(REG_FIFO, packet_sent.length); // Writing the packet length in FIFO + for(unsigned int i = 0; i < _payloadlength; i++) + { + writeRegister(REG_FIFO, packet_sent.data[i]); // Writing the payload in FIFO + } + // commented by C. Pham + //writeRegister(REG_FIFO, packet_sent.retry); // Writing the number retry in FIFO + state = 0; +#if (SX1272_debug_mode > 0) + printf("## Packet set and written in FIFO ##"); + // Print the complete packet if debug_mode + printf("## Packet to send: "); + printf("Destination: %d\n",packet_sent.dst); + // Serial.println(packet_sent.dst); // Printing destination + printf("Packet type: %d\n",packet_sent.type); + // Serial.println(packet_sent.type); // Printing packet type + printf("Source: %d\n",packet_sent.src); + // Serial.println(packet_sent.src); // Printing source + printf("Packet number: %d\n",packet_sent.packnum); + // Serial.println(packet_sent.packnum); // Printing packet number + printf("Packet length: %d\n",packet_sent.length); + // Serial.println(packet_sent.length); // Printing packet length + printf("Data: "); + for(unsigned int i = 0; i < _payloadlength; i++) + { + //Serial.print((char)packet_sent.data[i]); // Printing payload + printf("%c",packet_sent.data[i]); + } + printf("\n"); + //printf("Retry number: "); + //Serial.println(packet_sent.retry); // Printing retry number + printf("##"); +#endif + } + writeRegister(REG_OP_MODE, st0); // Getting back to previous status + return state; +} + +/* + Function: Configures the module to transmit information. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendWithMAXTimeout() +{ + return sendWithTimeout(MAX_TIMEOUT); +} + +/* + Function: Configures the module to transmit information. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendWithTimeout() +{ + setTimeout(); + return sendWithTimeout(_sendTime); +} + +/* + Function: Configures the module to transmit information. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendWithTimeout(uint16_t wait) +{ + uint8_t state = 2; + byte value = 0x00; + //unsigned long previous; + unsigned long exitTime; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'sendWithTimeout'\n"); +#endif + + // clearFlags(); // Initializing flags + + // wait to TxDone flag + //previous = millis(); + exitTime = millis() + (unsigned long)wait; + if( _modem == LORA ) + { // LoRa mode + clearFlags(); // Initializing flags + + writeRegister(REG_OP_MODE, LORA_TX_MODE); // LORA mode - Tx + +#if (SX1272_debug_mode > 1) + value = readRegister(REG_OP_MODE); + + if (value & LORA_TX_MODE == LORA_TX_MODE) + printf("OK"); + else + printf("ERROR"); +#endif + value = readRegister(REG_IRQ_FLAGS); + // Wait until the packet is sent (TX Done flag) or the timeout expires + //while ((bitRead(value, 3) == 0) && (millis() - previous < wait)) + while ((bitRead(value, 3) == 0) && (millis() < exitTime)) + { + value = readRegister(REG_IRQ_FLAGS); + // Condition to avoid an overflow (DO NOT REMOVE) + //if( millis() < previous ) + //{ + // previous = millis(); + //} + } + state = 1; + } + else + { // FSK mode + writeRegister(REG_OP_MODE, FSK_TX_MODE); // FSK mode - Tx + + value = readRegister(REG_IRQ_FLAGS2); + // Wait until the packet is sent (Packet Sent flag) or the timeout expires + //while ((bitRead(value, 3) == 0) && (millis() - previous < wait)) + while ((bitRead(value, 3) == 0) && (millis() < exitTime)) + { + value = readRegister(REG_IRQ_FLAGS2); + // Condition to avoid an overflow (DO NOT REMOVE) + //if( millis() < previous ) + //{ + // previous = millis(); + //} + } + state = 1; + } + if( bitRead(value, 3) == 1 ) + { + state = 0; // Packet successfully sent +#if (SX1272_debug_mode > 1) + printf("## Packet successfully sent ##"); + printf("\n"); +#endif + // added by C. Pham + // normally there should be enough remaing ToA as the test has been done earlier + if (_limitToA) + removeToA(_currentToA); + } + else + { + if( state == 1 ) + { +#if (SX1272_debug_mode > 1) + printf("** Timeout has expired **"); + printf("\n"); +#endif + } + else + { +#if (SX1272_debug_mode > 1) + printf("** There has been an error and packet has not been sent **"); + printf("\n"); +#endif + } + } + + clearFlags(); // Initializing flags + return state; +} + +/* + Function: Configures the module to transmit information. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendPacketMAXTimeout(uint8_t dest, char *payload) +{ + return sendPacketTimeout(dest, payload, MAX_TIMEOUT); +} + +/* + Function: Configures the module to transmit information. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendPacketMAXTimeout(uint8_t dest, uint8_t *payload, uint16_t length16) +{ + return sendPacketTimeout(dest, payload, length16, MAX_TIMEOUT); +} + +/* + Function: Configures the module to transmit information. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendPacketTimeout(uint8_t dest, char *payload) +{ + uint8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'sendPacketTimeout'\n"); +#endif + + state = setPacket(dest, payload); // Setting a packet with 'dest' destination + if (state == 0) // and writing it in FIFO. + { + state = sendWithTimeout(); // Sending the packet + } + return state; +} + +/* + Function: Configures the module to transmit information. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendPacketTimeout(uint8_t dest, uint8_t *payload, uint16_t length16) +{ + uint8_t state = 2; + uint8_t state_f = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'sendPacketTimeout'\n"); +#endif + + state = truncPayload(length16); + if( state == 0 ) + { + state_f = setPacket(dest, payload); // Setting a packet with 'dest' destination + } // and writing it in FIFO. + else + { + state_f = state; + } + if( state_f == 0 ) + { + state_f = sendWithTimeout(); // Sending the packet + } + return state_f; +} + +/* + Function: Configures the module to transmit information. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendPacketTimeout(uint8_t dest, char *payload, uint16_t wait) +{ + uint8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'sendPacketTimeout'\n"); +#endif + + state = setPacket(dest, payload); // Setting a packet with 'dest' destination + if (state == 0) // and writing it in FIFO. + { + state = sendWithTimeout(wait); // Sending the packet + } + return state; +} + +/* + Function: Configures the module to transmit information. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendPacketTimeout(uint8_t dest, uint8_t *payload, uint16_t length16, uint16_t wait) +{ + uint8_t state = 2; + uint8_t state_f = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'sendPacketTimeout'\n"); +#endif + + state = truncPayload(length16); + if( state == 0 ) + { + state_f = setPacket(dest, payload); // Setting a packet with 'dest' destination + } + else + { + state_f = state; + } + if( state_f == 0 ) // and writing it in FIFO. + { + state_f = sendWithTimeout(wait); // Sending the packet + } + return state_f; +} + +/* + Function: Configures the module to transmit information. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendPacketMAXTimeoutACK(uint8_t dest, char *payload) +{ + return sendPacketTimeoutACK(dest, payload, MAX_TIMEOUT); +} + +/* + Function: Configures the module to transmit information and receive an ACK. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendPacketMAXTimeoutACK(uint8_t dest, uint8_t *payload, uint16_t length16) +{ + return sendPacketTimeoutACK(dest, payload, length16, MAX_TIMEOUT); +} + +/* + Function: Configures the module to transmit information and receive an ACK. + Returns: Integer that determines if there has been any error + state = 3 --> Packet has been sent but ACK has not been received + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendPacketTimeoutACK(uint8_t dest, char *payload) +{ + uint8_t state = 2; + uint8_t state_f = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'sendPacketTimeoutACK'\n"); +#endif + +#ifdef W_REQUESTED_ACK + _requestACK = 1; +#endif + state = sendPacketTimeout(dest, payload); // Sending packet to 'dest' destination + + if( state == 0 ) + { + state = receive(); // Setting Rx mode to wait an ACK + } + else + { + state_f = state; + } + if( state == 0 ) + { + // added by C. Pham + printf("wait for ACK"); + + if( availableData() ) + { + state_f = getACK(); // Getting ACK + } + else + { + state_f = SX1272_ERROR_ACK; + // added by C. Pham + printf("no ACK"); + } + } + else + { + state_f = state; + } + +#ifdef W_REQUESTED_ACK + _requestACK = 0; +#endif + return state_f; +} + +/* + Function: Configures the module to transmit information and receive an ACK. + Returns: Integer that determines if there has been any error + state = 3 --> Packet has been sent but ACK has not been received + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendPacketTimeoutACK(uint8_t dest, uint8_t *payload, uint16_t length16) +{ + uint8_t state = 2; + uint8_t state_f = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'sendPacketTimeoutACK'\n"); +#endif + +#ifdef W_REQUESTED_ACK + _requestACK = 1; +#endif + // Sending packet to 'dest' destination + state = sendPacketTimeout(dest, payload, length16); + + // Trying to receive the ACK + if( state == 0 ) + { + state = receive(); // Setting Rx mode to wait an ACK + } + else + { + state_f = state; + } + if( state == 0 ) + { + // added by C. Pham + printf("wait for ACK"); + + if( availableData() ) + { + state_f = getACK(); // Getting ACK + } + else + { + state_f = SX1272_ERROR_ACK; + // added by C. Pham + printf("no ACK"); + } + } + else + { + state_f = state; + } + +#ifdef W_REQUESTED_ACK + _requestACK = 0; +#endif + return state_f; +} + +/* + Function: Configures the module to transmit information and receive an ACK. + Returns: Integer that determines if there has been any error + state = 3 --> Packet has been sent but ACK has not been received + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendPacketTimeoutACK(uint8_t dest, char *payload, uint16_t wait) +{ + uint8_t state = 2; + uint8_t state_f = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'sendPacketTimeoutACK'\n"); +#endif + +#ifdef W_REQUESTED_ACK + _requestACK = 1; +#endif + state = sendPacketTimeout(dest, payload, wait); // Sending packet to 'dest' destination + + if( state == 0 ) + { + state = receive(); // Setting Rx mode to wait an ACK + } + else + { + state_f = 1; + } + if( state == 0 ) + { + // added by C. Pham + printf("wait for ACK"); + + if( availableData() ) + { + state_f = getACK(); // Getting ACK + } + else + { + state_f = SX1272_ERROR_ACK; + // added by C. Pham + printf("no ACK"); + } + } + else + { + state_f = 1; + } + +#ifdef W_REQUESTED_ACK + _requestACK = 0; +#endif + return state_f; +} + +/* + Function: Configures the module to transmit information and receive an ACK. + Returns: Integer that determines if there has been any error + state = 3 --> Packet has been sent but ACK has not been received + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendPacketTimeoutACK(uint8_t dest, uint8_t *payload, uint16_t length16, uint16_t wait) +{ + uint8_t state = 2; + uint8_t state_f = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'sendPacketTimeoutACK'\n"); +#endif + +#ifdef W_REQUESTED_ACK + _requestACK = 1; +#endif + state = sendPacketTimeout(dest, payload, length16, wait); // Sending packet to 'dest' destination + + if( state == 0 ) + { + state = receive(); // Setting Rx mode to wait an ACK + } + else + { + state_f = 1; + } + if( state == 0 ) + { + // added by C. Pham + printf("wait for ACK"); + + if( availableData() ) + { + state_f = getACK(); // Getting ACK + } + else + { + state_f = SX1272_ERROR_ACK; + // added by C. Pham + printf("no ACK"); + } + } + else + { + state_f = 1; + } + +#ifdef W_REQUESTED_ACK + _requestACK = 0; +#endif + return state_f; +} + +/* + Function: It gets and stores an ACK if it is received. + Returns: +*/ +uint8_t SX1272::getACK() +{ + return getACK(MAX_TIMEOUT); +} + +/* + Function: It gets and stores an ACK if it is received, before ending 'wait' time. + Returns: Integer that determines if there has been any error + state = 2 --> The ACK has not been received + state = 1 --> The N-ACK has been received with no errors + state = 0 --> The ACK has been received with no errors + Parameters: + wait: time to wait while there is no a valid header received. +*/ +uint8_t SX1272::getACK(uint16_t wait) +{ + uint8_t state = 2; + byte value = 0x00; + //unsigned long previous; + unsigned long exitTime; + boolean a_received = false; + + //#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getACK'\n"); + //#endif + + //previous = millis(); + exitTime = millis()+(unsigned long)wait; + if( _modem == LORA ) + { // LoRa mode + value = readRegister(REG_IRQ_FLAGS); + // Wait until the ACK is received (RxDone flag) or the timeout expires + //while ((bitRead(value, 6) == 0) && (millis() - previous < wait)) + while ((bitRead(value, 6) == 0) && (millis() < exitTime)) + { + value = readRegister(REG_IRQ_FLAGS); + //if( millis() < previous ) + //{ + // previous = millis(); + //} + } + if( bitRead(value, 6) == 1 ) + { // ACK received + // comment by C. Pham + // not really safe because the received packet may not be an ACK + // probability is low if using unicast to gateway, but if broadcast + // can get a packet from another node!! + a_received = true; + } + // Standby para minimizar el consumo + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); // Setting standby LoRa mode + } + else + { // FSK mode + value = readRegister(REG_IRQ_FLAGS2); + // Wait until the packet is received (RxDone flag) or the timeout expires + //while ((bitRead(value, 2) == 0) && (millis() - previous < wait)) + while ((bitRead(value, 2) == 0) && (millis() < exitTime)) + { + value = readRegister(REG_IRQ_FLAGS2); + //if( millis() < previous ) + //{ + // previous = millis(); + //} + } + if( bitRead(value, 2) == 1 ) + { // ACK received + a_received = true; + } + // Standby para minimizar el consumo + writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Setting standby FSK mode + } + + // comment by C. Pham + // not safe because the received packet may not be an ACK! + if( a_received ) + { + // Storing the received ACK + ACK.dst = _destination; + ACK.type = readRegister(REG_FIFO); + ACK.src = readRegister(REG_FIFO); + ACK.packnum = readRegister(REG_FIFO); + ACK.length = readRegister(REG_FIFO); + ACK.data[0] = readRegister(REG_FIFO); + ACK.data[1] = readRegister(REG_FIFO); + + if (ACK.type == PKT_TYPE_ACK) { + + // Checking the received ACK + if( ACK.dst == packet_sent.src ) + { + if( ACK.src == packet_sent.dst ) + { + if( ACK.packnum == packet_sent.packnum ) + { + if( ACK.length == 2 ) + { + if( ACK.data[0] == CORRECT_PACKET ) + { + state = 0; + //#if (SX1272_debug_mode > 0) + // Printing the received ACK + printf("## ACK received:"); + printf("Destination: %d\n",ACK.dst); + // Serial.println(ACK.dst); // Printing destination + printf("Source: %d\n",ACK.src); + // Serial.println(ACK.src); // Printing source + printf("ACK number: %d\n",ACK.packnum); + // Serial.println(ACK.packnum); // Printing ACK number + printf("ACK length: %d\n",ACK.length); + // Serial.println(ACK.length); // Printing ACK length + printf("ACK payload: %d\n",ACK.data[0]); + // Serial.println(ACK.data[0]); // Printing ACK payload + printf("ACK SNR of rcv pkt at gw: "); + + value = ACK.data[1]; + + if( value & 0x80 ) // The SNR sign bit is 1 + { + // Invert and divide by 4 + value = ( ( ~value + 1 ) & 0xFF ) >> 2; + _rcv_snr_in_ack = -value; + } + else + { + // Divide by 4 + _rcv_snr_in_ack = ( value & 0xFF ) >> 2; + } + + //Serial.println(_rcv_snr_in_ack); + printf("%d\n",_rcv_snr_in_ack); + printf("##"); + printf("\n"); + //#endif + } + else + { + state = 1; + //#if (SX1272_debug_mode > 0) + printf("** N-ACK received **"); + printf("\n"); + //#endif + } + } + else + { + state = 1; + //#if (SX1272_debug_mode > 0) + printf("** ACK length incorrectly received **"); + printf("\n"); + //#endif + } + } + else + { + state = 1; + //#if (SX1272_debug_mode > 0) + printf("** ACK number incorrectly received **"); + printf("\n"); + //#endif + } + } + else + { + state = 1; + //#if (SX1272_debug_mode > 0) + printf("** ACK source incorrectly received **"); + printf("\n"); + //#endif + } + } + } + else + { + state = 1; + //#if (SX1272_debug_mode > 0) + printf("** ACK destination incorrectly received **"); + printf("\n"); + //#endif + } + } + else + { + state = 1; + //#if (SX1272_debug_mode > 0) + printf("** ACK lost **"); + printf("\n"); + //#endif + } + clearFlags(); // Initializing flags + return state; +} + +/* + Function: Configures the module to transmit information with retries in case of error. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendPacketMAXTimeoutACKRetries(uint8_t dest, char *payload) +{ + return sendPacketTimeoutACKRetries(dest, payload, MAX_TIMEOUT); +} + +/* + Function: Configures the module to transmit information with retries in case of error. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendPacketMAXTimeoutACKRetries(uint8_t dest, uint8_t *payload, uint16_t length16) +{ + return sendPacketTimeoutACKRetries(dest, payload, length16, MAX_TIMEOUT); +} + +/* + Function: Configures the module to transmit information with retries in case of error. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendPacketTimeoutACKRetries(uint8_t dest, char *payload) +{ + uint8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'sendPacketTimeoutACKRetries'\n"); +#endif + + // Sending packet to 'dest' destination and waiting an ACK response. + state = 1; + while( (state != 0) && (_retries <= _maxRetries) ) + { + state = sendPacketTimeoutACK(dest, payload); + _retries++; + } + _retries = 0; + + return state; +} + +/* + Function: Configures the module to transmit information with retries in case of error. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendPacketTimeoutACKRetries(uint8_t dest, uint8_t *payload, uint16_t length16) +{ + uint8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'sendPacketTimeoutACKRetries'\n"); +#endif + + // Sending packet to 'dest' destination and waiting an ACK response. + state = 1; + while((state != 0) && (_retries <= _maxRetries)) + { + state = sendPacketTimeoutACK(dest, payload, length16); + _retries++; + + } + _retries = 0; + + return state; +} + +/* + Function: Configures the module to transmit information with retries in case of error. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendPacketTimeoutACKRetries(uint8_t dest, char *payload, uint16_t wait) +{ + uint8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'sendPacketTimeoutACKRetries'\n"); +#endif + + // Sending packet to 'dest' destination and waiting an ACK response. + state = 1; + while((state != 0) && (_retries <= _maxRetries)) + { + state = sendPacketTimeoutACK(dest, payload, wait); + _retries++; + } + _retries = 0; + + return state; +} + +/* + Function: Configures the module to transmit information with retries in case of error. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::sendPacketTimeoutACKRetries(uint8_t dest, uint8_t *payload, uint16_t length16, uint16_t wait) +{ + uint8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'sendPacketTimeoutACKRetries'\n"); +#endif + + // Sending packet to 'dest' destination and waiting an ACK response. + state = 1; + while((state != 0) && (_retries <= _maxRetries)) + { + state = sendPacketTimeoutACK(dest, payload, length16, wait); + _retries++; + } + _retries = 0; + + return state; +} + +/* + Function: It gets the temperature from the measurement block module. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::getTemp() +{ + byte st0; + uint8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getTemp'\n"); +#endif + + st0 = readRegister(REG_OP_MODE); // Save the previous status + + if( _modem == LORA ) + { // Allowing access to FSK registers while in LoRa standby mode + writeRegister(REG_OP_MODE, LORA_STANDBY_FSK_REGS_MODE); + } + + state = 1; + // Saving temperature value + _temp = readRegister(REG_TEMP); + if( _temp & 0x80 ) // The SNR sign bit is 1 + { + // Invert and divide by 4 + _temp = ( ( ~_temp + 1 ) & 0xFF ); + } + else + { + // Divide by 4 + _temp = ( _temp & 0xFF ); + } + + +#if (SX1272_debug_mode > 1) + printf("## Temperature is: %d ",_temp); + // Serial.print(_temp); + printf(" ##"); + printf("\n"); +#endif + + if( _modem == LORA ) + { + writeRegister(REG_OP_MODE, st0); // Getting back to previous status + } + + state = 0; + return state; +} + +//**********************************************************************/ +// Added by C. Pham +//**********************************************************************/ + +void SX1272::setPacketType(uint8_t type) +{ + packet_sent.type=type; + + if (type & PKT_FLAG_ACK_REQ) + _requestACK=1; +} + +/* + Function: Configures the module to perform CAD. + Returns: Integer that determines if the number of requested CAD have been successfull + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors +*/ +uint8_t SX1272::doCAD(uint8_t counter) +{ + uint8_t state = 2; + byte value = 0x00; + unsigned long startCAD, endCAD, startDoCad, endDoCad; + //unsigned long previous; + unsigned long exitTime; + uint16_t wait = 100; + bool failedCAD=false; + uint8_t retryCAD = 3; + uint8_t save_counter; + byte st0; + int rssi_count=0; + int rssi_mean=0; + double bw=0.0; + bool hasRSSI=false; + unsigned long startRSSI=0; + + bw=(_bandwidth==BW_125)?125e3:((_bandwidth==BW_250)?250e3:500e3); + // Symbol rate : time for one symbol (usecs) + double rs = bw / ( 1 << _spreadingFactor); + double ts = 1 / rs; + ts = ts * 1000000.0; + + st0 = readRegister(REG_OP_MODE); // Save the previous status + +#ifdef DEBUG_CAD + printf("SX1272::Starting 'doCAD'\n"); +#endif + + save_counter = counter; + + startDoCad=millis(); + + if( _modem == LORA ) { // LoRa mode + + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); + + do { + + hasRSSI=false; + + clearFlags(); // Initializing flags + + // wait to CadDone flag + // previous = millis(); + startCAD = millis(); + exitTime = millis()+(unsigned long)wait; + + writeRegister(REG_OP_MODE, LORA_CAD_MODE); // LORA mode - Cad + + startRSSI=micros(); + + value = readRegister(REG_IRQ_FLAGS); + // Wait until CAD ends (CAD Done flag) or the timeout expires + //while ((bitRead(value, 2) == 0) && (millis() - previous < wait)) + while ((bitRead(value, 2) == 0) && (millis() < exitTime)) + { + // only one reading per CAD + if (micros()-startRSSI > ts+240 && !hasRSSI) { + _RSSI = -(OFFSET_RSSI+(_board==SX1276Chip?18:0)) + readRegister(REG_RSSI_VALUE_LORA); + rssi_mean += _RSSI; + rssi_count++; + hasRSSI=true; + } + + value = readRegister(REG_IRQ_FLAGS); + // Condition to avoid an overflow (DO NOT REMOVE) + //if( millis() < previous ) + //{ + // previous = millis(); + //} + } + state = 1; + + endCAD = millis(); + + if( bitRead(value, 2) == 1 ) + { + state = 0; // CAD successfully performed +#ifdef DEBUG_CAD + printf("SX1272::CAD duration %X\n",endCAD-startCAD); + + // Serial.println(endCAD-startCAD); + printf("SX1272::CAD successfully performed"); +#endif + + value = readRegister(REG_IRQ_FLAGS); + + // look for the CAD detected bit + if( bitRead(value, 0) == 1 ) + { + // we detected activity + failedCAD=true; +#ifdef DEBUG_CAD + printf("SX1272::CAD exits after %d\n",save_counter-counter); + // Serial.println(save_counter-counter); +#endif + } + + counter--; + } + else + { +#ifdef DEBUG_CAD + printf("SX1272::CAD duration %d\n",endCAD-startCAD); + // Serial.println(endCAD-startCAD); +#endif + if( state == 1 ) + { +#ifdef DEBUG_CAD + printf("SX1272::Timeout has expired"); +#endif + } + else + { +#ifdef DEBUG_CAD + printf("SX1272::Error and CAD has not been performed"); +#endif + } + + retryCAD--; + + // to many errors, so exit by indicating that channel is not free + if (!retryCAD) + failedCAD=true; + } + + } while (counter && !failedCAD); + + rssi_mean = rssi_mean / rssi_count; + _RSSI = rssi_mean; + } + + writeRegister(REG_OP_MODE, st0); + + endDoCad=millis(); + + clearFlags(); // Initializing flags + +#ifdef DEBUG_CAD + printf("SX1272::doCAD duration %d\n",endDoCad-startDoCad); + // Serial.println(endDoCad-startDoCad); +#endif + + if (failedCAD) + return 2; + + return state; +} + +//#define DEBUG_GETTOA + +#ifdef DEBUG_GETTOA + +void printDouble( double val, byte precision){ + // prints val with number of decimal places determine by precision + // precision is a number from 0 to 6 indicating the desired decimial places + // example: lcdPrintDouble( 3.1415, 2); // prints 3.14 (two decimal places) + + if(val < 0.0){ + Serial.print('-'); + val = -val; + } + + Serial.print (int(val)); //prints the int part + if( precision > 0) { + Serial.print("."); // print the decimal point + unsigned long frac; + unsigned long mult = 1; + byte padding = precision -1; + while(precision--) + mult *=10; + + if(val >= 0) + frac = (val - int(val)) * mult; + else + frac = (int(val)- val ) * mult; + unsigned long frac1 = frac; + while( frac1 /= 10 ) + padding--; + while( padding--) + Serial.print("0"); + printfrac,DEC) ; + } +} + +#endif + +uint16_t SX1272::getToA(uint8_t pl) { + + uint8_t DE = 0; + uint32_t airTime = 0; + + double bw=0.0; + + bw=(_bandwidth==BW_125)?125e3:((_bandwidth==BW_250)?250e3:500e3); + +#ifdef DEBUG_GETTOA + printf("SX1272::bw is "); + Serial.println(bw); + + printf("SX1272::SF is "); + Serial.println(_spreadingFactor); +#endif + + //double ts=pow(2,_spreadingFactor)/bw; + + ////// from LoRaMAC SX1272GetTimeOnAir() + + // Symbol rate : time for one symbol (secs) + double rs = bw / ( 1 << _spreadingFactor); + double ts = 1 / rs; + + // must add 4 to the programmed preamble length to get the effective preamble length + double tPreamble=((_preamblelength+4)+4.25)*ts; + +#ifdef DEBUG_GETTOA + printf("SX1272::ts is "); + printDouble(ts,6); + printf("\n"); + printf("SX1272::tPreamble is "); + printDouble(tPreamble,6); + printf("\n"); +#endif + + // for low data rate optimization + if ((_bandwidth == BW_125) && _spreadingFactor == 12) + DE = 1; + + // Symbol length of payload and time + double tmp = (8*pl - 4*_spreadingFactor + 28 + 16 - 20*_header) / + (double)(4*(_spreadingFactor-2*DE) ); + +#ifdef DEBUG_GETTOA + printf("SX1272::tmp is "); + printDouble(tmp,6); + printf("\n"); +#endif + + tmp = ceil(tmp)*(_codingRate + 4); + + double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 ); + +#ifdef DEBUG_GETTOA + printf("SX1272::nPayload is "); + Serial.println(nPayload); +#endif + + double tPayload = nPayload * ts; + // Time on air + double tOnAir = tPreamble + tPayload; + // in us secs + airTime = floor( tOnAir * 1e6 + 0.999 ); + + ////// + +#ifdef DEBUG_GETTOA + printf("SX1272::airTime is "); + Serial.println(airTime); +#endif + // return in ms + // Modifie par C.Dupaty A VERIFIER !!!!!!!!!!!!!!!!!!!!!!!!! + // _currentToA=ceil(airTime/1000)+1; + _currentToA=(airTime/1000)+1; + return _currentToA; +} + +// need to set _send_cad_number to a value > 0 +// we advise using _send_cad_number=3 for a SIFS and _send_cad_number=9 for a DIFS +// prior to send any data +// TODO: have a maximum number of trials +void SX1272::CarrierSense() { + + int e; + bool carrierSenseRetry=false; + + if (_send_cad_number && _enableCarrierSense) { + do { + do { + + // check for free channel (SIFS/DIFS) + _startDoCad=millis(); + e = doCAD(_send_cad_number); + _endDoCad=millis(); + + printf("--> CAD duration %d\n",_endDoCad-_startDoCad); + // Serial.print(_endDoCad-_startDoCad); + printf("\n"); + + if (!e) { + printf("OK1\n"); + + if (_extendedIFS) { + // wait for random number of CAD + // uint8_t w = random(1,8); + // ajoute par C.Dupaty + uint8_t w = rand()%8+1; + printf("--> waiting for %d\n",w); + // Serial.print(w); + printf(" CAD = %d\n",sx1272_CAD_value[_loraMode]*w); + // Serial.print(sx1272_CAD_value[_loraMode]*w); + printf("\n"); + + wait_ms(sx1272_CAD_value[_loraMode]*w); + + // check for free channel (SIFS/DIFS) once again + _startDoCad=millis(); + e = doCAD(_send_cad_number); + _endDoCad=millis(); + + printf("--> CAD duration %d\n",_endDoCad-_startDoCad); + // Serial.print(_endDoCad-_startDoCad); + printf("\n"); + + if (!e) + printf("OK2"); + else + printf("###2"); + + printf("\n"); + } + } + else { + printf("###1\n"); + + // wait for random number of DIFS + uint8_t w = rand()%8+1; + + printf("--> waiting for %d\n",w); + // Serial.print(w); + printf(" DIFS (DIFS=3SIFS) = %d\n",sx1272_SIFS_value[_loraMode]*3*w); + // Serial.print(sx1272_SIFS_value[_loraMode]*3*w); + printf("\n"); + + wait_ms(sx1272_SIFS_value[_loraMode]*3*w); + + printf("--> retry\n"); + } + + } while (e); + + // CAD is OK, but need to check RSSI + if (_RSSIonSend) { + + e=getRSSI(); + + uint8_t rssi_retry_count=10; + + if (!e) { + + printf("--> RSSI %d\n",_RSSI); + //Serial.print(_RSSI); + printf("\n"); + + while (_RSSI > -90 && rssi_retry_count) { + + wait_ms(1); + getRSSI(); + printf("--> RSSI %d\n",_RSSI); + //Serial.print(_RSSI); + printf("\n"); + rssi_retry_count--; + } + } + else + printf("--> RSSI error\n"); + + if (!rssi_retry_count) + carrierSenseRetry=true; + else + carrierSenseRetry=false; + } + + } while (carrierSenseRetry); + } +} + +/* + Function: Indicates the CR within the module is configured. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden command for this protocol +*/ +int8_t SX1272::getSyncWord() +{ + int8_t state = 2; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'getSyncWord'\n"); +#endif + + if( _modem == FSK ) + { + state = -1; // sync word is not available in FSK mode +#if (SX1272_debug_mode > 1) + printf("** FSK mode hasn't sync word **"); + printf("\n"); +#endif + } + else + { + _syncWord = readRegister(REG_SYNC_WORD); + + state = 0; + +#if (SX1272_debug_mode > 1) + printf("## Sync word is %X ",_syncWord); + // Serial.print(_syncWord, HEX); + printf(" ##"); + printf("\n"); +#endif + } + return state; +} + +/* + Function: Sets the sync word in the module. + Returns: Integer that determines if there has been any error + state = 2 --> The command has not been executed + state = 1 --> There has been an error while executing the command + state = 0 --> The command has been executed with no errors + state = -1 --> Forbidden command for this protocol + Parameters: + cod: sw is sync word value to set in LoRa modem configuration. +*/ +int8_t SX1272::setSyncWord(uint8_t sw) +{ + byte st0; + int8_t state = 2; + byte config1; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setSyncWord'\n"); +#endif + + st0 = readRegister(REG_OP_MODE); // Save the previous status + + if( _modem == FSK ) + { +#if (SX1272_debug_mode > 1) + printf("## Notice that FSK hasn't sync word parameter, "); + printf("so you are configuring it in LoRa mode ##"); +#endif + state = setLORA(); + } + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); // Set Standby mode to write in registers + + writeRegister(REG_SYNC_WORD, sw); + + wait_ms(100); + + config1 = readRegister(REG_SYNC_WORD); + + if (config1==sw) { + state=0; + _syncWord = sw; +#if (SX1272_debug_mode > 1) + printf("## Sync Word %X ",sw); + // Serial.print(sw, HEX); + printf(" has been successfully set ##"); + printf("\n"); +#endif + } + else { + state=1; +#if (SX1272_debug_mode > 1) + printf("** There has been an error while configuring Sync Word parameter **"); + printf("\n"); +#endif + } + + writeRegister(REG_OP_MODE,st0); // Getting back to previous status + wait_ms(100); + return state; +} + + +int8_t SX1272::setSleepMode() { + + int8_t state = 2; + byte value; + + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); + // proposed by escyes + // https://github.com/CongducPham/LowCostLoRaGw/issues/53#issuecomment-289237532 + // + // inserted to avoid REG_OP_MODE stay = 0x40 (no sleep mode) + wait_ms(100); + writeRegister(REG_OP_MODE, LORA_SLEEP_MODE); // LoRa sleep mode + + //delay(50); + + value = readRegister(REG_OP_MODE); + + //printf("## REG_OP_MODE 0x"); + //Serial.println(value, HEX); + + if (value == LORA_SLEEP_MODE) + state=0; + else + state=1; + + return state; +} + +int8_t SX1272::setPowerDBM(uint8_t dbm) { + byte st0; + int8_t state = 2; + byte value = 0x00; + + byte RegPaDacReg=(_board==SX1272Chip)?0x5A:0x4D; + +#if (SX1272_debug_mode > 1) + printf("\n"); + printf("Starting 'setPowerDBM'\n"); +#endif + + st0 = readRegister(REG_OP_MODE); // Save the previous status + if( _modem == LORA ) + { // LoRa Stdby mode to write in registers + writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); + } + else + { // FSK Stdby mode to write in registers + writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); + } + + if (dbm == 20) { + return setPower('X'); + } + + if (dbm > 14) + return state; + + // disable high power output in all other cases + writeRegister(RegPaDacReg, 0x84); + + if (dbm > 10) + // set RegOcp for OcpOn and OcpTrim + // 130mA + setMaxCurrent(0x10); + else + // 100mA + setMaxCurrent(0x0B); + + if (_board==SX1272Chip) { + // Pout = -1 + _power[3:0] on RFO + // Pout = 2 + _power[3:0] on PA_BOOST + if (_needPABOOST) { + value = dbm - 2; + // we set the PA_BOOST pin + value = value & 0B10000000; + } + else + value = dbm + 1; + + writeRegister(REG_PA_CONFIG, value); // Setting output power value + } + else { + // for the SX1276 + uint8_t pmax=15; + + // then Pout = Pmax-(15-_power[3:0]) if PaSelect=0 (RFO pin for +14dBm) + // so L=3dBm; H=7dBm; M=15dBm (but should be limited to 14dBm by RFO pin) + + // and Pout = 17-(15-_power[3:0]) if PaSelect=1 (PA_BOOST pin for +14dBm) + // so x= 14dBm (PA); + // when p=='X' for 20dBm, value is 0x0F and RegPaDacReg=0x87 so 20dBm is enabled + + if (_needPABOOST) { + value = dbm - 17 + 15; + // we set the PA_BOOST pin + value = value & 0B10000000; + } + else + value = dbm - pmax + 15; + + // set MaxPower to 7 -> Pmax=10.8+0.6*MaxPower [dBm] = 15 + value = value & 0B01110000; + + writeRegister(REG_PA_CONFIG, value); + } + + _power=value; + + value = readRegister(REG_PA_CONFIG); + + if( value == _power ) + { + state = 0; +#if (SX1272_debug_mode > 1) + printf("## Output power has been successfully set ##"); + printf("\n"); +#endif + } + else + { + state = 1; + } + + writeRegister(REG_OP_MODE, st0); // Getting back to previous status + wait_ms(100); + return state; +} + +long SX1272::limitToA() { + + // first time we set limitToA? + // in this design, once you set _limitToA to true + // it is not possible to set it back to false + if (_limitToA==false) { + _startToAcycle=millis(); + _remainingToA=MAX_DUTY_CYCLE_PER_HOUR; + // we are handling millis() rollover by calculating the end of cycle time + _endToAcycle=_startToAcycle+DUTYCYCLE_DURATION; + } + + _limitToA=true; + return getRemainingToA(); +} + +long SX1272::getRemainingToA() { + + if (_limitToA==false) + return MAX_DUTY_CYCLE_PER_HOUR; + + // we compare to the end of cycle so that millis() rollover is taken into account + // using unsigned long modulo operation + if ( (millis() > _endToAcycle ) ) { + _startToAcycle=_endToAcycle; + _remainingToA=MAX_DUTY_CYCLE_PER_HOUR; + _endToAcycle=_startToAcycle+DUTYCYCLE_DURATION; + + printf("## new cycle for ToA ##"); + printf("cycle begins at %d\n",_startToAcycle); + // Serial.print(_startToAcycle); + printf(" cycle ends at %d\n",_endToAcycle); + // Serial.print(_endToAcycle); + printf(" remaining ToA is %d\n",_remainingToA); + // Serial.print(_remainingToA); + printf("\n"); + } + + return _remainingToA; +} + +long SX1272::removeToA(uint16_t toa) { + + // first, update _remainingToA + getRemainingToA(); + + if (_limitToA) { + _remainingToA-=toa; + } + + return _remainingToA; +} + +SX1272 sx1272 = SX1272();