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