forked from adafruit/Adafruit_CC3000_Library
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Adafruit_CC3000_Server.cpp
279 lines (236 loc) · 9.13 KB
/
Adafruit_CC3000_Server.cpp
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
/**************************************************************************/
/*!
@file Adafruit_CC3000_Server.cpp
@author Tony DiCola ([email protected])
@license BSD (see license.txt)
Adafruit CC3000 TCP server implementation based on the same interface as
the Arduino Ethernet library server class.
See http://arduino.cc/en/Reference/Ethernet for documentation on the
Arduino Ethernet library and its server interface.
*/
/**************************************************************************/
#include "Adafruit_CC3000_Server.h"
#include "utility/socket.h"
#define CC3K_PRINTLN_F(text) CHECK_PRINTER { if(CC3KPrinter != NULL) { CC3KPrinter->println(F(text)); } }
#define HANDLE_NULL(client, value) { if (client == NULL) return value; }
/**************************************************************************/
/*
Adafruit_CC3000_ClientRef implementation
*/
/**************************************************************************/
Adafruit_CC3000_ClientRef::Adafruit_CC3000_ClientRef(Adafruit_CC3000_Client* client)
: _client(client)
{ }
// Return true if the referenced client is connected. This is provided for
// compatibility with Ethernet library code.
Adafruit_CC3000_ClientRef::operator bool() {
return connected();
}
// Below are wrappers around the public client functions. These hide the fact that users
// are dealing with a reference to a client instance and allow code to be written using
// value semantics like in the Ethernet library.
int Adafruit_CC3000_ClientRef::connect(IPAddress ip, uint16_t port) {
HANDLE_NULL(_client, false);
return _client->connect(ip, port);
}
int Adafruit_CC3000_ClientRef::connect(const char *host, uint16_t port) {
HANDLE_NULL(_client, false);
return _client->connect(host, port);
}
uint8_t Adafruit_CC3000_ClientRef::connected(void) {
HANDLE_NULL(_client, false);
return _client->connected();
}
size_t Adafruit_CC3000_ClientRef::write(uint8_t c) {
HANDLE_NULL(_client, 0);
return _client->write(c);
}
size_t Adafruit_CC3000_ClientRef::fastrprint(const char *str) {
HANDLE_NULL(_client, 0);
return _client->fastrprint(str);
}
size_t Adafruit_CC3000_ClientRef::fastrprintln(const char *str) {
HANDLE_NULL(_client, 0);
return _client->fastrprintln(str);
}
size_t Adafruit_CC3000_ClientRef::fastrprint(char *str) {
HANDLE_NULL(_client, 0);
return _client->fastrprint(str);
}
size_t Adafruit_CC3000_ClientRef::fastrprintln(char *str) {
HANDLE_NULL(_client, 0);
return _client->fastrprintln(str);
}
size_t Adafruit_CC3000_ClientRef::fastrprint(const __FlashStringHelper *ifsh) {
HANDLE_NULL(_client, 0);
return _client->fastrprint(ifsh);
}
size_t Adafruit_CC3000_ClientRef::fastrprintln(const __FlashStringHelper *ifsh) {
HANDLE_NULL(_client, 0);
return _client->fastrprintln(ifsh);
}
size_t Adafruit_CC3000_ClientRef::write(const void *buf, uint16_t len, uint32_t flags) {
HANDLE_NULL(_client, 0);
return _client->write(buf, len, flags);
}
int Adafruit_CC3000_ClientRef::read(void *buf, uint16_t len, uint32_t flags) {
HANDLE_NULL(_client, 0);
return _client->read(buf, len, flags);
}
int Adafruit_CC3000_ClientRef::read(void) {
HANDLE_NULL(_client, 0);
return _client->read();
}
int32_t Adafruit_CC3000_ClientRef::close(void) {
HANDLE_NULL(_client, 0);
return _client->close();
}
int Adafruit_CC3000_ClientRef::available(void) {
HANDLE_NULL(_client, 0);
return _client->available();
}
int Adafruit_CC3000_ClientRef::read(uint8_t *buf, size_t size) {
HANDLE_NULL(_client, 0);
return _client->read(buf, size);
}
size_t Adafruit_CC3000_ClientRef::write(const uint8_t *buf, size_t size) {
HANDLE_NULL(_client, 0);
return _client->write(buf, size);
}
int Adafruit_CC3000_ClientRef::peek() {
HANDLE_NULL(_client, 0);
return _client->peek();
}
void Adafruit_CC3000_ClientRef::flush() {
if (_client != NULL) _client->flush();
}
void Adafruit_CC3000_ClientRef::stop() {
if (_client != NULL) _client->stop();
}
/**************************************************************************/
/*
Adafruit_CC3000_Server implementation
*/
/**************************************************************************/
// Construct a TCP server to listen on the specified port.
Adafruit_CC3000_Server::Adafruit_CC3000_Server(uint16_t port)
: _port(port)
, _listenSocket(-1)
{ }
// Return index of a client with data available for reading. Can be turned
// into a client instance with getClientRef(). Accepts an optional parameter
// to return a boolean (by reference) indicating if available client is connecting
// for the first time.
int8_t Adafruit_CC3000_Server::availableIndex(bool *newClient) {
bool newClientCreated = acceptNewConnections();
if (newClient)
*newClient = newClientCreated;
// Find the first client which is ready to read and return it.
for (int i = 0; i < MAX_SERVER_CLIENTS; ++i) {
if (_clients[i].connected() && _clients[i].available() > 0) {
return i;
}
}
return -1;
}
// Given the index of client, returns the instance of that client for reading/writing
Adafruit_CC3000_ClientRef Adafruit_CC3000_Server::getClientRef(int8_t clientIndex) {
if (clientIndex != -1) {
return Adafruit_CC3000_ClientRef(&_clients[clientIndex]);
}
// Couldn't find a client ready to read, so return a client that is not
// connected to signal no clients are available for reading (convention
// used by the Ethernet library).
return Adafruit_CC3000_ClientRef(NULL);
}
// Return a reference to a client instance which has data available to read.
Adafruit_CC3000_ClientRef Adafruit_CC3000_Server::available() {
return getClientRef(availableIndex(NULL));
}
// Initialize the server and start listening for connections.
void Adafruit_CC3000_Server::begin() {
// Set the CC3000 inactivity timeout to 0 (never timeout). This will ensure
// the CC3000 does not close the listening socket when it's idle for more than
// 60 seconds (the default timeout). See more information from:
// http://e2e.ti.com/support/low_power_rf/f/851/t/292664.aspx
unsigned long aucDHCP = 14400;
unsigned long aucARP = 3600;
unsigned long aucKeepalive = 30;
unsigned long aucInactivity = 0;
cc3k_int_poll();
if (netapp_timeout_values(&aucDHCP, &aucARP, &aucKeepalive, &aucInactivity) != 0) {
CC3K_PRINTLN_F("Error setting inactivity timeout!");
return;
}
// Create a TCP socket
cc3k_int_poll();
int16_t soc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (soc < 0) {
CC3K_PRINTLN_F("Couldn't create listening socket!");
return;
}
// Set the socket's accept call as non-blocking.
cc3k_int_poll();
char arg = SOCK_ON; // nsd: looked in TI example code and they pass this as a 'short' in one example, and 'char' in two others. 'char' seems as likely work, and has no endianess issue
if (setsockopt(soc, SOL_SOCKET, SOCKOPT_ACCEPT_NONBLOCK, &arg, sizeof(arg)) < 0) {
CC3K_PRINTLN_F("Couldn't set socket as non-blocking!");
return;
}
// Bind the socket to a TCP address.
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(0); // Listen on any network interface, equivalent to INADDR_ANY in sockets programming.
address.sin_port = htons(_port); // Listen on the specified port.
cc3k_int_poll();
if (bind(soc, (sockaddr*) &address, sizeof(address)) < 0) {
CC3K_PRINTLN_F("Error binding listen socket to address!");
return;
}
// Start listening for connections.
// The backlog parameter is 0 as it is not supported on TI's CC3000 firmware.
cc3k_int_poll();
if (listen(soc, 0) < 0) {
CC3K_PRINTLN_F("Error opening socket for listening!");
return;
}
_listenSocket = soc;
}
// Write data to all connected clients. Buffer is a pointer to an array
// of bytes, and size specifies how many bytes to write from the buffer.
// Return the sum of bytes written to all clients.
size_t Adafruit_CC3000_Server::write(const uint8_t *buffer, size_t size) {
size_t written = 0;
for (int i = 0; i < MAX_SERVER_CLIENTS; ++i) {
if (_clients[i].connected()) {
written += _clients[i].write(buffer, size);
}
}
return written;
}
// Write a byte value to all connected clients.
// Return the sum of bytes written to all clients.
size_t Adafruit_CC3000_Server::write(uint8_t value) {
return write(&value, 1);
}
// Accept new connections and update the connected clients.
bool Adafruit_CC3000_Server::acceptNewConnections() {
bool newClientCreated = false;
// For any unconnected client, see if new connections are pending and accept
// them as a new client.
for (int i = 0; i < MAX_SERVER_CLIENTS; ++i) {
if (!_clients[i].connected()) {
// Note: Because the non-blocking option was set for the listening
// socket this call will not block and instead return SOC_IN_PROGRESS (-2)
// if there are no pending client connections. Also, the address of the
// connected client is not needed, so those parameters are set to NULL.
cc3k_int_poll();
int soc = accept(_listenSocket, NULL, NULL);
if (soc > -1) {
_clients[i] = Adafruit_CC3000_Client(soc);
newClientCreated = true;
}
// else either there were no sockets to accept or an error occured.
}
}
return newClientCreated;
}