diff --git a/components/wifi/esp8266-driver/ESP8266/ESP8266.cpp b/components/wifi/esp8266-driver/ESP8266/ESP8266.cpp index de7693d9cd..07c50c0ed2 100644 --- a/components/wifi/esp8266-driver/ESP8266/ESP8266.cpp +++ b/components/wifi/esp8266-driver/ESP8266/ESP8266.cpp @@ -373,6 +373,17 @@ bool ESP8266::disconnect(void) return done; } +bool ESP8266::ip_info_print(int enable) +{ + _smutex.lock(); + _disconnect = true; + bool done = _parser.send("AT+CIPDINFO=%d", enable) && _parser.recv("OK\n"); + _smutex.unlock(); + + return done; +} + + const char *ESP8266::ip_addr(void) { _smutex.lock(); @@ -508,11 +519,13 @@ int ESP8266::scan(WiFiAccessPoint *res, unsigned limit, scan_mode mode, unsigned return cnt; } -nsapi_error_t ESP8266::open_udp(int id, const char *addr, int port, int local_port) +nsapi_error_t ESP8266::open_udp(int id, const char *addr, int port, int local_port, int udp_mode) { static const char *type = "UDP"; bool done = false; + ip_info_print(1); + _smutex.lock(); // process OOB so that _sock_i reflects the correct state of the socket @@ -533,7 +546,7 @@ nsapi_error_t ESP8266::open_udp(int id, const char *addr, int port, int local_po for (int i = 0; i < 2; i++) { if (local_port) { - done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d,%d", id, type, addr, port, local_port); + done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d,%d,%d", id, type, addr, port, local_port, udp_mode); } else { done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d", id, type, addr, port); } @@ -572,6 +585,8 @@ nsapi_error_t ESP8266::open_tcp(int id, const char *addr, int port, int keepaliv static const char *type = "TCP"; bool done = false; + ip_info_print(1); + if (!addr) { return NSAPI_ERROR_PARAMETER; } @@ -754,6 +769,7 @@ END: void ESP8266::_oob_packet_hdlr() { int id; + int port; int amount; int pdu_len; @@ -763,6 +779,8 @@ void ESP8266::_oob_packet_hdlr() } if (_tcp_passive && _sock_i[id].open == true && _sock_i[id].proto == NSAPI_TCP) { + //For TCP +IPD return only id and amount and it is independent on AT+CIPDINFO settings + //Unfortunately no information about that in ESP manual but it has sense. if (_parser.recv("%d\n", &amount)) { _sock_i[id].tcp_data_avbl = amount; @@ -772,8 +790,12 @@ void ESP8266::_oob_packet_hdlr() } } return; - } else if (!_parser.scanf("%d:", &amount)) { - return; + } else { + if (!(_parser.scanf("%d,", &amount) + && _parser.scanf("%15[^,],", _ip_buffer) + && _parser.scanf("%d:", &port))) { + return; + } } pdu_len = sizeof(struct packet) + amount; @@ -791,6 +813,10 @@ void ESP8266::_oob_packet_hdlr() _heap_usage += pdu_len; packet->id = id; + if (_sock_i[id].proto == NSAPI_UDP) { + packet->remote_port = port; + memcpy(packet->remote_ip, _ip_buffer, 16); + } packet->len = amount; packet->alloc_len = amount; packet->next = 0; @@ -943,7 +969,7 @@ int32_t ESP8266::recv_tcp(int id, void *data, uint32_t amount, uint32_t timeout) return NSAPI_ERROR_WOULD_BLOCK; } -int32_t ESP8266::recv_udp(int id, void *data, uint32_t amount, uint32_t timeout) +int32_t ESP8266::recv_udp(struct esp8266_socket *socket, void *data, uint32_t amount, uint32_t timeout) { _smutex.lock(); set_timeout(timeout); @@ -956,9 +982,12 @@ int32_t ESP8266::recv_udp(int id, void *data, uint32_t amount, uint32_t timeout) // check if any packets are ready for us for (struct packet **p = &_packets; *p; p = &(*p)->next) { - if ((*p)->id == id) { + if ((*p)->id == socket->id) { struct packet *q = *p; + socket->addr.set_ip_address((*p)->remote_ip); + socket->addr.set_port((*p)->remote_port); + // Return and remove packet (truncated if necessary) uint32_t len = q->len < amount ? q->len : amount; memcpy(data, q + 1, len); diff --git a/components/wifi/esp8266-driver/ESP8266/ESP8266.h b/components/wifi/esp8266-driver/ESP8266/ESP8266.h index f0b108ec95..5123e83938 100644 --- a/components/wifi/esp8266-driver/ESP8266/ESP8266.h +++ b/components/wifi/esp8266-driver/ESP8266/ESP8266.h @@ -29,6 +29,7 @@ #include "platform/mbed_error.h" #include "rtos/Mutex.h" #include "rtos/ThisThread.h" +#include "features/netsocket/SocketAddress.h" // Various timeouts for different ESP8266 operations #ifndef ESP8266_CONNECT_TIMEOUT @@ -64,6 +65,15 @@ #define FW_AT_LEAST_VERSION(MAJOR,MINOR,PATCH,NUSED/*Not used*/,REF) \ (((MAJOR)*1000000+(MINOR)*10000+(PATCH)*100) >= REF ? true : false) +struct esp8266_socket { + int id; + nsapi_protocol_t proto; + bool connected; + bool bound; + SocketAddress addr; + int keepalive; // TCP +}; + /** ESP8266Interface class. This is an interface to a ESP8266 radio. */ @@ -167,6 +177,14 @@ public: */ bool disconnect(void); + /** + * Enable or disable Remote IP and Port printing with +IPD + * + * @param enable, 1 on, 0 off + * @return true only if ESP8266 is disconnected successfully + */ + bool ip_info_print(int enable); + /** * Get the IP address of ESP8266 * @@ -236,9 +254,10 @@ public: * @param addr the IP address of the destination * @param port the port on the destination * @param local_port UDP socket's local port, zero means any + * @param udp_mode UDP socket's mode, zero means can't change remote, 1 can change once, 2 can change multiple times * @return NSAPI_ERROR_OK in success, negative error code in failure */ - nsapi_error_t open_udp(int id, const char *addr, int port, int local_port = 0); + nsapi_error_t open_udp(int id, const char *addr, int port, int local_port = 0, int udp_mode = 0); /** * Open a socketed connection @@ -271,7 +290,7 @@ public: * @param amount number of bytes to be received * @return the number of bytes received */ - int32_t recv_udp(int id, void *data, uint32_t amount, uint32_t timeout = ESP8266_RECV_TIMEOUT); + int32_t recv_udp(struct esp8266_socket *socket, void *data, uint32_t amount, uint32_t timeout = ESP8266_RECV_TIMEOUT); /** * Receives stream data from an open TCP socket @@ -442,6 +461,8 @@ private: struct packet { struct packet *next; int id; + char remote_ip[16]; + int remote_port; uint32_t len; // Remaining length uint32_t alloc_len; // Original length // data follows diff --git a/components/wifi/esp8266-driver/ESP8266Interface.cpp b/components/wifi/esp8266-driver/ESP8266Interface.cpp index 275ceb2bc7..ce31c41a39 100644 --- a/components/wifi/esp8266-driver/ESP8266Interface.cpp +++ b/components/wifi/esp8266-driver/ESP8266Interface.cpp @@ -54,6 +54,8 @@ #define ESP8266_WIFI_IF_NAME "es0" +#define LOCAL_ADDR "127.0.0.1" + using namespace mbed; using namespace rtos; @@ -750,14 +752,6 @@ nsapi_error_t ESP8266Interface::_reset() return _esp.at_available() ? NSAPI_ERROR_OK : NSAPI_ERROR_DEVICE_ERROR; } -struct esp8266_socket { - int id; - nsapi_protocol_t proto; - bool connected; - SocketAddress addr; - int keepalive; // TCP -}; - int ESP8266Interface::socket_open(void **handle, nsapi_protocol_t proto) { // Look for an unused socket @@ -783,6 +777,7 @@ int ESP8266Interface::socket_open(void **handle, nsapi_protocol_t proto) socket->id = id; socket->proto = proto; socket->connected = false; + socket->bound = false; socket->keepalive = 0; *handle = socket; return 0; @@ -801,11 +796,16 @@ int ESP8266Interface::socket_close(void *handle) err = NSAPI_ERROR_DEVICE_ERROR; } + if (socket->bound && !_esp.close(socket->id)) { + err = NSAPI_ERROR_DEVICE_ERROR; + } + _cbs[socket->id].callback = NULL; _cbs[socket->id].data = NULL; core_util_atomic_store_u8(&_cbs[socket->id].deferred, false); socket->connected = false; + socket->bound = false; _sock_i[socket->id].open = false; _sock_i[socket->id].sport = 0; delete socket; @@ -828,12 +828,17 @@ int ESP8266Interface::socket_bind(void *handle, const SocketAddress &address) for (int id = 0; id < ESP8266_SOCKET_COUNT; id++) { if (_sock_i[id].sport == address.get_port() && id != socket->id) { // Port already reserved by another socket return NSAPI_ERROR_PARAMETER; - } else if (id == socket->id && socket->connected) { + } else if (id == socket->id && (socket->connected || socket->bound)) { return NSAPI_ERROR_PARAMETER; } } _sock_i[socket->id].sport = address.get_port(); - return 0; + + int ret = _esp.open_udp(socket->id, LOCAL_ADDR, address.get_port(), _sock_i[socket->id].sport, 2); + + socket->bound = (ret == NSAPI_ERROR_OK) ? true : false; + + return ret; } return NSAPI_ERROR_UNSUPPORTED; @@ -854,7 +859,7 @@ int ESP8266Interface::socket_connect(void *handle, const SocketAddress &addr) } if (socket->proto == NSAPI_UDP) { - ret = _esp.open_udp(socket->id, addr.get_ip_address(), addr.get_port(), _sock_i[socket->id].sport); + ret = _esp.open_udp(socket->id, addr.get_ip_address(), addr.get_port(), _sock_i[socket->id].sport, 0); } else { ret = _esp.open_tcp(socket->id, addr.get_ip_address(), addr.get_port(), socket->keepalive); } @@ -925,7 +930,7 @@ int ESP8266Interface::socket_recv(void *handle, void *data, unsigned size) socket->connected = false; } } else { - recv = _esp.recv_udp(socket->id, data, size); + recv = _esp.recv_udp(socket, data, size); } return recv; @@ -950,7 +955,7 @@ int ESP8266Interface::socket_sendto(void *handle, const SocketAddress &addr, con socket->connected = false; } - if (!socket->connected) { + if (!socket->connected && !socket->bound) { int err = socket_connect(socket, addr); if (err < 0) { return err; @@ -958,6 +963,10 @@ int ESP8266Interface::socket_sendto(void *handle, const SocketAddress &addr, con socket->addr = addr; } + if (socket->bound) { + socket->addr = addr; + } + return socket_send(socket, data, size); }