OLD

OLD

GSwifi.cpp

Committer:
gsfan
Date:
2012-11-08
Revision:
21:1270827d431a
Parent:
20:151b5a4fdd29

File content as of revision 21:1270827d431a:

/**
 * Gainspan wi-fi module library for mbed
 * Copyright (c) 2012 gsfan
 * Released under the MIT License: http://mbed.org/license/mit
 */

/** @file
 * @brief Gainspan wi-fi module library for mbed
 * GS1011MIC, GS1011MIP, GainSpan WiFi Breakout, etc.
 * module configuration: ATB=115200
 */

#include "dbg.h"
#include "mbed.h"
#include "GSwifi.h"
#include <ctype.h>

#ifdef GS_UART_DIRECT
#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
#define _gs_getc() LPC_UART1->RBR
#define _gs_putc(c) while(!(LPC_UART1->LSR & (1<<5))); LPC_UART1->THR = c
#elif defined(TARGET_LPC11U24)
#define _gs_getc() LPC_USART->RBR
#define _gs_putc(c) while(!(LPC_USART->LSR & (1<<5))); LPC_USART->THR = c
#endif
#else
#define _gs_getc() _gs.getc()
#define _gs_putc(c) _gs.putc(c)
#endif

GSwifi::GSwifi (PinName p_tx, PinName p_rx, int baud) : _gs(p_tx, p_rx), _buf_cmd(GS_CMD_SIZE) {
    _connect = false;
    _status = GSSTAT_READY;
    _escape = 0;
    _response = 1;
    _gs_mode = GSMODE_COMMAND;

    _gs.baud(baud);
    _gs.attach(this, &GSwifi::isr_recv, Serial::RxIrq);
    _rts = false;
}

GSwifi::GSwifi (PinName p_tx, PinName p_rx, PinName p_cts, PinName p_rts, int baud) : _gs(p_tx, p_rx), _buf_cmd(GS_CMD_SIZE) {
    _connect = false;
    _status = GSSTAT_READY;
    _escape = 0;
    _response = 1;
    _gs_mode = GSMODE_COMMAND;

    _gs.baud(baud);
    _gs.attach(this, &GSwifi::isr_recv, Serial::RxIrq);

#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
    if (p_cts == p12) { // CTS input (P0_17)
        LPC_UART1->MCR |= (1<<7); // CTSEN
        LPC_PINCON->PINSEL1 &= ~(3 << 2);
        LPC_PINCON->PINSEL1 |= (1 << 2); // UART CTS
    }
    if (p_rts == P0_22) { // RTS output (P0_22)
        LPC_UART1->MCR |= (1<<6); // RTSEN
        LPC_PINCON->PINSEL1 &= ~(3 << 12);
        LPC_PINCON->PINSEL1 |= (1 << 12); // UART RTS
        _rts = true;
    } else {
        _rts = false;
    }
#elif defined(TARGET_LPC11U24)
    if (p_cts == p21) { // CTS input (P0_7)
        LPC_USART->MCR |= (1<<7); // CTSEN
        LPC_IOCON->PIO0_7 &= ~0x07;
        LPC_IOCON->PIO0_7 |= 0x01; // UART CTS
    }
    if (p_rts == p22) { // RTS output (P0_17)
        LPC_USART->MCR |= (1<<6); // RTSEN
        LPC_IOCON->PIO0_17 &= ~0x07;
        LPC_IOCON->PIO0_17 |= 0x01; // UART RTS
        _rts = true;
    } else {
        _rts = false;
    }
#endif
}

