ESP8266 uart wifi module via AT command

Dependencies:   BufferedSerial

Dependents:   esb_gcc

Fork of ESP8266 by steeven lee

Esp8266.h

Committer:
ninad
Date:
2016-11-15
Revision:
1:32714c2fb1a9
Parent:
0:ee86ca9e494d

File content as of revision 1:32714c2fb1a9:

#ifndef ESP8266_H_
#define ESP8266_H_

#include "mbed.h"
#include "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_ */