forked from hallard/RadioHead
-
Notifications
You must be signed in to change notification settings - Fork 0
/
RH_TCP.h
187 lines (163 loc) · 7.94 KB
/
RH_TCP.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// RH_TCP.h
// Author: Mike McCauley (mikem@aierspayce.com)
// Copyright (C) 2014 Mike McCauley
// $Id: RH_TCP.h,v 1.4 2015/08/13 02:45:47 mikem Exp $
#ifndef RH_TCP_h
#define RH_TCP_h
#include <RHGenericDriver.h>
#include <RHTcpProtocol.h>
/////////////////////////////////////////////////////////////////////
/// \class RH_TCP RH_TCP.h <RH_TCP.h>
/// \brief Driver to send and receive unaddressed, unreliable datagrams via sockets on a Linux simulator
///
/// \par Overview
///
/// This class is intended to support the testing of RadioHead manager classes and simulated sketches
/// on a Linux host.
/// RH_TCP class sends messages to and from other simulator sketches via sockets to a 'Luminiferous Ether'
/// simulator server (provided).
/// Multiple instances of simulated clients and servers can run on a single Linux server,
/// passing messages to each other via the etherSimulator.pl server.
///
/// Simple RadioHead sketches can be compiled and run on Linux using a build script and some support files.
///
/// \par Running simulated sketches
///
/// \code
/// cd whatever/RadioHead
/// # build the client for Linux:
/// tools/simBuild examples/simulator/simulator_reliable_datagram_client/simulator_reliable_datagram_client.pde
/// # build the server for Linux:
/// tools/simBuild examples/simulator/simulator_reliable_datagram_server/simulator_reliable_datagram_server.pde
/// # in one window, run the simulator server:
/// tools/etherSimulator.pl
/// # in another window, run the server
/// ./simulator_reliable_datagram_server
/// # in another window, run the client:
/// ./simulator_reliable_datagram_client
/// # see output:
/// Sending to simulator_reliable_datagram_server
/// got reply from : 0x02: And hello back to you
/// Sending to simulator_reliable_datagram_server
/// got reply from : 0x02: And hello back to you
/// Sending to simulator_reliable_datagram_server
/// got reply from : 0x02: And hello back to you
/// ...
/// \endcode
///
/// You can change the listen port and the simulated baud rate with
/// command line arguments passed to etherSimulator.pl
///
/// \par Implementation
///
/// etherServer.pl is a conventional server written in Perl.
/// listens on a TCP socket (defaults to port 4000) for connections from sketch simulators
/// using RH_TCP as theur driver.
/// The simulated sketches send messages out to the 'ether' over the TCP connection to the etherServer.
/// etherServer manages the delivery of each message to any other RH_TCP sketches that are running.
///
/// \par Prerequisites
///
/// g++ compiler installed and in your $PATH
/// Perl
/// Perl POE library
///
class RH_TCP : public RHGenericDriver
{
public:
/// Constructor
/// \param[in] server Name and optionally the port number of the ether simulator server to contact.
/// Format is "name[:port]", where name can be any valid host name or address (IPV4 or IPV6).
/// The trailing :port is optional, and port can be any valid
/// port name or port number.
RH_TCP(const char* server = "localhost:4000");
/// Initialise the Driver transport hardware and software.
/// Make sure the Driver is properly configured before calling init().
/// \return true if initialisation succeeded.
virtual bool init();
/// Tests whether a new message is available
/// from the Driver.
/// On most drivers, this will also put the Driver into RHModeRx mode until
/// a message is actually received by the transport, when it will be returned to RHModeIdle.
/// This can be called multiple times in a timeout loop
/// \return true if a new, complete, error-free uncollected message is available to be retreived by recv()
virtual bool available();
/// Wait until a new message is available from the driver.
/// Blocks until a complete message is received as reported by available()
virtual void waitAvailable();
/// Wait until a new message is available from the driver
/// or the timeout expires
/// Blocks until a complete message is received as reported by available()
/// \param[in] timeout The maximum time to wait in milliseconds
/// \return true if a message is available as reported by available()
virtual bool waitAvailableTimeout(uint16_t timeout);
/// Turns the receiver on if it not already on.
/// If there is a valid message available, copy it to buf and return true
/// else return false.
/// If a message is copied, *len is set to the length (Caution, 0 length messages are permitted).
/// You should be sure to call this function frequently enough to not miss any messages
/// It is recommended that you call it in your main loop.
/// \param[in] buf Location to copy the received message
/// \param[in,out] len Pointer to available space in buf. Set to the actual number of octets copied.
/// \return true if a valid message was copied to buf
virtual bool recv(uint8_t* buf, uint8_t* len);
/// Waits until any previous transmit packet is finished being transmitted with waitPacketSent().
/// Then loads a message into the transmitter and starts the transmitter. Note that a message length
/// of 0 is NOT permitted. If the message is too long for the underlying radio technology, send() will
/// return false and will not send the message.
/// \param[in] data Array of data to be sent
/// \param[in] len Number of bytes of data to send (> 0)
/// \return true if the message length was valid and it was correctly queued for transmit
virtual bool send(const uint8_t* data, uint8_t len);
/// Returns the maximum message length
/// available in this Driver.
/// \return The maximum legal message length
virtual uint8_t maxMessageLength();
/// Sets the address of this node. Defaults to 0xFF. Subclasses or the user may want to change this.
/// This will be used to test the adddress in incoming messages. In non-promiscuous mode,
/// only messages with a TO header the same as thisAddress or the broadcast addess (0xFF) will be accepted.
/// In promiscuous mode, all messages will be accepted regardless of the TO header.
/// In a conventional multinode system, all nodes will have a unique address
/// (which you could store in EEPROM).
/// You would normally set the header FROM address to be the same as thisAddress (though you dont have to,
/// allowing the possibilty of address spoofing).
/// \param[in] address The address of this node.
void setThisAddress(uint8_t address);
protected:
private:
/// Connect to the address and port specified by the server constructor argument.
/// Prepares the socket for use.
bool connectToServer();
/// Check for new messages from the ether simulator server
void checkForEvents();
/// Clear the receive buffer
void clearRxBuf();
/// Sends thisAddress to the ether simulator server
/// in a RHTcpThisAddress message.
/// \param[in] thisAddress The node address of this node
/// \return true if successful
bool sendThisAddress(uint8_t thisAddress);
/// Sends a message to the ether simulator server for delivery to
/// other nodes
/// \param[in] data Array of data to be sent
/// \param[in] len Number of bytes of data to send (> 0)
/// \return true if successful
bool sendPacket(const uint8_t* data, uint8_t len);
/// Address and port of the server to which messages are sent
/// and received using the protocol RHTcpPRotocol
const char* _server;
/// The TCP socket used to communicate with the message server
int _socket;
/// Buffer to receive RHTcpProtocol messages
uint8_t _rxBuf[RH_TCP_MAX_PAYLOAD_LEN + 5];
uint16_t _rxBufLen;
bool _rxBufValid;
/// Check whether the latest received message is complete and uncorrupted
void validateRxBuf();
// Used in the interrupt handlers
/// Buf is filled but not validated
volatile bool _rxBufFull;
};
/// @example simulator_reliable_datagram_client.pde
/// @example simulator_reliable_datagram_server.pde
#endif