// uart interrupt
void GSwifi::isr_recv () {
    static int len, mode;
    static char tmp[20];
    char flg, dat;
    
#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
    flg = LPC_UART1->LSR;
#elif defined(TARGET_LPC11U24)
    flg = LPC_USART->LSR;
#endif
    dat = _gs_getc();
    
    if (flg & ((1 << 7)|(1 << 3)|(1 << 4))) return;
//    DBG("%02x_", dat);

    switch (_gs_mode) {
    case GSMODE_COMMAND: // command responce
        if (_escape) {
            // esc
            switch (dat) {
            case 'O':
                DBG("ok\r\n");
                _gs_ok = 1;
                break;
            case 'F':
                DBG("failure\r\n");
                _gs_failure = 1;
                break;
            case 'S':
                DBG("GSMODE_DATA_RX\r\n");
                _gs_mode = GSMODE_DATA_RX;
                mode = 0;
                break;
            case 'u':
                DBG("GSMODE_DATA_RXUDP\r\n");
                _gs_mode = GSMODE_DATA_RXUDP;
                mode = 0;
                break;
            case 'Z':
            case 'H':
                DBG("GSMODE_DATA_RX_BULK\r\n");
                _gs_mode = GSMODE_DATA_RX_BULK;
                mode = 0;
                break;
            case 'y':
                DBG("GSMODE_DATA_RXUDP_BULK\r\n");
                _gs_mode = GSMODE_DATA_RXUDP_BULK;
                mode = 0;
                break;
            default:
                DBG("unknown [ESC] %02x\r\n", dat);
                break;
            }
            _escape = 0;
        } else {
            if (dat == 0x1b) {
                _escape = 1;
            } else
            if (dat != '\r') {
                // command
                _buf_cmd.put(dat);
                if (dat == '\n') {
                    _gs_enter ++;
                    if (!_response && _connect) poll_cmd();
                }
            }
        }
        break;

    case GSMODE_DATA_RX:
    case GSMODE_DATA_RXUDP:
        if (mode == 0) {
            // cid
            _cid = x2i(dat);
            _gs_sock[_cid].received = 0;
            mode ++;
            if (_gs_mode == GSMODE_DATA_RX) {
                mode = 3;
            }
            len = 0;
        } else
        if (mode == 1) {
            // ip
            if ((dat < '0' || dat > '9') && dat != '.') {
                int ip1, ip2, ip3, ip4;
                tmp[len] = 0;
                sscanf(tmp, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4);
                _from.setIp(IpAddr(ip1, ip2, ip3, ip4));
                mode ++;
                len = 0;
                break;
            }
            tmp[len] = dat;    
            len ++;        
        } else
        if (mode == 2) {
            // port
            if (dat < '0' || dat > '9') {
                tmp[len] = 0;
                _from.setPort(atoi(tmp));
                mode ++;
                len = 0;
                break;
            }
            tmp[len] = dat;            
            len ++;        
        } else
        if (_escape) {
            // esc
            switch (dat) {
            case 'E':
                DBG("recv ascii %d\r\n", _cid);
                _gs_sock[_cid].received = 1;
                _gs_mode = GSMODE_COMMAND;
                // recv interrupt
                if (_gs_sock[_cid].protocol == GSPROT_HTTPGET && _gs_sock[_cid].onGsReceive != NULL) {
                    _gs_sock[_cid].onGsReceive(_cid, _gs_sock[_cid].data->use());
                    _gs_sock[_cid].received = 0;
                }
                break;
            default:
                DBG("unknown <ESC> %02x\r\n", dat);
                break;
            }
            _escape = 0;
        } else {
            if (dat == 0x1b) {
                _escape = 1;
            } else {
                // data
                _gs_sock[_cid].data->put(dat);
                len ++;
                if (len < GS_DATA_SIZE && _gs_sock[_cid].data->available() == 0) {
                    // buffer full
                    if (_gs_sock[_cid].onGsReceive != NULL) {
                        _gs_sock[_cid].onGsReceive(_cid, _gs_sock[_cid].data->use());
                    }
                }
            }
        }
        break;

    case GSMODE_DATA_RX_BULK:
    case GSMODE_DATA_RXUDP_BULK:
//        DBG("%c", dat);
        if (mode == 0) {
            // cid
            _cid = x2i(dat);
            _gs_sock[_cid].received = 0;
            mode ++;
            if (_gs_mode == GSMODE_DATA_RX_BULK) {
                mode = 3;
            }
            len = 0;
        } else
        if (mode == 1) {
            // ip
            if ((dat < '0' || dat > '9') && dat != '.') {
                int ip1, ip2, ip3, ip4;
                tmp[len] = 0;
                sscanf(tmp, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4);
                _from.setIp(IpAddr(ip1, ip2, ip3, ip4));
                mode ++;
                len = 0;
                break;
            }
            tmp[len] = dat;    
            len ++;        
        } else
        if (mode == 2) {
            // port
            if (dat < '0' || dat > '9') {
                tmp[len] = 0;
                _from.setPort(atoi(tmp));
                mode ++;
                len = 0;
                break;
            }
            tmp[len] = dat;            
            len ++;        
        } else
        if (mode == 3) {
            // length
            tmp[len] = dat;            
            len ++;        
            if (len >= 4) {
                tmp[len] = 0;
                len = atoi(tmp);
                mode ++;
                break;
            }
        } else
        if (mode == 4) {
            // data
            if (_gs_sock[_cid].data != NULL) {
                _gs_sock[_cid].data->put(dat);
            }
            len  --;
            if (len && _gs_sock[_cid].data->available() == 0) {
                // buffer full
                if (_gs_sock[_cid].onGsReceive != NULL) {
                    _gs_sock[_cid].onGsReceive(_cid, _gs_sock[_cid].data->use());
                }
            }
            if (len == 0) {
                DBG("recv binary %d\r\n", _cid);
                _gs_sock[_cid].received = 1;
                _escape = 0;
                _gs_mode = GSMODE_COMMAND;
                // recv interrupt
                if (_gs_sock[_cid].protocol == GSPROT_HTTPGET && _gs_sock[_cid].onGsReceive != NULL) {
                    _gs_sock[_cid].onGsReceive(_cid, _gs_sock[_cid].data->use());
                    _gs_sock[_cid].received = 0;
                }
            }
        }
        break;

    }
}

int GSwifi::command (const char *cmd, GSRESPONCE res, int timeout) {
    int i, r = 0;

    if (! cmd) {
        // dummy CR+LF
        _gs.printf("\r\n");
        for (i = 0; i < 10; i ++) {
            wait_ms(10);
            poll_cmd();
            _buf_cmd.clear();
        }
        return 0;
    }

    _response = 1;
    _buf_cmd.clear();
    _gs_ok = 0;
    _gs_failure = 0;
    _gs_enter = 0;
    for (i = 0; i < strlen(cmd); i ++) {
        _gs_putc(cmd[i]);
    }
    _gs_putc('\r');
    _gs_putc('\n');
    DBG("command: %s\r\n", cmd);
    if (strlen(cmd) == 0) return 0;
    wait_ms(10);
    if (timeout) {
        r = cmdResponse(res, timeout);
    }
    _response = 0;
    return r;
}

