PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

259 lines
11KB

  1. // RH_Serial.h
  2. //
  3. // Copyright (C) 2014 Mike McCauley
  4. // $Id: RH_Serial.h,v 1.11 2016/04/04 01:40:12 mikem Exp $
  5. // Works with any serial port. Tested with Arduino Mega connected to Serial1
  6. // Also works with 3DR Radio V1.3 Telemetry kit (serial at 57600baud)
  7. #ifndef RH_Serial_h
  8. #define RH_Serial_h
  9. #include <RHGenericDriver.h>
  10. // Special characters
  11. #define STX 0x02
  12. #define ETX 0x03
  13. #define DLE 0x10
  14. #define SYN 0x16
  15. // Maximum message length (including the headers) we are willing to support
  16. #define RH_SERIAL_MAX_PAYLOAD_LEN 64
  17. // The length of the headers we add.
  18. // The headers are inside the payload and are therefore protected by the FCS
  19. #define RH_SERIAL_HEADER_LEN 4
  20. // This is the maximum message length that can be supported by this library.
  21. // It is an arbitrary limit.
  22. // Can be pre-defined to a smaller size (to save SRAM) prior to including this header
  23. // Here we allow for 4 bytes of address and header and payload to be included in the 64 byte encryption limit.
  24. // the one byte payload length is not encrpyted
  25. #ifndef RH_SERIAL_MAX_MESSAGE_LEN
  26. #define RH_SERIAL_MAX_MESSAGE_LEN (RH_SERIAL_MAX_PAYLOAD_LEN - RH_SERIAL_HEADER_LEN)
  27. #endif
  28. #if (RH_PLATFORM == RH_PLATFORM_STM32F2)
  29. #define HardwareSerial USARTSerial
  30. #endif
  31. class HardwareSerial;
  32. /////////////////////////////////////////////////////////////////////
  33. /// \class RH_Serial RH_Serial.h <RH_Serial.h>
  34. /// \brief Driver to send and receive unaddressed, unreliable datagrams via a serial connection
  35. ///
  36. /// This class sends and received packetized messages over a serial connection.
  37. /// It can be used for point-to-point or multidrop, RS232, RS488 or other serial connections as
  38. /// supported by your controller hardware.
  39. /// It can also be used to communicate via radios with serial interfaces such as:
  40. /// - APC220 Radio Data Module http://www.dfrobot.com/image/data/TEL0005/APC220_Datasheet.pdf
  41. /// http://www.dfrobot.com/image/data/TEL0005/APC220_Datasheet.pdf
  42. /// - 3DR Telemetry Radio https://store.3drobotics.com/products/3dr-radio
  43. /// - HopeRF HM-TR module http://www.hoperf.com/upload/rf_app/HM-TRS.pdf
  44. /// - Others
  45. ///
  46. /// Compiles and runs on Linux, OSX and all the microprocessers and MCUs suported by
  47. /// radiohead. On Linux and OSX, a RadioHead specific version of HardwareSerial (in RHutil/HardwareSerial.*)
  48. /// encapsulates access to any serial port (or suported USB-serial converter)
  49. ///
  50. /// The packetised messages include message encapsulation, headers, a message payload and a checksum.
  51. /// It therefore can support robust binary message passing with error-detection and retransmission
  52. /// when used with the appropriate manager. This allows reliable serial communicaitons even over very long
  53. /// lines where noise might otherwise affect reliablity of the communications.
  54. ///
  55. /// \par Packet Format
  56. ///
  57. /// All messages sent and received by this RH_Serial Driver conform to this packet format:
  58. /// \code
  59. /// DLE
  60. /// STX
  61. /// TO Header (1 octet)
  62. /// FROM Header (1 octet)
  63. /// ID Header (1 octet)
  64. /// FLAGS Header (1 octet)
  65. /// Message payload (0 to 60 octets)
  66. /// DLE
  67. /// ETX
  68. /// Frame Check Sequence FCS CCITT CRC-16 (2 octets)
  69. /// \endcode
  70. ///
  71. /// If any of octets from TO header through to the end of the payload are a DLE,
  72. /// then they are preceded by a DLE (ie DLE stuffing).
  73. /// The FCS covers everything from the TO header to the ETX inclusive, but not any stuffed DLEs
  74. ///
  75. /// \par Physical connection
  76. ///
  77. /// The physical connection to your serial port will depend on the type of platform you are on.
  78. ///
  79. /// For example, many arduinos only support a single Serial port on pins 0 and 1,
  80. /// which is shared with the USB host connections. On such Arduinos, it is not possible to use both
  81. /// RH_Serial on the Serial port as well as using the Serial port for debugand other printing or communications.
  82. ///
  83. /// On Arduino Mega and Due, there are 4 serial ports:
  84. /// - Serial: this is the serial port connected to the USB interface and the programming host.
  85. /// - Serial1: on pins 18 (Tx) and 19 (Rx)
  86. /// - Serial2: on pins 16 (Tx) and 17 (Rx)
  87. /// - Serial3: on pins 14 (Tx) and 15 (Rx)
  88. ///
  89. /// On Uno32, there are 2 serial ports:
  90. /// - SerialUSB: this is the port for the USB host connection.
  91. /// - Serial1: on pins 39 (Rx) and 40 (Tx)
  92. ///
  93. /// On Maple and Flymaple, there are 4 serial ports:
  94. /// - SerialUSB: this is the port for the USB host connection.
  95. /// - Serial1: on pins 7 (Tx) and 8 (Rx)
  96. /// - Serial2: on pins 0 (Rx) and 1 (Tx)
  97. /// - Serial3: on pins 29 (Tx) and 30 (Rx)
  98. ///
  99. /// On Linux and OSX there can be any number of serial ports.
  100. /// - On Linux, names like /dev/ttyUSB0 (for a FTDO USB-serial converter)
  101. /// - On OSX, names like /dev/tty.usbserial-A501YSWL (for a FTDO USB-serial converter)
  102. ///
  103. /// Note that it is necessary for you to select which Serial port your RF_Serial will use and pass it to the
  104. /// contructor. On Linux you must pass an instance of HardwareSerial.
  105. ///
  106. /// \par Testing
  107. ///
  108. /// You can test this class and the RHReliableDatagram manager
  109. /// on Unix and OSX with back-to-back connected FTDI USB-serial adapters.
  110. /// Back-to-back means the TX of one is connected to the RX of the other and vice-versa.
  111. /// You should also join the ground pins.
  112. ///
  113. /// Assume the 2 USB-serial adapters are connected by USB
  114. /// and have been assigned device names:
  115. /// /dev/ttyUSB0 and /dev/ttyUSB1.
  116. /// Build the example RHReliableDatagram client and server programs:
  117. /// \code
  118. /// tools/simBuild examples/serial/serial_reliable_datagram_server/serial_reliable_datagram_server.pde
  119. /// tools/simBuild examples/serial/serial_reliable_datagram_client/serial_reliable_datagram_client.pde
  120. /// \endcode
  121. /// In one window run the server, specifying the device to use as an environment variable:
  122. /// \code
  123. /// RH_HARDWARESERIAL_DEVICE_NAME=/dev/ttyUSB1 ./serial_reliable_datagram_server
  124. /// \endcode
  125. /// And in another window run the client, specifying the other device to use as an environment variable:
  126. /// \code
  127. /// RH_HARDWARESERIAL_DEVICE_NAME=/dev/ttyUSB0 ./serial_reliable_datagram_client
  128. /// \endcode
  129. /// You should see the 2 programs passing messages to each other.
  130. ///
  131. class RH_Serial : public RHGenericDriver
  132. {
  133. public:
  134. /// Constructor
  135. /// \param[in] serial Reference to the HardwareSerial port which will be used by this instance.
  136. /// On Unix and OSX, this is an instance of RHutil/HardwareSerial. On
  137. /// Arduino and other, it is an instance of the built in HardwareSerial class.
  138. RH_Serial(HardwareSerial& serial);
  139. /// Return the HardwareSerial port in use by this instance
  140. /// \return The current HardwareSerial as a reference
  141. HardwareSerial& serial();
  142. /// Initialise the Driver transport hardware and software.
  143. /// Make sure the Driver is properly configured before calling init().
  144. /// \return true if initialisation succeeded.
  145. virtual bool init();
  146. /// Tests whether a new message is available
  147. /// This can be called multiple times in a timeout loop.
  148. /// \return true if a new, complete, error-free uncollected message is available to be retreived by recv()
  149. virtual bool available();
  150. /// Wait until a new message is available from the driver.
  151. /// Blocks until a complete message is received as reported by available()
  152. virtual void waitAvailable();
  153. /// Wait until a new message is available from the driver or the timeout expires.
  154. /// Blocks until a complete message is received as reported by available() or the timeout expires.
  155. /// \param[in] timeout The maximum time to wait in milliseconds
  156. /// \return true if a message is available as reported by available(), false on timeout.
  157. virtual bool waitAvailableTimeout(uint16_t timeout);
  158. /// If there is a valid message available, copy it to buf and return true
  159. /// else return false.
  160. /// If a message is copied, *len is set to the length (Caution, 0 length messages are permitted).
  161. /// You should be sure to call this function frequently enough to not miss any messages
  162. /// It is recommended that you call it in your main loop.
  163. /// \param[in] buf Location to copy the received message
  164. /// \param[in,out] len Pointer to available space in buf. Set to the actual number of octets copied.
  165. /// \return true if a valid message was copied to buf
  166. virtual bool recv(uint8_t* buf, uint8_t* len);
  167. /// Waits until any previous transmit packet is finished being transmitted with waitPacketSent().
  168. /// Then loads a message into the transmitter and starts the transmitter. Note that a message length
  169. /// of 0 is NOT permitted.
  170. /// \param[in] data Array of data to be sent
  171. /// \param[in] len Number of bytes of data to send (> 0)
  172. /// \return true if the message length was valid and it was correctly queued for transmit
  173. virtual bool send(const uint8_t* data, uint8_t len);
  174. /// Returns the maximum message length
  175. /// available in this Driver.
  176. /// \return The maximum legal message length
  177. virtual uint8_t maxMessageLength();
  178. protected:
  179. /// \brief Defines different receiver states in teh receiver state machine
  180. typedef enum
  181. {
  182. RxStateInitialising = 0, ///< Before init() is called
  183. RxStateIdle, ///< Waiting for an STX
  184. RxStateDLE, ///< Waiting for the DLE after STX
  185. RxStateData, ///< Receiving data
  186. RxStateEscape, ///< Got a DLE while receiving data.
  187. RxStateWaitFCS1, ///< Got DLE ETX, waiting for first FCS octet
  188. RxStateWaitFCS2 ///< Waiting for second FCS octet
  189. } RxState;
  190. /// HAndle a character received from the serial port. IMplements
  191. /// the receiver state machine
  192. void handleRx(uint8_t ch);
  193. /// Empties the Rx buffer
  194. void clearRxBuf();
  195. /// Adds a charater to the Rx buffer
  196. void appendRxBuf(uint8_t ch);
  197. /// Checks whether the Rx buffer contains valid data that is complete and uncorrupted
  198. /// Check the FCS, the TO address, and extracts the headers
  199. void validateRxBuf();
  200. /// Sends a single data octet to the serial port.
  201. /// Implements DLE stuffing and keeps track of the senders FCS
  202. void txData(uint8_t ch);
  203. /// Reference to the HardwareSerial port we will use
  204. HardwareSerial& _serial;
  205. /// The current state of the Rx state machine
  206. RxState _rxState;
  207. /// Progressive FCS calc (CCITT CRC-16 covering all received data (but not stuffed DLEs), plus trailing DLE, ETX)
  208. uint16_t _rxFcs;
  209. /// The received FCS at the end of the current message
  210. uint16_t _rxRecdFcs;
  211. /// The Rx buffer
  212. uint8_t _rxBuf[RH_SERIAL_MAX_PAYLOAD_LEN];
  213. /// Current length of data in the Rx buffer
  214. uint8_t _rxBufLen;
  215. /// True if the data in the Rx buffer is value and uncorrupted and complete message is available for collection
  216. bool _rxBufValid;
  217. /// FCS for transmitted data
  218. uint16_t _txFcs;
  219. };
  220. /// @example serial_reliable_datagram_client.pde
  221. /// @example serial_reliable_datagram_server.pde
  222. /// @example serial_gateway.pde
  223. #endif