ESP8266 uart wifi module via AT command

Dependents:   mbed_esp8266_demo

Revision:
0:ee86ca9e494d
--- /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_ */