RadioHead
RHGenericDriver.h
1// RHGenericDriver.h
2// Author: Mike McCauley (mikem@airspayce.com)
3// Copyright (C) 2014 Mike McCauley
4// $Id: RHGenericDriver.h,v 1.24 2020/04/09 23:40:34 mikem Exp $
5
6#ifndef RHGenericDriver_h
7#define RHGenericDriver_h
8
9#include <RadioHead.h>
10
11// Defines bits of the FLAGS header reserved for use by the RadioHead library and
12// the flags available for use by applications
13#define RH_FLAGS_RESERVED 0xf0
14#define RH_FLAGS_APPLICATION_SPECIFIC 0x0f
15#define RH_FLAGS_NONE 0
16
17// Default timeout for waitCAD() in ms
18#define RH_CAD_DEFAULT_TIMEOUT 10000
19
20/////////////////////////////////////////////////////////////////////
21/// \class RHGenericDriver RHGenericDriver.h <RHGenericDriver.h>
22/// \brief Abstract base class for a RadioHead driver.
23///
24/// This class defines the functions that must be provided by any RadioHead driver.
25/// Different types of driver will implement all the abstract functions, and will perhaps override
26/// other functions in this subclass, or perhaps add new functions specifically required by that driver.
27/// Do not directly instantiate this class: it is only to be subclassed by driver classes.
28///
29/// Subclasses are expected to implement a half-duplex, unreliable, error checked, unaddressed packet transport.
30/// They are expected to carry a message payload with an appropriate maximum length for the transport hardware
31/// and to also carry unaltered 4 message headers: TO, FROM, ID, FLAGS
32///
33/// \par Headers
34///
35/// Each message sent and received by a RadioHead driver includes 4 headers:
36/// -TO The node address that the message is being sent to (broadcast RH_BROADCAST_ADDRESS (255) is permitted)
37/// -FROM The node address of the sending node
38/// -ID A message ID, distinct (over short time scales) for each message sent by a particilar node
39/// -FLAGS A bitmask of flags. The most significant 4 bits are reserved for use by RadioHead. The least
40/// significant 4 bits are reserved for applications.
42{
43public:
44 /// \brief Defines different operating modes for the transport hardware
45 ///
46 /// These are the different values that can be adopted by the _mode variable and
47 /// returned by the mode() member function,
48 typedef enum
49 {
50 RHModeInitialising = 0, ///< Transport is initialising. Initial default value until init() is called..
51 RHModeSleep, ///< Transport hardware is in low power sleep mode (if supported)
52 RHModeIdle, ///< Transport is idle.
53 RHModeTx, ///< Transport is in the process of transmitting a message.
54 RHModeRx, ///< Transport is in the process of receiving a message.
55 RHModeCad ///< Transport is in the process of detecting channel activity (if supported)
57
58 /// Constructor
60
61 /// Generic destructor to prevent warnings when objects are dynamically allocated
62 virtual ~RHGenericDriver() {};
63
64 /// Initialise the Driver transport hardware and software.
65 /// Make sure the Driver is properly configured before calling init().
66 /// \return true if initialisation succeeded.
67 virtual bool init();
68
69 /// Tests whether a new message is available
70 /// from the Driver.
71 /// On most drivers, if there is an uncollected received message, and there is no message
72 /// currently bing transmitted, this will also put the Driver into RHModeRx mode until
73 /// a message is actually received by the transport, when it will be returned to RHModeIdle.
74 /// This can be called multiple times in a timeout loop.
75 /// \return true if a new, complete, error-free uncollected message is available to be retreived by recv().
76 virtual bool available() = 0;
77
78 /// Turns the receiver on if it not already on.
79 /// If there is a valid message available, copy it to buf and return true
80 /// else return false.
81 /// If a message is copied, *len is set to the length (Caution, 0 length messages are permitted).
82 /// You should be sure to call this function frequently enough to not miss any messages
83 /// It is recommended that you call it in your main loop.
84 /// \param[in] buf Location to copy the received message
85 /// \param[in,out] len Pointer to available space in buf. Set to the actual number of octets copied.
86 /// \return true if a valid message was copied to buf
87 virtual bool recv(uint8_t* buf, uint8_t* len) = 0;
88
89 /// Waits until any previous transmit packet is finished being transmitted with waitPacketSent().
90 /// Then optionally waits for Channel Activity Detection (CAD)
91 /// to show the channnel is clear (if the radio supports CAD) by calling waitCAD().
92 /// Then loads a message into the transmitter and starts the transmitter. Note that a message length
93 /// of 0 is NOT permitted. If the message is too long for the underlying radio technology, send() will
94 /// return false and will not send the message.
95 /// \param[in] data Array of data to be sent
96 /// \param[in] len Number of bytes of data to send (> 0)
97 /// specify the maximum time in ms to wait. If 0 (the default) do not wait for CAD before transmitting.
98 /// \return true if the message length was valid and it was correctly queued for transmit. Return false
99 /// if CAD was requested and the CAD timeout timed out before clear channel was detected.
100 virtual bool send(const uint8_t* data, uint8_t len) = 0;
101
102 /// Returns the maximum message length
103 /// available in this Driver.
104 /// \return The maximum legal message length
105 virtual uint8_t maxMessageLength() = 0;
106
107 /// Starts the receiver and blocks until a valid received
108 /// message is available.
109 /// Default implementation calls available() repeatedly until it returns true;
110 /// \param[in] polldelay Time between polling available() in milliseconds. This can be useful
111 /// in multitaking environment like Linux to prevent waitAvailableTimeout
112 /// using all the CPU while polling for receiver activity
113 virtual void waitAvailable(uint16_t polldelay = 0);
114
115 /// Blocks until the transmitter
116 /// is no longer transmitting.
117 virtual bool waitPacketSent();
118
119 /// Blocks until the transmitter is no longer transmitting.
120 /// or until the timeout occuers, whichever happens first
121 /// \param[in] timeout Maximum time to wait in milliseconds.
122 /// \return true if the radio completed transmission within the timeout period. False if it timed out.
123 virtual bool waitPacketSent(uint16_t timeout);
124
125 /// Starts the receiver and blocks until a received message is available or a timeout.
126 /// Default implementation calls available() repeatedly until it returns true;
127 /// \param[in] timeout Maximum time to wait in milliseconds.
128 /// \param[in] polldelay Time between polling available() in milliseconds. This can be useful
129 /// in multitaking environment like Linux to prevent waitAvailableTimeout
130 /// using all the CPU while polling for receiver activity
131 /// \return true if a message is available
132 virtual bool waitAvailableTimeout(uint16_t timeout, uint16_t polldelay = 0);
133
134 // Bent G Christensen (bentor@gmail.com), 08/15/2016
135 /// Channel Activity Detection (CAD).
136 /// Blocks until channel activity is finished or CAD timeout occurs.
137 /// Uses the radio's CAD function (if supported) to detect channel activity.
138 /// Implements random delays of 100 to 1000ms while activity is detected and until timeout.
139 /// Caution: the random() function is not seeded. If you want non-deterministic behaviour, consider
140 /// using something like randomSeed(analogRead(A0)); in your sketch.
141 /// Permits the implementation of listen-before-talk mechanism (Collision Avoidance).
142 /// Calls the isChannelActive() member function for the radio (if supported)
143 /// to determine if the channel is active. If the radio does not support isChannelActive(),
144 /// always returns true immediately
145 /// \return true if the radio-specific CAD (as returned by isChannelActive())
146 /// shows the channel is clear within the timeout period (or the timeout period is 0), else returns false.
147 virtual bool waitCAD();
148
149 /// Sets the Channel Activity Detection timeout in milliseconds to be used by waitCAD().
150 /// The default is 0, which means do not wait for CAD detection.
151 /// CAD detection depends on support for isChannelActive() by your particular radio.
152 void setCADTimeout(unsigned long cad_timeout);
153
154 /// Determine if the currently selected radio channel is active.
155 /// This is expected to be subclassed by specific radios to implement their Channel Activity Detection
156 /// if supported. If the radio does not support CAD, returns true immediately. If a RadioHead radio
157 /// supports isChannelActive() it will be documented in the radio specific documentation.
158 /// This is called automatically by waitCAD().
159 /// \return true if the radio-specific CAD (as returned by override of isChannelActive()) shows the
160 /// current radio channel as active, else false. If there is no radio-specific CAD, returns false.
161 virtual bool isChannelActive();
162
163 /// Sets the address of this node. Defaults to 0xFF. Subclasses or the user may want to change this.
164 /// This will be used to test the adddress in incoming messages. In non-promiscuous mode,
165 /// only messages with a TO header the same as thisAddress or the broadcast addess (0xFF) will be accepted.
166 /// In promiscuous mode, all messages will be accepted regardless of the TO header.
167 /// In a conventional multinode system, all nodes will have a unique address
168 /// (which you could store in EEPROM).
169 /// You would normally set the header FROM address to be the same as thisAddress (though you dont have to,
170 /// allowing the possibilty of address spoofing).
171 /// \param[in] thisAddress The address of this node.
172 virtual void setThisAddress(uint8_t thisAddress);
173
174 /// Sets the TO header to be sent in all subsequent messages
175 /// \param[in] to The new TO header value
176 virtual void setHeaderTo(uint8_t to);
177
178 /// Sets the FROM header to be sent in all subsequent messages
179 /// \param[in] from The new FROM header value
180 virtual void setHeaderFrom(uint8_t from);
181
182 /// Sets the ID header to be sent in all subsequent messages
183 /// \param[in] id The new ID header value
184 virtual void setHeaderId(uint8_t id);
185
186 /// Sets and clears bits in the FLAGS header to be sent in all subsequent messages
187 /// First it clears he FLAGS according to the clear argument, then sets the flags according to the
188 /// set argument. The default for clear always clears the application specific flags.
189 /// \param[in] set bitmask of bits to be set. Flags are cleared with the clear mask before being set.
190 /// \param[in] clear bitmask of flags to clear. Defaults to RH_FLAGS_APPLICATION_SPECIFIC
191 /// which clears the application specific flags, resulting in new application specific flags
192 /// identical to the set.
193 virtual void setHeaderFlags(uint8_t set, uint8_t clear = RH_FLAGS_APPLICATION_SPECIFIC);
194
195 /// Tells the receiver to accept messages with any TO address, not just messages
196 /// addressed to thisAddress or the broadcast address
197 /// \param[in] promiscuous true if you wish to receive messages with any TO address
198 virtual void setPromiscuous(bool promiscuous);
199
200 /// Returns the TO header of the last received message
201 /// \return The TO header
202 virtual uint8_t headerTo();
203
204 /// Returns the FROM header of the last received message
205 /// \return The FROM header
206 virtual uint8_t headerFrom();
207
208 /// Returns the ID header of the last received message
209 /// \return The ID header
210 virtual uint8_t headerId();
211
212 /// Returns the FLAGS header of the last received message
213 /// \return The FLAGS header
214 virtual uint8_t headerFlags();
215
216 /// Returns the most recent RSSI (Receiver Signal Strength Indicator).
217 /// Usually it is the RSSI of the last received message, which is measured when the preamble is received.
218 /// If you called readRssi() more recently, it will return that more recent value.
219 /// \return The most recent RSSI measurement in dBm.
220 virtual int16_t lastRssi();
221
222 /// Returns the operating mode of the library.
223 /// \return the current mode, one of RF69_MODE_*
224 virtual RHMode mode();
225
226 /// Sets the operating mode of the transport.
227 virtual void setMode(RHMode mode);
228
229 /// Sets the transport hardware into low-power sleep mode
230 /// (if supported). May be overridden by specific drivers to initialte sleep mode.
231 /// If successful, the transport will stay in sleep mode until woken by
232 /// changing mode it idle, transmit or receive (eg by calling send(), recv(), available() etc)
233 /// \return true if sleep mode is supported by transport hardware and the RadioHead driver, and if sleep mode
234 /// was successfully entered. If sleep mode is not suported, return false.
235 virtual bool sleep();
236
237 /// Prints a data buffer in HEX.
238 /// For diagnostic use
239 /// \param[in] prompt string to preface the print
240 /// \param[in] buf Location of the buffer to print
241 /// \param[in] len Length of the buffer in octets.
242 static void printBuffer(const char* prompt, const uint8_t* buf, uint8_t len);
243
244 /// Returns the count of the number of bad received packets (ie packets with bad lengths, checksum etc)
245 /// which were rejected and not delivered to the application.
246 /// Caution: not all drivers can correctly report this count. Some underlying hardware only report
247 /// good packets.
248 /// \return The number of bad packets received.
249 virtual uint16_t rxBad();
250
251 /// Returns the count of the number of
252 /// good received packets
253 /// \return The number of good packets received.
254 virtual uint16_t rxGood();
255
256 /// Returns the count of the number of
257 /// packets successfully transmitted (though not necessarily received by the destination)
258 /// \return The number of packets successfully transmitted
259 virtual uint16_t txGood();
260
261protected:
262
263 /// The current transport operating mode
264 volatile RHMode _mode;
265
266 /// This node id
268
269 /// Whether the transport is in promiscuous mode
271
272 /// TO header in the last received mesasge
273 volatile uint8_t _rxHeaderTo;
274
275 /// FROM header in the last received mesasge
276 volatile uint8_t _rxHeaderFrom;
277
278 /// ID header in the last received mesasge
279 volatile uint8_t _rxHeaderId;
280
281 /// FLAGS header in the last received mesasge
282 volatile uint8_t _rxHeaderFlags;
283
284 /// TO header to send in all messages
285 uint8_t _txHeaderTo;
286
287 /// FROM header to send in all messages
289
290 /// ID header to send in all messages
291 uint8_t _txHeaderId;
292
293 /// FLAGS header to send in all messages
295
296 /// The value of the last received RSSI value, in some transport specific units
297 volatile int16_t _lastRssi;
298
299 /// Count of the number of bad messages (eg bad checksum etc) received
300 volatile uint16_t _rxBad;
301
302 /// Count of the number of successfully transmitted messaged
303 volatile uint16_t _rxGood;
304
305 /// Count of the number of bad messages (correct checksum etc) received
306 volatile uint16_t _txGood;
307
308 /// Channel activity detected
309 volatile bool _cad;
310
311 /// Channel activity timeout in ms
312 unsigned int _cad_timeout;
313
314private:
315
316};
317
318#endif
Abstract base class for a RadioHead driver.
Definition: RHGenericDriver.h:42
virtual uint16_t rxBad()
Definition: RHGenericDriver.cpp:200
volatile bool _cad
Channel activity detected.
Definition: RHGenericDriver.h:309
virtual uint8_t headerFlags()
Definition: RHGenericDriver.cpp:155
virtual void setHeaderTo(uint8_t to)
Definition: RHGenericDriver.cpp:119
virtual uint8_t maxMessageLength()=0
virtual void setPromiscuous(bool promiscuous)
Definition: RHGenericDriver.cpp:109
uint8_t _txHeaderFrom
FROM header to send in all messages.
Definition: RHGenericDriver.h:288
bool _promiscuous
Whether the transport is in promiscuous mode.
Definition: RHGenericDriver.h:270
virtual bool available()=0
volatile uint8_t _rxHeaderId
ID header in the last received mesasge.
Definition: RHGenericDriver.h:279
volatile RHMode _mode
The current transport operating mode.
Definition: RHGenericDriver.h:264
volatile uint16_t _rxBad
Count of the number of bad messages (eg bad checksum etc) received.
Definition: RHGenericDriver.h:300
virtual bool init()
Definition: RHGenericDriver.cpp:23
unsigned int _cad_timeout
Channel activity timeout in ms.
Definition: RHGenericDriver.h:312
void setCADTimeout(unsigned long cad_timeout)
Definition: RHGenericDriver.cpp:215
virtual void setHeaderFrom(uint8_t from)
Definition: RHGenericDriver.cpp:124
virtual void setHeaderId(uint8_t id)
Definition: RHGenericDriver.cpp:129
virtual bool send(const uint8_t *data, uint8_t len)=0
virtual bool recv(uint8_t *buf, uint8_t *len)=0
virtual void setThisAddress(uint8_t thisAddress)
Definition: RHGenericDriver.cpp:114
volatile uint16_t _txGood
Count of the number of bad messages (correct checksum etc) received.
Definition: RHGenericDriver.h:306
virtual uint16_t rxGood()
Definition: RHGenericDriver.cpp:205
volatile uint8_t _rxHeaderFlags
FLAGS header in the last received mesasge.
Definition: RHGenericDriver.h:282
static void printBuffer(const char *prompt, const uint8_t *buf, uint8_t len)
Definition: RHGenericDriver.cpp:181
virtual uint16_t txGood()
Definition: RHGenericDriver.cpp:210
uint8_t _thisAddress
This node id.
Definition: RHGenericDriver.h:267
virtual uint8_t headerTo()
Definition: RHGenericDriver.cpp:140
volatile uint8_t _rxHeaderFrom
FROM header in the last received mesasge.
Definition: RHGenericDriver.h:276
virtual bool waitPacketSent()
Definition: RHGenericDriver.cpp:58
uint8_t _txHeaderTo
TO header to send in all messages.
Definition: RHGenericDriver.h:285
virtual void waitAvailable(uint16_t polldelay=0)
Definition: RHGenericDriver.cpp:29
RHMode
Defines different operating modes for the transport hardware.
Definition: RHGenericDriver.h:49
@ RHModeIdle
Transport is idle.
Definition: RHGenericDriver.h:52
@ RHModeTx
Transport is in the process of transmitting a message.
Definition: RHGenericDriver.h:53
@ RHModeCad
Transport is in the process of detecting channel activity (if supported)
Definition: RHGenericDriver.h:55
@ RHModeRx
Transport is in the process of receiving a message.
Definition: RHGenericDriver.h:54
@ RHModeSleep
Transport hardware is in low power sleep mode (if supported)
Definition: RHGenericDriver.h:51
@ RHModeInitialising
Transport is initialising. Initial default value until init() is called..
Definition: RHGenericDriver.h:50
virtual RHMode mode()
Definition: RHGenericDriver.cpp:165
virtual uint8_t headerId()
Definition: RHGenericDriver.cpp:150
virtual uint8_t headerFrom()
Definition: RHGenericDriver.cpp:145
virtual bool waitAvailableTimeout(uint16_t timeout, uint16_t polldelay=0)
Definition: RHGenericDriver.cpp:42
virtual bool sleep()
Definition: RHGenericDriver.cpp:175
volatile int16_t _lastRssi
The value of the last received RSSI value, in some transport specific units.
Definition: RHGenericDriver.h:297
virtual void setMode(RHMode mode)
Sets the operating mode of the transport.
Definition: RHGenericDriver.cpp:170
virtual int16_t lastRssi()
Definition: RHGenericDriver.cpp:160
RHGenericDriver()
Constructor.
Definition: RHGenericDriver.cpp:8
volatile uint16_t _rxGood
Count of the number of successfully transmitted messaged.
Definition: RHGenericDriver.h:303
uint8_t _txHeaderFlags
FLAGS header to send in all messages.
Definition: RHGenericDriver.h:294
volatile uint8_t _rxHeaderTo
TO header in the last received mesasge.
Definition: RHGenericDriver.h:273
virtual bool waitCAD()
Definition: RHGenericDriver.cpp:78
virtual void setHeaderFlags(uint8_t set, uint8_t clear=RH_FLAGS_APPLICATION_SPECIFIC)
Definition: RHGenericDriver.cpp:134
virtual ~RHGenericDriver()
Generic destructor to prevent warnings when objects are dynamically allocated.
Definition: RHGenericDriver.h:62
uint8_t _txHeaderId
ID header to send in all messages.
Definition: RHGenericDriver.h:291
virtual bool isChannelActive()
Definition: RHGenericDriver.cpp:104