int GSwifi::cmdResponse (GSRESPONCE res, int ms) {
    int i, n = 0, flg = 0;
    char buf[GS_CMD_SIZE];
    Timer timeout;

    timeout.start();
    for (;;) {
        // recv response
        i = 0;
        while (i < sizeof(buf)) {
            if (_buf_cmd.use()) {
                _buf_cmd.get(&buf[i]);
                if (buf[i] == '\n') {
                    break;
                }
                i ++;
            }
            if (timeout.read_ms() > ms) {
                timeout.stop();
                DBG("timeout\r\n");
                return -1;
            }
        }
        _gs_enter = 0;
        if (i == 0) continue;
        buf[i] = 0;
        DBG("response: %s\r\n", buf);
        timeout.stop();

        if (strcmp(buf, "OK") == 0) {
            _gs_ok = 1;
        } else
        if (strncmp(buf, "ERROR", 5) == 0) {
            _gs_failure = 1;
        }

        switch(res) {
        case GSRES_NORMAL:
            flg = 1;
            break;
        case GSRES_WPS:
            if (n == 0 && strncmp(buf, "SSID", 4) == 0) {
                n ++;
            } else
            if (n == 1 && strncmp(buf, "CHANNEL", 7) == 0) {
                n ++;
            } else
            if (n == 2 && strncmp(buf, "PASSPHRASE", 10) == 0) {
                n ++;
                flg = 1;
            }
            break;
        case GSRES_CONNECT:
            if (strncmp(buf, "CONNECT", 7) == 0) {
                _cid = x2i(buf[8]);
                flg = 1;
            }
            break;
        case GSRES_DHCP:
            if (n == 0 && strstr(buf, "SubNet") && strstr(buf, "Gateway")) {
                n ++;
            } else
            if (n == 1) {
                int ip1, ip2, ip3, ip4;
                char *tmp = buf + 1;
                sscanf(tmp, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4);
                _ipaddr = IpAddr(ip1, ip2, ip3, ip4);
                tmp = strstr(tmp, ":") + 2;
                sscanf(tmp, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4);
                _netmask = IpAddr(ip1, ip2, ip3, ip4);
                tmp = strstr(tmp, ":") + 2;
                sscanf(tmp, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4);
                _gateway = IpAddr(ip1, ip2, ip3, ip4);
                n ++;
                flg = 1;
            }
            break;
        case GSRES_MACADDRESS:
            if (buf[2] == ':' && buf[5] == ':') {
                int mac1, mac2, mac3, mac4, mac5, mac6;
                sscanf(buf, "%x:%x:%x:%x:%x:%x", &mac1, &mac2, &mac3, &mac4, &mac5, &mac6);
                _mac[0] = mac1;
                _mac[1] = mac2;
                _mac[2] = mac3;
                _mac[3] = mac4;
                _mac[4] = mac5;
                _mac[5] = mac6;
                flg = 1;
            }
            break;
        case GSRES_DNSLOOKUP:
            if (strncmp(buf, "IP:", 3) == 0) {
                int ip1, ip2, ip3, ip4;
                sscanf(&buf[3], "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4);
                _resolv = IpAddr(ip1, ip2, ip3, ip4);
                flg = 1;
            }
            break;
        case GSRES_HTTP:
            if (buf[0] >= '0' && buf[0] <= 'F') {
                _cid = x2i(buf[0]);
                flg = 1;
            }
            break;
        case GSRES_RSSI:
            if (buf[0] == '-' || (buf[0] >= '0' && buf[0] <= '9')) {
                _rssi = atoi(buf);
                flg = 1;
            }
            break;
        case GSRES_TIME:
            if (buf[0] >= '0' && buf[0] <= '9') {
                int year, month, day, hour, min, sec;
                struct tm t;
                sscanf(buf, "%d/%d/%d,%d:%d:%d", &day, &month, &year, &hour, &min, &sec);
                t.tm_sec = sec;
                t.tm_min = min;
                t.tm_hour = hour;
                t.tm_mday = day;
                t.tm_mon = month - 1;
                t.tm_year = year - 1900;   
                _time = mktime(&t);            
                flg = 1;
            }
            break;
        }
        
        if ((flg && _gs_ok) || _gs_failure) break;
        timeout.reset();
        timeout.start();
    }

    if (_gs_failure || flg == 0) {
        return -1;
    } else {
        return 0;
    }
}

int GSwifi::connect (GSSECURITY sec, const char *ssid, const char *pass, int dhcp) {
    int r;
    char cmd[GS_CMD_SIZE];
    
    if (_connect || _status != GSSTAT_READY) return -1;

    command(NULL, GSRES_NORMAL);
    if (command("ATE0", GSRES_NORMAL)) return -1;
    if (_rts) {
        command("AT&K0", GSRES_NORMAL);
        command("AT&R1", GSRES_NORMAL);
    }
    command("AT+NMAC=?", GSRES_MACADDRESS);
#ifdef GS_BULK
    command("AT+BDATA=1", GSRES_NORMAL);
#endif

    disconnect();
    command("AT+WM=0", GSRES_NORMAL); // infrastructure
    wait_ms(100);
    if (dhcp && sec != GSSEC_WPS_BUTTON) {
        command("AT+NDHCP=1", GSRES_NORMAL);
    } else {
        command("AT+NDHCP=0", GSRES_NORMAL);
    }

    switch (sec) {
    case GSSEC_NONE:
        command("AT+WAUTH=0", GSRES_NORMAL);
        sprintf(cmd, "AT+WA=%s", ssid);
        r = command(cmd, GSRES_DHCP, GS_TIMEOUT2);
        if (r) {
            DBG("retry\r\n");
            r = command(cmd, GSRES_DHCP, GS_TIMEOUT2); // retry
        }
        break;
    case GSSEC_OPEN:
    case GSSEC_WEP:
        sprintf(cmd, "AT+WAUTH=%d", sec);
        command(cmd, GSRES_NORMAL);
        sprintf(cmd, "AT+WWEP1=%s", pass);
        command(cmd, GSRES_NORMAL);
        wait_ms(100);
        sprintf(cmd, "AT+WA=%s", ssid);
        r = command(cmd, GSRES_DHCP, GS_TIMEOUT2);
        if (r) {
            DBG("retry\r\n");
            r = command(cmd, GSRES_DHCP, GS_TIMEOUT2);
        }
        break;
    case GSSEC_WPA_PSK:
    case GSSEC_WPA2_PSK:
        command("AT+WAUTH=0", GSRES_NORMAL);
//        sprintf(cmd, "AT+WWPA=%s", pass);
//        command(cmd, GSRES_NORMAL);
        sprintf(cmd, "AT+WPAPSK=%s,%s", ssid, pass);
        command(cmd, GSRES_NORMAL, GS_TIMEOUT2);
        wait_ms(100);
        sprintf(cmd, "AT+WA=%s", ssid);
        r = command(cmd, GSRES_DHCP, GS_TIMEOUT2);
        if (r) {
            DBG("retry\r\n");
            r = command(cmd, GSRES_DHCP, GS_TIMEOUT2);
        }
        break;
    case GSSEC_WPS_BUTTON:
        command("AT+WAUTH=0", GSRES_NORMAL);
        r = command("AT+WWPS=1", GSRES_WPS, GS_TIMEOUT2);
        if (r) break;
        if (dhcp) {
            r = command("AT+NDHCP=1", GSRES_DHCP, GS_TIMEOUT2);
        }
        break;
    default:
        DBG("Can't use security\r\n");
        r = -1;
        break;
    }

    if (r == 0 && !dhcp) {
        sprintf(cmd, "AT+DNSSET=%d.%d.%d.%d",
            _gateway[0], _gateway[1], _gateway[2], _gateway[3]);
        command(cmd, GSRES_NORMAL);
    }

    if (r == 0) _connect = true;
    return r;
}

int GSwifi::adhock (GSSECURITY sec, const char *ssid, const char *pass, IpAddr ipaddr, IpAddr netmask) {
    int r;
    char cmd[GS_CMD_SIZE];

    if (_connect || _status != GSSTAT_READY) return -1;

    command(NULL, GSRES_NORMAL);
    if (command("ATE0", GSRES_NORMAL)) return -1;
    if (_rts) {
        command("AT&K0", GSRES_NORMAL);
        command("AT&R1", GSRES_NORMAL);
    }
    disconnect();
    command("AT+NMAC=?", GSRES_MACADDRESS);
#ifdef GS_BULK
    command("AT+BDATA=1", GSRES_NORMAL);
#endif

    command("AT+WM=1", GSRES_NORMAL); // adhock
    wait_ms(100);
    command("AT+NDHCP=0", GSRES_NORMAL);
    setAddress(ipaddr, netmask, ipaddr, ipaddr);

    switch (sec) {
    case GSSEC_NONE:
        command("AT+WAUTH=0", GSRES_NORMAL);
        sprintf(cmd, "AT+WA=%s", ssid);
        r = command(cmd, GSRES_NORMAL, GS_TIMEOUT2);
        break;
    case GSSEC_OPEN:
    case GSSEC_WEP:
        sprintf(cmd, "AT+WAUTH=%d", sec);
        command(cmd, GSRES_NORMAL);
        sprintf(cmd, "AT+WWEP1=%s", pass);
        command(cmd, GSRES_NORMAL);
        wait_ms(100);
        sprintf(cmd, "AT+WA=%s", ssid);
        r = command(cmd, GSRES_NORMAL, GS_TIMEOUT2);
        break;
    default:
        DBG("Can't use security\r\n");
        r = -1;
        break;
    }

    if (r == 0) _connect = true;
    return r;
}

int GSwifi::limitedap (GSSECURITY sec, const char *ssid, const char *pass, IpAddr ipaddr, IpAddr netmask, bool prov) {
    int r;
    char cmd[GS_CMD_SIZE];
    
    if (_connect || _status != GSSTAT_READY) return -1;

    command(NULL, GSRES_NORMAL);
    if (command("ATE0", GSRES_NORMAL)) return -1;
    if (_rts) {
        command("AT&K0", GSRES_NORMAL);
        command("AT&R1", GSRES_NORMAL);
    }
    disconnect();
    command("AT+NMAC=?", GSRES_MACADDRESS);
#ifdef GS_BULK
    command("AT+BDATA=1", GSRES_NORMAL);
#endif

    command("AT+WM=2", GSRES_NORMAL); // limited ap
    wait_ms(1000);
    command("AT+NDHCP=0", GSRES_NORMAL);
    setAddress(ipaddr, netmask, ipaddr, ipaddr);
    if (command("AT+DHCPSRVR=1", GSRES_NORMAL)) return -1;
    if (command("AT+DNS=1,setup.local", GSRES_NORMAL)) return -1;

    switch (sec) {
    case GSSEC_NONE:
        command("AT+WAUTH=0", GSRES_NORMAL);
        sprintf(cmd, "AT+WA=%s", ssid);
        r = command(cmd, GSRES_NORMAL, GS_TIMEOUT2);
        break;
    case GSSEC_OPEN:
    case GSSEC_WEP:
        sprintf(cmd, "AT+WAUTH=%d", sec);
        command(cmd, GSRES_NORMAL);
        sprintf(cmd, "AT+WWEP1=%s", pass);
        command(cmd, GSRES_NORMAL);
        wait_ms(100);
        sprintf(cmd, "AT+WA=%s", ssid);
        r = command(cmd, GSRES_NORMAL, GS_TIMEOUT2);
        break;
    default:
        DBG("Can't use security\r\n");
        r = -1;
        break;
    }

    if (r == 0 && prov) {
        command("AT+WEBPROV=admin,password", GSRES_NORMAL);
    }

    if (r == 0) _connect = true;
    return r;
}

int GSwifi::disconnect () {
    int i;

    _connect = false;
    for (i = 0; i < 16; i ++) {
        _gs_sock[i].connect = false;
    }
    command("AT+NCLOSEALL", GSRES_NORMAL);
    command("AT+WD", GSRES_NORMAL);
    command("AT+NDHCP=0", GSRES_NORMAL);
    wait_ms(100);
    return 0;
}

int GSwifi::setAddress () {

    if (command("AT+NDHCP=1", GSRES_DHCP), GS_TIMEOUT2) return -1;
    if (_ipaddr.isNull()) return -1;
    return 0;
}

int GSwifi::setAddress (IpAddr ipaddr, IpAddr netmask, IpAddr gateway, IpAddr nameserver) {
    int r;
    char cmd[GS_CMD_SIZE];

    command("AT+NDHCP=0", GSRES_NORMAL);
    wait_ms(100);

    sprintf(cmd, "AT+NSET=%d.%d.%d.%d,%d.%d.%d.%d,%d.%d.%d.%d",
        ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3],
        netmask[0], netmask[1], netmask[2], netmask[3],
        gateway[0], gateway[1], gateway[2], gateway[3]);
    r = command(cmd, GSRES_NORMAL);
    if (r) return -1;
    _ipaddr = ipaddr;
    _netmask = netmask;
    _gateway = gateway;

    if (ipaddr != nameserver) {
        sprintf(cmd, "AT+DNSSET=%d.%d.%d.%d",
            nameserver[0], nameserver[1], nameserver[2], nameserver[3]);
        r = command(cmd, GSRES_NORMAL);
    }
    return r;
}

