diff --git a/boards/ppr.json b/boards/ppr.json index 5283fdc4e..5050758f7 100644 --- a/boards/ppr.json +++ b/boards/ppr.json @@ -10,7 +10,7 @@ "hwids": [["0x239A", "0x4403"]], "usb_product": "PPR", "mcu": "nrf52840", - "variant": "ppr", + "variant": "pca10056-rc-clock", "variants_dir": "variants", "bsp": { "name": "adafruit" diff --git a/docs/software/nrf52-TODO.md b/docs/software/nrf52-TODO.md index bf1d71b32..6e6555083 100644 --- a/docs/software/nrf52-TODO.md +++ b/docs/software/nrf52-TODO.md @@ -11,6 +11,7 @@ Minimum items needed to make sure hardware is good. - switch to RadioLab? test it with current radio. https://github.com/jgromes/RadioLib - use "variants" to get all gpio bindings - plug in correct variants for the real board +- remove unused sx1262 lib from github - Use the PMU driver on real hardware - add a NEMA based GPS driver to test GPS - Use new radio driver on real hardware - possibly start with https://os.mbed.com/teams/Semtech/code/SX126xLib/ diff --git a/platformio.ini b/platformio.ini index ceb57fbc6..d570b1190 100644 --- a/platformio.ini +++ b/platformio.ini @@ -73,7 +73,7 @@ lib_deps = Wire ; explicitly needed here because the AXP202 library forgets to add it https://github.com/meshtastic/arduino-fsm.git https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git - https://github.com/jgromes/RadioLib.git + https://github.com/meshtastic/RadioLib.git ; Common settings for ESP targes, mixin with extends = esp32_base [esp32_base] diff --git a/src/configuration.h b/src/configuration.h index 8f443904e..b02a1a00f 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -217,10 +217,12 @@ along with this program. If not, see . #define LED_INVERTED 1 // Temporarily testing if we can build the RF95 driver for NRF52 +#if 0 #define RESET_GPIO 14 // If defined, this pin will be used to reset the LORA radio #define RF95_IRQ_GPIO 26 // IRQ line for the LORA radio #define DIO1_GPIO 35 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number #define DIO2_GPIO 34 // DIO1 & DIO2 are not currently used, but they must be assigned to a pin number +#endif #endif diff --git a/src/main.cpp b/src/main.cpp index d0e8ddd7f..f79c9e016 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -118,6 +118,9 @@ static uint32_t ledBlinker() Periodic ledPeriodic(ledBlinker); +#include "RadioLibInterface.h" +#include "variant.h" + void setup() { #ifdef USE_SEGGER @@ -189,7 +192,15 @@ void setup() realRouter.setup(); // required for our periodic task (kinda skanky FIXME) // MUST BE AFTER service.init, so we have our radio config settings (from nodedb init) - radio = new MeshRadio(); + RadioInterface *rIf = +#if defined(RF95_IRQ_GPIO) + new CustomRF95(); +#elif defined(SX1262_CS) + new RadioLibInterface(SX1262_CS, SX1262_DIO1, SX1262_RESET, SX1262_BUSY, SPI); +#else + new SimRadio(); +#endif + radio = new MeshRadio(rIf); router.addInterface(&radio->radioIf); if (radio && !radio->init()) diff --git a/src/mesh/MeshRadio.cpp b/src/mesh/MeshRadio.cpp index 4242a94a2..9c21937cc 100644 --- a/src/mesh/MeshRadio.cpp +++ b/src/mesh/MeshRadio.cpp @@ -24,7 +24,7 @@ separated by 2.16 MHz with respect to the adjacent channels. Channel zero starts /// Sometimes while debugging it is useful to set this false, to disable rf95 accesses bool useHardware = true; -MeshRadio::MeshRadio() // , manager(radioIf) +MeshRadio::MeshRadio(RadioInterface *rIf) : radioIf(*rIf) // , manager(radioIf) { myNodeInfo.num_channels = NUM_CHANNELS; @@ -122,4 +122,3 @@ int MeshRadio::reloadConfig(void *unused) return 0; } - diff --git a/src/mesh/MeshRadio.h b/src/mesh/MeshRadio.h index 186af9f5e..da19eebb8 100644 --- a/src/mesh/MeshRadio.h +++ b/src/mesh/MeshRadio.h @@ -63,23 +63,19 @@ /** * A raw low level interface to our mesh. Only understands nodenums and bytes (not protobufs or node ids) + * FIXME - REMOVE THIS CLASS */ class MeshRadio { public: // Kinda ugly way of selecting different radio implementations, but soon this MeshRadio class will be going away // entirely. At that point we can make things pretty. -#ifdef RF95_IRQ_GPIO - CustomRF95 - radioIf; // the raw radio interface - for now I'm leaving public - because this class is shrinking to be almost nothing -#else - SimRadio radioIf; -#endif + RadioInterface &radioIf; /** 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 */ - MeshRadio(); + MeshRadio(RadioInterface *rIf); bool init(); diff --git a/src/rf95/CustomRF95.cpp b/src/rf95/CustomRF95.cpp index 7005a9ce1..eba19006a 100644 --- a/src/rf95/CustomRF95.cpp +++ b/src/rf95/CustomRF95.cpp @@ -149,7 +149,7 @@ void CustomRF95::handleIdleISR() startSend(txp); else { // Nothing to send, let's switch back to receive mode - setModeRx(); + RH_RF95::setModeRx(); } } @@ -193,9 +193,9 @@ void CustomRF95::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 && mode() == RHGenericDriver::RHModeTx) { + 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"); - setModeRx(); + RH_RF95::setModeRx(); if (sendingPacket) { // There was probably a packet we were trying to send, free it packetPool.release(sendingPacket); sendingPacket = NULL; diff --git a/src/rf95/RadioInterface.h b/src/rf95/RadioInterface.h index bad532a1e..59f64cdf7 100644 --- a/src/rf95/RadioInterface.h +++ b/src/rf95/RadioInterface.h @@ -55,6 +55,72 @@ class RadioInterface * If the txmit queue is full it might return an error */ virtual ErrorCode send(MeshPacket *p) = 0; + + // methods from radiohead + + /// 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) = 0; + + /// 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() = 0; + + /// 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 + virtual bool setFrequency(float centre) = 0; + + /// 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. + virtual bool setModemConfig(RH_RF95::ModemConfigChoice index) = 0; + + /// If current mode is Rx or Tx changes it to Idle. If the transmitter or receiver is running, + /// disables them. + virtual void setModeIdle() = 0; + + /// If current mode is Tx or Idle, changes it to Rx. + /// Starts the receiver in the RF95/96/97/98. + virtual void setModeRx() = 0; + + /// Returns the operating mode of the library. + /// \return the current mode, one of RF69_MODE_* + virtual RHGenericDriver::RHMode mode() = 0; + + /// 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) {} }; class SimRadio : public RadioInterface diff --git a/src/rf95/RadioLibInterface.cpp b/src/rf95/RadioLibInterface.cpp new file mode 100644 index 000000000..b387a253e --- /dev/null +++ b/src/rf95/RadioLibInterface.cpp @@ -0,0 +1,118 @@ +#include "RadioLibInterface.h" +#include + +// FIXME, we default to 4MHz SPI, SPI mode 0, check if the datasheet says it can really do that +static SPISettings spiSettings; + +RadioLibInterface::RadioLibInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, + SPIClass &spi) + : module(cs, irq, rst, busy, spi, spiSettings), lora(&module) +{ +} + +ErrorCode RadioLibInterface::send(MeshPacket *p) +{ + return ERR_NONE; +} + +/// Initialise the Driver transport hardware and software. +/// Make sure the Driver is properly configured before calling init(). +/// \return true if initialisation succeeded. +bool RadioLibInterface::init() +{ + // FIXME, move this to main + SPI.begin(); + + int res = lora.begin(); + DEBUG_MSG("LORA init result %d\n", res); + + return res == ERR_NONE; +} + +/** + * + * + * +// include the library + + +// SX1262 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1262 lora = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1262 lora = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1262 with default settings + Serial.print(F("[SX1262] Initializing ... ")); + // carrier frequency: 434.0 MHz + // bandwidth: 125.0 kHz + // spreading factor: 9 + // coding rate: 7 + // sync word: 0x12 (private network) + // output power: 14 dBm + // current limit: 60 mA + // preamble length: 8 symbols + // TCXO voltage: 1.6 V (set to 0 to not use TCXO) + // regulator: DC-DC (set to true to use LDO) + // CRC: enabled + int state = lora.begin(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[SX1262] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + // NOTE: transmit() is a blocking method! + // See example SX126x_Transmit_Interrupt for details + // on non-blocking transmission method. + int state = lora.transmit("Hello World!"); + + // you can also transmit byte array up to 256 bytes long + + byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; + int state = lora.transmit(byteArr, 8); + + +if (state == ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + // print measured data rate + Serial.print(F("[SX1262] Datarate:\t")); + Serial.print(lora.getDataRate()); + Serial.println(F(" bps")); + +} else if (state == ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 256 bytes + Serial.println(F("too long!")); + +} else if (state == ERR_TX_TIMEOUT) { + // timeout occured while transmitting packet + Serial.println(F("timeout!")); + +} else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); +} + +// wait for a second before transmitting again +delay(1000); +} + */ \ No newline at end of file diff --git a/src/rf95/RadioLibInterface.h b/src/rf95/RadioLibInterface.h new file mode 100644 index 000000000..a4ee06f9f --- /dev/null +++ b/src/rf95/RadioLibInterface.h @@ -0,0 +1,82 @@ +#pragma once + +#include "RadioInterface.h" + +#include + +class RadioLibInterface : public RadioInterface +{ + Module module; // The HW interface to the radio + SX1262 lora; + + public: + RadioLibInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi); + + virtual ErrorCode send(MeshPacket *p); + + // methods from radiohead + + /// 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) {} + + /// 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(); + + /// 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) { return true; } + + /// 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(RH_RF95::ModemConfigChoice index) { 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; } + + /// 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) {} +}; \ No newline at end of file diff --git a/variants/pca10056-rc-clock/variant.h b/variants/pca10056-rc-clock/variant.h index db5c71b67..b7201812a 100644 --- a/variants/pca10056-rc-clock/variant.h +++ b/variants/pca10056-rc-clock/variant.h @@ -142,6 +142,7 @@ static const uint8_t SCK = PIN_SPI_SCK; // CUSTOM GPIOs the SX1262MB2CAS shield when installed on the NRF52840-DK development board #define SX1262_CS (32 + 8) // P1.08 #define SX1262_DIO1 (32 + 6) // P1.06 +#define SX1262_BUSY (32 + 4) // P1.04 #define SX1262_RESET (0 + 3) // P0.03 #define SX1262_ANT_SW (32 + 10) // P1.10