diff --git a/core/MyTransportRFM95.cpp b/core/MyTransportRFM95.cpp index 8bdedf3..9981bd5 100644 --- a/core/MyTransportRFM95.cpp +++ b/core/MyTransportRFM95.cpp @@ -67,7 +67,26 @@ void transportPowerDown(void) (void)RFM95_sleep(); } -int16_t transportGetSignalStrength(void) +// experimental +// ********************************************** +int16_t transportGetReceivingSignalStrength(void) { - return RFM95_getRSSI(); + return RFM95_getReceivingRSSI(); } +int16_t transportGetSendingSignalStrength(void) +{ + return RFM95_getSendingRSSI(); +} +int8_t transportGetReceivingSNR(void) +{ + return RFM95_getReceivingSNR(); +} +int8_t transportGetSendingSNR(void) +{ + return RFM95_getSendingSNR(); +} +uint8_t transportGetTxPower(void) +{ + return RFM95_getTxPowerPercent(); +} +// ********************************************** diff --git a/drivers/RFM95/RFM95.cpp b/drivers/RFM95/RFM95.cpp index 7a0fc3d..a1cf7ba 100644 --- a/drivers/RFM95/RFM95.cpp +++ b/drivers/RFM95/RFM95.cpp @@ -25,11 +25,13 @@ #include "RFM95.h" #if defined(LINUX_ARCH_RASPBERRYPI) -uint8_t spi_rxbuff[32 + 1]; //SPI receive buffer (payload max 32 bytes, MYS protocol limitation) -uint8_t spi_txbuff[32 + - 1]; //SPI transmit buffer (payload max 32 bytes + 1 byte for the command, MYS protocol limitation) +// SPI RX and TX buffers (max packet len + 1 byte for the command) +uint8_t spi_rxbuff[RFM95_MAX_PACKET_LEN + 1]; +uint8_t spi_txbuff[RFM95_MAX_PACKET_LEN + 1]; #endif +volatile rfm95_internal_t RFM95; //!< internal variables + LOCAL void RFM95_csn(const bool level) { hwDigitalWrite(MY_RFM95_SPI_CS, level); @@ -110,10 +112,6 @@ LOCAL uint8_t RFM95_RAW_writeByteRegister(const uint8_t address, uint8_t value) #define RFM95_burstReadReg(__reg, __buf, __len) RFM95_spiMultiByteTransfer( __reg & RFM95_READ_REGISTER, (uint8_t*)__buf, __len, true ) #define RFM95_burstWriteReg(__reg, __buf, __len) RFM95_spiMultiByteTransfer( __reg | RFM95_WRITE_REGISTER, (uint8_t*)__buf, __len, false ) - -// check RegPktRssiValue (0x1A) vs. RegRssiValue (0x1B) - - LOCAL bool RFM95_initialise(const float frequency) { RFM95_DEBUG(PSTR("RFM95:INIT\n")); @@ -134,7 +132,7 @@ LOCAL bool RFM95_initialise(const float frequency) RFM95.txSequenceNumber = 0; // initialise TX sequence counter RFM95.powerLevel = 0; RFM95.ATCenabled = false; - RFM95.ATCtargetRSSI = RFM95_TARGET_RSSI + RFM95_RSSI_OFFSET; + RFM95.ATCtargetRSSI = RFM95_RSSItoInternal(RFM95_TARGET_RSSI); // SPI init hwDigitalWrite(MY_RFM95_SPI_CS, HIGH); @@ -143,8 +141,7 @@ LOCAL bool RFM95_initialise(const float frequency) // Set LoRa mode (during sleep mode) RFM95_writeReg(RFM95_REG_01_OP_MODE, RFM95_MODE_SLEEP | RFM95_LONG_RANGE_MODE); - delay(10); // Wait for sleep mode to take over from say, CAD - // Check we are in sleep mode, with LORA set + delay(10); // Wait for sleep mode to take over if (RFM95_readReg(RFM95_REG_01_OP_MODE) != (RFM95_MODE_SLEEP | RFM95_LONG_RANGE_MODE)) { return false; // No device present? } @@ -167,8 +164,14 @@ LOCAL bool RFM95_initialise(const float frequency) #if defined (SPI_HAS_TRANSACTION) && !defined (ESP8266) _SPI.usingInterrupt(digitalPinToInterrupt(MY_RFM95_IRQ_PIN)); #endif - attachInterrupt(digitalPinToInterrupt(MY_RFM95_IRQ_PIN), RFM95_interruptHandler, RISING); + if (!RFM95_sanityCheck()) { + RFM95_DEBUG( + PSTR("!RFM95:INIT:SANCHK FAIL\n")); // sanity check failed, check wiring or replace module + return false; + } + + attachInterrupt(digitalPinToInterrupt(MY_RFM95_IRQ_PIN), RFM95_interruptHandler, RISING); return true; } @@ -191,7 +194,8 @@ LOCAL void RFM95_interruptHandler(void) // Reset the fifo read ptr to the beginning of the packet RFM95_writeReg(RFM95_REG_0D_FIFO_ADDR_PTR, RFM95_readReg(RFM95_REG_10_FIFO_RX_CURRENT_ADDR)); RFM95_burstReadReg(RFM95_REG_00_FIFO, RFM95.currentPacket.data, bufLen); - RFM95.currentPacket.RSSI = RFM95_readReg(RFM95_REG_1A_PKT_RSSI_VALUE); + RFM95.currentPacket.RSSI = RFM95_readReg( + RFM95_REG_1A_PKT_RSSI_VALUE); // RSSI of latest packet received RFM95.currentPacket.SNR = static_cast(RFM95_readReg(RFM95_REG_19_PKT_SNR_VALUE)); RFM95.currentPacket.payloadLen = bufLen - RFM95_HEADER_LEN; // Message for us @@ -244,14 +248,13 @@ LOCAL uint8_t RFM95_recv(uint8_t* buf) const rfm95_RSSI_t RSSI = RFM95.currentPacket.RSSI; // of incoming packet const rfm95_SNR_t SNR = RFM95.currentPacket.SNR; if (buf != NULL) { - memcpy((void*)buf, (void*)RFM95.currentPacket.payload, payloadLen); + (void)memcpy((void*)buf, (void*)RFM95.currentPacket.payload, payloadLen); RFM95.rxBufferValid = false; } interrupts(); // ACK handling if (RFM95_getACKRequested(controlFlags)) { - RFM95_DEBUG(PSTR("RFM95:RCV:SEND ACK\n")); RFM95_sendACK(sender, sequenceNumber, RSSI, SNR); } @@ -262,9 +265,8 @@ LOCAL bool RFM95_send(rfm95_packet_t &packet) { const uint8_t finalLen = packet.payloadLen + RFM95_HEADER_LEN; // Make sure we dont interrupt an outgoing message - RFM95_waitPacketSent(); + (void)RFM95_waitPacketSent(); (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); - // Check channel activity if (!RFM95_waitCAD()) { return false; @@ -289,9 +291,9 @@ LOCAL bool RFM95_sendFrame(const uint8_t recipient, uint8_t* data, const uint8_t packet.header.sender = RFM95.address; packet.header.recipient = recipient; packet.header.controlFlags = 0x00; - packet.payloadLen = min(len, (const uint8_t)RFM95_MAX_PAYLOAD_LEN); + packet.payloadLen = min(len, (uint8_t)RFM95_MAX_PAYLOAD_LEN); packet.header.controlFlags = flags; - memcpy(&packet.payload, data, packet.payloadLen); + (void)memcpy(&packet.payload, data, packet.payloadLen); return RFM95_send(packet); } @@ -314,8 +316,7 @@ LOCAL bool RFM95_setTxPower(uint8_t powerLevel) if (powerLevel > 20) { // enable DAC, adds 3dBm // The documentation is pretty confusing on this topic: PaSelect says the max power is 20dBm, - // but OutputPower claims it would be 17dBm. - // My measurements show 20dBm is correct + // but OutputPower claims it would be 17dBm. Measurements show 20dBm is correct RFM95_writeReg(RFM95_REG_4D_PA_DAC, RFM95_PA_DAC_ENABLE); val = powerLevel - 8; } else { @@ -354,17 +355,6 @@ LOCAL uint8_t RFM95_getAddress(void) return RFM95.address; } - -LOCAL bool RFM95_isChannelActive(void) -{ - (void)RFM95_setRadioMode(RFM95_RADIO_MODE_CAD); - while (RFM95.radioMode == RFM95_RADIO_MODE_CAD) { - doYield(); - } - - return RFM95.cad; -} - LOCAL bool RFM95_setRadioMode(const rfm95_radioMode_t newRadioMode) { if (RFM95.radioMode == newRadioMode) { @@ -403,7 +393,7 @@ LOCAL bool RFM95_sleep(void) LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t sequenceNumber, const rfm95_RSSI_t RSSI, const rfm95_RSSI_t SNR) { - RFM95_DEBUG(PSTR("RFM95:SAC:SEND ACK to=%d,RSSI=%d\n"),recipient,RSSI); + RFM95_DEBUG(PSTR("RFM95:SAC:SEND ACK to=%d,RSSI=%d\n"),recipient,RFM95_internalToRSSI(RSSI)); rfm95_ack_t ACK; ACK.sequenceNumber = sequenceNumber; ACK.RSSI = RSSI; @@ -416,19 +406,21 @@ LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t s LOCAL bool RFM95_executeATC(const rfm95_RSSI_t currentRSSI, const rfm95_RSSI_t targetRSSI) { - // allow +-5% - if (currentRSSI < (targetRSSI*1.05) && RFM95.powerLevel < RFM95_MAX_POWER_LEVEL_DBM) { + // RFM95 internal format RSSI has an offset + if (currentRSSI < (targetRSSI * (1 + RFM95_ATC_TARGET_RANGE_PERCENT / 100)) && + RFM95.powerLevel < RFM95_MAX_POWER_LEVEL_DBM) { // increase transmitter power RFM95.powerLevel++; - } else if (currentRSSI > (targetRSSI*0.95) && RFM95.powerLevel > RFM95_MIN_POWER_LEVEL_DBM) { + } else if (currentRSSI > (targetRSSI * (1 - RFM95_ATC_TARGET_RANGE_PERCENT / 100)) && + RFM95.powerLevel > RFM95_MIN_POWER_LEVEL_DBM) { // decrease transmitter power RFM95.powerLevel--; } else { // nothing to adjust return false; } - RFM95_DEBUG(PSTR("RFM95:ATC:ADJ TXL,cR=%d,tR=%d,TXL=%d\n"), currentRSSI - RFM95_RSSI_OFFSET, - targetRSSI - RFM95_RSSI_OFFSET, RFM95.powerLevel); + RFM95_DEBUG(PSTR("RFM95:ATC:ADJ TXL,cR=%d,tR=%d,TXL=%d\n"), RFM95_internalToRSSI(currentRSSI), + RFM95_internalToRSSI(targetRSSI), RFM95.powerLevel); return RFM95_setTxPower(RFM95.powerLevel);; } @@ -454,7 +446,8 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, if (sender == recipient && RFM95_getACKReceived(flag) && (ACKsequenceNumber == RFM95.txSequenceNumber - 1)) { RFM95_DEBUG(PSTR("RFM95:SWR:ACK FROM=%d,SEQ=%d,RSSI=%d,SNR=%d\n"),sender,ACKsequenceNumber, - RFM95.currentPacket.ACK.RSSI-RFM95_RSSI_OFFSET, (int8_t)RFM95.currentPacket.ACK.SNR / 4); + RFM95_internalToRSSI(RFM95.currentPacket.ACK.RSSI), + RFM95_internalToSNR(RFM95.currentPacket.ACK.SNR)); RFM95_clearRxBuffer(); // ATC @@ -469,24 +462,24 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, RFM95_DEBUG(PSTR("!RFM95:SWR:NACK\n")); if (RFM95.ATCenabled) { // No ACK received, maybe out of reach: increase power level - RFM95_setTxPower(RFM95.powerLevel++); + (void)RFM95_setTxPower(RFM95.powerLevel++); } } return false; } - // Wait until no channel activity detected or timeout LOCAL bool RFM95_waitCAD(void) { + (void)RFM95_setRadioMode(RFM95_RADIO_MODE_CAD); const uint32_t enterMS = hwMillis(); - while (RFM95_isChannelActive()) { + while (RFM95.radioMode == RFM95_RADIO_MODE_CAD) { if (hwMillis() - enterMS > RFM95_CAD_TIMEOUT_MS) { return false; } doYield(); } - return true; + return !RFM95.cad; } // Wait for any previous transmission to finish @@ -498,15 +491,10 @@ LOCAL bool RFM95_waitPacketSent(void) return true; } -LOCAL int16_t RFM95_getRSSI(void) -{ - return (int16_t)(RFM95.currentPacket.RSSI - RFM95_RSSI_OFFSET); -} - LOCAL void RFM95_ATCmode(const bool OnOff, const int16_t targetRSSI) { RFM95.ATCenabled = OnOff; - RFM95.ATCtargetRSSI = (uint8_t)(targetRSSI + RFM95_RSSI_OFFSET); + RFM95.ATCtargetRSSI = RFM95_RSSItoInternal(targetRSSI); } LOCAL bool RFM95_sanityCheck(void) @@ -516,11 +504,46 @@ LOCAL bool RFM95_sanityCheck(void) } +LOCAL int16_t RFM95_getSendingRSSI(void) +{ + // own RSSI, as measured by the recipient - ACK part + if (RFM95_getACKRSSIReport(RFM95.currentPacket.header.controlFlags)) { + return RFM95_internalToRSSI(RFM95.currentPacket.ACK.RSSI); + } else { + // not possible + return RFM95_RSSI_INVALID; + } +} +LOCAL int8_t RFM95_getSendingSNR(void) +{ + // own SNR, as measured by the recipient - ACK part + if (RFM95_getACKRSSIReport(RFM95.currentPacket.header.controlFlags)) { + return RFM95_internalToSNR(RFM95.currentPacket.ACK.SNR); + } else { + // not possible + return RFM95_SNR_INVALID; + } +} +LOCAL int16_t RFM95_getReceivingRSSI(void) +{ + // RSSI from last received packet + return RFM95_internalToRSSI(RFM95.currentPacket.RSSI); +} +LOCAL int8_t RFM95_getReceivingSNR(void) +{ + // SNR from last received packet + return RFM95_internalToSNR(RFM95.currentPacket.SNR); +} - - - +LOCAL uint8_t RFM95_getTxPowerPercent(void) +{ + // report TX level in % + const uint8_t result = (uint8_t)(100.0f * (RFM95.powerLevel - RFM95_MIN_POWER_LEVEL_DBM) / + (RFM95_MAX_POWER_LEVEL_DBM + - RFM95_MIN_POWER_LEVEL_DBM)); + return result; +} diff --git a/drivers/RFM95/RFM95.h b/drivers/RFM95/RFM95.h index 110b165..bd78276 100644 --- a/drivers/RFM95/RFM95.h +++ b/drivers/RFM95/RFM95.h @@ -40,20 +40,17 @@ * RFM95 driver-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE * - [!] Exclamation mark is prepended in case of error * -* This section is WIP! -* -* |E| SYS | SUB | Message | Comment -* |-|-------|----------|-----------------------------------|--------------------------------------------------------------------- -* | | RFM95 | INIT | | Initialise RFM95 radio -* | | RFM95 | RCV | SEND ACK | ACK request received, sending ACK back -* | | RFM95 | PTC | LEVEL=%d | Set TX power level -* | | RFM95 | SAC | SEND ACK TO=%d,RSSI=%d | Send ACK to node (TO), RSSI of received message (RSSI) -* | | RFM95 | ATC | ADJ TXL,cR=%d,tR=%d,TXL=%d | Adjust TX level, current RSSI (cR), target RSSI (tR), TX level (TXL) -* | | RFM95 | SWR | SEND TO=%d,RETRY=%d | Send message to (TO), NACK retry counter (RETRY) -* | | RFM95 | SWR | ACK FROM=%d,SEQ=%d,RSSI=%d,SNR=%d | ACK received from node (FROM), seq ID (SEQ), (RSSI), (SNR) -* |!| RFM95 | SWR | NACK | No ACK received - -* +* |E| SYS | SUB | Message | Comment +* |-|-------|-------|-----------------------------------|--------------------------------------------------------------------- +* | | RFM95 | INIT | | Initialise RFM95 radio +* |!| RFM95 | INIT | SANCHK FAIL | Sanity check failed, check wiring or replace module +* | | RFM95 | RCV | SEND ACK | ACK request received, sending ACK back +* | | RFM95 | PTC | LEVEL=%d | Set TX power level +* | | RFM95 | SAC | SEND ACK TO=%d,RSSI=%d | Send ACK to node (TO), RSSI of received message (RSSI) +* | | RFM95 | ATC | ADJ TXL,cR=%d,tR=%d,TXL=%d | Adjust TX level, current RSSI (cR), target RSSI (tR), TX level (TXL) +* | | RFM95 | SWR | SEND TO=%d,RETRY=%d | Send message to (TO), NACK retry counter (RETRY) +* | | RFM95 | SWR | ACK FROM=%d,SEQ=%d,RSSI=%d,SNR=%d | ACK received from node (FROM), seq ID (SEQ), (RSSI), (SNR) +* |!| RFM95 | SWR | NACK | No ACK received * * RFM95 modem configuration * @@ -75,32 +72,33 @@ #ifndef _RFM95_h #define _RFM95_h +#include "RFM95registers.h" + +// default PIN assignments, can be overridden #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) -#define RFM95_IRQ_PIN (2) -#define RFM95_RST_PIN (9) +#define RFM95_IRQ_PIN (2) //!< RFM95_IRQ_PIN +#define RFM95_RST_PIN (9) //!< RFM95_RST_PIN #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) #define RFM95_IRQ_PIN (2) -#define RFM95_RST_PIN (9) +#define RFM95_RST_PIN (9) //!< RFM95_RST_PIN #elif defined(__AVR_ATmega32U4__) -#define RFM95_IRQ_PIN (3) -#define RFM95_RST_PIN (9) +#define RFM95_IRQ_PIN (3) //!< RFM95_IRQ_PIN +#define RFM95_RST_PIN (9) //!< RFM95_RST_PIN #elif defined(__arm__) -#define RFM95_IRQ_PIN (10) -#define RFM95_RST_PIN (27) +#define RFM95_IRQ_PIN (10) //!< RFM95_IRQ_PIN +#define RFM95_RST_PIN (27) //!< RFM95_RST_PIN #else -#define RFM95_IRQ_PIN (2) //!< RFM95_IRQ_PIN -#define RFM95_RST_PIN (9) //!< RFM95_IRQ_PIN +#define RFM95_IRQ_PIN (2) //!< RFM95_IRQ_PIN +#define RFM95_RST_PIN (9) //!< RFM95_RST_PIN #endif +#define RFM95_SPI_CS (SS) //!< RFM95_SPI_CS // SPI settings -#define RFM95_SPI_CS (SS) //!< SPI CS/SS pin - - #if !defined(MY_RFM95_SPI_MAX_SPEED) -#define MY_RFM95_SPI_MAX_SPEED 4000000 //!< SPI speed +#define MY_RFM95_SPI_MAX_SPEED (4*1000000ul) //!< Max SPI speed, 4Mhz #endif -#define MY_RFM95_SPI_DATA_ORDER MSBFIRST //!< SPI data order -#define MY_RFM95_SPI_DATA_MODE SPI_MODE0 //!< SPI mode +#define MY_RFM95_SPI_DATA_ORDER MSBFIRST //!< SPI data order +#define MY_RFM95_SPI_DATA_MODE SPI_MODE0 //!< SPI mode #if defined (ARDUINO) && !defined (__arm__) && !defined (_SPI) @@ -109,17 +107,17 @@ SoftSPI _SPI; #else -#define _SPI SPI +#define _SPI SPI //!< SPI #endif #else #if defined(__arm__) #include #else -extern HardwareSPI SPI; //!< SPI +extern HardwareSPI SPI; //!< SPI #endif #if !defined(_SPI) -#define _SPI SPI //!< SPI +#define _SPI SPI //!< SPI #endif #endif @@ -130,37 +128,43 @@ extern HardwareSPI SPI; //!< SPI #define RFM95_DEBUG(x,...) //!< Debug null #endif -#define RFM95_FIFO_SIZE (0xFFu) //!< Max number of bytes the LORA Rx/Tx FIFO can hold -#define RFM95_RX_FIFO_ADDR (0x00u) //!< RX FIFO addr pointer -#define RFM95_TX_FIFO_ADDR (0x80u) //!< TX FIFO addr pointer -#define RFM95_MAX_PACKET_LEN (0x40u) //!< This is the maximum number of bytes that can be carried by the LORA -#define RFM95_PREAMBLE_LENGTH (8u) //!< Preamble length, default=8 - - -#define RFM95_CAD_TIMEOUT_MS (2*1000ul) //!< channel activity detection timeout -#define RFM95_FXOSC (32000000.0f) //!< The crystal oscillator frequency of the module -#define RFM95_FSTEP (RFM95_FXOSC / 524288ul) //!< The Frequency Synthesizer step = RFM95_FXOSC / +#define RFM95_FIFO_SIZE (0xFFu) //!< Max number of bytes the LORA Rx/Tx FIFO can hold +#define RFM95_RX_FIFO_ADDR (0x00u) //!< RX FIFO addr pointer +#define RFM95_TX_FIFO_ADDR (0x80u) //!< TX FIFO addr pointer +#define RFM95_MAX_PACKET_LEN (0x40u) //!< This is the maximum number of bytes that can be carried by the LORA +#define RFM95_PREAMBLE_LENGTH (8u) //!< Preamble length, default=8 +#define RFM95_RETRIES (2u) //!< Retries in case of failed transmission +#define RFM95_RETRY_TIMEOUT_MS (500ul) //!< Timeout for ACK, adjustments needed if modem configuration changed (air time different) +#define RFM95_CAD_TIMEOUT_MS (2*1000ul) //!< channel activity detection timeout #define RFM95_PACKET_HEADER_VERSION (1u) //!< RFM95 packet header version #define RFM95_MIN_PACKET_HEADER_VERSION (1u) //!< Minimal RFM95 packet header version -#define RFM95_RETRIES (2u) //!< Retries in case of failed transmission -#define RFM95_RETRY_TIMEOUT_MS (500ul) //!< Timeout for ACK, adjustments needed if modem configuration changed (air time different) - #define RFM95_BIT_ACK_REQUESTED (7u) //!< RFM95 header, controlFlag, bit 7 #define RFM95_BIT_ACK_RECEIVED (6u) //!< RFM95 header, controlFlag, bit 6 #define RFM95_BIT_ACK_RSSI_REPORT (5u) //!< RFM95 header, controlFlag, bit 5 #define RFM95_BROADCAST_ADDRESS (255u) //!< Broadcasting address +#define RFM95_ATC_TARGET_RANGE_PERCENT (5u) //!< ATC target range +/-% #define RFM95_RSSI_OFFSET (137u) //!< RSSI offset #define RFM95_TARGET_RSSI (-60) //!< RSSI target +#define RFM95_RSSI_INVALID (127) //!< RSSI invalid +#define RFM95_SNR_INVALID (127) //!< SNR invalid #define RFM95_PROMISCUOUS (false) //!< RFM95 promiscuous mode -#define RFM95_getACKRequested(__value) ((bool)bitRead(__value, RFM95_BIT_ACK_REQUESTED)) //!< getACKRequested -#define RFM95_setACKRequested(__value, __flag) bitWrite(__value, RFM95_BIT_ACK_REQUESTED,__flag) //!< setACKRequested -#define RFM95_getACKReceived(__value) ((bool)bitRead(__value, RFM95_BIT_ACK_RECEIVED)) //!< getACKReceived -#define RFM95_setACKReceived(__value, __flag) bitWrite(__value, RFM95_BIT_ACK_RECEIVED,__flag) //!< setACKReceived -#define RFM95_setACKRSSIReport(__value, __flag) bitWrite(__value, RFM95_BIT_ACK_RSSI_REPORT,__flag) //!< setACKRSSIReport -#define RFM95_getACKRSSIReport(__value) ((bool)bitRead(__value, RFM95_BIT_ACK_RSSI_REPORT)) //!< getACKRSSIReport +#define RFM95_FXOSC (32*1000000ul) //!< The crystal oscillator frequency of the module +#define RFM95_FSTEP (RFM95_FXOSC / 524288ul) //!< The Frequency Synthesizer step = RFM95_FXOSC / + +// helper macros +#define RFM95_getACKRequested(__value) ((bool)bitRead(__value, RFM95_BIT_ACK_REQUESTED)) //!< getACKRequested +#define RFM95_setACKRequested(__value, __flag) bitWrite(__value, RFM95_BIT_ACK_REQUESTED,__flag) //!< setACKRequested +#define RFM95_getACKReceived(__value) ((bool)bitRead(__value, RFM95_BIT_ACK_RECEIVED)) //!< getACKReceived +#define RFM95_setACKReceived(__value, __flag) bitWrite(__value, RFM95_BIT_ACK_RECEIVED,__flag) //!< setACKReceived +#define RFM95_setACKRSSIReport(__value, __flag) bitWrite(__value, RFM95_BIT_ACK_RSSI_REPORT,__flag) //!< setACKRSSIReport +#define RFM95_getACKRSSIReport(__value) ((bool)bitRead(__value, RFM95_BIT_ACK_RSSI_REPORT)) //!< getACKRSSIReport +#define RFM95_internalToRSSI(__value) ((int16_t)(__value - RFM95_RSSI_OFFSET)) //!< Convert internal RSSI to RSSI +#define RFM95_RSSItoInternal(__value) ((uint8_t)(__value + RFM95_RSSI_OFFSET)) //!< Convert RSSI to internal RSSI +#define RFM95_internalToSNR(__value) ((int8_t)(__value / 4)) //!< Convert internal SNR to SNR + // RFM95 radio configurations: reg_1d, reg_1e, reg_26 (see datasheet) #define RFM95_BW125CR45SF128 RFM95_BW_125KHZ | RFM95_CODING_RATE_4_5, RFM95_SPREADING_FACTOR_128CPS | RFM95_RX_PAYLOAD_CRC_ON, RFM95_AGC_AUTO_ON //!< 0x72,0x74,0x04 @@ -341,11 +345,6 @@ LOCAL bool RFM95_setTxPower(uint8_t powerLevel); */ LOCAL bool RFM95_sleep(void); /** -* @brief Use the radio's Channel Activity Detect (CAD) function to detect channel activity -* @return true if channel is in use -*/ -LOCAL bool RFM95_isChannelActive(void); -/** * @brief RFM95_sendACK * @param recipient * @param sequenceNumber @@ -367,8 +366,8 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, const uint8_t bufferSize, const uint8_t retries = RFM95_RETRIES, const uint32_t retryWaitTime = RFM95_RETRY_TIMEOUT_MS); /** -* @brief RFM95_waitCAD -* @return True if no channel activity detected +* @brief Wait until no channel activity detected +* @return True if no channel activity detected, False if timeout occured */ LOCAL bool RFM95_waitCAD(void); /** @@ -391,10 +390,16 @@ LOCAL void RFM95_interruptHandler(void); */ LOCAL void RFM95_clearRxBuffer(void); /** -* @brief RFM95_getRSSI -* @return RSSI Signal strength of last packet +* @brief RFM95_getSendingRSSI +* @return RSSI Signal strength of last packet received */ -LOCAL int16_t RFM95_getRSSI(void); +LOCAL int16_t RFM95_getReceivingRSSI(void); + +/** +* @brief RFM95_getSendingRSSI +* @return RSSI Signal strength of last packet sent (if ACK and ATC enabled) +*/ +LOCAL int16_t RFM95_getSendingRSSI(void); /** * @brief RFM_executeATC * @param currentRSSI @@ -408,182 +413,11 @@ LOCAL bool RFM95_executeATC(const rfm95_RSSI_t currentRSSI, const rfm95_RSSI_t t * @param OnOff True to enable ATC */ LOCAL void RFM95_ATCmode(const bool OnOff, const int16_t targetRSSI = RFM95_TARGET_RSSI); - -volatile rfm95_internal_t RFM95; //!< internal variables - -// Register access -#define RFM95_READ_REGISTER (0x7Fu) //!< reading register -#define RFM95_WRITE_REGISTER (0x80u) //!< writing register - -// Registers, available LoRa mode -#define RFM95_REG_00_FIFO 0x00 //!< REG_00_FIFO -#define RFM95_REG_01_OP_MODE 0x01 //!< REG_01_OP_MODE -#define RFM95_REG_02_RESERVED 0x02 //!< REG_02_RESERVED -#define RFM95_REG_03_RESERVED 0x03 //!< REG_03_RESERVED -#define RFM95_REG_04_RESERVED 0x04 //!< REG_04_RESERVED -#define RFM95_REG_05_RESERVED 0x05 //!< REG_05_RESERVED -#define RFM95_REG_06_FRF_MSB 0x06 //!< REG_06_FRF_MSB -#define RFM95_REG_07_FRF_MID 0x07 //!< REG_07_FRF_MID -#define RFM95_REG_08_FRF_LSB 0x08 //!< REG_08_FRF_LSB -#define RFM95_REG_09_PA_CONFIG 0x09 //!< REG_09_PA_CONFIG -#define RFM95_REG_0A_PA_RAMP 0x0a //!< REG_0A_PA_RAMP -#define RFM95_REG_0B_OCP 0x0b //!< REG_0B_OCP -#define RFM95_REG_0C_LNA 0x0c //!< REG_0C_LNA -#define RFM95_REG_0D_FIFO_ADDR_PTR 0x0d //!< REG_0D_FIFO_ADDR_PTR -#define RFM95_REG_0E_FIFO_TX_BASE_ADDR 0x0e //!< REG_0E_FIFO_TX_BASE_ADDR -#define RFM95_REG_0F_FIFO_RX_BASE_ADDR 0x0f //!< REG_0F_FIFO_RX_BASE_ADDR -#define RFM95_REG_10_FIFO_RX_CURRENT_ADDR 0x10 //!< REG_10_FIFO_RX_CURRENT_ADDR -#define RFM95_REG_11_IRQ_FLAGS_MASK 0x11 //!< REG_11_IRQ_FLAGS_MASK -#define RFM95_REG_12_IRQ_FLAGS 0x12 //!< REG_12_IRQ_FLAGS -#define RFM95_REG_13_RX_NB_BYTES 0x13 //!< REG_13_RX_NB_BYTES -#define RFM95_REG_14_RX_HEADER_CNT_VALUE_MSB 0x14 //!< REG_14_RX_HEADER_CNT_VALUE_MSB -#define RFM95_REG_15_RX_HEADER_CNT_VALUE_LSB 0x15 //!< REG_15_RX_HEADER_CNT_VALUE_LSB -#define RFM95_REG_16_RX_PACKET_CNT_VALUE_MSB 0x16 //!< REG_16_RX_PACKET_CNT_VALUE_MSB -#define RFM95_REG_17_RX_PACKET_CNT_VALUE_LSB 0x17 //!< REG_17_RX_PACKET_CNT_VALUE_LSB -#define RFM95_REG_18_MODEM_STAT 0x18 //!< REG_18_MODEM_STAT -#define RFM95_REG_19_PKT_SNR_VALUE 0x19 //!< REG_19_PKT_SNR_VALUE -#define RFM95_REG_1A_PKT_RSSI_VALUE 0x1a //!< REG_1A_PKT_RSSI_VALUE -#define RFM95_REG_1B_RSSI_VALUE 0x1b //!< REG_1B_RSSI_VALUE -#define RFM95_REG_1C_HOP_CHANNEL 0x1c //!< REG_1C_HOP_CHANNEL -#define RFM95_REG_1D_MODEM_CONFIG1 0x1d //!< REG_1D_MODEM_CONFIG1 -#define RFM95_REG_1E_MODEM_CONFIG2 0x1e //!< REG_1E_MODEM_CONFIG2 -#define RFM95_REG_1F_SYMB_TIMEOUT_LSB 0x1f //!< REG_1F_SYMB_TIMEOUT_LSB -#define RFM95_REG_20_PREAMBLE_MSB 0x20 //!< REG_20_PREAMBLE_MSB -#define RFM95_REG_21_PREAMBLE_LSB 0x21 //!< REG_21_PREAMBLE_LSB -#define RFM95_REG_22_PAYLOAD_LENGTH 0x22 //!< REG_22_PAYLOAD_LENGTH -#define RFM95_REG_23_MAX_PAYLOAD_LENGTH 0x23 //!< REG_23_MAX_PAYLOAD_LENGTH -#define RFM95_REG_24_HOP_PERIOD 0x24 //!< REG_24_HOP_PERIOD -#define RFM95_REG_25_FIFO_RX_BYTE_ADDR 0x25 //!< REG_25_FIFO_RX_BYTE_ADDR -#define RFM95_REG_26_MODEM_CONFIG3 0x26 //!< REG_26_MODEM_CONFIG3 - -// Reserved when in LoRa mode -#define RFM95_REG_40_DIO_MAPPING1 0x40 //!< REG_40_DIO_MAPPING1 -#define RFM95_REG_41_DIO_MAPPING2 0x41 //!< REG_41_DIO_MAPPING2 -#define RFM95_REG_42_VERSION 0x42 //!< REG_42_VERSION -#define RFM95_REG_4B_TCXO 0x4b //!< REG_4B_TCXO -#define RFM95_REG_4D_PA_DAC 0x4d //!< REG_4D_PA_DAC -#define RFM95_REG_5B_FORMER_TEMP 0x5b //!< REG_5B_FORMER_TEMP -#define RFM95_REG_61_AGC_REF 0x61 //!< REG_61_AGC_REF -#define RFM95_REG_62_AGC_THRESH1 0x62 //!< REG_62_AGC_THRESH1 -#define RFM95_REG_63_AGC_THRESH2 0x63 //!< REG_63_AGC_THRESH2 -#define RFM95_REG_64_AGC_THRESH3 0x64 //!< REG_64_AGC_THRESH3 - -// RFM95_REG_01_OP_MODE 0x01 -#define RFM95_LONG_RANGE_MODE 0x80 //!< LONG_RANGE_MODE -#define RFM95_ACCESS_SHARED_REG 0x40 //!< ACCESS_SHARED_REG - -#define RFM95_MODE_SLEEP 0x00 //!< MODE_SLEEP -#define RFM95_MODE_STDBY 0x01 //!< MODE_STDBY -#define RFM95_MODE_FSTX 0x02 //!< MODE_FSTX -#define RFM95_MODE_TX 0x03 //!< MODE_TX -#define RFM95_MODE_FSRX 0x04 //!< MODE_FSRX -#define RFM95_MODE_RXCONTINUOUS 0x05 //!< MODE_RXCONTINUOUS -#define RFM95_MODE_RXSINGLE 0x06 //!< MODE_RXSINGLE -#define RFM95_MODE_CAD 0x07 //!< MODE_CAD - -// RFM95_REG_09_PA_CONFIG 0x09 -#define RFM95_OUTPUT_POWER 0x0F //!< OUTPUT_POWER -#define RFM95_MAX_POWER 0x70 //!< MAX_POWER -#define RFM95_PA_SELECT 0x80 //!< PA_SELECT - -// RFM95_REG_0A_PA_RAMP 0x0a -#define RFM95_PA_RAMP_3_4MS 0x00 //!< PA_RAMP_3_4MS -#define RFM95_PA_RAMP_2MS 0x01 //!< PA_RAMP_2MS -#define RFM95_PA_RAMP_1MS 0x02 //!< PA_RAMP_1MS -#define RFM95_PA_RAMP_500US 0x03 //!< PA_RAMP_500US -#define RFM95_PA_RAMP_250US 0x04 //!< PA_RAMP_250US -#define RFM95_PA_RAMP_125US 0x05 //!< PA_RAMP_125US -#define RFM95_PA_RAMP_100US 0x06 //!< PA_RAMP_100US -#define RFM95_PA_RAMP_62US 0x07 //!< PA_RAMP_62US -#define RFM95_PA_RAMP_50US 0x08 //!< PA_RAMP_50US -#define RFM95_PA_RAMP_40US 0x09 //!< PA_RAMP_40US -#define RFM95_PA_RAMP_31US 0x0A //!< PA_RAMP_31US -#define RFM95_PA_RAMP_25US 0x0B //!< PA_RAMP_25US -#define RFM95_PA_RAMP_20US 0x0C //!< PA_RAMP_20US -#define RFM95_PA_RAMP_15US 0x0D //!< PA_RAMP_15US -#define RFM95_PA_RAMP_12US 0x0E //!< PA_RAMP_12US -#define RFM95_PA_RAMP_10US 0x0F //!< PA_RAMP_10US -#define RFM95_LOW_PN_TX_PLL_OFF 0x10 //! +* Copyright (C) 2013-2016 Sensnology AB +* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors +* +* Documentation: http://www.mysensors.org +* Support Forum: http://forum.mysensors.org +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* version 2 as published by the Free Software Foundation. +* +* Based on Mike McCauley's RFM95 library, Copyright (C) 2014 Mike McCauley +* Radiohead http://www.airspayce.com/mikem/arduino/RadioHead/index.html +* RFM95 driver refactored and optimized for MySensors, Copyright (C) 2016 Olivier Mauti +* +* Changelog: +* - ACK with sequenceNumber +* - ATC control +* +* Definitions for HopeRF LoRa radios: +* http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf +* http://www.hoperf.cn/upload/rfchip/RF96_97_98.pdf +* +*/ + +// Register access +#define RFM95_READ_REGISTER (0x7Fu) //!< reading register +#define RFM95_WRITE_REGISTER (0x80u) //!< writing register + +// Registers, available in LoRa mode +#define RFM95_REG_00_FIFO 0x00 //!< REG_00_FIFO +#define RFM95_REG_01_OP_MODE 0x01 //!< REG_01_OP_MODE +#define RFM95_REG_02_RESERVED 0x02 //!< REG_02_RESERVED +#define RFM95_REG_03_RESERVED 0x03 //!< REG_03_RESERVED +#define RFM95_REG_04_RESERVED 0x04 //!< REG_04_RESERVED +#define RFM95_REG_05_RESERVED 0x05 //!< REG_05_RESERVED +#define RFM95_REG_06_FRF_MSB 0x06 //!< REG_06_FRF_MSB +#define RFM95_REG_07_FRF_MID 0x07 //!< REG_07_FRF_MID +#define RFM95_REG_08_FRF_LSB 0x08 //!< REG_08_FRF_LSB +#define RFM95_REG_09_PA_CONFIG 0x09 //!< REG_09_PA_CONFIG +#define RFM95_REG_0A_PA_RAMP 0x0a //!< REG_0A_PA_RAMP +#define RFM95_REG_0B_OCP 0x0b //!< REG_0B_OCP +#define RFM95_REG_0C_LNA 0x0c //!< REG_0C_LNA +#define RFM95_REG_0D_FIFO_ADDR_PTR 0x0d //!< REG_0D_FIFO_ADDR_PTR +#define RFM95_REG_0E_FIFO_TX_BASE_ADDR 0x0e //!< REG_0E_FIFO_TX_BASE_ADDR +#define RFM95_REG_0F_FIFO_RX_BASE_ADDR 0x0f //!< REG_0F_FIFO_RX_BASE_ADDR +#define RFM95_REG_10_FIFO_RX_CURRENT_ADDR 0x10 //!< REG_10_FIFO_RX_CURRENT_ADDR +#define RFM95_REG_11_IRQ_FLAGS_MASK 0x11 //!< REG_11_IRQ_FLAGS_MASK +#define RFM95_REG_12_IRQ_FLAGS 0x12 //!< REG_12_IRQ_FLAGS +#define RFM95_REG_13_RX_NB_BYTES 0x13 //!< REG_13_RX_NB_BYTES +#define RFM95_REG_14_RX_HEADER_CNT_VALUE_MSB 0x14 //!< REG_14_RX_HEADER_CNT_VALUE_MSB +#define RFM95_REG_15_RX_HEADER_CNT_VALUE_LSB 0x15 //!< REG_15_RX_HEADER_CNT_VALUE_LSB +#define RFM95_REG_16_RX_PACKET_CNT_VALUE_MSB 0x16 //!< REG_16_RX_PACKET_CNT_VALUE_MSB +#define RFM95_REG_17_RX_PACKET_CNT_VALUE_LSB 0x17 //!< REG_17_RX_PACKET_CNT_VALUE_LSB +#define RFM95_REG_18_MODEM_STAT 0x18 //!< REG_18_MODEM_STAT +#define RFM95_REG_19_PKT_SNR_VALUE 0x19 //!< REG_19_PKT_SNR_VALUE +#define RFM95_REG_1A_PKT_RSSI_VALUE 0x1a //!< REG_1A_PKT_RSSI_VALUE +#define RFM95_REG_1B_RSSI_VALUE 0x1b //!< REG_1B_RSSI_VALUE +#define RFM95_REG_1C_HOP_CHANNEL 0x1c //!< REG_1C_HOP_CHANNEL +#define RFM95_REG_1D_MODEM_CONFIG1 0x1d //!< REG_1D_MODEM_CONFIG1 +#define RFM95_REG_1E_MODEM_CONFIG2 0x1e //!< REG_1E_MODEM_CONFIG2 +#define RFM95_REG_1F_SYMB_TIMEOUT_LSB 0x1f //!< REG_1F_SYMB_TIMEOUT_LSB +#define RFM95_REG_20_PREAMBLE_MSB 0x20 //!< REG_20_PREAMBLE_MSB +#define RFM95_REG_21_PREAMBLE_LSB 0x21 //!< REG_21_PREAMBLE_LSB +#define RFM95_REG_22_PAYLOAD_LENGTH 0x22 //!< REG_22_PAYLOAD_LENGTH +#define RFM95_REG_23_MAX_PAYLOAD_LENGTH 0x23 //!< REG_23_MAX_PAYLOAD_LENGTH +#define RFM95_REG_24_HOP_PERIOD 0x24 //!< REG_24_HOP_PERIOD +#define RFM95_REG_25_FIFO_RX_BYTE_ADDR 0x25 //!< REG_25_FIFO_RX_BYTE_ADDR +#define RFM95_REG_26_MODEM_CONFIG3 0x26 //!< REG_26_MODEM_CONFIG3 + +// Reserved when in LoRa mode +#define RFM95_REG_40_DIO_MAPPING1 0x40 //!< REG_40_DIO_MAPPING1 +#define RFM95_REG_41_DIO_MAPPING2 0x41 //!< REG_41_DIO_MAPPING2 +#define RFM95_REG_42_VERSION 0x42 //!< REG_42_VERSION +#define RFM95_REG_4B_TCXO 0x4b //!< REG_4B_TCXO +#define RFM95_REG_4D_PA_DAC 0x4d //!< REG_4D_PA_DAC +#define RFM95_REG_5B_FORMER_TEMP 0x5b //!< REG_5B_FORMER_TEMP +#define RFM95_REG_61_AGC_REF 0x61 //!< REG_61_AGC_REF +#define RFM95_REG_62_AGC_THRESH1 0x62 //!< REG_62_AGC_THRESH1 +#define RFM95_REG_63_AGC_THRESH2 0x63 //!< REG_63_AGC_THRESH2 +#define RFM95_REG_64_AGC_THRESH3 0x64 //!< REG_64_AGC_THRESH3 + +// RFM95_REG_01_OP_MODE 0x01 +#define RFM95_LONG_RANGE_MODE 0x80 //!< LONG_RANGE_MODE +#define RFM95_ACCESS_SHARED_REG 0x40 //!< ACCESS_SHARED_REG + +#define RFM95_MODE_SLEEP 0x00 //!< MODE_SLEEP +#define RFM95_MODE_STDBY 0x01 //!< MODE_STDBY +#define RFM95_MODE_FSTX 0x02 //!< MODE_FSTX +#define RFM95_MODE_TX 0x03 //!< MODE_TX +#define RFM95_MODE_FSRX 0x04 //!< MODE_FSRX +#define RFM95_MODE_RXCONTINUOUS 0x05 //!< MODE_RXCONTINUOUS +#define RFM95_MODE_RXSINGLE 0x06 //!< MODE_RXSINGLE +#define RFM95_MODE_CAD 0x07 //!< MODE_CAD + +// RFM95_REG_09_PA_CONFIG 0x09 +#define RFM95_OUTPUT_POWER 0x0F //!< OUTPUT_POWER +#define RFM95_MAX_POWER 0x70 //!< MAX_POWER +#define RFM95_PA_SELECT 0x80 //!< PA_SELECT + +// RFM95_REG_0A_PA_RAMP 0x0a +#define RFM95_PA_RAMP_3_4MS 0x00 //!< PA_RAMP_3_4MS +#define RFM95_PA_RAMP_2MS 0x01 //!< PA_RAMP_2MS +#define RFM95_PA_RAMP_1MS 0x02 //!< PA_RAMP_1MS +#define RFM95_PA_RAMP_500US 0x03 //!< PA_RAMP_500US +#define RFM95_PA_RAMP_250US 0x04 //!< PA_RAMP_250US +#define RFM95_PA_RAMP_125US 0x05 //!< PA_RAMP_125US +#define RFM95_PA_RAMP_100US 0x06 //!< PA_RAMP_100US +#define RFM95_PA_RAMP_62US 0x07 //!< PA_RAMP_62US +#define RFM95_PA_RAMP_50US 0x08 //!< PA_RAMP_50US +#define RFM95_PA_RAMP_40US 0x09 //!< PA_RAMP_40US +#define RFM95_PA_RAMP_31US 0x0A //!< PA_RAMP_31US +#define RFM95_PA_RAMP_25US 0x0B //!< PA_RAMP_25US +#define RFM95_PA_RAMP_20US 0x0C //!< PA_RAMP_20US +#define RFM95_PA_RAMP_15US 0x0D //!< PA_RAMP_15US +#define RFM95_PA_RAMP_12US 0x0E //!< PA_RAMP_12US +#define RFM95_PA_RAMP_10US 0x0F //!< PA_RAMP_10US +#define RFM95_LOW_PN_TX_PLL_OFF 0x10 //!