PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1167 line
45KB

  1. // RH_RF24.cpp
  2. //
  3. // Copyright (C) 2011 Mike McCauley
  4. // $Id: RH_RF24.cpp,v 1.16 2016/04/04 01:40:12 mikem Exp $
  5. #include <RH_RF24.h>
  6. // Generated with Silicon Labs WDS software:
  7. #include "radio_config_Si4460.h"
  8. // Interrupt vectors for the 3 Arduino interrupt pins
  9. // Each interrupt can be handled by a different instance of RH_RF24, allowing you to have
  10. // 2 or more RF24s per Arduino
  11. RH_RF24* RH_RF24::_deviceForInterrupt[RH_RF24_NUM_INTERRUPTS] = {0, 0, 0};
  12. uint8_t RH_RF24::_interruptCount = 0; // Index into _deviceForInterrupt for next device
  13. // This configuration data is defined in radio_config_Si4460.h
  14. // which was generated with the Silicon Labs WDS program
  15. PROGMEM const uint8_t RFM26_CONFIGURATION_DATA[] = RADIO_CONFIGURATION_DATA_ARRAY;
  16. // These configurations were all generated originally by the Silicon LAbs WDS configuration tool.
  17. // The configurations were imported into RH_RF24, the complete properties set dumped to a file with printRegisters, then
  18. // RH_RF24_property_data/convert.pl was used to generate the entry for this table.
  19. // Contributions of new complete and tested ModemConfigs ready to add to this list will be readily accepted.
  20. // Casual suggestions of new schemes without working examples will probably be passed over
  21. PROGMEM static const RH_RF24::ModemConfig MODEM_CONFIG_TABLE[] =
  22. {
  23. // These were generated with convert.pl from data in RH_RF24_property_data
  24. // FSK_Rb0_5Fd1
  25. { 0x02, 0x00, 0x13, 0x88, 0x01, 0x00, 0x00, 0x46, 0x01, 0x34, 0x11, 0x02, 0x71, 0x00, 0xd1, 0xb7, 0x00, 0x69, 0x02, 0x36, 0x80, 0x01, 0x5a, 0xfc, 0xe2, 0x11, 0x89, 0x89, 0x00, 0x02, 0xff, 0xff, 0x00, 0x2b, 0x02, 0x81, 0x00, 0xad, 0x3a, 0xff, 0xba, 0x0f, 0x51, 0xcf, 0xa9, 0xc9, 0xfc, 0x1b, 0x1e, 0x0f, 0x01, 0xfc, 0xfd, 0x15, 0xff, 0x00, 0x0f, 0xff, 0xba, 0x0f, 0x51, 0xcf, 0xa9, 0xc9, 0xfc, 0x1b, 0x1e, 0x0f, 0x01, 0xfc, 0xfd, 0x15, 0xff, 0x00, 0x0f, 0x3f, 0x2c, 0x0e, 0x04, 0x0c, 0x73, },
  26. // FSK_Rb5Fd10
  27. { 0x02, 0x00, 0xc3, 0x50, 0x01, 0x00, 0x02, 0xbb, 0x01, 0x30, 0x20, 0x01, 0x77, 0x01, 0x5d, 0x86, 0x00, 0xaf, 0x02, 0x36, 0x80, 0x0f, 0x15, 0x87, 0xe2, 0x11, 0x52, 0x52, 0x00, 0x02, 0xff, 0xff, 0x00, 0x2a, 0x02, 0x83, 0x01, 0x20, 0x40, 0xff, 0xba, 0x0f, 0x51, 0xcf, 0xa9, 0xc9, 0xfc, 0x1b, 0x1e, 0x0f, 0x01, 0xfc, 0xfd, 0x15, 0xff, 0x00, 0x0f, 0xff, 0xba, 0x0f, 0x51, 0xcf, 0xa9, 0xc9, 0xfc, 0x1b, 0x1e, 0x0f, 0x01, 0xfc, 0xfd, 0x15, 0xff, 0x00, 0x0f, 0x3f, 0x2c, 0x0e, 0x04, 0x0c, 0x73, },
  28. // FSK_Rb50Fd100
  29. { 0x02, 0x07, 0xa1, 0x20, 0x01, 0x00, 0x1b, 0x4f, 0x01, 0x00, 0x10, 0x00, 0xc8, 0x02, 0x8f, 0x5c, 0x01, 0x48, 0x02, 0x36, 0x80, 0x92, 0x0a, 0x46, 0xe2, 0x11, 0x2c, 0x2c, 0x00, 0x02, 0xff, 0xff, 0x00, 0x29, 0x02, 0x83, 0x02, 0x7f, 0x40, 0xff, 0xc4, 0x30, 0x7f, 0xf5, 0xb5, 0xb8, 0xde, 0x05, 0x17, 0x16, 0x0c, 0x03, 0x00, 0x15, 0xff, 0x00, 0x00, 0xff, 0xc4, 0x30, 0x7f, 0xf5, 0xb5, 0xb8, 0xde, 0x05, 0x17, 0x16, 0x0c, 0x03, 0x00, 0x15, 0xff, 0x00, 0x00, 0x3f, 0x2c, 0x0e, 0x04, 0x0c, 0x73, },
  30. //FSK_Rb150Fd300
  31. { 0x02, 0x16, 0xe3, 0x60, 0x01, 0x00, 0x51, 0xec, 0x01, 0x00, 0x30, 0x00, 0xc8, 0x02, 0x8f, 0x5c, 0x01, 0x48, 0x02, 0x47, 0x83, 0x6a, 0x04, 0xb5, 0xe2, 0x22, 0x16, 0x16, 0x00, 0x02, 0xff, 0xff, 0x00, 0x29, 0x02, 0x83, 0x02, 0x7f, 0x40, 0xff, 0xc4, 0x30, 0x7f, 0xf5, 0xb5, 0xb8, 0xde, 0x05, 0x17, 0x16, 0x0c, 0x03, 0x00, 0x15, 0xff, 0x00, 0x00, 0xff, 0xc4, 0x30, 0x7f, 0xf5, 0xb5, 0xb8, 0xde, 0x05, 0x17, 0x16, 0x0c, 0x03, 0x00, 0x15, 0xff, 0x00, 0x00, 0x3f, 0x39, 0x04, 0x05, 0x04, 0x01, },
  32. // GFSK_Rb0_5Fd1
  33. { 0x03, 0x00, 0x4e, 0x20, 0x05, 0x00, 0x00, 0x46, 0x01, 0x34, 0x11, 0x02, 0x71, 0x00, 0xd1, 0xb7, 0x00, 0x69, 0x02, 0x36, 0x80, 0x01, 0x5a, 0xfc, 0xe2, 0x11, 0x89, 0x89, 0x00, 0x1a, 0xff, 0xff, 0x00, 0x2b, 0x02, 0x81, 0x00, 0x68, 0x3a, 0xff, 0xba, 0x0f, 0x51, 0xcf, 0xa9, 0xc9, 0xfc, 0x1b, 0x1e, 0x0f, 0x01, 0xfc, 0xfd, 0x15, 0xff, 0x00, 0x0f, 0xff, 0xba, 0x0f, 0x51, 0xcf, 0xa9, 0xc9, 0xfc, 0x1b, 0x1e, 0x0f, 0x01, 0xfc, 0xfd, 0x15, 0xff, 0x00, 0x0f, 0x3f, 0x2c, 0x0e, 0x04, 0x0c, 0x73, },
  34. // GFSK_Rb5Fd10
  35. { 0x03, 0x03, 0x0d, 0x40, 0x05, 0x00, 0x02, 0xbb, 0x01, 0x30, 0x20, 0x01, 0x77, 0x01, 0x5d, 0x86, 0x00, 0xaf, 0x02, 0x36, 0x80, 0x0f, 0x15, 0x87, 0xe2, 0x11, 0x52, 0x52, 0x00, 0x1a, 0xff, 0xff, 0x00, 0x2a, 0x02, 0x83, 0x00, 0xad, 0x40, 0xff, 0xba, 0x0f, 0x51, 0xcf, 0xa9, 0xc9, 0xfc, 0x1b, 0x1e, 0x0f, 0x01, 0xfc, 0xfd, 0x15, 0xff, 0x00, 0x0f, 0xff, 0xba, 0x0f, 0x51, 0xcf, 0xa9, 0xc9, 0xfc, 0x1b, 0x1e, 0x0f, 0x01, 0xfc, 0xfd, 0x15, 0xff, 0x00, 0x0f, 0x3f, 0x2c, 0x0e, 0x04, 0x0c, 0x73, },
  36. // GFSK_Rb50Fd100
  37. { 0x03, 0x0f, 0x42, 0x40, 0x09, 0x00, 0x1b, 0x4f, 0x01, 0x00, 0x10, 0x00, 0xc8, 0x02, 0x8f, 0x5c, 0x01, 0x48, 0x02, 0x36, 0x80, 0x92, 0x0a, 0x46, 0xe2, 0x11, 0x2c, 0x2c, 0x00, 0x1a, 0xff, 0xff, 0x00, 0x29, 0x02, 0x83, 0x01, 0x7f, 0x40, 0xff, 0xc4, 0x30, 0x7f, 0xf5, 0xb5, 0xb8, 0xde, 0x05, 0x17, 0x16, 0x0c, 0x03, 0x00, 0x15, 0xff, 0x00, 0x00, 0xff, 0xc4, 0x30, 0x7f, 0xf5, 0xb5, 0xb8, 0xde, 0x05, 0x17, 0x16, 0x0c, 0x03, 0x00, 0x15, 0xff, 0x00, 0x00, 0x3f, 0x2c, 0x0e, 0x04, 0x0c, 0x73, },
  38. // GFSK_Rb150Fd300
  39. { 0x03, 0x2d, 0xc6, 0xc0, 0x09, 0x00, 0x51, 0xec, 0x01, 0x00, 0x30, 0x00, 0xc8, 0x02, 0x8f, 0x5c, 0x01, 0x48, 0x02, 0x47, 0x83, 0x6a, 0x04, 0xb5, 0xe2, 0x22, 0x16, 0x16, 0x00, 0x1a, 0xff, 0xff, 0x00, 0x29, 0x02, 0x83, 0x01, 0x7f, 0x40, 0xff, 0xc4, 0x30, 0x7f, 0xf5, 0xb5, 0xb8, 0xde, 0x05, 0x17, 0x16, 0x0c, 0x03, 0x00, 0x15, 0xff, 0x00, 0x00, 0xff, 0xc4, 0x30, 0x7f, 0xf5, 0xb5, 0xb8, 0xde, 0x05, 0x17, 0x16, 0x0c, 0x03, 0x00, 0x15, 0xff, 0x00, 0x00, 0x3f, 0x39, 0x04, 0x05, 0x04, 0x01, },
  40. // OOK_Rb5Bw30
  41. { 0x01, 0x00, 0xc3, 0x50, 0x01, 0x00, 0x00, 0x00, 0x00, 0x34, 0x10, 0x00, 0x3f, 0x08, 0x31, 0x27, 0x04, 0x10, 0x02, 0x12, 0x00, 0x2c, 0x03, 0xf9, 0x62, 0x11, 0x0e, 0x0e, 0x00, 0x02, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00, 0x07, 0xff, 0x40, 0xcc, 0xa1, 0x30, 0xa0, 0x21, 0xd1, 0xb9, 0xc9, 0xea, 0x05, 0x12, 0x11, 0x0a, 0x04, 0x15, 0xfc, 0x03, 0x00, 0xcc, 0xa1, 0x30, 0xa0, 0x21, 0xd1, 0xb9, 0xc9, 0xea, 0x05, 0x12, 0x11, 0x0a, 0x04, 0x15, 0xfc, 0x03, 0x00, 0x3f, 0x2c, 0x0e, 0x04, 0x0c, 0x73, },
  42. // OOK_Rb10Bw40
  43. { 0x01, 0x01, 0x86, 0xa0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x32, 0x20, 0x00, 0x5e, 0x05, 0x76, 0x1a, 0x02, 0xb9, 0x02, 0x12, 0x00, 0x57, 0x02, 0xb0, 0x62, 0x11, 0x15, 0x15, 0x00, 0x02, 0xff, 0xff, 0x00, 0x28, 0x00, 0x00, 0x07, 0xff, 0x40, 0xa2, 0x81, 0x26, 0xaf, 0x3f, 0xee, 0xc8, 0xc7, 0xdb, 0xf2, 0x02, 0x08, 0x07, 0x03, 0x15, 0xfc, 0x0f, 0x00, 0xa2, 0x81, 0x26, 0xaf, 0x3f, 0xee, 0xc8, 0xc7, 0xdb, 0xf2, 0x02, 0x08, 0x07, 0x03, 0x15, 0xfc, 0x0f, 0x00, 0x3f, 0x2c, 0x0e, 0x04, 0x0c, 0x73, },
  44. };
  45. RH_RF24::RH_RF24(uint8_t slaveSelectPin, uint8_t interruptPin, uint8_t sdnPin, RHGenericSPI& spi)
  46. :
  47. RHSPIDriver(slaveSelectPin, spi)
  48. {
  49. _interruptPin = interruptPin;
  50. _sdnPin = sdnPin;
  51. _idleMode = RH_RF24_DEVICE_STATE_READY;
  52. _myInterruptIndex = 0xff; // Not allocated yet
  53. }
  54. void RH_RF24::setIdleMode(uint8_t idleMode)
  55. {
  56. _idleMode = idleMode;
  57. }
  58. bool RH_RF24::init()
  59. {
  60. if (!RHSPIDriver::init())
  61. return false;
  62. // Determine the interrupt number that corresponds to the interruptPin
  63. int interruptNumber = digitalPinToInterrupt(_interruptPin);
  64. if (interruptNumber == NOT_AN_INTERRUPT)
  65. return false;
  66. #ifdef RH_ATTACHINTERRUPT_TAKES_PIN_NUMBER
  67. interruptNumber = _interruptPin;
  68. #endif
  69. // Initialise the radio
  70. power_on_reset();
  71. cmd_clear_all_interrupts();
  72. // Here we use a configuration generated by the Silicon Las Wireless Development Suite
  73. // in radio_config_Si4460.h
  74. // WE override a few things later that we ned to be sure of.
  75. configure(RFM26_CONFIGURATION_DATA);
  76. // Get the device type and check it
  77. // This also tests whether we are really connected to a device
  78. uint8_t buf[8];
  79. if (!command(RH_RF24_CMD_PART_INFO, 0, 0, buf, sizeof(buf)))
  80. return false; // SPI error? Not connected?
  81. _deviceType = (buf[1] << 8) | buf[2];
  82. // Check PART to be either 0x4460, 0x4461, 0x4463, 0x4464
  83. if (_deviceType != 0x4460 &&
  84. _deviceType != 0x4461 &&
  85. _deviceType != 0x4463 &&
  86. _deviceType != 0x4464)
  87. return false; // Unknown radio type, or not connected
  88. // Add by Adrien van den Bossche <vandenbo@univ-tlse2.fr> for Teensy
  89. // ARM M4 requires the below. else pin interrupt doesn't work properly.
  90. // On all other platforms, its innocuous, belt and braces
  91. pinMode(_interruptPin, INPUT);
  92. // Set up interrupt handler
  93. // Since there are a limited number of interrupt glue functions isr*() available,
  94. // we can only support a limited number of devices simultaneously
  95. // ON some devices, notably most Arduinos, the interrupt pin passed in is actuallt the
  96. // interrupt number. You have to figure out the interruptnumber-to-interruptpin mapping
  97. // yourself based on knwledge of what Arduino board you are running on.
  98. if (_myInterruptIndex == 0xff)
  99. {
  100. // First run, no interrupt allocated yet
  101. if (_interruptCount <= RH_RF24_NUM_INTERRUPTS)
  102. _myInterruptIndex = _interruptCount++;
  103. else
  104. return false; // Too many devices, not enough interrupt vectors
  105. }
  106. _deviceForInterrupt[_myInterruptIndex] = this;
  107. if (_myInterruptIndex == 0)
  108. attachInterrupt(interruptNumber, isr0, FALLING);
  109. else if (_myInterruptIndex == 1)
  110. attachInterrupt(interruptNumber, isr1, FALLING);
  111. else if (_myInterruptIndex == 2)
  112. attachInterrupt(interruptNumber, isr2, FALLING);
  113. else
  114. return false; // Too many devices, not enough interrupt vectors
  115. // Ensure we get the interrupts we need, irrespective of whats in the radio_config
  116. uint8_t int_ctl[] = {RH_RF24_MODEM_INT_STATUS_EN | RH_RF24_PH_INT_STATUS_EN, 0xff, 0xff, 0x00 };
  117. set_properties(RH_RF24_PROPERTY_INT_CTL_ENABLE, int_ctl, sizeof(int_ctl));
  118. // RSSI Latching should be configured in MODEM_RSSI_CONTROL in radio_config
  119. // PKT_TX_THRESHOLD and PKT_RX_THRESHOLD should be set to about 0x30 in radio_config
  120. // Configure important RH_RF24 registers
  121. // Here we set up the standard packet format for use by the RH_RF24 library:
  122. // We will use FIFO Mode, with automatic packet generation
  123. // We have 2 fields:
  124. // Field 1 contains only the (variable) length of field 2, with CRC
  125. // Field 2 contains the variable length payload and the CRC
  126. // Hmmm, having no CRC on field 1 and CRC on field 2 causes CRC errors when resetting after an odd
  127. // number of packets! Anyway its prob a good thing at the cost of some airtime.
  128. // Hmmm, enabling WHITEN stops it working!
  129. uint8_t pkt_config1[] = { 0x00 };
  130. set_properties(RH_RF24_PROPERTY_PKT_CONFIG1, pkt_config1, sizeof(pkt_config1));
  131. uint8_t pkt_len[] = { 0x02, 0x01, 0x00 };
  132. set_properties(RH_RF24_PROPERTY_PKT_LEN, pkt_len, sizeof(pkt_len));
  133. uint8_t pkt_field1[] = { 0x00, 0x01, 0x00, RH_RF24_FIELD_CONFIG_CRC_START | RH_RF24_FIELD_CONFIG_SEND_CRC | RH_RF24_FIELD_CONFIG_CHECK_CRC | RH_RF24_FIELD_CONFIG_CRC_ENABLE };
  134. set_properties(RH_RF24_PROPERTY_PKT_FIELD_1_LENGTH_12_8, pkt_field1, sizeof(pkt_field1));
  135. uint8_t pkt_field2[] = { 0x00, sizeof(_buf), 0x00, RH_RF24_FIELD_CONFIG_CRC_START | RH_RF24_FIELD_CONFIG_SEND_CRC | RH_RF24_FIELD_CONFIG_CHECK_CRC | RH_RF24_FIELD_CONFIG_CRC_ENABLE };
  136. set_properties(RH_RF24_PROPERTY_PKT_FIELD_2_LENGTH_12_8, pkt_field2, sizeof(pkt_field2));
  137. // Clear all other fields so they are never used, irrespective of the radio_config
  138. uint8_t pkt_fieldn[] = { 0x00, 0x00, 0x00, 0x00 };
  139. set_properties(RH_RF24_PROPERTY_PKT_FIELD_3_LENGTH_12_8, pkt_fieldn, sizeof(pkt_fieldn));
  140. set_properties(RH_RF24_PROPERTY_PKT_FIELD_4_LENGTH_12_8, pkt_fieldn, sizeof(pkt_fieldn));
  141. set_properties(RH_RF24_PROPERTY_PKT_FIELD_5_LENGTH_12_8, pkt_fieldn, sizeof(pkt_fieldn));
  142. // The following can be changed later by the user if necessary.
  143. // Set up default configuration
  144. setCRCPolynomial(CRC_16_IBM);
  145. uint8_t syncwords[] = { 0x2d, 0xd4 };
  146. setSyncWords(syncwords, sizeof(syncwords)); // Same as RF22's
  147. // Reasonably fast and reliable default speed and modulation
  148. setModemConfig(GFSK_Rb5Fd10);
  149. // 3 would be sufficient, but this is the same as RF22's
  150. // actualy, 4 seems to work much better for some modulations
  151. setPreambleLength(4);
  152. // An innocuous ISM frequency, same as RF22's
  153. setFrequency(434.0);
  154. // About 2.4dBm on RFM24:
  155. setTxPower(0x10);
  156. return true;
  157. }
  158. // C++ level interrupt handler for this instance
  159. void RH_RF24::handleInterrupt()
  160. {
  161. uint8_t status[8];
  162. command(RH_RF24_CMD_GET_INT_STATUS, NULL, 0, status, sizeof(status));
  163. // Decode and handle the interrupt bits we are interested in
  164. // if (status[0] & RH_RF24_INT_STATUS_CHIP_INT_STATUS)
  165. if (status[0] & RH_RF24_INT_STATUS_MODEM_INT_STATUS)
  166. {
  167. // if (status[4] & RH_RF24_INT_STATUS_INVALID_PREAMBLE)
  168. if (status[4] & RH_RF24_INT_STATUS_INVALID_SYNC)
  169. {
  170. // After INVALID_SYNC, sometimes the radio gets into a silly state and subsequently reports it for every packet
  171. // Need to reset the radio and clear the RX FIFO, cause sometimes theres junk there too
  172. _mode = RHModeIdle;
  173. clearRxFifo();
  174. clearBuffer();
  175. }
  176. }
  177. if (status[0] & RH_RF24_INT_STATUS_PH_INT_STATUS)
  178. {
  179. if (status[2] & RH_RF24_INT_STATUS_CRC_ERROR)
  180. {
  181. // CRC Error
  182. // Radio automatically went to _idleMode
  183. _mode = RHModeIdle;
  184. _rxBad++;
  185. clearRxFifo();
  186. clearBuffer();
  187. }
  188. if (status[2] & RH_RF24_INT_STATUS_PACKET_SENT)
  189. {
  190. _txGood++;
  191. // Transmission does not automatically clear the tx buffer.
  192. // Could retransmit if we wanted
  193. // RH_RF24 configured to transition automatically to Idle after packet sent
  194. _mode = RHModeIdle;
  195. clearBuffer();
  196. }
  197. if (status[2] & RH_RF24_INT_STATUS_PACKET_RX)
  198. {
  199. // A complete message has been received with good CRC
  200. // Get the RSSI, configured to latch at sync detect in radio_config
  201. uint8_t modem_status[6];
  202. command(RH_RF24_CMD_GET_MODEM_STATUS, NULL, 0, modem_status, sizeof(modem_status));
  203. _lastRssi = modem_status[3];
  204. _lastPreambleTime = millis();
  205. // Save it in our buffer
  206. readNextFragment();
  207. // And see if we have a valid message
  208. validateRxBuf();
  209. // Radio will have transitioned automatically to the _idleMode
  210. _mode = RHModeIdle;
  211. }
  212. if (status[2] & RH_RF24_INT_STATUS_TX_FIFO_ALMOST_EMPTY)
  213. {
  214. // TX FIFO almost empty, maybe send another chunk, if there is one
  215. sendNextFragment();
  216. }
  217. if (status[2] & RH_RF24_INT_STATUS_RX_FIFO_ALMOST_FULL)
  218. {
  219. // Some more data to read, get it
  220. readNextFragment();
  221. }
  222. }
  223. }
  224. // Check whether the latest received message is complete and uncorrupted
  225. void RH_RF24::validateRxBuf()
  226. {
  227. // Validate headers etc
  228. if (_bufLen >= RH_RF24_HEADER_LEN)
  229. {
  230. _rxHeaderTo = _buf[0];
  231. _rxHeaderFrom = _buf[1];
  232. _rxHeaderId = _buf[2];
  233. _rxHeaderFlags = _buf[3];
  234. if (_promiscuous ||
  235. _rxHeaderTo == _thisAddress ||
  236. _rxHeaderTo == RH_BROADCAST_ADDRESS)
  237. {
  238. // Its for us
  239. _rxGood++;
  240. _rxBufValid = true;
  241. }
  242. }
  243. }
  244. bool RH_RF24::clearRxFifo()
  245. {
  246. uint8_t fifo_clear[] = { 0x02 };
  247. return command(RH_RF24_CMD_FIFO_INFO, fifo_clear, sizeof(fifo_clear));
  248. }
  249. void RH_RF24::clearBuffer()
  250. {
  251. _bufLen = 0;
  252. _txBufSentIndex = 0;
  253. _rxBufValid = false;
  254. }
  255. // These are low level functions that call the interrupt handler for the correct
  256. // instance of RH_RF24.
  257. // 3 interrupts allows us to have 3 different devices
  258. void RH_RF24::isr0()
  259. {
  260. if (_deviceForInterrupt[0])
  261. _deviceForInterrupt[0]->handleInterrupt();
  262. }
  263. void RH_RF24::isr1()
  264. {
  265. if (_deviceForInterrupt[1])
  266. _deviceForInterrupt[1]->handleInterrupt();
  267. }
  268. void RH_RF24::isr2()
  269. {
  270. if (_deviceForInterrupt[2])
  271. _deviceForInterrupt[2]->handleInterrupt();
  272. }
  273. bool RH_RF24::available()
  274. {
  275. if (_mode == RHModeTx)
  276. return false;
  277. if (!_rxBufValid)
  278. setModeRx(); // Make sure we are receiving
  279. return _rxBufValid;
  280. }
  281. bool RH_RF24::recv(uint8_t* buf, uint8_t* len)
  282. {
  283. if (!available())
  284. return false;
  285. // CAUTION: first 4 octets of _buf contain the headers
  286. if (buf && len && (_bufLen >= RH_RF24_HEADER_LEN))
  287. {
  288. ATOMIC_BLOCK_START;
  289. if (*len > _bufLen - RH_RF24_HEADER_LEN)
  290. *len = _bufLen - RH_RF24_HEADER_LEN;
  291. memcpy(buf, _buf + RH_RF24_HEADER_LEN, *len);
  292. ATOMIC_BLOCK_END;
  293. }
  294. clearBuffer(); // Got the most recent message
  295. return true;
  296. }
  297. bool RH_RF24::send(const uint8_t* data, uint8_t len)
  298. {
  299. if (len > RH_RF24_MAX_MESSAGE_LEN)
  300. return false;
  301. waitPacketSent(); // Make sure we dont interrupt an outgoing message
  302. setModeIdle(); // Prevent RX while filling the fifo
  303. // Put the payload in the FIFO
  304. // First the length in fixed length field 1. This wont appear in the receiver fifo since
  305. // we have turned off IN_FIFO in PKT_LEN
  306. _buf[0] = len + RH_RF24_HEADER_LEN;
  307. // Now the rest of the payload in variable length field 2
  308. // First the headers
  309. _buf[1] = _txHeaderTo;
  310. _buf[2] = _txHeaderFrom;
  311. _buf[3] = _txHeaderId;
  312. _buf[4] = _txHeaderFlags;
  313. // Then the message
  314. memcpy(_buf + 1 + RH_RF24_HEADER_LEN, data, len);
  315. _bufLen = len + 1 + RH_RF24_HEADER_LEN;
  316. _txBufSentIndex = 0;
  317. // Set the field 2 length to the variable payload length
  318. uint8_t l[] = { (uint8_t)(len + RH_RF24_HEADER_LEN)};
  319. set_properties(RH_RF24_PROPERTY_PKT_FIELD_2_LENGTH_7_0, l, sizeof(l));
  320. sendNextFragment();
  321. setModeTx();
  322. return true;
  323. }
  324. // This is different to command() since we must not wait for CTS
  325. bool RH_RF24::writeTxFifo(uint8_t *data, uint8_t len)
  326. {
  327. ATOMIC_BLOCK_START;
  328. _spi.beginTransaction();
  329. // First send the command
  330. digitalWrite(_slaveSelectPin, LOW);
  331. _spi.transfer(RH_RF24_CMD_TX_FIFO_WRITE);
  332. // Now write any write data
  333. while (len--)
  334. _spi.transfer(*data++);
  335. digitalWrite(_slaveSelectPin, HIGH);
  336. _spi.endTransaction();
  337. ATOMIC_BLOCK_END;
  338. return true;
  339. }
  340. void RH_RF24::sendNextFragment()
  341. {
  342. if (_txBufSentIndex < _bufLen)
  343. {
  344. // Some left to send?
  345. uint8_t len = _bufLen - _txBufSentIndex;
  346. // But dont send too much, see how much room is left
  347. uint8_t fifo_info[2];
  348. command(RH_RF24_CMD_FIFO_INFO, NULL, 0, fifo_info, sizeof(fifo_info));
  349. // fifo_info[1] is space left in TX FIFO
  350. if (len > fifo_info[1])
  351. len = fifo_info[1];
  352. writeTxFifo(_buf + _txBufSentIndex, len);
  353. _txBufSentIndex += len;
  354. }
  355. }
  356. void RH_RF24::readNextFragment()
  357. {
  358. // Get the packet length from the RX FIFO length
  359. uint8_t fifo_info[1];
  360. command(RH_RF24_CMD_FIFO_INFO, NULL, 0, fifo_info, sizeof(fifo_info));
  361. uint8_t fifo_len = fifo_info[0];
  362. // Check for overflow
  363. if ((_bufLen + fifo_len) > sizeof(_buf))
  364. {
  365. // Overflow pending
  366. _rxBad++;
  367. setModeIdle();
  368. clearRxFifo();
  369. clearBuffer();
  370. return;
  371. }
  372. // So we have room
  373. // Now read the fifo_len bytes from the RX FIFO
  374. // This is different to command() since we dont wait for CTS
  375. _spi.beginTransaction();
  376. digitalWrite(_slaveSelectPin, LOW);
  377. _spi.transfer(RH_RF24_CMD_RX_FIFO_READ);
  378. uint8_t* p = _buf + _bufLen;
  379. uint8_t l = fifo_len;
  380. while (l--)
  381. *p++ = _spi.transfer(0);
  382. digitalWrite(_slaveSelectPin, HIGH);
  383. _spi.endTransaction();
  384. _bufLen += fifo_len;
  385. }
  386. uint8_t RH_RF24::maxMessageLength()
  387. {
  388. return RH_RF24_MAX_MESSAGE_LEN;
  389. }
  390. // Sets registers from a canned modem configuration structure
  391. void RH_RF24::setModemRegisters(const ModemConfig* config)
  392. {
  393. // This list also generated with convert.pl
  394. set_properties(0x2000, &config->prop_2000, 1);
  395. set_properties(0x2003, &config->prop_2003, 1);
  396. set_properties(0x2004, &config->prop_2004, 1);
  397. set_properties(0x2005, &config->prop_2005, 1);
  398. set_properties(0x2006, &config->prop_2006, 1);
  399. set_properties(0x200b, &config->prop_200b, 1);
  400. set_properties(0x200c, &config->prop_200c, 1);
  401. set_properties(0x2018, &config->prop_2018, 1);
  402. set_properties(0x201e, &config->prop_201e, 1);
  403. set_properties(0x201f, &config->prop_201f, 1);
  404. set_properties(0x2022, &config->prop_2022, 1);
  405. set_properties(0x2023, &config->prop_2023, 1);
  406. set_properties(0x2024, &config->prop_2024, 1);
  407. set_properties(0x2025, &config->prop_2025, 1);
  408. set_properties(0x2026, &config->prop_2026, 1);
  409. set_properties(0x2027, &config->prop_2027, 1);
  410. set_properties(0x2028, &config->prop_2028, 1);
  411. set_properties(0x2029, &config->prop_2029, 1);
  412. set_properties(0x202d, &config->prop_202d, 1);
  413. set_properties(0x202e, &config->prop_202e, 1);
  414. set_properties(0x202f, &config->prop_202f, 1);
  415. set_properties(0x2030, &config->prop_2030, 1);
  416. set_properties(0x2031, &config->prop_2031, 1);
  417. set_properties(0x2035, &config->prop_2035, 1);
  418. set_properties(0x2038, &config->prop_2038, 1);
  419. set_properties(0x2039, &config->prop_2039, 1);
  420. set_properties(0x203a, &config->prop_203a, 1);
  421. set_properties(0x203b, &config->prop_203b, 1);
  422. set_properties(0x203c, &config->prop_203c, 1);
  423. set_properties(0x203d, &config->prop_203d, 1);
  424. set_properties(0x203e, &config->prop_203e, 1);
  425. set_properties(0x203f, &config->prop_203f, 1);
  426. set_properties(0x2040, &config->prop_2040, 1);
  427. set_properties(0x2043, &config->prop_2043, 1);
  428. set_properties(0x2045, &config->prop_2045, 1);
  429. set_properties(0x2046, &config->prop_2046, 1);
  430. set_properties(0x2047, &config->prop_2047, 1);
  431. set_properties(0x204e, &config->prop_204e, 1);
  432. set_properties(0x2100, &config->prop_2100, 1);
  433. set_properties(0x2101, &config->prop_2101, 1);
  434. set_properties(0x2102, &config->prop_2102, 1);
  435. set_properties(0x2103, &config->prop_2103, 1);
  436. set_properties(0x2104, &config->prop_2104, 1);
  437. set_properties(0x2105, &config->prop_2105, 1);
  438. set_properties(0x2106, &config->prop_2106, 1);
  439. set_properties(0x2107, &config->prop_2107, 1);
  440. set_properties(0x2108, &config->prop_2108, 1);
  441. set_properties(0x2109, &config->prop_2109, 1);
  442. set_properties(0x210a, &config->prop_210a, 1);
  443. set_properties(0x210b, &config->prop_210b, 1);
  444. set_properties(0x210c, &config->prop_210c, 1);
  445. set_properties(0x210d, &config->prop_210d, 1);
  446. set_properties(0x210e, &config->prop_210e, 1);
  447. set_properties(0x210f, &config->prop_210f, 1);
  448. set_properties(0x2110, &config->prop_2110, 1);
  449. set_properties(0x2111, &config->prop_2111, 1);
  450. set_properties(0x2112, &config->prop_2112, 1);
  451. set_properties(0x2113, &config->prop_2113, 1);
  452. set_properties(0x2114, &config->prop_2114, 1);
  453. set_properties(0x2115, &config->prop_2115, 1);
  454. set_properties(0x2116, &config->prop_2116, 1);
  455. set_properties(0x2117, &config->prop_2117, 1);
  456. set_properties(0x2118, &config->prop_2118, 1);
  457. set_properties(0x2119, &config->prop_2119, 1);
  458. set_properties(0x211a, &config->prop_211a, 1);
  459. set_properties(0x211b, &config->prop_211b, 1);
  460. set_properties(0x211c, &config->prop_211c, 1);
  461. set_properties(0x211d, &config->prop_211d, 1);
  462. set_properties(0x211e, &config->prop_211e, 1);
  463. set_properties(0x211f, &config->prop_211f, 1);
  464. set_properties(0x2120, &config->prop_2120, 1);
  465. set_properties(0x2121, &config->prop_2121, 1);
  466. set_properties(0x2122, &config->prop_2122, 1);
  467. set_properties(0x2123, &config->prop_2123, 1);
  468. set_properties(0x2203, &config->prop_2203, 1);
  469. set_properties(0x2300, &config->prop_2300, 1);
  470. set_properties(0x2301, &config->prop_2301, 1);
  471. set_properties(0x2303, &config->prop_2303, 1);
  472. set_properties(0x2304, &config->prop_2304, 1);
  473. set_properties(0x2305, &config->prop_2305, 1);
  474. }
  475. // Set one of the canned Modem configs
  476. // Returns true if its a valid choice
  477. bool RH_RF24::setModemConfig(ModemConfigChoice index)
  478. {
  479. if (index > (signed int)(sizeof(MODEM_CONFIG_TABLE) / sizeof(ModemConfig)))
  480. return false;
  481. ModemConfig cfg;
  482. memcpy_P(&cfg, &MODEM_CONFIG_TABLE[index], sizeof(RH_RF24::ModemConfig));
  483. setModemRegisters(&cfg);
  484. return true;
  485. }
  486. void RH_RF24::setPreambleLength(uint16_t bytes)
  487. {
  488. uint8_t config[] = { (uint8_t)bytes, 0x14, 0x00, 0x00,
  489. RH_RF24_PREAMBLE_FIRST_1 | RH_RF24_PREAMBLE_LENGTH_BYTES | RH_RF24_PREAMBLE_STANDARD_1010};
  490. set_properties(RH_RF24_PROPERTY_PREAMBLE_TX_LENGTH, config, sizeof(config));
  491. }
  492. bool RH_RF24::setCRCPolynomial(CRCPolynomial polynomial)
  493. {
  494. if (polynomial >= CRC_NONE &&
  495. polynomial <= CRC_Castagnoli)
  496. {
  497. // Caution this only has effect if CRCs are enabled
  498. uint8_t config[] = { (uint8_t)((polynomial & RH_RF24_CRC_MASK) | RH_RF24_CRC_SEED_ALL_1S) };
  499. return set_properties(RH_RF24_PROPERTY_PKT_CRC_CONFIG, config, sizeof(config));
  500. }
  501. else
  502. return false;
  503. }
  504. void RH_RF24::setSyncWords(const uint8_t* syncWords, uint8_t len)
  505. {
  506. if (len > 4 || len < 1)
  507. return;
  508. uint8_t config[] = { (uint8_t)(len-1), 0, 0, 0, 0};
  509. memcpy(config+1, syncWords, len);
  510. set_properties(RH_RF24_PROPERTY_SYNC_CONFIG, config, sizeof(config));
  511. }
  512. bool RH_RF24::setFrequency(float centre, float afcPullInRange)
  513. {
  514. // See Si446x Data Sheet section 5.3.1
  515. // Also the Si446x PLL Synthesizer / VCO_CNT Calculator Rev 0.4
  516. uint8_t outdiv;
  517. uint8_t band;
  518. if (_deviceType == 0x4460 ||
  519. _deviceType == 0x4461 ||
  520. _deviceType == 0x4463)
  521. {
  522. // Non-continuous frequency bands
  523. if (centre <= 1050.0 && centre >= 850.0)
  524. outdiv = 4, band = 0;
  525. else if (centre <= 525.0 && centre >= 425.0)
  526. outdiv = 8, band = 2;
  527. else if (centre <= 350.0 && centre >= 284.0)
  528. outdiv = 12, band = 3;
  529. else if (centre <= 175.0 && centre >= 142.0)
  530. outdiv = 24, band = 5;
  531. else
  532. return false;
  533. }
  534. else
  535. {
  536. // 0x4464
  537. // Continuous frequency bands
  538. if (centre <= 960.0 && centre >= 675.0)
  539. outdiv = 4, band = 1;
  540. else if (centre < 675.0 && centre >= 450.0)
  541. outdiv = 6, band = 2;
  542. else if (centre < 450.0 && centre >= 338.0)
  543. outdiv = 8, band = 3;
  544. else if (centre < 338.0 && centre >= 225.0)
  545. outdiv = 12, band = 4;
  546. else if (centre < 225.0 && centre >= 169.0)
  547. outdiv = 16, band = 4;
  548. else if (centre < 169.0 && centre >= 119.0)
  549. outdiv = 24, band = 5;
  550. else
  551. return false;
  552. }
  553. // Set the MODEM_CLKGEN_BAND (not documented)
  554. uint8_t modem_clkgen[] = { (uint8_t)(band + 8) };
  555. if (!set_properties(RH_RF24_PROPERTY_MODEM_CLKGEN_BAND, modem_clkgen, sizeof(modem_clkgen)))
  556. return false;
  557. centre *= 1000000.0; // Convert to Hz
  558. // Now generate the RF frequency properties
  559. // Need the Xtal/XO freq from the radio_config file:
  560. uint32_t xtal_frequency[1] = RADIO_CONFIGURATION_DATA_RADIO_XO_FREQ;
  561. unsigned long f_pfd = 2 * xtal_frequency[0] / outdiv;
  562. unsigned int n = ((unsigned int)(centre / f_pfd)) - 1;
  563. float ratio = centre / (float)f_pfd;
  564. float rest = ratio - (float)n;
  565. unsigned long m = (unsigned long)(rest * 524288UL);
  566. unsigned int m2 = m / 0x10000;
  567. unsigned int m1 = (m - m2 * 0x10000) / 0x100;
  568. unsigned int m0 = (m - m2 * 0x10000 - m1 * 0x100);
  569. // PROP_FREQ_CONTROL_GROUP
  570. uint8_t freq_control[] = { (uint8_t)n, (uint8_t)m2, (uint8_t)m1, (uint8_t)m0 };
  571. return set_properties(RH_RF24_PROPERTY_FREQ_CONTROL_INTE, freq_control, sizeof(freq_control));
  572. }
  573. void RH_RF24::setModeIdle()
  574. {
  575. if (_mode != RHModeIdle)
  576. {
  577. // Set the antenna switch pins using the GPIO, assuming we have an RFM module with antenna switch
  578. uint8_t config[] = { RH_RF24_GPIO_HIGH, RH_RF24_GPIO_HIGH };
  579. command(RH_RF24_CMD_GPIO_PIN_CFG, config, sizeof(config));
  580. uint8_t state[] = { _idleMode };
  581. command(RH_RF24_CMD_REQUEST_DEVICE_STATE, state, sizeof(state));
  582. _mode = RHModeIdle;
  583. }
  584. }
  585. bool RH_RF24::sleep()
  586. {
  587. if (_mode != RHModeSleep)
  588. {
  589. uint8_t state[] = { RH_RF24_DEVICE_STATE_SLEEP };
  590. command(RH_RF24_CMD_REQUEST_DEVICE_STATE, state, sizeof(state));
  591. _mode = RHModeSleep;
  592. }
  593. return true;
  594. }
  595. void RH_RF24::setModeRx()
  596. {
  597. if (_mode != RHModeRx)
  598. {
  599. // CAUTION: we cant clear the rx buffers here, else we set up a race condition
  600. // with the _rxBufValid test in available()
  601. // Tell the receiver the max data length we will accept (a TX may have changed it)
  602. uint8_t l[] = { sizeof(_buf) };
  603. set_properties(RH_RF24_PROPERTY_PKT_FIELD_2_LENGTH_7_0, l, sizeof(l));
  604. // Set the antenna switch pins using the GPIO, assuming we have an RFM module with antenna switch
  605. uint8_t gpio_config[] = { RH_RF24_GPIO_HIGH, RH_RF24_GPIO_LOW };
  606. command(RH_RF24_CMD_GPIO_PIN_CFG, gpio_config, sizeof(gpio_config));
  607. uint8_t rx_config[] = { 0x00, RH_RF24_CONDITION_RX_START_IMMEDIATE, 0x00, 0x00, _idleMode, _idleMode, _idleMode};
  608. command(RH_RF24_CMD_START_RX, rx_config, sizeof(rx_config));
  609. _mode = RHModeRx;
  610. }
  611. }
  612. void RH_RF24::setModeTx()
  613. {
  614. if (_mode != RHModeTx)
  615. {
  616. // Set the antenna switch pins using the GPIO, assuming we have an RFM module with antenna switch
  617. uint8_t config[] = { RH_RF24_GPIO_LOW, RH_RF24_GPIO_HIGH };
  618. command(RH_RF24_CMD_GPIO_PIN_CFG, config, sizeof(config));
  619. uint8_t tx_params[] = { 0x00,
  620. (uint8_t)((_idleMode << 4) | RH_RF24_CONDITION_RETRANSMIT_NO | RH_RF24_CONDITION_START_IMMEDIATE)};
  621. command(RH_RF24_CMD_START_TX, tx_params, sizeof(tx_params));
  622. _mode = RHModeTx;
  623. }
  624. }
  625. void RH_RF24::setTxPower(uint8_t power)
  626. {
  627. uint8_t pa_bias_clkduty = 0;
  628. // These calculations valid for advertised power from Si chips at Vcc = 3.3V
  629. // you may get lower power from RFM modules, depending on Vcc voltage, antenna etc
  630. if (_deviceType == 0x4460)
  631. {
  632. // 0x4f = 13dBm
  633. pa_bias_clkduty = 0xc0;
  634. if (power > 0x4f)
  635. power = 0x4f;
  636. }
  637. else if (_deviceType == 0x4461)
  638. {
  639. // 0x7f = 16dBm
  640. pa_bias_clkduty = 0xc0;
  641. if (power > 0x7f)
  642. power = 0x7f;
  643. }
  644. else if (_deviceType == 0x4463 || _deviceType == 0x4464 )
  645. {
  646. // 0x7f = 20dBm
  647. pa_bias_clkduty = 0x00; // Per WDS suggestion
  648. if (power > 0x7f)
  649. power = 0x7f;
  650. }
  651. uint8_t power_properties[] = {0x18, 0x00, 0x00 }; // PA_MODE from WDS sugggestions (why?)
  652. power_properties[1] = power;
  653. power_properties[2] = pa_bias_clkduty;
  654. set_properties(RH_RF24_PROPERTY_PA_MODE, power_properties, sizeof(power_properties));
  655. }
  656. // Caution: There was a bug in A1 hardware that will not handle 1 byte commands.
  657. bool RH_RF24::command(uint8_t cmd, const uint8_t* write_buf, uint8_t write_len, uint8_t* read_buf, uint8_t read_len)
  658. {
  659. bool done = false;
  660. ATOMIC_BLOCK_START;
  661. // First send the command
  662. _spi.beginTransaction();
  663. digitalWrite(_slaveSelectPin, LOW);
  664. _spi.transfer(cmd);
  665. // Now write any write data
  666. if (write_buf && write_len)
  667. {
  668. while (write_len--)
  669. _spi.transfer(*write_buf++);
  670. }
  671. // Sigh, the RFM26 at least has problems if we deselect too quickly :-(
  672. // Innocuous timewaster:
  673. digitalWrite(_slaveSelectPin, LOW);
  674. // And finalise the command
  675. digitalWrite(_slaveSelectPin, HIGH);
  676. uint16_t count; // Number of times we have tried to get CTS
  677. for (count = 0; !done && count < RH_RF24_CTS_RETRIES; count++)
  678. {
  679. // Wait for the CTS
  680. digitalWrite(_slaveSelectPin, LOW);
  681. _spi.transfer(RH_RF24_CMD_READ_BUF);
  682. if (_spi.transfer(0) == RH_RF24_REPLY_CTS)
  683. {
  684. // Now read any expected reply data
  685. if (read_buf && read_len)
  686. {
  687. while (read_len--)
  688. {
  689. *read_buf++ = _spi.transfer(0);
  690. }
  691. }
  692. done = true;
  693. }
  694. // Sigh, the RFM26 at least has problems if we deselect too quickly :-(
  695. // Innocuous timewaster:
  696. digitalWrite(_slaveSelectPin, LOW);
  697. // Finalise the read
  698. digitalWrite(_slaveSelectPin, HIGH);
  699. }
  700. _spi.endTransaction();
  701. ATOMIC_BLOCK_END;
  702. return done; // False if too many attempts at CTS
  703. }
  704. bool RH_RF24::configure(const uint8_t* commands)
  705. {
  706. // Command strings are constructed in radio_config_Si4460.h
  707. // Each command starts with a count of the bytes in that command:
  708. // <bytecount> <command> <bytecount-2 bytes of args/data>
  709. uint8_t next_cmd_len;
  710. while (memcpy_P(&next_cmd_len, commands, 1), next_cmd_len > 0)
  711. {
  712. uint8_t buf[20]; // As least big as the biggest permitted command/property list of 15
  713. memcpy_P(buf, commands+1, next_cmd_len);
  714. command(buf[0], buf+1, next_cmd_len - 1);
  715. commands += (next_cmd_len + 1);
  716. }
  717. return true;
  718. }
  719. void RH_RF24::power_on_reset()
  720. {
  721. // Sigh: its necessary to control the SDN pin to reset this ship.
  722. // Tying it to GND does not produce reliable startups
  723. // Per Si4464 Data Sheet 3.3.2
  724. digitalWrite(_sdnPin, HIGH); // So we dont get a glitch after setting pinMode OUTPUT
  725. pinMode(_sdnPin, OUTPUT);
  726. delay(10);
  727. digitalWrite(_sdnPin, LOW);
  728. delay(10);
  729. }
  730. bool RH_RF24::cmd_clear_all_interrupts()
  731. {
  732. uint8_t write_buf[] = { 0x00, 0x00, 0x00 };
  733. return command(RH_RF24_CMD_GET_INT_STATUS, write_buf, sizeof(write_buf));
  734. }
  735. bool RH_RF24::set_properties(uint16_t firstProperty, const uint8_t* values, uint8_t count)
  736. {
  737. uint8_t buf[15];
  738. buf[0] = firstProperty >> 8; // GROUP
  739. buf[1] = count; // NUM_PROPS
  740. buf[2] = firstProperty & 0xff; // START_PROP
  741. uint8_t i;
  742. for (i = 0; i < 12 && i < count; i++)
  743. buf[3 + i] = values[i]; // DATAn
  744. return command(RH_RF24_CMD_SET_PROPERTY, buf, count + 3);
  745. }
  746. bool RH_RF24::get_properties(uint16_t firstProperty, uint8_t* values, uint8_t count)
  747. {
  748. if (count > 16)
  749. count = 16;
  750. uint8_t buf[3];
  751. buf[0] = firstProperty >> 8; // GROUP
  752. buf[1] = count; // NUM_PROPS
  753. buf[2] = firstProperty & 0xff; // START_PROP
  754. return command(RH_RF24_CMD_GET_PROPERTY, buf, sizeof(buf), values, count);
  755. }
  756. float RH_RF24::get_temperature()
  757. {
  758. uint8_t write_buf[] = { 0x10 };
  759. uint8_t read_buf[8];
  760. // Takes nearly 4ms
  761. command(RH_RF24_CMD_GET_ADC_READING, write_buf, sizeof(write_buf), read_buf, sizeof(read_buf));
  762. uint16_t temp_adc = (read_buf[4] << 8) | read_buf[5];
  763. return ((800 + read_buf[6]) / 4096.0) * temp_adc - ((read_buf[7] / 2) + 256);
  764. }
  765. float RH_RF24::get_battery_voltage()
  766. {
  767. uint8_t write_buf[] = { 0x08 };
  768. uint8_t read_buf[8];
  769. // Takes nearly 4ms
  770. command(RH_RF24_CMD_GET_ADC_READING, write_buf, sizeof(write_buf), read_buf, sizeof(read_buf));
  771. uint16_t battery_adc = (read_buf[2] << 8) | read_buf[3];
  772. return 3.0 * battery_adc / 1280;
  773. }
  774. float RH_RF24::get_gpio_voltage(uint8_t gpio)
  775. {
  776. uint8_t write_buf[] = { 0x04 };
  777. uint8_t read_buf[8];
  778. write_buf[0] |= (gpio & 0x3);
  779. // Takes nearly 4ms
  780. command(RH_RF24_CMD_GET_ADC_READING, write_buf, sizeof(write_buf), read_buf, sizeof(read_buf));
  781. uint16_t gpio_adc = (read_buf[0] << 8) | read_buf[1];
  782. return 3.0 * gpio_adc / 1280;
  783. }
  784. uint8_t RH_RF24::frr_read(uint8_t reg)
  785. {
  786. uint8_t ret;
  787. // Do not wait for CTS
  788. ATOMIC_BLOCK_START;
  789. _spi.beginTransaction();
  790. // First send the command
  791. digitalWrite(_slaveSelectPin, LOW);
  792. _spi.transfer(RH_RF24_PROPERTY_FRR_CTL_A_MODE + reg);
  793. // Get the fast response
  794. ret = _spi.transfer(0);
  795. digitalWrite(_slaveSelectPin, HIGH);
  796. _spi.endTransaction();
  797. ATOMIC_BLOCK_END;
  798. return ret;
  799. }
  800. // List of command replies to be printed by prinRegisters()
  801. PROGMEM static const RH_RF24::CommandInfo commands[] =
  802. {
  803. { RH_RF24_CMD_PART_INFO, 8 },
  804. { RH_RF24_CMD_FUNC_INFO, 6 },
  805. { RH_RF24_CMD_GPIO_PIN_CFG, 7 },
  806. { RH_RF24_CMD_FIFO_INFO, 2 },
  807. { RH_RF24_CMD_PACKET_INFO, 2 },
  808. { RH_RF24_CMD_GET_INT_STATUS, 8 },
  809. { RH_RF24_CMD_GET_PH_STATUS, 2 },
  810. { RH_RF24_CMD_GET_MODEM_STATUS, 8 },
  811. { RH_RF24_CMD_GET_CHIP_STATUS, 3 },
  812. { RH_RF24_CMD_REQUEST_DEVICE_STATE, 2 },
  813. };
  814. #define NUM_COMMAND_INFO (sizeof(commands)/sizeof(CommandInfo))
  815. // List of properties to be printed by printRegisters()
  816. PROGMEM static const uint16_t properties[] =
  817. {
  818. RH_RF24_PROPERTY_GLOBAL_XO_TUNE,
  819. RH_RF24_PROPERTY_GLOBAL_CLK_CFG,
  820. RH_RF24_PROPERTY_GLOBAL_LOW_BATT_THRESH,
  821. RH_RF24_PROPERTY_GLOBAL_CONFIG,
  822. RH_RF24_PROPERTY_GLOBAL_WUT_CONFIG,
  823. RH_RF24_PROPERTY_GLOBAL_WUT_M_15_8,
  824. RH_RF24_PROPERTY_GLOBAL_WUT_M_7_0,
  825. RH_RF24_PROPERTY_GLOBAL_WUT_R,
  826. RH_RF24_PROPERTY_GLOBAL_WUT_LDC,
  827. RH_RF24_PROPERTY_INT_CTL_ENABLE,
  828. RH_RF24_PROPERTY_INT_CTL_PH_ENABLE,
  829. RH_RF24_PROPERTY_INT_CTL_MODEM_ENABLE,
  830. RH_RF24_PROPERTY_INT_CTL_CHIP_ENABLE,
  831. RH_RF24_PROPERTY_FRR_CTL_A_MODE,
  832. RH_RF24_PROPERTY_FRR_CTL_B_MODE,
  833. RH_RF24_PROPERTY_FRR_CTL_C_MODE,
  834. RH_RF24_PROPERTY_FRR_CTL_D_MODE,
  835. RH_RF24_PROPERTY_PREAMBLE_TX_LENGTH,
  836. RH_RF24_PROPERTY_PREAMBLE_CONFIG_STD_1,
  837. RH_RF24_PROPERTY_PREAMBLE_CONFIG_NSTD,
  838. RH_RF24_PROPERTY_PREAMBLE_CONFIG_STD_2,
  839. RH_RF24_PROPERTY_PREAMBLE_CONFIG,
  840. RH_RF24_PROPERTY_PREAMBLE_PATTERN_31_24,
  841. RH_RF24_PROPERTY_PREAMBLE_PATTERN_23_16,
  842. RH_RF24_PROPERTY_PREAMBLE_PATTERN_15_8,
  843. RH_RF24_PROPERTY_PREAMBLE_PATTERN_7_0,
  844. RH_RF24_PROPERTY_SYNC_CONFIG,
  845. RH_RF24_PROPERTY_SYNC_BITS_31_24,
  846. RH_RF24_PROPERTY_SYNC_BITS_23_16,
  847. RH_RF24_PROPERTY_SYNC_BITS_15_8,
  848. RH_RF24_PROPERTY_SYNC_BITS_7_0,
  849. RH_RF24_PROPERTY_PKT_CRC_CONFIG,
  850. RH_RF24_PROPERTY_PKT_CONFIG1,
  851. RH_RF24_PROPERTY_PKT_LEN,
  852. RH_RF24_PROPERTY_PKT_LEN_FIELD_SOURCE,
  853. RH_RF24_PROPERTY_PKT_LEN_ADJUST,
  854. RH_RF24_PROPERTY_PKT_TX_THRESHOLD,
  855. RH_RF24_PROPERTY_PKT_RX_THRESHOLD,
  856. RH_RF24_PROPERTY_PKT_FIELD_1_LENGTH_12_8,
  857. RH_RF24_PROPERTY_PKT_FIELD_1_LENGTH_7_0,
  858. RH_RF24_PROPERTY_PKT_FIELD_1_CONFIG,
  859. RH_RF24_PROPERTY_PKT_FIELD_1_CRC_CONFIG,
  860. RH_RF24_PROPERTY_PKT_FIELD_2_LENGTH_12_8,
  861. RH_RF24_PROPERTY_PKT_FIELD_2_LENGTH_7_0,
  862. RH_RF24_PROPERTY_PKT_FIELD_2_CONFIG,
  863. RH_RF24_PROPERTY_PKT_FIELD_2_CRC_CONFIG,
  864. RH_RF24_PROPERTY_PKT_FIELD_3_LENGTH_12_8,
  865. RH_RF24_PROPERTY_PKT_FIELD_3_LENGTH_7_0,
  866. RH_RF24_PROPERTY_PKT_FIELD_3_CONFIG,
  867. RH_RF24_PROPERTY_PKT_FIELD_3_CRC_CONFIG,
  868. RH_RF24_PROPERTY_PKT_FIELD_4_LENGTH_12_8,
  869. RH_RF24_PROPERTY_PKT_FIELD_4_LENGTH_7_0,
  870. RH_RF24_PROPERTY_PKT_FIELD_4_CONFIG,
  871. RH_RF24_PROPERTY_PKT_FIELD_4_CRC_CONFIG,
  872. RH_RF24_PROPERTY_PKT_FIELD_5_LENGTH_12_8,
  873. RH_RF24_PROPERTY_PKT_FIELD_5_LENGTH_7_0,
  874. RH_RF24_PROPERTY_PKT_FIELD_5_CONFIG,
  875. RH_RF24_PROPERTY_PKT_FIELD_5_CRC_CONFIG,
  876. RH_RF24_PROPERTY_PKT_RX_FIELD_1_LENGTH_12_8,
  877. RH_RF24_PROPERTY_PKT_RX_FIELD_1_LENGTH_7_0,
  878. RH_RF24_PROPERTY_PKT_RX_FIELD_1_CONFIG,
  879. RH_RF24_PROPERTY_PKT_RX_FIELD_1_CRC_CONFIG,
  880. RH_RF24_PROPERTY_PKT_RX_FIELD_2_LENGTH_12_8,
  881. RH_RF24_PROPERTY_PKT_RX_FIELD_2_LENGTH_7_0,
  882. RH_RF24_PROPERTY_PKT_RX_FIELD_2_CONFIG,
  883. RH_RF24_PROPERTY_PKT_RX_FIELD_2_CRC_CONFIG,
  884. RH_RF24_PROPERTY_PKT_RX_FIELD_3_LENGTH_12_8,
  885. RH_RF24_PROPERTY_PKT_RX_FIELD_3_LENGTH_7_0,
  886. RH_RF24_PROPERTY_PKT_RX_FIELD_3_CONFIG,
  887. RH_RF24_PROPERTY_PKT_RX_FIELD_3_CRC_CONFIG,
  888. RH_RF24_PROPERTY_PKT_RX_FIELD_4_LENGTH_12_8,
  889. RH_RF24_PROPERTY_PKT_RX_FIELD_4_LENGTH_7_0,
  890. RH_RF24_PROPERTY_PKT_RX_FIELD_4_CONFIG,
  891. RH_RF24_PROPERTY_PKT_RX_FIELD_4_CRC_CONFIG,
  892. RH_RF24_PROPERTY_PKT_RX_FIELD_5_LENGTH_12_8,
  893. RH_RF24_PROPERTY_PKT_RX_FIELD_5_LENGTH_7_0,
  894. RH_RF24_PROPERTY_PKT_RX_FIELD_5_CONFIG,
  895. RH_RF24_PROPERTY_PKT_RX_FIELD_5_CRC_CONFIG,
  896. RH_RF24_PROPERTY_MODEM_MOD_TYPE,
  897. RH_RF24_PROPERTY_MODEM_MAP_CONTROL,
  898. RH_RF24_PROPERTY_MODEM_DSM_CTRL,
  899. RH_RF24_PROPERTY_MODEM_DATA_RATE_2,
  900. RH_RF24_PROPERTY_MODEM_DATA_RATE_1,
  901. RH_RF24_PROPERTY_MODEM_DATA_RATE_0,
  902. RH_RF24_PROPERTY_MODEM_TX_NCO_MODE_3,
  903. RH_RF24_PROPERTY_MODEM_TX_NCO_MODE_2,
  904. RH_RF24_PROPERTY_MODEM_TX_NCO_MODE_1,
  905. RH_RF24_PROPERTY_MODEM_TX_NCO_MODE_0,
  906. RH_RF24_PROPERTY_MODEM_FREQ_DEV_2,
  907. RH_RF24_PROPERTY_MODEM_FREQ_DEV_1,
  908. RH_RF24_PROPERTY_MODEM_FREQ_DEV_0,
  909. RH_RF24_PROPERTY_MODEM_TX_RAMP_DELAY,
  910. RH_RF24_PROPERTY_MODEM_MDM_CTRL,
  911. RH_RF24_PROPERTY_MODEM_IF_CONTROL,
  912. RH_RF24_PROPERTY_MODEM_IF_FREQ_2,
  913. RH_RF24_PROPERTY_MODEM_IF_FREQ_1,
  914. RH_RF24_PROPERTY_MODEM_IF_FREQ_0,
  915. RH_RF24_PROPERTY_MODEM_DECIMATION_CFG1,
  916. RH_RF24_PROPERTY_MODEM_DECIMATION_CFG0,
  917. RH_RF24_PROPERTY_MODEM_BCR_OSR_1,
  918. RH_RF24_PROPERTY_MODEM_BCR_OSR_0,
  919. RH_RF24_PROPERTY_MODEM_BCR_NCO_OFFSET_2,
  920. RH_RF24_PROPERTY_MODEM_BCR_NCO_OFFSET_1,
  921. RH_RF24_PROPERTY_MODEM_BCR_NCO_OFFSET_0,
  922. RH_RF24_PROPERTY_MODEM_BCR_GAIN_1,
  923. RH_RF24_PROPERTY_MODEM_BCR_GAIN_0,
  924. RH_RF24_PROPERTY_MODEM_BCR_GEAR,
  925. RH_RF24_PROPERTY_MODEM_BCR_MISC1,
  926. RH_RF24_PROPERTY_MODEM_AFC_GEAR,
  927. RH_RF24_PROPERTY_MODEM_AFC_WAIT,
  928. RH_RF24_PROPERTY_MODEM_AFC_GAIN_1,
  929. RH_RF24_PROPERTY_MODEM_AFC_GAIN_0,
  930. RH_RF24_PROPERTY_MODEM_AFC_LIMITER_1,
  931. RH_RF24_PROPERTY_MODEM_AFC_LIMITER_0,
  932. RH_RF24_PROPERTY_MODEM_AFC_MISC,
  933. RH_RF24_PROPERTY_MODEM_AGC_CONTROL,
  934. RH_RF24_PROPERTY_MODEM_AGC_WINDOW_SIZE,
  935. RH_RF24_PROPERTY_MODEM_AGC_RFPD_DECAY,
  936. RH_RF24_PROPERTY_MODEM_AGC_IFPD_DECAY,
  937. RH_RF24_PROPERTY_MODEM_FSK4_GAIN1,
  938. RH_RF24_PROPERTY_MODEM_FSK4_GAIN0,
  939. RH_RF24_PROPERTY_MODEM_FSK4_TH1,
  940. RH_RF24_PROPERTY_MODEM_FSK4_TH0,
  941. RH_RF24_PROPERTY_MODEM_FSK4_MAP,
  942. RH_RF24_PROPERTY_MODEM_OOK_PDTC,
  943. RH_RF24_PROPERTY_MODEM_OOK_CNT1,
  944. RH_RF24_PROPERTY_MODEM_OOK_MISC,
  945. RH_RF24_PROPERTY_MODEM_RAW_SEARCH,
  946. RH_RF24_PROPERTY_MODEM_RAW_CONTROL,
  947. RH_RF24_PROPERTY_MODEM_RAW_EYE_1,
  948. RH_RF24_PROPERTY_MODEM_RAW_EYE_0,
  949. RH_RF24_PROPERTY_MODEM_ANT_DIV_MODE,
  950. RH_RF24_PROPERTY_MODEM_ANT_DIV_CONTROL,
  951. RH_RF24_PROPERTY_MODEM_RSSI_THRESH,
  952. RH_RF24_PROPERTY_MODEM_RSSI_JUMP_THRESH,
  953. RH_RF24_PROPERTY_MODEM_RSSI_CONTROL,
  954. RH_RF24_PROPERTY_MODEM_RSSI_CONTROL2,
  955. RH_RF24_PROPERTY_MODEM_RSSI_COMP,
  956. RH_RF24_PROPERTY_MODEM_ANT_DIV_CONT,
  957. RH_RF24_PROPERTY_MODEM_CLKGEN_BAND,
  958. RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE13_7_0,
  959. RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE12_7_0,
  960. RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE11_7_0,
  961. RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE10_7_0,
  962. RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE9_7_0,
  963. RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE8_7_0,
  964. RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE7_7_0,
  965. RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE6_7_0,
  966. RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE5_7_0,
  967. RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE4_7_0,
  968. RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE3_7_0,
  969. RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE2_7_0,
  970. RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE1_7_0,
  971. RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COE0_7_0,
  972. RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COEM0,
  973. RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COEM1,
  974. RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COEM2,
  975. RH_RF24_PROPERTY_MODEM_CHFLT_RX1_CHFLT_COEM3,
  976. RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE13_7_0,
  977. RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE12_7_0,
  978. RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE11_7_0,
  979. RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE10_7_0,
  980. RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE9_7_0,
  981. RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE8_7_0,
  982. RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE7_7_0,
  983. RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE6_7_0,
  984. RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE5_7_0,
  985. RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE4_7_0,
  986. RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE3_7_0,
  987. RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE2_7_0,
  988. RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE1_7_0,
  989. RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COE0_7_0,
  990. RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COEM0,
  991. RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COEM1,
  992. RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COEM2,
  993. RH_RF24_PROPERTY_MODEM_CHFLT_RX2_CHFLT_COEM3,
  994. RH_RF24_PROPERTY_PA_MODE,
  995. RH_RF24_PROPERTY_PA_PWR_LVL,
  996. RH_RF24_PROPERTY_PA_BIAS_CLKDUTY,
  997. RH_RF24_PROPERTY_PA_TC,
  998. RH_RF24_PROPERTY_SYNTH_PFDCP_CPFF,
  999. RH_RF24_PROPERTY_SYNTH_PFDCP_CPINT,
  1000. RH_RF24_PROPERTY_SYNTH_VCO_KV,
  1001. RH_RF24_PROPERTY_SYNTH_LPFILT3,
  1002. RH_RF24_PROPERTY_SYNTH_LPFILT2,
  1003. RH_RF24_PROPERTY_SYNTH_LPFILT1,
  1004. RH_RF24_PROPERTY_SYNTH_LPFILT0,
  1005. RH_RF24_PROPERTY_MATCH_VALUE_1,
  1006. RH_RF24_PROPERTY_MATCH_MASK_1,
  1007. RH_RF24_PROPERTY_MATCH_CTRL_1,
  1008. RH_RF24_PROPERTY_MATCH_VALUE_2,
  1009. RH_RF24_PROPERTY_MATCH_MASK_2,
  1010. RH_RF24_PROPERTY_MATCH_CTRL_2,
  1011. RH_RF24_PROPERTY_MATCH_VALUE_3,
  1012. RH_RF24_PROPERTY_MATCH_MASK_3,
  1013. RH_RF24_PROPERTY_MATCH_CTRL_3,
  1014. RH_RF24_PROPERTY_MATCH_VALUE_4,
  1015. RH_RF24_PROPERTY_MATCH_MASK_4,
  1016. RH_RF24_PROPERTY_MATCH_CTRL_4,
  1017. RH_RF24_PROPERTY_FREQ_CONTROL_INTE,
  1018. RH_RF24_PROPERTY_FREQ_CONTROL_FRAC_2,
  1019. RH_RF24_PROPERTY_FREQ_CONTROL_FRAC_1,
  1020. RH_RF24_PROPERTY_FREQ_CONTROL_FRAC_0,
  1021. RH_RF24_PROPERTY_FREQ_CONTROL_CHANNEL_STEP_SIZE_1,
  1022. RH_RF24_PROPERTY_FREQ_CONTROL_CHANNEL_STEP_SIZE_0,
  1023. RH_RF24_PROPERTY_FREQ_CONTROL_VCOCNT_RX_ADJ,
  1024. RH_RF24_PROPERTY_RX_HOP_CONTROL,
  1025. RH_RF24_PROPERTY_RX_HOP_TABLE_SIZE,
  1026. RH_RF24_PROPERTY_RX_HOP_TABLE_ENTRY_0,
  1027. };
  1028. #define NUM_PROPERTIES (sizeof(properties)/sizeof(uint16_t))
  1029. bool RH_RF24::printRegisters()
  1030. {
  1031. #ifdef RH_HAVE_SERIAL
  1032. uint8_t i;
  1033. // First print the commands that return interesting data
  1034. for (i = 0; i < NUM_COMMAND_INFO; i++)
  1035. {
  1036. CommandInfo cmd;
  1037. memcpy_P(&cmd, &commands[i], sizeof(cmd));
  1038. uint8_t buf[10]; // Big enough for the biggest command reply
  1039. if (command(cmd.cmd, NULL, 0, buf, cmd.replyLen))
  1040. {
  1041. // Print the results:
  1042. Serial.print("cmd: ");
  1043. Serial.print(cmd.cmd, HEX);
  1044. Serial.print(" : ");
  1045. uint8_t j;
  1046. for (j = 0; j < cmd.replyLen; j++)
  1047. {
  1048. Serial.print(buf[j], HEX);
  1049. Serial.print(" ");
  1050. }
  1051. Serial.println("");
  1052. }
  1053. }
  1054. // Now print the properties
  1055. for (i = 0; i < NUM_PROPERTIES; i++)
  1056. {
  1057. uint16_t prop;
  1058. memcpy_P(&prop, &properties[i], sizeof(prop));
  1059. uint8_t result;
  1060. get_properties(prop, &result, 1);
  1061. Serial.print("prop: ");
  1062. Serial.print(prop, HEX);
  1063. Serial.print(": ");
  1064. Serial.print(result, HEX);
  1065. Serial.println("");
  1066. }
  1067. #endif
  1068. return true;
  1069. }