int GSwifi::getAddress (IpAddr &ipaddr, IpAddr &netmask, IpAddr &gateway, IpAddr &nameserver) {
    ipaddr = _ipaddr;
    netmask = _netmask;
    gateway = _gateway;
    nameserver = _nameserver;
    return 0;
}

int GSwifi::getHostByName (const char* name, IpAddr &addr) {
    char cmd[GS_CMD_SIZE];

    if (! _connect || _status != GSSTAT_READY) return -1;

    sprintf(cmd, "AT+DNSLOOKUP=%s", name);
    if (command(cmd, GSRES_DNSLOOKUP)) return -1;

    addr = _resolv;
    return 0;
}

int GSwifi::getHostByName (Host &host) {
    char cmd[GS_CMD_SIZE];

    if (! _connect || _status != GSSTAT_READY) return -1;

    sprintf(cmd, "AT+DNSLOOKUP=%s", host.getName());
    if (command(cmd, GSRES_DNSLOOKUP)) return -1;

    host.setIp(_resolv);
    return 0;
}

int GSwifi::setRFPower (int power) {
    char cmd[GS_CMD_SIZE];

    if (power < 0 || power > 7) return -1;

    sprintf(cmd, "AT+WP=%d", power);
    return command(cmd, GSRES_NORMAL);
}

