Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Revision 0:ee86ca9e494d, committed 2015-05-03
- Comitter:
- steeven
- Date:
- Sun May 03 14:45:51 2015 +0000
- Commit message:
- ESP8266 driver module
Changed in this revision
| Esp8266.cpp | Show annotated file Show diff for this revision Revisions of this file |
| Esp8266.h | Show annotated file Show diff for this revision Revisions of this file |
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Esp8266.cpp Sun May 03 14:45:51 2015 +0000
@@ -0,0 +1,153 @@
+#include <ESP8266/Esp8266.h>
+
+namespace steeven {
+
+void Esp8266::init() {
+ _ch_pd = 1;
+ _rst = 1;
+ wait_rst();
+ cmd_data("AT+GMR"); //get version
+
+}
+
+void Esp8266::wait_rst() {
+ cmd_data(NULL, NULL, 0, 10000, "\r\nready\r\n");
+}
+
+// 1: client, 2: AP, 3: mixed
+void Esp8266::switchClientMode(int mode) {
+ int reset = 0;
+
+ //remembered in flash, don't change and restart if not changed.
+ if (query_int("AT+CWMODE?") != mode) {
+ sprintf(_buf, "AT+CWMODE=%d", mode);
+ cmd_data(_buf);
+ reset = 1;
+ }
+ if (query_int("AT+CIPMUX?") != 0) {
+ cmd_data("AT+CIPMUX=0", NULL, 0, 3000, "OK\r"); // no multiple connection
+ reset = 1;
+ }
+ if (reset) {
+ cmd_data("AT+RST");
+ wait_rst();
+ }
+}
+
+int Esp8266::connect(const char *ap, const char *pswd) {
+ char buf[100];
+ int n = 0;
+ const char *noip = "+CIFSR:STAIP,\"0.0.0.0\"";
+
+ if (strcmp(ap, query("AT+CWJAP?")) != 0) {
+ sprintf(buf, "AT+SWJAP=\"%s\",\"%s\"", ap, pswd);
+ cmd_data(buf);
+ }
+
+ while (cmd_data("AT+CIFSR", buf, sizeof(buf)) && n++ < 10) {
+ if (memcmp(buf, noip, strlen(noip)) != 0)
+ return 1;
+ wait(0.3);
+ }
+ return 0;
+}
+
+int Esp8266::send(const char *host, int port, const char *tx,
+ void (*cb)(char *, int)) {
+ char buf[100];
+ int r;
+
+ ASSERT(cmd_data("AT+CIPMODE=0")); //none-transparent data xfer mode
+ //TODO
+ cmd_data("AT+CIPCLOSE");
+ // AT+CIPSTART="TCP","www.baidu.com",80
+ sprintf(buf, "AT+CIPSTART=\"TCP\",\"%s\",%d", host, port);
+ ASSERT(cmd_data(buf));
+ sprintf(buf, "AT+CIPSEND=%d", strlen(tx));
+ // AT+CIPSEND=4
+ ASSERT(cmd_data(buf, NULL, 0, 5000, "OK\r\n", NULL));
+// _dbg = 2;
+ ASSERT(cmd_data(tx, NULL, 0, 5000, "SEND OK\r\n\r\n", ""));
+// _dbg = 0;
+ _rcv_cnt = 0;
+ _rcv_exp = 0;
+ _rcv_start = 0;
+ _rcv_cb = cb;
+ _uart.attach(this, &Esp8266::ipd_rx, SerialBase::RxIrq);
+ return 1;
+}
+
+//Esp8266::~Esp8266() {
+// _uart.close();
+//}
+
+//"+IPD,xxx:"
+void Esp8266::ipd_dect() {
+ int i;
+ DBG("testing IPD...\n");
+ if (memcmp("+IPD,", _buf, 5) == 0) {
+ DBG("IPD found...\n");
+ for (i = 5; i < _rcv_cnt; ++i) {
+ if (_buf[i] >= '0' && _buf[i] <= '9')
+ continue;
+ if (_buf[i] == ':') {
+ DBG("':' found...\n");
+ _buf[i] = 0;
+ break;
+ }
+ }
+ if (i == _rcv_cnt) //not found
+ return;
+ _rcv_exp = atoi(&_buf[5]);
+ _rcv_start = i + 1;
+ log('[');
+ DBG("IPD:%d %d\n", _rcv_start, _rcv_exp);
+ } else if (memcmp(_buf, "CLOSED", 5) == 0) {
+ DBG("connection closed\n");
+ if (_rcv_cb != NULL)
+ _rcv_cb(NULL, 0); //end of rcv
+ _rcv_cb = NULL;
+ //notify receiver
+ _uart.attach(NULL, SerialBase::RxIrq);
+ }
+}
+
+void Esp8266::ipd_rx() {
+ char ch;
+ int i = 0;
+ while (_uart.readable()) {
+ ch = _uart.getc();
+ log(ch);
+ if (_rcv_exp == 0 && (ch == '\r' || ch == '\n')) {
+ DBG("ignore leading blank");
+ continue;
+ }
+ _buf[_rcv_cnt++] = ch;
+ i++;
+ if (_rcv_exp == 0) {
+ if (_rcv_cnt > 5 && _rcv_cnt <= 11) { // expecting "+IPD:xxx" or "CLOSED"
+ ipd_dect();
+ }
+ if (_rcv_cnt>11 && _rcv_exp==0) { //failed to detect IPD
+ _uart.attach(NULL, SerialBase::RxIrq);
+ _buf[_rcv_cnt] = 0;
+ LOG("\nFailed to detect IPD: %s", _buf);
+ return;
+ }
+ }
+ if (_rcv_cnt >= (int) sizeof(_buf)) {
+ error("rx buffer overflow size\n");
+ }
+ if (_rcv_exp > 0 && _rcv_exp + _rcv_start == _rcv_cnt) { //reach end of pkt
+ if (_rcv_cb != NULL)
+ _rcv_cb(&_buf[_rcv_start], _rcv_exp); //end of IPD
+ _rcv_exp = 0;
+ _rcv_cnt = 0;
+ _rcv_start = 0;
+ log(']');
+ }
+ }
+ DBG(" %d %d\n", i, _rcv_cnt);
+}
+
+} // namespace steeven
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Esp8266.h Sun May 03 14:45:51 2015 +0000
@@ -0,0 +1,328 @@
+#ifndef ESP8266_H_
+#define ESP8266_H_
+
+#include "mbed.h"
+#include "BufferedSerial/BufferedSerial.h"
+
+#define WIFI_TIME_OUT 5000
+#define _DBG 1
+#if _DBG==1
+#define DBG(msg...) do{if(_logger && _dbg) _logger->printf(msg);}while(0)
+#define LOG(msg...) do{if(_logger) _logger->printf(msg);}while(0)
+#else
+#define DBG(msg...)
+#define LOG(msg...)
+#endif
+#define ASSERT(eval,msg...) if((r=eval)<=0) { LOG("%s():%d result: %d\n", __FUNCTION__, __LINE__, r); return r;}
+
+namespace steeven {
+
+/** Esp8266 WiFi serial module.
+ * Warnning:
+ * CH_PD pin has to connect VCC to boot from internal flash!
+ * Command has to end with "\r\n"
+ * If you can't get full AT output, set console same baudrate or higher, or set wifi baudrate low!!!
+ * DO NOT print console if you want get a long result from internet.
+ * Some bad data at beginning because the baudrate changed to 74880
+ * \r: 0xd \n: 0xa
+ */
+class Esp8266 {
+
+public:
+ /**
+ *
+ * @param pin LED pin with PWM support
+ * @param time Time for the brightness transition
+ * @param hold Time for holding the brightness before next transition.
+ * Effective for loop mode.
+ */
+ Esp8266(PinName tx, PinName rx, PinName ch_pd, PinName rst, int baudrate =
+ 115200) :
+ _ch_pd(ch_pd), _rst(rst), _uart(tx, rx) {
+
+ _uart.baud(baudrate);
+// _uart.attach(this, &Esp8266::on_rx, SerialBase::RxIrq);
+
+ _timer.start();
+ _timeout_ms = WIFI_TIME_OUT;
+
+ _ch_pd = 0; //uart mode
+ _rst = 0; //reset
+ }
+
+ void init();
+
+ void wait_rst();
+
+ // 1: client, 2: AP, 3: mixed
+ void switchClientMode(int mode);
+
+ int connect(const char *ap, const char *pswd);
+
+ int send(const char *host, int port, const char *tx,
+ void (*cb)(char *, int) = NULL);
+
+ void set_log(BufferedSerial* logger, int dbg) {
+ _logger = logger;
+ _dbg = dbg;
+ }
+
+ void log(char ch) {
+ if (_logger) {
+ _logger->putc(ch);
+ if (_dbg > 1) {
+ _logger->printf("[%x]", ch);
+ }
+ }
+ }
+
+ void dbg(char ch) {
+ if (_logger == NULL || _dbg == 0)
+ return;
+ _logger->putc(ch);
+ }
+
+ void dbg(const char *msg) {
+ if (_logger == NULL || _dbg == 0)
+ return;
+ _logger->puts(msg);
+ }
+
+ void dbg(const char * type, const char *msg) {
+ if (_logger == NULL || _dbg == 0)
+ return;
+ _logger->printf("::wifi:: %s: %s\n", type, msg);
+ }
+
+ void clear() {
+ while (_uart.readable()) {
+ log(_uart.getc());
+ }
+ }
+
+ /*
+ * query result of a command, command must end with '?'
+ * >>>AT+CWMODE?
+ * <<<+CWMODE:3
+ * <<<OK
+ * cmd CWMODE, result is 3.
+ */
+ char* query(const char *cmd) {
+ int r;
+ int len = strlen(cmd) - 3;
+
+ r = cmd_data(cmd, _buf, sizeof(_buf));
+ if (r < 0) {
+ dbg("query", "failed");
+ return NULL;
+ }
+ dbg("query result", _buf);
+ if (r < len + 2) { // has to be: +CMD:xxx
+ dbg("query", "invalid result length");
+ return NULL;
+ }
+ if (memcmp(cmd + 2, _buf, len) != 0) { //check: +CMD
+ dbg("query", "length not match");
+ return NULL;
+ }
+ if (_buf[len] != ':') {
+ dbg("query", "\":\" not found");
+ return NULL;
+ }
+ return _buf + len + 1;
+ }
+
+ int query_int(const char *cmd) {
+ return atoi(query(cmd));
+ }
+
+ int query_match(const char *cmd, const char *r) {
+ return strcmp(query(cmd), r);
+ }
+
+ /**
+ * Read data until match or reach max size
+ * return
+ * size of data
+ * -3: timeout
+ * -1: get error pattern
+ */
+ int read_until(char *buf, int max, const char *p_ok = "OK\r\n",
+ const char *p_error = "ERROR\r\n") {
+ int i = 0, i_ok = 0, i_err = 0;
+ char ch;
+
+ int ok_size = strlen(p_ok);
+ int err_size = strlen(p_error);
+
+ while (1) {
+ while (_uart.readable()) {
+ ch = _uart.getc();
+ if (buf)
+ buf[i] = ch;
+ log(ch);
+ i++;
+
+ //check ok pattern
+ if (p_ok) {
+ if (p_ok[i_ok] != ch) {
+ if (i_ok > 0 && _logger && _dbg > 0)
+ _logger->putc('*');
+ i_ok = 0;
+ }
+ if (p_ok[i_ok] == ch) {
+ i_ok++;
+ if (i_ok > 0)
+ if (_logger && _dbg > 1)
+ _logger->putc('_');
+ if (i_ok == ok_size) { //found ok pattern
+ if (buf)
+ buf[i - ok_size] = 0;
+ dbg("match", "done\n");
+ return i - ok_size;
+ }
+ }
+ }
+
+ //check error pattern
+ if (p_error) {
+ if (p_error[i_err] != ch)
+ i_err = 0;
+ if (p_error[i_err] == ch) {
+ i_err++;
+ if (i_err == err_size) { //match error
+ if (buf)
+ buf[i - err_size] = 0;
+ dbg("match", "error\n");
+ return -1;
+ }
+ }
+ }
+
+ if (buf) {
+ if (i >= max) {
+ dbg("buffer", "overflow\n");
+// buf[i-1] = 0;
+ return i;
+ }
+ } else {
+ // Just continue check ok/error
+ }
+ }
+ if (_timer.read_ms() > _timeout_ms) {
+ dbg("cmd", "timeout\n");
+ return -3;
+ }
+ }
+
+ }
+
+ int cmd_send(const char* cmd, const char *echo = NULL) {
+ int r = 0;
+
+ _uart.attach(NULL, SerialBase::RxIrq);
+
+ _uart.puts(cmd);
+ _uart.puts("\r\n");
+ dbg("cmd", "sent");
+
+ //check echo
+ if (echo == NULL)
+ echo = cmd;
+
+ if (echo && strlen(echo) > 0) {
+ r = read_until(NULL, 0, echo, NULL);
+ if (r < 0) {
+ dbg("cmd", "no echo");
+ return r;
+ }
+
+ r = read_until(NULL, 0, "\r\r\n", NULL);
+ if (r < 0) {
+ dbg("cmd", "no echo end");
+ return r;
+ }
+ }
+
+ dbg("cmd", "sent");
+ return r;
+ }
+
+ /** every command has to end with "\r\n"
+ *
+ * >>>cmd
+ * <<<cmd
+ * <<<data
+ * <<<OK/ERROR
+ * <<<
+ *
+ * return size of result
+ * 0: ok
+ * -1: if error
+ * -2: if buffer overflow
+ * -3: timeout
+ * others: size of content
+ */
+ int cmd_data(const char *cmd, char* ret = NULL, int size = 0,
+ int timeout_ms =
+ WIFI_TIME_OUT, const char *end = "OK\r\n",
+ const char *echo = NULL) {
+ int r = 0;
+
+ _timer.reset();
+ _timeout_ms = timeout_ms;
+
+ dbg("cmd", cmd);
+
+ clear();
+ dbg("cmd", "cleared");
+
+ if (cmd) {
+ if ((r = cmd_send(cmd, echo)) < 0) {
+ dbg("cmd", "send failed");
+ return r;
+ }
+ }
+
+ if (end != NULL) {
+ /* check OK or ERROR */
+ dbg("cmd", "matching end...");
+ if ((r = read_until(ret, size, end)) < 0)
+ dbg("cmd", "check end failed");
+ return r;
+ }
+
+ clear();
+ dbg("cmd", "cleared");
+
+ dbg("cmd", "complete");
+ return r;
+ }
+
+ void ipd_rx();
+
+// virtual ~Esp8266();
+
+ BufferedSerial *_logger;
+ int _dbg;
+
+protected:
+ void ipd_dect();
+
+ DigitalOut _ch_pd; //ESP8266 CH_PD pin
+ DigitalOut _rst; //ESP8266 reset pin
+ Serial _uart;
+
+ char _buf[1600];
+ Timer _timer;
+ int _timeout_ms;
+
+ int _rcv_start; //"+IPD,xxx:"
+ int _rcv_cnt; // total buffer used
+ int _rcv_exp; // expected size
+ void (*_rcv_cb)(char *buf, int len);
+
+}
+;
+}
+#endif /* ESP8266_H_ */