Skip to content

AT firmware >= 1.7.0 - treat data as OOB #109

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 87 additions & 50 deletions ESP8266/ESP8266.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,23 @@
* limitations under the License.
*/

#include <string.h>
#include <stdint.h>

#include "ESP8266.h"
#include "Callback.h"
#include "mbed_error.h"
#include "nsapi_types.h"
#include "features/netsocket/nsapi_types.h"
#include "mbed_trace.h"
#include "PinNames.h"
#include "platform/Callback.h"
#include "platform/mbed_error.h"

#include <cstring>
#define TRACE_GROUP "ESPA" // ESP8266 AT layer

#define ESP8266_DEFAULT_BAUD_RATE 115200
#define ESP8266_ALL_SOCKET_IDS -1

using namespace mbed;

ESP8266::ESP8266(PinName tx, PinName rx, bool debug, PinName rts, PinName cts)
: _sdk_v(-1, -1, -1),
_at_v(-1, -1, -1),
Expand Down Expand Up @@ -67,10 +73,15 @@ ESP8266::ESP8266(PinName tx, PinName rx, bool debug, PinName rts, PinName cts)
//https://github.com/esp8266/Arduino/blob/4897e0006b5b0123a2fa31f67b14a3fff65ce561/doc/faq/a02-my-esp-crashes.md#watchdog
_parser.oob("Soft WDT reset", callback(this, &ESP8266::_oob_watchdog_reset));
_parser.oob("busy ", callback(this, &ESP8266::_oob_busy));
// NOTE: documentation v3.0 says '+CIPRECVDATA:<data_len>,' but it's not how the FW responds...
_parser.oob("+CIPRECVDATA,", callback(this, &ESP8266::_oob_tcp_data_hdlr));

for (int i = 0; i < SOCKET_COUNT; i++) {
_sock_i[i].open = false;
_sock_i[i].proto = NSAPI_UDP;
_sock_i[i].tcp_data = NULL;
_sock_i[i].tcp_data_avbl = 0;
_sock_i[i].tcp_data_rcvd = 0;
}
}

Expand Down Expand Up @@ -442,6 +453,10 @@ nsapi_error_t ESP8266::open_udp(int id, const char *addr, int port, int local_po

_smutex.unlock();

if (done) {
tr_debug("UDP socket %d opened", id);
}

return done ? NSAPI_ERROR_OK : NSAPI_ERROR_DEVICE_ERROR;
}

Expand Down Expand Up @@ -488,6 +503,10 @@ nsapi_error_t ESP8266::open_tcp(int id, const char *addr, int port, int keepaliv

_smutex.unlock();

if (done) {
tr_debug("TCP socket %d opened", id);
}

return done ? NSAPI_ERROR_OK : NSAPI_ERROR_DEVICE_ERROR;
}

Expand Down Expand Up @@ -538,32 +557,26 @@ void ESP8266::_oob_packet_hdlr()
if (!_parser.recv(",%d,", &id)) {
return;
}
// In passive mode amount not used...
if (_tcp_passive
&& _sock_i[id].open == true
&& _sock_i[id].proto == NSAPI_TCP) {
if (!_parser.recv("%d\n", &amount)) {
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENODATA), \
"ESP8266::_packet_handler(): Data length missing");

if(_tcp_passive && _sock_i[id].open == true && _sock_i[id].proto == NSAPI_TCP) {
if (_parser.recv("%d\n", &amount)) {
_sock_i[id].tcp_data_avbl = amount; // Not used but stored for the sake of visibility
}
return;
// Amount required in active mode
} else if (!_parser.recv("%d:", &amount)) {
return;
}

pdu_len = sizeof(struct packet) + amount;

if ((_heap_usage + pdu_len) > MBED_CONF_ESP8266_SOCKET_BUFSIZE) {
MBED_WARNING(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENOBUFS), \
"ESP8266::_packet_handler(): \"esp8266.socket-bufsize\"-limit exceeded, packet dropped");
tr_debug("\"esp8266.socket-bufsize\"-limit exceeded, packet dropped");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why these have been changed from MBED_WARNING to tr_debug()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on @kjbracey-arm's comment about usage of MBED_WARNING.

return;
}