int GSwifi::powerSave (int active, int save) {
    char cmd[GS_CMD_SIZE];

    if (_status != GSSTAT_READY) return -1;

    sprintf(cmd, "AT+WRXACTIVE=%d", active);
    command(cmd, GSRES_NORMAL);
    sprintf(cmd, "AT+WRXPS=%d", save);
    return command(cmd, GSRES_NORMAL);
}

int GSwifi::standby (int msec) {
    char cmd[GS_CMD_SIZE];

    if (_status != GSSTAT_READY && _status != GSSTAT_WAKEUP) return -1;

    if (_status != GSSTAT_WAKEUP) {
        command("AT+WRXACTIVE=0", GSRES_NORMAL);
        command("AT+STORENWCONN", GSRES_NORMAL);
    } else {
        command("ATE0", GSRES_NORMAL);
        if (_rts) {
            command("AT&K0", GSRES_NORMAL);
            command("AT&R1", GSRES_NORMAL);
        }
    }
    _status = GSSTAT_STANDBY;
    sprintf(cmd, "AT+PSSTBY=%d,0,0,0", msec); // go standby
    return command(cmd, GSRES_NORMAL, 0);
}

int GSwifi::wakeup () {

    if (_status == GSSTAT_WAKEUP) {
        _status = GSSTAT_READY;
        command("ATE0", GSRES_NORMAL);
        if (_rts) {
            command("AT&K0", GSRES_NORMAL);
            command("AT&R1", GSRES_NORMAL);
        }
#ifdef GS_BULK
        command("AT+BDATA=1", GSRES_NORMAL);
#endif
        command("AT+RESTORENWCONN", GSRES_NORMAL);
        wait_ms(100);
        return command("AT+WRXACTIVE=1", GSRES_NORMAL);
    } else
    if (_status == GSSTAT_DEEPSLEEP) {
        _status = GSSTAT_READY;
        return command("AT", GSRES_NORMAL);
    }
    return -1;
}

int GSwifi::deepSleep () {

    if (_status != GSSTAT_READY) return -1;

    _status = GSSTAT_DEEPSLEEP;
    return command("AT+PSDPSLEEP", GSRES_NORMAL, 0); // go deep sleep
}

bool GSwifi::isConnected () {
    return _connect;
}

GSSTATUS GSwifi::getStatus () {
    return _status;
}

int GSwifi::getRssi () {
    if (command("AT+WRSSI=?", GSRES_RSSI)) {
        return 0;
    }
    return _rssi;
}

int GSwifi::ntpdate (Host host, int sec) {
    char cmd[GS_CMD_SIZE];

    if (! _connect || _status != GSSTAT_READY) return -1;

    if (host.getIp().isNull()) {
        if (getHostByName(host)) {
            if (getHostByName(host)) return -1;
        }
    }

    if (sec) {
        sprintf(cmd, "AT+NTIMESYNC=1,%d.%d.%d.%d,%d,1,%d", host.getIp()[0], host.getIp()[1], host.getIp()[2], host.getIp()[3],
          GS_TIMEOUT / 1000, sec);
    } else {
        sprintf(cmd, "AT+NTIMESYNC=1,%d.%d.%d.%d,%d,0", host.getIp()[0], host.getIp()[1], host.getIp()[2], host.getIp()[3],
          GS_TIMEOUT / 1000);
    }
    return command(cmd, GSRES_NORMAL);
}

int GSwifi::setTime (time_t time) {
    char cmd[GS_CMD_SIZE];
    struct tm *t;

    if (_status != GSSTAT_READY) return -1;

    t = localtime(&time);
    sprintf(cmd, "AT+SETTIME=%d/%d/%d,%d:%d:%d", t->tm_mday, t->tm_mon + 1, t->tm_year + 1900, t->tm_hour, t->tm_min, t->tm_sec);
    return command(cmd, GSRES_NORMAL);
}

time_t GSwifi::getTime () {

    if (command("AT+GETTIME=?", GSRES_TIME)) {
        return 0;
    }
    return _time;
}

int GSwifi::gpioOut (int port, int out) {
    char cmd[GS_CMD_SIZE];

    if (_status != GSSTAT_READY) return -1;

    sprintf(cmd, "AT+DGPIO=%d,%d", port, out);
    return command(cmd, GSRES_NORMAL);
}

