diff --git a/src/CustomRF95.cpp b/src/rf95/CustomRF95.cpp similarity index 100% rename from src/CustomRF95.cpp rename to src/rf95/CustomRF95.cpp diff --git a/src/CustomRF95.h b/src/rf95/CustomRF95.h similarity index 100% rename from src/CustomRF95.h rename to src/rf95/CustomRF95.h diff --git a/src/rf95/RHGenericDriver.h b/src/rf95/RHGenericDriver.h index ae523d966..d06c9e4c0 100644 --- a/src/rf95/RHGenericDriver.h +++ b/src/rf95/RHGenericDriver.h @@ -8,21 +8,21 @@ #include -// Defines bits of the FLAGS header reserved for use by the RadioHead library and +// Defines bits of the FLAGS header reserved for use by the RadioHead library and // the flags available for use by applications -#define RH_FLAGS_RESERVED 0xf0 -#define RH_FLAGS_APPLICATION_SPECIFIC 0x0f -#define RH_FLAGS_NONE 0 +#define RH_FLAGS_RESERVED 0xf0 +#define RH_FLAGS_APPLICATION_SPECIFIC 0x0f +#define RH_FLAGS_NONE 0 // Default timeout for waitCAD() in ms -#define RH_CAD_DEFAULT_TIMEOUT 10000 +#define RH_CAD_DEFAULT_TIMEOUT 10000 ///////////////////////////////////////////////////////////////////// /// \class RHGenericDriver RHGenericDriver.h /// \brief Abstract base class for a RadioHead driver. /// /// This class defines the functions that must be provided by any RadioHead driver. -/// Different types of driver will implement all the abstract functions, and will perhaps override +/// Different types of driver will implement all the abstract functions, and will perhaps override /// other functions in this subclass, or perhaps add new functions specifically required by that driver. /// Do not directly instantiate this class: it is only to be subclassed by driver classes. /// @@ -40,19 +40,18 @@ /// significant 4 bits are reserved for applications. class RHGenericDriver { -public: + public: /// \brief Defines different operating modes for the transport hardware /// - /// These are the different values that can be adopted by the _mode variable and + /// These are the different values that can be adopted by the _mode variable and /// returned by the mode() member function, - typedef enum - { - RHModeInitialising = 0, ///< Transport is initialising. Initial default value until init() is called.. - RHModeSleep, ///< Transport hardware is in low power sleep mode (if supported) - RHModeIdle, ///< Transport is idle. - RHModeTx, ///< Transport is in the process of transmitting a message. - RHModeRx, ///< Transport is in the process of receiving a message. - RHModeCad ///< Transport is in the process of detecting channel activity (if supported) + typedef enum { + RHModeInitialising = 0, ///< Transport is initialising. Initial default value until init() is called.. + RHModeSleep, ///< Transport hardware is in low power sleep mode (if supported) + RHModeIdle, ///< Transport is idle. + RHModeTx, ///< Transport is in the process of transmitting a message. + RHModeRx, ///< Transport is in the process of receiving a message. + RHModeCad ///< Transport is in the process of detecting channel activity (if supported) } RHMode; /// Constructor @@ -64,7 +63,7 @@ public: virtual bool init(); /// Tests whether a new message is available - /// from the Driver. + /// from the Driver. /// On most drivers, if there is an uncollected received message, and there is no message /// currently bing transmitted, this will also put the Driver into RHModeRx mode until /// a message is actually received by the transport, when it will be returned to RHModeIdle. @@ -72,53 +71,29 @@ public: /// \return true if a new, complete, error-free uncollected message is available to be retreived by recv(). virtual bool available() = 0; - /// Turns the receiver on if it not already on. - /// If there is a valid message available, copy it to buf and return true - /// else return false. - /// If a message is copied, *len is set to the length (Caution, 0 length messages are permitted). - /// You should be sure to call this function frequently enough to not miss any messages - /// It is recommended that you call it in your main loop. - /// \param[in] buf Location to copy the received message - /// \param[in,out] len Pointer to available space in buf. Set to the actual number of octets copied. - /// \return true if a valid message was copied to buf - virtual bool recv(uint8_t* buf, uint8_t* len) = 0; - - /// Waits until any previous transmit packet is finished being transmitted with waitPacketSent(). - /// Then optionally waits for Channel Activity Detection (CAD) - /// to show the channnel is clear (if the radio supports CAD) by calling waitCAD(). - /// Then loads a message into the transmitter and starts the transmitter. Note that a message length - /// of 0 is NOT permitted. If the message is too long for the underlying radio technology, send() will - /// return false and will not send the message. - /// \param[in] data Array of data to be sent - /// \param[in] len Number of bytes of data to send (> 0) - /// specify the maximum time in ms to wait. If 0 (the default) do not wait for CAD before transmitting. - /// \return true if the message length was valid and it was correctly queued for transmit. Return false - /// if CAD was requested and the CAD timeout timed out before clear channel was detected. - virtual bool send(const uint8_t* data, uint8_t len) = 0; - - /// Returns the maximum message length + /// Returns the maximum message length /// available in this Driver. /// \return The maximum legal message length virtual uint8_t maxMessageLength() = 0; - /// Starts the receiver and blocks until a valid received + /// Starts the receiver and blocks until a valid received /// message is available. - virtual void waitAvailable(); + virtual void waitAvailable(); - /// Blocks until the transmitter + /// Blocks until the transmitter /// is no longer transmitting. - virtual bool waitPacketSent(); + virtual bool waitPacketSent(); /// Blocks until the transmitter is no longer transmitting. /// or until the timeout occuers, whichever happens first /// \param[in] timeout Maximum time to wait in milliseconds. /// \return true if the radio completed transmission within the timeout period. False if it timed out. - virtual bool waitPacketSent(uint16_t timeout); + virtual bool waitPacketSent(uint16_t timeout); /// Starts the receiver and blocks until a received message is available or a timeout /// \param[in] timeout Maximum time to wait in milliseconds. /// \return true if a message is available - virtual bool waitAvailableTimeout(uint16_t timeout); + virtual bool waitAvailableTimeout(uint16_t timeout); // Bent G Christensen (bentor@gmail.com), 08/15/2016 /// Channel Activity Detection (CAD). @@ -128,12 +103,12 @@ public: /// Caution: the random() function is not seeded. If you want non-deterministic behaviour, consider /// using something like randomSeed(analogRead(A0)); in your sketch. /// Permits the implementation of listen-before-talk mechanism (Collision Avoidance). - /// Calls the isChannelActive() member function for the radio (if supported) + /// Calls the isChannelActive() member function for the radio (if supported) /// to determine if the channel is active. If the radio does not support isChannelActive(), /// always returns true immediately /// \return true if the radio-specific CAD (as returned by isChannelActive()) /// shows the channel is clear within the timeout period (or the timeout period is 0), else returns false. - virtual bool waitCAD(); + virtual bool waitCAD(); /// Sets the Channel Activity Detection timeout in milliseconds to be used by waitCAD(). /// The default is 0, which means do not wait for CAD detection. @@ -142,166 +117,164 @@ public: /// Determine if the currently selected radio channel is active. /// This is expected to be subclassed by specific radios to implement their Channel Activity Detection - /// if supported. If the radio does not support CAD, returns true immediately. If a RadioHead radio + /// if supported. If the radio does not support CAD, returns true immediately. If a RadioHead radio /// supports isChannelActive() it will be documented in the radio specific documentation. /// This is called automatically by waitCAD(). /// \return true if the radio-specific CAD (as returned by override of isChannelActive()) shows the /// current radio channel as active, else false. If there is no radio-specific CAD, returns false. - virtual bool isChannelActive(); + virtual bool isChannelActive(); /// Sets the address of this node. Defaults to 0xFF. Subclasses or the user may want to change this. /// This will be used to test the adddress in incoming messages. In non-promiscuous mode, /// only messages with a TO header the same as thisAddress or the broadcast addess (0xFF) will be accepted. /// In promiscuous mode, all messages will be accepted regardless of the TO header. - /// In a conventional multinode system, all nodes will have a unique address + /// In a conventional multinode system, all nodes will have a unique address /// (which you could store in EEPROM). - /// You would normally set the header FROM address to be the same as thisAddress (though you dont have to, + /// You would normally set the header FROM address to be the same as thisAddress (though you dont have to, /// allowing the possibilty of address spoofing). /// \param[in] thisAddress The address of this node. virtual void setThisAddress(uint8_t thisAddress); /// Sets the TO header to be sent in all subsequent messages /// \param[in] to The new TO header value - virtual void setHeaderTo(uint8_t to); + virtual void setHeaderTo(uint8_t to); /// Sets the FROM header to be sent in all subsequent messages /// \param[in] from The new FROM header value - virtual void setHeaderFrom(uint8_t from); + virtual void setHeaderFrom(uint8_t from); /// Sets the ID header to be sent in all subsequent messages /// \param[in] id The new ID header value - virtual void setHeaderId(uint8_t id); + virtual void setHeaderId(uint8_t id); /// Sets and clears bits in the FLAGS header to be sent in all subsequent messages - /// First it clears he FLAGS according to the clear argument, then sets the flags according to the + /// First it clears he FLAGS according to the clear argument, then sets the flags according to the /// set argument. The default for clear always clears the application specific flags. /// \param[in] set bitmask of bits to be set. Flags are cleared with the clear mask before being set. /// \param[in] clear bitmask of flags to clear. Defaults to RH_FLAGS_APPLICATION_SPECIFIC /// which clears the application specific flags, resulting in new application specific flags /// identical to the set. - virtual void setHeaderFlags(uint8_t set, uint8_t clear = RH_FLAGS_APPLICATION_SPECIFIC); + virtual void setHeaderFlags(uint8_t set, uint8_t clear = RH_FLAGS_APPLICATION_SPECIFIC); /// Tells the receiver to accept messages with any TO address, not just messages /// addressed to thisAddress or the broadcast address /// \param[in] promiscuous true if you wish to receive messages with any TO address - virtual void setPromiscuous(bool promiscuous); + virtual void setPromiscuous(bool promiscuous); /// Returns the TO header of the last received message /// \return The TO header - virtual uint8_t headerTo(); + virtual uint8_t headerTo(); /// Returns the FROM header of the last received message /// \return The FROM header - virtual uint8_t headerFrom(); + virtual uint8_t headerFrom(); /// Returns the ID header of the last received message /// \return The ID header - virtual uint8_t headerId(); + virtual uint8_t headerId(); /// Returns the FLAGS header of the last received message /// \return The FLAGS header - virtual uint8_t headerFlags(); + virtual uint8_t headerFlags(); /// Returns the most recent RSSI (Receiver Signal Strength Indicator). /// Usually it is the RSSI of the last received message, which is measured when the preamble is received. /// If you called readRssi() more recently, it will return that more recent value. /// \return The most recent RSSI measurement in dBm. - virtual int16_t lastRssi(); + virtual int16_t lastRssi(); /// Returns the operating mode of the library. /// \return the current mode, one of RF69_MODE_* - virtual RHMode mode(); + virtual RHMode mode(); /// Sets the operating mode of the transport. - virtual void setMode(RHMode mode); + virtual void setMode(RHMode mode); /// Sets the transport hardware into low-power sleep mode /// (if supported). May be overridden by specific drivers to initialte sleep mode. - /// If successful, the transport will stay in sleep mode until woken by + /// If successful, the transport will stay in sleep mode until woken by /// changing mode it idle, transmit or receive (eg by calling send(), recv(), available() etc) /// \return true if sleep mode is supported by transport hardware and the RadioHead driver, and if sleep mode /// was successfully entered. If sleep mode is not suported, return false. - virtual bool sleep(); + virtual bool sleep(); /// Prints a data buffer in HEX. /// For diagnostic use /// \param[in] prompt string to preface the print /// \param[in] buf Location of the buffer to print /// \param[in] len Length of the buffer in octets. - static void printBuffer(const char* prompt, const uint8_t* buf, uint8_t len); + static void printBuffer(const char *prompt, const uint8_t *buf, uint8_t len); /// Returns the count of the number of bad received packets (ie packets with bad lengths, checksum etc) /// which were rejected and not delivered to the application. /// Caution: not all drivers can correctly report this count. Some underlying hardware only report /// good packets. /// \return The number of bad packets received. - virtual uint16_t rxBad(); + virtual uint16_t rxBad(); - /// Returns the count of the number of + /// Returns the count of the number of /// good received packets /// \return The number of good packets received. - virtual uint16_t rxGood(); + virtual uint16_t rxGood(); - /// Returns the count of the number of + /// Returns the count of the number of /// packets successfully transmitted (though not necessarily received by the destination) /// \return The number of packets successfully transmitted - virtual uint16_t txGood(); - -protected: + virtual uint16_t txGood(); + protected: /// The current transport operating mode - volatile RHMode _mode; + volatile RHMode _mode; /// This node id - uint8_t _thisAddress; - + uint8_t _thisAddress; + /// Whether the transport is in promiscuous mode - bool _promiscuous; + bool _promiscuous; /// TO header in the last received mesasge - volatile uint8_t _rxHeaderTo; + volatile uint8_t _rxHeaderTo; /// FROM header in the last received mesasge - volatile uint8_t _rxHeaderFrom; + volatile uint8_t _rxHeaderFrom; /// ID header in the last received mesasge - volatile uint8_t _rxHeaderId; + volatile uint8_t _rxHeaderId; /// FLAGS header in the last received mesasge - volatile uint8_t _rxHeaderFlags; + volatile uint8_t _rxHeaderFlags; /// TO header to send in all messages - uint8_t _txHeaderTo; + uint8_t _txHeaderTo; /// FROM header to send in all messages - uint8_t _txHeaderFrom; + uint8_t _txHeaderFrom; /// ID header to send in all messages - uint8_t _txHeaderId; + uint8_t _txHeaderId; /// FLAGS header to send in all messages - uint8_t _txHeaderFlags; + uint8_t _txHeaderFlags; /// The value of the last received RSSI value, in some transport specific units - volatile int16_t _lastRssi; + volatile int16_t _lastRssi; /// Count of the number of bad messages (eg bad checksum etc) received - volatile uint16_t _rxBad; + volatile uint16_t _rxBad; /// Count of the number of successfully transmitted messaged - volatile uint16_t _rxGood; + volatile uint16_t _rxGood; /// Count of the number of bad messages (correct checksum etc) received - volatile uint16_t _txGood; - + volatile uint16_t _txGood; + /// Channel activity detected - volatile bool _cad; + volatile bool _cad; /// Channel activity timeout in ms - unsigned int _cad_timeout; - -private: + unsigned int _cad_timeout; + private: }; -#endif +#endif diff --git a/src/rf95/RH_RF95.cpp b/src/rf95/RH_RF95.cpp index 7d7bf0fd9..d08de8b1d 100644 --- a/src/rf95/RH_RF95.cpp +++ b/src/rf95/RH_RF95.cpp @@ -13,19 +13,17 @@ uint8_t RH_RF95::_interruptCount = 0; // Index into _deviceForInterrupt for next // These are indexed by the values of ModemConfigChoice // Stored in flash (program) memory to save SRAM -PROGMEM static const RH_RF95::ModemConfig MODEM_CONFIG_TABLE[] = - { - // 1d, 1e, 26 - {0x72, 0x74, 0x04}, // Bw125Cr45Sf128 (the chip default), AGC enabled - {0x92, 0x74, 0x04}, // Bw500Cr45Sf128, AGC enabled - {0x48, 0x94, 0x04}, // Bw31_25Cr48Sf512, AGC enabled - {0x78, 0xc4, 0x0c}, // Bw125Cr48Sf4096, AGC enabled +PROGMEM static const RH_RF95::ModemConfig MODEM_CONFIG_TABLE[] = { + // 1d, 1e, 26 + {0x72, 0x74, 0x04}, // Bw125Cr45Sf128 (the chip default), AGC enabled + {0x92, 0x74, 0x04}, // Bw500Cr45Sf128, AGC enabled + {0x48, 0x94, 0x04}, // Bw31_25Cr48Sf512, AGC enabled + {0x78, 0xc4, 0x0c}, // Bw125Cr48Sf4096, AGC enabled }; RH_RF95::RH_RF95(uint8_t slaveSelectPin, uint8_t interruptPin, RHGenericSPI &spi) - : RHSPIDriver(slaveSelectPin, spi), - _rxBufValid(0) + : RHSPIDriver(slaveSelectPin, spi), _rxBufValid(0) { _interruptPin = interruptPin; _myInterruptIndex = 0xff; // Not allocated yet @@ -54,16 +52,15 @@ bool RH_RF95::init() // On all other platforms, its innocuous, belt and braces pinMode(_interruptPin, INPUT); - bool isWakeFromDeepSleep = false; // true if we think we are waking from deep sleep AND the rf95 seems to have a valid configuration + bool isWakeFromDeepSleep = + false; // true if we think we are waking from deep sleep AND the rf95 seems to have a valid configuration - if (!isWakeFromDeepSleep) - { + if (!isWakeFromDeepSleep) { // Set sleep mode, so we can also set LORA mode: spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_SLEEP | RH_RF95_LONG_RANGE_MODE); delay(10); // Wait for sleep mode to take over from say, CAD // Check we are in sleep mode, with LORA set - if (spiRead(RH_RF95_REG_01_OP_MODE) != (RH_RF95_MODE_SLEEP | RH_RF95_LONG_RANGE_MODE)) - { + if (spiRead(RH_RF95_REG_01_OP_MODE) != (RH_RF95_MODE_SLEEP | RH_RF95_LONG_RANGE_MODE)) { // Serial.println(spiRead(RH_RF95_REG_01_OP_MODE), HEX); return false; // No device present? } @@ -93,16 +90,15 @@ bool RH_RF95::init() setTxPower(13); Serial.printf("IRQ flag mask 0x%x\n", spiRead(RH_RF95_REG_11_IRQ_FLAGS_MASK)); - } - else - { + } else { // FIXME // restore mode base off reading RS95 registers // Only let CPU enter deep sleep if RF95 is sitting waiting on a receive or is in idle or sleep. } - // geeksville: we do this last, because if there is an interrupt pending from during the deep sleep, this attach will cause it to be taken. + // geeksville: we do this last, because if there is an interrupt pending from during the deep sleep, this attach will cause it + // to be taken. // Set up interrupt handler // Since there are a limited number of interrupt glue functions isr*() available, @@ -110,8 +106,7 @@ bool RH_RF95::init() // ON some devices, notably most Arduinos, the interrupt pin passed in is actuallt the // interrupt number. You have to figure out the interruptnumber-to-interruptpin mapping // yourself based on knwledge of what Arduino board you are running on. - if (_myInterruptIndex == 0xff) - { + if (_myInterruptIndex == 0xff) { // First run, no interrupt allocated yet if (_interruptCount <= RH_RF95_NUM_INTERRUPTS) _myInterruptIndex = _interruptCount++; @@ -139,17 +134,15 @@ void RH_RF95::prepareDeepSleep() detachInterrupt(interruptNumber); } -bool RH_RF95::isReceiving() +bool RH_RF95::isReceiving() { // 0x0b == Look for header info valid, signal synchronized or signal detected uint8_t reg = spiRead(RH_RF95_REG_18_MODEM_STAT) & 0x1f; // Serial.printf("reg %x\n", reg); - return _mode == RHModeRx && (reg & (RH_RF95_MODEM_STATUS_SIGNAL_DETECTED | - RH_RF95_MODEM_STATUS_SIGNAL_SYNCHRONIZED | - RH_RF95_MODEM_STATUS_HEADER_INFO_VALID)) != 0; + return _mode == RHModeRx && (reg & (RH_RF95_MODEM_STATUS_SIGNAL_DETECTED | RH_RF95_MODEM_STATUS_SIGNAL_SYNCHRONIZED | + RH_RF95_MODEM_STATUS_HEADER_INFO_VALID)) != 0; } - // C++ level interrupt handler for this instance // LORA is unusual in that it has several interrupt lines, and not a single, combined one. // On MiniWirelessLoRa, only one of the several interrupt lines (DI0) from the RFM95 is usefuly @@ -172,21 +165,17 @@ void RH_RF95::handleInterrupt() clearRxBuf(); } - if ((irq_flags & RH_RF95_RX_DONE) && !haveRxError) - { + if ((irq_flags & RH_RF95_RX_DONE) && !haveRxError) { // Read the RegHopChannel register to check if CRC presence is signalled // in the header. If not it might be a stray (noise) packet.* uint8_t crc_present = spiRead(RH_RF95_REG_1C_HOP_CHANNEL) & RH_RF95_RX_PAYLOAD_CRC_IS_ON; spiWrite(RH_RF95_REG_12_IRQ_FLAGS, 0xff); // Clear all IRQ flags, required before reading fifo (according to datasheet) - if (!crc_present) - { + if (!crc_present) { _rxBad++; clearRxBuf(); - } - else - { + } else { // Have received a packet uint8_t len = spiRead(RH_RF95_REG_13_RX_NB_BYTES); @@ -220,21 +209,18 @@ void RH_RF95::handleInterrupt() } } - if (irq_flags & RH_RF95_TX_DONE) - { + if (irq_flags & RH_RF95_TX_DONE) { _txGood++; setModeIdle(); } - - if (_mode == RHModeCad && (irq_flags & RH_RF95_CAD_DONE)) - { + + if (_mode == RHModeCad && (irq_flags & RH_RF95_CAD_DONE)) { _cad = irq_flags & RH_RF95_CAD_DETECTED; setModeIdle(); } // ack all interrupts, note - we did this already in the RX_DONE case above, and we don't want to do it twice - if (!(irq_flags & RH_RF95_RX_DONE)) - { + if (!(irq_flags & RH_RF95_RX_DONE)) { // Sigh: on some processors, for some unknown reason, doing this only once does not actually // clear the radio's interrupt flag. So we do it twice. Why? // kevinh: turn this off until root cause is known, because it can cause missed interrupts! @@ -272,10 +258,7 @@ void RH_RF95::validateRxBuf() _rxHeaderFrom = _buf[1]; _rxHeaderId = _buf[2]; _rxHeaderFlags = _buf[3]; - if (_promiscuous || - _rxHeaderTo == _thisAddress || - _rxHeaderTo == RH_BROADCAST_ADDRESS) - { + if (_promiscuous || _rxHeaderTo == _thisAddress || _rxHeaderTo == RH_BROADCAST_ADDRESS) { _rxGood++; _rxBufValid = true; } @@ -297,23 +280,6 @@ void RH_RF95::clearRxBuf() ATOMIC_BLOCK_END; } -bool RH_RF95::recv(uint8_t *buf, uint8_t *len) -{ - if (!available()) - return false; - if (buf && len) - { - ATOMIC_BLOCK_START; - // Skip the 4 headers that are at the beginning of the rxBuf - if (*len > _bufLen - RH_RF95_HEADER_LEN) - *len = _bufLen - RH_RF95_HEADER_LEN; - memcpy(buf, _buf + RH_RF95_HEADER_LEN, *len); - ATOMIC_BLOCK_END; - } - clearRxBuf(); // This message accepted and cleared - return true; -} - bool RH_RF95::send(const uint8_t *data, uint8_t len) { if (len > RH_RF95_MAX_MESSAGE_LEN) @@ -344,11 +310,12 @@ bool RH_RF95::send(const uint8_t *data, uint8_t len) bool RH_RF95::printRegisters() { #ifdef RH_HAVE_SERIAL - uint8_t registers[] = {0x01, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x014, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27}; + uint8_t registers[] = {0x01, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x014, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, + 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27}; uint8_t i; - for (i = 0; i < sizeof(registers); i++) - { + for (i = 0; i < sizeof(registers); i++) { Serial.print(registers[i], HEX); Serial.print(": "); Serial.println(spiRead(registers[i]), HEX); @@ -376,8 +343,7 @@ bool RH_RF95::setFrequency(float centre) void RH_RF95::setModeIdle() { - if (_mode != RHModeIdle) - { + if (_mode != RHModeIdle) { spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_STDBY); _mode = RHModeIdle; } @@ -385,8 +351,7 @@ void RH_RF95::setModeIdle() bool RH_RF95::sleep() { - if (_mode != RHModeSleep) - { + if (_mode != RHModeSleep) { spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_SLEEP); _mode = RHModeSleep; } @@ -395,8 +360,7 @@ bool RH_RF95::sleep() void RH_RF95::setModeRx() { - if (_mode != RHModeRx) - { + if (_mode != RHModeRx) { spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_RXCONTINUOUS); spiWrite(RH_RF95_REG_40_DIO_MAPPING1, 0x00); // Interrupt on RxDone _mode = RHModeRx; @@ -405,8 +369,7 @@ void RH_RF95::setModeRx() void RH_RF95::setModeTx() { - if (_mode != RHModeTx) - { + if (_mode != RHModeTx) { spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_TX); spiWrite(RH_RF95_REG_40_DIO_MAPPING1, 0x40); // Interrupt on TxDone _mode = RHModeTx; @@ -417,16 +380,13 @@ void RH_RF95::setTxPower(int8_t power, bool useRFO) { // Sigh, different behaviours depending on whther the module use PA_BOOST or the RFO pin // for the transmitter output - if (useRFO) - { + if (useRFO) { if (power > 14) power = 14; if (power < -1) power = -1; spiWrite(RH_RF95_REG_09_PA_CONFIG, RH_RF95_MAX_POWER | (power + 1)); - } - else - { + } else { if (power > 23) power = 23; if (power < 5) @@ -435,13 +395,10 @@ void RH_RF95::setTxPower(int8_t power, bool useRFO) // For RH_RF95_PA_DAC_ENABLE, manual says '+20dBm on PA_BOOST when OutputPower=0xf' // RH_RF95_PA_DAC_ENABLE actually adds about 3dBm to all power levels. We will us it // for 21, 22 and 23dBm - if (power > 20) - { + if (power > 20) { spiWrite(RH_RF95_REG_4D_PA_DAC, RH_RF95_PA_DAC_ENABLE); power -= 3; - } - else - { + } else { spiWrite(RH_RF95_REG_4D_PA_DAC, RH_RF95_PA_DAC_DISABLE); } @@ -486,8 +443,7 @@ void RH_RF95::setPreambleLength(uint16_t bytes) bool RH_RF95::isChannelActive() { // Set mode RHModeCad - if (_mode != RHModeCad) - { + if (_mode != RHModeCad) { spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_CAD); spiWrite(RH_RF95_REG_40_DIO_MAPPING1, 0x80); // Interrupt on CadDone _mode = RHModeCad; @@ -501,8 +457,7 @@ bool RH_RF95::isChannelActive() void RH_RF95::enableTCXO() { - while ((spiRead(RH_RF95_REG_4B_TCXO) & RH_RF95_TCXO_TCXO_INPUT_ON) != RH_RF95_TCXO_TCXO_INPUT_ON) - { + while ((spiRead(RH_RF95_REG_4B_TCXO) & RH_RF95_TCXO_TCXO_INPUT_ON) != RH_RF95_TCXO_TCXO_INPUT_ON) { sleep(); spiWrite(RH_RF95_REG_4B_TCXO, (spiRead(RH_RF95_REG_4B_TCXO) | RH_RF95_TCXO_TCXO_INPUT_ON)); } @@ -577,7 +532,7 @@ void RH_RF95::setSpreadingFactor(uint8_t sf) void RH_RF95::setSignalBandwidth(long sbw) { - uint8_t bw; //register bit pattern + uint8_t bw; // register bit pattern if (sbw <= 7800) bw = RH_RF95_BW_7_8KHZ; @@ -629,7 +584,8 @@ void RH_RF95::setLowDatarate() // Semtech modem design guide AN1200.13 says // "To avoid issues surrounding drift of the crystal reference oscillator due to either temperature change // or motion,the low data rate optimization bit is used. Specifically for 125 kHz bandwidth and SF = 11 and 12, - // this adds a small overhead to increase robustness to reference frequency variations over the timescale of the LoRa packet." + // this adds a small overhead to increase robustness to reference frequency variations over the timescale of the LoRa + // packet." // read current value for BW and SF uint8_t BW = spiRead(RH_RF95_REG_1D_MODEM_CONFIG1) >> 4; // bw is in bits 7..4 diff --git a/src/rf95/RH_RF95.h b/src/rf95/RH_RF95.h index 43a5bc573..7a4a34a64 100644 --- a/src/rf95/RH_RF95.h +++ b/src/rf95/RH_RF95.h @@ -7,7 +7,7 @@ // Author: Mike McCauley (mikem@airspayce.com) // Copyright (C) 2014 Mike McCauley // $Id: RH_RF95.h,v 1.23 2019/11/02 02:34:22 mikem Exp $ -// +// #ifndef RH_RF95_h #define RH_RF95_h @@ -29,222 +29,221 @@ // The headers are inside the LORA's payload #define RH_RF95_HEADER_LEN 4 -// This is the maximum message length that can be supported by this driver. +// This is the maximum message length that can be supported by this driver. // Can be pre-defined to a smaller size (to save SRAM) prior to including this header // Here we allow for 1 byte message length, 4 bytes headers, user data and 2 bytes of FCS #ifndef RH_RF95_MAX_MESSAGE_LEN - #define RH_RF95_MAX_MESSAGE_LEN (RH_RF95_MAX_PAYLOAD_LEN - RH_RF95_HEADER_LEN) +#define RH_RF95_MAX_MESSAGE_LEN (RH_RF95_MAX_PAYLOAD_LEN - RH_RF95_HEADER_LEN) #endif // The crystal oscillator frequency of the module #define RH_RF95_FXOSC 32000000.0 // The Frequency Synthesizer step = RH_RF95_FXOSC / 2^^19 -#define RH_RF95_FSTEP (RH_RF95_FXOSC / 524288) - +#define RH_RF95_FSTEP (RH_RF95_FXOSC / 524288) // Register names (LoRa Mode, from table 85) -#define RH_RF95_REG_00_FIFO 0x00 -#define RH_RF95_REG_01_OP_MODE 0x01 -#define RH_RF95_REG_02_RESERVED 0x02 -#define RH_RF95_REG_03_RESERVED 0x03 -#define RH_RF95_REG_04_RESERVED 0x04 -#define RH_RF95_REG_05_RESERVED 0x05 -#define RH_RF95_REG_06_FRF_MSB 0x06 -#define RH_RF95_REG_07_FRF_MID 0x07 -#define RH_RF95_REG_08_FRF_LSB 0x08 -#define RH_RF95_REG_09_PA_CONFIG 0x09 -#define RH_RF95_REG_0A_PA_RAMP 0x0a -#define RH_RF95_REG_0B_OCP 0x0b -#define RH_RF95_REG_0C_LNA 0x0c -#define RH_RF95_REG_0D_FIFO_ADDR_PTR 0x0d -#define RH_RF95_REG_0E_FIFO_TX_BASE_ADDR 0x0e -#define RH_RF95_REG_0F_FIFO_RX_BASE_ADDR 0x0f -#define RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR 0x10 -#define RH_RF95_REG_11_IRQ_FLAGS_MASK 0x11 -#define RH_RF95_REG_12_IRQ_FLAGS 0x12 -#define RH_RF95_REG_13_RX_NB_BYTES 0x13 -#define RH_RF95_REG_14_RX_HEADER_CNT_VALUE_MSB 0x14 -#define RH_RF95_REG_15_RX_HEADER_CNT_VALUE_LSB 0x15 -#define RH_RF95_REG_16_RX_PACKET_CNT_VALUE_MSB 0x16 -#define RH_RF95_REG_17_RX_PACKET_CNT_VALUE_LSB 0x17 -#define RH_RF95_REG_18_MODEM_STAT 0x18 -#define RH_RF95_REG_19_PKT_SNR_VALUE 0x19 -#define RH_RF95_REG_1A_PKT_RSSI_VALUE 0x1a -#define RH_RF95_REG_1B_RSSI_VALUE 0x1b -#define RH_RF95_REG_1C_HOP_CHANNEL 0x1c -#define RH_RF95_REG_1D_MODEM_CONFIG1 0x1d -#define RH_RF95_REG_1E_MODEM_CONFIG2 0x1e -#define RH_RF95_REG_1F_SYMB_TIMEOUT_LSB 0x1f -#define RH_RF95_REG_20_PREAMBLE_MSB 0x20 -#define RH_RF95_REG_21_PREAMBLE_LSB 0x21 -#define RH_RF95_REG_22_PAYLOAD_LENGTH 0x22 -#define RH_RF95_REG_23_MAX_PAYLOAD_LENGTH 0x23 -#define RH_RF95_REG_24_HOP_PERIOD 0x24 -#define RH_RF95_REG_25_FIFO_RX_BYTE_ADDR 0x25 -#define RH_RF95_REG_26_MODEM_CONFIG3 0x26 +#define RH_RF95_REG_00_FIFO 0x00 +#define RH_RF95_REG_01_OP_MODE 0x01 +#define RH_RF95_REG_02_RESERVED 0x02 +#define RH_RF95_REG_03_RESERVED 0x03 +#define RH_RF95_REG_04_RESERVED 0x04 +#define RH_RF95_REG_05_RESERVED 0x05 +#define RH_RF95_REG_06_FRF_MSB 0x06 +#define RH_RF95_REG_07_FRF_MID 0x07 +#define RH_RF95_REG_08_FRF_LSB 0x08 +#define RH_RF95_REG_09_PA_CONFIG 0x09 +#define RH_RF95_REG_0A_PA_RAMP 0x0a +#define RH_RF95_REG_0B_OCP 0x0b +#define RH_RF95_REG_0C_LNA 0x0c +#define RH_RF95_REG_0D_FIFO_ADDR_PTR 0x0d +#define RH_RF95_REG_0E_FIFO_TX_BASE_ADDR 0x0e +#define RH_RF95_REG_0F_FIFO_RX_BASE_ADDR 0x0f +#define RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR 0x10 +#define RH_RF95_REG_11_IRQ_FLAGS_MASK 0x11 +#define RH_RF95_REG_12_IRQ_FLAGS 0x12 +#define RH_RF95_REG_13_RX_NB_BYTES 0x13 +#define RH_RF95_REG_14_RX_HEADER_CNT_VALUE_MSB 0x14 +#define RH_RF95_REG_15_RX_HEADER_CNT_VALUE_LSB 0x15 +#define RH_RF95_REG_16_RX_PACKET_CNT_VALUE_MSB 0x16 +#define RH_RF95_REG_17_RX_PACKET_CNT_VALUE_LSB 0x17 +#define RH_RF95_REG_18_MODEM_STAT 0x18 +#define RH_RF95_REG_19_PKT_SNR_VALUE 0x19 +#define RH_RF95_REG_1A_PKT_RSSI_VALUE 0x1a +#define RH_RF95_REG_1B_RSSI_VALUE 0x1b +#define RH_RF95_REG_1C_HOP_CHANNEL 0x1c +#define RH_RF95_REG_1D_MODEM_CONFIG1 0x1d +#define RH_RF95_REG_1E_MODEM_CONFIG2 0x1e +#define RH_RF95_REG_1F_SYMB_TIMEOUT_LSB 0x1f +#define RH_RF95_REG_20_PREAMBLE_MSB 0x20 +#define RH_RF95_REG_21_PREAMBLE_LSB 0x21 +#define RH_RF95_REG_22_PAYLOAD_LENGTH 0x22 +#define RH_RF95_REG_23_MAX_PAYLOAD_LENGTH 0x23 +#define RH_RF95_REG_24_HOP_PERIOD 0x24 +#define RH_RF95_REG_25_FIFO_RX_BYTE_ADDR 0x25 +#define RH_RF95_REG_26_MODEM_CONFIG3 0x26 -#define RH_RF95_REG_27_PPM_CORRECTION 0x27 -#define RH_RF95_REG_28_FEI_MSB 0x28 -#define RH_RF95_REG_29_FEI_MID 0x29 -#define RH_RF95_REG_2A_FEI_LSB 0x2a -#define RH_RF95_REG_2C_RSSI_WIDEBAND 0x2c -#define RH_RF95_REG_31_DETECT_OPTIMIZE 0x31 -#define RH_RF95_REG_33_INVERT_IQ 0x33 -#define RH_RF95_REG_37_DETECTION_THRESHOLD 0x37 -#define RH_RF95_REG_39_SYNC_WORD 0x39 +#define RH_RF95_REG_27_PPM_CORRECTION 0x27 +#define RH_RF95_REG_28_FEI_MSB 0x28 +#define RH_RF95_REG_29_FEI_MID 0x29 +#define RH_RF95_REG_2A_FEI_LSB 0x2a +#define RH_RF95_REG_2C_RSSI_WIDEBAND 0x2c +#define RH_RF95_REG_31_DETECT_OPTIMIZE 0x31 +#define RH_RF95_REG_33_INVERT_IQ 0x33 +#define RH_RF95_REG_37_DETECTION_THRESHOLD 0x37 +#define RH_RF95_REG_39_SYNC_WORD 0x39 -#define RH_RF95_REG_40_DIO_MAPPING1 0x40 -#define RH_RF95_REG_41_DIO_MAPPING2 0x41 -#define RH_RF95_REG_42_VERSION 0x42 +#define RH_RF95_REG_40_DIO_MAPPING1 0x40 +#define RH_RF95_REG_41_DIO_MAPPING2 0x41 +#define RH_RF95_REG_42_VERSION 0x42 -#define RH_RF95_REG_4B_TCXO 0x4b -#define RH_RF95_REG_4D_PA_DAC 0x4d -#define RH_RF95_REG_5B_FORMER_TEMP 0x5b -#define RH_RF95_REG_61_AGC_REF 0x61 -#define RH_RF95_REG_62_AGC_THRESH1 0x62 -#define RH_RF95_REG_63_AGC_THRESH2 0x63 -#define RH_RF95_REG_64_AGC_THRESH3 0x64 +#define RH_RF95_REG_4B_TCXO 0x4b +#define RH_RF95_REG_4D_PA_DAC 0x4d +#define RH_RF95_REG_5B_FORMER_TEMP 0x5b +#define RH_RF95_REG_61_AGC_REF 0x61 +#define RH_RF95_REG_62_AGC_THRESH1 0x62 +#define RH_RF95_REG_63_AGC_THRESH2 0x63 +#define RH_RF95_REG_64_AGC_THRESH3 0x64 // RH_RF95_REG_01_OP_MODE 0x01 -#define RH_RF95_LONG_RANGE_MODE 0x80 -#define RH_RF95_ACCESS_SHARED_REG 0x40 -#define RH_RF95_LOW_FREQUENCY_MODE 0x08 -#define RH_RF95_MODE 0x07 -#define RH_RF95_MODE_SLEEP 0x00 -#define RH_RF95_MODE_STDBY 0x01 -#define RH_RF95_MODE_FSTX 0x02 -#define RH_RF95_MODE_TX 0x03 -#define RH_RF95_MODE_FSRX 0x04 -#define RH_RF95_MODE_RXCONTINUOUS 0x05 -#define RH_RF95_MODE_RXSINGLE 0x06 -#define RH_RF95_MODE_CAD 0x07 +#define RH_RF95_LONG_RANGE_MODE 0x80 +#define RH_RF95_ACCESS_SHARED_REG 0x40 +#define RH_RF95_LOW_FREQUENCY_MODE 0x08 +#define RH_RF95_MODE 0x07 +#define RH_RF95_MODE_SLEEP 0x00 +#define RH_RF95_MODE_STDBY 0x01 +#define RH_RF95_MODE_FSTX 0x02 +#define RH_RF95_MODE_TX 0x03 +#define RH_RF95_MODE_FSRX 0x04 +#define RH_RF95_MODE_RXCONTINUOUS 0x05 +#define RH_RF95_MODE_RXSINGLE 0x06 +#define RH_RF95_MODE_CAD 0x07 // RH_RF95_REG_09_PA_CONFIG 0x09 -#define RH_RF95_PA_SELECT 0x80 -#define RH_RF95_MAX_POWER 0x70 -#define RH_RF95_OUTPUT_POWER 0x0f +#define RH_RF95_PA_SELECT 0x80 +#define RH_RF95_MAX_POWER 0x70 +#define RH_RF95_OUTPUT_POWER 0x0f // RH_RF95_REG_0A_PA_RAMP 0x0a -#define RH_RF95_LOW_PN_TX_PLL_OFF 0x10 -#define RH_RF95_PA_RAMP 0x0f -#define RH_RF95_PA_RAMP_3_4MS 0x00 -#define RH_RF95_PA_RAMP_2MS 0x01 -#define RH_RF95_PA_RAMP_1MS 0x02 -#define RH_RF95_PA_RAMP_500US 0x03 -#define RH_RF95_PA_RAMP_250US 0x04 -#define RH_RF95_PA_RAMP_125US 0x05 -#define RH_RF95_PA_RAMP_100US 0x06 -#define RH_RF95_PA_RAMP_62US 0x07 -#define RH_RF95_PA_RAMP_50US 0x08 -#define RH_RF95_PA_RAMP_40US 0x09 -#define RH_RF95_PA_RAMP_31US 0x0a -#define RH_RF95_PA_RAMP_25US 0x0b -#define RH_RF95_PA_RAMP_20US 0x0c -#define RH_RF95_PA_RAMP_15US 0x0d -#define RH_RF95_PA_RAMP_12US 0x0e -#define RH_RF95_PA_RAMP_10US 0x0f +#define RH_RF95_LOW_PN_TX_PLL_OFF 0x10 +#define RH_RF95_PA_RAMP 0x0f +#define RH_RF95_PA_RAMP_3_4MS 0x00 +#define RH_RF95_PA_RAMP_2MS 0x01 +#define RH_RF95_PA_RAMP_1MS 0x02 +#define RH_RF95_PA_RAMP_500US 0x03 +#define RH_RF95_PA_RAMP_250US 0x04 +#define RH_RF95_PA_RAMP_125US 0x05 +#define RH_RF95_PA_RAMP_100US 0x06 +#define RH_RF95_PA_RAMP_62US 0x07 +#define RH_RF95_PA_RAMP_50US 0x08 +#define RH_RF95_PA_RAMP_40US 0x09 +#define RH_RF95_PA_RAMP_31US 0x0a +#define RH_RF95_PA_RAMP_25US 0x0b +#define RH_RF95_PA_RAMP_20US 0x0c +#define RH_RF95_PA_RAMP_15US 0x0d +#define RH_RF95_PA_RAMP_12US 0x0e +#define RH_RF95_PA_RAMP_10US 0x0f // RH_RF95_REG_0B_OCP 0x0b -#define RH_RF95_OCP_ON 0x20 -#define RH_RF95_OCP_TRIM 0x1f +#define RH_RF95_OCP_ON 0x20 +#define RH_RF95_OCP_TRIM 0x1f // RH_RF95_REG_0C_LNA 0x0c -#define RH_RF95_LNA_GAIN 0xe0 -#define RH_RF95_LNA_GAIN_G1 0x20 -#define RH_RF95_LNA_GAIN_G2 0x40 -#define RH_RF95_LNA_GAIN_G3 0x60 -#define RH_RF95_LNA_GAIN_G4 0x80 -#define RH_RF95_LNA_GAIN_G5 0xa0 -#define RH_RF95_LNA_GAIN_G6 0xc0 -#define RH_RF95_LNA_BOOST_LF 0x18 -#define RH_RF95_LNA_BOOST_LF_DEFAULT 0x00 -#define RH_RF95_LNA_BOOST_HF 0x03 -#define RH_RF95_LNA_BOOST_HF_DEFAULT 0x00 -#define RH_RF95_LNA_BOOST_HF_150PC 0x03 +#define RH_RF95_LNA_GAIN 0xe0 +#define RH_RF95_LNA_GAIN_G1 0x20 +#define RH_RF95_LNA_GAIN_G2 0x40 +#define RH_RF95_LNA_GAIN_G3 0x60 +#define RH_RF95_LNA_GAIN_G4 0x80 +#define RH_RF95_LNA_GAIN_G5 0xa0 +#define RH_RF95_LNA_GAIN_G6 0xc0 +#define RH_RF95_LNA_BOOST_LF 0x18 +#define RH_RF95_LNA_BOOST_LF_DEFAULT 0x00 +#define RH_RF95_LNA_BOOST_HF 0x03 +#define RH_RF95_LNA_BOOST_HF_DEFAULT 0x00 +#define RH_RF95_LNA_BOOST_HF_150PC 0x03 // RH_RF95_REG_11_IRQ_FLAGS_MASK 0x11 -#define RH_RF95_RX_TIMEOUT_MASK 0x80 -#define RH_RF95_RX_DONE_MASK 0x40 -#define RH_RF95_PAYLOAD_CRC_ERROR_MASK 0x20 -#define RH_RF95_VALID_HEADER_MASK 0x10 -#define RH_RF95_TX_DONE_MASK 0x08 -#define RH_RF95_CAD_DONE_MASK 0x04 -#define RH_RF95_FHSS_CHANGE_CHANNEL_MASK 0x02 -#define RH_RF95_CAD_DETECTED_MASK 0x01 +#define RH_RF95_RX_TIMEOUT_MASK 0x80 +#define RH_RF95_RX_DONE_MASK 0x40 +#define RH_RF95_PAYLOAD_CRC_ERROR_MASK 0x20 +#define RH_RF95_VALID_HEADER_MASK 0x10 +#define RH_RF95_TX_DONE_MASK 0x08 +#define RH_RF95_CAD_DONE_MASK 0x04 +#define RH_RF95_FHSS_CHANGE_CHANNEL_MASK 0x02 +#define RH_RF95_CAD_DETECTED_MASK 0x01 // RH_RF95_REG_12_IRQ_FLAGS 0x12 -#define RH_RF95_RX_TIMEOUT 0x80 -#define RH_RF95_RX_DONE 0x40 -#define RH_RF95_PAYLOAD_CRC_ERROR 0x20 -#define RH_RF95_VALID_HEADER 0x10 -#define RH_RF95_TX_DONE 0x08 -#define RH_RF95_CAD_DONE 0x04 -#define RH_RF95_FHSS_CHANGE_CHANNEL 0x02 -#define RH_RF95_CAD_DETECTED 0x01 +#define RH_RF95_RX_TIMEOUT 0x80 +#define RH_RF95_RX_DONE 0x40 +#define RH_RF95_PAYLOAD_CRC_ERROR 0x20 +#define RH_RF95_VALID_HEADER 0x10 +#define RH_RF95_TX_DONE 0x08 +#define RH_RF95_CAD_DONE 0x04 +#define RH_RF95_FHSS_CHANGE_CHANNEL 0x02 +#define RH_RF95_CAD_DETECTED 0x01 // RH_RF95_REG_18_MODEM_STAT 0x18 -#define RH_RF95_RX_CODING_RATE 0xe0 -#define RH_RF95_MODEM_STATUS_CLEAR 0x10 -#define RH_RF95_MODEM_STATUS_HEADER_INFO_VALID 0x08 -#define RH_RF95_MODEM_STATUS_RX_ONGOING 0x04 -#define RH_RF95_MODEM_STATUS_SIGNAL_SYNCHRONIZED 0x02 -#define RH_RF95_MODEM_STATUS_SIGNAL_DETECTED 0x01 +#define RH_RF95_RX_CODING_RATE 0xe0 +#define RH_RF95_MODEM_STATUS_CLEAR 0x10 +#define RH_RF95_MODEM_STATUS_HEADER_INFO_VALID 0x08 +#define RH_RF95_MODEM_STATUS_RX_ONGOING 0x04 +#define RH_RF95_MODEM_STATUS_SIGNAL_SYNCHRONIZED 0x02 +#define RH_RF95_MODEM_STATUS_SIGNAL_DETECTED 0x01 // RH_RF95_REG_1C_HOP_CHANNEL 0x1c -#define RH_RF95_PLL_TIMEOUT 0x80 -#define RH_RF95_RX_PAYLOAD_CRC_IS_ON 0x40 -#define RH_RF95_FHSS_PRESENT_CHANNEL 0x3f +#define RH_RF95_PLL_TIMEOUT 0x80 +#define RH_RF95_RX_PAYLOAD_CRC_IS_ON 0x40 +#define RH_RF95_FHSS_PRESENT_CHANNEL 0x3f // RH_RF95_REG_1D_MODEM_CONFIG1 0x1d -#define RH_RF95_BW 0xf0 +#define RH_RF95_BW 0xf0 -#define RH_RF95_BW_7_8KHZ 0x00 -#define RH_RF95_BW_10_4KHZ 0x10 -#define RH_RF95_BW_15_6KHZ 0x20 -#define RH_RF95_BW_20_8KHZ 0x30 -#define RH_RF95_BW_31_25KHZ 0x40 -#define RH_RF95_BW_41_7KHZ 0x50 -#define RH_RF95_BW_62_5KHZ 0x60 -#define RH_RF95_BW_125KHZ 0x70 -#define RH_RF95_BW_250KHZ 0x80 -#define RH_RF95_BW_500KHZ 0x90 -#define RH_RF95_CODING_RATE 0x0e -#define RH_RF95_CODING_RATE_4_5 0x02 -#define RH_RF95_CODING_RATE_4_6 0x04 -#define RH_RF95_CODING_RATE_4_7 0x06 -#define RH_RF95_CODING_RATE_4_8 0x08 -#define RH_RF95_IMPLICIT_HEADER_MODE_ON 0x01 +#define RH_RF95_BW_7_8KHZ 0x00 +#define RH_RF95_BW_10_4KHZ 0x10 +#define RH_RF95_BW_15_6KHZ 0x20 +#define RH_RF95_BW_20_8KHZ 0x30 +#define RH_RF95_BW_31_25KHZ 0x40 +#define RH_RF95_BW_41_7KHZ 0x50 +#define RH_RF95_BW_62_5KHZ 0x60 +#define RH_RF95_BW_125KHZ 0x70 +#define RH_RF95_BW_250KHZ 0x80 +#define RH_RF95_BW_500KHZ 0x90 +#define RH_RF95_CODING_RATE 0x0e +#define RH_RF95_CODING_RATE_4_5 0x02 +#define RH_RF95_CODING_RATE_4_6 0x04 +#define RH_RF95_CODING_RATE_4_7 0x06 +#define RH_RF95_CODING_RATE_4_8 0x08 +#define RH_RF95_IMPLICIT_HEADER_MODE_ON 0x01 // RH_RF95_REG_1E_MODEM_CONFIG2 0x1e -#define RH_RF95_SPREADING_FACTOR 0xf0 -#define RH_RF95_SPREADING_FACTOR_64CPS 0x60 -#define RH_RF95_SPREADING_FACTOR_128CPS 0x70 -#define RH_RF95_SPREADING_FACTOR_256CPS 0x80 -#define RH_RF95_SPREADING_FACTOR_512CPS 0x90 -#define RH_RF95_SPREADING_FACTOR_1024CPS 0xa0 -#define RH_RF95_SPREADING_FACTOR_2048CPS 0xb0 -#define RH_RF95_SPREADING_FACTOR_4096CPS 0xc0 -#define RH_RF95_TX_CONTINUOUS_MODE 0x08 +#define RH_RF95_SPREADING_FACTOR 0xf0 +#define RH_RF95_SPREADING_FACTOR_64CPS 0x60 +#define RH_RF95_SPREADING_FACTOR_128CPS 0x70 +#define RH_RF95_SPREADING_FACTOR_256CPS 0x80 +#define RH_RF95_SPREADING_FACTOR_512CPS 0x90 +#define RH_RF95_SPREADING_FACTOR_1024CPS 0xa0 +#define RH_RF95_SPREADING_FACTOR_2048CPS 0xb0 +#define RH_RF95_SPREADING_FACTOR_4096CPS 0xc0 +#define RH_RF95_TX_CONTINUOUS_MODE 0x08 -#define RH_RF95_PAYLOAD_CRC_ON 0x04 -#define RH_RF95_SYM_TIMEOUT_MSB 0x03 +#define RH_RF95_PAYLOAD_CRC_ON 0x04 +#define RH_RF95_SYM_TIMEOUT_MSB 0x03 // RH_RF95_REG_26_MODEM_CONFIG3 -#define RH_RF95_MOBILE_NODE 0x08 // HopeRF term -#define RH_RF95_LOW_DATA_RATE_OPTIMIZE 0x08 // Semtechs term -#define RH_RF95_AGC_AUTO_ON 0x04 +#define RH_RF95_MOBILE_NODE 0x08 // HopeRF term +#define RH_RF95_LOW_DATA_RATE_OPTIMIZE 0x08 // Semtechs term +#define RH_RF95_AGC_AUTO_ON 0x04 // RH_RF95_REG_4B_TCXO 0x4b -#define RH_RF95_TCXO_TCXO_INPUT_ON 0x10 +#define RH_RF95_TCXO_TCXO_INPUT_ON 0x10 // RH_RF95_REG_4D_PA_DAC 0x4d -#define RH_RF95_PA_DAC_DISABLE 0x04 -#define RH_RF95_PA_DAC_ENABLE 0x07 +#define RH_RF95_PA_DAC_DISABLE 0x04 +#define RH_RF95_PA_DAC_ENABLE 0x07 ///////////////////////////////////////////////////////////////////// /// \class RH_RF95 RH_RF95.h -/// \brief Driver to send and receive unaddressed, unreliable datagrams via a LoRa +/// \brief Driver to send and receive unaddressed, unreliable datagrams via a LoRa /// capable radio transceiver. /// /// For Semtech SX1276/77/78/79 and HopeRF RF95/96/97/98 and other similar LoRa capable radios. @@ -257,27 +256,28 @@ /// /// Works with /// - the excellent MiniWirelessLoRa from Anarduino http://www.anarduino.com/miniwireless -/// - The excellent Modtronix inAir4 http://modtronix.com/inair4.html +/// - The excellent Modtronix inAir4 http://modtronix.com/inair4.html /// and inAir9 modules http://modtronix.com/inair9.html. -/// - the excellent Rocket Scream Mini Ultra Pro with the RFM95W +/// - the excellent Rocket Scream Mini Ultra Pro with the RFM95W /// http://www.rocketscream.com/blog/product/mini-ultra-pro-with-radio/ /// - Lora1276 module from NiceRF http://www.nicerf.com/product_view.aspx?id=99 /// - Adafruit Feather M0 with RFM95 /// - The very fine Talk2 Whisper Node LoRa boards https://wisen.com.au/store/products/whisper-node-lora -/// an Arduino compatible board, which include an on-board RFM95/96 LoRa Radio (Semtech SX1276), external antenna, +/// an Arduino compatible board, which include an on-board RFM95/96 LoRa Radio (Semtech SX1276), external antenna, /// run on 2xAAA batteries and support low power operations. RF95 examples work without modification. /// Use Arduino Board Manager to install the Talk2 code support. Upload the code with an FTDI adapter set to 5V. -/// - heltec / TTGO ESP32 LoRa OLED https://www.aliexpress.com/item/Internet-Development-Board-SX1278-ESP32-WIFI-chip-0-96-inch-OLED-Bluetooth-WIFI-Lora-Kit-32/32824535649.html +/// - heltec / TTGO ESP32 LoRa OLED +/// https://www.aliexpress.com/item/Internet-Development-Board-SX1278-ESP32-WIFI-chip-0-96-inch-OLED-Bluetooth-WIFI-Lora-Kit-32/32824535649.html /// /// \par Overview /// -/// This class provides basic functions for sending and receiving unaddressed, +/// This class provides basic functions for sending and receiving unaddressed, /// unreliable datagrams of arbitrary length to 251 octets per packet. /// -/// Manager classes may use this class to implement reliable, addressed datagrams and streams, +/// Manager classes may use this class to implement reliable, addressed datagrams and streams, /// mesh routers, repeaters, translators etc. /// -/// Naturally, for any 2 radios to communicate that must be configured to use the same frequency and +/// Naturally, for any 2 radios to communicate that must be configured to use the same frequency and /// modulation scheme. /// /// This Driver provides an object-oriented interface for sending and receiving data messages with Hope-RF @@ -301,7 +301,7 @@ /// also provided. /// /// Tested on MinWirelessLoRa with arduino-1.0.5 -/// on OpenSuSE 13.1. +/// on OpenSuSE 13.1. /// Also tested with Teensy3.1, Modtronix inAir4 and Arduino 1.6.5 on OpenSuSE 13.1 /// /// \par Packet Format @@ -312,7 +312,7 @@ /// - 8 symbol PREAMBLE /// - Explicit header with header CRC (handled internally by the radio) /// - 4 octets HEADER: (TO, FROM, ID, FLAGS) -/// - 0 to 251 octets DATA +/// - 0 to 251 octets DATA /// - CRC (handled internally by the radio) /// /// \par Connecting RFM95/96/97/98 and Semtech SX1276/77/78/79 to Arduino @@ -326,7 +326,7 @@ /// Arduino, otherwise you will also need voltage level shifters between the /// Arduino and the RFM95. CAUTION, you must also ensure you connect an /// antenna. -/// +/// /// \code /// Arduino RFM95/96/97/98 /// GND----------GND (ground in) @@ -363,11 +363,11 @@ /// /// Note that if you are using Modtronix inAir4 or inAir9,or any other module which uses the /// transmitter RFO pins and not the PA_BOOST pins -/// that you must configure the power transmitter power for -1 to 14 dBm and with useRFO true. +/// that you must configure the power transmitter power for -1 to 14 dBm and with useRFO true. /// Failure to do that will result in extremely low transmit powers. /// -/// If you have an Arduino M0 Pro from arduino.org, -/// you should note that you cannot use Pin 2 for the interrupt line +/// If you have an Arduino M0 Pro from arduino.org, +/// you should note that you cannot use Pin 2 for the interrupt line /// (Pin 2 is for the NMI only). The same comments apply to Pin 4 on Arduino Zero from arduino.cc. /// Instead you can use any other pin (we use Pin 3) and initialise RH_RF69 like this: /// \code @@ -377,7 +377,7 @@ /// /// If you have a Rocket Scream Mini Ultra Pro with the RFM95W: /// - Ensure you have Arduino SAMD board support 1.6.5 or later in Arduino IDE 1.6.8 or later. -/// - The radio SS is hardwired to pin D5 and the DIO0 interrupt to pin D2, +/// - The radio SS is hardwired to pin D5 and the DIO0 interrupt to pin D2, /// so you need to initialise the radio like this: /// \code /// RH_RF95 driver(5, 2); @@ -387,7 +387,7 @@ /// \code /// #define Serial SerialUSB /// \endcode -/// - You also need this in setup before radio initialisation +/// - You also need this in setup before radio initialisation /// \code /// // Ensure serial flash is not interfering with radio communication on SPI bus /// pinMode(4, OUTPUT); @@ -403,13 +403,13 @@ /// #include /// RH_RF95 rf95(5, 2); // Rocket Scream Mini Ultra Pro with the RFM95W /// #define Serial SerialUSB -/// -/// void setup() +/// +/// void setup() /// { /// // Ensure serial flash is not interfering with radio communication on SPI bus /// pinMode(4, OUTPUT); /// digitalWrite(4, HIGH); -/// +/// /// Serial.begin(9600); /// while (!Serial) ; // Wait for serial port to be available /// if (!rf95.init()) @@ -424,7 +424,7 @@ /// RH_RF95 rf95(8, 3); /// \endcode /// -/// If you have a talk2 Whisper Node LoRa board with on-board RF95 radio, +/// If you have a talk2 Whisper Node LoRa board with on-board RF95 radio, /// the example rf95_* sketches work without modification. Initialise the radio like /// with the default constructor: /// \code @@ -440,7 +440,7 @@ /// need to set the usual SS pin to be an output to force the Arduino into SPI /// master mode. /// -/// Caution: Power supply requirements of the RFM module may be relevant in some circumstances: +/// Caution: Power supply requirements of the RFM module may be relevant in some circumstances: /// RFM95/96/97/98 modules are capable of pulling 120mA+ at full power, where Arduino's 3.3V line can /// give 50mA. You may need to make provision for alternate power supply for /// the RFM module, especially if you wish to use full transmit power, and/or you have @@ -469,7 +469,7 @@ /// more critical. Therefore, you should be vary sparing with RAM use in /// programs that use the RH_RF95 driver. /// -/// It is often hard to accurately identify when you are hitting RAM limits on Arduino. +/// It is often hard to accurately identify when you are hitting RAM limits on Arduino. /// The symptoms can include: /// - Mysterious crashes and restarts /// - Changes in behaviour when seemingly unrelated changes are made (such as adding print() statements) @@ -489,18 +489,18 @@ /// /// It should be noted that at this data rate, a 12 octet message takes 2 seconds to transmit. /// -/// At 20dBm (100mW) with Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. +/// At 20dBm (100mW) with Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. /// (Default medium range) in the conditions described above. /// - Range over flat ground through heavy trees and vegetation approx 2km. /// /// Caution: the performance of this radio, especially with narrow bandwidths is strongly dependent on the -/// accuracy and stability of the chip clock. HopeRF and Semtech do not appear to -/// recommend bandwidths of less than 62.5 kHz -/// unless you have the optional Temperature Compensated Crystal Oscillator (TCXO) installed and +/// accuracy and stability of the chip clock. HopeRF and Semtech do not appear to +/// recommend bandwidths of less than 62.5 kHz +/// unless you have the optional Temperature Compensated Crystal Oscillator (TCXO) installed and /// enabled on your radio module. See the refernece manual for more data. /// Also https://lowpowerlab.com/forum/rf-range-antennas-rfm69-library/lora-library-experiences-range/15/ /// and http://www.semtech.com/images/datasheet/an120014-xo-guidance-lora-modulation.pdf -/// +/// /// \par Transmitter Power /// /// You can control the transmitter power on the RF transceiver @@ -533,10 +533,10 @@ /// 15 15 /// 17 16 /// 19 18 -/// 20 20 -/// 21 21 -/// 22 22 -/// 23 23 +/// 20 20 +/// 21 21 +/// 22 22 +/// 23 23 /// \endcode /// /// We have also measured the actual power output from a Modtronix inAir4 http://modtronix.com/inair4.html @@ -563,7 +563,7 @@ /// You would not expect to get anywhere near these powers to air with a simple 1/4 wavelength wire antenna. class RH_RF95 : public RHSPIDriver { -public: + public: /// \brief Defines register values for a set of modem configuration registers /// /// Defines register values for a set of modem configuration registers @@ -571,32 +571,30 @@ public: /// ModemConfigChoice suit your need setModemRegisters() writes the /// register values from this structure to the appropriate registers /// to set the desired spreading factor, coding rate and bandwidth - typedef struct - { - uint8_t reg_1d; ///< Value for register RH_RF95_REG_1D_MODEM_CONFIG1 - uint8_t reg_1e; ///< Value for register RH_RF95_REG_1E_MODEM_CONFIG2 - uint8_t reg_26; ///< Value for register RH_RF95_REG_26_MODEM_CONFIG3 + typedef struct { + uint8_t reg_1d; ///< Value for register RH_RF95_REG_1D_MODEM_CONFIG1 + uint8_t reg_1e; ///< Value for register RH_RF95_REG_1E_MODEM_CONFIG2 + uint8_t reg_26; ///< Value for register RH_RF95_REG_26_MODEM_CONFIG3 } ModemConfig; - + /// Choices for setModemConfig() for a selected subset of common /// data rates. If you need another configuration, /// determine the necessary settings and call setModemRegisters() with your - /// desired settings. It might be helpful to use the LoRa calculator mentioned in + /// desired settings. It might be helpful to use the LoRa calculator mentioned in /// http://www.semtech.com/images/datasheet/LoraDesignGuide_STD.pdf /// These are indexes into MODEM_CONFIG_TABLE. We strongly recommend you use these symbolic /// definitions and not their integer equivalents: its possible that new values will be /// introduced in later versions (though we will try to avoid it). /// Caution: if you are using slow packet rates and long packets with RHReliableDatagram or subclasses /// you may need to change the RHReliableDatagram timeout for reliable operations. - /// Caution: for some slow rates nad with ReliableDatagrams youi may need to increase the reply timeout + /// Caution: for some slow rates nad with ReliableDatagrams youi may need to increase the reply timeout /// with manager.setTimeout() to /// deal with the long transmission times. - typedef enum - { - Bw125Cr45Sf128 = 0, ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium range - Bw500Cr45Sf128, ///< Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short range - Bw31_25Cr48Sf512, ///< Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long range - Bw125Cr48Sf4096, ///< Bw = 125 kHz, Cr = 4/8, Sf = 4096chips/symbol, CRC on. Slow+long range + typedef enum { + Bw125Cr45Sf128 = 0, ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium range + Bw500Cr45Sf128, ///< Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short range + Bw31_25Cr48Sf512, ///< Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long range + Bw125Cr48Sf4096, ///< Bw = 125 kHz, Cr = 4/8, Sf = 4096chips/symbol, CRC on. Slow+long range } ModemConfigChoice; /// Constructor. You can have multiple instances, but each instance must have its own @@ -605,28 +603,28 @@ public: /// distinct interrupt lines, one for each instance. /// \param[in] slaveSelectPin the Arduino pin number of the output to use to select the RH_RF22 before /// accessing it. Defaults to the normal SS pin for your Arduino (D10 for Diecimila, Uno etc, D53 for Mega, D10 for Maple) - /// \param[in] interruptPin The interrupt Pin number that is connected to the RFM DIO0 interrupt line. + /// \param[in] interruptPin The interrupt Pin number that is connected to the RFM DIO0 interrupt line. /// Defaults to pin 2, as required by Anarduino MinWirelessLoRa module. /// Caution: You must specify an interrupt capable pin. /// On many Arduino boards, there are limitations as to which pins may be used as interrupts. /// On Leonardo pins 0, 1, 2 or 3. On Mega2560 pins 2, 3, 18, 19, 20, 21. On Due and Teensy, any digital pin. /// On Arduino Zero from arduino.cc, any digital pin other than 4. /// On Arduino M0 Pro from arduino.org, any digital pin other than 2. - /// On other Arduinos pins 2 or 3. + /// On other Arduinos pins 2 or 3. /// See http://arduino.cc/en/Reference/attachInterrupt for more details. /// On Chipkit Uno32, pins 38, 2, 7, 8, 35. /// On other boards, any digital pin may be used. - /// \param[in] spi Pointer to the SPI interface object to use. + /// \param[in] spi Pointer to the SPI interface object to use. /// Defaults to the standard Arduino hardware SPI interface - RH_RF95(uint8_t slaveSelectPin = SS, uint8_t interruptPin = 2, RHGenericSPI& spi = hardware_spi); - + RH_RF95(uint8_t slaveSelectPin = SS, uint8_t interruptPin = 2, RHGenericSPI &spi = hardware_spi); + /// Initialise the Driver transport hardware and software. /// Make sure the Driver is properly configured before calling init(). /// \return true if initialisation succeeded. - virtual bool init(); + virtual bool init(); /// The main CPU is about to enter deep sleep, prepare the RF95 so it will be able to wake properly after we reboot - /// i.e. confirm we are in idle or rx mode, set a rtcram flag with state we need to restore after boot. Later in boot + /// i.e. confirm we are in idle or rx mode, set a rtcram flag with state we need to restore after boot. Later in boot /// we'll need to be careful not to wipe registers and be ready to handle any pending interrupts that occurred while /// the main CPU was powered down. void prepareDeepSleep(); @@ -637,110 +635,87 @@ public: /// \return true on success bool printRegisters(); - /// Sets all the registered required to configure the data modem in the RF95/96/97/98, including the bandwidth, - /// spreading factor etc. You can use this to configure the modem with custom configurations if none of the + /// Sets all the registered required to configure the data modem in the RF95/96/97/98, including the bandwidth, + /// spreading factor etc. You can use this to configure the modem with custom configurations if none of the /// canned configurations in ModemConfigChoice suit you. /// \param[in] config A ModemConfig structure containing values for the modem configuration registers. - void setModemRegisters(const ModemConfig* config); + void setModemRegisters(const ModemConfig *config); - /// Select one of the predefined modem configurations. If you need a modem configuration not provided + /// Select one of the predefined modem configurations. If you need a modem configuration not provided /// here, use setModemRegisters() with your own ModemConfig. /// Caution: the slowest protocols may require a radio module with TCXO temperature controlled oscillator /// for reliable operation. /// \param[in] index The configuration choice. /// \return true if index is a valid choice. - bool setModemConfig(ModemConfigChoice index); + bool setModemConfig(ModemConfigChoice index); /// Tests whether a new message is available - /// from the Driver. + /// from the Driver. /// On most drivers, this will also put the Driver into RHModeRx mode until /// a message is actually received by the transport, when it wil be returned to RHModeIdle. /// This can be called multiple times in a timeout loop /// \return true if a new, complete, error-free uncollected message is available to be retreived by recv() - virtual bool available(); - - /// Turns the receiver on if it not already on. - /// If there is a valid message available, copy it to buf and return true - /// else return false. - /// If a message is copied, *len is set to the length (Caution, 0 length messages are permitted). - /// You should be sure to call this function frequently enough to not miss any messages - /// It is recommended that you call it in your main loop. - /// \param[in] buf Location to copy the received message - /// \param[in,out] len Pointer to available space in buf. Set to the actual number of octets copied. - /// \return true if a valid message was copied to buf - virtual bool recv(uint8_t* buf, uint8_t* len); - - /// Waits until any previous transmit packet is finished being transmitted with waitPacketSent(). - /// Then optionally waits for Channel Activity Detection (CAD) - /// to show the channnel is clear (if the radio supports CAD) by calling waitCAD(). - /// Then loads a message into the transmitter and starts the transmitter. Note that a message length - /// of 0 is permitted. - /// \param[in] data Array of data to be sent - /// \param[in] len Number of bytes of data to send - /// specify the maximum time in ms to wait. If 0 (the default) do not wait for CAD before transmitting. - /// \return true if the message length was valid and it was correctly queued for transmit. Return false - /// if CAD was requested and the CAD timeout timed out before clear channel was detected. - virtual bool send(const uint8_t* data, uint8_t len); + virtual bool available(); /// Sets the length of the preamble - /// in bytes. - /// Caution: this should be set to the same + /// in bytes. + /// Caution: this should be set to the same /// value on all nodes in your network. Default is 8. /// Sets the message preamble length in RH_RF95_REG_??_PREAMBLE_?SB - /// \param[in] bytes Preamble length in bytes. - void setPreambleLength(uint16_t bytes); + /// \param[in] bytes Preamble length in bytes. + void setPreambleLength(uint16_t bytes); - /// Returns the maximum message length + /// Returns the maximum message length /// available in this Driver. /// \return The maximum legal message length virtual uint8_t maxMessageLength(); - /// Sets the transmitter and receiver + /// Sets the transmitter and receiver /// centre frequency. /// \param[in] centre Frequency in MHz. 137.0 to 1020.0. Caution: RFM95/96/97/98 comes in several /// different frequency ranges, and setting a frequency outside that range of your radio will probably not work /// \return true if the selected frquency centre is within range - bool setFrequency(float centre); + bool setFrequency(float centre); - /// If current mode is Rx or Tx changes it to Idle. If the transmitter or receiver is running, + /// If current mode is Rx or Tx changes it to Idle. If the transmitter or receiver is running, /// disables them. - void setModeIdle(); + void setModeIdle(); - /// If current mode is Tx or Idle, changes it to Rx. + /// If current mode is Tx or Idle, changes it to Rx. /// Starts the receiver in the RF95/96/97/98. - void setModeRx(); + void setModeRx(); /// If current mode is Rx or Idle, changes it to Rx. F /// Starts the transmitter in the RF95/96/97/98. - void setModeTx(); + void setModeTx(); /// Sets the transmitter power output level, and configures the transmitter pin. /// Be a good neighbour and set the lowest power level you need. - /// Some SX1276/77/78/79 and compatible modules (such as RFM95/96/97/98) + /// Some SX1276/77/78/79 and compatible modules (such as RFM95/96/97/98) /// use the PA_BOOST transmitter pin for high power output (and optionally the PA_DAC) - /// while some (such as the Modtronix inAir4 and inAir9) + /// while some (such as the Modtronix inAir4 and inAir9) /// use the RFO transmitter pin for lower power but higher efficiency. /// You must set the appropriate power level and useRFO argument for your module. /// Check with your module manufacturer which transmtter pin is used on your module - /// to ensure you are setting useRFO correctly. - /// Failure to do so will result in very low + /// to ensure you are setting useRFO correctly. + /// Failure to do so will result in very low /// transmitter power output. /// Caution: legal power limits may apply in certain countries. /// After init(), the power will be set to 13dBm, with useRFO false (ie PA_BOOST enabled). - /// \param[in] power Transmitter power level in dBm. For RFM95/96/97/98 LORA with useRFO false, + /// \param[in] power Transmitter power level in dBm. For RFM95/96/97/98 LORA with useRFO false, /// valid values are from +5 to +23. - /// For Modtronix inAir4 and inAir9 with useRFO true (ie RFO pins in use), + /// For Modtronix inAir4 and inAir9 with useRFO true (ie RFO pins in use), /// valid values are from -1 to 14. /// \param[in] useRFO If true, enables the use of the RFO transmitter pins instead of /// the PA_BOOST pin (false). Choose the correct setting for your module. - void setTxPower(int8_t power, bool useRFO = false); + void setTxPower(int8_t power, bool useRFO = false); /// Sets the radio into low-power sleep mode. - /// If successful, the transport will stay in sleep mode until woken by + /// If successful, the transport will stay in sleep mode until woken by /// changing mode it idle, transmit or receive (eg by calling send(), recv(), available() etc) /// Caution: there is a time penalty as the radio takes a finite time to wake from sleep mode. /// \return true if sleep mode was successfully entered. - virtual bool sleep(); + virtual bool sleep(); // Bent G Christensen (bentor@gmail.com), 08/15/2016 /// Use the radio's Channel Activity Detect (CAD) function to detect channel activity. @@ -748,11 +723,11 @@ public: /// To be used in a listen-before-talk mechanism (Collision Avoidance) /// with a reasonable time backoff algorithm. /// This is called automatically by waitCAD(). - /// \return true if channel is in use. - virtual bool isChannelActive(); + /// \return true if channel is in use. + virtual bool isChannelActive(); /// Enable TCXO mode - /// Call this immediately after init(), to force your radio to use an external + /// Call this immediately after init(), to force your radio to use an external /// frequency source, such as a Temperature Compensated Crystal Oscillator (TCXO), if available. /// See the comments in the main documentation about the sensitivity of this radio to /// clock frequency especially when using narrow bandwidths. @@ -764,12 +739,12 @@ public: /// Returns the last measured frequency error. /// The LoRa receiver estimates the frequency offset between the receiver centre frequency - /// and that of the received LoRa signal. This function returns the estimates offset (in Hz) - /// of the last received message. Caution: this measurement is not absolute, but is measured - /// relative to the local receiver's oscillator. + /// and that of the received LoRa signal. This function returns the estimates offset (in Hz) + /// of the last received message. Caution: this measurement is not absolute, but is measured + /// relative to the local receiver's oscillator. /// Apparent errors may be due to the transmitter, the receiver or both. - /// \return The estimated centre frequency offset in Hz of the last received message. - /// If the modem bandwidth selector in + /// \return The estimated centre frequency offset in Hz of the last received message. + /// If the modem bandwidth selector in /// register RH_RF95_REG_1D_MODEM_CONFIG1 is invalid, returns 0. int frequencyError(); @@ -787,8 +762,8 @@ public: /// /// \param[in] uint8_t sf (spreading factor 6..12) /// \return nothing - void setSpreadingFactor(uint8_t sf); - + void setSpreadingFactor(uint8_t sf); + /// brian.n.norman@gmail.com 9th Nov 2018 /// Sets the radio signal bandwidth /// sbw ranges and resultant settings are as follows:- @@ -806,32 +781,32 @@ public: /// NOTE caution Earlier - Semtech do not recommend BW below 62.5 although, in testing /// I managed 31.25 with two devices in close proximity. /// \param[in] sbw long, signal bandwidth e.g. 125000 - void setSignalBandwidth(long sbw); - + void setSignalBandwidth(long sbw); + /// brian.n.norman@gmail.com 9th Nov 2018 /// Sets the coding rate to 4/5, 4/6, 4/7 or 4/8. /// Valid denominator values are 5, 6, 7 or 8. A value of 5 sets the coding rate to 4/5 etc. /// Values below 5 are clamped at 5 /// values above 8 are clamped at 8 /// \param[in] denominator uint8_t range 5..8 - void setCodingRate4(uint8_t denominator); - + void setCodingRate4(uint8_t denominator); + /// brian.n.norman@gmail.com 9th Nov 2018 /// sets the low data rate flag if symbol time exceeds 16ms /// ref: https://www.thethingsnetwork.org/forum/t/a-point-to-note-lora-low-data-rate-optimisation-flag/12007 /// called by setBandwidth() and setSpreadingfactor() since these affect the symbol time. - void setLowDatarate(); - + void setLowDatarate(); + /// brian.n.norman@gmail.com 9th Nov 2018 /// allows the payload CRC bit to be turned on/off. Normally this should be left on /// so that packets with a bad CRC are rejected /// \patam[in] on bool, true turns the payload CRC on, false turns it off void setPayloadCRC(bool on); - + /// Return true if we are currently receiving a packet bool isReceiving(); - -protected: + + protected: /// This is a low level function to handle the interrupts for one instance of RH_RF95. /// Called automatically by isr*() /// Should not need to be called by user code. @@ -843,44 +818,56 @@ protected: /// Clear our local receive buffer void clearRxBuf(); -private: + /// Waits until any previous transmit packet is finished being transmitted with waitPacketSent(). + /// Then optionally waits for Channel Activity Detection (CAD) + /// to show the channnel is clear (if the radio supports CAD) by calling waitCAD(). + /// Then loads a message into the transmitter and starts the transmitter. Note that a message length + /// of 0 is permitted. + /// \param[in] data Array of data to be sent + /// \param[in] len Number of bytes of data to send + /// specify the maximum time in ms to wait. If 0 (the default) do not wait for CAD before transmitting. + /// \return true if the message length was valid and it was correctly queued for transmit. Return false + /// if CAD was requested and the CAD timeout timed out before clear channel was detected. + virtual bool send(const uint8_t *data, uint8_t len); + + private: /// Low level interrupt service routine for device connected to interrupt 0 - static void isr0(); + static void isr0(); /// Low level interrupt service routine for device connected to interrupt 1 - static void isr1(); + static void isr1(); /// Low level interrupt service routine for device connected to interrupt 1 - static void isr2(); + static void isr2(); /// Array of instances connected to interrupts 0 and 1 - static RH_RF95* _deviceForInterrupt[]; + static RH_RF95 *_deviceForInterrupt[]; /// Index of next interrupt number to use in _deviceForInterrupt - static uint8_t _interruptCount; + static uint8_t _interruptCount; /// The configured interrupt pin connected to this instance - uint8_t _interruptPin; + uint8_t _interruptPin; /// The index into _deviceForInterrupt[] for this device (if an interrupt is already allocated) /// else 0xff - uint8_t _myInterruptIndex; + uint8_t _myInterruptIndex; // True if we are using the HF port (779.0 MHz and above) - bool _usingHFport; + bool _usingHFport; // Last measured SNR, dB - int8_t _lastSNR; + int8_t _lastSNR; -protected: + protected: /// Number of octets in the buffer - volatile uint8_t _bufLen; - + volatile uint8_t _bufLen; + /// The receiver/transmitter buffer - uint8_t _buf[RH_RF95_MAX_PAYLOAD_LEN]; + uint8_t _buf[RH_RF95_MAX_PAYLOAD_LEN]; /// True when there is a valid message in the buffer - volatile bool _rxBufValid; + volatile bool _rxBufValid; }; /// @example rf95_client.pde @@ -891,4 +878,3 @@ protected: /// @example rf95_reliable_datagram_server.pde #endif -