struct packet *packet = (struct packet *)malloc(pdu_len);
if (!packet) {
MBED_WARNING(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENOMEM), \
"ESP8266::_packet_handler(): Could not allocate memory for RX data");
tr_debug("out of memory, unable to allocate memory for packet");
return;
}
_heap_usage += pdu_len;
Expand Down Expand Up @@ -602,15 +615,13 @@ void ESP8266::bg_process_oob(uint32_t timeout, bool all)

int32_t ESP8266::_recv_tcp_passive(int id, void *data, uint32_t amount, uint32_t timeout)
{
int32_t len;
int32_t ret = (int32_t)NSAPI_ERROR_WOULD_BLOCK;
int32_t ret;

_smutex.lock();

// No flow control, drain the USART receive register ASAP to avoid data overrun
if (_serial_rts == NC) {
_process_oob(timeout, true);
}
_sock_i[id].tcp_data = (char*)data;
_sock_i[id].tcp_data_rcvd = NSAPI_ERROR_WOULD_BLOCK;
_sock_active_id = id;

// +CIPRECVDATA supports up to 2048 bytes at a time
if (amount > 2048) {
Expand All @@ -619,29 +630,18 @@ int32_t ESP8266::_recv_tcp_passive(int id, void *data, uint32_t amount, uint32_t

// NOTE: documentation v3.0 says '+CIPRECVDATA:<data_len>,' but it's not how the FW responds...
bool done = _parser.send("AT+CIPRECVDATA=%d,%lu", id, amount)
&& _parser.recv("+CIPRECVDATA,%ld:", &len)
&& _parser.read((char *)data, len)
&& _parser.recv("OK\n");

if (done) {
_smutex.unlock();
return len;
}
(void)done;
_sock_i[id].tcp_data = NULL;
_sock_active_id = -1;

// Socket closed, doesn't mean there couldn't be data left
if (!_sock_i[id].open) {
done = _parser.send("AT+CIPRECVDATA=%d,%lu", id, amount)
&& _parser.recv("+CIPRECVDATA,%ld:", &len)
&& _parser.read((char *)data, len)
&& _parser.recv("OK\n");
ret = _sock_i[id].tcp_data_rcvd;

ret = done ? len : 0;
if (!_sock_i[id].open && ret == NSAPI_ERROR_WOULD_BLOCK) {
ret = 0;
}

// Flow control, read from USART receive register only when no more data is buffered, and as little as possible
if (_serial_rts != NC) {
_process_oob(timeout, false);
}
_smutex.unlock();
return ret;
}
Expand Down Expand Up @@ -768,6 +768,13 @@ void ESP8266::_clear_socket_packets(int id)
p = &(*p)->next;
}
}
if (id == ESP8266_ALL_SOCKET_IDS) {
for (int id = 0; id < 5; id++) {
_sock_i[id].tcp_data_avbl = 0;
}
} else {
_sock_i[id].tcp_data_avbl = 0;
}
}

bool ESP8266::close(int id)
Expand Down Expand Up @@ -856,18 +863,37 @@ void ESP8266::_oob_busy()
{
char status[5];
if (_parser.recv("%4[^\"]\n", status)) {
if (strcmp(status, " s...\n") == 0) {
; //TODO maybe do something here, or not...
} else if (strcmp(status, "p...\n") == 0) {
; //TODO maybe do something here, or not...
if (strcmp(status, "s...") == 0) {
tr_debug("busy s...");
} else if (strcmp(status, "p...") == 0) {
tr_debug("busy p...");
} else {
tr_error("unrecognized busy state \'%s\'", status);
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_EBADMSG), \
"ESP8266::_oob_busy: unrecognized busy state\n");
"ESP8266::_oob_busy() unrecognized busy state\n");
}
} else {
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENOMSG), \
"ESP8266::_oob_busy: AT timeout\n");
"ESP8266::_oob_busy() AT timeout\n");
}
_busy = true;
}

void ESP8266::_oob_tcp_data_hdlr()
{
int32_t len;

MBED_ASSERT(_sock_active_id >= 0 && _sock_active_id < 5);

if (!_parser.recv("%ld:", &len)) {
return;
}

if (!_parser.read(_sock_i[_sock_active_id].tcp_data, len)) {
return;
}

_sock_i[_sock_active_id].tcp_data_rcvd = len;
}

void ESP8266::_oob_connect_err()
Expand Down Expand Up @@ -904,27 +930,37 @@ void ESP8266::_oob_socket_close_err()

void ESP8266::_oob_socket0_closed()
{
_sock_i[0].open = false;
static const int id = 0;
_sock_i[id].open = false;
tr_debug("socket %d closed", id);
}