void GSwifi::poll_cmd () {
    int i;

    while (_gs_enter) {
        // received "\n"
        char buf[GS_CMD_SIZE];

        wait_ms(10);
        _gs_enter --;
        i = 0;
        while (_buf_cmd.use() && i < sizeof(buf)) {
            _buf_cmd.get(&buf[i]);
            if (buf[i] == '\n') {
                break;
            }
            i ++;
        }
        buf[i] = 0;
        DBG("poll: %s\r\n", buf);

        if (i == 0) {
        } else
        if (strncmp(buf, "CONNECT", 7) == 0 && buf[8] >= '0' && buf[8] <= 'F') {
            int cid = x2i(buf[8]);
            if (_gs_sock[cid].type == GSTYPE_SERVER) {
                int acid, ip1, ip2, ip3, ip4;
                char *tmp = buf + 12;

                acid = x2i(buf[10]);
                DBG("connect %d -> %d\r\n", cid, acid);
                newSock(acid, _gs_sock[cid].type, _gs_sock[cid].protocol, _gs_sock[cid].onGsReceive);
                _gs_sock[acid].lcid = cid;
                sscanf(tmp, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4);
                _gs_sock[acid].host.setIp(IpAddr(ip1, ip2, ip3, ip4));
                tmp = strstr(tmp, " ") + 1;
                _gs_sock[acid].host.setPort(atoi(tmp));

#ifdef GS_USE_HTTPD
                if (_gs_sock[acid].protocol == GSPROT_HTTPD) {
                    poll_httpd(acid, 0);
                } else
#endif
                if (_gs_sock[acid].onGsReceive != NULL) {
                    _gs_sock[acid].onGsReceive(acid, 0); // event connected
                }
            }
        } else
        if (strncmp(buf, "DISCONNECT", 10) == 0) {
            int cid = x2i(buf[11]);
            DBG("disconnect %d\r\n", cid);
            _gs_sock[cid].connect = false;

#ifdef GS_USE_HTTPD
            if (_gs_sock[cid].protocol == GSPROT_HTTPD) {
                poll_httpd(cid, 0);
            } else
#endif
            if (_gs_sock[cid].onGsReceive != NULL) {
                _gs_sock[cid].onGsReceive(cid, 0); // event disconnected
            }
        } else
        if (strncmp(buf, "DISASSOCIATED", 13) == 0 ||
          strncmp(buf, "Disassociated", 13) == 0 ||
          strncmp(buf, "Disassociation Event", 20) == 0 ||
          strncmp(buf, "UnExpected Warm Boot", 20) == 0) {
            _connect = false;
            for (i = 0; i < 16; i ++) {
                _gs_sock[i].connect = false;
            }
        } else
        if (strncmp(buf, "Out of StandBy-Timer", 20) == 0 ||
          strncmp(buf, "Out of StandBy-Alarm", 20) == 0) {
//            if (_status == GSSTAT_STANDBY) {
                _status = GSSTAT_WAKEUP;
//            }
        } else 
        if (strncmp(buf, "Out of Deep Sleep", 17) == 0 ) {
//            if (_status == GSSTAT_DEEPSLEEP) {
                _status = GSSTAT_READY;
//            }
        } else 
        if (strncmp(buf, "Out of", 6) == 0) {
        }
        DBG("status: %d\r\n", _status);
    }
}

void GSwifi::poll () {
    int i, j;

    poll_cmd();

    for (i = 0; i < 16; i ++) {
//        if (_gs_sock[i].connect && _gs_sock[i].received) {
        if (_gs_sock[i].received && _gs_sock[i].data->use()) {
            // recv interrupt
            _gs_sock[i].received = 0;
#ifdef GS_USE_HTTPD
            if (_gs_sock[i].protocol == GSPROT_HTTPD) {
                for (j = 0; j < 1500 / GS_DATA_SIZE + 1; j ++) {
                    if (! _gs_sock[i].connect || ! _gs_sock[i].data->use()) break;
                    poll_httpd(i, _gs_sock[i].data->use());
                }
            } else
#endif
            if (_gs_sock[i].onGsReceive != NULL) {
                for (j = 0; j < 1500 / GS_DATA_SIZE + 1; j ++) {
                    if (! _gs_sock[i].connect || ! _gs_sock[i].data->use()) break;
                    _gs_sock[i].onGsReceive(i, _gs_sock[i].data->use());
                }
            }
        }
    }
}

void GSwifi::newSock (int cid, GSTYPE type, GSPROTOCOL pro, onGsReceiveFunc ponGsReceive) {
    _gs_sock[cid].type = type;
    _gs_sock[cid].protocol = pro;
    _gs_sock[cid].connect = true;
    if (_gs_sock[cid].data == NULL) {
        _gs_sock[cid].data = new RingBuffer(GS_DATA_SIZE);
    } else {
        _gs_sock[cid].data->clear();
    }
    _gs_sock[cid].lcid = 0;
    _gs_sock[cid].received = 0;
    _gs_sock[cid].onGsReceive = ponGsReceive;
}

int GSwifi::open (Host &host, GSPROTOCOL pro, onGsReceiveFunc ponGsReceive) {
    char cmd[GS_CMD_SIZE];

    if (! _connect || _status != GSSTAT_READY) return -1;
    if (host.getIp().isNull() || host.getPort() == 0) {
        return -1;
    }

    if (pro == GSPROT_UDP) {
        sprintf(cmd, "AT+NCUDP=%d.%d.%d.%d,%d", host.getIp()[0], host.getIp()[1], host.getIp()[2], host.getIp()[3], host.getPort());
    } else {
        sprintf(cmd, "AT+NCTCP=%d.%d.%d.%d,%d", host.getIp()[0], host.getIp()[1], host.getIp()[2], host.getIp()[3], host.getPort());
    }
    if (command(cmd, GSRES_CONNECT)) return -1;

    newSock(_cid, GSTYPE_CLIENT, pro, ponGsReceive);
    return _cid;
}

int GSwifi::listen (int port, GSPROTOCOL pro, onGsReceiveFunc ponGsReceive) {
    char cmd[GS_CMD_SIZE];

    if (! _connect || _status != GSSTAT_READY) return -1;
    if (port == 0) {
        return -1;
    }

    if (pro == GSPROT_UDP) {
        sprintf(cmd, "AT+NSUDP=%d", port);
    } else {
        sprintf(cmd, "AT+NSTCP=%d", port);
    }
    if (command(cmd, GSRES_CONNECT)) return -1;

    newSock(_cid, GSTYPE_SERVER, pro, ponGsReceive);
    return _cid;
}

int GSwifi::close (int cid) {
    char cmd[GS_CMD_SIZE];

    if (! _gs_sock[cid].connect) return -1;

    _gs_sock[cid].connect = false;
    delete _gs_sock[cid].data;
    _gs_sock[cid].data = NULL;
    sprintf(cmd, "AT+NCLOSE=%X", cid);
    return command(cmd, GSRES_NORMAL);    
}

int GSwifi::send (int cid, const char *buf, int len) {
    int i;
    Timer timeout;

    if (! _gs_sock[cid].connect) return -1;

    if ((_gs_sock[cid].protocol == GSPROT_TCP) ||
      (_gs_sock[cid].protocol == GSPROT_UDP && _gs_sock[cid].type == GSTYPE_CLIENT) ||
      (_gs_sock[cid].protocol == GSPROT_HTTPD)) {
        // TCP Client, TCP Server, UDP Client
        _gs_ok = 0;
        _gs_failure = 0;
#ifdef GS_BULK
        _gs.printf("\x1bZ%X%04d", cid, len);
        for (i = 0; i < len; i ++) {
            _gs_putc(buf[i]);
//            DBG("%c", buf[i]);
        }
#else
        _gs.printf("\x1bS%X", cid);
        for (i = 0; i < len; i ++) {
            if (buf[i] >= 0x20 && buf[i] < 0x7f) {
                _gs_putc(buf[i]);
//                DBG("%c", buf[i]);
            }
        }
        _gs_putc(0x1b);
        _gs_putc('E');
#endif
    } else {
        return -1;
    }
    timeout.start();
    while (!_gs_ok && !_gs_failure && timeout.read_ms() < GS_TIMEOUT);
    return _gs_ok == 1 ? 0 : -1;
}

