Skip to content

Commit a0483f0

Browse files
committed
Do not rely on ATParser library for CONNECT and CLOSE commands
1 parent c0aa5d4 commit a0483f0

File tree

4 files changed

+118
-56
lines changed

4 files changed

+118
-56
lines changed

Diff for: ESP8266/ESP8266.cpp

+90-23
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,6 @@ bool ESP8266::startup(int mode)
5151

5252
_parser.oob("+IPD", this, &ESP8266::_packet_handler);
5353

54-
_parser.oob("0,CONNECT", this, &ESP8266::_incoming_socket_opened0);
55-
_parser.oob("1,CONNECT", this, &ESP8266::_incoming_socket_opened1);
56-
_parser.oob("2,CONNECT", this, &ESP8266::_incoming_socket_opened2);
57-
_parser.oob("3,CONNECT", this, &ESP8266::_incoming_socket_opened3);
58-
_parser.oob("4,CONNECT", this, &ESP8266::_incoming_socket_opened4);
59-
60-
_parser.oob("0,CLOSED", this, &ESP8266::_incoming_socket_closed0);
61-
_parser.oob("1,CLOSED", this, &ESP8266::_incoming_socket_closed1);
62-
_parser.oob("2,CLOSED", this, &ESP8266::_incoming_socket_closed2);
63-
_parser.oob("3,CLOSED", this, &ESP8266::_incoming_socket_closed3);
64-
_parser.oob("4,CLOSED", this, &ESP8266::_incoming_socket_closed4);
65-
6654
return success;
6755
}
6856

@@ -253,6 +241,10 @@ void ESP8266::_packet_handler()
253241

254242
int32_t ESP8266::recv(int id, void *data, uint32_t amount)
255243
{
244+
bool exit_when_not_found = false;
245+
246+
bool is_incoming_socket = _incoming_socket_status[id];
247+
256248
while (true) {
257249
// check if any packets are ready for us
258250
for (struct packet **p = &_packets; *p; p = &(*p)->next) {
@@ -281,10 +273,37 @@ int32_t ESP8266::recv(int id, void *data, uint32_t amount)
281273
}
282274
}
283275

284-
// Wait for inbound packet
285-
if (!_parser.recv("OK")) {
276+
if (exit_when_not_found) {
286277
return -1;
287278
}
279+
280+
// Here's a problem... recv() blocks for forever, but it might be that the underlying socket closes in the meantime.
281+
// We know when it happens (due to monitoring the RX IRQ channel)
282+
// but there's no way of signaling this thread and actually abort the request...
283+
284+
if (is_incoming_socket) {
285+
int timeout = _parser.getTimeout();
286+
_parser.setTimeout(1000);
287+
288+
if (!_parser.recv("OK")) {
289+
_parser.setTimeout(timeout);
290+
291+
// socket gone
292+
if (!_incoming_socket_status[id]) return NSAPI_ERROR_NO_SOCKET;
293+
294+
// otherwise, just continue trying to get data...
295+
continue;
296+
}
297+
}
298+
else {
299+
// Wait for inbound packet
300+
if (!_parser.recv("OK")) {
301+
// so this is weird... the message just received by the parser could actually be one of ours (in TCPServer mode)...
302+
// so do one more pass...
303+
exit_when_not_found = true;
304+
continue;
305+
}
306+
}
288307
}
289308
}
290309

@@ -316,7 +335,7 @@ bool ESP8266::writeable()
316335
return _serial.writeable();
317336
}
318337

319-
void ESP8266::attach(Callback<void()> func)
338+
void ESP8266::attach(Callback<void(int)> func)
320339
{
321340
_serial.attach(func);
322341
}
@@ -335,20 +354,68 @@ bool ESP8266::recv_ap(nsapi_wifi_ap_t *ap)
335354

336355
bool ESP8266::bind(const SocketAddress& address)
337356
{
357+
// we need an event queue to dispatch from serial RX IRQ -> non-IRQ thread
358+
event_queue = new EventQueue();
359+
event_thread = new Thread(osPriorityNormal, 2048);
360+
if (!event_queue || !event_thread) {
361+
return NSAPI_ERROR_NO_MEMORY;
362+
}
363+
event_thread->start(callback(event_queue, &EventQueue::dispatch_forever));
364+
365+
// buffer to store RX data in
366+
rx_buffer = (char*)malloc(1024);
367+
rx_ix = 0;
368+
if (!rx_buffer) {
369+
return NSAPI_ERROR_NO_MEMORY;
370+
}
371+
372+
// clear incoming socket status
373+
memset(_incoming_socket_status, 0, sizeof(_incoming_socket_status));
374+
375+
// attach to the serial
376+
_serial.attach(callback(this, &ESP8266::attach_rx));
377+
378+
// and start the actual server
338379
return _parser.send("AT+CIPSERVER=1,%d", address.get_port())
339380
&& _parser.recv("OK");
340381
}
341382

