p2p with rssi value
Dependents: Lora_SX1272_serial_apr29-rssi
SX1272.cpp
- Committer:
- afzalsamira
- Date:
- 2021-02-01
- Revision:
- 6:d7c7e731da3a
- Parent:
- 4:f77a79f4239a
- Child:
- 7:e99757b7c421
File content as of revision 6:d7c7e731da3a:
/* * 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 // config pour SX1272MB2xAS sur NUCLEO-L073RZ #define SX1272_debug_mode 0 //Coragem pins SPI spi(P0_4,P0_6,P0_8);; // PA_7, PA_6, PA_5 DigitalOut ss(P0_26); //(PB_6) DigitalOut rst(P1_15); //**********************************************************************/ // Public functions. //**********************************************************************/ SX1272::SX1272() { //ajoute par C.DUPATY us_ticker_init(); srand(time(NULL)); // ajoute parC.Dupaty 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_07_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=true;//____________________________________________________ _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_07_900); // 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::Read() //readRegister( 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 //__________________________lendo todos os registradores________________________ // for(char i=0;i<100;i++){ // int value =readRegister(i); //// printf("reg%d =%d ",i,value); // } readRegister(0);//evitar falsos positivos uint8_t version = readRegister(REG_VERSION); if (version == 0x22) { //sx1272 ? // sx1272 printf("\nSX1272 detected, starting\n"); _board = SX1272Chip; } else if (version ==0x12) {// sx1276? printf("SX1276 detected, starting\n"); _board = SX1276Chip; } else { // rst=0; // wait_ms(100); // rst=1; // wait_ms(100); while(1){ printf("Unrecognized transceiver\n"); wait_ms(2000); } } // 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,0x8F);// was 0, 8F gives max outputpower 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 // printf("reg1=%d \n",readRegister(1)); 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) { // printf("Samira - writeRegister ( ) - ENTER..\n"); //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 { 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 ) { printf("XXXXXXXXXXXXXXXXXXXXX MAX_PAYLOAD XXXXXXXXXXXXXXXX\n"); _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 // printf("dentro do setPacket payload = %s\n",payload); // 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 printf("setPacket1____________________\n"); if( _modem == LORA ) { // LoRa mode writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); // Stdby LoRa mode to write in FIFO printf("_modem == Lora\n"); } else { // FSK mode writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Stdby FSK mode to write in FIFO printf("_modem == FSK\n"); } _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 writeRegister(0x01,129);//standby mode 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 // for (int i=0 ; i<255 ; i++) // printf("%d ",readRegister(REG_FIFO)); // printf("/n"); state = 0; #if (SX1272_debug_mode > 0) printf("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; // sx1272.writeRegister(0x01,129); //standby mode #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 // printf("setPacket_2_____________________\n"); // printf("mode =%d\n",readRegister(REG_OP_MODE)&3); if( _modem == LORA ) { // LoRa mode writeRegister(REG_OP_MODE, LORA_STANDBY_MODE); // Stdby LoRa mode to write in FIFO // printf("setpacket_2 LORA\n"); } else { // FSK mode writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Stdby FSK mode to write in FIFO printf("setpacket_2 FSK\n"); } // printf("mode =%d\n",readRegister(REG_OP_MODE)&3); _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 } this->packet_sent.packnum++; // 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 } // printf("FIFO depois da escrita\n"); // for(int i=0; i!= 255 ;i++) // printf("%c",readRegister(REG_FIFO)); // printf("\n"); // 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 printf("sendPacketTimeout saio da fifo\n"); if (state == 0) // and writing it in FIFO. { printf("sendPacketTimeout vai enviar\n"); state = sendWithTimeout(); // Sending the packet printf("sendPacketTimeout enviou\n"); } 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; // printf("chegou no sendPacketTimeout\n"); #if (SX1272_debug_mode > 1) printf("\n"); printf("Starting 'sendPacketTimeout'\n"); #endif state = truncPayload(length16); if( state == 0 ) { // printf("vai pro setpacket\n"); 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();