void ESP8266::_oob_socket1_closed()
{
_sock_i[1].open = false;
static const int id = 1;
_sock_i[id].open = false;
tr_debug("socket %d closed", id);
}

void ESP8266::_oob_socket2_closed()
{
_sock_i[2].open = false;
static const int id = 2;
_sock_i[id].open = false;
tr_debug("socket %d closed", id);
}

void ESP8266::_oob_socket3_closed()
{
_sock_i[3].open = false;
static const int id = 3;
_sock_i[id].open = false;
tr_debug("socket %d closed", id);
}

void ESP8266::_oob_socket4_closed()
{
_sock_i[4].open = false;
static const int id = 4;
_sock_i[id].open = false;
tr_debug("socket %d closed", id);
}

void ESP8266::_oob_connection_status()
Expand All @@ -938,6 +974,7 @@ void ESP8266::_oob_connection_status()
} else if (strcmp(status, "CONNECTED\n") == 0) {
_conn_status = NSAPI_STATUS_CONNECTING;
} else {
tr_error("invalid AT cmd \'%s\'", status);
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_EBADMSG), \
"ESP8266::_oob_connection_status: invalid AT cmd\n");
}
Expand Down
31 changes: 21 additions & 10 deletions ESP8266/ESP8266.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,16 @@
#ifndef ESP8266_H
#define ESP8266_H

#include "ATCmdParser.h"
#include "Mutex.h"
#include "nsapi_types.h"
#include "rtos.h"
#include <stdint.h>

#include "drivers/UARTSerial.h"
#include "features/netsocket/nsapi_types.h"
#include "features/netsocket/WiFiAccessPoint.h"
#include "PinNames.h"
#include "platform/ATCmdParser.h"
#include "platform/Callback.h"
#include "platform/mbed_error.h"
#include "rtos/Mutex.h"

// Various timeouts for different ESP8266 operations
#ifndef ESP8266_CONNECT_TIMEOUT
Expand Down Expand Up @@ -281,7 +286,7 @@ class ESP8266 {
*
* @param func A pointer to a void function, or 0 to set as none
*/
void sigio(Callback<void()> func);
void sigio(mbed::Callback<void()> func);

/**
* Attach a function to call whenever sigio happens in the serial
Expand All @@ -292,7 +297,7 @@ class ESP8266 {
template <typename T, typename M>
void sigio(T *obj, M method)
{
sigio(Callback<void()>(obj, method));
sigio(mbed::Callback<void()>(obj, method));
}

/**
Expand Down Expand Up @@ -368,13 +373,13 @@ class ESP8266 {
int32_t _recv_tcp_passive(int id, void *data, uint32_t amount, uint32_t timeout);

// UART settings
UARTSerial _serial;
mbed::UARTSerial _serial;
PinName _serial_rts;
PinName _serial_cts;
Mutex _smutex; // Protect serial port access
rtos::Mutex _smutex; // Protect serial port access

// AT Command Parser
ATCmdParser _parser;
mbed::ATCmdParser _parser;

// Wifi scan result handling
bool _recv_ap(nsapi_wifi_ap_t *ap);
Expand All @@ -388,6 +393,7 @@ class ESP8266 {
// data follows
} *_packets, * *_packets_end;
void _clear_socket_packets(int id);
int _sock_active_id;

// Memory statistics
size_t _heap_usage; // (Socket data buffer usage)
Expand All @@ -409,13 +415,15 @@ class ESP8266 {
void _oob_socket_close_err();
void _oob_watchdog_reset();
void _oob_busy();
void _oob_tcp_data_hdlr();

// OOB state variables
int _connect_error;
bool _fail;
bool _sock_already;
bool _closed;
bool _error;
bool _busy;

// Modem's address info
char _ip_buffer[16];
Expand All @@ -427,12 +435,15 @@ class ESP8266 {
struct _sock_info {
bool open;
nsapi_protocol_t proto;
char *tcp_data;
int32_t tcp_data_avbl; // Data waiting on modem
int32_t tcp_data_rcvd;
};
struct _sock_info _sock_i[SOCKET_COUNT];

// Connection state reporting
nsapi_connection_status_t _conn_status;
Callback<void()> _conn_stat_cb; // ESP8266Interface registered
mbed::Callback<void()> _conn_stat_cb; // ESP8266Interface registered
};

#endif
Loading