Skip to content

Commit 9d07746

Browse files
author
Veijo Pesonen
authored
Merge pull request #62 from ARMmbed/tcpsocket_keepalive
Tcpsocket keepalive
2 parents 5392ae2 + 598875e commit 9d07746

File tree

4 files changed

+156
-10
lines changed

4 files changed

+156
-10
lines changed

ESP8266/ESP8266.cpp

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616

1717
#include "ESP8266.h"
18-
#include "mbed_trace.h"
18+
#include "mbed_debug.h"
1919
#include "nsapi_types.h"
2020

2121
#include <cstring>
@@ -260,22 +260,56 @@ int ESP8266::scan(WiFiAccessPoint *res, unsigned limit)
260260
return cnt;
261261
}
262262

263-
bool ESP8266::open(const char *type, int id, const char* addr, int port, int local_port)
263+
bool ESP8266::open_udp(int id, const char* addr, int port, int local_port)
264264
{
265-
bool done;
265+
static const char *type = "UDP";
266+
bool done = false;
266267

267-
if (id >= SOCKET_COUNT) {
268+
if (id >= SOCKET_COUNT || _socket_open[id]) {
268269
return false;
269270
}
271+
270272
_smutex.lock();
271273
if(local_port) {
272274
done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d,%d", id, type, addr, port, local_port)
275+
&& _parser.recv("OK\n");
276+
} else {
277+
done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d", id, type, addr, port)
273278
&& _parser.recv("OK\n");
279+
}
280+
281+
if (done) {
282+
_socket_open[id] = 1;
283+
}
284+
285+
_smutex.unlock();
286+
287+
return done;
288+
}
289+
290+
bool ESP8266::open_tcp(int id, const char* addr, int port, int keepalive)
291+
{
292+
static const char *type = "UDP";
293+
bool done = false;
294+
295+
if (id >= SOCKET_COUNT || _socket_open[id]) {
296+
return false;
297+
}
298+
299+
_smutex.lock();
300+
301+
if(keepalive) {
302+
done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d,%d", id, type, addr, port, keepalive)
303+
&& _parser.recv("OK\n");
274304
} else {
275305
done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d", id, type, addr, port)
276306
&& _parser.recv("OK\n");
277307
}
278-
_socket_open[id] = 1;
308+
309+
if (done) {
310+
_socket_open[id] = 1;
311+
}
312+
279313
_smutex.unlock();
280314

281315
return done;
@@ -321,7 +355,7 @@ void ESP8266::_packet_handler()
321355
struct packet *packet = (struct packet*)malloc(
322356
sizeof(struct packet) + amount);
323357
if (!packet) {
324-
tr_error("Could not allocate memory for RX data");
358+
debug("Could not allocate memory for RX data");
325359
return;
326360
}
327361

ESP8266/ESP8266.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,24 @@ class ESP8266
134134
* @param id id to give the new socket, valid 0-4
135135
* @param port port to open connection with
136136
* @param addr the IP address of the destination
137+
* @param port the port on the destination
138+
* @param local_port UDP socket's local port, zero means any
137139
* @return true only if socket opened successfully
138140
*/
139-
bool open(const char *type, int id, const char* addr, int port, int local_port=0);
141+
bool open_udp(int id, const char* addr, int port, int local_port = 0);
142+
143+
/**
144+
* Open a socketed connection
145+
*
146+
* @param type the type of socket to open "UDP" or "TCP"
147+
* @param id id to give the new socket, valid 0-4
148+
* @param port port to open connection with
149+
* @param addr the IP address of the destination
150+
* @param port the port on the destination
151+
* @param tcp_keepalive TCP connection's keep alive time, zero means disabled
152+
* @return true only if socket opened successfully
153+
*/
154+
bool open_tcp(int id, const char* addr, int port, int keepalive = 0);
140155

141156
/**
142157
* Sends data to an open socket

ESP8266Interface.cpp

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ struct esp8266_socket {
301301
nsapi_protocol_t proto;
302302
bool connected;
303303
SocketAddress addr;
304+
int keepalive; // TCP
304305
};
305306

306307
int ESP8266Interface::socket_open(void **handle, nsapi_protocol_t proto)
@@ -328,6 +329,7 @@ int ESP8266Interface::socket_open(void **handle, nsapi_protocol_t proto)
328329
socket->id = id;
329330
socket->proto = proto;
330331
socket->connected = false;
332+
socket->keepalive = 0;
331333
*handle = socket;
332334
return 0;
333335
}
@@ -380,11 +382,17 @@ int ESP8266Interface::socket_listen(void *handle, int backlog)
380382
int ESP8266Interface::socket_connect(void *handle, const SocketAddress &addr)
381383
{
382384
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
385+
383386
_esp.setTimeout(ESP8266_MISC_TIMEOUT);
384387

385-
const char *proto = (socket->proto == NSAPI_UDP) ? "UDP" : "TCP";
386-
if (!_esp.open(proto, socket->id, addr.get_ip_address(), addr.get_port(), _local_ports[socket->id])) {
387-
return NSAPI_ERROR_DEVICE_ERROR;
388+
if (socket->proto == NSAPI_UDP) {
389+
if (!_esp.open_udp(socket->id, addr.get_ip_address(), addr.get_port(), _local_ports[socket->id])) {
390+
return NSAPI_ERROR_DEVICE_ERROR;
391+
}
392+
} else {
393+
if (!_esp.open_tcp(socket->id, addr.get_ip_address(), addr.get_port(), socket->keepalive)) {
394+
return NSAPI_ERROR_DEVICE_ERROR;
395+
}
388396
}
389397

390398
socket->connected = true;
@@ -472,6 +480,61 @@ void ESP8266Interface::socket_attach(void *handle, void (*callback)(void *), voi
472480
_cbs[socket->id].data = data;
473481
}
474482

483+
nsapi_error_t ESP8266Interface::setsockopt(nsapi_socket_t handle, int level,
484+
int optname, const void *optval, unsigned optlen)
485+
{
486+
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
487+
488+
if (!optlen || !socket) {
489+
return NSAPI_ERROR_PARAMETER;
490+
}
491+
492+
if (level == NSAPI_SOCKET && socket->proto == NSAPI_TCP) {
493+
switch (optname) {
494+
case NSAPI_KEEPALIVE: {
495+
if(socket->connected) {// ESP8266 limitation, keepalive needs to be given before connecting
496+
return NSAPI_ERROR_UNSUPPORTED;
497+
}
498+
499+
if (optlen == sizeof(int)) {
500+
int secs = *(int *)optval;
501+
if (secs >= 0 && secs <= 7200) {
502+
socket->keepalive = secs;
503+
return NSAPI_ERROR_OK;
504+
}
505+
}
506+
return NSAPI_ERROR_PARAMETER;
507+
}
508+
}
509+
}
510+
511+
return NSAPI_ERROR_UNSUPPORTED;
512+
}
513+
514+
nsapi_error_t ESP8266Interface::getsockopt(nsapi_socket_t handle, int level, int optname, void *optval, unsigned *optlen)
515+
{
516+
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
517+
518+
if (!optval || !optlen || !socket) {
519+
return NSAPI_ERROR_PARAMETER;
520+
}
521+
522+
if (level == NSAPI_SOCKET && socket->proto == NSAPI_TCP) {
523+
switch (optname) {
524+
case NSAPI_KEEPALIVE: {
525+
if(*optlen > sizeof(int)) {
526+
*optlen = sizeof(int);
527+
}
528+
memcpy(optval, &(socket->keepalive), *optlen);
529+
return NSAPI_ERROR_OK;
530+
}
531+
}
532+
}
533+
534+
return NSAPI_ERROR_UNSUPPORTED;
535+
}
536+
537+
475538
void ESP8266Interface::event() {
476539
for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) {
477540
if (_cbs[i].callback) {

ESP8266Interface.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,40 @@ class ESP8266Interface : public NetworkStack, public WiFiInterface
147147
*/
148148
using NetworkInterface::add_dns_server;
149149

150+
/* Set socket options
151+
*
152+
* The setsockopt allow an application to pass stack-specific hints
153+
* to the underlying stack. For unsupported options,
154+
* NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified.
155+
*
156+
* @param handle Socket handle
157+
* @param level Stack-specific protocol level
158+
* @param optname Stack-specific option identifier
159+
* @param optval Option value
160+
* @param optlen Length of the option value
161+
* @return 0 on success, negative error code on failure
162+
*/
163+
virtual nsapi_error_t setsockopt(nsapi_socket_t handle, int level,
164+
int optname, const void *optval, unsigned optlen);
165+
166+
/* Get socket options
167+
*
168+
* getsockopt allows an application to retrieve stack-specific options
169+
* from the underlying stack using stack-specific level and option names,
170+
* or to request generic options using levels from nsapi_socket_level_t.
171+
*
172+
* For unsupported options, NSAPI_ERROR_UNSUPPORTED is returned
173+
* and the socket is unmodified.
174+
*
175+
* @param level Stack-specific protocol level or nsapi_socket_level_t
176+
* @param optname Level-specific option name
177+
* @param optval Destination for option value
178+
* @param optlen Length of the option value
179+
* @return 0 on success, negative error code on failure
180+
*/
181+
virtual nsapi_error_t getsockopt(nsapi_socket_t handle, int level, int optname,
182+
void *optval, unsigned *optlen);
183+
150184
protected:
151185
/** Open a socket
152186
* @param handle Handle in which to store new socket

0 commit comments

Comments
 (0)