diff --git a/src/mesh/MeshRadio.cpp b/src/mesh/MeshRadio.cpp index 5ff3d46be..53c052be5 100644 --- a/src/mesh/MeshRadio.cpp +++ b/src/mesh/MeshRadio.cpp @@ -55,13 +55,13 @@ bool MeshRadio::init() #endif // we now expect interfaces to operate in promiscous mode - // radioIf.setThisAddress(nodeDB.getNodeNum()); // Note: we must do this here, because the nodenum isn't inited at constructor time. + // radioIf.setThisAddress(nodeDB.getNodeNum()); // Note: we must do this here, because the nodenum isn't inited at constructor + // time. applySettings(); if (!radioIf.init()) { DEBUG_MSG("LoRa radio init failed\n"); - DEBUG_MSG("Uncomment '#define SERIAL_DEBUG' in RH_RF95.cpp for detailed debug info\n"); return false; } @@ -93,7 +93,7 @@ void MeshRadio::applySettings() { // Set up default configuration // No Sync Words in LORA mode. - radioIf.modemConfig = (RH_RF95::ModemConfigChoice)channelSettings.modem_config; + radioIf.modemConfig = (ModemConfigChoice)channelSettings.modem_config; // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM int channel_num = hash(channelSettings.name) % NUM_CHANNELS; diff --git a/src/mesh/MeshRadio.h b/src/mesh/MeshRadio.h index 1580cea47..85c3e77fd 100644 --- a/src/mesh/MeshRadio.h +++ b/src/mesh/MeshRadio.h @@ -1,10 +1,10 @@ #pragma once -#include "CustomRF95.h" #include "MemoryPool.h" #include "MeshTypes.h" #include "Observer.h" #include "PointerQueue.h" +#include "RadioInterface.h" #include "configuration.h" #include "mesh.pb.h" diff --git a/src/rf95/CustomRF95.cpp b/src/rf95/CustomRF95.cpp deleted file mode 100644 index b67404dfb..000000000 --- a/src/rf95/CustomRF95.cpp +++ /dev/null @@ -1,221 +0,0 @@ -#include "CustomRF95.h" -#include "NodeDB.h" // FIXME, this class should not need to touch nodedb -#include "assert.h" -#include "configuration.h" -#include -#include - -#ifdef RF95_IRQ_GPIO - -CustomRF95::CustomRF95() : RH_RF95(NSS_GPIO, RF95_IRQ_GPIO) {} - -bool CustomRF95::canSleep() -{ - // We allow initializing mode, because sometimes while testing we don't ever call init() to turn on the hardware - bool isRx = isReceiving(); - - bool res = (_mode == RHModeInitialising || _mode == RHModeIdle || _mode == RHModeRx) && !isRx && txQueue.isEmpty(); - if (!res) // only print debug messages if we are vetoing sleep - DEBUG_MSG("radio wait to sleep, mode=%d, isRx=%d, txEmpty=%d, txGood=%d\n", _mode, isRx, txQueue.isEmpty(), _txGood); - - return res; -} - -bool CustomRF95::sleep() -{ - // we no longer care about interrupts from this device - prepareDeepSleep(); - - // FIXME - leave the device state in rx mode instead - return RH_RF95::sleep(); -} - -bool CustomRF95::init() -{ - bool ok = RH_RF95::init(); - - // this->setPromiscuous(true); // Make the old RH stack work like the new one, make make CPU check dest addr - if (ok) - reconfigure(); // Finish our device setup - - return ok; -} - -/// Send a packet (possibly by enquing in a private fifo). This routine will -/// later free() the packet to pool. This routine is not allowed to stall because it is called from -/// bluetooth comms code. If the txmit queue is empty it might return an error -ErrorCode CustomRF95::send(MeshPacket *p) -{ - // We wait _if_ we are partially though receiving a packet (rather than just merely waiting for one). - // To do otherwise would be doubly bad because not only would we drop the packet that was on the way in, - // we almost certainly guarantee no one outside will like the packet we are sending. - if (_mode == RHModeIdle || (_mode == RHModeRx && !isReceiving())) { - // if the radio is idle, we can send right away - DEBUG_MSG("immediate send on mesh fr=0x%x,to=0x%x,id=%d\n (txGood=%d,rxGood=%d,rxBad=%d)\n", p->from, p->to, p->id, - txGood(), rxGood(), rxBad()); - - if (!waitCAD()) - return false; // Check channel activity - - startSend(p); - return ERRNO_OK; - } else { - DEBUG_MSG("enqueuing packet for send from=0x%x, to=0x%x\n", p->from, p->to); - ErrorCode res = txQueue.enqueue(p, 0) ? ERRNO_OK : ERRNO_UNKNOWN; - - if (res != ERRNO_OK) // we weren't able to queue it, so we must drop it to prevent leaks - packetPool.release(p); - - return res; - } -} - -// After doing standard behavior, check to see if a new packet arrived or one was sent and start a new send or receive as -// necessary -void CustomRF95::handleInterrupt() -{ - setThisAddress( - nodeDB - .getNodeNum()); // temp hack to make sure we are looking for the right address. This class is going away soon anyways - - RH_RF95::handleInterrupt(); - - if (_mode == RHModeIdle) // We are now done sending or receiving - { - if (sendingPacket) // Were we sending? - { - // We are done sending that packet, release it - packetPool.release(sendingPacket); - sendingPacket = NULL; - // DEBUG_MSG("Done with send\n"); - } - - // If we just finished receiving a packet, forward it into a queue - if (_rxBufValid) { - // We received a packet - - // Skip the 4 headers that are at the beginning of the rxBuf - size_t payloadLen = _bufLen - RH_RF95_HEADER_LEN; - uint8_t *payload = _buf + RH_RF95_HEADER_LEN; - - // FIXME - throws exception if called in ISR context: frequencyError() - probably the floating point math - int32_t snr = lastSNR(); - // DEBUG_MSG("Received packet from mesh src=0x%x,dest=0x%x,id=%d,len=%d rxGood=%d,rxBad=%d,freqErr=%d,snr=%d\n", - // srcaddr, destaddr, id, rxlen, rf95.rxGood(), rf95.rxBad(), freqerr, snr); - - MeshPacket *mp = packetPool.allocZeroed(); - - SubPacket *p = &mp->payload; - - mp->from = _rxHeaderFrom; - mp->to = _rxHeaderTo; - mp->id = _rxHeaderId; - mp->rx_snr = snr; - - //_rxHeaderId = _buf[2]; - //_rxHeaderFlags = _buf[3]; - - if (!pb_decode_from_bytes(payload, payloadLen, SubPacket_fields, p)) { - packetPool.release(mp); - } else { - // parsing was successful, queue for our recipient - mp->has_payload = true; - - deliverToReceiver(mp); - } - - clearRxBuf(); // This message accepted and cleared - } - - handleIdleISR(); - } -} - -/** The ISR doesn't have any good work to do, give a new assignment. - * - * Return true if a higher pri task has woken - */ -void CustomRF95::handleIdleISR() -{ - // First send any outgoing packets we have ready - MeshPacket *txp = txQueue.dequeuePtr(0); - if (txp) - startSend(txp); - else { - // Nothing to send, let's switch back to receive mode - RH_RF95::setModeRx(); - } -} - -/// This routine might be called either from user space or ISR -void CustomRF95::startSend(MeshPacket *txp) -{ - size_t numbytes = beginSending(txp); - - setHeaderTo(txp->to); - setHeaderId(txp->id); - - // if the sender nodenum is zero, that means uninitialized - setHeaderFrom(txp->from); // We must do this before each send, because we might have just changed our nodenum - - assert(numbytes <= 251); // Make sure we don't overflow the tiny max packet size - - // uint32_t start = millis(); // FIXME, store this in the class - - // This legacy implementation doesn't use our inserted packet header - int res = RH_RF95::send(radiobuf + sizeof(PacketHeader), numbytes - sizeof(PacketHeader)); - assert(res); -} - -#define TX_WATCHDOG_TIMEOUT 30 * 1000 - -#include "error.h" - -void CustomRF95::loop() -{ - RH_RF95::loop(); - - // It should never take us more than 30 secs to send a packet, if it does, we have a bug, FIXME, move most of this - // into CustomRF95 - uint32_t now = millis(); - if (lastTxStart != 0 && (now - lastTxStart) > TX_WATCHDOG_TIMEOUT && RH_RF95::mode() == RHGenericDriver::RHModeTx) { - DEBUG_MSG("ERROR! Bug! Tx packet took too long to send, forcing radio into rx mode\n"); - RH_RF95::setModeRx(); - if (sendingPacket) { // There was probably a packet we were trying to send, free it - packetPool.release(sendingPacket); - sendingPacket = NULL; - } - recordCriticalError(ErrTxWatchdog); - lastTxStart = 0; // Stop checking for now, because we just warned the developer - } -} - -bool CustomRF95::reconfigure() -{ - setModeIdle(); // Need to be idle before doing init - - // Set up default configuration - // No Sync Words in LORA mode. - setModemConfig(modemConfig); // Radio default - // setModemConfig(Bw125Cr48Sf4096); // slow and reliable? - // rf95.setPreambleLength(8); // Default is 8 - - if (!setFrequency(freq)) { - DEBUG_MSG("setFrequency failed\n"); - assert(0); // fixme panic - } - - // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on - - // The default transmitter power is 13dBm, using PA_BOOST. - // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then - // you can set transmitter powers from 5 to 23 dBm: - // FIXME - can we do this? It seems to be in the Heltec board. - setTxPower(power, false); - - // Done with init tell radio to start receiving - setModeRx(); - - return true; -} -#endif \ No newline at end of file diff --git a/src/rf95/CustomRF95.h b/src/rf95/CustomRF95.h deleted file mode 100644 index e40c1f020..000000000 --- a/src/rf95/CustomRF95.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include "RadioInterface.h" -#include "mesh.pb.h" -#include - -#define MAX_TX_QUEUE 16 // max number of packets which can be waiting for transmission - -/** - * A version of the RF95 driver which is smart enough to manage packets via queues (no polling or blocking in user threads!) - */ -class CustomRF95 : public RH_RF95, public RadioInterface -{ - friend class MeshRadio; // for debugging we let that class touch pool - - public: - /** pool is the pool we will alloc our rx packets from - * rxDest is where we will send any rx packets, it becomes receivers responsibility to return packet to the pool - */ - CustomRF95(); - - /** - * Return true if we think the board can go to sleep (i.e. our tx queue is empty, we are not sending or receiving) - * - * This method must be used before putting the CPU into deep or light sleep. - */ - bool canSleep(); - - /// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep. - virtual bool sleep(); - - /// Send a packet (possibly by enquing in a private fifo). This routine will - /// later free() the packet to pool. This routine is not allowed to stall because it is called from - /// bluetooth comms code. If the txmit queue is empty it might return an error - ErrorCode send(MeshPacket *p); - - bool init(); - - bool reconfigure(); - - void loop(); // Idle processing - - protected: - // After doing standard behavior, check to see if a new packet arrived or one was sent and start a new send or receive as - // necessary - virtual void handleInterrupt(); - - private: - /// Send a new packet - this low level call can be called from either ISR or userspace - void startSend(MeshPacket *txp); - - /// Return true if a higher pri task has woken - void handleIdleISR(); -}; \ No newline at end of file diff --git a/src/rf95/RHGenericDriver.cpp b/src/rf95/RHGenericDriver.cpp deleted file mode 100644 index 0dbb995fb..000000000 --- a/src/rf95/RHGenericDriver.cpp +++ /dev/null @@ -1,207 +0,0 @@ -// RHGenericDriver.cpp -// -// Copyright (C) 2014 Mike McCauley -// $Id: RHGenericDriver.cpp,v 1.23 2018/02/11 23:57:18 mikem Exp $ - -#include - -RHGenericDriver::RHGenericDriver() - : _mode(RHModeInitialising), _thisAddress(RH_BROADCAST_ADDRESS), _txHeaderTo(RH_BROADCAST_ADDRESS), - _txHeaderFrom(RH_BROADCAST_ADDRESS), _txHeaderId(0), _txHeaderFlags(0), _rxBad(0), _rxGood(0), _txGood(0), _cad_timeout(0) -{ -} - -bool RHGenericDriver::init() -{ - return true; -} - -// Blocks until a valid message is received -void RHGenericDriver::waitAvailable() -{ - while (!available()) - YIELD; -} - -// Blocks until a valid message is received or timeout expires -// Return true if there is a message available -// Works correctly even on millis() rollover -bool RHGenericDriver::waitAvailableTimeout(uint16_t timeout) -{ - unsigned long starttime = millis(); - while ((millis() - starttime) < timeout) { - if (available()) { - return true; - } - YIELD; - } - return false; -} - -bool RHGenericDriver::waitPacketSent() -{ - while (_mode == RHModeTx) - YIELD; // Wait for any previous transmit to finish - return true; -} - -bool RHGenericDriver::waitPacketSent(uint16_t timeout) -{ - unsigned long starttime = millis(); - while ((millis() - starttime) < timeout) { - if (_mode != RHModeTx) // Any previous transmit finished? - return true; - YIELD; - } - return false; -} - -// Wait until no channel activity detected or timeout -bool RHGenericDriver::waitCAD() -{ - if (!_cad_timeout) - return true; - - // Wait for any channel activity to finish or timeout - // Sophisticated DCF function... - // DCF : BackoffTime = random() x aSlotTime - // 100 - 1000 ms - // 10 sec timeout - unsigned long t = millis(); - while (isChannelActive()) { - if (millis() - t > _cad_timeout) - return false; -#if (RH_PLATFORM == RH_PLATFORM_STM32) // stdlib on STMF103 gets confused if random is redefined - delay(_random(1, 10) * 100); -#else - delay(random(1, 10) * 100); // Should these values be configurable? Macros? -#endif - } - - return true; -} - -// subclasses are expected to override if CAD is available for that radio -bool RHGenericDriver::isChannelActive() -{ - return false; -} - -void RHGenericDriver::setPromiscuous(bool promiscuous) -{ - _promiscuous = promiscuous; -} - -void RHGenericDriver::setThisAddress(uint8_t address) -{ - _thisAddress = address; -} - -void RHGenericDriver::setHeaderTo(uint8_t to) -{ - _txHeaderTo = to; -} - -void RHGenericDriver::setHeaderFrom(uint8_t from) -{ - _txHeaderFrom = from; -} - -void RHGenericDriver::setHeaderId(uint8_t id) -{ - _txHeaderId = id; -} - -void RHGenericDriver::setHeaderFlags(uint8_t set, uint8_t clear) -{ - _txHeaderFlags &= ~clear; - _txHeaderFlags |= set; -} - -uint8_t RHGenericDriver::headerTo() -{ - return _rxHeaderTo; -} - -uint8_t RHGenericDriver::headerFrom() -{ - return _rxHeaderFrom; -} - -uint8_t RHGenericDriver::headerId() -{ - return _rxHeaderId; -} - -uint8_t RHGenericDriver::headerFlags() -{ - return _rxHeaderFlags; -} - -int16_t RHGenericDriver::lastRssi() -{ - return _lastRssi; -} - -RHGenericDriver::RHMode RHGenericDriver::mode() -{ - return _mode; -} - -void RHGenericDriver::setMode(RHMode mode) -{ - _mode = mode; -} - -bool RHGenericDriver::sleep() -{ - return false; -} - -// Diagnostic help -void RHGenericDriver::printBuffer(const char *prompt, const uint8_t *buf, uint8_t len) -{ -#ifdef RH_HAVE_SERIAL - Serial.println(prompt); - uint8_t i; - for (i = 0; i < len; i++) { - if (i % 16 == 15) - Serial.println(buf[i], HEX); - else { - Serial.print(buf[i], HEX); - Serial.print(' '); - } - } - Serial.println(""); -#endif -} - -uint16_t RHGenericDriver::rxBad() -{ - return _rxBad; -} - -uint16_t RHGenericDriver::rxGood() -{ - return _rxGood; -} - -uint16_t RHGenericDriver::txGood() -{ - return _txGood; -} - -void RHGenericDriver::setCADTimeout(unsigned long cad_timeout) -{ - _cad_timeout = cad_timeout; -} - -#if (RH_PLATFORM == RH_PLATFORM_ATTINY) -// Tinycore does not have __cxa_pure_virtual, so without this we -// get linking complaints from the default code generated for pure virtual functions -extern "C" void __cxa_pure_virtual() -{ - while (1) - ; -} -#endif diff --git a/src/rf95/RHGenericDriver.h b/src/rf95/RHGenericDriver.h deleted file mode 100644 index d06c9e4c0..000000000 --- a/src/rf95/RHGenericDriver.h +++ /dev/null @@ -1,280 +0,0 @@ -// RHGenericDriver.h -// Author: Mike McCauley (mikem@airspayce.com) -// Copyright (C) 2014 Mike McCauley -// $Id: RHGenericDriver.h,v 1.23 2018/09/23 23:54:01 mikem Exp $ - -#ifndef RHGenericDriver_h -#define RHGenericDriver_h - -#include - -// 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 - -// Default timeout for waitCAD() in ms -#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 -/// 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. -/// -/// Subclasses are expected to implement a half-duplex, unreliable, error checked, unaddressed packet transport. -/// They are expected to carry a message payload with an appropriate maximum length for the transport hardware -/// and to also carry unaltered 4 message headers: TO, FROM, ID, FLAGS -/// -/// \par Headers -/// -/// Each message sent and received by a RadioHead driver includes 4 headers: -/// -TO The node address that the message is being sent to (broadcast RH_BROADCAST_ADDRESS (255) is permitted) -/// -FROM The node address of the sending node -/// -ID A message ID, distinct (over short time scales) for each message sent by a particilar node -/// -FLAGS A bitmask of flags. The most significant 4 bits are reserved for use by RadioHead. The least -/// significant 4 bits are reserved for applications. -class RHGenericDriver -{ - public: - /// \brief Defines different operating modes for the transport hardware - /// - /// 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) - } RHMode; - - /// Constructor - RHGenericDriver(); - - /// 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(); - - /// Tests whether a new message is available - /// 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. - /// 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() = 0; - - /// 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 - /// message is available. - virtual void waitAvailable(); - - /// Blocks until the transmitter - /// is no longer transmitting. - 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); - - /// 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); - - // Bent G Christensen (bentor@gmail.com), 08/15/2016 - /// Channel Activity Detection (CAD). - /// Blocks until channel activity is finished or CAD timeout occurs. - /// Uses the radio's CAD function (if supported) to detect channel activity. - /// Implements random delays of 100 to 1000ms while activity is detected and until timeout. - /// 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) - /// 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(); - - /// 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. - /// CAD detection depends on support for isChannelActive() by your particular radio. - void setCADTimeout(unsigned long cad_timeout); - - /// 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 - /// 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(); - - /// 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 - /// (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, - /// 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); - - /// 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); - - /// 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); - - /// 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 - /// 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); - - /// 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); - - /// Returns the TO header of the last received message - /// \return The TO header - virtual uint8_t headerTo(); - - /// Returns the FROM header of the last received message - /// \return The FROM header - virtual uint8_t headerFrom(); - - /// Returns the ID header of the last received message - /// \return The ID header - virtual uint8_t headerId(); - - /// Returns the FLAGS header of the last received message - /// \return The FLAGS header - 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(); - - /// Returns the operating mode of the library. - /// \return the current mode, one of RF69_MODE_* - virtual RHMode mode(); - - /// Sets the operating mode of the transport. - 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 - /// 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(); - - /// 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); - - /// 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(); - - /// Returns the count of the number of - /// good received packets - /// \return The number of good packets received. - virtual uint16_t rxGood(); - - /// 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: - /// The current transport operating mode - volatile RHMode _mode; - - /// This node id - uint8_t _thisAddress; - - /// Whether the transport is in promiscuous mode - bool _promiscuous; - - /// TO header in the last received mesasge - volatile uint8_t _rxHeaderTo; - - /// FROM header in the last received mesasge - volatile uint8_t _rxHeaderFrom; - - /// ID header in the last received mesasge - volatile uint8_t _rxHeaderId; - - /// FLAGS header in the last received mesasge - volatile uint8_t _rxHeaderFlags; - - /// TO header to send in all messages - uint8_t _txHeaderTo; - - /// FROM header to send in all messages - uint8_t _txHeaderFrom; - - /// ID header to send in all messages - uint8_t _txHeaderId; - - /// FLAGS header to send in all messages - uint8_t _txHeaderFlags; - - /// The value of the last received RSSI value, in some transport specific units - volatile int16_t _lastRssi; - - /// Count of the number of bad messages (eg bad checksum etc) received - volatile uint16_t _rxBad; - - /// Count of the number of successfully transmitted messaged - volatile uint16_t _rxGood; - - /// Count of the number of bad messages (correct checksum etc) received - volatile uint16_t _txGood; - - /// Channel activity detected - volatile bool _cad; - - /// Channel activity timeout in ms - unsigned int _cad_timeout; - - private: -}; - -#endif diff --git a/src/rf95/RHGenericSPI.cpp b/src/rf95/RHGenericSPI.cpp deleted file mode 100644 index ec43cd403..000000000 --- a/src/rf95/RHGenericSPI.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// RHGenericSPI.cpp -// Author: Mike McCauley (mikem@airspayce.com) -// Copyright (C) 2011 Mike McCauley -// Contributed by Joanna Rutkowska -// $Id: RHGenericSPI.cpp,v 1.2 2014/04/12 05:26:05 mikem Exp $ - -#include - -RHGenericSPI::RHGenericSPI(Frequency frequency, BitOrder bitOrder, DataMode dataMode) - : - _frequency(frequency), - _bitOrder(bitOrder), - _dataMode(dataMode) -{ -} - -void RHGenericSPI::setBitOrder(BitOrder bitOrder) -{ - _bitOrder = bitOrder; -} - -void RHGenericSPI::setDataMode(DataMode dataMode) -{ - _dataMode = dataMode; -} - -void RHGenericSPI::setFrequency(Frequency frequency) -{ - _frequency = frequency; -} - diff --git a/src/rf95/RHGenericSPI.h b/src/rf95/RHGenericSPI.h deleted file mode 100644 index 4b961b310..000000000 --- a/src/rf95/RHGenericSPI.h +++ /dev/null @@ -1,183 +0,0 @@ -// RHGenericSPI.h -// Author: Mike McCauley (mikem@airspayce.com) -// Copyright (C) 2011 Mike McCauley -// Contributed by Joanna Rutkowska -// $Id: RHGenericSPI.h,v 1.9 2020/01/05 07:02:23 mikem Exp mikem $ - -#ifndef RHGenericSPI_h -#define RHGenericSPI_h - -#include - -///////////////////////////////////////////////////////////////////// -/// \class RHGenericSPI RHGenericSPI.h -/// \brief Base class for SPI interfaces -/// -/// This generic abstract class is used to encapsulate hardware or software SPI interfaces for -/// a variety of platforms. -/// The intention is so that driver classes can be configured to use hardware or software SPI -/// without changing the main code. -/// -/// You must provide a subclass of this class to driver constructors that require SPI. -/// A concrete subclass that encapsualates the standard Arduino hardware SPI and a bit-banged -/// software implementation is included. -/// -/// Do not directly use this class: it must be subclassed and the following abstract functions at least -/// must be implmented: -/// - begin() -/// - end() -/// - transfer() -class RHGenericSPI -{ -public: - - /// \brief Defines constants for different SPI modes - /// - /// Defines constants for different SPI modes - /// that can be passed to the constructor or setMode() - /// We need to define these in a device and platform independent way, because the - /// SPI implementation is different on each platform. - typedef enum - { - DataMode0 = 0, ///< SPI Mode 0: CPOL = 0, CPHA = 0 - DataMode1, ///< SPI Mode 1: CPOL = 0, CPHA = 1 - DataMode2, ///< SPI Mode 2: CPOL = 1, CPHA = 0 - DataMode3, ///< SPI Mode 3: CPOL = 1, CPHA = 1 - } DataMode; - - /// \brief Defines constants for different SPI bus frequencies - /// - /// Defines constants for different SPI bus frequencies - /// that can be passed to setFrequency(). - /// The frequency you get may not be exactly the one according to the name. - /// We need to define these in a device and platform independent way, because the - /// SPI implementation is different on each platform. - typedef enum - { - Frequency1MHz = 0, ///< SPI bus frequency close to 1MHz - Frequency2MHz, ///< SPI bus frequency close to 2MHz - Frequency4MHz, ///< SPI bus frequency close to 4MHz - Frequency8MHz, ///< SPI bus frequency close to 8MHz - Frequency16MHz ///< SPI bus frequency close to 16MHz - } Frequency; - - /// \brief Defines constants for different SPI endianness - /// - /// Defines constants for different SPI endianness - /// that can be passed to setBitOrder() - /// We need to define these in a device and platform independent way, because the - /// SPI implementation is different on each platform. - typedef enum - { - BitOrderMSBFirst = 0, ///< SPI MSB first - BitOrderLSBFirst, ///< SPI LSB first - } BitOrder; - - /// Constructor - /// Creates an instance of an abstract SPI interface. - /// Do not use this contructor directly: you must instead use on of the concrete subclasses provided - /// such as RHHardwareSPI or RHSoftwareSPI - /// \param[in] frequency One of RHGenericSPI::Frequency to select the SPI bus frequency. The frequency - /// is mapped to the closest available bus frequency on the platform. - /// \param[in] bitOrder Select the SPI bus bit order, one of RHGenericSPI::BitOrderMSBFirst or - /// RHGenericSPI::BitOrderLSBFirst. - /// \param[in] dataMode Selects the SPI bus data mode. One of RHGenericSPI::DataMode - RHGenericSPI(Frequency frequency = Frequency1MHz, BitOrder bitOrder = BitOrderMSBFirst, DataMode dataMode = DataMode0); - - /// Transfer a single octet to and from the SPI interface - /// \param[in] data The octet to send - /// \return The octet read from SPI while the data octet was sent - virtual uint8_t transfer(uint8_t data) = 0; - -#if (RH_PLATFORM == RH_PLATFORM_MONGOOSE_OS) - /// Transfer up to 2 bytes on the SPI interface - /// \param[in] byte0 The first byte to be sent on the SPI interface - /// \param[in] byte1 The second byte to be sent on the SPI interface - /// \return The second byte clocked in as the second byte is sent. - virtual uint8_t transfer2B(uint8_t byte0, uint8_t byte1) = 0; - - /// Read a number of bytes on the SPI interface from an NRF device - /// \param[in] reg The NRF device register to read - /// \param[out] dest The buffer to hold the bytes read - /// \param[in] len The number of bytes to read - /// \return The NRF status byte - virtual uint8_t spiBurstRead(uint8_t reg, uint8_t* dest, uint8_t len) = 0; - - /// Wrte a number of bytes on the SPI interface to an NRF device - /// \param[in] reg The NRF device register to read - /// \param[out] src The buffer to hold the bytes write - /// \param[in] len The number of bytes to write - /// \return The NRF status byte - virtual uint8_t spiBurstWrite(uint8_t reg, const uint8_t* src, uint8_t len) = 0; - -#endif - - /// SPI Configuration methods - /// Enable SPI interrupts (if supported) - /// This can be used in an SPI slave to indicate when an SPI message has been received - virtual void attachInterrupt() {}; - - /// Disable SPI interrupts (if supported) - /// This can be used to diable the SPI interrupt in slaves where that is supported. - virtual void detachInterrupt() {}; - - /// Initialise the SPI library. - /// Call this after configuring and before using the SPI library - virtual void begin() = 0; - - /// Disables the SPI bus (leaving pin modes unchanged). - /// Call this after you have finished using the SPI interface - virtual void end() = 0; - - /// Sets the bit order the SPI interface will use - /// Sets the order of the bits shifted out of and into the SPI bus, either - /// LSBFIRST (least-significant bit first) or MSBFIRST (most-significant bit first). - /// \param[in] bitOrder Bit order to be used: one of RHGenericSPI::BitOrder - virtual void setBitOrder(BitOrder bitOrder); - - /// Sets the SPI data mode: that is, clock polarity and phase. - /// See the Wikipedia article on SPI for details. - /// \param[in] dataMode The mode to use: one of RHGenericSPI::DataMode - virtual void setDataMode(DataMode dataMode); - - /// Sets the SPI clock divider relative to the system clock. - /// On AVR based boards, the dividers available are 2, 4, 8, 16, 32, 64 or 128. - /// The default setting is SPI_CLOCK_DIV4, which sets the SPI clock to one-quarter - /// the frequency of the system clock (4 Mhz for the boards at 16 MHz). - /// \param[in] frequency The data rate to use: one of RHGenericSPI::Frequency - virtual void setFrequency(Frequency frequency); - - /// Signal the start of an SPI transaction that must not be interrupted by other SPI actions - /// In subclasses that support transactions this will ensure that other SPI transactions - /// are blocked until this one is completed by endTransaction(). - /// Base does nothing - /// Might be overridden in subclass - virtual void beginTransaction(){} - - /// Signal the end of an SPI transaction - /// Base does nothing - /// Might be overridden in subclass - virtual void endTransaction(){} - - /// Specify the interrupt number of the interrupt that will use SPI transactions - /// Tells the SPI support software that SPI transactions will occur with the interrupt - /// handler assocated with interruptNumber - /// Base does nothing - /// Might be overridden in subclass - /// \param[in] interruptNumber The number of the interrupt - virtual void usingInterrupt(uint8_t interruptNumber){ - (void)interruptNumber; - } - -protected: - - /// The configure SPI Bus frequency, one of RHGenericSPI::Frequency - Frequency _frequency; // Bus frequency, one of RHGenericSPI::Frequency - - /// Bit order, one of RHGenericSPI::BitOrder - BitOrder _bitOrder; - - /// SPI bus mode, one of RHGenericSPI::DataMode - DataMode _dataMode; -}; -#endif diff --git a/src/rf95/RHHardwareSPI.cpp b/src/rf95/RHHardwareSPI.cpp deleted file mode 100644 index b4b1f6bd6..000000000 --- a/src/rf95/RHHardwareSPI.cpp +++ /dev/null @@ -1,499 +0,0 @@ -// RHHardwareSPI.cpp -// Author: Mike McCauley (mikem@airspayce.com) -// Copyright (C) 2011 Mike McCauley -// Contributed by Joanna Rutkowska -// $Id: RHHardwareSPI.cpp,v 1.25 2020/01/05 07:02:23 mikem Exp mikem $ - -#include - -#ifdef RH_HAVE_HARDWARE_SPI - -// Declare a single default instance of the hardware SPI interface class -RHHardwareSPI hardware_spi; - - -#if (RH_PLATFORM == RH_PLATFORM_STM32) // Maple etc -// Declare an SPI interface to use -HardwareSPI SPI(1); -#elif (RH_PLATFORM == RH_PLATFORM_STM32STD) // STM32F4 Discovery -// Declare an SPI interface to use -HardwareSPI SPI(1); -#elif (RH_PLATFORM == RH_PLATFORM_MONGOOSE_OS) // Mongoose OS platform -HardwareSPI SPI(1); -#endif - -// Arduino Due has default SPI pins on central SPI headers, and not on 10, 11, 12, 13 -// as per other Arduinos -// http://21stdigitalhome.blogspot.com.au/2013/02/arduino-due-hardware-spi.html -#if defined (__arm__) && !defined(CORE_TEENSY) && !defined(SPI_CLOCK_DIV16) && !defined(RH_PLATFORM_NRF52) - // Arduino Due in 1.5.5 has no definitions for SPI dividers - // SPI clock divider is based on MCK of 84MHz - #define SPI_CLOCK_DIV16 (VARIANT_MCK/84000000) // 1MHz - #define SPI_CLOCK_DIV8 (VARIANT_MCK/42000000) // 2MHz - #define SPI_CLOCK_DIV4 (VARIANT_MCK/21000000) // 4MHz - #define SPI_CLOCK_DIV2 (VARIANT_MCK/10500000) // 8MHz - #define SPI_CLOCK_DIV1 (VARIANT_MCK/5250000) // 16MHz -#endif - -RHHardwareSPI::RHHardwareSPI(Frequency frequency, BitOrder bitOrder, DataMode dataMode) - : - RHGenericSPI(frequency, bitOrder, dataMode) -{ -} - -uint8_t RHHardwareSPI::transfer(uint8_t data) -{ - return SPI.transfer(data); -} - -#if (RH_PLATFORM == RH_PLATFORM_MONGOOSE_OS) -uint8_t RHHardwareSPI::transfer2B(uint8_t byte0, uint8_t byte1) -{ - return SPI.transfer2B(byte0, byte1); -} - -uint8_t RHHardwareSPI::spiBurstRead(uint8_t reg, uint8_t* dest, uint8_t len) -{ - return SPI.spiBurstRead(reg, dest, len); -} - -uint8_t RHHardwareSPI::spiBurstWrite(uint8_t reg, const uint8_t* src, uint8_t len) -{ - uint8_t status = SPI.spiBurstWrite(reg, src, len); - return status; -} -#endif - -void RHHardwareSPI::attachInterrupt() -{ -#if (RH_PLATFORM == RH_PLATFORM_ARDUINO || RH_PLATFORM == RH_PLATFORM_NRF52) - SPI.attachInterrupt(); -#endif -} - -void RHHardwareSPI::detachInterrupt() -{ -#if (RH_PLATFORM == RH_PLATFORM_ARDUINO || RH_PLATFORM == RH_PLATFORM_NRF52) - SPI.detachInterrupt(); -#endif -} - -void RHHardwareSPI::begin() -{ -#if defined(SPI_HAS_TRANSACTION) - // Perhaps this is a uniform interface for SPI? - // Currently Teensy and ESP32 only - uint32_t frequency; - if (_frequency == Frequency16MHz) - frequency = 16000000; - else if (_frequency == Frequency8MHz) - frequency = 8000000; - else if (_frequency == Frequency4MHz) - frequency = 4000000; - else if (_frequency == Frequency2MHz) - frequency = 2000000; - else - frequency = 1000000; - -#if ((RH_PLATFORM == RH_PLATFORM_ARDUINO) && defined (__arm__) && (defined(ARDUINO_SAM_DUE) || defined(ARDUINO_ARCH_SAMD))) || defined(ARDUINO_ARCH_NRF52) || defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_STM32) || defined(NRF52) - // Arduino Due in 1.5.5 has its own BitOrder :-( - // So too does Arduino Zero - // So too does rogerclarkmelbourne/Arduino_STM32 - ::BitOrder bitOrder; -#elif (RH_PLATFORM == RH_PLATFORM_ATTINY_MEGA) - ::BitOrder bitOrder; -#else - uint8_t bitOrder; -#endif - - if (_bitOrder == BitOrderLSBFirst) - bitOrder = LSBFIRST; - else - bitOrder = MSBFIRST; - - uint8_t dataMode; - if (_dataMode == DataMode0) - dataMode = SPI_MODE0; - else if (_dataMode == DataMode1) - dataMode = SPI_MODE1; - else if (_dataMode == DataMode2) - dataMode = SPI_MODE2; - else if (_dataMode == DataMode3) - dataMode = SPI_MODE3; - else - dataMode = SPI_MODE0; - - // Save the settings for use in transactions - _settings = SPISettings(frequency, bitOrder, dataMode); - SPI.begin(); - -#else // SPI_HAS_TRANSACTION - - // Sigh: there are no common symbols for some of these SPI options across all platforms -#if (RH_PLATFORM == RH_PLATFORM_ARDUINO) || (RH_PLATFORM == RH_PLATFORM_UNO32) || (RH_PLATFORM == RH_PLATFORM_CHIPKIT_CORE || RH_PLATFORM == RH_PLATFORM_NRF52) - uint8_t dataMode; - if (_dataMode == DataMode0) - dataMode = SPI_MODE0; - else if (_dataMode == DataMode1) - dataMode = SPI_MODE1; - else if (_dataMode == DataMode2) - dataMode = SPI_MODE2; - else if (_dataMode == DataMode3) - dataMode = SPI_MODE3; - else - dataMode = SPI_MODE0; -#if (RH_PLATFORM == RH_PLATFORM_ARDUINO) && defined(__arm__) && defined(CORE_TEENSY) - // Temporary work-around due to problem where avr_emulation.h does not work properly for the setDataMode() cal - SPCR &= ~SPI_MODE_MASK; -#else - #if ((RH_PLATFORM == RH_PLATFORM_ARDUINO) && defined (__arm__) && defined(ARDUINO_ARCH_SAMD)) || defined(ARDUINO_ARCH_NRF52) - // Zero requires begin() before anything else :-) - SPI.begin(); - #endif - - SPI.setDataMode(dataMode); -#endif - -#if ((RH_PLATFORM == RH_PLATFORM_ARDUINO) && defined (__arm__) && (defined(ARDUINO_SAM_DUE) || defined(ARDUINO_ARCH_SAMD))) || defined(ARDUINO_ARCH_NRF52) || defined (ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_STM32) - // Arduino Due in 1.5.5 has its own BitOrder :-( - // So too does Arduino Zero - // So too does rogerclarkmelbourne/Arduino_STM32 - ::BitOrder bitOrder; -#else - uint8_t bitOrder; -#endif - if (_bitOrder == BitOrderLSBFirst) - bitOrder = LSBFIRST; - else - bitOrder = MSBFIRST; - SPI.setBitOrder(bitOrder); - uint8_t divider; - switch (_frequency) - { - case Frequency1MHz: - default: -#if F_CPU == 8000000 - divider = SPI_CLOCK_DIV8; -#else - divider = SPI_CLOCK_DIV16; -#endif - break; - - case Frequency2MHz: -#if F_CPU == 8000000 - divider = SPI_CLOCK_DIV4; -#else - divider = SPI_CLOCK_DIV8; -#endif - break; - - case Frequency4MHz: -#if F_CPU == 8000000 - divider = SPI_CLOCK_DIV2; -#else - divider = SPI_CLOCK_DIV4; -#endif - break; - - case Frequency8MHz: - divider = SPI_CLOCK_DIV2; // 4MHz on an 8MHz Arduino - break; - - case Frequency16MHz: - divider = SPI_CLOCK_DIV2; // Not really 16MHz, only 8MHz. 4MHz on an 8MHz Arduino - break; - - } - SPI.setClockDivider(divider); - SPI.begin(); - // Teensy requires it to be set _after_ begin() - SPI.setClockDivider(divider); - -#elif (RH_PLATFORM == RH_PLATFORM_STM32) // Maple etc - spi_mode dataMode; - // Hmmm, if we do this as a switch, GCC on maple gets v confused! - if (_dataMode == DataMode0) - dataMode = SPI_MODE_0; - else if (_dataMode == DataMode1) - dataMode = SPI_MODE_1; - else if (_dataMode == DataMode2) - dataMode = SPI_MODE_2; - else if (_dataMode == DataMode3) - dataMode = SPI_MODE_3; - else - dataMode = SPI_MODE_0; - - uint32 bitOrder; - if (_bitOrder == BitOrderLSBFirst) - bitOrder = LSBFIRST; - else - bitOrder = MSBFIRST; - - SPIFrequency frequency; // Yes, I know these are not exact equivalents. - switch (_frequency) - { - case Frequency1MHz: - default: - frequency = SPI_1_125MHZ; - break; - - case Frequency2MHz: - frequency = SPI_2_25MHZ; - break; - - case Frequency4MHz: - frequency = SPI_4_5MHZ; - break; - - case Frequency8MHz: - frequency = SPI_9MHZ; - break; - - case Frequency16MHz: - frequency = SPI_18MHZ; - break; - - } - SPI.begin(frequency, bitOrder, dataMode); - -#elif (RH_PLATFORM == RH_PLATFORM_STM32STD) // STM32F4 discovery - uint8_t dataMode; - if (_dataMode == DataMode0) - dataMode = SPI_MODE0; - else if (_dataMode == DataMode1) - dataMode = SPI_MODE1; - else if (_dataMode == DataMode2) - dataMode = SPI_MODE2; - else if (_dataMode == DataMode3) - dataMode = SPI_MODE3; - else - dataMode = SPI_MODE0; - - uint32_t bitOrder; - if (_bitOrder == BitOrderLSBFirst) - bitOrder = LSBFIRST; - else - bitOrder = MSBFIRST; - - SPIFrequency frequency; // Yes, I know these are not exact equivalents. - switch (_frequency) - { - case Frequency1MHz: - default: - frequency = SPI_1_3125MHZ; - break; - - case Frequency2MHz: - frequency = SPI_2_625MHZ; - break; - - case Frequency4MHz: - frequency = SPI_5_25MHZ; - break; - - case Frequency8MHz: - frequency = SPI_10_5MHZ; - break; - - case Frequency16MHz: - frequency = SPI_21_0MHZ; - break; - - } - SPI.begin(frequency, bitOrder, dataMode); - -#elif (RH_PLATFORM == RH_PLATFORM_STM32F2) // Photon - uint8_t dataMode; - if (_dataMode == DataMode0) - dataMode = SPI_MODE0; - else if (_dataMode == DataMode1) - dataMode = SPI_MODE1; - else if (_dataMode == DataMode2) - dataMode = SPI_MODE2; - else if (_dataMode == DataMode3) - dataMode = SPI_MODE3; - else - dataMode = SPI_MODE0; - SPI.setDataMode(dataMode); - if (_bitOrder == BitOrderLSBFirst) - SPI.setBitOrder(LSBFIRST); - else - SPI.setBitOrder(MSBFIRST); - - switch (_frequency) - { - case Frequency1MHz: - default: - SPI.setClockSpeed(1, MHZ); - break; - - case Frequency2MHz: - SPI.setClockSpeed(2, MHZ); - break; - - case Frequency4MHz: - SPI.setClockSpeed(4, MHZ); - break; - - case Frequency8MHz: - SPI.setClockSpeed(8, MHZ); - break; - - case Frequency16MHz: - SPI.setClockSpeed(16, MHZ); - break; - } - -// SPI.setClockDivider(SPI_CLOCK_DIV4); // 72MHz / 4MHz = 18MHz -// SPI.setClockSpeed(1, MHZ); - SPI.begin(); - -#elif (RH_PLATFORM == RH_PLATFORM_ESP8266) - // Requires SPI driver for ESP8266 from https://github.com/esp8266/Arduino/tree/master/libraries/SPI - // Which ppears to be in Arduino Board Manager ESP8266 Community version 2.1.0 - // Contributed by David Skinner - // begin comes first - SPI.begin(); - - // datamode - switch ( _dataMode ) - { - case DataMode1: - SPI.setDataMode ( SPI_MODE1 ); - break; - case DataMode2: - SPI.setDataMode ( SPI_MODE2 ); - break; - case DataMode3: - SPI.setDataMode ( SPI_MODE3 ); - break; - case DataMode0: - default: - SPI.setDataMode ( SPI_MODE0 ); - break; - } - - // bitorder - SPI.setBitOrder(_bitOrder == BitOrderLSBFirst ? LSBFIRST : MSBFIRST); - - // frequency (this sets the divider) - switch (_frequency) - { - case Frequency1MHz: - default: - SPI.setFrequency(1000000); - break; - case Frequency2MHz: - SPI.setFrequency(2000000); - break; - case Frequency4MHz: - SPI.setFrequency(4000000); - break; - case Frequency8MHz: - SPI.setFrequency(8000000); - break; - case Frequency16MHz: - SPI.setFrequency(16000000); - break; - } - -#elif (RH_PLATFORM == RH_PLATFORM_RASPI) // Raspberry PI - uint8_t dataMode; - if (_dataMode == DataMode0) - dataMode = BCM2835_SPI_MODE0; - else if (_dataMode == DataMode1) - dataMode = BCM2835_SPI_MODE1; - else if (_dataMode == DataMode2) - dataMode = BCM2835_SPI_MODE2; - else if (_dataMode == DataMode3) - dataMode = BCM2835_SPI_MODE3; - - uint8_t bitOrder; - if (_bitOrder == BitOrderLSBFirst) - bitOrder = BCM2835_SPI_BIT_ORDER_LSBFIRST; - else - bitOrder = BCM2835_SPI_BIT_ORDER_MSBFIRST; - - uint32_t divider; - switch (_frequency) - { - case Frequency1MHz: - default: - divider = BCM2835_SPI_CLOCK_DIVIDER_256; - break; - case Frequency2MHz: - divider = BCM2835_SPI_CLOCK_DIVIDER_128; - break; - case Frequency4MHz: - divider = BCM2835_SPI_CLOCK_DIVIDER_64; - break; - case Frequency8MHz: - divider = BCM2835_SPI_CLOCK_DIVIDER_32; - break; - case Frequency16MHz: - divider = BCM2835_SPI_CLOCK_DIVIDER_16; - break; - } - SPI.begin(divider, bitOrder, dataMode); -#elif (RH_PLATFORM == RH_PLATFORM_MONGOOSE_OS) - uint8_t dataMode = SPI_MODE0; - uint32_t frequency = 4000000; //!!! ESP32/NRF902 works ok at 4MHz but not at 8MHz SPI clock. - uint32_t bitOrder = MSBFIRST; - - if (_dataMode == DataMode0) { - dataMode = SPI_MODE0; - } else if (_dataMode == DataMode1) { - dataMode = SPI_MODE1; - } else if (_dataMode == DataMode2) { - dataMode = SPI_MODE2; - } else if (_dataMode == DataMode3) { - dataMode = SPI_MODE3; - } - - if (_bitOrder == BitOrderLSBFirst) { - bitOrder = LSBFIRST; - } - - if (_frequency == Frequency4MHz) - frequency = 4000000; - else if (_frequency == Frequency2MHz) - frequency = 2000000; - else - frequency = 1000000; - - SPI.begin(frequency, bitOrder, dataMode); -#else - #warning RHHardwareSPI does not support this platform yet. Consider adding it and contributing a patch. -#endif - -#endif // SPI_HAS_TRANSACTION -} - -void RHHardwareSPI::end() -{ - return SPI.end(); -} - -void RHHardwareSPI::beginTransaction() -{ -#if defined(SPI_HAS_TRANSACTION) - SPI.beginTransaction(_settings); -#endif -} - -void RHHardwareSPI::endTransaction() -{ -#if defined(SPI_HAS_TRANSACTION) - SPI.endTransaction(); -#endif -} - -void RHHardwareSPI::usingInterrupt(uint8_t interrupt) -{ -#if defined(SPI_HAS_TRANSACTION) && !defined(RH_MISSING_SPIUSINGINTERRUPT) - SPI.usingInterrupt(interrupt); -#endif - (void)interrupt; -} - -#endif diff --git a/src/rf95/RHHardwareSPI.h b/src/rf95/RHHardwareSPI.h deleted file mode 100644 index 3238ff378..000000000 --- a/src/rf95/RHHardwareSPI.h +++ /dev/null @@ -1,116 +0,0 @@ -// RHHardwareSPI.h -// Author: Mike McCauley (mikem@airspayce.com) -// Copyright (C) 2011 Mike McCauley -// Contributed by Joanna Rutkowska -// $Id: RHHardwareSPI.h,v 1.12 2020/01/05 07:02:23 mikem Exp mikem $ - -#ifndef RHHardwareSPI_h -#define RHHardwareSPI_h - -#include - -///////////////////////////////////////////////////////////////////// -/// \class RHHardwareSPI RHHardwareSPI.h -/// \brief Encapsulate a hardware SPI bus interface -/// -/// This concrete subclass of GenericSPIClass encapsulates the standard Arduino hardware and other -/// hardware SPI interfaces. -/// -/// SPI transactions are supported in development environments that support it with SPI_HAS_TRANSACTION. -class RHHardwareSPI : public RHGenericSPI -{ -#ifdef RH_HAVE_HARDWARE_SPI -public: - /// Constructor - /// Creates an instance of a hardware SPI interface, using whatever SPI hardware is available on - /// your processor platform. On Arduino and Uno32, uses SPI. On Maple, uses HardwareSPI. - /// \param[in] frequency One of RHGenericSPI::Frequency to select the SPI bus frequency. The frequency - /// is mapped to the closest available bus frequency on the platform. - /// \param[in] bitOrder Select the SPI bus bit order, one of RHGenericSPI::BitOrderMSBFirst or - /// RHGenericSPI::BitOrderLSBFirst. - /// \param[in] dataMode Selects the SPI bus data mode. One of RHGenericSPI::DataMode - RHHardwareSPI(Frequency frequency = Frequency1MHz, BitOrder bitOrder = BitOrderMSBFirst, DataMode dataMode = DataMode0); - - /// Transfer a single octet to and from the SPI interface - /// \param[in] data The octet to send - /// \return The octet read from SPI while the data octet was sent - uint8_t transfer(uint8_t data); - -#if (RH_PLATFORM == RH_PLATFORM_MONGOOSE_OS) - /// Transfer (write) 2 bytes on the SPI interface to an NRF device - /// \param[in] byte0 The first byte to be sent on the SPI interface - /// \param[in] byte1 The second byte to be sent on the SPI interface - /// \return The second byte clocked in as the second byte is sent. - uint8_t transfer2B(uint8_t byte0, uint8_t byte1); - - /// Read a number of bytes on the SPI interface from an NRF device - /// \param[in] reg The NRF device register to read - /// \param[out] dest The buffer to hold the bytes read - /// \param[in] len The number of bytes to read - /// \return The NRF status byte - uint8_t spiBurstRead(uint8_t reg, uint8_t* dest, uint8_t len); - - /// Wrte a number of bytes on the SPI interface to an NRF device - /// \param[in] reg The NRF device register to read - /// \param[out] src The buffer to hold the bytes write - /// \param[in] len The number of bytes to write - /// \return The NRF status byte - uint8_t spiBurstWrite(uint8_t reg, const uint8_t* src, uint8_t len); - -#endif - - // SPI Configuration methods - /// Enable SPI interrupts - /// This can be used in an SPI slave to indicate when an SPI message has been received - /// It will cause the SPI_STC_vect interrupt vectr to be executed - void attachInterrupt(); - - /// Disable SPI interrupts - /// This can be used to diable the SPI interrupt in slaves where that is supported. - void detachInterrupt(); - - /// Initialise the SPI library - /// Call this after configuring the SPI interface and before using it to transfer data. - /// Initializes the SPI bus by setting SCK, MOSI, and SS to outputs, pulling SCK and MOSI low, and SS high. - void begin(); - - /// Disables the SPI bus (leaving pin modes unchanged). - /// Call this after you have finished using the SPI interface. - void end(); -#else - // not supported on ATTiny etc - uint8_t transfer(uint8_t /*data*/) {return 0;} - void begin(){} - void end(){} - -#endif - - /// Signal the start of an SPI transaction that must not be interrupted by other SPI actions - /// In subclasses that support transactions this will ensure that other SPI transactions - /// are blocked until this one is completed by endTransaction(). - /// Uses the underlying SPI transaction support if available as specified by SPI_HAS_TRANSACTION. - virtual void beginTransaction(); - - /// Signal the end of an SPI transaction - /// Uses the underlying SPI transaction support if available as specified by SPI_HAS_TRANSACTION. - virtual void endTransaction(); - - /// Specify the interrupt number of the interrupt that will use SPI transactions - /// Tells the SPI support software that SPI transactions will occur with the interrupt - /// handler assocated with interruptNumber - /// Uses the underlying SPI transaction support if available as specified by SPI_HAS_TRANSACTION. - /// \param[in] interruptNumber The number of the interrupt - virtual void usingInterrupt(uint8_t interruptNumber); - -protected: - -#if defined(SPI_HAS_TRANSACTION) - // Storage for SPI settings used in SPI transactions - SPISettings _settings; -#endif -}; - -// Built in default instance -extern RHHardwareSPI hardware_spi; - -#endif diff --git a/src/rf95/RHNRFSPIDriver.cpp b/src/rf95/RHNRFSPIDriver.cpp deleted file mode 100644 index a1e8f0da7..000000000 --- a/src/rf95/RHNRFSPIDriver.cpp +++ /dev/null @@ -1,137 +0,0 @@ -// RHNRFSPIDriver.cpp -// -// Copyright (C) 2014 Mike McCauley -// $Id: RHNRFSPIDriver.cpp,v 1.5 2020/01/05 07:02:23 mikem Exp mikem $ - -#include - -RHNRFSPIDriver::RHNRFSPIDriver(uint8_t slaveSelectPin, RHGenericSPI& spi) - : - _spi(spi), - _slaveSelectPin(slaveSelectPin) -{ -} - -bool RHNRFSPIDriver::init() -{ - // start the SPI library with the default speeds etc: - // On Arduino Due this defaults to SPI1 on the central group of 6 SPI pins - _spi.begin(); - - // Initialise the slave select pin - // On Maple, this must be _after_ spi.begin - pinMode(_slaveSelectPin, OUTPUT); - digitalWrite(_slaveSelectPin, HIGH); - - delay(100); - return true; -} - -// Low level commands for interfacing with the device -uint8_t RHNRFSPIDriver::spiCommand(uint8_t command) -{ - uint8_t status; - ATOMIC_BLOCK_START; -#if (RH_PLATFORM == RH_PLATFORM_MONGOOSE_OS) - status = _spi.transfer(command); -#else - _spi.beginTransaction(); - digitalWrite(_slaveSelectPin, LOW); - status = _spi.transfer(command); - digitalWrite(_slaveSelectPin, HIGH); - _spi.endTransaction(); -#endif - ATOMIC_BLOCK_END; - return status; -} - -uint8_t RHNRFSPIDriver::spiRead(uint8_t reg) -{ - uint8_t val; - ATOMIC_BLOCK_START; -#if (RH_PLATFORM == RH_PLATFORM_MONGOOSE_OS) - val = _spi.transfer2B(reg, 0); // Send the address, discard the status, The written value is ignored, reg value is read -#else - _spi.beginTransaction(); - digitalWrite(_slaveSelectPin, LOW); - _spi.transfer(reg); // Send the address, discard the status - val = _spi.transfer(0); // The written value is ignored, reg value is read - digitalWrite(_slaveSelectPin, HIGH); - _spi.endTransaction(); -#endif - ATOMIC_BLOCK_END; - return val; -} - -uint8_t RHNRFSPIDriver::spiWrite(uint8_t reg, uint8_t val) -{ - uint8_t status = 0; - ATOMIC_BLOCK_START; -#if (RH_PLATFORM == RH_PLATFORM_MONGOOSE_OS) - status = _spi.transfer2B(reg, val); -#else - _spi.beginTransaction(); - digitalWrite(_slaveSelectPin, LOW); - status = _spi.transfer(reg); // Send the address - _spi.transfer(val); // New value follows -#if (RH_PLATFORM == RH_PLATFORM_ARDUINO) && defined(__arm__) && defined(CORE_TEENSY) - // Sigh: some devices, such as MRF89XA dont work properly on Teensy 3.1: - // At 1MHz, the clock returns low _after_ slave select goes high, which prevents SPI - // write working. This delay gixes time for the clock to return low. -delayMicroseconds(5); -#endif - digitalWrite(_slaveSelectPin, HIGH); - _spi.endTransaction(); -#endif - ATOMIC_BLOCK_END; - return status; -} - -uint8_t RHNRFSPIDriver::spiBurstRead(uint8_t reg, uint8_t* dest, uint8_t len) -{ - uint8_t status = 0; - ATOMIC_BLOCK_START; -#if (RH_PLATFORM == RH_PLATFORM_MONGOOSE_OS) - status = _spi.spiBurstRead(reg, dest, len); -#else - _spi.beginTransaction(); - digitalWrite(_slaveSelectPin, LOW); - status = _spi.transfer(reg); // Send the start address - while (len--) - *dest++ = _spi.transfer(0); - digitalWrite(_slaveSelectPin, HIGH); - _spi.endTransaction(); -#endif - ATOMIC_BLOCK_END; - return status; -} - -uint8_t RHNRFSPIDriver::spiBurstWrite(uint8_t reg, const uint8_t* src, uint8_t len) -{ - uint8_t status = 0; - ATOMIC_BLOCK_START; -#if (RH_PLATFORM == RH_PLATFORM_MONGOOSE_OS) - status = _spi.spiBurstWrite(reg, src, len); -#else - _spi.beginTransaction(); - digitalWrite(_slaveSelectPin, LOW); - status = _spi.transfer(reg); // Send the start address - while (len--) - _spi.transfer(*src++); - digitalWrite(_slaveSelectPin, HIGH); - _spi.endTransaction(); -#endif - ATOMIC_BLOCK_END; - return status; -} - -void RHNRFSPIDriver::setSlaveSelectPin(uint8_t slaveSelectPin) -{ - _slaveSelectPin = slaveSelectPin; -} - -void RHNRFSPIDriver::spiUsingInterrupt(uint8_t interruptNumber) -{ - _spi.usingInterrupt(interruptNumber); -} - diff --git a/src/rf95/RHNRFSPIDriver.h b/src/rf95/RHNRFSPIDriver.h deleted file mode 100644 index b93557d78..000000000 --- a/src/rf95/RHNRFSPIDriver.h +++ /dev/null @@ -1,101 +0,0 @@ -// RHNRFSPIDriver.h -// Author: Mike McCauley (mikem@airspayce.com) -// Copyright (C) 2014 Mike McCauley -// $Id: RHNRFSPIDriver.h,v 1.5 2017/11/06 00:04:08 mikem Exp $ - -#ifndef RHNRFSPIDriver_h -#define RHNRFSPIDriver_h - -#include -#include - -class RHGenericSPI; - -///////////////////////////////////////////////////////////////////// -/// \class RHNRFSPIDriver RHNRFSPIDriver.h -/// \brief Base class for RadioHead drivers that use the SPI bus -/// to communicate with its NRF family transport hardware. -/// -/// This class can be subclassed by Drivers that require to use the SPI bus. -/// It can be configured to use either the RHHardwareSPI class (if there is one available on the platform) -/// of the bitbanged RHSoftwareSPI class. The dfault behaviour is to use a pre-instantiated built-in RHHardwareSPI -/// interface. -/// -/// SPI bus access is protected by ATOMIC_BLOCK_START and ATOMIC_BLOCK_END, which will ensure interrupts -/// are disabled during access. -/// -/// The read and write routines use SPI conventions as used by Nordic NRF radios and otehr devices, -/// but these can be overriden -/// in subclasses if necessary. -/// -/// Application developers are not expected to instantiate this class directly: -/// it is for the use of Driver developers. -class RHNRFSPIDriver : public RHGenericDriver -{ -public: - /// Constructor - /// \param[in] slaveSelectPin The controller pin to use to select the desired SPI device. This pin will be driven LOW - /// during SPI communications with the SPI device that uis iused by this Driver. - /// \param[in] spi Reference to the SPI interface to use. The default is to use a default built-in Hardware interface. - RHNRFSPIDriver(uint8_t slaveSelectPin = SS, 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. - bool init(); - - /// Sends a single command to the device - /// \param[in] command The command code to send to the device. - /// \return Some devices return a status byte during the first data transfer. This byte is returned. - /// it may or may not be meaningfule depending on the the type of device being accessed. - uint8_t spiCommand(uint8_t command); - - /// Reads a single register from the SPI device - /// \param[in] reg Register number - /// \return The value of the register - uint8_t spiRead(uint8_t reg); - - /// Writes a single byte to the SPI device - /// \param[in] reg Register number - /// \param[in] val The value to write - /// \return Some devices return a status byte during the first data transfer. This byte is returned. - /// it may or may not be meaningfule depending on the the type of device being accessed. - uint8_t spiWrite(uint8_t reg, uint8_t val); - - /// Reads a number of consecutive registers from the SPI device using burst read mode - /// \param[in] reg Register number of the first register - /// \param[in] dest Array to write the register values to. Must be at least len bytes - /// \param[in] len Number of bytes to read - /// \return Some devices return a status byte during the first data transfer. This byte is returned. - /// it may or may not be meaningfule depending on the the type of device being accessed. - uint8_t spiBurstRead(uint8_t reg, uint8_t* dest, uint8_t len); - - /// Write a number of consecutive registers using burst write mode - /// \param[in] reg Register number of the first register - /// \param[in] src Array of new register values to write. Must be at least len bytes - /// \param[in] len Number of bytes to write - /// \return Some devices return a status byte during the first data transfer. This byte is returned. - /// it may or may not be meaningfule depending on the the type of device being accessed. - uint8_t spiBurstWrite(uint8_t reg, const uint8_t* src, uint8_t len); - - /// Set or change the pin to be used for SPI slave select. - /// This can be called at any time to change the - /// pin that will be used for slave select in subsquent SPI operations. - /// \param[in] slaveSelectPin The pin to use - void setSlaveSelectPin(uint8_t slaveSelectPin); - - /// Set the SPI interrupt number - /// If SPI transactions can occur within an interrupt, tell the low level SPI - /// interface which interrupt is used - /// \param[in] interruptNumber the interrupt number - void spiUsingInterrupt(uint8_t interruptNumber); - -protected: - /// Reference to the RHGenericSPI instance to use to trasnfer data with teh SPI device - RHGenericSPI& _spi; - - /// The pin number of the Slave Select pin that is used to select the desired device. - uint8_t _slaveSelectPin; -}; - -#endif diff --git a/src/rf95/RHSPIDriver.cpp b/src/rf95/RHSPIDriver.cpp deleted file mode 100644 index 25bae8a08..000000000 --- a/src/rf95/RHSPIDriver.cpp +++ /dev/null @@ -1,95 +0,0 @@ -// RHSPIDriver.cpp -// -// Copyright (C) 2014 Mike McCauley -// $Id: RHSPIDriver.cpp,v 1.11 2017/11/06 00:04:08 mikem Exp $ - -#include - -RHSPIDriver::RHSPIDriver(uint8_t slaveSelectPin, RHGenericSPI& spi) - : - _spi(spi), - _slaveSelectPin(slaveSelectPin) -{ -} - -bool RHSPIDriver::init() -{ - // start the SPI library with the default speeds etc: - // On Arduino Due this defaults to SPI1 on the central group of 6 SPI pins - _spi.begin(); - - // Initialise the slave select pin - // On Maple, this must be _after_ spi.begin - pinMode(_slaveSelectPin, OUTPUT); - digitalWrite(_slaveSelectPin, HIGH); - - delay(100); - return true; -} - -uint8_t RHSPIDriver::spiRead(uint8_t reg) -{ - uint8_t val; - ATOMIC_BLOCK_START; - digitalWrite(_slaveSelectPin, LOW); - _spi.transfer(reg & ~RH_SPI_WRITE_MASK); // Send the address with the write mask off - val = _spi.transfer(0); // The written value is ignored, reg value is read - digitalWrite(_slaveSelectPin, HIGH); - ATOMIC_BLOCK_END; - return val; -} - -uint8_t RHSPIDriver::spiWrite(uint8_t reg, uint8_t val) -{ - uint8_t status = 0; - ATOMIC_BLOCK_START; - _spi.beginTransaction(); - digitalWrite(_slaveSelectPin, LOW); - status = _spi.transfer(reg | RH_SPI_WRITE_MASK); // Send the address with the write mask on - _spi.transfer(val); // New value follows - digitalWrite(_slaveSelectPin, HIGH); - _spi.endTransaction(); - ATOMIC_BLOCK_END; - return status; -} - -uint8_t RHSPIDriver::spiBurstRead(uint8_t reg, uint8_t* dest, uint8_t len) -{ - uint8_t status = 0; - ATOMIC_BLOCK_START; - _spi.beginTransaction(); - digitalWrite(_slaveSelectPin, LOW); - status = _spi.transfer(reg & ~RH_SPI_WRITE_MASK); // Send the start address with the write mask off - while (len--) - *dest++ = _spi.transfer(0); - digitalWrite(_slaveSelectPin, HIGH); - _spi.endTransaction(); - ATOMIC_BLOCK_END; - return status; -} - -uint8_t RHSPIDriver::spiBurstWrite(uint8_t reg, const uint8_t* src, uint8_t len) -{ - uint8_t status = 0; - ATOMIC_BLOCK_START; - _spi.beginTransaction(); - digitalWrite(_slaveSelectPin, LOW); - status = _spi.transfer(reg | RH_SPI_WRITE_MASK); // Send the start address with the write mask on - while (len--) - _spi.transfer(*src++); - digitalWrite(_slaveSelectPin, HIGH); - _spi.endTransaction(); - ATOMIC_BLOCK_END; - return status; -} - -void RHSPIDriver::setSlaveSelectPin(uint8_t slaveSelectPin) -{ - _slaveSelectPin = slaveSelectPin; -} - -void RHSPIDriver::spiUsingInterrupt(uint8_t interruptNumber) -{ - _spi.usingInterrupt(interruptNumber); -} - diff --git a/src/rf95/RHSPIDriver.h b/src/rf95/RHSPIDriver.h deleted file mode 100644 index fdd5de410..000000000 --- a/src/rf95/RHSPIDriver.h +++ /dev/null @@ -1,100 +0,0 @@ -// RHSPIDriver.h -// Author: Mike McCauley (mikem@airspayce.com) -// Copyright (C) 2014 Mike McCauley -// $Id: RHSPIDriver.h,v 1.14 2019/09/06 04:40:40 mikem Exp $ - -#ifndef RHSPIDriver_h -#define RHSPIDriver_h - -#include -#include - -// This is the bit in the SPI address that marks it as a write -#define RH_SPI_WRITE_MASK 0x80 - -class RHGenericSPI; - -///////////////////////////////////////////////////////////////////// -/// \class RHSPIDriver RHSPIDriver.h -/// \brief Base class for RadioHead drivers that use the SPI bus -/// to communicate with its transport hardware. -/// -/// This class can be subclassed by Drivers that require to use the SPI bus. -/// It can be configured to use either the RHHardwareSPI class (if there is one available on the platform) -/// of the bitbanged RHSoftwareSPI class. The default behaviour is to use a pre-instantiated built-in RHHardwareSPI -/// interface. -/// -/// SPI bus access is protected by ATOMIC_BLOCK_START and ATOMIC_BLOCK_END, which will ensure interrupts -/// are disabled during access. -/// -/// The read and write routines implement commonly used SPI conventions: specifically that the MSB -/// of the first byte transmitted indicates that it is a write and the remaining bits indicate the rehgister to access) -/// This can be overriden -/// in subclasses if necessaryor an alternative class, RHNRFSPIDriver can be used to access devices like -/// Nordic NRF series radios, which have different requirements. -/// -/// Application developers are not expected to instantiate this class directly: -/// it is for the use of Driver developers. -class RHSPIDriver : public RHGenericDriver -{ -public: - /// Constructor - /// \param[in] slaveSelectPin The controler pin to use to select the desired SPI device. This pin will be driven LOW - /// during SPI communications with the SPI device that uis iused by this Driver. - /// \param[in] spi Reference to the SPI interface to use. The default is to use a default built-in Hardware interface. - RHSPIDriver(uint8_t slaveSelectPin = SS, 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. - bool init(); - - /// Reads a single register from the SPI device - /// \param[in] reg Register number - /// \return The value of the register - uint8_t spiRead(uint8_t reg); - - /// Writes a single byte to the SPI device - /// \param[in] reg Register number - /// \param[in] val The value to write - /// \return Some devices return a status byte during the first data transfer. This byte is returned. - /// it may or may not be meaningfule depending on the the type of device being accessed. - uint8_t spiWrite(uint8_t reg, uint8_t val); - - /// Reads a number of consecutive registers from the SPI device using burst read mode - /// \param[in] reg Register number of the first register - /// \param[in] dest Array to write the register values to. Must be at least len bytes - /// \param[in] len Number of bytes to read - /// \return Some devices return a status byte during the first data transfer. This byte is returned. - /// it may or may not be meaningfule depending on the the type of device being accessed. - uint8_t spiBurstRead(uint8_t reg, uint8_t* dest, uint8_t len); - - /// Write a number of consecutive registers using burst write mode - /// \param[in] reg Register number of the first register - /// \param[in] src Array of new register values to write. Must be at least len bytes - /// \param[in] len Number of bytes to write - /// \return Some devices return a status byte during the first data transfer. This byte is returned. - /// it may or may not be meaningfule depending on the the type of device being accessed. - uint8_t spiBurstWrite(uint8_t reg, const uint8_t* src, uint8_t len); - - /// Set or change the pin to be used for SPI slave select. - /// This can be called at any time to change the - /// pin that will be used for slave select in subsquent SPI operations. - /// \param[in] slaveSelectPin The pin to use - void setSlaveSelectPin(uint8_t slaveSelectPin); - - /// Set the SPI interrupt number - /// If SPI transactions can occur within an interrupt, tell the low level SPI - /// interface which interrupt is used - /// \param[in] interruptNumber the interrupt number - void spiUsingInterrupt(uint8_t interruptNumber); - - protected: - /// Reference to the RHGenericSPI instance to use to transfer data with the SPI device - RHGenericSPI& _spi; - - /// The pin number of the Slave Select pin that is used to select the desired device. - uint8_t _slaveSelectPin; -}; - -#endif diff --git a/src/rf95/RHSoftwareSPI.cpp b/src/rf95/RHSoftwareSPI.cpp deleted file mode 100644 index f1959cb06..000000000 --- a/src/rf95/RHSoftwareSPI.cpp +++ /dev/null @@ -1,166 +0,0 @@ -// SoftwareSPI.cpp -// Author: Chris Lapa (chris@lapa.com.au) -// Copyright (C) 2014 Chris Lapa -// Contributed by Chris Lapa - -#include - -RHSoftwareSPI::RHSoftwareSPI(Frequency frequency, BitOrder bitOrder, DataMode dataMode) - : - RHGenericSPI(frequency, bitOrder, dataMode) -{ - setPins(12, 11, 13); -} - -// Caution: on Arduino Uno and many other CPUs, digitalWrite is quite slow, taking about 4us -// digitalWrite is also slow, taking about 3.5us -// resulting in very slow SPI bus speeds using this technique, up to about 120us per octet of transfer -uint8_t RHSoftwareSPI::transfer(uint8_t data) -{ - uint8_t readData; - uint8_t writeData; - uint8_t builtReturn; - uint8_t mask; - - if (_bitOrder == BitOrderMSBFirst) - { - mask = 0x80; - } - else - { - mask = 0x01; - } - builtReturn = 0; - readData = 0; - - for (uint8_t count=0; count<8; count++) - { - if (data & mask) - { - writeData = HIGH; - } - else - { - writeData = LOW; - } - - if (_clockPhase == 1) - { - // CPHA=1, miso/mosi changing state now - digitalWrite(_mosi, writeData); - digitalWrite(_sck, ~_clockPolarity); - delayPeriod(); - - // CPHA=1, miso/mosi stable now - readData = digitalRead(_miso); - digitalWrite(_sck, _clockPolarity); - delayPeriod(); - } - else - { - // CPHA=0, miso/mosi changing state now - digitalWrite(_mosi, writeData); - digitalWrite(_sck, _clockPolarity); - delayPeriod(); - - // CPHA=0, miso/mosi stable now - readData = digitalRead(_miso); - digitalWrite(_sck, ~_clockPolarity); - delayPeriod(); - } - - if (_bitOrder == BitOrderMSBFirst) - { - mask >>= 1; - builtReturn |= (readData << (7 - count)); - } - else - { - mask <<= 1; - builtReturn |= (readData << count); - } - } - - digitalWrite(_sck, _clockPolarity); - - return builtReturn; -} - -/// Initialise the SPI library -void RHSoftwareSPI::begin() -{ - if (_dataMode == DataMode0 || - _dataMode == DataMode1) - { - _clockPolarity = LOW; - } - else - { - _clockPolarity = HIGH; - } - - if (_dataMode == DataMode0 || - _dataMode == DataMode2) - { - _clockPhase = 0; - } - else - { - _clockPhase = 1; - } - digitalWrite(_sck, _clockPolarity); - - // Caution: these counts assume that digitalWrite is very fast, which is usually not true - switch (_frequency) - { - case Frequency1MHz: - _delayCounts = 8; - break; - - case Frequency2MHz: - _delayCounts = 4; - break; - - case Frequency4MHz: - _delayCounts = 2; - break; - - case Frequency8MHz: - _delayCounts = 1; - break; - - case Frequency16MHz: - _delayCounts = 0; - break; - } -} - -/// Disables the SPI bus usually, in this case -/// there is no hardware controller to disable. -void RHSoftwareSPI::end() { } - -/// Sets the pins used by this SoftwareSPIClass instance. -/// \param[in] miso master in slave out pin used -/// \param[in] mosi master out slave in pin used -/// \param[in] sck clock pin used -void RHSoftwareSPI::setPins(uint8_t miso, uint8_t mosi, uint8_t sck) -{ - _miso = miso; - _mosi = mosi; - _sck = sck; - - pinMode(_miso, INPUT); - pinMode(_mosi, OUTPUT); - pinMode(_sck, OUTPUT); - digitalWrite(_sck, _clockPolarity); -} - - -void RHSoftwareSPI::delayPeriod() -{ - for (uint8_t count = 0; count < _delayCounts; count++) - { - __asm__ __volatile__ ("nop"); - } -} - diff --git a/src/rf95/RHSoftwareSPI.h b/src/rf95/RHSoftwareSPI.h deleted file mode 100644 index 5e7e1a5dd..000000000 --- a/src/rf95/RHSoftwareSPI.h +++ /dev/null @@ -1,90 +0,0 @@ -// SoftwareSPI.h -// Author: Chris Lapa (chris@lapa.com.au) -// Copyright (C) 2014 Chris Lapa -// Contributed by Chris Lapa - -#ifndef RHSoftwareSPI_h -#define RHSoftwareSPI_h - -#include - -///////////////////////////////////////////////////////////////////// -/// \class RHSoftwareSPI RHSoftwareSPI.h -/// \brief Encapsulate a software SPI interface -/// -/// This concrete subclass of RHGenericSPI enapsulates a bit-banged software SPI interface. -/// Caution: this software SPI interface will be much slower than hardware SPI on most -/// platforms. -/// -/// SPI transactions are not supported, and associated functions do nothing. -/// -/// \par Usage -/// -/// Usage varies slightly depending on what driver you are using. -/// -/// For RF22, for example: -/// \code -/// #include -/// RHSoftwareSPI spi; -/// RH_RF22 driver(SS, 2, spi); -/// RHReliableDatagram(driver, CLIENT_ADDRESS); -/// void setup() -/// { -/// spi.setPins(6, 5, 7); // Or whatever SPI pins you need -/// .... -/// } -/// \endcode -class RHSoftwareSPI : public RHGenericSPI -{ -public: - - /// Constructor - /// Creates an instance of a bit-banged software SPI interface. - /// Sets the SPI pins to the defaults of - /// MISO = 12, MOSI = 11, SCK = 13. If you need other assigments, call setPins() before - /// calling manager.init() or driver.init(). - /// \param[in] frequency One of RHGenericSPI::Frequency to select the SPI bus frequency. The frequency - /// is mapped to the closest available bus frequency on the platform. CAUTION: the achieved - /// frequency will almost certainly be very much slower on most platforms. eg on Arduino Uno, the - /// the clock rate is likely to be at best around 46kHz. - /// \param[in] bitOrder Select the SPI bus bit order, one of RHGenericSPI::BitOrderMSBFirst or - /// RHGenericSPI::BitOrderLSBFirst. - /// \param[in] dataMode Selects the SPI bus data mode. One of RHGenericSPI::DataMode - RHSoftwareSPI(Frequency frequency = Frequency1MHz, BitOrder bitOrder = BitOrderMSBFirst, DataMode dataMode = DataMode0); - - /// Transfer a single octet to and from the SPI interface - /// \param[in] data The octet to send - /// \return The octet read from SPI while the data octet was sent. - uint8_t transfer(uint8_t data); - - /// Initialise the software SPI library - /// Call this after configuring the SPI interface and before using it to transfer data. - /// Initializes the SPI bus by setting SCK, MOSI, and SS to outputs, pulling SCK and MOSI low, and SS high. - void begin(); - - /// Disables the SPI bus usually, in this case - /// there is no hardware controller to disable. - void end(); - - /// Sets the pins used by this SoftwareSPIClass instance. - /// The defaults are: MISO = 12, MOSI = 11, SCK = 13. - /// \param[in] miso master in slave out pin used - /// \param[in] mosi master out slave in pin used - /// \param[in] sck clock pin used - void setPins(uint8_t miso = 12, uint8_t mosi = 11, uint8_t sck = 13); - -private: - - /// Delay routine for bus timing. - void delayPeriod(); - -private: - uint8_t _miso; - uint8_t _mosi; - uint8_t _sck; - uint8_t _delayCounts; - uint8_t _clockPolarity; - uint8_t _clockPhase; -}; - -#endif diff --git a/src/rf95/RH_RF95.cpp b/src/rf95/RH_RF95.cpp deleted file mode 100644 index a5d6b47a7..000000000 --- a/src/rf95/RH_RF95.cpp +++ /dev/null @@ -1,651 +0,0 @@ -// RH_RF95.cpp -// -// Copyright (C) 2011 Mike McCauley -// $Id: RH_RF95.cpp,v 1.22 2020/01/05 07:02:23 mikem Exp mikem $ - -#include - -// Interrupt vectors for the 3 Arduino interrupt pins -// Each interrupt can be handled by a different instance of RH_RF95, allowing you to have -// 2 or more LORAs per Arduino -RH_RF95 *RH_RF95::_deviceForInterrupt[RH_RF95_NUM_INTERRUPTS] = {0, 0, 0}; -uint8_t RH_RF95::_interruptCount = 0; // Index into _deviceForInterrupt for next device - -// 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 - -}; - -RH_RF95::RH_RF95(uint8_t slaveSelectPin, uint8_t interruptPin, RHGenericSPI &spi) - : RHSPIDriver(slaveSelectPin, spi), _rxBufValid(0) -{ - _interruptPin = interruptPin; - _myInterruptIndex = 0xff; // Not allocated yet -} - -bool RH_RF95::init() -{ - if (!RHSPIDriver::init()) - return false; - -#ifdef RH_ATTACHINTERRUPT_TAKES_PIN_NUMBER - interruptNumber = _interruptPin; -#endif - - // Tell the low level SPI interface we will use SPI within this interrupt - // spiUsingInterrupt(interruptNumber); - - // No way to check the device type :-( - - // Add by Adrien van den Bossche for Teensy - // ARM M4 requires the below. else pin interrupt doesn't work properly. - // 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 - - 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)) { - // Serial.println(spiRead(RH_RF95_REG_01_OP_MODE), HEX); - return false; // No device present? - } - - // Set up FIFO - // We configure so that we can use the entire 256 byte FIFO for either receive - // or transmit, but not both at the same time - spiWrite(RH_RF95_REG_0E_FIFO_TX_BASE_ADDR, 0); - spiWrite(RH_RF95_REG_0F_FIFO_RX_BASE_ADDR, 0); - - // Packet format is preamble + explicit-header + payload + crc - // Explicit Header Mode - // payload is TO + FROM + ID + FLAGS + message data - // RX mode is implmented with RXCONTINUOUS - // max message data length is 255 - 4 = 251 octets - - setModeIdle(); - - // Set up default configuration - // No Sync Words in LORA mode. - setModemConfig(Bw125Cr45Sf128); // Radio default - // setModemConfig(Bw125Cr48Sf4096); // slow and reliable? - setPreambleLength(8); // Default is 8 - // An innocuous ISM frequency, same as RF22's - setFrequency(434.0); - // Lowish power - setTxPower(13); - - Serial.printf("IRQ flag mask 0x%x\n", spiRead(RH_RF95_REG_11_IRQ_FLAGS_MASK)); - } 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. - - // Set up interrupt handler - // Since there are a limited number of interrupt glue functions isr*() available, - // we can only support a limited number of devices simultaneously - // 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) { - // First run, no interrupt allocated yet - if (_interruptCount <= RH_RF95_NUM_INTERRUPTS) - _myInterruptIndex = _interruptCount++; - else - return false; // Too many devices, not enough interrupt vectors - } - _deviceForInterrupt[_myInterruptIndex] = this; - - return enableInterrupt(); -} - -// If on a platform without level trigger definitions, just use RISING and suck it up. -#ifndef ONHIGH -#define ONHIGH RISING -#endif - -bool RH_RF95::enableInterrupt() -{ - // Determine the interrupt number that corresponds to the interruptPin - int interruptNumber = digitalPinToInterrupt(_interruptPin); - if (interruptNumber == NOT_AN_INTERRUPT) - return false; - - if (_myInterruptIndex == 0) - attachInterrupt(interruptNumber, isr0, ONHIGH); - else if (_myInterruptIndex == 1) - attachInterrupt(interruptNumber, isr1, ONHIGH); - else if (_myInterruptIndex == 2) - attachInterrupt(interruptNumber, isr2, ONHIGH); - else - return false; // Too many devices, not enough interrupt vectors - - return true; -} - -void RH_INTERRUPT_ATTR RH_RF95::disableInterrupt() -{ - int interruptNumber = digitalPinToInterrupt(_interruptPin); - detachInterrupt(interruptNumber); -} - -void RH_RF95::prepareDeepSleep() -{ - // Determine the interrupt number that corresponds to the interruptPin - int interruptNumber = digitalPinToInterrupt(_interruptPin); - - detachInterrupt(interruptNumber); -} - -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; -} - -void RH_INTERRUPT_ATTR RH_RF95::handleInterruptLevel0() -{ - disableInterrupt(); // Disable our interrupt until our helper thread can run (because the IRQ will remain asserted until we - // talk to it via SPI) - pendingInterrupt = true; -} - -// 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 -// connnected to the processor. -// We use this to get RxDone and TxDone interrupts -void RH_RF95::handleInterrupt() -{ - // Read the interrupt register - uint8_t irq_flags = spiRead(RH_RF95_REG_12_IRQ_FLAGS); - - // ack all interrupts - // note from radiohead author wrt old code (with IMO wrong fix) - // 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 - I think the root cause we want level - // triggered interrupts here - not edge. Because edge allows us to miss handling secondard interrupts that occurred - // while this ISR was running. Better to instead, configure the interrupts as level triggered and clear pending - // at the _beginning_ of the ISR. If any interrupts occur while handling the ISR, the signal will remain asserted and - // our ISR will be reinvoked to handle that case) - spiWrite(RH_RF95_REG_12_IRQ_FLAGS, 0xff); // Clear all IRQ flags - - // Note: there can be substantial latency between ISR assertion and this function being run, therefore - // multiple flags might be set. Handle them all - - // Note: we are running the chip in continuous receive mode (currently, so RX_TIMEOUT shouldn't ever occur) - bool haveRxError = irq_flags & (RH_RF95_RX_TIMEOUT | RH_RF95_PAYLOAD_CRC_ERROR); - if (haveRxError) { - _rxBad++; - clearRxBuf(); - } else if (irq_flags & RH_RF95_RX_DONE) { - // 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; - - if (!crc_present) { - _rxBad++; - clearRxBuf(); - } else { - // Have received a packet - uint8_t len = spiRead(RH_RF95_REG_13_RX_NB_BYTES); - - // Reset the fifo read ptr to the beginning of the packet - spiWrite(RH_RF95_REG_0D_FIFO_ADDR_PTR, spiRead(RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR)); - spiBurstRead(RH_RF95_REG_00_FIFO, _buf, len); - _bufLen = len; - - // Remember the last signal to noise ratio, LORA mode - // Per page 111, SX1276/77/78/79 datasheet - _lastSNR = (int8_t)spiRead(RH_RF95_REG_19_PKT_SNR_VALUE) / 4; - - // Remember the RSSI of this packet, LORA mode - // this is according to the doc, but is it really correct? - // weakest receiveable signals are reported RSSI at about -66 - _lastRssi = spiRead(RH_RF95_REG_1A_PKT_RSSI_VALUE); - // Adjust the RSSI, datasheet page 87 - if (_lastSNR < 0) - _lastRssi = _lastRssi + _lastSNR; - else - _lastRssi = (int)_lastRssi * 16 / 15; - if (_usingHFport) - _lastRssi -= 157; - else - _lastRssi -= 164; - - // We have received a message. - validateRxBuf(); - if (_rxBufValid) - setModeIdle(); // Got one - } - } - - if (irq_flags & RH_RF95_TX_DONE) { - _txGood++; - setModeIdle(); - } - - if (_mode == RHModeCad && (irq_flags & RH_RF95_CAD_DONE)) { - _cad = irq_flags & RH_RF95_CAD_DETECTED; - setModeIdle(); - } - - enableInterrupt(); // Let ISR run again -} - -void RH_RF95::loop() -{ - while (pendingInterrupt) { - pendingInterrupt = false; // If the flag was set, it is _guaranteed_ the ISR won't be running, because it masked itself - handleInterrupt(); - } -} - -// These are low level functions that call the interrupt handler for the correct -// instance of RH_RF95. -// 3 interrupts allows us to have 3 different devices -void RH_INTERRUPT_ATTR RH_RF95::isr0() -{ - if (_deviceForInterrupt[0]) - _deviceForInterrupt[0]->handleInterruptLevel0(); -} -void RH_INTERRUPT_ATTR RH_RF95::isr1() -{ - if (_deviceForInterrupt[1]) - _deviceForInterrupt[1]->handleInterruptLevel0(); -} -void RH_INTERRUPT_ATTR RH_RF95::isr2() -{ - if (_deviceForInterrupt[2]) - _deviceForInterrupt[2]->handleInterruptLevel0(); -} - -// Check whether the latest received message is complete and uncorrupted -void RH_RF95::validateRxBuf() -{ - if (_bufLen < 4) - return; // Too short to be a real message - // Extract the 4 headers - _rxHeaderTo = _buf[0]; - _rxHeaderFrom = _buf[1]; - _rxHeaderId = _buf[2]; - _rxHeaderFlags = _buf[3]; - if (_promiscuous || _rxHeaderTo == _thisAddress || _rxHeaderTo == RH_BROADCAST_ADDRESS) { - _rxGood++; - _rxBufValid = true; - } -} - -bool RH_RF95::available() -{ - if (_mode == RHModeTx) - return false; - setModeRx(); - return _rxBufValid; // Will be set by the interrupt handler when a good message is received -} - -void RH_RF95::clearRxBuf() -{ - ATOMIC_BLOCK_START; - _rxBufValid = false; - _bufLen = 0; - ATOMIC_BLOCK_END; -} - -/// Note: This routine might be called from inside the RF95 ISR -bool RH_RF95::send(const uint8_t *data, uint8_t len) -{ - if (len > RH_RF95_MAX_MESSAGE_LEN) - return false; - - setModeIdle(); - - // Position at the beginning of the FIFO - spiWrite(RH_RF95_REG_0D_FIFO_ADDR_PTR, 0); - // The headers - spiWrite(RH_RF95_REG_00_FIFO, _txHeaderTo); - spiWrite(RH_RF95_REG_00_FIFO, _txHeaderFrom); - spiWrite(RH_RF95_REG_00_FIFO, _txHeaderId); - spiWrite(RH_RF95_REG_00_FIFO, _txHeaderFlags); - // The message data - spiBurstWrite(RH_RF95_REG_00_FIFO, data, len); - spiWrite(RH_RF95_REG_22_PAYLOAD_LENGTH, len + RH_RF95_HEADER_LEN); - - setModeTx(); // Start the transmitter - // when Tx is done, interruptHandler will fire and radio mode will return to STANDBY - return true; -} - -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 i; - for (i = 0; i < sizeof(registers); i++) { - Serial.print(registers[i], HEX); - Serial.print(": "); - Serial.println(spiRead(registers[i]), HEX); - } -#endif - return true; -} - -uint8_t RH_RF95::maxMessageLength() -{ - return RH_RF95_MAX_MESSAGE_LEN; -} - -bool RH_RF95::setFrequency(float centre) -{ - // Frf = FRF / FSTEP - uint32_t frf = (centre * 1000000.0) / RH_RF95_FSTEP; - spiWrite(RH_RF95_REG_06_FRF_MSB, (frf >> 16) & 0xff); - spiWrite(RH_RF95_REG_07_FRF_MID, (frf >> 8) & 0xff); - spiWrite(RH_RF95_REG_08_FRF_LSB, frf & 0xff); - _usingHFport = (centre >= 779.0); - - return true; -} - -void RH_RF95::setModeIdle() -{ - if (_mode != RHModeIdle) { - spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_STDBY); - _mode = RHModeIdle; - } -} - -bool RH_RF95::sleep() -{ - if (_mode != RHModeSleep) { - spiWrite(RH_RF95_REG_01_OP_MODE, RH_RF95_MODE_SLEEP); - _mode = RHModeSleep; - } - return true; -} - -void RH_RF95::setModeRx() -{ - 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; - } -} - -void RH_RF95::setModeTx() -{ - 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; - } -} - -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 (power > 14) - power = 14; - if (power < -1) - power = -1; - spiWrite(RH_RF95_REG_09_PA_CONFIG, RH_RF95_MAX_POWER | (power + 1)); - } else { - if (power > 23) - power = 23; - if (power < 5) - power = 5; - - // 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) { - spiWrite(RH_RF95_REG_4D_PA_DAC, RH_RF95_PA_DAC_ENABLE); - power -= 3; - } else { - spiWrite(RH_RF95_REG_4D_PA_DAC, RH_RF95_PA_DAC_DISABLE); - } - - // RFM95/96/97/98 does not have RFO pins connected to anything. Only PA_BOOST - // pin is connected, so must use PA_BOOST - // Pout = 2 + OutputPower. - // 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 - spiWrite(RH_RF95_REG_09_PA_CONFIG, RH_RF95_PA_SELECT | (power - 5)); - } -} - -// Sets registers from a canned modem configuration structure -void RH_RF95::setModemRegisters(const ModemConfig *config) -{ - spiWrite(RH_RF95_REG_1D_MODEM_CONFIG1, config->reg_1d); - spiWrite(RH_RF95_REG_1E_MODEM_CONFIG2, config->reg_1e); - spiWrite(RH_RF95_REG_26_MODEM_CONFIG3, config->reg_26); -} - -// Set one of the canned FSK Modem configs -// Returns true if its a valid choice -bool RH_RF95::setModemConfig(ModemConfigChoice index) -{ - if (index > (signed int)(sizeof(MODEM_CONFIG_TABLE) / sizeof(ModemConfig))) - return false; - - ModemConfig cfg; - memcpy_P(&cfg, &MODEM_CONFIG_TABLE[index], sizeof(RH_RF95::ModemConfig)); - setModemRegisters(&cfg); - - return true; -} - -void RH_RF95::setPreambleLength(uint16_t bytes) -{ - spiWrite(RH_RF95_REG_20_PREAMBLE_MSB, bytes >> 8); - spiWrite(RH_RF95_REG_21_PREAMBLE_LSB, bytes & 0xff); -} - -bool RH_RF95::isChannelActive() -{ - // Set 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; - } - - while (_mode == RHModeCad) - YIELD; - - return _cad; -} - -void RH_RF95::enableTCXO() -{ - 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)); - } -} - -// From section 4.1.5 of SX1276/77/78/79 -// Ferror = FreqError * 2**24 * BW / Fxtal / 500 -int RH_RF95::frequencyError() -{ - int32_t freqerror = 0; - - // Convert 2.5 bytes (5 nibbles, 20 bits) to 32 bit signed int - // Caution: some C compilers make errors with eg: - // freqerror = spiRead(RH_RF95_REG_28_FEI_MSB) << 16 - // so we go more carefully. - freqerror = spiRead(RH_RF95_REG_28_FEI_MSB); - freqerror <<= 8; - freqerror |= spiRead(RH_RF95_REG_29_FEI_MID); - freqerror <<= 8; - freqerror |= spiRead(RH_RF95_REG_2A_FEI_LSB); - // Sign extension into top 3 nibbles - if (freqerror & 0x80000) - freqerror |= 0xfff00000; - - int error = 0; // In hertz - float bw_tab[] = {7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250, 500}; - uint8_t bwindex = spiRead(RH_RF95_REG_1D_MODEM_CONFIG1) >> 4; - if (bwindex < (sizeof(bw_tab) / sizeof(float))) - error = (float)freqerror * bw_tab[bwindex] * ((float)(1L << 24) / (float)RH_RF95_FXOSC / 500.0); - // else not defined - - return error; -} - -int RH_RF95::lastSNR() -{ - return _lastSNR; -} - -/////////////////////////////////////////////////// -// -// additions below by Brian Norman 9th Nov 2018 -// brian.n.norman@gmail.com -// -// Routines intended to make changing BW, SF and CR -// a bit more intuitive -// -/////////////////////////////////////////////////// - -void RH_RF95::setSpreadingFactor(uint8_t sf) -{ - if (sf <= 6) - sf = RH_RF95_SPREADING_FACTOR_64CPS; - else if (sf == 7) - sf = RH_RF95_SPREADING_FACTOR_128CPS; - else if (sf == 8) - sf = RH_RF95_SPREADING_FACTOR_256CPS; - else if (sf == 9) - sf = RH_RF95_SPREADING_FACTOR_512CPS; - else if (sf == 10) - sf = RH_RF95_SPREADING_FACTOR_1024CPS; - else if (sf == 11) - sf = RH_RF95_SPREADING_FACTOR_2048CPS; - else if (sf >= 12) - sf = RH_RF95_SPREADING_FACTOR_4096CPS; - - // set the new spreading factor - spiWrite(RH_RF95_REG_1E_MODEM_CONFIG2, (spiRead(RH_RF95_REG_1E_MODEM_CONFIG2) & ~RH_RF95_SPREADING_FACTOR) | sf); - // check if Low data Rate bit should be set or cleared - setLowDatarate(); -} - -void RH_RF95::setSignalBandwidth(long sbw) -{ - uint8_t bw; // register bit pattern - - if (sbw <= 7800) - bw = RH_RF95_BW_7_8KHZ; - else if (sbw <= 10400) - bw = RH_RF95_BW_10_4KHZ; - else if (sbw <= 15600) - bw = RH_RF95_BW_15_6KHZ; - else if (sbw <= 20800) - bw = RH_RF95_BW_20_8KHZ; - else if (sbw <= 31250) - bw = RH_RF95_BW_31_25KHZ; - else if (sbw <= 41700) - bw = RH_RF95_BW_41_7KHZ; - else if (sbw <= 62500) - bw = RH_RF95_BW_62_5KHZ; - else if (sbw <= 125000) - bw = RH_RF95_BW_125KHZ; - else if (sbw <= 250000) - bw = RH_RF95_BW_250KHZ; - else - bw = RH_RF95_BW_500KHZ; - - // top 4 bits of reg 1D control bandwidth - spiWrite(RH_RF95_REG_1D_MODEM_CONFIG1, (spiRead(RH_RF95_REG_1D_MODEM_CONFIG1) & ~RH_RF95_BW) | bw); - // check if low data rate bit should be set or cleared - setLowDatarate(); -} - -void RH_RF95::setCodingRate4(uint8_t denominator) -{ - int cr = RH_RF95_CODING_RATE_4_5; - - // if (denominator <= 5) - // cr = RH_RF95_CODING_RATE_4_5; - if (denominator == 6) - cr = RH_RF95_CODING_RATE_4_6; - else if (denominator == 7) - cr = RH_RF95_CODING_RATE_4_7; - else if (denominator >= 8) - cr = RH_RF95_CODING_RATE_4_8; - - // CR is bits 3..1 of RH_RF95_REG_1D_MODEM_CONFIG1 - spiWrite(RH_RF95_REG_1D_MODEM_CONFIG1, (spiRead(RH_RF95_REG_1D_MODEM_CONFIG1) & ~RH_RF95_CODING_RATE) | cr); -} - -void RH_RF95::setLowDatarate() -{ - // called after changing bandwidth and/or spreading factor - // 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." - - // read current value for BW and SF - uint8_t BW = spiRead(RH_RF95_REG_1D_MODEM_CONFIG1) >> 4; // bw is in bits 7..4 - uint8_t SF = spiRead(RH_RF95_REG_1E_MODEM_CONFIG2) >> 4; // sf is in bits 7..4 - - // calculate symbol time (see Semtech AN1200.22 section 4) - float bw_tab[] = {7800, 10400, 15600, 20800, 31250, 41700, 62500, 125000, 250000, 500000}; - - float bandwidth = bw_tab[BW]; - - float symbolTime = 1000.0 * pow(2, SF) / bandwidth; // ms - - // the symbolTime for SF 11 BW 125 is 16.384ms. - // and, according to this :- - // https://www.thethingsnetwork.org/forum/t/a-point-to-note-lora-low-data-rate-optimisation-flag/12007 - // the LDR bit should be set if the Symbol Time is > 16ms - // So the threshold used here is 16.0ms - - // the LDR is bit 3 of RH_RF95_REG_26_MODEM_CONFIG3 - uint8_t current = spiRead(RH_RF95_REG_26_MODEM_CONFIG3) & ~RH_RF95_LOW_DATA_RATE_OPTIMIZE; // mask off the LDR bit - if (symbolTime > 16.0) - spiWrite(RH_RF95_REG_26_MODEM_CONFIG3, current | RH_RF95_LOW_DATA_RATE_OPTIMIZE); - else - spiWrite(RH_RF95_REG_26_MODEM_CONFIG3, current); -} - -void RH_RF95::setPayloadCRC(bool on) -{ - // Payload CRC is bit 2 of register 1E - uint8_t current = spiRead(RH_RF95_REG_1E_MODEM_CONFIG2) & ~RH_RF95_PAYLOAD_CRC_ON; // mask off the CRC - - if (on) - spiWrite(RH_RF95_REG_1E_MODEM_CONFIG2, current | RH_RF95_PAYLOAD_CRC_ON); - else - spiWrite(RH_RF95_REG_1E_MODEM_CONFIG2, current); -} diff --git a/src/rf95/RH_RF95.h b/src/rf95/RH_RF95.h deleted file mode 100644 index 3e0776036..000000000 --- a/src/rf95/RH_RF95.h +++ /dev/null @@ -1,890 +0,0 @@ -// RH_RF95.h -// -// Definitions for HopeRF LoRa radios per: -// http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf -// http://www.hoperf.cn/upload/rfchip/RF96_97_98.pdf -// -// 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 - -#include - -// This is the maximum number of interrupts the driver can support -// Most Arduinos can handle 2, Megas can handle more -#define RH_RF95_NUM_INTERRUPTS 3 - -// Max number of octets the LORA Rx/Tx FIFO can hold -#define RH_RF95_FIFO_SIZE 255 - -// This is the maximum number of bytes that can be carried by the LORA. -// We use some for headers, keeping fewer for RadioHead messages -#define RH_RF95_MAX_PAYLOAD_LEN RH_RF95_FIFO_SIZE - -// The length of the headers we add. -// 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. -// 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) -#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) - -// 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_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_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 - -// 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 - -// 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 - -// RH_RF95_REG_0B_OCP 0x0b -#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 - -// 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 - -// 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 - -// 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 - -// 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 - -// RH_RF95_REG_1D_MODEM_CONFIG1 0x1d -#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 - -// 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_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 - -// RH_RF95_REG_4B_TCXO 0x4b -#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 - -///////////////////////////////////////////////////////////////////// -/// \class RH_RF95 RH_RF95.h -/// \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. -/// Based on http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf -/// and http://www.hoperf.cn/upload/rfchip/RF96_97_98.pdf -/// and http://www.semtech.com/images/datasheet/LoraDesignGuide_STD.pdf -/// and http://www.semtech.com/images/datasheet/sx1276.pdf -/// and http://www.semtech.com/images/datasheet/sx1276_77_78_79.pdf -/// FSK/GFSK/OOK modes are not (yet) supported. -/// -/// Works with -/// - the excellent MiniWirelessLoRa from Anarduino http://www.anarduino.com/miniwireless -/// - 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 -/// 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, -/// 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 -/// -/// \par Overview -/// -/// 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, -/// mesh routers, repeaters, translators etc. -/// -/// 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 -/// RFM95/96/97/98(W), Semtech SX1276/77/78/79 and compatible radio modules in LoRa mode. -/// -/// The Hope-RF (http://www.hoperf.com) RFM95/96/97/98(W) and Semtech SX1276/77/78/79 is a low-cost ISM transceiver -/// chip. It supports FSK, GFSK, OOK over a wide range of frequencies and -/// programmable data rates, and it also supports the proprietary LoRA (Long Range) mode, which -/// is the only mode supported in this RadioHead driver. -/// -/// This Driver provides functions for sending and receiving messages of up -/// to 251 octets on any frequency supported by the radio, in a range of -/// predefined Bandwidths, Spreading Factors and Coding Rates. Frequency can be set with -/// 61Hz precision to any frequency from 240.0MHz to 960.0MHz. Caution: most modules only support a more limited -/// range of frequencies due to antenna tuning. -/// -/// Up to 2 modules can be connected to an Arduino (3 on a Mega), -/// permitting the construction of translators and frequency changers, etc. -/// -/// Support for other features such as transmitter power control etc is -/// also provided. -/// -/// Tested on MinWirelessLoRa with arduino-1.0.5 -/// on OpenSuSE 13.1. -/// Also tested with Teensy3.1, Modtronix inAir4 and Arduino 1.6.5 on OpenSuSE 13.1 -/// -/// \par Packet Format -/// -/// All messages sent and received by this RH_RF95 Driver conform to this packet format: -/// -/// - LoRa mode: -/// - 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 -/// - CRC (handled internally by the radio) -/// -/// \par Connecting RFM95/96/97/98 and Semtech SX1276/77/78/79 to Arduino -/// -/// We tested with Anarduino MiniWirelessLoRA, which is an Arduino Duemilanove compatible with a RFM96W -/// module on-board. Therefore it needs no connections other than the USB -/// programming connection and an antenna to make it work. -/// -/// If you have a bare RFM95/96/97/98 that you want to connect to an Arduino, you -/// might use these connections (untested): CAUTION: you must use a 3.3V type -/// 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) -/// 3V3----------3.3V (3.3V in) -/// interrupt 0 pin D2-----------DIO0 (interrupt request out) -/// SS pin D10----------NSS (CS chip select in) -/// SCK pin D13----------SCK (SPI clock in) -/// MOSI pin D11----------MOSI (SPI Data in) -/// MISO pin D12----------MISO (SPI Data out) -/// \endcode -/// With these connections, you can then use the default constructor RH_RF95(). -/// You can override the default settings for the SS pin and the interrupt in -/// the RH_RF95 constructor if you wish to connect the slave select SS to other -/// than the normal one for your Arduino (D10 for Diecimila, Uno etc and D53 -/// for Mega) or the interrupt request to other than pin D2 (Caution, -/// different processors have different constraints as to the pins available -/// for interrupts). -/// -/// You can connect a Modtronix inAir4 or inAir9 directly to a 3.3V part such as a Teensy 3.1 like -/// this (tested). -/// \code -/// Teensy inAir4 inAir9 -/// GND----------0V (ground in) -/// 3V3----------3.3V (3.3V in) -/// interrupt 0 pin D2-----------D0 (interrupt request out) -/// SS pin D10----------CS (CS chip select in) -/// SCK pin D13----------CK (SPI clock in) -/// MOSI pin D11----------SI (SPI Data in) -/// MISO pin D12----------SO (SPI Data out) -/// \endcode -/// With these connections, you can then use the default constructor RH_RF95(). -/// you must also set the transmitter power with useRFO: -/// driver.setTxPower(13, true); -/// -/// 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. -/// 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 -/// (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 -/// // Slave Select is pin 10, interrupt is Pin 3 -/// RH_RF95 driver(10, 3); -/// \endcode -/// -/// 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, -/// so you need to initialise the radio like this: -/// \code -/// RH_RF95 driver(5, 2); -/// \endcode -/// - The name of the serial port on that board is 'SerialUSB', not 'Serial', so this may be helpful at the top of our -/// sample sketches: -/// \code -/// #define Serial SerialUSB -/// \endcode -/// - 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); -/// digitalWrite(4, HIGH); -/// \endcode -/// - and if you have a 915MHz part, you need this after driver/manager intitalisation: -/// \code -/// rf95.setFrequency(915.0); -/// \endcode -/// which adds up to modifying sample sketches something like: -/// \code -/// #include -/// #include -/// RH_RF95 rf95(5, 2); // Rocket Scream Mini Ultra Pro with the RFM95W -/// #define Serial SerialUSB -/// -/// 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()) -/// Serial.println("init failed"); -/// rf95.setFrequency(915.0); -/// } -/// ... -/// \endcode -/// -/// For Adafruit Feather M0 with RFM95, construct the driver like this: -/// \code -/// RH_RF95 rf95(8, 3); -/// \endcode -/// -/// 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 -/// RH_RF95 driver; -/// \endcode -/// -/// It is possible to have 2 or more radios connected to one Arduino, provided -/// each radio has its own SS and interrupt line (SCK, SDI and SDO are common -/// to all radios) -/// -/// Caution: on some Arduinos such as the Mega 2560, if you set the slave -/// select pin to be other than the usual SS pin (D53 on Mega 2560), you may -/// 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: -/// 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 -/// other shields demanding power. Inadequate power for the RFM is likely to cause symptoms such as: -/// - reset's/bootups terminate with "init failed" messages -/// - random termination of communication after 5-30 packets sent/received -/// - "fake ok" state, where initialization passes fluently, but communication doesn't happen -/// - shields hang Arduino boards, especially during the flashing -/// -/// \par Interrupts -/// -/// The RH_RF95 driver uses interrupts to react to events in the RFM module, -/// such as the reception of a new packet, or the completion of transmission -/// of a packet. The RH_RF95 driver interrupt service routine reads status from -/// and writes data to the the RFM module via the SPI interface. It is very -/// important therefore, that if you are using the RH_RF95 driver with another -/// SPI based deviced, that you disable interrupts while you transfer data to -/// and from that other device. Use cli() to disable interrupts and sei() to -/// reenable them. -/// -/// \par Memory -/// -/// The RH_RF95 driver requires non-trivial amounts of memory. The sample -/// programs all compile to about 8kbytes each, which will fit in the -/// flash proram memory of most Arduinos. However, the RAM requirements are -/// 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. -/// The symptoms can include: -/// - Mysterious crashes and restarts -/// - Changes in behaviour when seemingly unrelated changes are made (such as adding print() statements) -/// - Hanging -/// - Output from Serial.print() not appearing -/// -/// \par Range -/// -/// We have made some simple range tests under the following conditions: -/// - rf95_client base station connected to a VHF discone antenna at 8m height above ground -/// - rf95_server mobile connected to 17.3cm 1/4 wavelength antenna at 1m height, no ground plane. -/// - Both configured for 13dBm, 434MHz, Bw = 125 kHz, Cr = 4/8, Sf = 4096chips/symbol, CRC on. Slow+long range -/// - Minimum reported RSSI seen for successful comms was about -91 -/// - Range over flat ground through heavy trees and vegetation approx 2km. -/// - At 20dBm (100mW) otherwise identical conditions approx 3km. -/// - At 20dBm, along salt water flat sandy beach, 3.2km. -/// -/// 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. -/// (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 -/// 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 -/// with the RH_RF95::setTxPower() function. The argument can be any of -/// +5 to +23 (for modules that use PA_BOOST) -/// -1 to +14 (for modules that use RFO transmitter pin) -/// The default is 13. Eg: -/// \code -/// driver.setTxPower(10); // use PA_BOOST transmitter pin -/// driver.setTxPower(10, true); // use PA_RFO pin transmitter pin -/// \endcode -/// -/// We have made some actual power measurements against -/// programmed power for Anarduino MiniWirelessLoRa (which has RFM96W-433Mhz installed) -/// - MiniWirelessLoRa RFM96W-433Mhz, USB power -/// - 30cm RG316 soldered direct to RFM96W module ANT and GND -/// - SMA connector -/// - 12db attenuator -/// - SMA connector -/// - MiniKits AD8307 HF/VHF Power Head (calibrated against Rohde&Schwartz 806.2020 test set) -/// - Tektronix TDS220 scope to measure the Vout from power head -/// \code -/// Program power Measured Power -/// dBm dBm -/// 5 5 -/// 7 7 -/// 9 8 -/// 11 11 -/// 13 13 -/// 15 15 -/// 17 16 -/// 19 18 -/// 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 -/// connected to a Teensy 3.1: -/// Teensy 3.1 this is a 3.3V part, connected directly to: -/// Modtronix inAir4 with SMA antenna connector, connected as above: -/// 10cm SMA-SMA cable -/// - MiniKits AD8307 HF/VHF Power Head (calibrated against Rohde&Schwartz 806.2020 test set) -/// - Tektronix TDS220 scope to measure the Vout from power head -/// \code -/// Program power Measured Power -/// dBm dBm -/// -1 0 -/// 1 2 -/// 3 4 -/// 5 7 -/// 7 10 -/// 9 13 -/// 11 14.2 -/// 13 15 -/// 14 16 -/// \endcode -/// (Caution: we dont claim laboratory accuracy for these power measurements) -/// 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: - /// \brief Defines register values for a set of modem configuration registers - /// - /// Defines register values for a set of modem configuration registers - /// that can be passed to setModemRegisters() if none of the choices in - /// 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 - } 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 - /// 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 - /// 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 - } ModemConfigChoice; - - /// Constructor. You can have multiple instances, but each instance must have its own - /// interrupt and slave select pin. After constructing, you must call init() to initialise the interface - /// and the radio module. A maximum of 3 instances can co-exist on one processor, provided there are sufficient - /// 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. - /// 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. - /// 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. - /// Defaults to the standard Arduino hardware SPI interface - 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(); - - /// 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 - /// 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(); - - /// Prints the value of all chip registers - /// to the Serial device if RH_HAVE_SERIAL is defined for the current platform - /// For debugging purposes only. - /// \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 - /// canned configurations in ModemConfigChoice suit you. - /// \param[in] config A ModemConfig structure containing values for the modem configuration registers. - void setModemRegisters(const ModemConfig *config); - - /// 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); - - /// Tests whether a new message is available - /// 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(); - - /// Sets the length of the preamble - /// 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); - - /// Returns the maximum message length - /// available in this Driver. - /// \return The maximum legal message length - virtual uint8_t maxMessageLength(); - - /// 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); - - /// If current mode is Rx or Tx changes it to Idle. If the transmitter or receiver is running, - /// disables them. - void setModeIdle(); - - /// If current mode is Tx or Idle, changes it to Rx. - /// Starts the receiver in the RF95/96/97/98. - 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(); - - /// 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) - /// use the PA_BOOST transmitter pin for high power output (and optionally the PA_DAC) - /// 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 - /// 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, - /// valid values are from +5 to +23. - /// 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); - - /// Sets the radio into low-power sleep mode. - /// 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(); - - // Bent G Christensen (bentor@gmail.com), 08/15/2016 - /// Use the radio's Channel Activity Detect (CAD) function to detect channel activity. - /// Sets the RF95 radio into CAD mode and waits until CAD detection is complete. - /// 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(); - - /// Enable TCXO mode - /// 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. - /// Leaves the module in sleep mode. - /// Caution, this function has not been tested by us. - /// Caution, the TCXO model radios are not low power when in sleep (consuming - /// about ~600 uA, reported by Phang Moh Lim.
- void enableTCXO(); - - /// 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. - /// 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 - /// register RH_RF95_REG_1D_MODEM_CONFIG1 is invalid, returns 0. - int frequencyError(); - - /// Returns the Signal-to-noise ratio (SNR) of the last received message, as measured - /// by the receiver. - /// \return SNR of the last received message in dB - int lastSNR(); - - /// brian.n.norman@gmail.com 9th Nov 2018 - /// Sets the radio spreading factor. - /// valid values are 6 through 12. - /// Out of range values below 6 are clamped to 6 - /// Out of range values above 12 are clamped to 12 - /// See Semtech DS SX1276/77/78/79 page 27 regarding SF6 configuration. - /// - /// \param[in] uint8_t sf (spreading factor 6..12) - /// \return nothing - 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:- - /// sbw range actual bw (kHz) - /// 0-7800 7.8 - /// 7801-10400 10.4 - /// 10401-15600 15.6 - /// 15601-20800 20.8 - /// 20801-31250 31.25 - /// 31251-41700 41.7 - /// 41701-62500 62.5 - /// 62501-12500 125.0 - /// 12501-250000 250.0 - /// >250000 500.0 - /// 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); - - /// 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); - - /// 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(); - - /// 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(); - - void loop(); // Perform idle processing - - 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. - virtual void handleInterrupt(); - - /// This is the only code called in ISR context, it just queues up our helper thread to run handleInterrupt(); - void RH_INTERRUPT_ATTR handleInterruptLevel0(); - - /// Examine the revceive buffer to determine whether the message is for this node - void validateRxBuf(); - - /// Clear our local receive buffer - void clearRxBuf(); - - /// 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(); - - /// Low level interrupt service routine for device connected to interrupt 1 - static void isr1(); - - /// Low level interrupt service routine for device connected to interrupt 1 - static void isr2(); - - /// Array of instances connected to interrupts 0 and 1 - static RH_RF95 *_deviceForInterrupt[]; - - /// Index of next interrupt number to use in _deviceForInterrupt - static uint8_t _interruptCount; - - bool enableInterrupt(); // enable our IRQ - void disableInterrupt(); // disable our IRQ - - volatile bool pendingInterrupt = false; - - /// The configured interrupt pin connected to this instance - uint8_t _interruptPin; - - /// The index into _deviceForInterrupt[] for this device (if an interrupt is already allocated) - /// else 0xff - uint8_t _myInterruptIndex; - - // True if we are using the HF port (779.0 MHz and above) - bool _usingHFport; - - // Last measured SNR, dB - int8_t _lastSNR; - - protected: - /// Number of octets in the buffer - volatile uint8_t _bufLen; - - /// The receiver/transmitter buffer - uint8_t _buf[RH_RF95_MAX_PAYLOAD_LEN]; - - /// True when there is a valid message in the buffer - volatile bool _rxBufValid; -}; - -/// @example rf95_client.pde -/// @example rf95_server.pde -/// @example rf95_encrypted_client.pde -/// @example rf95_encrypted_server.pde -/// @example rf95_reliable_datagram_client.pde -/// @example rf95_reliable_datagram_server.pde - -#endif diff --git a/src/rf95/RHutil/atomic.h b/src/rf95/RHutil/atomic.h deleted file mode 100644 index 019219827..000000000 --- a/src/rf95/RHutil/atomic.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -* This is port of Dean Camera's ATOMIC_BLOCK macros for AVR to ARM Cortex M3 -* v1.0 -* Mark Pendrith, Nov 27, 2012. -* -* From Mark: -* >When I ported the macros I emailed Dean to ask what attribution would be -* >appropriate, and here is his response: -* > -* >>Mark, -* >>I think it's great that you've ported the macros; consider them -* >>public domain, to do with whatever you wish. I hope you find them >useful . -* >> -* >>Cheers! -* >>- Dean -*/ - -#ifdef __arm__ -#ifndef _CORTEX_M3_ATOMIC_H_ -#define _CORTEX_M3_ATOMIC_H_ - -static __inline__ uint32_t __get_primask(void) \ -{ uint32_t primask = 0; \ - __asm__ volatile ("MRS %[result], PRIMASK\n\t":[result]"=r"(primask)::); \ - return primask; } // returns 0 if interrupts enabled, 1 if disabled - -static __inline__ void __set_primask(uint32_t setval) \ -{ __asm__ volatile ("MSR PRIMASK, %[value]\n\t""dmb\n\t""dsb\n\t""isb\n\t"::[value]"r"(setval):); - __asm__ volatile ("" ::: "memory");} - -static __inline__ uint32_t __iSeiRetVal(void) \ -{ __asm__ volatile ("CPSIE i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \ - __asm__ volatile ("" ::: "memory"); return 1; } - -static __inline__ uint32_t __iCliRetVal(void) \ -{ __asm__ volatile ("CPSID i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \ - __asm__ volatile ("" ::: "memory"); return 1; } - -static __inline__ void __iSeiParam(const uint32_t *__s) \ -{ __asm__ volatile ("CPSIE i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \ - __asm__ volatile ("" ::: "memory"); (void)__s; } - -static __inline__ void __iCliParam(const uint32_t *__s) \ -{ __asm__ volatile ("CPSID i\n\t""dmb\n\t""dsb\n\t""isb\n\t"); \ - __asm__ volatile ("" ::: "memory"); (void)__s; } - -static __inline__ void __iRestore(const uint32_t *__s) \ -{ __set_primask(*__s); __asm__ volatile ("dmb\n\t""dsb\n\t""isb\n\t"); \ - __asm__ volatile ("" ::: "memory"); } - - -#define ATOMIC_BLOCK(type) \ -for ( type, __ToDo = __iCliRetVal(); __ToDo ; __ToDo = 0 ) - -#define ATOMIC_RESTORESTATE \ -uint32_t primask_save __attribute__((__cleanup__(__iRestore))) = __get_primask() - -#define ATOMIC_FORCEON \ -uint32_t primask_save __attribute__((__cleanup__(__iSeiParam))) = 0 - -#define NONATOMIC_BLOCK(type) \ -for ( type, __ToDo = __iSeiRetVal(); __ToDo ; __ToDo = 0 ) - -#define NONATOMIC_RESTORESTATE \ -uint32_t primask_save __attribute__((__cleanup__(__iRestore))) = __get_primask() - -#define NONATOMIC_FORCEOFF \ -uint32_t primask_save __attribute__((__cleanup__(__iCliParam))) = 0 - -#endif -#endif diff --git a/src/rf95/RadioHead.h b/src/rf95/RadioHead.h deleted file mode 100644 index ed1551ff4..000000000 --- a/src/rf95/RadioHead.h +++ /dev/null @@ -1,1595 +0,0 @@ -// RadioHead.h -// Author: Mike McCauley (mikem@airspayce.com) DO NOT CONTACT THE AUTHOR DIRECTLY -// Copyright (C) 2014 Mike McCauley -// $Id: RadioHead.h,v 1.80 2020/01/05 07:02:23 mikem Exp mikem $ - -/*! \mainpage RadioHead Packet Radio library for embedded microprocessors - -This is the RadioHead Packet Radio library for embedded microprocessors. -It provides a complete object-oriented library for sending and receiving packetized messages -via a variety of common data radios and other transports on a range of embedded microprocessors. - -The version of the package that this documentation refers to can be downloaded -from http://www.airspayce.com/mikem/arduino/RadioHead/RadioHead-1.98.zip -You can find the latest version of the documentation at http://www.airspayce.com/mikem/arduino/RadioHead - -You can also find online help and discussion at -http://groups.google.com/group/radiohead-arduino -Please use that group for all questions and discussions on this topic. -Do not contact the author directly, unless it is to discuss commercial licensing. -Before asking a question or reporting a bug, please read -- http://en.wikipedia.org/wiki/Wikipedia:Reference_desk/How_to_ask_a_software_question -- http://www.catb.org/esr/faqs/smart-questions.html -- http://www.chiark.greenend.org.uk/~shgtatham/bugs.html - -Caution: Developing this type of software and using data radios -successfully is challenging and requires a substantial knowledge -base in software and radio and data transmission technologies and -theory. It may not be an appropriate project for beginners. If -you are a beginner, you will need to spend some time gaining -knowledge in these areas first. - -\par Overview - -RadioHead consists of 2 main sets of classes: Drivers and Managers. - -- Drivers provide low level access to a range of different packet radios and other packetized message transports. -- Managers provide high level message sending and receiving facilities for a range of different requirements. - -Every RadioHead program will have an instance of a Driver to -provide access to the data radio or transport, and usually a -Manager that uses that driver to send and receive messages for the -application. The programmer is required to instantiate a Driver -and a Manager, and to initialise the Manager. Thereafter the -facilities of the Manager can be used to send and receive -messages. - -It is also possible to use a Driver on its own, without a Manager, although this only allows unaddressed, -unreliable transport via the Driver's facilities. - -In some specialised use cases, it is possible to instantiate more than one Driver and more than one Manager. - -A range of different common embedded microprocessor platforms are supported, allowing your project to run -on your choice of processor. - -Example programs are included to show the main modes of use. - -\par Drivers - -The following Drivers are provided: - -- RH_RF22 -Works with Hope-RF -RF22B and RF23B based transceivers, and compatible chips and modules, -including the RFM22B transceiver module such as -hthis bare module: http://www.sparkfun.com/products/10153 -and this shield: http://www.sparkfun.com/products/11018 -and this board: http://www.anarduino.com/miniwireless -and RF23BP modules such as: http://www.anarduino.com/details.jsp?pid=130 -Supports GFSK, FSK and OOK. Access to other chip -features such as on-chip temperature measurement, analog-digital -converter, transmitter power control etc is also provided. - -- RH_RF24 -Works with Silicon Labs Si4460/4461/4463/4464 family of transceivers chip, and the equivalent -HopeRF RF24/26/27 family of chips and the HopeRF RFM24W/26W/27W modules. -Supports GFSK, FSK and OOK. Access to other chip -features such as on-chip temperature measurement, analog-digital -converter, transmitter power control etc is also provided. - -- RH_RF69 -Works with Hope-RF -RF69B based radio modules, such as the RFM69 module, (as used on the excellent Moteino and Moteino-USB -boards from LowPowerLab http://lowpowerlab.com/moteino/ ) -and compatible chips and modules such as RFM69W, RFM69HW, RFM69CW, RFM69HCW (Semtech SX1231, SX1231H). -Also works with Anarduino MiniWireless -CW and -HW boards http://www.anarduino.com/miniwireless/ including -the marvellous high powered MinWireless-HW (with 20dBm output for excellent range). -Supports GFSK, FSK. - -- RH_NRF24 -Works with Nordic nRF24 based 2.4GHz radio modules, such as nRF24L01 and others. -Also works with Hope-RF RFM73 -and compatible devices (such as BK2423). nRF24L01 and RFM73 can interoperate -with each other. - -- RH_NRF905 -Works with Nordic nRF905 based 433/868/915 MHz radio modules. - -- RH_NRF51 -Works with Nordic nRF51 compatible 2.4 GHz SoC/devices such as the nRF51822. -Also works with Sparkfun nRF52832 breakout board, with Arduino 1.6.13 and -Sparkfun nRF52 boards manager 0.2.3. Caution: although RadioHead compiles with nRF52832 as at 2019-06-06 -there appears to be a problem with the support of interupt handlers in the Sparkfun support libraries, -and drivers (ie most of the SPI based radio drivers) that require interrupts do not work correctly. - -- RH_RF95 -Works with Semtech SX1276/77/78/79, Modtronix inAir4 and inAir9, -and HopeRF RFM95/96/97/98 and other similar LoRa capable radios. -Supports Long Range (LoRa) with spread spectrum frequency hopping, large payloads etc. -FSK/GFSK/OOK modes are not (yet) supported. - -- RH_MRF89 -Works with Microchip MRF89XA and compatible transceivers. -and modules such as MRF89XAM9A. - -- RH_CC110 -Works with Texas Instruments CC110L transceivers and compatible modules such as -Anaren AIR BoosterPack 430BOOST-CC110L - -- RH_E32 -Works with EBYTE E32-TTL-1W serial radio transceivers (and possibly other transceivers in the same family) - -- RH_ASK -Works with a range of inexpensive ASK (amplitude shift keying) RF transceivers such as RX-B1 -(also known as ST-RX04-ASK) receiver; TX-C1 transmitter and DR3100 transceiver; FS1000A/XY-MK-5V transceiver; -HopeRF RFM83C / RFM85. Supports ASK (OOK). - -- RH_Serial -Works with RS232, RS422, RS485, RS488 and other point-to-point and multidropped serial connections, -or with TTL serial UARTs such as those on Arduino and many other processors, -or with data radios with a -serial port interface. RH_Serial provides packetization and error detection over any hardware or -virtual serial connection. Also builds and runs on Linux and OSX. - -- RH_TCP -For use with simulated sketches compiled and running on Linux. -Works with tools/etherSimulator.pl to pass messages between simulated sketches, allowing -testing of Manager classes on Linux and without need for real radios or other transport hardware. - -- RHEncryptedDriver -Adds encryption and decryption to any RadioHead transport driver, using any encrpytion cipher -supported by ArduinoLibs Cryptographic Library http://rweather.github.io/arduinolibs/crypto.html - -Drivers can be used on their own to provide unaddressed, unreliable datagrams. -All drivers have the same identical API. -Or you can use any Driver with any of the Managers described below. - -We welcome contributions of well tested and well documented code to support other transports. - -If your radio or transciever is not on the list above, there is a good chance it -wont work without modifying RadioHead to suit it. If you wish for -support for another radio or transciever, and you send 2 of them to -AirSpayce Pty Ltd, we will consider adding support for it. - -\par Managers - -The drivers above all provide for unaddressed, unreliable, variable -length messages, but if you need more than that, the following -Managers are provided: - -- RHDatagram -Addressed, unreliable variable length messages, with optional broadcast facilities. - -- RHReliableDatagram -Addressed, reliable, retransmitted, acknowledged variable length messages. - -- RHRouter -Multi-hop delivery of RHReliableDatagrams from source node to destination node via 0 or more -intermediate nodes, with manual, pre-programmed routing. - -- RHMesh -Multi-hop delivery of RHReliableDatagrams with automatic route discovery and rediscovery. - -Any Manager may be used with any Driver. - -\par Platforms - -A range of processors and platforms are supported: - -- Arduino and the Arduino IDE (version 1.0 to 1.8.1 and later) -Including Diecimila, Uno, Mega, Leonardo, Yun, Due, Zero etc. http://arduino.cc/, Also similar boards such as - - Moteino http://lowpowerlab.com/moteino/ - - Anarduino Mini http://www.anarduino.com/mini/ - - RedBearLab Blend V1.0 http://redbearlab.com/blend/ (with Arduino 1.0.5 and RedBearLab Blend Add-On version 20140701) - - MoteinoMEGA https://lowpowerlab.com/shop/moteinomega - (with Arduino 1.0.5 and the MoteinoMEGA Arduino Core - https://github.com/LowPowerLab/Moteino/tree/master/MEGA/Core) - - ESP8266 on Arduino IDE and Boards Manager per https://github.com/esp8266/Arduino - Tested using Arduino 1.6.8 with esp8266 by ESP8266 Community version 2.1.0 - Also Arduino 1.8.1 with esp8266 by SparkFun Electronics 2.5.2 - Examples serial_reliable_datagram_* and ask_* are shown to work. - CAUTION: The GHz radio included in the ESP8266 is - not yet supported. - CAUTION: tests here show that when powered by an FTDI USB-Serial converter, - the ESP8266 can draw so much power when transmitting on its GHz WiFi that VCC will sag - causing random crashes. We strongly recommend a large cap, say 1000uF 10V on VCC if you are also using the WiFi. - - Various Talk2 Whisper boards eg https://wisen.com.au/store/products/whisper-node-lora. - Use Arduino Board Manager to install the Talk2 code support. - - etc. - -- STM32 F4 Discover board, using Arduino 1.8.2 or later and - Roger Clarkes Arduino_STM from https://github.com/rogerclarkmelbourne/Arduino_STM32 - Caution: with this library and board, sending text to Serial causes the board to hang in mysterious ways. - Serial2 emits to PA2. The default SPI pins are SCK: PB3, MOSI PB5, MISO PB4. - We tested with PB0 as slave select and PB1 as interrupt pin for various radios. RH_ASK and RH_Serial also work. - -- ChipKIT Core with Arduino IDE on any ChipKIT Core supported Digilent processor (tested on Uno32) - http://chipkit.net/wiki/index.php?title=ChipKIT_core - -- Maple and Flymaple boards with libmaple and the Maple-IDE development environment - http://leaflabs.com/devices/maple/ and http://www.open-drone.org/flymaple - -- Teensy including Teensy 3.1 and earlier built using Arduino IDE 1.0.5 to 1.6.4 and later with - teensyduino addon 1.18 to 1.23 and later. - http://www.pjrc.com/teensy - -- Particle Photon https://store.particle.io/collections/photon and ARM3 based CPU with built-in - Wi-Fi transceiver and extensive IoT software suport. RadioHead does not support the built-in transceiver - but can be used to control other SPI based radios, Serial ports etc. - See below for details on how to build RadioHead for Photon - -- ATTiny built using Arduino IDE 1.8 and the ATTiny core from - https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json - using the instructions at - https://medium.com/jungletronics/attiny85-easy-flashing-through-arduino-b5f896c48189 - (Caution: these are very small processors and not all RadioHead features may be available, depending on memory requirements) - (Caution: we have not had good success building RH_ASK sketches for ATTiny 85 with SpenceKonde ATTinyCore) - -- AtTiny Mega chips supported by Spencer Konde's megaTinyCore (https://github.com/SpenceKonde/megaTinyCore) - (on Arduino 1.8.9 or later) such as AtTiny 3216, AtTiny 1616 etc. These chips can be easily programmed through their - UPDI pin, using an ordinary Arduino board programmed as a jtag2updi programmer as described in - https://github.com/SpenceKonde/megaTinyCore/blob/master/MakeUPDIProgrammer.md. - Make sure you set the programmer type to jtag2updi in the Arduino Tools->Programmer menu. - See https://github.com/SpenceKonde/megaTinyCore/blob/master/megaavr/extras/ImportantInfo.md for links to pinouts - and pin numbering information for all the suported chips. - -- nRF51 compatible Arm chips such as nRF51822 with Arduino 1.6.4 and later using the procedures - in http://redbearlab.com/getting-started-nrf51822/ - -- nRF52 compatible Arm chips such as as Adafruit BLE Feather board - https://www.adafruit.com/product/3406 - -- Adafruit Feather. These are excellent boards that are available with a variety of radios. We tested with the - Feather 32u4 with RFM69HCW radio, with Arduino IDE 1.6.8 and the Adafruit AVR Boards board manager version 1.6.10. - https://www.adafruit.com/products/3076 - -- Adafruit Feather M0 boards with Arduino 1.8.1 and later, using the Arduino and Adafruit SAMD board support. - https://learn.adafruit.com/adafruit-feather-m0-basic-proto/using-with-arduino-ide - -- ESP32 built using Arduino IDE 1.8.9 or later using the ESP32 toolchain installed per - https://github.com/espressif/arduino-esp32 - The internal 2.4GHz radio is not yet supported. Tested with RFM22 using SPI interface - -- Raspberry Pi - Uses BCM2835 library for GPIO http://www.airspayce.com/mikem/bcm2835/ - Currently works only with RH_NRF24 driver or other drivers that do not require interrupt support. - Contributed by Mike Poublon. - -- Linux and OSX - Using the RHutil/HardwareSerial class, the RH_Serial driver and any manager will - build and run on Linux and OSX. These can be used to build programs that talk securely and reliably to - Arduino and other processors or to other Linux or OSX hosts on a reliable, error detected (and possibly encrypted) datagram - protocol over various types of serial line. - -- Mongoose OS, courtesy Paul Austen. Mongoose OSis an Internet of Things Firmware Development Framework - available under Apache License Version 2.0. It supports low power, connected microcontrollers such as: - ESP32, ESP8266, TI CC3200, TI CC3220, STM32. - https://mongoose-os.com/ - -Other platforms are partially supported, such as Generic AVR 8 bit processors, MSP430. -We welcome contributions that will expand the range of supported platforms. - -If your processor is not on the list above, there is a good chance it -wont work without modifying RadioHead to suit it. If you wish for -support for another processor, and you send 2 of them to -AirSpayce Pty Ltd, we will consider adding support for it. - -RadioHead is available (through the efforts of others) -for PlatformIO. PlatformIO is a cross-platform code builder and the missing library manager. -http://platformio.org/#!/lib/show/124/RadioHead - -\par History - -RadioHead was created in April 2014, substantially based on code from some of our other earlier Radio libraries: - -- RHMesh, RHRouter, RHReliableDatagram and RHDatagram are derived from the RF22 library version 1.39. -- RH_RF22 is derived from the RF22 library version 1.39. -- RH_RF69 is derived from the RF69 library version 1.2. -- RH_ASK is based on the VirtualWire library version 1.26, after significant conversion to C++. -- RH_Serial was new. -- RH_NRF24 is based on the NRF24 library version 1.12, with some significant changes. - -During this combination and redevelopment, we have tried to retain all the processor dependencies and support from -the libraries that were contributed by other people. However not all platforms can be tested by us, so if you -find that support from some platform has not been successfully migrated, please feel free to fix it and send us a -patch. - -Users of RHMesh, RHRouter, RHReliableDatagram and RHDatagram in the previous RF22 library will find that their -existing code will run mostly without modification. See the RH_RF22 documentation for more details. - -\par Installation - -Install in the usual way: unzip the distribution zip file to the libraries -sub-folder of your sketchbook. -The example sketches will be visible in in your Arduino, mpide, maple-ide or whatever. -http://arduino.cc/en/Guide/Libraries - -\par Building for Particle Photon - -The Photon is not supported by the Arduino IDE, so it takes a little effort to set up a build environment. -Heres what we did to enable building of RadioHead example sketches on Linux, -but there are other ways to skin this cat. -Basic reference for getting started is: http://particle-firmware.readthedocs.org/en/develop/build/ -- Download the ARM gcc cross compiler binaries and unpack it in a suitable place: -\code -cd /tmp -wget https://launchpad.net/gcc-arm-embedded/5.0/5-2015-q4-major/+download/gcc-arm-none-eabi-5_2-2015q4-20151219-linux.tar.bz2 -tar xvf gcc-arm-none-eabi-5_2-2015q4-20151219-linux.tar.bz2 -\endcode -- If dfu-util and friends not installed on your platform, download dfu-util and friends to somewhere in your path -\code -cd ~/bin -wget http://dfu-util.sourceforge.net/releases/dfu-util-0.8-binaries/linux-i386/dfu-util -wget http://dfu-util.sourceforge.net/releases/dfu-util-0.8-binaries/linux-i386/dfu-suffix -wget http://dfu-util.sourceforge.net/releases/dfu-util-0.8-binaries/linux-i386/dfu-prefix -\endcode -- Download the Particle firmware (contains headers and libraries require to compile Photon sketches) - to a suitable place: -\code -cd /tmp -wget https://github.com/spark/firmware/archive/develop.zip -unzip develop.zip -\endcode -- Make a working area containing the RadioHead library source code and your RadioHead sketch. You must - rename the sketch from .pde or .ino to application.cpp -\code -cd /tmp -mkdir RadioHead -cd RadioHead -cp /usr/local/projects/arduino/libraries/RadioHead/ *.h . -cp /usr/local/projects/arduino/libraries/RadioHead/ *.cpp . -cp /usr/local/projects/arduino/libraries/RadioHead/examples/cc110/cc110_client/cc110_client.pde application.cpp -\endcode -- Edit application.cpp and comment out any \#include so it looks like: -\code - // #include -\endcode -- Connect your Photon by USB. Put it in DFU mode as descibed in Photon documentation. Light should be flashing yellow -- Compile the RadioHead sketch and install it as the user program (this does not update the rest of the - Photon firmware, just the user part: -\code -cd /tmp/firmware-develop/main -PATH=$PATH:/tmp/gcc-arm-none-eabi-5_2-2015q4/bin make APPDIR=/tmp/RadioHead all PLATFORM=photon program-dfu -\endcode -- You should see RadioHead compile without errors and download the finished sketch into the Photon. - -\par Compatible Hardware Suppliers - -We have had good experiences with the following suppliers of RadioHead compatible hardware: - -- LittleBird http://littlebirdelectronics.com.au in Australia for all manner of Arduinos and radios. -- LowPowerLab http://lowpowerlab.com/moteino in USA for the excellent Moteino and Moteino-USB - boards which include Hope-RF RF69B radios on-board. -- Anarduino and HopeRF USA (http://www.hoperfusa.com and http://www.anarduino.com) who have a wide range - of HopeRF radios and Arduino integrated modules. -- SparkFun https://www.sparkfun.com/ in USA who design and sell a wide range of Arduinos and radio modules. -- Wisen http://wisen.com.au who design and sell a wide range of integrated radio/processor modules including the - excellent Talk2 range. - -\par Coding Style - -RadioHead is designed so it can run on small processors with very -limited resources and strict timing contraints. As a result, we -tend only to use the simplest and least demanding (in terms of memory and CPU) C++ -facilities. In particular we avoid as much as possible dynamic -memory allocation, and the use of complex objects like C++ -strings, IO and buffers. We are happy with this, but we are aware -that some people may think we are leaving useful tools on the -table. You should not use this code as an example of how to do -generalised C++ programming on well resourced processors. - -\par Donations - -This library is offered under a free GPL license for those who want to use it that way. -We try hard to keep it up to date, fix bugs -and to provide free support. If this library has helped you save time or money, please consider donating at -http://www.airspayce.com or here: - -\htmlonly
\endhtmlonly - -\subpage packingdata "Passing Sensor Data Between RadioHead nodes" - -\par Trademarks - -RadioHead is a trademark of AirSpayce Pty Ltd. The RadioHead mark was first used on April 12 2014 for -international trade, and is used only in relation to data communications hardware and software and related services. -It is not to be confused with any other similar marks covering other goods and services. - -\par Copyright - -This software is Copyright (C) 2011-2018 Mike McCauley. Use is subject to license -conditions. The main licensing options available are GPL V2 or Commercial: - -\par Open Source Licensing GPL V2 - -This is the appropriate option if you want to share the source code of your -application with everyone you distribute it to, and you also want to give them -the right to share who uses it. If you wish to use this software under Open -Source Licensing, you must contribute all your source code to the open source -community in accordance with the GPL Version 2 when your application is -distributed. See https://www.gnu.org/licenses/gpl-2.0.html - -\par Commercial Licensing - -This is the appropriate option if you are creating proprietary applications -and you are not prepared to distribute and share the source code of your -application. To purchase a commercial license, contact info@airspayce.com - -\par Revision History -\version 1.1 2014-04-14
- Initial public release -\version 1.2 2014-04-23
- Fixed various typos.
- Added links to compatible Anarduino products.
- Added RHNRFSPIDriver, RH_NRF24 classes to support Nordic NRF24 based radios. -\version 1.3 2014-04-28
- Various documentation fixups.
- RHDatagram::setThisAddress() did not set the local copy of thisAddress. Reported by Steve Childress.
- Fixed a problem on Teensy with RF22 and RF69, where the interrupt pin needs to be set for input,
- else pin interrupt doesn't work properly. Reported by Steve Childress and patched by - Adrien van den Bossche. Thanks.
- Fixed a problem that prevented RF22 honouring setPromiscuous(true). Reported by Steve Childress.
- Updated documentation to clarify some issues to do with maximum message lengths - reported by Steve Childress.
- Added support for yield() on systems that support it (currently Arduino 1.5.5 and later) - so that spin-loops can suport multitasking. Suggested by Steve Childress.
- Added RH_RF22::setGpioReversed() so the reversal it can be configured at run-time after - radio initialisation. It must now be called _after_ init(). Suggested by Steve Childress.
-\version 1.4 2014-04-29
- Fixed further problems with Teensy compatibility for RH_RF22. Tested on Teensy 3.1. - The example/rf22_* examples now run out of the box with the wiring connections as documented for Teensy - in RH_RF22.
- Added YIELDs to spin-loops in RHRouter, RHMesh and RHReliableDatagram, RH_NRF24.
- Tested RH_Serial examples with Teensy 3.1: they now run out of the box.
- Tested RH_ASK examples with Teensy 3.1: they now run out of the box.
- Reduced default SPI speed for NRF24 from 8MHz to 1MHz on Teensy, to improve reliability when - poor wiring is in use.
- on some devices such as Teensy.
- Tested RH_NRF24 examples with Teensy 3.1: they now run out of the box.
-\version 1.5 2014-04-29
- Added support for Nordic Semiconductor nRF905 transceiver with RH_NRF905 driver. Also - added examples for nRF905 and tested on Teensy 3.1 -\version 1.6 2014-04-30
- NRF905 examples were missing -\version 1.7 2014-05-03
- Added support for Arduino Due. Tested with RH_NRF905, RH_Serial, RH_ASK. - IMPORTANT CHANGE to interrupt pins on Arduino with RH_RF22 and RH_RF69 constructors: - previously, you had to specify the interrupt _number_ not the interrupt _pin_. Arduinos and Uno32 - are now consistent with all other platforms: you must specify the interrupt pin number. Default - changed to pin 2 (a common choice with RF22 shields). - Removed examples/maple/maple_rf22_reliable_datagram_client and - examples/maple/maple_rf22_reliable_datagram_client since the rf22 examples now work out - of the box with Flymaple. - Removed examples/uno32/uno32_rf22_reliable_datagram_client and - examples/uno32/uno32_rf22_reliable_datagram_client since the rf22 examples now work out - of the box with ChipKit Uno32. -\version 1.8 2014-05-08
- Added support for YIELD in Teensy 2 and 3, suggested by Steve Childress.
- Documentation updates. Clarify use of headers and Flags
- Fixed misalignment in RH_RF69 between ModemConfigChoice definitions and the implemented choices - which meant you didnt get the choice you thought and GFSK_Rb55555Fd50 hung the transmitter.
- Preliminary work on Linux simulator. -\version 1.9 2014-05-14
- Added support for using Timer 2 instead of Timer 1 on Arduino in RH_ASK when - RH_ASK_ARDUINO_USE_TIMER2 is defined. With the kind assistance of - Luc Small. Thanks!
- Updated comments in RHReliableDatagram concerning servers, retries, timeouts and delays. - Fixed an error in RHReliableDatagram where recvfrom return value was not checked. - Reported by Steve Childress.
- Added Linux simulator support so simple RadioHead sketches can be compiled and run on Linux.
- Added RH_TCP driver to permit message passing between simulated sketches on Linux.
- Added example simulator sketches.
- Added tools/etherSimulator.pl, a simulator of the 'Luminiferous Ether' that passes - messages between simulated sketches and can simulate random message loss etc.
- Fixed a number of typos and improved some documentation.
-\version 1.10 2014-05-15
- Added support for RFM73 modules to RH_NRF24. These 2 radios are very similar, and can interoperate - with each other. Added new RH_NRF24::TransmitPower enums for the RFM73, which has a different - range of available powers
- reduced the default SPI bus speed for RH_NRF24 to 1MHz, since so many modules and CPU have problems - with 8MHz.
-\version 1.11 2014-05-18
- Testing RH_RF22 with RFM23BP and 3.3V Teensy 3.1 and 5V Arduinos. - Updated documentation with respect to GPIO and antenna - control pins for RFM23. Updated documentation with respect to transmitter power control for RFM23
- Fixed a problem with RH_RF22 driver, where GPIO TX and RX pins were not configured during - initialisation, causing poor transmit power and sensitivity on those RF22/RF23 devices where GPIO controls - the antenna selection pins. -\version 1.12 2014-05-20
- Testing with RF69HW and the RH_RF69 driver. Works well with the Anarduino MiniWireless -CW and -HW - boards http://www.anarduino.com/miniwireless/ including - the marvellous high powered MinWireless-HW (with 20dBm output for excellent range).
- Clarified documentation of RH_RF69::setTxPower values for different models of RF69.
- Added RHReliableDatagram::resetRetransmissions().
- Retransmission count precision increased to uin32_t.
- Added data about actual power measurements from RFM22 module.
-\version 1.13 2014-05-23
- setHeaderFlags(flags) changed to setHeaderFlags(set, clear), enabling any flags to be - individually set and cleared by either RadioHead or application code. Requested by Steve Childress.
- Fixed power output setting for boost power on RF69HW for 18, 19 and 20dBm.
- Added data about actual power measurements from RFM69W and RFM69HW modules.
-\version 1.14 2014-05-26
- RH_RF69::init() now always sets the PA boost back to the default settings, else can get invalid - PA power modes after uploading new sketches without a power cycle. Reported by Bryan.
- Added new macros RH_VERSION_MAJOR RH_VERSION_MINOR, with automatic maintenance in Makefile.
- Improvements to RH_TCP: constructor now honours the server argument in the form "servername:port".
- Added YIELD to RHReliableDatagram::recvfromAckTimeout. Requested by Steve Childress.
- Fixed a problem with RH_RF22 reliable datagram acknowledgements that was introduced in version 1.13. - Reported by Steve Childress.
-\version 1.15 2014-05-27
- Fixed a problem with the RadioHead .zip link. -\version 1.16 2014-05-30
- Fixed RH_RF22 so that lastRssi() returns the signal strength in dBm. Suggested by Steve Childress.
- Added support for getLastPreambleTime() to RH_RF69. Requested by Steve Childress.
- RH_NRF24::init() now checks if there is a device connected and responding, else init() will fail. - Suggested by Steve Brown.
- RHSoftwareSPI now initialises default values for SPI pins MOSI = 12, MISO = 11 and SCK = 13.
- Fixed some problems that prevented RH_NRF24 working with mixed software and hardware SPI - on different devices: a race condition - due to slow SPI transfers and fast acknowledgement.
-\version 1.17 2014-06-02
- Fixed a debug typo in RHReliableDatagram that was introduced in 1.16.
- RH_NRF24 now sets default power, data rate and channel in init(), in case another - app has previously set different values without powerdown.
- Caution: there are still problems with RH_NRF24 and Software SPI. Do not use.
-\version 1.18 2014-06-02
- Improvements to performance of RH_NRF24 statusRead, allowing RH_NRF24 and Software SPI - to operate on slow devices like Arduino Uno.
-\version 1.19 2014-06-19
- Added examples ask_transmitter.pde and ask_receiver.pde.
- Fixed an error in the RH_RF22 doc for connection of Teensy to RF22.
- Improved documentation of start symbol bit patterns in RH_ASK.cpp -\version 1.20 2014-06-24
- Fixed a problem with compiling on platforms such as ATTiny where SS is not defined.
- Added YIELD to RHMesh::recvfromAckTimeout().
-\version 1.21 2014-06-24
- Fixed an issue in RH_Serial where characters might be lost with back-to-back frames. - Suggested by Steve Childress.
- Brought previous RHutil/crc16.h code into mainline RHCRC.cpp to prevent name collisions - with other similarly named code in other libraries. Suggested by Steve Childress.
- Fix SPI bus speed errors on 8MHz Arduinos. -\version 1.22 2014-07-01
- Update RH_ASK documentation for common wiring connections.
- Testing RH_ASK with HopeRF RFM83C/RFM85 courtesy Anarduino http://www.anarduino.com/
- Testing RH_NRF24 with Itead Studio IBoard Pro http://imall.iteadstudio.com/iboard-pro.html - using both hardware SPI on the ITDB02 Parallel LCD Module Interface pins and software SPI - on the nRF24L01+ Module Interface pins. Documented wiring required.
- Added support for AVR 1284 and 1284p, contributed by Peter Scargill. - Added support for Semtech SX1276/77/78 and HopeRF RFM95/96/97/98 and other similar LoRa capable radios - in LoRa mode only. Tested with the excellent MiniWirelessLoRa from - Anarduino http://www.anarduino.com/miniwireless
-\version 1.23 2014-07-03
- Changed the default modulation for RH_RF69 to GFSK_Rb250Fd250, since the previous default - was not very reliable.
- Documented RH_RF95 range tests.
- Improvements to RH_RF22 RSSI readings so that lastRssi correctly returns the last message in dBm.
-\version 1.24 2014-07-18 - Added support for building RadioHead for STM32F4 Discovery boards, using the native STM Firmware libraries, - in order to support Codec2WalkieTalkie (http://www.airspayce.com/mikem/Codec2WalkieTalkie) - and other projects. See STM32ArduinoCompat.
- Default modulation for RH_RF95 was incorrectly set to a very slow Bw125Cr48Sf4096 -\version 1.25 2014-07-25 - The available() function will longer terminate any current transmission, and force receive mode. - Now, if there is no unprocessed incoming message and an outgoing message is currently being transmitted, - available() will return false.
- RHRouter::sendtoWait(uint8_t*, uint8_t, uint8_t, uint8_t) renamed to sendtoFromSourceWait due to conflicts - with new sendtoWait() with optional flags.
- RHMEsh and RHRouter already supported end-to-end application layer flags, but RHMesh::sendtoWait() - and RHRouter::sendToWait have now been extended to expose a way to send optional application layer flags. -\version 1.26 2014-08-12 - Fixed a Teensy 2.0 compile problem due yield() not available on Teensy < 3.0.
- Adjusted the algorithm of RH_RF69::temperatureRead() to more closely reflect reality.
- Added functions to RHGenericDriver to get driver packet statistics: rxBad(), rxGood(), txGood().
- Added RH_RF69::printRegisters().
- RH_RF95::printRegisters() was incorrectly printing the register index instead of the address. - Reported by Phang Moh Lim.
- RH_RF95, added definitions for some more registers that are usable in LoRa mode.
- RH_RF95::setTxPower now uses RH_RF95_PA_DAC_ENABLE to achieve 21, 22 and 23dBm.
- RH_RF95, updated power output measurements.
- Testing RH_RF69 on Teensy 3.1 with RF69 on PJRC breakout board. OK.
- Improvements so RadioHead will build under Arduino where SPI is not supported, such as - ATTiny.
- Improvements so RadioHead will build for ATTiny using Arduino IDE and tinycore arduino-tiny-0100-0018.zip.
- Testing RH_ASK on ATTiny85. Reduced RAM footprint. - Added helpful documentation. Caution: RAM memory is *very* tight on this platform.
- RH_RF22 and RH_RF69, added setIdleMode() function to allow the idle mode radio operating state - to be controlled for lower idle power consumption at the expense of slower transitions to TX and RX.
-\version 1.27 2014-08-13 - All RH_RF69 modulation schemes now have data whitening enabled by default.
- Tested and added a number of OOK modulation schemes to RH_RF69 Modem config table.
- Minor improvements to a number of the faster RH_RF69 modulation schemes, but some slower ones - are still not working correctly.
-\version 1.28 2014-08-20 - Added new RH_RF24 driver to support Si446x, RF24/26/26, RFM24/26/27 family of transceivers. - Tested with the excellent - Anarduino Mini and RFM24W and RFM26W with the generous assistance of the good people at - Anarduino http://www.anarduino.com. -\version 1.29 2014-08-21 - Fixed a compile error in RH_RF24 introduced at the last minute in hte previous release.
- Improvements to RH_RF69 modulation schemes: now include the AFCBW in teh ModemConfig.
- ModemConfig RH_RF69::FSK_Rb2Fd5 and RH_RF69::GFSK_Rb2Fd5 are now working.
-\version 1.30 2014-08-25 - Fixed some compile problems with ATtiny84 on Arduino 1.5.5 reported by Glen Cook.
-\version 1.31 2014-08-27 - Changed RH_RF69 FSK and GFSK modulations from Rb2_4Fd2_4 to Rb2_4Fd4_8 and FSK_Rb4_8Fd4_8 to FSK_Rb4_8Fd9_6 - since the previous ones were unreliable (they had modulation indexes of 1).
-\version 1.32 2014-08-28 - Testing with RedBearLab Blend board http://redbearlab.com/blend/. OK.
- Changed more RH_RF69 FSK and GFSK slowish modulations to have modulation index of 2 instead of 1. - This required chnaging the symbolic names.
-\version 1.33 2014-09-01 - Added support for sleep mode in RHGeneric driver, with new mode - RHModeSleep and new virtual function sleep().
- Added support for sleep to RH_RF69, RH_RF22, RH_NRF24, RH_RF24, RH_RF95 drivers.
-\version 1.34 2014-09-19 - Fixed compile errors in example rf22_router_test.
- Fixed a problem with RH_NRF24::setNetworkAddress, also improvements to RH_NRF24 register printing. - Patched by Yveaux.
- Improvements to RH_NRF24 initialisation for version 2.0 silicon.
- Fixed problem with ambigiguous print call in RH_RFM69 when compiling for Codec2.
- Fixed a problem with RH_NRF24 on RFM73 where the LNA gain was not set properly, reducing the sensitivity - of the receiver. -\version 1.35 2014-09-19 - Fixed a problem with interrupt setup on RH_RF95 with Teensy3.1. Reported by AD.
-\version 1.36 2014-09-22 - Improvements to interrupt pin assignments for __AVR_ATmega1284__ and__AVR_ATmega1284P__, provided by - Peter Scargill.
- Work around a bug in Arduino 1.0.6 where digitalPinToInterrupt is defined but NOT_AN_INTERRUPT is not.
- \version 1.37 2014-10-19 - Updated doc for connecting RH_NRF24 to Arduino Mega.
- Changes to RHGenericDriver::setHeaderFlags(), so that the default for the clear argument - is now RH_FLAGS_APPLICATION_SPECIFIC, which is less surprising to users. - Testing with the excellent MoteinoMEGA from LowPowerLab - https://lowpowerlab.com/shop/moteinomega with on-board RFM69W. - \version 1.38 2014-12-29 - Fixed compile warning on some platforms where RH_RF24::send and RH_RF24::writeTxFifo - did not return a value.
- Fixed some more compiler warnings in RH_RF24 on some platforms.
- Refactored printRegisters for some radios. Printing to Serial - is now controlled by the definition of RH_HAVE_SERIAL.
- Added partial support for ARM M4 w/CMSIS with STM's Hardware Abstraction lib for - Steve Childress.
- \version 1.39 2014-12-30 - Fix some compiler warnings under IAR.
- RH_HAVE_SERIAL and Serial.print calls removed for ATTiny platforms.
- \version 1.40 2015-03-09 - Added notice about availability on PlatformIO, thanks to Ivan Kravets.
- Fixed a problem with RH_NRF24 where short packet lengths would occasionally not be trasmitted - due to a race condition with RH_NRF24_TX_DS. Reported by Mark Fox.
- \version 1.41 2015-03-29 - RH_RF22, RH_RF24, RH_RF69 and RH_RF95 improved to allow driver.init() to be called multiple - times without reallocating a new interrupt, allowing the driver to be reinitialised - after sleeping or powering down. - \version 1.42 2015-05-17 - Added support for RH_NRF24 driver on Raspberry Pi, using BCM2835 - library for GPIO pin IO. Contributed by Mike Poublon.
- Tested RH_NRF24 module with NRF24L01+PA+LNA SMA Antenna Wireless Transceiver modules - similar to: http://www.elecfreaks.com/wiki/index.php?title=2.4G_Wireless_nRF24L01p_with_PA_and_LNA - works with no software changes. Measured max power output 18dBm.
- \version 1.43 2015-08-02 - Added RH_NRF51 driver to support Nordic nRF51 family processor with 2.4GHz radio such - as nRF51822, to be built on Arduino 1.6.4 and later. Tested with RedBearLabs nRF51822 board - and BLE Nano kit
- \version 1.44 2015-08-08 - Fixed errors with compiling on some platforms without serial, such as ATTiny. - Reported by Friedrich Müller.
- \version 1.45 2015-08-13 - Added support for using RH_Serial on Linux and OSX (new class RHutil/HardwareSerial - encapsulates serial ports on those platforms). Example examples/serial upgraded - to build and run on Linux and OSX using the tools/simBuild builder. - RHMesh, RHRouter and RHReliableDatagram updated so they can use RH_Serial without - polling loops on Linux and OSX for CPU efficiency.
- \version 1.46 2015-08-14 - Amplified some doc concerning Linux and OSX RH_Serial. Added support for 230400 - baud rate in HardwareSerial.
- Added sample sketches nrf51_audio_tx and nrf51_audio_rx which show how to - build an audio TX/RX pair with RedBear nRF51822 boards and a SparkFun MCP4725 DAC board. - Uses the built-in ADC of the nRF51822 to sample audio at 5kHz and transmit packets - to the receiver which plays them via the DAC.
-\version 1.47 2015-09-18 - Removed top level Makefile from distribution: its only used by the developer and - its presence confuses some people.
- Fixed a problem with RHReliableDatagram with some versions of Raspberry Pi random() that causes - problems: random(min, max) sometimes exceeds its max limit. -\version 1.48 2015-09-30 - Added support for Arduino Zero. Tested on Arduino Zero Pro. -\version 1.49 2015-10-01 - Fixed problems that prevented interrupts working correctly on Arduino Zero and Due. - Builds and runs with 1.6.5 (with 'Arduino SAMD Boards' for Zero version 1.6.1) from arduino.cc. - Arduino version 1.7.7 from arduino.org is not currently supported. -\version 1.50 2015-10-25 - Verified correct building and operation with Arduino 1.7.7 from arduino.org. - Caution: You must burn the bootloader from 1.7.7 to the Arduino Zero before it will - work with Arduino 1.7.7 from arduino.org. Conversely, you must burn the bootloader from 1.6.5 - to the Arduino Zero before it will - work with Arduino 1.6.5 from arduino.cc. Sigh. - Fixed a problem with RH_NRF905 that prevented the power and frequency ranges being set - properly. Reported by Alan Webber. -\version 1.51 2015-12-11 - Changes to RH_RF6::setTxPower() to be compatible with SX1276/77/78/79 modules that - use RFO transmitter pins instead of PA_BOOST, such as the excellent - Modtronix inAir4 http://modtronix.com/inair4.html - and inAir9 modules http://modtronix.com/inair9.html. With the kind assistance of - David from Modtronix. -\version 1.52 2015-12-17 - Added RH_MRF89 module to suport Microchip MRF89XA and compatible transceivers. - and modules.
-\version 1.53 2016-01-02 - Added RH_CC110 module to support Texas Instruments CC110L and compatible transceivers and modules.
-\version 1.54 2016-01-29 - Added support for ESP8266 processor on Arduino IDE. Examples serial_reliable_datagram_* are shown to work. - CAUTION: SPI not supported yet. Timers used by RH_ASK are not tested. - The GHz radio included in the ESP8266 is not yet supported. -\version 1.55 2016-02-12 - Added macros for htons() and friends to RadioHead.h. - Added example sketch serial_gateway.pde. Acts as a transparent gateway between RH_RF22 and RH_Serial, - and with minor mods acts as a universal gateway between any 2 RadioHead driver networks. - Initial work on supporting STM32 F2 on Particle Photon: new platform type defined. - Fixed many warnings exposed by test building for Photon. - Particle Photon tested support for RH_Serial, RH_ASK, SPI, RH_CC110 etc. - Added notes on how to build RadioHead sketches for Photon. -\version 1.56 2016-02-18 - Implemented timers for RH_ASK on ESP8266, added some doc on IO pin selection. -\version 1.57 2016-02-23 - Fixed an issue reported by S3B, where RH_RF22 would sometimes not clear the rxbufvalid flag. -\version 1.58 2-16-04-04 - Tested RH_RF69 with Arduino Due. OK. Updated doc.
- Added support for all ChipKIT Core supported boards - http://chipkit.net/wiki/index.php?title=ChipKIT_core - Tested on ChipKIT Uno32.
- Digilent Uno32 under the old MPIDE is no longer formally - supported but may continue to work for some time.
-\version 1.59 2016-04-12 - Testing with the excellent Rocket Scream Mini Ultra Pro with the RFM95W and RFM69HCW modules from - http://www.rocketscream.com/blog/product/mini-ultra-pro-with-radio/ (915MHz versions). Updated - documentation with hints to suit. Caution: requires Arduino 1.6.8 and Arduino SAMD Boards 1.6.5. - See also http://www.rocketscream.com/blog/2016/03/10/radio-range-test-with-rfm69hcw/ - for the vendors tests and range with the RFM69HCW version. They also have an RF95 version equipped with - TCXO temperature controllled oscillator for extra frequency stability and support of very slow and - long range protocols. - These boards are highly recommended. They also include battery charging support. -\version 1.60 2016-06-25 - Tested with the excellent talk2 Whisper Node boards - (https://talk2.wisen.com.au/ and https://bitbucket.org/talk2/), - an Arduino Nano compatible board, which include an on-board RF69 radio, external antenna, - run on 2xAA batteries and support low power operations. RF69 examples work without modification. - Added support for ESP8266 SPI, provided by David Skinner. -\version 1.61 2016-07-07 - Patch to RH_ASK.cpp for ESP8266, to prevent crashes in interrupt handlers. Patch from Alexander Mamchits. -\version 1.62 2016-08-17 - Fixed a problem in RH_ASK where _rxInverted was not properly initialised. Reported by "gno.sun.sop". - Added support for waitCAD() and isChannelActive() and setCADTimeout() to RHGeneric. - Implementation of RH_RF95::isChannelActive() allows the RF95 module to support - Channel Activity Detection (CAD). Based on code contributed by Bent Guldbjerg Christensen. - Implmentations of isChannelActive() plus documentation for other radio modules wil be welcomed. -\version 1.63 2016-10-20 - Testing with Adafruit Feather 32u4 with RFM69HCW. Updated documentation to reflect.
-\version 1.64 2016-12-10 - RHReliableDatagram now initialises _seenids. Fix from Ben Lim.
- In RH_NRF51, added get_temperature().
- In RH_NRF51, added support for AES packet encryption, which required a slight change - to the on-air message format.
-\version 1.65 2017-01-11 - Fixed a race condition with RH_NRF51 that prevented ACKs being reliably received.
- Removed code in RH_NRF51 that enabled the DC-DC converter. This seems not to be a necessary condition - for the radio to work and is now left to the application if that is required.
- Proven interoperation between nRF51822 and nRF52832.
- Modification and testing of RH_NRF51 so it works with nRF52 family processors, - such Sparkfun nRF52832 breakout board, with Arduino 1.6.13 and - Sparkfun nRF52 boards manager 0.2.3 using the procedures outlined in - https://learn.sparkfun.com/tutorials/nrf52832-breakout-board-hookup-guide
- Caution, the Sparkfun development system for Arduino is still immature. We had to - rebuild the nrfutil program since the supplied one was not suitable for - the Linux host we were developing on. See https://forum.sparkfun.com/viewtopic.php?f=32&t=45071 - Also, after downloading a sketch in the nRF52832, the program does not start executing cleanly: - you have to reset the processor again by pressing the reset button. - This appears to be a problem with nrfutil, rather than a bug in RadioHead. -\version 1.66 2017-01-15 - Fixed some errors in (unused) register definitions in RH_RF95.h.
- Fixed a problem that caused compilation errors in RH_NRF51 if the appropriate board - support was not installed. -\version 1.67 2017-01-24 - Added RH_RF95::frequencyError() to return the estimated centre frequency offset in Hz - of the last received message -\version 1.68 2017-01-25 - Fixed arithmetic error in RH_RF95::frequencyError() for some platforms. -\version 1.69 2017-02-02 - Added RH_RF95::lastSNR() and improved lastRssi() calculations per the manual. -\version 1.70 2017-02-03 - Added link to Binpress commercial license purchasing. -\version 1.71 2017-02-07 - Improved support for STM32. Patch from Bent Guldbjerg Christensen. -\version 1.72 2017-03-02 - In RH_RF24, fixed a problem where some important properties were not set by the ModemConfig. - Added properties 2007, 2008, 2009. Also properties 200a was not being set in the chip. - Reported by Shannon Bailey and Alan Adamson. - Fixed corresponding convert.pl and added it to the distribution. -\version 1.73 2017-03-04 - Significant changes to RH_RF24 and its API. It is no longer possible to change the modulation scheme - programatically: it proved impossible to cater for all the possible crystal frequencies, - base frequency and modulation schemes. Instead you can use one of a small set of supplied radio - configuration header files, or generate your own with Silicon Labs WDS application. Changing - modulation scheme required editing RH_RF24.cpp to specify the appropriate header and recompiling. - convert.pl is now redundant and removed from the distribution. -\version 1.74 2017-03-08 - Changed RHReliableDatagram so it would not ACK messages heard addressed to other nodes - in promiscuous mode.
- Added RH_RF24::deviceType() to return the integer value of the connected device.
- Added documentation about how to connect RFM69 to an ESP8266. Tested OK.
- RH_RF24 was not correctly changing state in sleep() and setModeIdle().
- Added example rf24_lowpower_client.pde showing how to put an arduino and radio into a low power - mode between transmissions to save battery power.
- Improvements to RH_RF69::setTxPower so it now takes an optional ishighpowermodule - flag to indicate if the connected module is a high power RFM69HW, and so set the power level - correctly. Based on code contributed by bob. -\version 1.75 2017-06-22 - Fixed broken compiler issues with RH_RF95::frequencyError() reported by Steve Rogerson.
- Testing with the very excellent Rocket Scream boards equipped with RF95 TCXO modules. The - temperature controlled oscillator stabilises the chip enough to be able to use even the slowest - protocol Bw125Cr48Sf4096. Caution, the TCXO model radios are not low power when in sleep (consuming - about ~600 uA, reported by Phang Moh Lim).
- Added support for EBYTE E32-TTL-1W and family serial radio transceivers. These RF95 LoRa based radios - can deliver reliable messages at up to 7km measured. -\version 1.76 2017-06-23 - Fixed a problem with RH_RF95 hanging on transmit under some mysterious circumstances. - Reported by several people at https://forum.pjrc.com/threads/41878-Probable-race-condition-in-Radiohead-library?p=146601#post146601
- Increased the size of rssi variables to 16 bits to permit RSSI less than -128 as reported by RF95. -\version 1.77 2017-06-25 - Fixed a compilation error with lastRssi().
-\version 1.78 2017-07-19 - Fixed a number of unused variable warnings from g++.
- Added new module RHEncryptedDriver and examples, contributed by Philippe Rochat, which - adds encryption and decryption to any RadioHead transport driver, using any encryption cipher - supported by ArduinoLibs Cryptographic Library http://rweather.github.io/arduinolibs/crypto.html - Includes several examples.
-\version 1.79 2017-07-25 - Added documentation about 'Passing Sensor Data Between RadioHead nodes'.
- Changes to RH_CC110 driver to calculate RSSI in dBm, based on a patch from Jurie Pieterse.
- Added missing passthroughmethoids to RHEncryptedDriver, allowing it to be used with RHDatagram, - RHReliableDatagram etc. Tested with RH_Serial. Added examples -\version 1.80 2017-10-04 - Testing with 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, - 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.
- Added support for SPI transactions in development environments that support it with SPI_HAS_TRANSACTION. - Tested on ESP32 with RFM-22 and Teensy 3.1 with RF69 - Added support for ESP32, tested with RFM-22 connected by SPI.
-\version 1.81 2017-11-15 - RH_CC110, moved setPaTable() from protected to public.
- RH_RF95 modem config Bw125Cr48Sf4096 altered to enable slow daat rate in register 26 - as suggested by Dieter Kneffel. - Added support for nRF52 compatible Arm chips such as as Adafruit BLE Feather board - https://www.adafruit.com/product/3406, with a patch from Mike Bell.
- Fixed a problem where rev 1.80 broke Adafruit M0 LoRa support by declaring - bitOrder variable always as a unsigned char. Reported by Guilherme Jardim.
- In RH_RF95, all modes now have AGC enabled, as suggested by Dieter Kneffel.
-\version 1.82 2018-01-07 - Added guard code to RH_NRF24::waitPacketSent() so that if the transmit never completes for some - reason, the code will eventually return with FALSE. - Added the low-datarate-optimization bit to config for RH_RF95::Bw125Cr48Sf4096. - Fix from Jurie Pieterse to ensure RH_CC110::sleep always enters sleep mode. - Update ESP32 support to include ASK timers. RH_ASK module is now working on ESP32. -\version 1.83 2018-02-12 - Testing adafruit M0 Feather with E32. Updated RH_E32 documentation to show suggested connections - and contructor initialisation.
- Fixed a problem with RHEncryptedDriver that could cause a crash on some platforms when used - with RHReliableDatagram. Reported by Joachim Baumann.
- Improvments to doxygen doc layout in RadioHead.h -\version 1.84 2018-05-07 - Compiles with Roger Clarkes Arduino_STM32 https://github.com/rogerclarkmelbourne/Arduino_STM32, - to support STM32F103C etc, and STM32 F4 Discovery etc.
- Tested STM32 F4 Discovery board with RH_RF22, RH_ASK and RH_Serial. - -\version 1.85 2018-07-09 - RHGenericDriver methods changed to virtual, to allow overriding by RHEncrypredDriver: - lastRssi(), mode(), setMode(). Reported by Eyal Gal.
- Fixed a problem with compiling RH_E32 on some older IDEs, contributed by Philippe Rochat.
- Improvements to RH_RF95 to improve detection of bad packets, contributed by PiNi.
- Fixed an error in RHEncryptedDriver that caused incorrect message lengths for messages multiples of 16 bytes - when STRICT_CONTENT_LEN is defined.
- Fixed a bug in RHMesh which causes the creation of a route to the address which is the byte - behind the end of the route array. Reported by Pascal Gillès de Pélichy.
-\version 1.86 2018-08-28 - Update commercial licensing, remove binpress. -\version 1.87 2018-10-06 - RH_RF22 now resets all registers to default state before initialisation commences. Suggested by Wothke.
- Added RH_ENABLE_EXPLICIT_RETRY_DEDUP which improves the handling of duplicate detection especiually - in the case where a transmitter periodically wakes up and start tranmitting from the first sequence number. - Patch courtesy Justin Newitter. Thanks. -\version 1.88 2018-11-13 - Updated to support ATTiny using instructions in - https://medium.com/jungletronics/attiny85-easy-flashing-through-arduino-b5f896c48189 - Updated examples ask_transmitter and ask_receiver to compile cleanly on ATTiny. - Tested using ATTiny85 and Arduino 1.8.1.
-\version 1.89 2018-11-15 - Testing with ATTiny core from https://github.com/SpenceKonde/ATTinyCore and RH_ASK, - using example ask_transmitter. This resulted in 'Low Memory, instability may occur', - and the resulting sketch would transmit only one packet. Suggest ATTiny users do not use this core, but use - the one from https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json - as described in https://medium.com/jungletronics/attiny85-easy-flashing-through-arduino-b5f896c48189
- Added support for RH_RF95::setSpreadingFactor(), RH_RF95::setSignalBandwidth(), RH_RF95::setLowDatarate() and - RH_RF95::setPayloadCRC(). Patch from Brian Norman. Thanks.
- -\version 1.90 2019-05-21 - Fixed a block size error in RhEncryptedDriver for the case when - using STRICT_CONTENT_LEN and sending messages of exactly _blockcipher.blockSize() bytes in length. - Reported and patched by Philippe Rochat. - Patch from Samuel Archibald to prevent compile errors with RH_AAK.cpp fo ATSAMD51. - Fixed a probem in RH_RF69::setSyncWords that prevented setSyncWords(NULL, 0) correctly - disabling sync detection and generation. Reported by Federico Maggi. - RHHardwareSPI::usingInterrupt() was a noop. Fixed to call SPI.usingInterrupt(interrupt);. - -\version 1.91 2019-06-01 - Fixed a problem with new RHHardwareSPI::usingInterrupt() that prevented compilation on ESP8266 - which does not have that call. - -\version 1.92 2019-07-14 - Retested serial_reliable_datagram_client.pde and serial_reliable_datagram_server.pde built on Linux - as described in their headers, and with USB-RS485 adapters. No changes, working correctly. - Testing of nRF5232 with Sparkfun nRF52 board support 0.2.3 shows that there appears to be a problem with - interrupt handlers on this board, and none of the interrupt based radio drivers can be expected to work - with this chip. - Ensured all interrupt routines are flagged with ICACHE_RAM_ATTR when compiled for ESP8266, to prevent crashes. - -\version 1.94 2019-09-02 - Fixed a bug in RHSoftwareSPI where RHGenericSPI::setBitOrder() has no effect for - on RHSoftwareSPI. Reported by Peter.
- Added support in RHRouter for a node to optionally be leaf node, and not participate as a router in the - network. See RHRouter::setNodeTypePatch from Alex Evans.
- Fixed a problem with ESP32 causing compile errors over missing SPI.usingInterrupt().
- -\version 1.95 2019-10-14 - Fixed some typos in RH_RF05.h macro definitions reported by Clayton Smith.
- Patch from Michael Cain from RH_ASK on ESP32, untested by me.
- Added support for RPi Zero and Zero W for the RF95, contributed by Brody Mahoney. - Not tested by me.
- -\version 1.96 2019-10-14 - Added examples for RPi Zero and Zero W to examples/raspi/rf95, contributed by Brody Mahoney - not tested by me.
- -\version 1.97 2019-11-02 - Added support for Mongoose OS, contributed by Paul Austen. - -\version 1.98 2020-01-06 - Rationalised use of RH_PLATFORM_ATTINY to be consistent with other platforms.
- Added support for RH_PLATFORM_ATTINY_MEGA, for use with Spencer Konde's megaTinyCore - https://github.com/SpenceKonde/megaTinyCore on Atmel megaAVR AtTiny chips. - Tested with AtTiny 3217, 3216 and 1614, using - RH_Serial, RH_ASK, and RH_RF22 drivers.
- - -\author Mike McCauley. DO NOT CONTACT THE AUTHOR DIRECTLY. USE THE GOOGLE LIST GIVEN ABOVE -*/ - -/*! \page packingdata -\par Passing Sensor Data Between RadioHead nodes - -People often ask about how to send data (such as numbers, sensor -readings etc) from one RadioHead node to another. Although this issue -is not specific to RadioHead, and more properly lies in the area of -programming for networks, we will try to give some guidance here. - -One reason for the uncertainty and confusion in this area, especially -amongst beginners, is that there is no *best* way to do it. The best -solution for your project may depend on the range of processors and -data that you have to deal with. Also, it gets more difficult if you -need to send several numbers in one packet, and/or deal with floating -point numbers and/or different types of processors. - -The principal cause of difficulty is that different microprocessors of -the kind that run RadioHead may have different ways of representing -binary data such as integers. Some processors are little-endian and -some are big-endian in the way they represent multi-byte integers -(https://en.wikipedia.org/wiki/Endianness). And different processors -and maths libraries may represent floating point numbers in radically -different ways: -(https://en.wikipedia.org/wiki/Floating-point_arithmetic) - -All the RadioHead examples show how to send and receive simple ASCII -strings, and if thats all you want, refer to the examples folder in -your RadioHead distribution. But your needs may be more complicated -than that. - -The essence of all engineering is compromise so it will be up to you to -decide whats best for your particular needs. The main choices are: -- Raw Binary -- Network Order Binary -- ASCII - -\par Raw Binary - -With this technique you just pack the raw binary numbers into the packet: - -\code -// Sending a single 16 bit unsigned integer -// in the transmitter: -... -uint16_t data = getsomevalue(); -if (!driver.send((uint8_t*)&data, sizeof(data))) -{ - ... -\endcode - -\code -// and in the receiver: -... -uint16_t data; -uint8_t datalen = sizeof(data); -if ( driver.recv((uint8_t*)&data, &datalen) - && datalen == sizeof(data)) -{ - // Have the data, so do something with it - uint16_t xyz = data; - ... -\endcode - -If you need to send more than one number at a time, its best to pack -them into a structure - -\code -// Sending several 16 bit unsigned integers in a structure -// in a common header for your project: -typedef struct -{ - uint16_t dataitem1; - uint16_t dataitem2; -} MyDataStruct; -... -\endcode - -\code -// In the transmitter -... -MyDataStruct data; -data.dataitem1 = getsomevalue(); -data.dataitem2 = getsomeothervalue(); -if (!driver.send((uint8_t*)&data, sizeof(data))) -{ - ... -\endcode - -\code -// in the receiver -MyDataStruct data; -uint8_t datalen = sizeof(data); -if ( driver.recv((uint8_t*)&data, &datalen) - && datalen == sizeof(data)) -{ - // Have the data, so do something with it - uint16_t pqr = data.dataitem1; - uint16_t xyz = data.dataitem2; - .... -\endcode - - -The disadvantage with this simple technique becomes apparent if your -transmitter and receiver have different endianness: the integers you -receive will not be the same as the ones you sent (actually they are, -but with the internal bytes swapped around, so they probably wont make -sense to you). Endianness is not a problem if *every* data item you -send is a just single byte (uint8_t or int8_t or char), or if the -transmitter and receiver have the same endianness. - -So you should only adopt this technique if: -- You only send data items of a single byte each, or -- You are absolutely sure (now and forever into the future) that you -will only ever use the same processor endianness in the transmitter and receiver. - -\par Network Order Binary - -One solution to the issue of endianness in your processors is to -always convert your data from the processor's native byte order to -'network byte order' before transmission and then convert it back to -the receiver's native byte order on reception. You do this with the -htons (host to network short) macro and friends. These functions may -be a no-op on big-endian processors. - -With this technique you convert every multi-byte number to and from -network byte order (note that in most Arduino processors an integer is -in fact a short, and is the same as int16_t. We prefer to use types -that explicitly specify their size so we can be sure of applying the -right conversions): - -\code -// Sending a single 16 bit unsigned integer -// in the transmitter: -... -uint16_t data = htons(getsomevalue()); -if (!driver.send((uint8_t*)&data, sizeof(data))) -{ - ... -\endcode -\code -// and in the receiver: -... -uint16_t data; -uint8_t datalen = sizeof(data); -if ( driver.recv((uint8_t*)&data, &datalen) - && datalen == sizeof(data)) -{ - // Have the data, so do something with it - uint16_t xyz = ntohs(data); - ... -\endcode - -If you need to send more than one number at a time, its best to pack -them into a structure - -\code -// Sending several 16 bit unsigned integers in a structure -// in a common header for your project: -typedef struct -{ - uint16_t dataitem1; - uint16_t dataitem2; -} MyDataStruct; -... -\endcode -\code -// In the transmitter -... -MyDataStruct data; -data.dataitem1 = htons(getsomevalue()); -data.dataitem2 = htons(getsomeothervalue()); -if (!driver.send((uint8_t*)&data, sizeof(data))) -{ - ... -\endcode -\code -// in the receiver -MyDataStruct data; -uint8_t datalen = sizeof(data); -if ( driver.recv((uint8_t*)&data, &datalen) - && datalen == sizeof(data)) -{ - // Have the data, so do something with it - uint16_t pqr = ntohs(data.dataitem1); - uint16_t xyz = ntohs(data.dataitem2); - .... -\endcode - -This technique is quite general for integers but may not work if you -want to send floating point number between transmitters and receivers -that have different floating point number representations. - - -\par ASCII - -In this technique, you transmit the printable ASCII equivalent of -each floating point and then convert it back to a float in the receiver: - -\code -// In the transmitter -... -float data = getsomevalue(); -uint8_t buf[15]; // Bigger than the biggest possible ASCII -snprintf(buf, sizeof(buf), "%f", data); -if (!driver.send(buf, strlen(buf) + 1)) // Include the trailing NUL -{ - ... -\endcode -\code - -// In the receiver -... -float data; -uint8_t buf[15]; // Bigger than the biggest possible ASCII -uint8_t buflen = sizeof(buf); -if (driver.recv(buf, &buflen)) -{ - // Have the data, so do something with it - float data = atof(buf); // String to float - ... -\endcode - -\par Conclusion: - -- This is just a basic introduction to the issues. You may need to -extend your study into related C/C++ programming techniques. - -- You can extend these ideas to signed 16 bit (int16_t) and 32 bit -(uint32_t, int32_t) numbers. - -- Things can be simple or complicated depending on the needs of your -project. - -- We are not going to write your code for you: its up to you to take -these examples and explanations and extend them to suit your needs. - -*/ - - - -#ifndef RadioHead_h -#define RadioHead_h - -// Official version numbers are maintained automatically by Makefile: -#define RH_VERSION_MAJOR 1 -#define RH_VERSION_MINOR 98 - -// Symbolic names for currently supported platform types -#define RH_PLATFORM_ARDUINO 1 -#define RH_PLATFORM_MSP430 2 -#define RH_PLATFORM_STM32 3 -#define RH_PLATFORM_GENERIC_AVR8 4 -#define RH_PLATFORM_UNO32 5 -#define RH_PLATFORM_UNIX 6 -#define RH_PLATFORM_STM32STD 7 -#define RH_PLATFORM_STM32F4_HAL 8 -#define RH_PLATFORM_RASPI 9 -#define RH_PLATFORM_NRF51 10 -#define RH_PLATFORM_ESP8266 11 -#define RH_PLATFORM_STM32F2 12 -#define RH_PLATFORM_CHIPKIT_CORE 13 -#define RH_PLATFORM_ESP32 14 -#define RH_PLATFORM_NRF52 15 -#define RH_PLATFORM_MONGOOSE_OS 16 -#define RH_PLATFORM_ATTINY 17 -// Spencer Kondes megaTinyCore: -#define RH_PLATFORM_ATTINY_MEGA 18 - -//////////////////////////////////////////////////// -// Select platform automatically, if possible -#ifndef RH_PLATFORM - #if (defined(MPIDE) && MPIDE>=150 && defined(ARDUINO)) - // Using ChipKIT Core on Arduino IDE - #define RH_PLATFORM RH_PLATFORM_CHIPKIT_CORE - #elif defined(MPIDE) - // Uno32 under old MPIDE, which has been discontinued: - #define RH_PLATFORM RH_PLATFORM_UNO32 - #elif defined(NRF51) - #define RH_PLATFORM RH_PLATFORM_NRF51 - #elif defined(NRF52) - #define RH_PLATFORM RH_PLATFORM_NRF52 - #elif defined(ESP8266) - #define RH_PLATFORM RH_PLATFORM_ESP8266 - #elif defined(ESP32) - #define RH_PLATFORM RH_PLATFORM_ESP32 - #elif defined(MGOS) - #define RH_PLATFORM RH_PLATFORM_MONGOOSE_OS - #elif defined(ARDUINO_attinyxy2) || defined(ARDUINO_attinyxy4) || defined(ARDUINO_attinyxy6) || defined(ARDUINO_attinyxy7) - #define RH_PLATFORM RH_PLATFORM_ATTINY_MEGA - #elif defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtinyX4__) || defined(__AVR_ATtinyX5__) || defined(__AVR_ATtiny2313__) || defined(__AVR_ATtiny4313__) || defined(__AVR_ATtinyX313__) || defined(ARDUINO_attiny) - #define RH_PLATFORM RH_PLATFORM_ATTINY - #elif defined(ARDUINO) - #define RH_PLATFORM RH_PLATFORM_ARDUINO - #elif defined(__MSP430G2452__) || defined(__MSP430G2553__) - #define RH_PLATFORM RH_PLATFORM_MSP430 - #elif defined(MCU_STM32F103RE) - #define RH_PLATFORM RH_PLATFORM_STM32 - #elif defined(STM32F2XX) - #define RH_PLATFORM RH_PLATFORM_STM32F2 - #elif defined(USE_STDPERIPH_DRIVER) - #define RH_PLATFORM RH_PLATFORM_STM32STD - #elif defined(RASPBERRY_PI) - #define RH_PLATFORM RH_PLATFORM_RASPI - #elif defined(__unix__) // Linux - #define RH_PLATFORM RH_PLATFORM_UNIX - #elif defined(__APPLE__) // OSX - #define RH_PLATFORM RH_PLATFORM_UNIX - #else - #error Platform not defined! - #endif -#endif - -//////////////////////////////////////////////////// -// Platform specific headers: -#if (RH_PLATFORM == RH_PLATFORM_ARDUINO) - #if (ARDUINO >= 100) - #include - #else - #include - #endif - #include - #define RH_HAVE_HARDWARE_SPI - #define RH_HAVE_SERIAL - #if defined(ARDUINO_ARCH_STM32F4) - // output to Serial causes hangs on STM32 F4 Discovery board - // There seems to be no way to output text to the USB connection - #define Serial Serial2 - #endif -#elif (RH_PLATFORM == RH_PLATFORM_ATTINY) - #warning Arduino TinyCore does not support hardware SPI. Use software SPI instead. -#elif (RH_PLATFORM == RH_PLATFORM_ATTINY_MEGA) - #include - #define RH_HAVE_HARDWARE_SPI - #define RH_HAVE_SERIAL -#elif (RH_PLATFORM == RH_PLATFORM_ESP8266) // ESP8266 processor on Arduino IDE - #include - #include - #define RH_HAVE_HARDWARE_SPI - #define RH_HAVE_SERIAL - #define RH_MISSING_SPIUSINGINTERRUPT - -#elif (RH_PLATFORM == RH_PLATFORM_ESP32) // ESP32 processor on Arduino IDE - #include - #include - #define RH_HAVE_HARDWARE_SPI - #define RH_HAVE_SERIAL - #define RH_MISSING_SPIUSINGINTERRUPT - - #elif (RH_PLATFORM == RH_PLATFORM_MONGOOSE_OS) // Mongoose OS platform - #include - #include - #include - #include - #include - #include - #include // We use the floor() math function. - #define RH_HAVE_HARDWARE_SPI - //If a Radio is connected via a serial port then this defines the serial - //port the radio is connected to. - #if defined(RH_SERIAL_PORT) - #if RH_SERIAL_PORT == 0 - #define Serial Serial0 - #elif RH_SERIAL_PORT == 1 - #define Serial Serial1 - #elif RH_SERIAL_PORT == 2 - #define Serial Serial2 - #endif - #else - #warning "RH_SERIAL_PORT not defined. Therefore serial port 0 selected" - #define Serial Serial0 - #endif - #define RH_HAVE_SERIAL - -#elif (RH_PLATFORM == RH_PLATFORM_MSP430) // LaunchPad specific - #include "legacymsp430.h" - #include "Energia.h" - #include - #define RH_HAVE_HARDWARE_SPI - #define RH_HAVE_SERIALg - -#elif (RH_PLATFORM == RH_PLATFORM_UNO32 || RH_PLATFORM == RH_PLATFORM_CHIPKIT_CORE) - #include - #include - #include - #define RH_HAVE_HARDWARE_SPI - #define memcpy_P memcpy - #define RH_HAVE_SERIAL - -#elif (RH_PLATFORM == RH_PLATFORM_STM32) // Maple, Flymaple etc - #include - #include - #include - #include - #define RH_HAVE_HARDWARE_SPI - // Defines which timer to use on Maple - #define MAPLE_TIMER 1 - #define PROGMEM - #define memcpy_P memcpy - #define Serial SerialUSB - #define RH_HAVE_SERIAL - -#elif (RH_PLATFORM == RH_PLATFORM_STM32F2) // Particle Photon with firmware-develop - #include - #include - #include // floor - #define RH_HAVE_SERIAL - #define RH_HAVE_HARDWARE_SPI - -#elif (RH_PLATFORM == RH_PLATFORM_STM32STD) // STM32 with STM32F4xx_StdPeriph_Driver - #include - #include - #include - #include - #include - #include - #define RH_HAVE_HARDWARE_SPI - #define Serial SerialUSB - #define RH_HAVE_SERIAL - -#elif (RH_PLATFORM == RH_PLATFORM_GENERIC_AVR8) - #include - #include - #include - #include - #include - #define RH_HAVE_HARDWARE_SPI - #include - -// For Steve Childress port to ARM M4 w/CMSIS with STM's Hardware Abstraction lib. -// See ArduinoWorkarounds.h (not supplied) -#elif (RH_PLATFORM == RH_PLATFORM_STM32F4_HAL) - #include - #include // Also using ST's CubeMX to generate I/O and CPU setup source code for IAR/EWARM, not GCC ARM. - #include - #include - #include - #define RH_HAVE_HARDWARE_SPI // using HAL (Hardware Abstraction Libraries from ST along with CMSIS, not arduino libs or pins concept. - -#elif (RH_PLATFORM == RH_PLATFORM_RASPI) - #define RH_HAVE_HARDWARE_SPI - #define RH_HAVE_SERIAL - #define PROGMEM - #if (__has_include ()) - #include - #else - #include - #endif - #include - //Define SS for CS0 or pin 24 - #define SS 8 - -#elif (RH_PLATFORM == RH_PLATFORM_NRF51) - #define RH_HAVE_SERIAL - #define PROGMEM - #include - -#elif (RH_PLATFORM == RH_PLATFORM_NRF52) - #include - #define RH_HAVE_HARDWARE_SPI - #define RH_HAVE_SERIAL - #define PROGMEM - #include - -#elif (RH_PLATFORM == RH_PLATFORM_UNIX) - // Simulate the sketch on Linux and OSX - #include - #define RH_HAVE_SERIAL -#include // For htons and friends - -#else - #error Platform unknown! -#endif - -//////////////////////////////////////////////////// -// This is an attempt to make a portable atomic block -#if (RH_PLATFORM == RH_PLATFORM_ARDUINO) -#if defined(__arm__) - #include - #else - #include - #endif - #define ATOMIC_BLOCK_START ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - #define ATOMIC_BLOCK_END } -#elif (RH_PLATFORM == RH_PLATFORM_CHIPKIT_CORE) - // UsingChipKIT Core on Arduino IDE - #define ATOMIC_BLOCK_START unsigned int __status = disableInterrupts(); { - #define ATOMIC_BLOCK_END } restoreInterrupts(__status); -#elif (RH_PLATFORM == RH_PLATFORM_UNO32) - // Under old MPIDE, which has been discontinued: - #include - #define ATOMIC_BLOCK_START unsigned int __status = INTDisableInterrupts(); { - #define ATOMIC_BLOCK_END } INTRestoreInterrupts(__status); -#elif (RH_PLATFORM == RH_PLATFORM_STM32F2) // Particle Photon with firmware-develop - #define ATOMIC_BLOCK_START { int __prev = HAL_disable_irq(); - #define ATOMIC_BLOCK_END HAL_enable_irq(__prev); } -#elif (RH_PLATFORM == RH_PLATFORM_ESP8266) -// See hardware/esp8266/2.0.0/cores/esp8266/Arduino.h - #define ATOMIC_BLOCK_START { uint32_t __savedPS = xt_rsil(15); - #define ATOMIC_BLOCK_END xt_wsr_ps(__savedPS);} -#else - // TO BE DONE: - #define ATOMIC_BLOCK_START - #define ATOMIC_BLOCK_END -#endif - -//////////////////////////////////////////////////// -// Try to be compatible with systems that support yield() and multitasking -// instead of spin-loops -// Recent Arduino IDE or Teensy 3 has yield() -#if (RH_PLATFORM == RH_PLATFORM_ARDUINO && ARDUINO >= 155) || (defined(TEENSYDUINO) && defined(__MK20DX128__)) - #define YIELD yield(); -#elif (RH_PLATFORM == RH_PLATFORM_ESP8266) -// ESP8266 also has it - #define YIELD yield(); -#elif (RH_PLATFORM == RH_PLATFORM_MONGOOSE_OS) - //ESP32 and ESP8266 use freertos so we include calls - //that we would normall exit a function and return to - //the rtos in mgosYield() (E.G flush TX uart buffer - extern "C" { - void mgosYield(void); - } - #define YIELD mgosYield() -#else - #define YIELD -#endif - -//////////////////////////////////////////////////// -// digitalPinToInterrupt is not available prior to Arduino 1.5.6 and 1.0.6 -// See http://arduino.cc/en/Reference/attachInterrupt -#ifndef NOT_AN_INTERRUPT - #define NOT_AN_INTERRUPT -1 -#endif -#ifndef digitalPinToInterrupt - #if (RH_PLATFORM == RH_PLATFORM_ARDUINO) && !defined(__arm__) - - #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - // Arduino Mega, Mega ADK, Mega Pro - // 2->0, 3->1, 21->2, 20->3, 19->4, 18->5 - #define digitalPinToInterrupt(p) ((p) == 2 ? 0 : ((p) == 3 ? 1 : ((p) >= 18 && (p) <= 21 ? 23 - (p) : NOT_AN_INTERRUPT))) - - #elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) - // Arduino 1284 and 1284P - See Manicbug and Optiboot - // 10->0, 11->1, 2->2 - #define digitalPinToInterrupt(p) ((p) == 10 ? 0 : ((p) == 11 ? 1 : ((p) == 2 ? 2 : NOT_AN_INTERRUPT))) - - #elif defined(__AVR_ATmega32U4__) - // Leonardo, Yun, Micro, Pro Micro, Flora, Esplora - // 3->0, 2->1, 0->2, 1->3, 7->4 - #define digitalPinToInterrupt(p) ((p) == 0 ? 2 : ((p) == 1 ? 3 : ((p) == 2 ? 1 : ((p) == 3 ? 0 : ((p) == 7 ? 4 : NOT_AN_INTERRUPT))))) - - #else - // All other arduino except Due: - // Serial Arduino, Extreme, NG, BT, Uno, Diecimila, Duemilanove, Nano, Menta, Pro, Mini 04, Fio, LilyPad, Ethernet etc - // 2->0, 3->1 - #define digitalPinToInterrupt(p) ((p) == 2 ? 0 : ((p) == 3 ? 1 : NOT_AN_INTERRUPT)) - - #endif - - #elif (RH_PLATFORM == RH_PLATFORM_UNO32) || (RH_PLATFORM == RH_PLATFORM_CHIPKIT_CORE) - // Hmmm, this is correct for Uno32, but what about other boards on ChipKIT Core? - #define digitalPinToInterrupt(p) ((p) == 38 ? 0 : ((p) == 2 ? 1 : ((p) == 7 ? 2 : ((p) == 8 ? 3 : ((p) == 735 ? 4 : NOT_AN_INTERRUPT))))) - - #else - // Everything else (including Due and Teensy) interrupt number the same as the interrupt pin number - #define digitalPinToInterrupt(p) (p) - #endif -#endif - -// On some platforms, attachInterrupt() takes a pin number, not an interrupt number -#if (RH_PLATFORM == RH_PLATFORM_ARDUINO) && defined (__arm__) && (defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_SAM_DUE)) - #define RH_ATTACHINTERRUPT_TAKES_PIN_NUMBER -#endif - -// Slave select pin, some platforms such as ATTiny do not define it. -#ifndef SS - #define SS 10 -#endif - -// Some platforms require specail attributes for interrupt routines -#if (RH_PLATFORM == RH_PLATFORM_ESP8266) - // interrupt handler and related code must be in RAM on ESP8266, - // according to issue #46. - #define RH_INTERRUPT_ATTR ICACHE_RAM_ATTR - -#elif (RH_PLATFORM == RH_PLATFORM_ESP32) - #define RH_INTERRUPT_ATTR IRAM_ATTR -#else - #define RH_INTERRUPT_ATTR -#endif - -// These defs cause trouble on some versions of Arduino -#undef abs -#undef round -#undef double - -// Sigh: there is no widespread adoption of htons and friends in the base code, only in some WiFi headers etc -// that have a lot of excess baggage -#if RH_PLATFORM != RH_PLATFORM_UNIX && !defined(htons) -// #ifndef htons -// These predefined macros available on modern GCC compilers - #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - // Atmel processors - #define htons(x) ( ((x)<<8) | (((x)>>8)&0xFF) ) - #define ntohs(x) htons(x) - #define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ - ((x)<< 8 & 0x00FF0000UL) | \ - ((x)>> 8 & 0x0000FF00UL) | \ - ((x)>>24 & 0x000000FFUL) ) - #define ntohl(x) htonl(x) - - #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - // Others - #define htons(x) (x) - #define ntohs(x) (x) - #define htonl(x) (x) - #define ntohl(x) (x) - - #else - #error "Dont know how to define htons and friends for this processor" - #endif -#endif - -// This is the address that indicates a broadcast -#define RH_BROADCAST_ADDRESS 0xff - -// Uncomment this is to enable Encryption (see RHEncryptedDriver): -// But ensure you have installed the Crypto directory from arduinolibs first: -// http://rweather.github.io/arduinolibs/index.html -//#define RH_ENABLE_ENCRYPTION_MODULE - -#endif diff --git a/src/rf95/RadioInterface.cpp b/src/rf95/RadioInterface.cpp index fa618f1cd..90f865b58 100644 --- a/src/rf95/RadioInterface.cpp +++ b/src/rf95/RadioInterface.cpp @@ -1,4 +1,5 @@ -#include "CustomRF95.h" + +#include "RadioInterface.h" #include "NodeDB.h" #include "assert.h" #include "configuration.h" @@ -46,7 +47,8 @@ size_t RadioInterface::beginSending(MeshPacket *p) // if the sender nodenum is zero, that means uninitialized assert(h->from); - size_t numbytes = pb_encode_to_bytes(radiobuf + sizeof(PacketHeader), sizeof(radiobuf), SubPacket_fields, &p->payload) + sizeof(PacketHeader); + size_t numbytes = pb_encode_to_bytes(radiobuf + sizeof(PacketHeader), sizeof(radiobuf), SubPacket_fields, &p->payload) + + sizeof(PacketHeader); assert(numbytes <= MAX_RHPACKETLEN); diff --git a/src/rf95/RadioInterface.h b/src/rf95/RadioInterface.h index e24f063db..549c280a4 100644 --- a/src/rf95/RadioInterface.h +++ b/src/rf95/RadioInterface.h @@ -4,21 +4,25 @@ #include "MeshTypes.h" #include "PointerQueue.h" #include "mesh.pb.h" -#include #define MAX_TX_QUEUE 16 // max number of packets which can be waiting for transmission #define MAX_RHPACKETLEN 256 /** - * This structure has to exactly match the wire layout when sent over the radio link. Used to keep compatibility + * This structure has to exactly match the wire layout when sent over the radio link. Used to keep compatibility * wtih the old radiohead implementation. */ typedef struct { uint8_t to, from, id, flags; } PacketHeader; - +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; /** * Basic operations all radio chipsets must implement. @@ -48,7 +52,7 @@ class RadioInterface public: float freq = 915.0; // FIXME, init all these params from user setings int8_t power = 17; - RH_RF95::ModemConfigChoice modemConfig; + ModemConfigChoice modemConfig; /** pool is the pool we will alloc our rx packets from * rxDest is where we will send any rx packets, it becomes receivers responsibility to return packet to the pool @@ -81,7 +85,6 @@ class RadioInterface // methods from radiohead - /// Initialise the Driver transport hardware and software. /// Make sure the Driver is properly configured before calling init(). /// \return true if initialisation succeeded. @@ -94,9 +97,10 @@ class RadioInterface protected: /*** - * given a packet set sendingPacket and decode the protobufs into radiobuf. Returns # of bytes to send (including the PacketHeader & payload). - * - * Used as the first step of + * given a packet set sendingPacket and decode the protobufs into radiobuf. Returns # of bytes to send (including the + * PacketHeader & payload). + * + * Used as the first step of */ size_t beginSending(MeshPacket *p); }; @@ -112,16 +116,4 @@ class SimRadio : public RadioInterface /// Make sure the Driver is properly configured before calling init(). /// \return true if initialisation succeeded. virtual bool init() { return true; } - - /// If current mode is Rx or Tx changes it to Idle. If the transmitter or receiver is running, - /// disables them. - void setModeIdle() {} - - /// If current mode is Tx or Idle, changes it to Rx. - /// Starts the receiver in the RF95/96/97/98. - void setModeRx() {} - - /// Returns the operating mode of the library. - /// \return the current mode, one of RF69_MODE_* - virtual RHGenericDriver::RHMode mode() { return RHGenericDriver::RHModeIdle; } }; diff --git a/src/rf95/RadioLibInterface.cpp b/src/rf95/RadioLibInterface.cpp index 6cfb54fee..21dc8271c 100644 --- a/src/rf95/RadioLibInterface.cpp +++ b/src/rf95/RadioLibInterface.cpp @@ -39,22 +39,22 @@ RadioLibInterface *RadioLibInterface::instance; void RadioLibInterface::applyModemConfig() { switch (modemConfig) { - case RH_RF95::Bw125Cr45Sf128: ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium range + case Bw125Cr45Sf128: ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium range bw = 125; cr = 5; sf = 7; break; - case RH_RF95::Bw500Cr45Sf128: ///< Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short range + case Bw500Cr45Sf128: ///< Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short range bw = 500; cr = 5; sf = 7; break; - case RH_RF95::Bw31_25Cr48Sf512: ///< Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long range + case Bw31_25Cr48Sf512: ///< Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long range bw = 31.25; cr = 8; sf = 9; break; - case RH_RF95::Bw125Cr48Sf4096: + case Bw125Cr48Sf4096: bw = 125; cr = 8; sf = 12; diff --git a/src/rf95/Router.h b/src/rf95/Router.h index 8f2ef6fa1..20378371d 100644 --- a/src/rf95/Router.h +++ b/src/rf95/Router.h @@ -6,7 +6,6 @@ #include "PointerQueue.h" #include "RadioInterface.h" #include "mesh.pb.h" -#include /** * A mesh aware router that supports multiple interfaces.