int GSwifi::send (int cid, const char *buf, int len, Host &host) {
    int i;
    Timer timeout;

    if (! _gs_sock[cid].connect) return -1;

    if ((_gs_sock[cid].protocol == GSPROT_UDP && _gs_sock[cid].type == GSTYPE_SERVER)) {
        // UDP Server
        _gs_ok = 0;
        _gs_failure = 0;
#ifdef GS_BULK
        _gs.printf("\x1bY%X", cid);
        _gs.printf("%d.%d.%d.%d:%d:", host.getIp()[0], host.getIp()[1], host.getIp()[2], host.getIp()[3], host.getPort());
        _gs.printf("%04d", len);
        for (i = 0; i < len; i ++) {
            _gs_putc(buf[i]);
//            DBG("%c", buf[i]);
        }
#else
        _gs.printf("\x1bU%X", cid);
        _gs.printf("%d.%d.%d.%d:%d:", host.getIp()[0], host.getIp()[1], host.getIp()[2], host.getIp()[3], host.getPort());
        for (i = 0; i < len; i ++) {
            if (buf[i] >= 0x20 && buf[i] < 0x7f) {
                _gs_putc(buf[i]);
//                DBG("%c", buf[i]);
            }
        }
        _gs_putc(0x1b);
        _gs_putc('E');
#endif
    } else {
        return -1;
    }
    timeout.start();
    while (!_gs_ok && !_gs_failure && timeout.read_ms() < GS_TIMEOUT);
    return _gs_ok == 1 ? 0 : -1;
}

int GSwifi::recv (int cid, char *buf, int len) {
    int r;
    Timer timeout;
    
    if (_gs_sock[cid].data == NULL) return 0;

    timeout.start();
    while (_gs_sock[cid].data->use() == 0) {
        if (timeout.read_ms() > GS_TIMEOUT) return 0;
    }
    timeout.stop();

    r = _gs_sock[cid].data->get(buf, len);
    return r;
}

int GSwifi::recv (int cid, char *buf, int len, Host &host) {
    int r;
    Timer timeout;
    
    if (_gs_sock[cid].data == NULL) return 0;

    timeout.start();
    while (_gs_sock[cid].data->use() == 0) {
        if (timeout.read_ms() > GS_TIMEOUT) return 0;
    }
    timeout.stop();

    r = _gs_sock[cid].data->get(buf, len);
    host = _from;
    return r;
}

bool GSwifi::isConnected (int cid) {
    return _gs_sock[cid].connect;
}

int GSwifi::httpGet (Host &host, const char *uri, const char *user, const char *pwd, int ssl, onGsReceiveFunc ponGsReceive) {
    char cmd[GS_CMD_SIZE];

    if (! _connect || _status != GSSTAT_READY) return -1;

    if (host.getIp().isNull()) {
        if (getHostByName(host)) {
            if (getHostByName(host)) return -1;
        }
    }
    if (host.getPort() == 0) {
        if (ssl) {
            host.setPort(443);
        } else {
            host.setPort(80);
        }
    }

    command("AT+HTTPCONF=3,close", GSRES_NORMAL); // Connection:
    sprintf(cmd, "AT+HTTPCONF=11,%s", host.getName());  // Host:
    command(cmd, GSRES_NORMAL);
    if (user && pwd) {
        char tmp[GS_CMD_SIZE], tmp2[GS_CMD_SIZE];
        snprintf(tmp, sizeof(tmp), "%s:%s", user, pwd);
        base64encode(tmp, strlen(tmp), tmp2, sizeof(tmp2));
        sprintf(cmd, "AT+HTTPCONF=2,Basic %s", tmp2);  // Authorization:
        command(cmd, GSRES_NORMAL);
    } else {
        command("AT+HTTPCONFDEL=2", GSRES_NORMAL);
    }
    command("AT+HTTPCONFDEL=5", GSRES_NORMAL);
    command("AT+HTTPCONFDEL=7", GSRES_NORMAL);

    sprintf(cmd, "AT+HTTPOPEN=%d.%d.%d.%d,%d", host.getIp()[0], host.getIp()[1], host.getIp()[2], host.getIp()[3], host.getPort());
    if (ssl) {
        strcat(cmd, ",1");
    }
    if (command(cmd, GSRES_HTTP)) return -1;
    newSock(_cid, GSTYPE_CLIENT, GSPROT_HTTPGET, ponGsReceive);

    sprintf(cmd, "AT+HTTPSEND=%d,1,%d,%s", _cid, GS_TIMEOUT / 1000, uri);  // GET
    command(cmd, GSRES_NORMAL);

    return _cid;
}

int GSwifi::httpGet (Host &host, const char *uri, int ssl, onGsReceiveFunc ponGsReceive) {
    return httpGet (host, uri, NULL, NULL, ssl, ponGsReceive);
}

