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