342-
void ESP8266::_incoming_socket_opened(int8_t socket_id)
343-
{
344-
printf("Incoming socket opened %d\n", socket_id);
383+
void ESP8266::process_command(char* cmd, size_t size) {
384+
if (size == 9 /* 0,CONNECT */
385+
&& (cmd[0] >= '0' && cmd[0] <= '9')
386+
&& (cmd[1] == ',')
387+
&& (strcmp(&cmd[2], "CONNECT") == 0)) {
388+
389+
_incoming_socket_status[cmd[0] - '0'] = true;
390+
391+
_signalingCallback(ESP8266_SOCKET_CONNECT, cmd[0] - '0');
392+
}
393+
else if (size == 8 /* 0,CLOSED */
394+
&& (cmd[0] >= '0' && cmd[0] <= '9')
395+
&& (cmd[1] == ',')
396+
&& (strcmp(&cmd[2], "CLOSED") == 0)) {
345397

346-
_signalingCallback(ESP8266_SOCKET_CONNECT, socket_id);
398+
_incoming_socket_status[cmd[0] - '0'] = false;
399+
400+
_signalingCallback(ESP8266_SOCKET_CLOSE, cmd[0] - '0');
401+
}
402+
free(cmd);
347403
}
348404

349-
void ESP8266::_incoming_socket_closed(int8_t socket_id)
350-
{
351-
printf("Incoming socket closed %d\n", socket_id);
405+
void ESP8266::attach_rx(int c) {
406+
// store value in buffer
407+
rx_buffer[rx_ix] = c;
408+
rx_buffer[rx_ix + 1] = 0;
409+
410+
if (rx_ix > 0 && c == '\n') {
411+
// got a whole command
412+
char* cmd = (char*)calloc(rx_ix, 1);
413+
memcpy(cmd, rx_buffer, rx_ix - 1);
414+
event_queue->call(callback(this, &ESP8266::process_command), cmd, rx_ix - 1);
415+
416+
rx_ix = 0;
417+
return;
418+
}
352419

353-
_signalingCallback(ESP8266_SOCKET_CLOSE, socket_id);
420+
rx_ix++;
354421
}

Diff for: ESP8266/ESP8266.h

+10-17
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,10 @@ class ESP8266
218218
*/
219219
bool bind(const SocketAddress& address);
220220

221-
void ping();
222-
223221
private:
222+
void attach_rx(int);
223+
void process_command(char*, size_t);
224+
224225
BufferedSerial _serial;
225226
ATParser _parser;
226227
Callback<void(SignalingAction, int)> _signalingCallback;
@@ -232,28 +233,20 @@ class ESP8266
232233
// data follows
233234
} *_packets, **_packets_end;
234235
void _packet_handler();
235-
void _incoming_socket_opened(int8_t);
236-
void _incoming_socket_closed(int8_t);
237236
bool recv_ap(nsapi_wifi_ap_t *ap);
238237

239238
char _ip_buffer[16];
240239
char _gateway_buffer[16];
241240
char _netmask_buffer[16];
242241
char _mac_buffer[18];
243242

244-
// The CONNECTED OOB messages start with %d, and patching the ATParser is not worth it
245-
// Max. connections is 5 according to ESP8266_SOCKET_COUNT, if that changes, this has to change too
246-
void _incoming_socket_opened0() { _incoming_socket_opened(0); }
247-
void _incoming_socket_opened1() { _incoming_socket_opened(1); }
248-
void _incoming_socket_opened2() { _incoming_socket_opened(2); }
249-
void _incoming_socket_opened3() { _incoming_socket_opened(3); }
250-
void _incoming_socket_opened4() { _incoming_socket_opened(4); }
251-
252-
void _incoming_socket_closed0() { _incoming_socket_closed(0); }
253-
void _incoming_socket_closed1() { _incoming_socket_closed(1); }
254-
void _incoming_socket_closed2() { _incoming_socket_closed(2); }
255-
void _incoming_socket_closed3() { _incoming_socket_closed(3); }
256-
void _incoming_socket_closed4() { _incoming_socket_closed(4); }
243+
// TCPServer mode needs a separate thread to dispatch RX IRQ commands from
244+
EventQueue* event_queue;
245+
Thread* event_thread;
246+
char* rx_buffer;
247+
size_t rx_ix;
248+
bool _incoming_socket_status[5];
249+
257250
};
258251

259252
#endif

Diff for: ESP8266Interface.cpp