int GSwifi::httpPost (Host &host, const char *uri, const char *body, const char *user, const char *pwd, int ssl, onGsReceiveFunc ponGsReceive) {
    char cmd[GS_CMD_SIZE];
    int i, len;

    if (! _connect || _status != GSSTAT_READY) return -1;

    if (host.getIp().isNull()) {
        if (getHostByName(host)) {
            if (getHostByName(host)) return -1;
        }
    }
    if (host.getPort() == 0) {
        if (ssl) {
            host.setPort(443);
        } else {
            host.setPort(80);
        }
    }
    len = strlen(body);

    command("AT+HTTPCONF=3,close", GSRES_NORMAL); // Connection:
    sprintf(cmd, "AT+HTTPCONF=11,%s", host.getName());  // Host:
    command(cmd, GSRES_NORMAL);
    sprintf(cmd, "AT+HTTPCONF=5,%d", len);  // Content-Length:
    command(cmd, GSRES_NORMAL);
    command("AT+HTTPCONF=7,application/x-www-form-urlencoded", GSRES_NORMAL); // Content-type:
    if (user && pwd) {
        char tmp[GS_CMD_SIZE], tmp2[GS_CMD_SIZE];
        snprintf(tmp, sizeof(tmp), "%s:%s", user, pwd);
        base64encode(tmp, strlen(tmp), tmp2, sizeof(tmp2));
        sprintf(cmd, "AT+HTTPCONF=2,Basic %s", tmp2);  // Authorization:
        command(cmd, GSRES_NORMAL);
    } else {
        command("AT+HTTPCONFDEL=2", GSRES_NORMAL);
    }

    sprintf(cmd, "AT+HTTPOPEN=%d.%d.%d.%d,%d", host.getIp()[0], host.getIp()[1], host.getIp()[2], host.getIp()[3], host.getPort());
    if (ssl) {
        strcat(cmd, ",1");
    }
    if (command(cmd, GSRES_HTTP)) return -1;
    newSock(_cid, GSTYPE_CLIENT, GSPROT_HTTPPOST, ponGsReceive);

    sprintf(cmd, "AT+HTTPSEND=%d,3,%d,%s,%d", _cid, GS_TIMEOUT / 1000, uri, len);  // POST
    command(cmd, GSRES_NORMAL);

    _gs.printf("\x1bH%X", _cid);
    for (i = 0; i < len; i ++) {
        _gs_putc(body[i]);
        DBG("%c", body[i]);
    }

    return _cid;
}

int GSwifi::httpPost (Host &host, const char *uri, const char *body, int ssl, onGsReceiveFunc ponGsReceive) {
    return httpPost (host, uri, body, NULL, NULL, ssl, ponGsReceive);
}

int GSwifi::certAdd (const char *name, const char *cert, int len) {
    int i;
    char cmd[GS_CMD_SIZE];

    if (! _connect || _status != GSSTAT_READY) return -1;

    sprintf(cmd, "AT+TCERTADD=%s,1,%d,1", name, len);  // Hex, ram
    command(cmd, GSRES_NORMAL);
    
    _gs_putc(0x1b);
    _gs_putc('W');
    for (i = 0; i < len; i ++) {
        _gs_putc(cert[i]);
    }
    return cmdResponse(GSRES_NORMAL, GS_TIMEOUT);
}

int GSwifi::base64encode (char *input, int length, char *output, int len) {
    // code from 
    // Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
    static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    unsigned int c, c1, c2, c3;

    if (len < ((((length-1)/3)+1)<<2)) return -1;
    for(unsigned int i = 0, j = 0; i<length; i+=3,j+=4) {
        c1 = ((((unsigned char)*((unsigned char *)&input[i]))));
        c2 = (length>i+1)?((((unsigned char)*((unsigned char *)&input[i+1])))):0;
        c3 = (length>i+2)?((((unsigned char)*((unsigned char *)&input[i+2])))):0;

        c = ((c1 & 0xFC) >> 2);
        output[j+0] = base64[c];
        c = ((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4);
        output[j+1] = base64[c];
        c = ((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6);
        output[j+2] = (length>i+1)?base64[c]:'=';
        c = (c3 & 0x3F);
        output[j+3] = (length>i+2)?base64[c]:'=';
    }
    output[(((length-1)/3)+1)<<2] = '\0';
    return 0;
}

int GSwifi::from_hex (int ch) {
  return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
}

int GSwifi::to_hex (int code) {
  static char hex[] = "0123456789abcdef";
  return hex[code & 15];
}

int GSwifi::urlencode (char *str, char *buf, int len) {
    // code from 
    // Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
//  char *pstr = str, *buf = (char*)malloc(strlen(str) * 3 + 1), *pbuf = buf;
    char *pstr = str, *pbuf = buf;

    if (len < (strlen(str) * 3 + 1)) return -1;
    while (*pstr) {
        if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') 
            *pbuf++ = *pstr;
        else if (*pstr == ' ') 
            *pbuf++ = '+';
        else 
            *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
        pstr++;
    }
    *pbuf = '\0';
    return 0;
}

int GSwifi::urldecode (char *str, char *buf, int len) {
    // code from 
    // Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
//  char *pstr = str, *buf = (char*)malloc(strlen(str) + 1), *pbuf = buf;
    char *pstr = str, *pbuf = buf;

    if (len < (strlen(str) / 3 - 1)) return -1;
    while (*pstr) {
        if (*pstr == '%') {
            if (pstr[1] && pstr[2]) {
                *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
                pstr += 2;
            }
        } else if (*pstr == '+') { 
            *pbuf++ = ' ';
        } else {
            *pbuf++ = *pstr;
        }
        pstr++;
    }
    *pbuf = '\0';
    return 0;
}

int GSwifi::x2i (char c) {
    if (c >= '0' && c <= '9') {
        return c - '0';
    } else
    if (c >= 'A' && c <= 'F') {
        return c - 'A' + 10;
    } else
    if (c >= 'a' && c <= 'f') {
        return c - 'a' + 10;
    }
    return 0;
}

char GSwifi::i2x (int i) {
    if (i >= 0 && i <= 9) {
        return i + '0';
    } else
    if (i >= 10 && i <= 15) {
        return i - 10 + 'A';
    }
    return 0;
}


#ifdef DEBUF
// for test

void GSwifi::test () {
/*
    command(NULL, GSRES_NORMAL);
    wait_ms(100);
    command("AT+NCLOSEALL", GSRES_NORMAL);
    _connect = true;
*/
    command("AT+WRXACTIVE=1", GSRES_NORMAL);
}

int GSwifi::getc() {
    char c;
    if (_buf_cmd.use()) {
        _buf_cmd.get(&c);
    }
/*
    } else
    if (_gs_sock[0].data != NULL) {
        _gs_sock[0].data->get(&c);
    }
*/
    return c;
}

void GSwifi::putc(char c) {
    _gs_putc(c);
}

int GSwifi::readable() {
    return _buf_cmd.use();
//    return _buf_cmd.use() || (_gs_sock[0].data != NULL && _gs_sock[0].data->use());
}
#endif