PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

423 líneas
19KB

  1. // RH_ASK.h
  2. //
  3. // Copyright (C) 2014 Mike McCauley
  4. // $Id: RH_ASK.h,v 1.16 2016/07/07 00:02:53 mikem Exp mikem $
  5. #ifndef RH_ASK_h
  6. #define RH_ASK_h
  7. #include <RHGenericDriver.h>
  8. // Maximum message length (including the headers, byte count and FCS) we are willing to support
  9. // This is pretty arbitrary
  10. #define RH_ASK_MAX_PAYLOAD_LEN 67
  11. // The length of the headers we add (To, From, Id, Flags)
  12. // The headers are inside the payload and are therefore protected by the FCS
  13. #define RH_ASK_HEADER_LEN 4
  14. // This is the maximum message length that can be supported by this library.
  15. // Can be pre-defined to a smaller size (to save SRAM) prior to including this header
  16. // Here we allow for 1 byte message length, 4 bytes headers, user data and 2 bytes of FCS
  17. #ifndef RH_ASK_MAX_MESSAGE_LEN
  18. #define RH_ASK_MAX_MESSAGE_LEN (RH_ASK_MAX_PAYLOAD_LEN - RH_ASK_HEADER_LEN - 3)
  19. #endif
  20. #if !defined(RH_ASK_RX_SAMPLES_PER_BIT)
  21. /// Number of samples per bit
  22. #define RH_ASK_RX_SAMPLES_PER_BIT 8
  23. #endif //RH_ASK_RX_SAMPLES_PER_BIT
  24. /// The size of the receiver ramp. Ramp wraps modulo this number
  25. #define RH_ASK_RX_RAMP_LEN 160
  26. // Ramp adjustment parameters
  27. // Standard is if a transition occurs before RH_ASK_RAMP_TRANSITION (80) in the ramp,
  28. // the ramp is retarded by adding RH_ASK_RAMP_INC_RETARD (11)
  29. // else by adding RH_ASK_RAMP_INC_ADVANCE (29)
  30. // If there is no transition it is adjusted by RH_ASK_RAMP_INC (20)
  31. /// Internal ramp adjustment parameter
  32. #define RH_ASK_RAMP_INC (RH_ASK_RX_RAMP_LEN/RH_ASK_RX_SAMPLES_PER_BIT)
  33. /// Internal ramp adjustment parameter
  34. #define RH_ASK_RAMP_TRANSITION RH_ASK_RX_RAMP_LEN/2
  35. /// Internal ramp adjustment parameter
  36. #define RH_ASK_RAMP_ADJUST 9
  37. /// Internal ramp adjustment parameter
  38. #define RH_ASK_RAMP_INC_RETARD (RH_ASK_RAMP_INC-RH_ASK_RAMP_ADJUST)
  39. /// Internal ramp adjustment parameter
  40. #define RH_ASK_RAMP_INC_ADVANCE (RH_ASK_RAMP_INC+RH_ASK_RAMP_ADJUST)
  41. /// Outgoing message bits grouped as 6-bit words
  42. /// 36 alternating 1/0 bits, followed by 12 bits of start symbol (together called the preamble)
  43. /// Followed immediately by the 4-6 bit encoded byte count,
  44. /// message buffer and 2 byte FCS
  45. /// Each byte from the byte count on is translated into 2x6-bit words
  46. /// Caution, each symbol is transmitted LSBit first,
  47. /// but each byte is transmitted high nybble first
  48. /// This is the number of 6 bit nibbles in the preamble
  49. #define RH_ASK_PREAMBLE_LEN 8
  50. /////////////////////////////////////////////////////////////////////
  51. /// \class RH_ASK RH_ASK.h <RH_ASK.h>
  52. /// \brief Driver to send and receive unaddressed, unreliable datagrams via inexpensive ASK (Amplitude Shift Keying) or
  53. /// OOK (On Off Keying) RF transceivers.
  54. ///
  55. /// The message format and software technology is based on our earlier VirtualWire library
  56. /// (http://www.airspayce.com/mikem/arduino/VirtualWire), with which it is compatible.
  57. /// See http://www.airspayce.com/mikem/arduino/VirtualWire.pdf for more details.
  58. /// VirtualWire is now obsolete and unsupported and is replaced by this library.
  59. ///
  60. /// RH_ASK is a Driver for Arduino, Maple and others that provides features to send short
  61. /// messages, without addressing, retransmit or acknowledgment, a bit like UDP
  62. /// over wireless, using ASK (amplitude shift keying). Supports a number of
  63. /// inexpensive radio transmitters and receivers. All that is required is
  64. /// transmit data, receive data and (for transmitters, optionally) a PTT
  65. /// transmitter enable. Can also be used over various analog connections (not just a data radio),
  66. /// such as the audio channel of an A/V sender, or long TTL lines.
  67. ///
  68. /// It is intended to be compatible with the RF Monolithics (www.rfm.com)
  69. /// Virtual Wire protocol, but this has not been tested.
  70. ///
  71. /// Does not use the Arduino UART. Messages are sent with a training preamble,
  72. /// message length and checksum. Messages are sent with 4-to-6 bit encoding
  73. /// for good DC balance, and a CRC checksum for message integrity.
  74. ///
  75. /// But why not just use a UART connected directly to the
  76. /// transmitter/receiver? As discussed in the RFM documentation, ASK receivers
  77. /// require a burst of training pulses to synchronize the transmitter and
  78. /// receiver, and also requires good balance between 0s and 1s in the message
  79. /// stream in order to maintain the DC balance of the message. UARTs do not
  80. /// provide these. They work a bit with ASK wireless, but not as well as this
  81. /// code.
  82. ///
  83. /// \par Theory of operation
  84. ///
  85. /// See ASH Transceiver Software Designer's Guide of 2002.08.07
  86. /// http://wireless.murata.com/media/products/apnotes/tr_swg05.pdf?ref=rfm.com
  87. ///
  88. /// http://web.engr.oregonstate.edu/~moon/research/files/cas2_mar_07_dpll.pdf while not directly relevant
  89. /// is also interesting.
  90. ///
  91. /// \par Implementation Details
  92. ///
  93. /// Messages of up to RH_ASK_MAX_PAYLOAD_LEN (67) bytes can be sent
  94. /// Each message is transmitted as:
  95. ///
  96. /// - 36 bit training preamble consisting of 0-1 bit pairs
  97. /// - 12 bit start symbol 0xb38
  98. /// - 1 byte of message length byte count (4 to 30), count includes byte count and FCS bytes
  99. /// - n message bytes (uincluding 4 bytes of header), maximum n is RH_ASK_MAX_MESSAGE_LEN + 4 (64)
  100. /// - 2 bytes FCS, sent low byte-hi byte
  101. ///
  102. /// Everything after the start symbol is encoded 4 to 6 bits, Therefore a byte in the message
  103. /// is encoded as 2x6 bit symbols, sent hi nybble, low nybble. Each symbol is sent LSBit
  104. /// first. The message may consist of any binary digits.
  105. ///
  106. /// The Arduino Diecimila clock rate is 16MHz => 62.5ns/cycle.
  107. /// For an RF bit rate of 2000 bps, need 500microsec bit period.
  108. /// The ramp requires 8 samples per bit period, so need 62.5microsec per sample => interrupt tick is 62.5microsec.
  109. ///
  110. /// The maximum packet length consists of
  111. /// (6 + 2 + RH_ASK_MAX_MESSAGE_LEN*2) * 6 = 768 bits = 0.384 secs (at 2000 bps).
  112. /// where RH_ASK_MAX_MESSAGE_LEN is RH_ASK_MAX_PAYLOAD_LEN - 7 (= 60).
  113. /// The code consists of an ISR interrupt handler. Most of the work is done in the interrupt
  114. /// handler for both transmit and receive, but some is done from the user level. Expensive
  115. /// functions like CRC computations are always done in the user level.
  116. ///
  117. /// \par Supported Hardware
  118. ///
  119. /// A range of communications
  120. /// hardware is supported. The ones listed below are available in common retail
  121. /// outlets in Australia and other countries for under $10 per unit. Many
  122. /// other modules may also work with this software.
  123. ///
  124. /// Runs on a wide range of Arduino processors using Arduino IDE 1.0 or later.
  125. /// Also runs on on Energia,
  126. /// with MSP430G2553 / G2452 and Arduino with ATMega328 (courtesy Yannick DEVOS - XV4Y),
  127. /// but untested by us. It also runs on Teensy 3.0 (courtesy of Paul
  128. /// Stoffregen), but untested by us. Also compiles and runs on ATtiny85 in
  129. /// Arduino environment, courtesy r4z0r7o3. Also compiles on maple-ide-v0.0.12,
  130. /// and runs on Maple, flymaple 1.1 etc. Runs on ATmega8/168 (Arduino Diecimila,
  131. /// Uno etc), ATmega328 and can run on almost any other AVR8 platform,
  132. /// without relying on the Arduino framework, by properly configuring the
  133. /// library editing the RH_ASK.h header file for describing the access
  134. /// to IO pins and for setting up the timer.
  135. /// Runs on ChipKIT Core supported processors such as Uno32 etc.
  136. ///
  137. /// - Receivers
  138. /// - RX-B1 (433.92MHz) (also known as ST-RX04-ASK)
  139. /// - RFM83C from HopeRF http://www.hoperfusa.com/details.jsp?pid=126
  140. /// - Transmitters:
  141. /// - TX-C1 (433.92MHz)
  142. /// - RFM85 from HopeRF http://www.hoperfusa.com/details.jsp?pid=127
  143. /// - Transceivers
  144. /// - DR3100 (433.92MHz)
  145. ///
  146. /// \par Connecting to Arduino
  147. ///
  148. /// Most transmitters can be connected to Arduino like this:
  149. /// \code
  150. /// Arduino Transmitter
  151. /// GND------------------------------GND
  152. /// D12------------------------------Data
  153. /// 5V-------------------------------VCC
  154. /// \endcode
  155. ///
  156. /// Most receivers can be connected to Arduino like this:
  157. /// \code
  158. /// Arduino Receiver
  159. /// GND------------------------------GND
  160. /// D11------------------------------Data
  161. /// 5V-------------------------------VCC
  162. /// SHUT (not connected)
  163. /// WAKEB (not connected)
  164. /// GND |
  165. /// ANT |- connect to your antenna syetem
  166. /// \endcode
  167. ///
  168. /// RH_ASK works with ATTiny85, using Arduino 1.0.5 and tinycore from
  169. /// https://code.google.com/p/arduino-tiny/downloads/detail?name=arduino-tiny-0100-0018.zip
  170. /// Tested with the examples ask_transmitter and ask_receiver on ATTiny85.
  171. /// Caution: The RAM memory requirements on an ATTiny85 are *very* tight. Even the bare bones
  172. /// ask_transmitter sketch barely fits in eh RAM available on the ATTiny85. Its unlikely to work on
  173. /// smaller ATTinys such as the ATTiny45 etc. If you have wierd behaviour, consider
  174. /// reducing the size of RH_ASK_MAX_PAYLOAD_LEN to the minimum you can work with.
  175. /// Caution: the default internal clock speed on an ATTiny85 is 1MHz. You MUST set the internal clock speed
  176. /// to 8MHz. You can do this with Arduino IDE, tineycore and ArduinoISP by setting the board type to "ATtiny85@8MHz',
  177. /// setting theProgrammer to 'Arduino as ISP' and selecting Tools->Burn Bootloader. This does not actually burn a
  178. /// bootloader into the tiny, it just changes the fuses so the chip runs at 8MHz.
  179. /// If you run the chip at 1MHz, you will get RK_ASK speeds 1/8th of the expected.
  180. ///
  181. /// Initialise RH_ASK for ATTiny85 like this:
  182. /// // #include <SPI.h> // comment this out, not needed
  183. /// RH_ASK driver(2000, 4, 3); // 200bps, TX on D3 (pin 2), RX on D4 (pin 3)
  184. /// then:
  185. /// Connect D3 (pin 2) as the output to the transmitter
  186. /// Connect D4 (pin 3) as the input from the receiver.
  187. ///
  188. ///
  189. /// For testing purposes you can connect 2 Arduino RH_ASK instances directly, by
  190. /// connecting pin 12 of one to 11 of the other and vice versa, like this for a duplex connection:
  191. ///
  192. /// \code
  193. /// Arduino 1 wires Arduino 1
  194. /// D11-----------------------------D12
  195. /// D12-----------------------------D11
  196. /// GND-----------------------------GND
  197. /// \endcode
  198. ///
  199. /// You can also connect 2 RH_ASK instances over a suitable analog
  200. /// transmitter/receiver, such as the audio channel of an A/V transmitter/receiver. You may need
  201. /// buffers at each end of the connection to convert the 0-5V digital output to a suitable analog voltage.
  202. ///
  203. /// Measured power output from RFM85 at 5V was 18dBm.
  204. ///
  205. /// \par ESP8266
  206. /// This module has been tested with the ESP8266 using an ESP-12 on a breakout board
  207. /// ESP-12E SMD Adaptor Board with Power Regulator from tronixlabs
  208. /// http://tronixlabs.com.au/wireless/esp8266/esp8266-esp-12e-smd-adaptor-board-with-power-regulator-australia/
  209. /// compiled on Arduino 1.6.5 and the ESP8266 support 2.0 installed with Board Manager.
  210. /// CAUTION: do not use pin 11 for IO with this chip: it will cause the sketch to hang. Instead
  211. /// use constructor arguments to configure different pins, eg:
  212. /// \code
  213. /// RH_ASK driver(2000, 2, 4, 5);
  214. /// \endcode
  215. /// Which will initialise the driver at 2000 bps, recieve on GPIO2, transmit on GPIO4, PTT on GPIO5.
  216. /// Caution: on the tronixlabs breakout board, pins 4 and 5 may be labelled vice-versa.
  217. ///
  218. /// \par Timers
  219. /// The RH_ASK driver uses a timer-driven interrupt to generate 8 interrupts per bit period. RH_ASK
  220. /// takes over a timer on Arduino-like platforms. By default it takes over Timer 1. You can force it
  221. /// to use Timer 2 instead by enabling the define RH_ASK_ARDUINO_USE_TIMER2 near the top of RH_ASK.cpp
  222. /// On Arduino Zero it takes over timer TC3. On Arduino Due it takes over timer
  223. /// TC0. On ESP8266, takes over timer0 (which conflicts with ServoTimer0).
  224. ///
  225. /// Caution: ATTiny85 has only 2 timers, one (timer 0) usually used for
  226. /// millis() and one (timer 1) for PWM analog outputs. The RH_ASK Driver
  227. /// library, when built for ATTiny85, takes over timer 0, which prevents use
  228. /// of millis() etc but does permit analog outputs. This will affect the accuracy of millis() and time
  229. /// measurement.
  230. class RH_ASK : public RHGenericDriver
  231. {
  232. public:
  233. /// Constructor.
  234. /// At present only one instance of RH_ASK per sketch is supported.
  235. /// \param[in] speed The desired bit rate in bits per second
  236. /// \param[in] rxPin The pin that is used to get data from the receiver
  237. /// \param[in] txPin The pin that is used to send data to the transmitter
  238. /// \param[in] pttPin The pin that is connected to the transmitter controller. It will be set HIGH to enable the transmitter (unless pttInverted is true).
  239. /// \param[in] pttInverted true if you desire the pttin to be inverted so that LOW wil enable the transmitter.
  240. RH_ASK(uint16_t speed = 2000, uint8_t rxPin = 11, uint8_t txPin = 12, uint8_t pttPin = 10, bool pttInverted = false);
  241. /// Initialise the Driver transport hardware and software.
  242. /// Make sure the Driver is properly configured before calling init().
  243. /// \return true if initialisation succeeded.
  244. virtual bool init();
  245. /// Tests whether a new message is available
  246. /// from the Driver.
  247. /// On most drivers, this will also put the Driver into RHModeRx mode until
  248. /// a message is actually received bythe transport, when it wil be returned to RHModeIdle.
  249. /// This can be called multiple times in a timeout loop
  250. /// \return true if a new, complete, error-free uncollected message is available to be retreived by recv()
  251. virtual bool available();
  252. /// Turns the receiver on if it not already on.
  253. /// If there is a valid message available, copy it to buf and return true
  254. /// else return false.
  255. /// If a message is copied, *len is set to the length (Caution, 0 length messages are permitted).
  256. /// You should be sure to call this function frequently enough to not miss any messages
  257. /// It is recommended that you call it in your main loop.
  258. /// \param[in] buf Location to copy the received message
  259. /// \param[in,out] len Pointer to available space in buf. Set to the actual number of octets copied.
  260. /// \return true if a valid message was copied to buf
  261. virtual bool recv(uint8_t* buf, uint8_t* len);
  262. /// Waits until any previous transmit packet is finished being transmitted with waitPacketSent().
  263. /// Then loads a message into the transmitter and starts the transmitter. Note that a message length
  264. /// of 0 is NOT permitted.
  265. /// \param[in] data Array of data to be sent
  266. /// \param[in] len Number of bytes of data to send (> 0)
  267. /// \return true if the message length was valid and it was correctly queued for transmit
  268. virtual bool send(const uint8_t* data, uint8_t len);
  269. /// Returns the maximum message length
  270. /// available in this Driver.
  271. /// \return The maximum legal message length
  272. virtual uint8_t maxMessageLength();
  273. /// If current mode is Rx or Tx changes it to Idle. If the transmitter or receiver is running,
  274. /// disables them.
  275. void setModeIdle();
  276. /// If current mode is Tx or Idle, changes it to Rx.
  277. /// Starts the receiver in the RF69.
  278. void setModeRx();
  279. /// If current mode is Rx or Idle, changes it to Rx. F
  280. /// Starts the transmitter in the RF69.
  281. void setModeTx();
  282. /// dont call this it used by the interrupt handler
  283. void handleTimerInterrupt();
  284. /// Returns the current speed in bits per second
  285. /// \return The current speed in bits per second
  286. uint16_t speed() { return _speed;}
  287. #if (RH_PLATFORM == RH_PLATFORM_ESP8266)
  288. /// ESP8266 timer0 increment value
  289. uint32_t _timerIncrement;
  290. #endif
  291. protected:
  292. /// Helper function for calculating timer ticks
  293. uint8_t timerCalc(uint16_t speed, uint16_t max_ticks, uint16_t *nticks);
  294. /// Set up the timer and its interrutps so the interrupt handler is called at the right frequency
  295. void timerSetup();
  296. /// Read the rxPin in a platform dependent way, taking into account whether it is inverted or not
  297. bool readRx();
  298. /// Write the txPin in a platform dependent way
  299. void writeTx(bool value);
  300. /// Write the txPin in a platform dependent way, taking into account whether it is inverted or not
  301. void writePtt(bool value);
  302. /// Translates a 6 bit symbol to its 4 bit plaintext equivalent
  303. uint8_t symbol_6to4(uint8_t symbol);
  304. /// The receiver handler function, called a 8 times the bit rate
  305. void receiveTimer();
  306. /// The transmitter handler function, called a 8 times the bit rate
  307. void transmitTimer();
  308. /// Check whether the latest received message is complete and uncorrupted
  309. /// We should always check the FCS at user level, not interrupt level
  310. /// since it is slow
  311. void validateRxBuf();
  312. /// Configure bit rate in bits per second
  313. uint16_t _speed;
  314. /// The configure receiver pin
  315. uint8_t _rxPin;
  316. /// The configure transmitter pin
  317. uint8_t _txPin;
  318. /// The configured transmitter enable pin
  319. uint8_t _pttPin;
  320. /// True of the sense of the rxPin is to be inverted
  321. bool _rxInverted;
  322. /// True of the sense of the pttPin is to be inverted
  323. bool _pttInverted;
  324. // Used in the interrupt handlers
  325. /// Buf is filled but not validated
  326. volatile bool _rxBufFull;
  327. /// Buf is full and valid
  328. volatile bool _rxBufValid;
  329. /// Last digital input from the rx data pin
  330. volatile bool _rxLastSample;
  331. /// This is the integrate and dump integral. If there are <5 0 samples in the PLL cycle
  332. /// the bit is declared a 0, else a 1
  333. volatile uint8_t _rxIntegrator;
  334. /// PLL ramp, varies between 0 and RH_ASK_RX_RAMP_LEN-1 (159) over
  335. /// RH_ASK_RX_SAMPLES_PER_BIT (8) samples per nominal bit time.
  336. /// When the PLL is synchronised, bit transitions happen at about the
  337. /// 0 mark.
  338. volatile uint8_t _rxPllRamp;
  339. /// Flag indicates if we have seen the start symbol of a new message and are
  340. /// in the processes of reading and decoding it
  341. volatile uint8_t _rxActive;
  342. /// Last 12 bits received, so we can look for the start symbol
  343. volatile uint16_t _rxBits;
  344. /// How many bits of message we have received. Ranges from 0 to 12
  345. volatile uint8_t _rxBitCount;
  346. /// The incoming message buffer
  347. uint8_t _rxBuf[RH_ASK_MAX_PAYLOAD_LEN];
  348. /// The incoming message expected length
  349. volatile uint8_t _rxCount;
  350. /// The incoming message buffer length received so far
  351. volatile uint8_t _rxBufLen;
  352. /// Index of the next symbol to send. Ranges from 0 to vw_tx_len
  353. uint8_t _txIndex;
  354. /// Bit number of next bit to send
  355. uint8_t _txBit;
  356. /// Sample number for the transmitter. Runs 0 to 7 during one bit interval
  357. uint8_t _txSample;
  358. /// The transmitter buffer in _symbols_ not data octets
  359. uint8_t _txBuf[(RH_ASK_MAX_PAYLOAD_LEN * 2) + RH_ASK_PREAMBLE_LEN];
  360. /// Number of symbols in _txBuf to be sent;
  361. uint8_t _txBufLen;
  362. };
  363. /// @example ask_reliable_datagram_client.pde
  364. /// @example ask_reliable_datagram_server.pde
  365. /// @example ask_transmitter.pde
  366. /// @example ask_receiver.pde
  367. #endif