mirror of https://github.com/ARMmbed/mbed-os.git
Add ESP8266 driver v1.6
parent
b5240db10d
commit
fc5bf5986b
|
@ -0,0 +1,670 @@
|
|||
/* ESP8266 Example
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ESP8266.h"
|
||||
#include "mbed_debug.h"
|
||||
#include "nsapi_types.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#define ESP8266_DEFAULT_BAUD_RATE 115200
|
||||
#define ESP8266_ALL_SOCKET_IDS -1
|
||||
|
||||
ESP8266::ESP8266(PinName tx, PinName rx, bool debug)
|
||||
: _serial(tx, rx, ESP8266_DEFAULT_BAUD_RATE),
|
||||
_parser(&_serial),
|
||||
_packets(0),
|
||||
_packets_end(&_packets),
|
||||
_connect_error(0),
|
||||
_fail(false),
|
||||
_closed(false),
|
||||
_socket_open(),
|
||||
_connection_status(NSAPI_STATUS_DISCONNECTED)
|
||||
{
|
||||
_serial.set_baud( ESP8266_DEFAULT_BAUD_RATE );
|
||||
_parser.debug_on(debug);
|
||||
_parser.set_delimiter("\r\n");
|
||||
_parser.oob("+IPD", callback(this, &ESP8266::_packet_handler));
|
||||
//Note: espressif at command document says that this should be +CWJAP_CUR:<error code>
|
||||
//but seems that at least current version is not sending it
|
||||
//https://www.espressif.com/sites/default/files/documentation/4a-esp8266_at_instruction_set_en.pdf
|
||||
//Also seems that ERROR is not sent, but FAIL instead
|
||||
_parser.oob("+CWJAP:", callback(this, &ESP8266::_connect_error_handler));
|
||||
_parser.oob("0,CLOSED", callback(this, &ESP8266::_oob_socket0_closed_handler));
|
||||
_parser.oob("1,CLOSED", callback(this, &ESP8266::_oob_socket1_closed_handler));
|
||||
_parser.oob("2,CLOSED", callback(this, &ESP8266::_oob_socket2_closed_handler));
|
||||
_parser.oob("3,CLOSED", callback(this, &ESP8266::_oob_socket3_closed_handler));
|
||||
_parser.oob("4,CLOSED", callback(this, &ESP8266::_oob_socket4_closed_handler));
|
||||
_parser.oob("WIFI ", callback(this, &ESP8266::_connection_status_handler));
|
||||
_parser.oob("UNLINK", callback(this, &ESP8266::_oob_socket_close_error));
|
||||
}
|
||||
|
||||
int ESP8266::get_firmware_version()
|
||||
{
|
||||
int version;
|
||||
|
||||
_smutex.lock();
|
||||
bool done = _parser.send("AT+GMR")
|
||||
&& _parser.recv("SDK version:%d", &version)
|
||||
&& _parser.recv("OK\n");
|
||||
_smutex.unlock();
|
||||
|
||||
if(done) {
|
||||
return version;
|
||||
} else {
|
||||
// Older firmware versions do not prefix the version with "SDK version: "
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool ESP8266::startup(int mode)
|
||||
{
|
||||
if (!(mode == WIFIMODE_STATION || mode == WIFIMODE_SOFTAP
|
||||
|| mode == WIFIMODE_STATION_SOFTAP)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_smutex.lock();
|
||||
setTimeout(ESP8266_CONNECT_TIMEOUT);
|
||||
bool done = _parser.send("AT+CWMODE_CUR=%d", mode)
|
||||
&& _parser.recv("OK\n")
|
||||
&&_parser.send("AT+CIPMUX=1")
|
||||
&& _parser.recv("OK\n");
|
||||
setTimeout(); //Restore default
|
||||
_smutex.unlock();
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
bool ESP8266::reset(void)
|
||||
{
|
||||
_smutex.lock();
|
||||
setTimeout(ESP8266_CONNECT_TIMEOUT);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (_parser.send("AT+RST")
|
||||
&& _parser.recv("OK\n")
|
||||
&& _parser.recv("ready")) {
|
||||
_clear_socket_packets(ESP8266_ALL_SOCKET_IDS);
|
||||
_smutex.unlock();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
setTimeout();
|
||||
_smutex.unlock();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ESP8266::dhcp(bool enabled, int mode)
|
||||
{
|
||||
//only 3 valid modes
|
||||
if (mode < 0 || mode > 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_smutex.lock();
|
||||
bool done = _parser.send("AT+CWDHCP_CUR=%d,%d", mode, enabled?1:0)
|
||||
&& _parser.recv("OK\n");
|
||||
_smutex.unlock();
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
nsapi_error_t ESP8266::connect(const char *ap, const char *passPhrase)
|
||||
{
|
||||
_smutex.lock();
|
||||
setTimeout(ESP8266_CONNECT_TIMEOUT);
|
||||
_connection_status = NSAPI_STATUS_CONNECTING;
|
||||
if(_connection_status_cb)
|
||||
_connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connection_status);
|
||||
|
||||
_parser.send("AT+CWJAP_CUR=\"%s\",\"%s\"", ap, passPhrase);
|
||||
if (!_parser.recv("OK\n")) {
|
||||
if (_fail) {
|
||||
_smutex.unlock();
|
||||
nsapi_error_t ret;
|
||||
if (_connect_error == 1)
|
||||
ret = NSAPI_ERROR_CONNECTION_TIMEOUT;
|
||||
else if (_connect_error == 2)
|
||||
ret = NSAPI_ERROR_AUTH_FAILURE;
|
||||
else if (_connect_error == 3)
|
||||
ret = NSAPI_ERROR_NO_SSID;
|
||||
else
|
||||
ret = NSAPI_ERROR_NO_CONNECTION;
|
||||
|
||||
_fail = false;
|
||||
_connect_error = 0;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
setTimeout();
|
||||
_smutex.unlock();
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
bool ESP8266::disconnect(void)
|
||||
{
|
||||
_smutex.lock();
|
||||
bool done = _parser.send("AT+CWQAP") && _parser.recv("OK\n");
|
||||
_smutex.unlock();
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
const char *ESP8266::getIPAddress(void)
|
||||
{
|
||||
_smutex.lock();
|
||||
setTimeout(ESP8266_CONNECT_TIMEOUT);
|
||||
if (!(_parser.send("AT+CIFSR")
|
||||
&& _parser.recv("+CIFSR:STAIP,\"%15[^\"]\"", _ip_buffer)
|
||||
&& _parser.recv("OK\n"))) {
|
||||
_smutex.unlock();
|
||||
return 0;
|
||||
}
|
||||
setTimeout();
|
||||
_smutex.unlock();
|
||||
|
||||
return _ip_buffer;
|
||||
}
|
||||
|
||||
const char *ESP8266::getMACAddress(void)
|
||||
{
|
||||
_smutex.lock();
|
||||
if (!(_parser.send("AT+CIFSR")
|
||||
&& _parser.recv("+CIFSR:STAMAC,\"%17[^\"]\"", _mac_buffer)
|
||||
&& _parser.recv("OK\n"))) {
|
||||
_smutex.unlock();
|
||||
return 0;
|
||||
}
|
||||
_smutex.unlock();
|
||||
|
||||
return _mac_buffer;
|
||||
}
|
||||
|
||||
const char *ESP8266::getGateway()
|
||||
{
|
||||
_smutex.lock();
|
||||
if (!(_parser.send("AT+CIPSTA_CUR?")
|
||||
&& _parser.recv("+CIPSTA_CUR:gateway:\"%15[^\"]\"", _gateway_buffer)
|
||||
&& _parser.recv("OK\n"))) {
|
||||
_smutex.unlock();
|
||||
return 0;
|
||||
}
|
||||
_smutex.unlock();
|
||||
|
||||
return _gateway_buffer;
|
||||
}
|
||||
|
||||
const char *ESP8266::getNetmask()
|
||||
{
|
||||
_smutex.lock();
|
||||
if (!(_parser.send("AT+CIPSTA_CUR?")
|
||||
&& _parser.recv("+CIPSTA_CUR:netmask:\"%15[^\"]\"", _netmask_buffer)
|
||||
&& _parser.recv("OK\n"))) {
|
||||
_smutex.unlock();
|
||||
return 0;
|
||||
}
|
||||
_smutex.unlock();
|
||||
|
||||
return _netmask_buffer;
|
||||
}
|
||||
|
||||
int8_t ESP8266::getRSSI()
|
||||
{
|
||||
int8_t rssi;
|
||||
char bssid[18];
|
||||
|
||||
_smutex.lock();
|
||||
setTimeout(ESP8266_CONNECT_TIMEOUT);
|
||||
if (!(_parser.send("AT+CWJAP_CUR?")
|
||||
&& _parser.recv("+CWJAP_CUR:\"%*[^\"]\",\"%17[^\"]\"", bssid)
|
||||
&& _parser.recv("OK\n"))) {
|
||||
_smutex.unlock();
|
||||
return 0;
|
||||
}
|
||||
setTimeout();
|
||||
_smutex.unlock();
|
||||
|
||||
_smutex.lock();
|
||||
setTimeout(ESP8266_CONNECT_TIMEOUT);
|
||||
if (!(_parser.send("AT+CWLAP=\"\",\"%s\",", bssid)
|
||||
&& _parser.recv("+CWLAP:(%*d,\"%*[^\"]\",%hhd,", &rssi)
|
||||
&& _parser.recv("OK\n"))) {
|
||||
_smutex.unlock();
|
||||
return 0;
|
||||
}
|
||||
setTimeout();
|
||||
_smutex.unlock();
|
||||
|
||||
return rssi;
|
||||
}
|
||||
|
||||
int ESP8266::scan(WiFiAccessPoint *res, unsigned limit)
|
||||
{
|
||||
unsigned cnt = 0;
|
||||
nsapi_wifi_ap_t ap;
|
||||
|
||||
_smutex.lock();
|
||||
setTimeout(ESP8266_CONNECT_TIMEOUT);
|
||||
|
||||
if (!_parser.send("AT+CWLAP")) {
|
||||
_smutex.unlock();
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
while (recv_ap(&ap)) {
|
||||
if (cnt < limit) {
|
||||
res[cnt] = WiFiAccessPoint(ap);
|
||||
}
|
||||
|
||||
cnt++;
|
||||
if (limit != 0 && cnt >= limit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
setTimeout();
|
||||
_smutex.unlock();
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
nsapi_error_t ESP8266::open_udp(int id, const char* addr, int port, int local_port)
|
||||
{
|
||||
static const char *type = "UDP";
|
||||
bool done = false;
|
||||
|
||||
if (id >= SOCKET_COUNT) {
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
} else if (_socket_open[id]) {
|
||||
return NSAPI_ERROR_IS_CONNECTED;
|
||||
}
|
||||
|
||||
_smutex.lock();
|
||||
if(local_port) {
|
||||
done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d,%d", id, type, addr, port, local_port)
|
||||
&& _parser.recv("OK\n");
|
||||
} else {
|
||||
done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d", id, type, addr, port)
|
||||
&& _parser.recv("OK\n");
|
||||
}
|
||||
|
||||
if (done) {
|
||||
_socket_open[id] = 1;
|
||||
}
|
||||
|
||||
_clear_socket_packets(id);
|
||||
|
||||
_smutex.unlock();
|
||||
|
||||
return done ? NSAPI_ERROR_OK : NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
bool ESP8266::open_tcp(int id, const char* addr, int port, int keepalive)
|
||||
{
|
||||
static const char *type = "TCP";
|
||||
bool done = false;
|
||||
|
||||
if (id >= SOCKET_COUNT || _socket_open[id]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_smutex.lock();
|
||||
if(keepalive) {
|
||||
done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d,%d", id, type, addr, port, keepalive)
|
||||
&& _parser.recv("OK\n");
|
||||
} else {
|
||||
done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d", id, type, addr, port)
|
||||
&& _parser.recv("OK\n");
|
||||
}
|
||||
|
||||
if (done) {
|
||||
_socket_open[id] = 1;
|
||||
}
|
||||
|
||||
_clear_socket_packets(id);
|
||||
|
||||
_smutex.unlock();
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
bool ESP8266::dns_lookup(const char* name, char* ip)
|
||||
{
|
||||
_smutex.lock();
|
||||
bool done = _parser.send("AT+CIPDOMAIN=\"%s\"", name) && _parser.recv("+CIPDOMAIN:%s%*[\r]%*[\n]", ip);
|
||||
_smutex.unlock();
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
nsapi_error_t ESP8266::send(int id, const void *data, uint32_t amount)
|
||||
{
|
||||
//May take a second try if device is busy
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
_smutex.lock();
|
||||
setTimeout(ESP8266_SEND_TIMEOUT);
|
||||
if (_parser.send("AT+CIPSEND=%d,%lu", id, amount)
|
||||
&& _parser.recv(">")
|
||||
&& _parser.write((char*)data, (int)amount) >= 0) {
|
||||
while (_parser.process_oob()); // multiple sends in a row require this
|
||||
_smutex.unlock();
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
setTimeout();
|
||||
_smutex.unlock();
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
void ESP8266::_packet_handler()
|
||||
{
|
||||
int id;
|
||||
int amount;
|
||||
|
||||
// parse out the packet
|
||||
if (!_parser.recv(",%d,%d:", &id, &amount)) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct packet *packet = (struct packet*)malloc(
|
||||
sizeof(struct packet) + amount);
|
||||
if (!packet) {
|
||||
debug("ESP8266: could not allocate memory for RX data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
packet->id = id;
|
||||
packet->len = amount;
|
||||
packet->next = 0;
|
||||
|
||||
if (_parser.read((char*)(packet + 1), amount) < amount) {
|
||||
free(packet);
|
||||
return;
|
||||
}
|
||||
|
||||
// append to packet list
|
||||
*_packets_end = packet;
|
||||
_packets_end = &packet->next;
|
||||
}
|
||||
|
||||
int32_t ESP8266::recv_tcp(int id, void *data, uint32_t amount, uint32_t timeout)
|
||||
{
|
||||
_smutex.lock();
|
||||
setTimeout(timeout);
|
||||
|
||||
// Poll for inbound packets
|
||||
while (_parser.process_oob()) {
|
||||
}
|
||||
|
||||
setTimeout();
|
||||
|
||||
// check if any packets are ready for us
|
||||
for (struct packet **p = &_packets; *p; p = &(*p)->next) {
|
||||
if ((*p)->id == id) {
|
||||
struct packet *q = *p;
|
||||
|
||||
if (q->len <= amount) { // Return and remove full packet
|
||||
memcpy(data, q+1, q->len);
|
||||
|
||||
if (_packets_end == &(*p)->next) {
|
||||
_packets_end = p;
|
||||
}
|
||||
*p = (*p)->next;
|
||||
_smutex.unlock();
|
||||
|
||||
uint32_t len = q->len;
|
||||
free(q);
|
||||
return len;
|
||||
} else { // return only partial packet
|
||||
memcpy(data, q+1, amount);
|
||||
|
||||
q->len -= amount;
|
||||
memmove(q+1, (uint8_t*)(q+1) + amount, q->len);
|
||||
|
||||
_smutex.unlock();
|
||||
return amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!_socket_open[id]) {
|
||||
_smutex.unlock();
|
||||
return 0;
|
||||
}
|
||||
_smutex.unlock();
|
||||
|
||||
return NSAPI_ERROR_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
int32_t ESP8266::recv_udp(int id, void *data, uint32_t amount, uint32_t timeout)
|
||||
{
|
||||
_smutex.lock();
|
||||
setTimeout(timeout);
|
||||
|
||||
// Poll for inbound packets
|
||||
while (_parser.process_oob()) {
|
||||
}
|
||||
|
||||
setTimeout();
|
||||
|
||||
// check if any packets are ready for us
|
||||
for (struct packet **p = &_packets; *p; p = &(*p)->next) {
|
||||
if ((*p)->id == id) {
|
||||
struct packet *q = *p;
|
||||
|
||||
// Return and remove packet (truncated if necessary)
|
||||
uint32_t len = q->len < amount ? q->len : amount;
|
||||
memcpy(data, q+1, len);
|
||||
|
||||
if (_packets_end == &(*p)->next) {
|
||||
_packets_end = p;
|
||||
}
|
||||
*p = (*p)->next;
|
||||
_smutex.unlock();
|
||||
|
||||
free(q);
|
||||
return len;
|
||||
}
|
||||
}
|
||||
_smutex.unlock();
|
||||
|
||||
return NSAPI_ERROR_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
void ESP8266::_clear_socket_packets(int id)
|
||||
{
|
||||
struct packet **p = &_packets;
|
||||
|
||||
while (*p) {
|
||||
if ((*p)->id == id || id == ESP8266_ALL_SOCKET_IDS) {
|
||||
struct packet *q = *p;
|
||||
|
||||
if (_packets_end == &(*p)->next) {
|
||||
_packets_end = p; // Set last packet next field/_packets
|
||||
}
|
||||
*p = (*p)->next;
|
||||
|
||||
free(q);
|
||||
} else {
|
||||
// Point to last packet next field
|
||||
p = &(*p)->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ESP8266::close(int id)
|
||||
{
|
||||
//May take a second try if device is busy
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
_smutex.lock();
|
||||
if (_parser.send("AT+CIPCLOSE=%d", id)) {
|
||||
if (!_parser.recv("OK\n")) {
|
||||
if (_closed) { // UNLINK ERROR
|
||||
_closed = false;
|
||||
_socket_open[id] = 0;
|
||||
_clear_socket_packets(id);
|
||||
_smutex.unlock();
|
||||
// ESP8266 has a habit that it might close a socket on its own.
|
||||
//debug("ESP8266: socket %d already closed when calling close\n", id);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
_clear_socket_packets(id);
|
||||
_smutex.unlock();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_smutex.unlock();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ESP8266::setTimeout(uint32_t timeout_ms)
|
||||
{
|
||||
_parser.set_timeout(timeout_ms);
|
||||
}
|
||||
|
||||
bool ESP8266::readable()
|
||||
{
|
||||
return _serial.FileHandle::readable();
|
||||
}
|
||||
|
||||
bool ESP8266::writeable()
|
||||
{
|
||||
return _serial.FileHandle::writable();
|
||||
}
|
||||
|
||||
void ESP8266::sigio(Callback<void()> func)
|
||||
{
|
||||
_serial.sigio(func);
|
||||
}
|
||||
|
||||
void ESP8266::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
|
||||
{
|
||||
_connection_status_cb = status_cb;
|
||||
}
|
||||
|
||||
bool ESP8266::recv_ap(nsapi_wifi_ap_t *ap)
|
||||
{
|
||||
int sec;
|
||||
int dummy;
|
||||
bool ret = _parser.recv("+CWLAP:(%d,\"%32[^\"]\",%hhd,\"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\",%hhu,%d,%d)\n",
|
||||
&sec,
|
||||
ap->ssid,
|
||||
&ap->rssi,
|
||||
&ap->bssid[0], &ap->bssid[1], &ap->bssid[2], &ap->bssid[3], &ap->bssid[4], &ap->bssid[5],
|
||||
&ap->channel,
|
||||
&dummy,
|
||||
&dummy);
|
||||
|
||||
ap->security = sec < 5 ? (nsapi_security_t)sec : NSAPI_SECURITY_UNKNOWN;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ESP8266::_connect_error_handler()
|
||||
{
|
||||
_fail = false;
|
||||
_connect_error = 0;
|
||||
|
||||
if (_parser.recv("%d", &_connect_error) && _parser.recv("FAIL")) {
|
||||
_fail = true;
|
||||
_parser.abort();
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266::_oob_socket_close_error()
|
||||
{
|
||||
if (_parser.recv("ERROR\n")) {
|
||||
_closed = true; // Not possible to pinpoint to a certain socket
|
||||
_parser.abort();
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266::_oob_socket0_closed_handler()
|
||||
{
|
||||
_socket_open[0] = 0;
|
||||
}
|
||||
|
||||
void ESP8266::_oob_socket1_closed_handler()
|
||||
{
|
||||
_socket_open[1] = 0;
|
||||
}
|
||||
|
||||
void ESP8266::_oob_socket2_closed_handler()
|
||||
{
|
||||
_socket_open[2] = 0;
|
||||
}
|
||||
|
||||
void ESP8266::_oob_socket3_closed_handler()
|
||||
{
|
||||
_socket_open[3] = 0;
|
||||
}
|
||||
|
||||
void ESP8266::_oob_socket4_closed_handler()
|
||||
{
|
||||
_socket_open[4] = 0;
|
||||
}
|
||||
|
||||
void ESP8266::_connection_status_handler()
|
||||
{
|
||||
char status[13];
|
||||
if (_parser.recv("%12[^\"]\n", status)) {
|
||||
if (strcmp(status, "GOT IP\n") == 0)
|
||||
_connection_status = NSAPI_STATUS_GLOBAL_UP;
|
||||
else if (strcmp(status, "DISCONNECT\n") == 0)
|
||||
_connection_status = NSAPI_STATUS_DISCONNECTED;
|
||||
else
|
||||
return;
|
||||
|
||||
if(_connection_status_cb)
|
||||
_connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connection_status);
|
||||
}
|
||||
}
|
||||
|
||||
int8_t ESP8266::get_default_wifi_mode()
|
||||
{
|
||||
int8_t mode;
|
||||
|
||||
_smutex.lock();
|
||||
if (_parser.send("AT+CWMODE_DEF?")
|
||||
&& _parser.recv("+CWMODE_DEF:%hhd", &mode)
|
||||
&& _parser.recv("OK\n")) {
|
||||
_smutex.unlock();
|
||||
return mode;
|
||||
}
|
||||
_smutex.unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ESP8266::set_default_wifi_mode(const int8_t mode)
|
||||
{
|
||||
_smutex.lock();
|
||||
bool done = _parser.send("AT+CWMODE_DEF=%hhd", mode)
|
||||
&& _parser.recv("OK\n");
|
||||
_smutex.unlock();
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
nsapi_connection_status_t ESP8266::get_connection_status() const
|
||||
{
|
||||
return _connection_status;
|
||||
}
|
|
@ -0,0 +1,309 @@
|
|||
/* ESP8266Interface Example
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ESP8266_H
|
||||
#define ESP8266_H
|
||||
|
||||
#include "ATCmdParser.h"
|
||||
#include "nsapi_types.h"
|
||||
#include "rtos.h"
|
||||
|
||||
// Various timeouts for different ESP8266 operations
|
||||
#ifndef ESP8266_CONNECT_TIMEOUT
|
||||
#define ESP8266_CONNECT_TIMEOUT 15000
|
||||
#endif
|
||||
#ifndef ESP8266_SEND_TIMEOUT
|
||||
#define ESP8266_SEND_TIMEOUT 2000
|
||||
#endif
|
||||
#ifndef ESP8266_RECV_TIMEOUT
|
||||
#define ESP8266_RECV_TIMEOUT 2000
|
||||
#endif
|
||||
#ifndef ESP8266_MISC_TIMEOUT
|
||||
#define ESP8266_MISC_TIMEOUT 2000
|
||||
#endif
|
||||
|
||||
/** ESP8266Interface class.
|
||||
This is an interface to a ESP8266 radio.
|
||||
*/
|
||||
class ESP8266
|
||||
{
|
||||
public:
|
||||
ESP8266(PinName tx, PinName rx, bool debug=false);
|
||||
|
||||
/**
|
||||
* Check firmware version of ESP8266
|
||||
*
|
||||
* @return integer firmware version or -1 if firmware query command gives outdated response
|
||||
*/
|
||||
int get_firmware_version(void);
|
||||
|
||||
/**
|
||||
* Startup the ESP8266
|
||||
*
|
||||
* @param mode mode of WIFI 1-client, 2-host, 3-both
|
||||
* @return true only if ESP8266 was setup correctly
|
||||
*/
|
||||
bool startup(int mode);
|
||||
|
||||
/**
|
||||
* Reset ESP8266
|
||||
*
|
||||
* @return true only if ESP8266 resets successfully
|
||||
*/
|
||||
bool reset(void);
|
||||
|
||||
/**
|
||||
* Enable/Disable DHCP
|
||||
*
|
||||
* @param enabled DHCP enabled when true
|
||||
* @param mode mode of DHCP 0-softAP, 1-station, 2-both
|
||||
* @return true only if ESP8266 enables/disables DHCP successfully
|
||||
*/
|
||||
bool dhcp(bool enabled, int mode);
|
||||
|
||||
/**
|
||||
* Connect ESP8266 to AP
|
||||
*
|
||||
* @param ap the name of the AP
|
||||
* @param passPhrase the password of AP
|
||||
* @return NSAPI_ERROR_OK only if ESP8266 is connected successfully
|
||||
*/
|
||||
nsapi_error_t connect(const char *ap, const char *passPhrase);
|
||||
|
||||
/**
|
||||
* Disconnect ESP8266 from AP
|
||||
*
|
||||
* @return true only if ESP8266 is disconnected successfully
|
||||
*/
|
||||
bool disconnect(void);
|
||||
|
||||
/**
|
||||
* Get the IP address of ESP8266
|
||||
*
|
||||
* @return null-teriminated IP address or null if no IP address is assigned
|
||||
*/
|
||||
const char *getIPAddress(void);
|
||||
|
||||
/**
|
||||
* Get the MAC address of ESP8266
|
||||
*
|
||||
* @return null-terminated MAC address or null if no MAC address is assigned
|
||||
*/
|
||||
const char *getMACAddress(void);
|
||||
|
||||
/** Get the local gateway
|
||||
*
|
||||
* @return Null-terminated representation of the local gateway
|
||||
* or null if no network mask has been recieved
|
||||
*/
|
||||
const char *getGateway();
|
||||
|
||||
/** Get the local network mask
|
||||
*
|
||||
* @return Null-terminated representation of the local network mask
|
||||
* or null if no network mask has been recieved
|
||||
*/
|
||||
const char *getNetmask();
|
||||
|
||||
/* Return RSSI for active connection
|
||||
*
|
||||
* @return Measured RSSI
|
||||
*/
|
||||
int8_t getRSSI();
|
||||
|
||||
/** Scan for available networks
|
||||
*
|
||||
* @param ap Pointer to allocated array to store discovered AP
|
||||
* @param limit Size of allocated @a res array, or 0 to only count available AP
|
||||
* @return Number of entries in @a res, or if @a count was 0 number of available networks, negative on error
|
||||
* see @a nsapi_error
|
||||
*/
|
||||
int scan(WiFiAccessPoint *res, unsigned limit);
|
||||
|
||||
/**Perform a dns query
|
||||
*
|
||||
* @param name Hostname to resolve
|
||||
* @param ip Buffer to store IP address
|
||||
* @return 0 true on success, false on failure
|
||||
*/
|
||||
bool dns_lookup(const char *name, char *ip);
|
||||
|
||||
/**
|
||||
* Open a socketed connection
|
||||
*
|
||||
* @param type the type of socket to open "UDP" or "TCP"
|
||||
* @param id id to give the new socket, valid 0-4
|
||||
* @param port port to open connection with
|
||||
* @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
|
||||
* @return true only if socket opened successfully
|
||||
*/
|
||||
nsapi_error_t open_udp(int id, const char* addr, int port, int local_port = 0);
|
||||
|
||||
/**
|
||||
* Open a socketed connection
|
||||
*
|
||||
* @param type the type of socket to open "UDP" or "TCP"
|
||||
* @param id id to give the new socket, valid 0-4
|
||||
* @param port port to open connection with
|
||||
* @param addr the IP address of the destination
|
||||
* @param port the port on the destination
|
||||
* @param tcp_keepalive TCP connection's keep alive time, zero means disabled
|
||||
* @return true only if socket opened successfully
|
||||
*/
|
||||
bool open_tcp(int id, const char* addr, int port, int keepalive = 0);
|
||||
|
||||
/**
|
||||
* Sends data to an open socket
|
||||
*
|
||||
* @param id id of socket to send to
|
||||
* @param data data to be sent
|
||||
* @param amount amount of data to be sent - max 1024
|
||||
* @return NSAPI_ERROR_OK in success, negative error code in failure
|
||||
*/
|
||||
nsapi_error_t send(int id, const void *data, uint32_t amount);
|
||||
|
||||
/**
|
||||
* Receives datagram from an open UDP socket
|
||||
*
|
||||
* @param id id to receive from
|
||||
* @param data placeholder for returned information
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* Receives stream data from an open TCP socket
|
||||
*
|
||||
* @param id id to receive from
|
||||
* @param data placeholder for returned information
|
||||
* @param amount number of bytes to be received
|
||||
* @return the number of bytes received
|
||||
*/
|
||||
int32_t recv_tcp(int id, void *data, uint32_t amount, uint32_t timeout=ESP8266_RECV_TIMEOUT);
|
||||
|
||||
/**
|
||||
* Closes a socket
|
||||
*
|
||||
* @param id id of socket to close, valid only 0-4
|
||||
* @return true only if socket is closed successfully
|
||||
*/
|
||||
bool close(int id);
|
||||
|
||||
/**
|
||||
* Allows timeout to be changed between commands
|
||||
*
|
||||
* @param timeout_ms timeout of the connection
|
||||
*/
|
||||
void setTimeout(uint32_t timeout_ms=ESP8266_MISC_TIMEOUT);
|
||||
|
||||
/**
|
||||
* Checks if data is available
|
||||
*/
|
||||
bool readable();
|
||||
|
||||
/**
|
||||
* Checks if data can be written
|
||||
*/
|
||||
bool writeable();
|
||||
|
||||
/**
|
||||
* Attach a function to call whenever sigio happens in the serial
|
||||
*
|
||||
* @param func A pointer to a void function, or 0 to set as none
|
||||
*/
|
||||
void sigio(Callback<void()> func);
|
||||
|
||||
/**
|
||||
* Attach a function to call whenever sigio happens in the serial
|
||||
*
|
||||
* @param obj pointer to the object to call the member function on
|
||||
* @param method pointer to the member function to call
|
||||
*/
|
||||
template <typename T, typename M>
|
||||
void sigio(T *obj, M method) {
|
||||
sigio(Callback<void()>(obj, method));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a function to call whenever network state has changed
|
||||
*
|
||||
* @param func A pointer to a void function, or 0 to set as none
|
||||
*/
|
||||
void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
|
||||
|
||||
/**
|
||||
* Read default Wifi mode from flash
|
||||
*
|
||||
* return Station, SoftAP or SoftAP+Station - 0 on failure
|
||||
*/
|
||||
int8_t get_default_wifi_mode();
|
||||
|
||||
/**
|
||||
* Write default Wifi mode to flash
|
||||
*/
|
||||
bool set_default_wifi_mode(const int8_t mode);
|
||||
|
||||
/** Get the connection status
|
||||
*
|
||||
* @return The connection status according to ConnectionStatusType
|
||||
*/
|
||||
nsapi_connection_status_t get_connection_status() const;
|
||||
|
||||
static const int8_t WIFIMODE_STATION = 1;
|
||||
static const int8_t WIFIMODE_SOFTAP = 2;
|
||||
static const int8_t WIFIMODE_STATION_SOFTAP = 3;
|
||||
static const int8_t SOCKET_COUNT = 5;
|
||||
|
||||
private:
|
||||
UARTSerial _serial;
|
||||
ATCmdParser _parser;
|
||||
Mutex _smutex; // Protect serial port access
|
||||
|
||||
struct packet {
|
||||
struct packet *next;
|
||||
int id;
|
||||
uint32_t len;
|
||||
// data follows
|
||||
} *_packets, **_packets_end;
|
||||
void _packet_handler();
|
||||
void _connect_error_handler();
|
||||
bool recv_ap(nsapi_wifi_ap_t *ap);
|
||||
void _oob_socket0_closed_handler();
|
||||
void _oob_socket1_closed_handler();
|
||||
void _oob_socket2_closed_handler();
|
||||
void _oob_socket3_closed_handler();
|
||||
void _oob_socket4_closed_handler();
|
||||
void _connection_status_handler();
|
||||
void _oob_socket_close_error();
|
||||
void _clear_socket_packets(int id);
|
||||
|
||||
char _ip_buffer[16];
|
||||
char _gateway_buffer[16];
|
||||
char _netmask_buffer[16];
|
||||
char _mac_buffer[18];
|
||||
|
||||
int _connect_error;
|
||||
bool _fail;
|
||||
bool _closed;
|
||||
int _socket_open[SOCKET_COUNT];
|
||||
nsapi_connection_status_t _connection_status;
|
||||
Callback<void(nsapi_event_t, intptr_t)> _connection_status_cb;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,586 @@
|
|||
/* ESP8266 implementation of NetworkInterfaceAPI
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include "ESP8266.h"
|
||||
#include "ESP8266Interface.h"
|
||||
#include "mbed_debug.h"
|
||||
#include "nsapi_types.h"
|
||||
|
||||
|
||||
#ifndef MBED_CONF_ESP8266_TX
|
||||
#ifdef TARGET_FF_ARDUINO
|
||||
#define MBED_CONF_ESP8266_TX D1
|
||||
#else
|
||||
#define MBED_CONF_ESP8266_TX NC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MBED_CONF_ESP8266_RX
|
||||
#ifdef TARGET_FF_ARDUINO
|
||||
#define MBED_CONF_ESP8266_RX D0
|
||||
#else
|
||||
#define MBED_CONF_ESP8266_RX NC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Firmware version
|
||||
#define ESP8266_VERSION 2
|
||||
|
||||
ESP8266Interface::ESP8266Interface()
|
||||
: _esp(MBED_CONF_ESP8266_TX, MBED_CONF_ESP8266_RX, MBED_CONF_ESP8266_DEBUG),
|
||||
_initialized(false),
|
||||
_started(false)
|
||||
{
|
||||
memset(_ids, 0, sizeof(_ids));
|
||||
memset(_cbs, 0, sizeof(_cbs));
|
||||
memset(ap_ssid, 0, sizeof(ap_ssid));
|
||||
memset(ap_pass, 0, sizeof(ap_pass));
|
||||
memset(_local_ports, 0, sizeof(_local_ports));
|
||||
ap_sec = NSAPI_SECURITY_UNKNOWN;
|
||||
|
||||
_esp.sigio(this, &ESP8266Interface::event);
|
||||
_esp.setTimeout();
|
||||
}
|
||||
|
||||
// ESP8266Interface implementation
|
||||
ESP8266Interface::ESP8266Interface(PinName tx, PinName rx, bool debug)
|
||||
: _esp(tx, rx, debug),
|
||||
_initialized(false),
|
||||
_started(false)
|
||||
{
|
||||
memset(_ids, 0, sizeof(_ids));
|
||||
memset(_cbs, 0, sizeof(_cbs));
|
||||
memset(ap_ssid, 0, sizeof(ap_ssid));
|
||||
memset(ap_pass, 0, sizeof(ap_pass));
|
||||
memset(_local_ports, 0, sizeof(_local_ports));
|
||||
ap_sec = NSAPI_SECURITY_UNKNOWN;
|
||||
|
||||
_esp.sigio(this, &ESP8266Interface::event);
|
||||
_esp.setTimeout();
|
||||
}
|
||||
|
||||
int ESP8266Interface::connect(const char *ssid, const char *pass, nsapi_security_t security,
|
||||
uint8_t channel)
|
||||
{
|
||||
if (channel != 0) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int err = set_credentials(ssid, pass, security);
|
||||
if(err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return connect();
|
||||
}
|
||||
|
||||
int ESP8266Interface::connect()
|
||||
{
|
||||
nsapi_error_t status;
|
||||
|
||||
if (strlen(ap_ssid) == 0) {
|
||||
return NSAPI_ERROR_NO_SSID;
|
||||
}
|
||||
|
||||
if (ap_sec != NSAPI_SECURITY_NONE) {
|
||||
if (strlen(ap_pass) < ESP8266_PASSPHRASE_MIN_LENGTH) {
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
status = _init();
|
||||
if(status != NSAPI_ERROR_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if(get_ip_address()) {
|
||||
return NSAPI_ERROR_IS_CONNECTED;
|
||||
}
|
||||
|
||||
status = _startup(ESP8266::WIFIMODE_STATION);
|
||||
if(status != NSAPI_ERROR_OK) {
|
||||
return status;
|
||||
}
|
||||
_started = true;
|
||||
|
||||
if (!_esp.dhcp(true, 1)) {
|
||||
return NSAPI_ERROR_DHCP_FAILURE;
|
||||
}
|
||||
|
||||
int connect_error = _esp.connect(ap_ssid, ap_pass);
|
||||
if (connect_error) {
|
||||
return connect_error;
|
||||
}
|
||||
|
||||
if (!get_ip_address()) {
|
||||
return NSAPI_ERROR_DHCP_FAILURE;
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
int ESP8266Interface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security)
|
||||
{
|
||||
ap_sec = security;
|
||||
|
||||
if (!ssid) {
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
int ssid_length = strlen(ssid);
|
||||
|
||||
if (ssid_length > 0
|
||||
&& ssid_length <= ESP8266_SSID_MAX_LENGTH) {
|
||||
memset(ap_ssid, 0, sizeof(ap_ssid));
|
||||
strncpy(ap_ssid, ssid, sizeof(ap_ssid));
|
||||
} else {
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
if (ap_sec != NSAPI_SECURITY_NONE) {
|
||||
|
||||
if (!pass) {
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
int pass_length = strlen(pass);
|
||||
if (pass_length >= ESP8266_PASSPHRASE_MIN_LENGTH
|
||||
&& pass_length <= ESP8266_PASSPHRASE_MAX_LENGTH ) {
|
||||
memset(ap_pass, 0, sizeof(ap_pass));
|
||||
strncpy(ap_pass, pass, sizeof(ap_pass));
|
||||
} else {
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
} else {
|
||||
memset(ap_pass, 0, sizeof(ap_pass));
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
int ESP8266Interface::set_channel(uint8_t channel)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
int ESP8266Interface::disconnect()
|
||||
{
|
||||
_started = false;
|
||||
_initialized = false;
|
||||
|
||||
return _esp.disconnect() ? NSAPI_ERROR_OK : NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
const char *ESP8266Interface::get_ip_address()
|
||||
{
|
||||
if(!_started) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *ip_buff = _esp.getIPAddress();
|
||||
if(!ip_buff || std::strcmp(ip_buff, "0.0.0.0") == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ip_buff;
|
||||
}
|
||||
|
||||
const char *ESP8266Interface::get_mac_address()
|
||||
{
|
||||
return _esp.getMACAddress();
|
||||
}
|
||||
|
||||
const char *ESP8266Interface::get_gateway()
|
||||
{
|
||||
return _started ? _esp.getGateway() : NULL;
|
||||
}
|
||||
|
||||
const char *ESP8266Interface::get_netmask()
|
||||
{
|
||||
return _started ? _esp.getNetmask() : NULL;
|
||||
}
|
||||
|
||||
int8_t ESP8266Interface::get_rssi()
|
||||
{
|
||||
return _started ? _esp.getRSSI() : 0;
|
||||
}
|
||||
|
||||
int ESP8266Interface::scan(WiFiAccessPoint *res, unsigned count)
|
||||
{
|
||||
nsapi_error_t status;
|
||||
|
||||
status = _init();
|
||||
if(status != NSAPI_ERROR_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = _startup(ESP8266::WIFIMODE_STATION);
|
||||
if(status != NSAPI_ERROR_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return _esp.scan(res, count);
|
||||
}
|
||||
|
||||
bool ESP8266Interface::_get_firmware_ok()
|
||||
{
|
||||
if (_esp.get_firmware_version() != ESP8266_VERSION) {
|
||||
debug("ESP8266: ERROR: Firmware incompatible with this driver.\
|
||||
\r\nUpdate to v%d - https://developer.mbed.org/teams/ESP8266/wiki/Firmware-Update\r\n",ESP8266_VERSION);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ESP8266Interface::_disable_default_softap()
|
||||
{
|
||||
static int disabled = false;
|
||||
|
||||
if (disabled || _esp.get_default_wifi_mode() == ESP8266::WIFIMODE_STATION) {
|
||||
disabled = true;
|
||||
return true;
|
||||
}
|
||||
if (_esp.set_default_wifi_mode(ESP8266::WIFIMODE_STATION)) {
|
||||
disabled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nsapi_error_t ESP8266Interface::_init(void)
|
||||
{
|
||||
if (!_initialized) {
|
||||
if (!_esp.reset()) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
if (!_get_firmware_ok()) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
if (_disable_default_softap() == false) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
_initialized = true;
|
||||
}
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t ESP8266Interface::_startup(const int8_t wifi_mode)
|
||||
{
|
||||
if (!_started) {
|
||||
if (!_esp.startup(wifi_mode)) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
}
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
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
|
||||
int id = -1;
|
||||
|
||||
for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) {
|
||||
if (!_ids[i]) {
|
||||
id = i;
|
||||
_ids[i] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (id == -1) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
struct esp8266_socket *socket = new struct esp8266_socket;
|
||||
if (!socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
socket->id = id;
|
||||
socket->proto = proto;
|
||||
socket->connected = false;
|
||||
socket->keepalive = 0;
|
||||
*handle = socket;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_close(void *handle)
|
||||
{
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
int err = 0;
|
||||
|
||||
if (!socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
if (socket->connected && !_esp.close(socket->id)) {
|
||||
err = NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
socket->connected = false;
|
||||
_ids[socket->id] = false;
|
||||
_local_ports[socket->id] = 0;
|
||||
delete socket;
|
||||
return err;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_bind(void *handle, const SocketAddress &address)
|
||||
{
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
|
||||
if (!socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
if (socket->proto == NSAPI_UDP) {
|
||||
if(address.get_addr().version != NSAPI_UNSPEC) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
for(int id = 0; id < ESP8266_SOCKET_COUNT; id++) {
|
||||
if(_local_ports[id] == address.get_port() && id != socket->id) { // Port already reserved by another socket
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
} else if (id == socket->id && socket->connected) {
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
}
|
||||
_local_ports[socket->id] = address.get_port();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_listen(void *handle, int backlog)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_connect(void *handle, const SocketAddress &addr)
|
||||
{
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
nsapi_error_t ret;
|
||||
|
||||
if (!socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
if (socket->proto == NSAPI_UDP) {
|
||||
ret = _esp.open_udp(socket->id, addr.get_ip_address(), addr.get_port(), _local_ports[socket->id]);
|
||||
if (ret != NSAPI_ERROR_OK) {
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
if (!_esp.open_tcp(socket->id, addr.get_ip_address(), addr.get_port(), socket->keepalive)) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
socket->connected = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_accept(void *server, void **socket, SocketAddress *addr)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_send(void *handle, const void *data, unsigned size)
|
||||
{
|
||||
nsapi_error_t status;
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
|
||||
if (!socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
status = _esp.send(socket->id, data, size);
|
||||
|
||||
return status != NSAPI_ERROR_OK ? status : size;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_recv(void *handle, void *data, unsigned size)
|
||||
{
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
|
||||
if (!socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
int32_t recv;
|
||||
if (socket->proto == NSAPI_TCP) {
|
||||
recv = _esp.recv_tcp(socket->id, data, size);
|
||||
if (recv <= 0 && recv != NSAPI_ERROR_WOULD_BLOCK) {
|
||||
socket->connected = false;
|
||||
}
|
||||
} else {
|
||||
recv = _esp.recv_udp(socket->id, data, size);
|
||||
}
|
||||
|
||||
return recv;
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size)
|
||||
{
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
|
||||
if (!socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
if((strcmp(addr.get_ip_address(), "0.0.0.0") == 0) || !addr.get_port()) {
|
||||
return NSAPI_ERROR_DNS_FAILURE;
|
||||
}
|
||||
|
||||
if (socket->connected && socket->addr != addr) {
|
||||
if (!_esp.close(socket->id)) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
socket->connected = false;
|
||||
}
|
||||
|
||||
if (!socket->connected) {
|
||||
int err = socket_connect(socket, addr);
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
socket->addr = addr;
|
||||
}
|
||||
|
||||
return socket_send(socket, data, size);
|
||||
}
|
||||
|
||||
int ESP8266Interface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size)
|
||||
{
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
|
||||
if (!socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
int ret = socket_recv(socket, data, size);
|
||||
if (ret >= 0 && addr) {
|
||||
*addr = socket->addr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ESP8266Interface::socket_attach(void *handle, void (*callback)(void *), void *data)
|
||||
{
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
_cbs[socket->id].callback = callback;
|
||||
_cbs[socket->id].data = data;
|
||||
}
|
||||
|
||||
nsapi_error_t ESP8266Interface::setsockopt(nsapi_socket_t handle, int level,
|
||||
int optname, const void *optval, unsigned optlen)
|
||||
{
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
|
||||
if (!optlen) {
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
} else if (!socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
if (level == NSAPI_SOCKET && socket->proto == NSAPI_TCP) {
|
||||
switch (optname) {
|
||||
case NSAPI_KEEPALIVE: {
|
||||
if(socket->connected) {// ESP8266 limitation, keepalive needs to be given before connecting
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (optlen == sizeof(int)) {
|
||||
int secs = *(int *)optval;
|
||||
if (secs >= 0 && secs <= 7200) {
|
||||
socket->keepalive = secs;
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
}
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
nsapi_error_t ESP8266Interface::getsockopt(nsapi_socket_t handle, int level, int optname, void *optval, unsigned *optlen)
|
||||
{
|
||||
struct esp8266_socket *socket = (struct esp8266_socket *)handle;
|
||||
|
||||
if (!optval || !optlen) {
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
} else if (!socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
|
||||
if (level == NSAPI_SOCKET && socket->proto == NSAPI_TCP) {
|
||||
switch (optname) {
|
||||
case NSAPI_KEEPALIVE: {
|
||||
if(*optlen > sizeof(int)) {
|
||||
*optlen = sizeof(int);
|
||||
}
|
||||
memcpy(optval, &(socket->keepalive), *optlen);
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
void ESP8266Interface::event()
|
||||
{
|
||||
for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) {
|
||||
if (_cbs[i].callback) {
|
||||
_cbs[i].callback(_cbs[i].data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266Interface::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
|
||||
{
|
||||
_esp.attach(status_cb);
|
||||
}
|
||||
|
||||
nsapi_connection_status_t ESP8266Interface::get_connection_status() const
|
||||
{
|
||||
return _esp.get_connection_status();
|
||||
}
|
||||
|
||||
#if MBED_CONF_ESP8266_PROVIDE_DEFAULT
|
||||
|
||||
WiFiInterface *WiFiInterface::get_default_instance() {
|
||||
static ESP8266Interface esp();
|
||||
return &esp;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,346 @@
|
|||
/* ESP8266 implementation of NetworkInterfaceAPI
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ESP8266_INTERFACE_H
|
||||
#define ESP8266_INTERFACE_H
|
||||
|
||||
#include "mbed.h"
|
||||
#include "ESP8266.h"
|
||||
|
||||
|
||||
#define ESP8266_SOCKET_COUNT 5
|
||||
|
||||
/** ESP8266Interface class
|
||||
* Implementation of the NetworkStack for the ESP8266
|
||||
*/
|
||||
class ESP8266Interface : public NetworkStack, public WiFiInterface
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief ESP8266Interface default constructor
|
||||
* Will use values defined in mbed_lib.json
|
||||
*/
|
||||
ESP8266Interface();
|
||||
|
||||
/** ESP8266Interface lifetime
|
||||
* @param tx TX pin
|
||||
* @param rx RX pin
|
||||
* @param debug Enable debugging
|
||||
*/
|
||||
ESP8266Interface(PinName tx, PinName rx, bool debug = false);
|
||||
|
||||
/** Start the interface
|
||||
*
|
||||
* Attempts to connect to a WiFi network. Requires ssid and passphrase to be set.
|
||||
* If passphrase is invalid, NSAPI_ERROR_AUTH_ERROR is returned.
|
||||
*
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual int connect();
|
||||
|
||||
/** Start the interface
|
||||
*
|
||||
* Attempts to connect to a WiFi network.
|
||||
*
|
||||
* @param ssid Name of the network to connect to
|
||||
* @param pass Security passphrase to connect to the network
|
||||
* @param security Type of encryption for connection (Default: NSAPI_SECURITY_NONE)
|
||||
* @param channel This parameter is not supported, setting it to anything else than 0 will result in NSAPI_ERROR_UNSUPPORTED
|
||||
* @return 0 on success, or error code on failure
|
||||
*/
|
||||
virtual int connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE,
|
||||
uint8_t channel = 0);
|
||||
|
||||
/** Set the WiFi network credentials
|
||||
*
|
||||
* @param ssid Name of the network to connect to
|
||||
* @param pass Security passphrase to connect to the network
|
||||
* @param security Type of encryption for connection
|
||||
* (defaults to NSAPI_SECURITY_NONE)
|
||||
* @return 0 on success, or error code on failure
|
||||
*/
|
||||
virtual int set_credentials(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE);
|
||||
|
||||
/** Set the WiFi network channel - NOT SUPPORTED
|
||||
*
|
||||
* This function is not supported and will return NSAPI_ERROR_UNSUPPORTED
|
||||
*
|
||||
* @param channel Channel on which the connection is to be made, or 0 for any (Default: 0)
|
||||
* @return Not supported, returns NSAPI_ERROR_UNSUPPORTED
|
||||
*/
|
||||
virtual int set_channel(uint8_t channel);
|
||||
|
||||
/** Stop the interface
|
||||
* @return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int disconnect();
|
||||
|
||||
/** Get the internally stored IP address
|
||||
* @return IP address of the interface or null if not yet connected
|
||||
*/
|
||||
virtual const char *get_ip_address();
|
||||
|
||||
/** Get the internally stored MAC address
|
||||
* @return MAC address of the interface
|
||||
*/
|
||||
virtual const char *get_mac_address();
|
||||
|
||||
/** Get the local gateway
|
||||
*
|
||||
* @return Null-terminated representation of the local gateway
|
||||
* or null if no network mask has been recieved
|
||||
*/
|
||||
virtual const char *get_gateway();
|
||||
|
||||
/** Get the local network mask
|
||||
*
|
||||
* @return Null-terminated representation of the local network mask
|
||||
* or null if no network mask has been recieved
|
||||
*/
|
||||
virtual const char *get_netmask();
|
||||
|
||||
/** Gets the current radio signal strength for active connection
|
||||
*
|
||||
* @return Connection strength in dBm (negative value)
|
||||
*/
|
||||
virtual int8_t get_rssi();
|
||||
|
||||
/** Scan for available networks
|
||||
*
|
||||
* This function will block.
|
||||
*
|
||||
* @param ap Pointer to allocated array to store discovered AP
|
||||
* @param count Size of allocated @a res array, or 0 to only count available AP
|
||||
* @param timeout Timeout in milliseconds; 0 for no timeout (Default: 0)
|
||||
* @return Number of entries in @a, or if @a count was 0 number of available networks, negative on error
|
||||
* see @a nsapi_error
|
||||
*/
|
||||
virtual int scan(WiFiAccessPoint *res, unsigned count);
|
||||
|
||||
/** Translates a hostname to an IP address with specific version
|
||||
*
|
||||
* The hostname may be either a domain name or an IP address. If the
|
||||
* hostname is an IP address, no network transactions will be performed.
|
||||
*
|
||||
* If no stack-specific DNS resolution is provided, the hostname
|
||||
* will be resolve using a UDP socket on the stack.
|
||||
*
|
||||
* @param address Destination for the host SocketAddress
|
||||
* @param host Hostname to resolve
|
||||
* @param version IP version of address to resolve, NSAPI_UNSPEC indicates
|
||||
* version is chosen by the stack (defaults to NSAPI_UNSPEC)
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
using NetworkInterface::gethostbyname;
|
||||
|
||||
/** Add a domain name server to list of servers to query
|
||||
*
|
||||
* @param addr Destination for the host address
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
using NetworkInterface::add_dns_server;
|
||||
|
||||
/** Set socket options
|
||||
*
|
||||
* The setsockopt allow an application to pass stack-specific hints
|
||||
* to the underlying stack. For unsupported options,
|
||||
* NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified.
|
||||
*
|
||||
* @param handle Socket handle
|
||||
* @param level Stack-specific protocol level
|
||||
* @param optname Stack-specific option identifier
|
||||
* @param optval Option value
|
||||
* @param optlen Length of the option value
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual nsapi_error_t setsockopt(nsapi_socket_t handle, int level,
|
||||
int optname, const void *optval, unsigned optlen);
|
||||
|
||||
/** Get socket options
|
||||
*
|
||||
* getsockopt allows an application to retrieve stack-specific options
|
||||
* from the underlying stack using stack-specific level and option names,
|
||||
* or to request generic options using levels from nsapi_socket_level_t.
|
||||
*
|
||||
* For unsupported options, NSAPI_ERROR_UNSUPPORTED is returned
|
||||
* and the socket is unmodified.
|
||||
*
|
||||
* @param level Stack-specific protocol level or nsapi_socket_level_t
|
||||
* @param optname Level-specific option name
|
||||
* @param optval Destination for option value
|
||||
* @param optlen Length of the option value
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual nsapi_error_t getsockopt(nsapi_socket_t handle, int level, int optname,
|
||||
void *optval, unsigned *optlen);
|
||||
|
||||
/** Register callback for status reporting
|
||||
*
|
||||
* The specified status callback function will be called on status changes
|
||||
* on the network. The parameters on the callback are the event type and
|
||||
* event-type dependent reason parameter.
|
||||
*
|
||||
* In ESP8266 the callback will be called when processing OOB-messages via
|
||||
* AT-parser. Do NOT call any ESP8266Interface -functions or do extensive
|
||||
* processing in the callback.
|
||||
*
|
||||
* @param status_cb The callback for status changes
|
||||
*/
|
||||
virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
|
||||
|
||||
/** Get the connection status
|
||||
*
|
||||
* @return The connection status according to ConnectionStatusType
|
||||
*/
|
||||
virtual nsapi_connection_status_t get_connection_status() const;
|
||||
|
||||
protected:
|
||||
/** Open a socket
|
||||
* @param handle Handle in which to store new socket
|
||||
* @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP
|
||||
* @return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_open(void **handle, nsapi_protocol_t proto);
|
||||
|
||||
/** Close the socket
|
||||
* @param handle Socket handle
|
||||
* @return 0 on success, negative on failure
|
||||
* @note On failure, any memory associated with the socket must still
|
||||
* be cleaned up
|
||||
*/
|
||||
virtual int socket_close(void *handle);
|
||||
|
||||
/** Bind a server socket to a specific port
|
||||
* @param handle Socket handle
|
||||
* @param address Local address to listen for incoming connections on
|
||||
* @return 0 on success, negative on failure.
|
||||
*/
|
||||
virtual int socket_bind(void *handle, const SocketAddress &address);
|
||||
|
||||
/** Start listening for incoming connections
|
||||
* @param handle Socket handle
|
||||
* @param backlog Number of pending connections that can be queued up at any
|
||||
* one time [Default: 1]
|
||||
* @return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_listen(void *handle, int backlog);
|
||||
|
||||
/** Connects this TCP socket to the server
|
||||
* @param handle Socket handle
|
||||
* @param address SocketAddress to connect to
|
||||
* @return 0 on success, negative on failure
|
||||
*/
|
||||
virtual int socket_connect(void *handle, const SocketAddress &address);
|
||||
|
||||
/** Accept a new connection.
|
||||
* @param handle Handle in which to store new socket
|
||||
* @param server Socket handle to server to accept from
|
||||
* @return 0 on success, negative on failure
|
||||
* @note This call is not-blocking, if this call would block, must
|
||||
* immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_accept(void *handle, void **socket, SocketAddress *address);
|
||||
|
||||
/** Send data to the remote host
|
||||
* @param handle Socket handle
|
||||
* @param data The buffer to send to the host
|
||||
* @param size The length of the buffer to send
|
||||
* @return Number of written bytes on success, negative on failure
|
||||
* @note This call is not-blocking, if this call would block, must
|
||||
* immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_send(void *handle, const void *data, unsigned size);
|
||||
|
||||
/** Receive data from the remote host
|
||||
* @param handle Socket handle
|
||||
* @param data The buffer in which to store the data received from the host
|
||||
* @param size The maximum length of the buffer
|
||||
* @return Number of received bytes on success, negative on failure
|
||||
* @note This call is not-blocking, if this call would block, must
|
||||
* immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_recv(void *handle, void *data, unsigned size);
|
||||
|
||||
/** Send a packet to a remote endpoint
|
||||
* @param handle Socket handle
|
||||
* @param address The remote SocketAddress
|
||||
* @param data The packet to be sent
|
||||
* @param size The length of the packet to be sent
|
||||
* @return The number of written bytes on success, negative on failure
|
||||
* @note This call is not-blocking, if this call would block, must
|
||||
* immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size);
|
||||
|
||||
/** Receive a packet from a remote endpoint
|
||||
* @param handle Socket handle
|
||||
* @param address Destination for the remote SocketAddress or null
|
||||
* @param buffer The buffer for storing the incoming packet data
|
||||
* If a packet is too long to fit in the supplied buffer,
|
||||
* excess bytes are discarded
|
||||
* @param size The length of the buffer
|
||||
* @return The number of received bytes on success, negative on failure
|
||||
* @note This call is not-blocking, if this call would block, must
|
||||
* immediately return NSAPI_ERROR_WOULD_WAIT
|
||||
*/
|
||||
virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size);
|
||||
|
||||
/** Register a callback on state change of the socket
|
||||
* @param handle Socket handle
|
||||
* @param callback Function to call on state change
|
||||
* @param data Argument to pass to callback
|
||||
* @note Callback may be called in an interrupt context.
|
||||
*/
|
||||
virtual void socket_attach(void *handle, void (*callback)(void *), void *data);
|
||||
|
||||
/** Provide access to the NetworkStack object
|
||||
*
|
||||
* @return The underlying NetworkStack object
|
||||
*/
|
||||
virtual NetworkStack *get_stack()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
private:
|
||||
static const int ESP8266_SSID_MAX_LENGTH = 32; /* 32 is what 802.11 defines as longest possible name */
|
||||
static const int ESP8266_PASSPHRASE_MAX_LENGTH = 63; /* The longest allowed passphrase */
|
||||
static const int ESP8266_PASSPHRASE_MIN_LENGTH = 8; /* The shortest allowed passphrase */
|
||||
|
||||
ESP8266 _esp;
|
||||
bool _ids[ESP8266_SOCKET_COUNT];
|
||||
int _initialized;
|
||||
int _started;
|
||||
|
||||
char ap_ssid[ESP8266_SSID_MAX_LENGTH + 1]; /* 32 is what 802.11 defines as longest possible name; +1 for the \0 */
|
||||
nsapi_security_t ap_sec;
|
||||
uint8_t ap_ch;
|
||||
char ap_pass[ESP8266_PASSPHRASE_MAX_LENGTH + 1];
|
||||
uint16_t _local_ports[ESP8266_SOCKET_COUNT];
|
||||
|
||||
bool _disable_default_softap();
|
||||
void event();
|
||||
bool _get_firmware_ok();
|
||||
nsapi_error_t _init(void);
|
||||
nsapi_error_t _startup(const int8_t wifi_mode);
|
||||
|
||||
struct {
|
||||
void (*callback)(void *);
|
||||
void *data;
|
||||
} _cbs[ESP8266_SOCKET_COUNT];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,13 @@
|
|||
# ESP8266 WiFi driver for Mbed OS
|
||||
|
||||
The Mbed OS driver for the ESP8266 WiFi module.
|
||||
|
||||
## Firmware version
|
||||
|
||||
ESP8266 modules come in different shapes and formats, but the most important factor is the firmware version in it. To make sure that the firmware in your module is compatible with Mbed OS, follow the [Update guide](https://developer.mbed.org/teams/ESP8266/wiki/Firmware-Update).
|
||||
|
||||
## Restrictions
|
||||
|
||||
- The ESP8266 WiFi module does not allow the TCP client to bind on a specific port.
|
||||
- Setting up a UDP server is not possible.
|
||||
- The serial port does not have hardware flow control enabled. The AT command set does not either have a way to limit the download rate. Therefore, downloading anything larger than the serial port input buffer is unreliable. An application should be able to read fast enough to stay ahead of the network. This affects mostly the TCP protocol where data would be lost with no notification. On UDP, this would lead to only packet losses which the higher layer protocol should recover from.
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"name": "esp8266",
|
||||
"config": {
|
||||
"tx": {
|
||||
"help": "TX pin for serial connection",
|
||||
"value": null
|
||||
},
|
||||
"rx": {
|
||||
"help": "RX pin for serial connection",
|
||||
"value": null
|
||||
},
|
||||
"debug": {
|
||||
"help": "Enable debug logs",
|
||||
"value": false
|
||||
},
|
||||
"provide-default": {
|
||||
"help": "Provide default WifiInterface. [true/false]",
|
||||
"value": false
|
||||
}
|
||||
},
|
||||
"target_overrides": {
|
||||
"HEXIWEAR": {
|
||||
"tx": "PTD3",
|
||||
"rx": "PTD2"
|
||||
},
|
||||
"NUCLEO_F401RE": {
|
||||
"tx": "D8",
|
||||
"rx": "D2"
|
||||
},
|
||||
"NUCLEO_F411RE": {
|
||||
"tx": "D8",
|
||||
"rx": "D2"
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue