PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

729 linhas
35KB

  1. // RH_RF95.h
  2. //
  3. // Definitions for HopeRF LoRa radios per:
  4. // http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf
  5. // http://www.hoperf.cn/upload/rfchip/RF96_97_98.pdf
  6. //
  7. // Author: Mike McCauley (mikem@airspayce.com)
  8. // Copyright (C) 2014 Mike McCauley
  9. // $Id: RH_RF95.h,v 1.11 2016/07/07 00:02:53 mikem Exp mikem $
  10. //
  11. #ifndef RH_RF95_h
  12. #define RH_RF95_h
  13. #include <RHSPIDriver.h>
  14. // This is the maximum number of interrupts the driver can support
  15. // Most Arduinos can handle 2, Megas can handle more
  16. #define RH_RF95_NUM_INTERRUPTS 3
  17. // Max number of octets the LORA Rx/Tx FIFO can hold
  18. #define RH_RF95_FIFO_SIZE 255
  19. // This is the maximum number of bytes that can be carried by the LORA.
  20. // We use some for headers, keeping fewer for RadioHead messages
  21. #define RH_RF95_MAX_PAYLOAD_LEN RH_RF95_FIFO_SIZE
  22. // The length of the headers we add.
  23. // The headers are inside the LORA's payload
  24. #define RH_RF95_HEADER_LEN 4
  25. // This is the maximum message length that can be supported by this driver.
  26. // Can be pre-defined to a smaller size (to save SRAM) prior to including this header
  27. // Here we allow for 1 byte message length, 4 bytes headers, user data and 2 bytes of FCS
  28. #ifndef RH_RF95_MAX_MESSAGE_LEN
  29. #define RH_RF95_MAX_MESSAGE_LEN (RH_RF95_MAX_PAYLOAD_LEN - RH_RF95_HEADER_LEN)
  30. #endif
  31. // The crystal oscillator frequency of the module
  32. #define RH_RF95_FXOSC 32000000.0
  33. // The Frequency Synthesizer step = RH_RF95_FXOSC / 2^^19
  34. #define RH_RF95_FSTEP (RH_RF95_FXOSC / 524288)
  35. // Register names (LoRa Mode, from table 85)
  36. #define RH_RF95_REG_00_FIFO 0x00
  37. #define RH_RF95_REG_01_OP_MODE 0x01
  38. #define RH_RF95_REG_02_RESERVED 0x02
  39. #define RH_RF95_REG_03_RESERVED 0x03
  40. #define RH_RF95_REG_04_RESERVED 0x04
  41. #define RH_RF95_REG_05_RESERVED 0x05
  42. #define RH_RF95_REG_06_FRF_MSB 0x06
  43. #define RH_RF95_REG_07_FRF_MID 0x07
  44. #define RH_RF95_REG_08_FRF_LSB 0x08
  45. #define RH_RF95_REG_09_PA_CONFIG 0x09
  46. #define RH_RF95_REG_0A_PA_RAMP 0x0a
  47. #define RH_RF95_REG_0B_OCP 0x0b
  48. #define RH_RF95_REG_0C_LNA 0x0c
  49. #define RH_RF95_REG_0D_FIFO_ADDR_PTR 0x0d
  50. #define RH_RF95_REG_0E_FIFO_TX_BASE_ADDR 0x0e
  51. #define RH_RF95_REG_0F_FIFO_RX_BASE_ADDR 0x0f
  52. #define RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR 0x10
  53. #define RH_RF95_REG_11_IRQ_FLAGS_MASK 0x11
  54. #define RH_RF95_REG_12_IRQ_FLAGS 0x12
  55. #define RH_RF95_REG_13_RX_NB_BYTES 0x13
  56. #define RH_RF95_REG_14_RX_HEADER_CNT_VALUE_MSB 0x14
  57. #define RH_RF95_REG_15_RX_HEADER_CNT_VALUE_LSB 0x15
  58. #define RH_RF95_REG_16_RX_PACKET_CNT_VALUE_MSB 0x16
  59. #define RH_RF95_REG_17_RX_PACKET_CNT_VALUE_LSB 0x17
  60. #define RH_RF95_REG_18_MODEM_STAT 0x18
  61. #define RH_RF95_REG_19_PKT_SNR_VALUE 0x19
  62. #define RH_RF95_REG_1A_PKT_RSSI_VALUE 0x1a
  63. #define RH_RF95_REG_1B_RSSI_VALUE 0x1b
  64. #define RH_RF95_REG_1C_HOP_CHANNEL 0x1c
  65. #define RH_RF95_REG_1D_MODEM_CONFIG1 0x1d
  66. #define RH_RF95_REG_1E_MODEM_CONFIG2 0x1e
  67. #define RH_RF95_REG_1F_SYMB_TIMEOUT_LSB 0x1f
  68. #define RH_RF95_REG_20_PREAMBLE_MSB 0x20
  69. #define RH_RF95_REG_21_PREAMBLE_LSB 0x21
  70. #define RH_RF95_REG_22_PAYLOAD_LENGTH 0x22
  71. #define RH_RF95_REG_23_MAX_PAYLOAD_LENGTH 0x23
  72. #define RH_RF95_REG_24_HOP_PERIOD 0x24
  73. #define RH_RF95_REG_25_FIFO_RX_BYTE_ADDR 0x25
  74. #define RH_RF95_REG_26_MODEM_CONFIG3 0x26
  75. #define RH_RF95_REG_40_DIO_MAPPING1 0x40
  76. #define RH_RF95_REG_41_DIO_MAPPING2 0x41
  77. #define RH_RF95_REG_42_VERSION 0x42
  78. #define RH_RF95_REG_4B_TCXO 0x4b
  79. #define RH_RF95_REG_4D_PA_DAC 0x4d
  80. #define RH_RF95_REG_5B_FORMER_TEMP 0x5b
  81. #define RH_RF95_REG_61_AGC_REF 0x61
  82. #define RH_RF95_REG_62_AGC_THRESH1 0x62
  83. #define RH_RF95_REG_63_AGC_THRESH2 0x63
  84. #define RH_RF95_REG_64_AGC_THRESH3 0x64
  85. // RH_RF95_REG_01_OP_MODE 0x01
  86. #define RH_RF95_LONG_RANGE_MODE 0x80
  87. #define RH_RF95_ACCESS_SHARED_REG 0x40
  88. #define RH_RF95_MODE 0x07
  89. #define RH_RF95_MODE_SLEEP 0x00
  90. #define RH_RF95_MODE_STDBY 0x01
  91. #define RH_RF95_MODE_FSTX 0x02
  92. #define RH_RF95_MODE_TX 0x03
  93. #define RH_RF95_MODE_FSRX 0x04
  94. #define RH_RF95_MODE_RXCONTINUOUS 0x05
  95. #define RH_RF95_MODE_RXSINGLE 0x06
  96. #define RH_RF95_MODE_CAD 0x07
  97. // RH_RF95_REG_09_PA_CONFIG 0x09
  98. #define RH_RF95_PA_SELECT 0x80
  99. #define RH_RF95_MAX_POWER 0x70
  100. #define RH_RF95_OUTPUT_POWER 0x0f
  101. // RH_RF95_REG_0A_PA_RAMP 0x0a
  102. #define RH_RF95_LOW_PN_TX_PLL_OFF 0x10
  103. #define RH_RF95_PA_RAMP 0x0f
  104. #define RH_RF95_PA_RAMP_3_4MS 0x00
  105. #define RH_RF95_PA_RAMP_2MS 0x01
  106. #define RH_RF95_PA_RAMP_1MS 0x02
  107. #define RH_RF95_PA_RAMP_500US 0x03
  108. #define RH_RF95_PA_RAMP_250US 0x0
  109. #define RH_RF95_PA_RAMP_125US 0x05
  110. #define RH_RF95_PA_RAMP_100US 0x06
  111. #define RH_RF95_PA_RAMP_62US 0x07
  112. #define RH_RF95_PA_RAMP_50US 0x08
  113. #define RH_RF95_PA_RAMP_40US 0x09
  114. #define RH_RF95_PA_RAMP_31US 0x0a
  115. #define RH_RF95_PA_RAMP_25US 0x0b
  116. #define RH_RF95_PA_RAMP_20US 0x0c
  117. #define RH_RF95_PA_RAMP_15US 0x0d
  118. #define RH_RF95_PA_RAMP_12US 0x0e
  119. #define RH_RF95_PA_RAMP_10US 0x0f
  120. // RH_RF95_REG_0B_OCP 0x0b
  121. #define RH_RF95_OCP_ON 0x20
  122. #define RH_RF95_OCP_TRIM 0x1f
  123. // RH_RF95_REG_0C_LNA 0x0c
  124. #define RH_RF95_LNA_GAIN 0xe0
  125. #define RH_RF95_LNA_BOOST 0x03
  126. #define RH_RF95_LNA_BOOST_DEFAULT 0x00
  127. #define RH_RF95_LNA_BOOST_150PC 0x11
  128. // RH_RF95_REG_11_IRQ_FLAGS_MASK 0x11
  129. #define RH_RF95_RX_TIMEOUT_MASK 0x80
  130. #define RH_RF95_RX_DONE_MASK 0x40
  131. #define RH_RF95_PAYLOAD_CRC_ERROR_MASK 0x20
  132. #define RH_RF95_VALID_HEADER_MASK 0x10
  133. #define RH_RF95_TX_DONE_MASK 0x08
  134. #define RH_RF95_CAD_DONE_MASK 0x04
  135. #define RH_RF95_FHSS_CHANGE_CHANNEL_MASK 0x02
  136. #define RH_RF95_CAD_DETECTED_MASK 0x01
  137. // RH_RF95_REG_12_IRQ_FLAGS 0x12
  138. #define RH_RF95_RX_TIMEOUT 0x80
  139. #define RH_RF95_RX_DONE 0x40
  140. #define RH_RF95_PAYLOAD_CRC_ERROR 0x20
  141. #define RH_RF95_VALID_HEADER 0x10
  142. #define RH_RF95_TX_DONE 0x08
  143. #define RH_RF95_CAD_DONE 0x04
  144. #define RH_RF95_FHSS_CHANGE_CHANNEL 0x02
  145. #define RH_RF95_CAD_DETECTED 0x01
  146. // RH_RF95_REG_18_MODEM_STAT 0x18
  147. #define RH_RF95_RX_CODING_RATE 0xe0
  148. #define RH_RF95_MODEM_STATUS_CLEAR 0x10
  149. #define RH_RF95_MODEM_STATUS_HEADER_INFO_VALID 0x08
  150. #define RH_RF95_MODEM_STATUS_RX_ONGOING 0x04
  151. #define RH_RF95_MODEM_STATUS_SIGNAL_SYNCHRONIZED 0x02
  152. #define RH_RF95_MODEM_STATUS_SIGNAL_DETECTED 0x01
  153. // RH_RF95_REG_1C_HOP_CHANNEL 0x1c
  154. #define RH_RF95_PLL_TIMEOUT 0x80
  155. #define RH_RF95_RX_PAYLOAD_CRC_IS_ON 0x40
  156. #define RH_RF95_FHSS_PRESENT_CHANNEL 0x3f
  157. // RH_RF95_REG_1D_MODEM_CONFIG1 0x1d
  158. #define RH_RF95_BW 0xc0
  159. #define RH_RF95_BW_125KHZ 0x00
  160. #define RH_RF95_BW_250KHZ 0x40
  161. #define RH_RF95_BW_500KHZ 0x80
  162. #define RH_RF95_BW_RESERVED 0xc0
  163. #define RH_RF95_CODING_RATE 0x38
  164. #define RH_RF95_CODING_RATE_4_5 0x00
  165. #define RH_RF95_CODING_RATE_4_6 0x08
  166. #define RH_RF95_CODING_RATE_4_7 0x10
  167. #define RH_RF95_CODING_RATE_4_8 0x18
  168. #define RH_RF95_IMPLICIT_HEADER_MODE_ON 0x04
  169. #define RH_RF95_RX_PAYLOAD_CRC_ON 0x02
  170. #define RH_RF95_LOW_DATA_RATE_OPTIMIZE 0x01
  171. // RH_RF95_REG_1E_MODEM_CONFIG2 0x1e
  172. #define RH_RF95_SPREADING_FACTOR 0xf0
  173. #define RH_RF95_SPREADING_FACTOR_64CPS 0x60
  174. #define RH_RF95_SPREADING_FACTOR_128CPS 0x70
  175. #define RH_RF95_SPREADING_FACTOR_256CPS 0x80
  176. #define RH_RF95_SPREADING_FACTOR_512CPS 0x90
  177. #define RH_RF95_SPREADING_FACTOR_1024CPS 0xa0
  178. #define RH_RF95_SPREADING_FACTOR_2048CPS 0xb0
  179. #define RH_RF95_SPREADING_FACTOR_4096CPS 0xc0
  180. #define RH_RF95_TX_CONTINUOUS_MOE 0x08
  181. #define RH_RF95_AGC_AUTO_ON 0x04
  182. #define RH_RF95_SYM_TIMEOUT_MSB 0x03
  183. // RH_RF95_REG_4D_PA_DAC 0x4d
  184. #define RH_RF95_PA_DAC_DISABLE 0x04
  185. #define RH_RF95_PA_DAC_ENABLE 0x07
  186. /////////////////////////////////////////////////////////////////////
  187. /// \class RH_RF95 RH_RF95.h <RH_RF95.h>
  188. /// \brief Driver to send and receive unaddressed, unreliable datagrams via a LoRa
  189. /// capable radio transceiver.
  190. ///
  191. /// For Semtech SX1276/77/78/79 and HopeRF RF95/96/97/98 and other similar LoRa capable radios.
  192. /// Based on http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf
  193. /// and http://www.hoperf.cn/upload/rfchip/RF96_97_98.pdf
  194. /// and http://www.semtech.com/images/datasheet/LoraDesignGuide_STD.pdf
  195. /// and http://www.semtech.com/images/datasheet/sx1276.pdf
  196. /// and http://www.semtech.com/images/datasheet/sx1276_77_78_79.pdf
  197. /// FSK/GFSK/OOK modes are not (yet) supported.
  198. ///
  199. /// Works with
  200. /// - the excellent MiniWirelessLoRa from Anarduino http://www.anarduino.com/miniwireless
  201. /// - The excellent Modtronix inAir4 http://modtronix.com/inair4.html
  202. /// and inAir9 modules http://modtronix.com/inair9.html.
  203. /// - the excellent Rocket Scream Mini Ultra Pro with the RFM95W
  204. /// http://www.rocketscream.com/blog/product/mini-ultra-pro-with-radio/
  205. /// - Lora1276 module from NiceRF http://www.nicerf.com/product_view.aspx?id=99
  206. /// - Adafruit Feather M0 with RFM95
  207. ///
  208. /// \par Overview
  209. ///
  210. /// This class provides basic functions for sending and receiving unaddressed,
  211. /// unreliable datagrams of arbitrary length to 251 octets per packet.
  212. ///
  213. /// Manager classes may use this class to implement reliable, addressed datagrams and streams,
  214. /// mesh routers, repeaters, translators etc.
  215. ///
  216. /// Naturally, for any 2 radios to communicate that must be configured to use the same frequency and
  217. /// modulation scheme.
  218. ///
  219. /// This Driver provides an object-oriented interface for sending and receiving data messages with Hope-RF
  220. /// RFM95/96/97/98(W), Semtech SX1276/77/78/79 and compatible radio modules in LoRa mode.
  221. ///
  222. /// The Hope-RF (http://www.hoperf.com) RFM95/96/97/98(W) and Semtech SX1276/77/78/79 is a low-cost ISM transceiver
  223. /// chip. It supports FSK, GFSK, OOK over a wide range of frequencies and
  224. /// programmable data rates, and it also supports the proprietary LoRA (Long Range) mode, which
  225. /// is the only mode supported in this RadioHead driver.
  226. ///
  227. /// This Driver provides functions for sending and receiving messages of up
  228. /// to 251 octets on any frequency supported by the radio, in a range of
  229. /// predefined Bandwidths, Spreading Factors and Coding Rates. Frequency can be set with
  230. /// 61Hz precision to any frequency from 240.0MHz to 960.0MHz. Caution: most modules only support a more limited
  231. /// range of frequencies due to antenna tuning.
  232. ///
  233. /// Up to 2 modules can be connected to an Arduino (3 on a Mega),
  234. /// permitting the construction of translators and frequency changers, etc.
  235. ///
  236. /// Support for other features such as transmitter power control etc is
  237. /// also provided.
  238. ///
  239. /// Tested on MinWirelessLoRa with arduino-1.0.5
  240. /// on OpenSuSE 13.1.
  241. /// Also tested with Teensy3.1, Modtronix inAir4 and Arduino 1.6.5 on OpenSuSE 13.1
  242. ///
  243. /// \par Packet Format
  244. ///
  245. /// All messages sent and received by this RH_RF95 Driver conform to this packet format:
  246. ///
  247. /// - LoRa mode:
  248. /// - 8 symbol PREAMBLE
  249. /// - Explicit header with header CRC (handled internally by the radio)
  250. /// - 4 octets HEADER: (TO, FROM, ID, FLAGS)
  251. /// - 0 to 251 octets DATA
  252. /// - CRC (handled internally by the radio)
  253. ///
  254. /// \par Connecting RFM95/96/97/98 and Semtech SX1276/77/78/79 to Arduino
  255. ///
  256. /// We tested with Anarduino MiniWirelessLoRA, which is an Arduino Duemilanove compatible with a RFM96W
  257. /// module on-board. Therefore it needs no connections other than the USB
  258. /// programming connection and an antenna to make it work.
  259. ///
  260. /// If you have a bare RFM95/96/97/98 that you want to connect to an Arduino, you
  261. /// might use these connections (untested): CAUTION: you must use a 3.3V type
  262. /// Arduino, otherwise you will also need voltage level shifters between the
  263. /// Arduino and the RFM95. CAUTION, you must also ensure you connect an
  264. /// antenna.
  265. ///
  266. /// \code
  267. /// Arduino RFM95/96/97/98
  268. /// GND----------GND (ground in)
  269. /// 3V3----------3.3V (3.3V in)
  270. /// interrupt 0 pin D2-----------DIO0 (interrupt request out)
  271. /// SS pin D10----------NSS (CS chip select in)
  272. /// SCK pin D13----------SCK (SPI clock in)
  273. /// MOSI pin D11----------MOSI (SPI Data in)
  274. /// MISO pin D12----------MISO (SPI Data out)
  275. /// \endcode
  276. /// With these connections, you can then use the default constructor RH_RF95().
  277. /// You can override the default settings for the SS pin and the interrupt in
  278. /// the RH_RF95 constructor if you wish to connect the slave select SS to other
  279. /// than the normal one for your Arduino (D10 for Diecimila, Uno etc and D53
  280. /// for Mega) or the interrupt request to other than pin D2 (Caution,
  281. /// different processors have different constraints as to the pins available
  282. /// for interrupts).
  283. ///
  284. /// You can connect a Modtronix inAir4 or inAir9 directly to a 3.3V part such as a Teensy 3.1 like
  285. /// this (tested).
  286. /// \code
  287. /// Teensy inAir4 inAir9
  288. /// GND----------GND (ground in)
  289. /// 3V3----------3.3V (3.3V in)
  290. /// interrupt 0 pin D2-----------D00 (interrupt request out)
  291. /// SS pin D10----------CS (CS chip select in)
  292. /// SCK pin D13----------CK (SPI clock in)
  293. /// MOSI pin D11----------SI (SPI Data in)
  294. /// MISO pin D12----------SO (SPI Data out)
  295. /// \endcode
  296. /// With these connections, you can then use the default constructor RH_RF95().
  297. /// you must also set the transmitter power with useRFO:
  298. /// driver.setTxPower(13, true);
  299. ///
  300. /// Note that if you are using Modtronix inAir4 or inAir9,or any other module which uses the
  301. /// transmitter RFO pins and not the PA_BOOST pins
  302. /// that you must configure the power transmitter power for -1 to 14 dBm and with useRFO true.
  303. /// Failure to do that will result in extremely low transmit powers.
  304. ///
  305. /// If you have an Arduino M0 Pro from arduino.org,
  306. /// you should note that you cannot use Pin 2 for the interrupt line
  307. /// (Pin 2 is for the NMI only). The same comments apply to Pin 4 on Arduino Zero from arduino.cc.
  308. /// Instead you can use any other pin (we use Pin 3) and initialise RH_RF69 like this:
  309. /// \code
  310. /// // Slave Select is pin 10, interrupt is Pin 3
  311. /// RH_RF95 driver(10, 3);
  312. /// \endcode
  313. ///
  314. /// If you have a Rocket Scream Mini Ultra Pro with the RFM95W:
  315. /// - Ensure you have Arduino SAMD board support 1.6.5 or later in Arduino IDE 1.6.8 or later.
  316. /// - The radio SS is hardwired to pin D5 and the DIO0 interrupt to pin D2,
  317. /// so you need to initialise the radio like this:
  318. /// \code
  319. /// RH_RF95 driver(5, 2);
  320. /// \endcode
  321. /// - The name of the serial port on that board is 'SerialUSB', not 'Serial', so this may be helpful at the top of our
  322. /// sample sketches:
  323. /// \code
  324. /// #define Serial SerialUSB
  325. /// \endcode
  326. /// - You also need this in setup before radio initialisation
  327. /// \code
  328. /// // Ensure serial flash is not interfering with radio communication on SPI bus
  329. /// pinMode(4, OUTPUT);
  330. /// digitalWrite(4, HIGH);
  331. /// \endcode
  332. /// - and if you have a 915MHz part, you need this after driver/manager intitalisation:
  333. /// \code
  334. /// rf95.setFrequency(915.0);
  335. /// \endcode
  336. /// which adds up to modifying sample sketches something like:
  337. /// \code
  338. /// #include <SPI.h>
  339. /// #include <RH_RF95.h>
  340. /// RH_RF95 rf95(5, 2); // Rocket Scream Mini Ultra Pro with the RFM95W
  341. /// #define Serial SerialUSB
  342. ///
  343. /// void setup()
  344. /// {
  345. /// // Ensure serial flash is not interfering with radio communication on SPI bus
  346. /// pinMode(4, OUTPUT);
  347. /// digitalWrite(4, HIGH);
  348. ///
  349. /// Serial.begin(9600);
  350. /// while (!Serial) ; // Wait for serial port to be available
  351. /// if (!rf95.init())
  352. /// Serial.println("init failed");
  353. /// rf95.setFrequency(915.0);
  354. /// }
  355. /// ...
  356. /// \endcode
  357. ///
  358. /// For Adafruit Feather M0 with RFM95, construct the driver like this:
  359. /// \code
  360. /// RH_RF95 rf95(8, 3);
  361. /// \endcode
  362. ///
  363. /// It is possible to have 2 or more radios connected to one Arduino, provided
  364. /// each radio has its own SS and interrupt line (SCK, SDI and SDO are common
  365. /// to all radios)
  366. ///
  367. /// Caution: on some Arduinos such as the Mega 2560, if you set the slave
  368. /// select pin to be other than the usual SS pin (D53 on Mega 2560), you may
  369. /// need to set the usual SS pin to be an output to force the Arduino into SPI
  370. /// master mode.
  371. ///
  372. /// Caution: Power supply requirements of the RFM module may be relevant in some circumstances:
  373. /// RFM95/96/97/98 modules are capable of pulling 120mA+ at full power, where Arduino's 3.3V line can
  374. /// give 50mA. You may need to make provision for alternate power supply for
  375. /// the RFM module, especially if you wish to use full transmit power, and/or you have
  376. /// other shields demanding power. Inadequate power for the RFM is likely to cause symptoms such as:
  377. /// - reset's/bootups terminate with "init failed" messages
  378. /// - random termination of communication after 5-30 packets sent/received
  379. /// - "fake ok" state, where initialization passes fluently, but communication doesn't happen
  380. /// - shields hang Arduino boards, especially during the flashing
  381. ///
  382. /// \par Interrupts
  383. ///
  384. /// The RH_RF95 driver uses interrupts to react to events in the RFM module,
  385. /// such as the reception of a new packet, or the completion of transmission
  386. /// of a packet. The RH_RF95 driver interrupt service routine reads status from
  387. /// and writes data to the the RFM module via the SPI interface. It is very
  388. /// important therefore, that if you are using the RH_RF95 driver with another
  389. /// SPI based deviced, that you disable interrupts while you transfer data to
  390. /// and from that other device. Use cli() to disable interrupts and sei() to
  391. /// reenable them.
  392. ///
  393. /// \par Memory
  394. ///
  395. /// The RH_RF95 driver requires non-trivial amounts of memory. The sample
  396. /// programs all compile to about 8kbytes each, which will fit in the
  397. /// flash proram memory of most Arduinos. However, the RAM requirements are
  398. /// more critical. Therefore, you should be vary sparing with RAM use in
  399. /// programs that use the RH_RF95 driver.
  400. ///
  401. /// It is often hard to accurately identify when you are hitting RAM limits on Arduino.
  402. /// The symptoms can include:
  403. /// - Mysterious crashes and restarts
  404. /// - Changes in behaviour when seemingly unrelated changes are made (such as adding print() statements)
  405. /// - Hanging
  406. /// - Output from Serial.print() not appearing
  407. ///
  408. /// \par Range
  409. ///
  410. /// We have made some simple range tests under the following conditions:
  411. /// - rf95_client base station connected to a VHF discone antenna at 8m height above ground
  412. /// - rf95_server mobile connected to 17.3cm 1/4 wavelength antenna at 1m height, no ground plane.
  413. /// - Both configured for 13dBm, 434MHz, Bw = 125 kHz, Cr = 4/8, Sf = 4096chips/symbol, CRC on. Slow+long range
  414. /// - Minimum reported RSSI seen for successful comms was about -91
  415. /// - Range over flat ground through heavy trees and vegetation approx 2km.
  416. /// - At 20dBm (100mW) otherwise identical conditions approx 3km.
  417. /// - At 20dBm, along salt water flat sandy beach, 3.2km.
  418. ///
  419. /// It should be noted that at this data rate, a 12 octet message takes 2 seconds to transmit.
  420. ///
  421. /// At 20dBm (100mW) with Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on.
  422. /// (Default medium range) in the conditions described above.
  423. /// - Range over flat ground through heavy trees and vegetation approx 2km.
  424. ///
  425. /// \par Transmitter Power
  426. ///
  427. /// You can control the transmitter power on the RF transceiver
  428. /// with the RH_RF95::setTxPower() function. The argument can be any of
  429. /// +5 to +23 (for modules that use PA_BOOST)
  430. /// -1 to +14 (for modules that use RFO transmitter pin)
  431. /// The default is 13. Eg:
  432. /// \code
  433. /// driver.setTxPower(10); // use PA_BOOST transmitter pin
  434. /// driver.setTxPower(10, true); // use PA_RFO pin transmitter pin
  435. /// \endcode
  436. ///
  437. /// We have made some actual power measurements against
  438. /// programmed power for Anarduino MiniWirelessLoRa (which has RFM96W-433Mhz installed)
  439. /// - MiniWirelessLoRa RFM96W-433Mhz, USB power
  440. /// - 30cm RG316 soldered direct to RFM96W module ANT and GND
  441. /// - SMA connector
  442. /// - 12db attenuator
  443. /// - SMA connector
  444. /// - MiniKits AD8307 HF/VHF Power Head (calibrated against Rohde&Schwartz 806.2020 test set)
  445. /// - Tektronix TDS220 scope to measure the Vout from power head
  446. /// \code
  447. /// Program power Measured Power
  448. /// dBm dBm
  449. /// 5 5
  450. /// 7 7
  451. /// 9 8
  452. /// 11 11
  453. /// 13 13
  454. /// 15 15
  455. /// 17 16
  456. /// 19 18
  457. /// 20 20
  458. /// 21 21
  459. /// 22 22
  460. /// 23 23
  461. /// \endcode
  462. ///
  463. /// We have also measured the actual power output from a Modtronix inAir4 http://modtronix.com/inair4.html
  464. /// connected to a Teensy 3.1:
  465. /// Teensy 3.1 this is a 3.3V part, connected directly to:
  466. /// Modtronix inAir4 with SMA antenna connector, connected as above:
  467. /// 10cm SMA-SMA cable
  468. /// - MiniKits AD8307 HF/VHF Power Head (calibrated against Rohde&Schwartz 806.2020 test set)
  469. /// - Tektronix TDS220 scope to measure the Vout from power head
  470. /// \code
  471. /// Program power Measured Power
  472. /// dBm dBm
  473. /// -1 0
  474. /// 1 2
  475. /// 3 4
  476. /// 5 7
  477. /// 7 10
  478. /// 9 13
  479. /// 11 14.2
  480. /// 13 15
  481. /// 14 16
  482. /// \endcode
  483. /// (Caution: we dont claim laboratory accuracy for these power measurements)
  484. /// You would not expect to get anywhere near these powers to air with a simple 1/4 wavelength wire antenna.
  485. class RH_RF95 : public RHSPIDriver
  486. {
  487. public:
  488. /// \brief Defines register values for a set of modem configuration registers
  489. ///
  490. /// Defines register values for a set of modem configuration registers
  491. /// that can be passed to setModemRegisters() if none of the choices in
  492. /// ModemConfigChoice suit your need setModemRegisters() writes the
  493. /// register values from this structure to the appropriate registers
  494. /// to set the desired spreading factor, coding rate and bandwidth
  495. typedef struct
  496. {
  497. uint8_t reg_1d; ///< Value for register RH_RF95_REG_1D_MODEM_CONFIG1
  498. uint8_t reg_1e; ///< Value for register RH_RF95_REG_1E_MODEM_CONFIG2
  499. uint8_t reg_26; ///< Value for register RH_RF95_REG_26_MODEM_CONFIG3
  500. } ModemConfig;
  501. /// Choices for setModemConfig() for a selected subset of common
  502. /// data rates. If you need another configuration,
  503. /// determine the necessary settings and call setModemRegisters() with your
  504. /// desired settings. It might be helpful to use the LoRa calculator mentioned in
  505. /// http://www.semtech.com/images/datasheet/LoraDesignGuide_STD.pdf
  506. /// These are indexes into MODEM_CONFIG_TABLE. We strongly recommend you use these symbolic
  507. /// definitions and not their integer equivalents: its possible that new values will be
  508. /// introduced in later versions (though we will try to avoid it).
  509. /// Caution: if you are using slow packet rates and long packets with RHReliableDatagram or subclasses
  510. /// you may need to change the RHReliableDatagram timeout for reliable operations.
  511. typedef enum
  512. {
  513. Bw125Cr45Sf128 = 0, ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium range
  514. Bw500Cr45Sf128, ///< Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short range
  515. Bw31_25Cr48Sf512, ///< Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long range
  516. Bw125Cr48Sf4096, ///< Bw = 125 kHz, Cr = 4/8, Sf = 4096chips/symbol, CRC on. Slow+long range
  517. } ModemConfigChoice;
  518. /// Constructor. You can have multiple instances, but each instance must have its own
  519. /// interrupt and slave select pin. After constructing, you must call init() to initialise the interface
  520. /// and the radio module. A maximum of 3 instances can co-exist on one processor, provided there are sufficient
  521. /// distinct interrupt lines, one for each instance.
  522. /// \param[in] slaveSelectPin the Arduino pin number of the output to use to select the RH_RF22 before
  523. /// accessing it. Defaults to the normal SS pin for your Arduino (D10 for Diecimila, Uno etc, D53 for Mega, D10 for Maple)
  524. /// \param[in] interruptPin The interrupt Pin number that is connected to the RFM DIO0 interrupt line.
  525. /// Defaults to pin 2, as required by Anarduino MinWirelessLoRa module.
  526. /// Caution: You must specify an interrupt capable pin.
  527. /// On many Arduino boards, there are limitations as to which pins may be used as interrupts.
  528. /// On Leonardo pins 0, 1, 2 or 3. On Mega2560 pins 2, 3, 18, 19, 20, 21. On Due and Teensy, any digital pin.
  529. /// On Arduino Zero from arduino.cc, any digital pin other than 4.
  530. /// On Arduino M0 Pro from arduino.org, any digital pin other than 2.
  531. /// On other Arduinos pins 2 or 3.
  532. /// See http://arduino.cc/en/Reference/attachInterrupt for more details.
  533. /// On Chipkit Uno32, pins 38, 2, 7, 8, 35.
  534. /// On other boards, any digital pin may be used.
  535. /// \param[in] spi Pointer to the SPI interface object to use.
  536. /// Defaults to the standard Arduino hardware SPI interface
  537. RH_RF95(uint8_t slaveSelectPin = SS, uint8_t interruptPin = 2, RHGenericSPI& spi = hardware_spi);
  538. /// Initialise the Driver transport hardware and software.
  539. /// Make sure the Driver is properly configured before calling init().
  540. /// \return true if initialisation succeeded.
  541. virtual bool init();
  542. /// Prints the value of all chip registers
  543. /// to the Serial device if RH_HAVE_SERIAL is defined for the current platform
  544. /// For debugging purposes only.
  545. /// \return true on success
  546. bool printRegisters();
  547. /// Sets all the registered required to configure the data modem in the RF95/96/97/98, including the bandwidth,
  548. /// spreading factor etc. You can use this to configure the modem with custom configurations if none of the
  549. /// canned configurations in ModemConfigChoice suit you.
  550. /// \param[in] config A ModemConfig structure containing values for the modem configuration registers.
  551. void setModemRegisters(const ModemConfig* config);
  552. /// Select one of the predefined modem configurations. If you need a modem configuration not provided
  553. /// here, use setModemRegisters() with your own ModemConfig.
  554. /// \param[in] index The configuration choice.
  555. /// \return true if index is a valid choice.
  556. bool setModemConfig(ModemConfigChoice index);
  557. /// Tests whether a new message is available
  558. /// from the Driver.
  559. /// On most drivers, this will also put the Driver into RHModeRx mode until
  560. /// a message is actually received by the transport, when it wil be returned to RHModeIdle.
  561. /// This can be called multiple times in a timeout loop
  562. /// \return true if a new, complete, error-free uncollected message is available to be retreived by recv()
  563. virtual bool available();
  564. /// Turns the receiver on if it not already on.
  565. /// If there is a valid message available, copy it to buf and return true
  566. /// else return false.
  567. /// If a message is copied, *len is set to the length (Caution, 0 length messages are permitted).
  568. /// You should be sure to call this function frequently enough to not miss any messages
  569. /// It is recommended that you call it in your main loop.
  570. /// \param[in] buf Location to copy the received message
  571. /// \param[in,out] len Pointer to available space in buf. Set to the actual number of octets copied.
  572. /// \return true if a valid message was copied to buf
  573. virtual bool recv(uint8_t* buf, uint8_t* len);
  574. /// Waits until any previous transmit packet is finished being transmitted with waitPacketSent().
  575. /// Then loads a message into the transmitter and starts the transmitter. Note that a message length
  576. /// of 0 is permitted.
  577. /// \param[in] data Array of data to be sent
  578. /// \param[in] len Number of bytes of data to send
  579. /// \return true if the message length was valid and it was correctly queued for transmit
  580. virtual bool send(const uint8_t* data, uint8_t len);
  581. /// Sets the length of the preamble
  582. /// in bytes.
  583. /// Caution: this should be set to the same
  584. /// value on all nodes in your network. Default is 8.
  585. /// Sets the message preamble length in RH_RF95_REG_??_PREAMBLE_?SB
  586. /// \param[in] bytes Preamble length in bytes.
  587. void setPreambleLength(uint16_t bytes);
  588. /// Returns the maximum message length
  589. /// available in this Driver.
  590. /// \return The maximum legal message length
  591. virtual uint8_t maxMessageLength();
  592. /// Sets the transmitter and receiver
  593. /// centre frequency.
  594. /// \param[in] centre Frequency in MHz. 137.0 to 1020.0. Caution: RFM95/96/97/98 comes in several
  595. /// different frequency ranges, and setting a frequency outside that range of your radio will probably not work
  596. /// \return true if the selected frquency centre is within range
  597. bool setFrequency(float centre);
  598. /// If current mode is Rx or Tx changes it to Idle. If the transmitter or receiver is running,
  599. /// disables them.
  600. void setModeIdle();
  601. /// If current mode is Tx or Idle, changes it to Rx.
  602. /// Starts the receiver in the RF95/96/97/98.
  603. void setModeRx();
  604. /// If current mode is Rx or Idle, changes it to Rx. F
  605. /// Starts the transmitter in the RF95/96/97/98.
  606. void setModeTx();
  607. /// Sets the transmitter power output level, and configures the transmitter pin.
  608. /// Be a good neighbour and set the lowest power level you need.
  609. /// Some SX1276/77/78/79 and compatible modules (such as RFM95/96/97/98)
  610. /// use the PA_BOOST transmitter pin for high power output (and optionally the PA_DAC)
  611. /// while some (such as the Modtronix inAir4 and inAir9)
  612. /// use the RFO transmitter pin for lower power but higher efficiency.
  613. /// You must set the appropriate power level and useRFO argument for your module.
  614. /// Check with your module manufacturer which transmtter pin is used on your module
  615. /// to ensure you are setting useRFO correctly.
  616. /// Failure to do so will result in very low
  617. /// transmitter power output.
  618. /// Caution: legal power limits may apply in certain countries.
  619. /// After init(), the power will be set to 13dBm, with useRFO false (ie PA_BOOST enabled).
  620. /// \param[in] power Transmitter power level in dBm. For RFM95/96/97/98 LORA with useRFO false,
  621. /// valid values are from +5 to +23.
  622. /// For Modtronix inAir4 and inAir9 with useRFO true (ie RFO pins in use),
  623. /// valid values are from -1 to 14.
  624. /// \param[in] useRFO If true, enables the use of the RFO transmitter pins instead of
  625. /// the PA_BOOST pin (false). Choose the correct setting for your module.
  626. void setTxPower(int8_t power, bool useRFO = false);
  627. /// Sets the radio into low-power sleep mode.
  628. /// If successful, the transport will stay in sleep mode until woken by
  629. /// changing mode it idle, transmit or receive (eg by calling send(), recv(), available() etc)
  630. /// Caution: there is a time penalty as the radio takes a finite time to wake from sleep mode.
  631. /// \return true if sleep mode was successfully entered.
  632. virtual bool sleep();
  633. protected:
  634. /// This is a low level function to handle the interrupts for one instance of RH_RF95.
  635. /// Called automatically by isr*()
  636. /// Should not need to be called by user code.
  637. void handleInterrupt();
  638. /// Examine the revceive buffer to determine whether the message is for this node
  639. void validateRxBuf();
  640. /// Clear our local receive buffer
  641. void clearRxBuf();
  642. private:
  643. /// Low level interrupt service routine for device connected to interrupt 0
  644. static void isr0();
  645. /// Low level interrupt service routine for device connected to interrupt 1
  646. static void isr1();
  647. /// Low level interrupt service routine for device connected to interrupt 1
  648. static void isr2();
  649. /// Array of instances connected to interrupts 0 and 1
  650. static RH_RF95* _deviceForInterrupt[];
  651. /// Index of next interrupt number to use in _deviceForInterrupt
  652. static uint8_t _interruptCount;
  653. /// The configured interrupt pin connected to this instance
  654. uint8_t _interruptPin;
  655. /// The index into _deviceForInterrupt[] for this device (if an interrupt is already allocated)
  656. /// else 0xff
  657. uint8_t _myInterruptIndex;
  658. /// Number of octets in the buffer
  659. volatile uint8_t _bufLen;
  660. /// The receiver/transmitter buffer
  661. uint8_t _buf[RH_RF95_MAX_PAYLOAD_LEN];
  662. /// True when there is a valid message in the buffer
  663. volatile bool _rxBufValid;
  664. };
  665. /// @example rf95_client.pde
  666. /// @example rf95_server.pde
  667. /// @example rf95_reliable_datagram_client.pde
  668. /// @example rf95_reliable_datagram_server.pde
  669. #endif