+17-16
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737

3838
// ESP8266Interface implementation
3939
ESP8266Interface::ESP8266Interface(PinName tx, PinName rx, bool debug)
40-
: _esp(tx, rx, callback(this, &ESP8266Interface::signal), false)
40+
: _esp(tx, rx, callback(this, &ESP8266Interface::signal), debug)
4141
{
4242
memset(_ids, 0, sizeof(_ids));
4343
memset(_cbs, 0, sizeof(_cbs));
@@ -208,7 +208,11 @@ int ESP8266Interface::socket_close(void *handle)
208208

209209
int ESP8266Interface::socket_bind(void *handle, const SocketAddress &address)
210210
{
211-
return _esp.bind(address);
211+
int bind_res = _esp.bind(address);
212+
if (bind_res < -3000) return bind_res;
213+
if (bind_res != 1) return NSAPI_ERROR_DEVICE_ERROR;
214+
215+
return NSAPI_ERROR_OK;
212216
}
213217

214218
int ESP8266Interface::socket_listen(void *handle, int backlog)
@@ -232,13 +236,7 @@ int ESP8266Interface::socket_connect(void *handle, const SocketAddress &addr)
232236

233237
int ESP8266Interface::socket_accept(void *server, void **socket, SocketAddress *addr)
234238
{
235-
printf("socket_accept\n");
236-
237239
while (1) {
238-
// to get the OOB messages we need to send something to the ESP8266 so the ATParser has time to
239-
// grab the packets. Send a bogus message to the module...
240-
_esp.get_firmware_version();
241-
242240
// now go through the _incoming_sockets array and see if there are unattached sockets...
243241
for (size_t ix = 0; ix < ESP8266_SOCKET_COUNT; ix++) {
244242
// printf("_incoming_sockets[ix] socket=%p connected=%d accepted=%d\n",
@@ -254,7 +252,7 @@ int ESP8266Interface::socket_accept(void *server, void **socket, SocketAddress *
254252
}
255253
}
256254

257-
wait_ms(20); // socket_accept is blocking
255+
wait_ms(20);
258256
}
259257
return 0;
260258
}
@@ -277,7 +275,10 @@ int ESP8266Interface::socket_recv(void *handle, void *data, unsigned size)
277275
_esp.setTimeout(ESP8266_RECV_TIMEOUT);
278276

279277
int32_t recv = _esp.recv(socket->id, data, size);
280-
if (recv < 0) {
278+
if (recv < -3000) {
279+
return recv;
280+
}
281+
else if (recv < 0) {
281282
return NSAPI_ERROR_WOULD_BLOCK;
282283
}
283284

@@ -334,12 +335,11 @@ void ESP8266Interface::event() {
334335
}
335336

336337
void ESP8266Interface::signal(SignalingAction action, int socket_id) {
337-
printf("ESP8266Interface::signal %d %d\n", action, socket_id);
338-
339338
if (action == ESP8266_SOCKET_CONNECT) {
339+
printf("ESP8266::SOCKET CONNECT %d\n", socket_id);
340340
if (_ids[socket_id]) {
341341
// this should not be possible...
342-
printf("ESP8266_SOCKET_CONNECT for socket that already exists...\n");
342+
// printf("ESP8266_SOCKET_CONNECT for socket that already exists...\n");
343343
// return;
344344
}
345345

@@ -359,6 +359,8 @@ void ESP8266Interface::signal(SignalingAction action, int socket_id) {
359359
_incoming_sockets[socket_id].accepted = false;
360360
}
361361
else if (action == ESP8266_SOCKET_CLOSE) {
362+
printf("ESP8266::SOCKET CLOSE %d\n", socket_id);
363+
362364
// Q: should we be able to delete the socket here? probably segfaults if held in user code
363365
struct esp8266_socket *socket = _incoming_sockets[socket_id].socket;
364366
if (!socket || !socket->connected) {
@@ -367,10 +369,9 @@ void ESP8266Interface::signal(SignalingAction action, int socket_id) {
367369
}
368370

369371
socket->connected = false;
372+
_ids[socket_id] = false;
370373
_incoming_sockets[socket_id].accepted = false;
371374
_incoming_sockets[socket_id].socket = NULL;
372-
_ids[socket_id] = false;
373-
374-
// delete socket?
375+
delete socket;
375376
}
376377
}

Diff for: ESP8266Interface.h

+1
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ class ESP8266Interface : public NetworkStack, public WiFiInterface
283283
struct esp8266_socket* socket;
284284
bool accepted;
285285
} _incoming_sockets[ESP8266_SOCKET_COUNT];
286+
286287
};
287288

288289
#endif

0 commit comments

Comments
 (0)