private fork
Fork of GSwifiInterface by
Diff: GSwifi/GSwifi.cpp
- Revision:
- 5:78943b3945b5
- Parent:
- 4:0bcec6272784
- Child:
- 7:f94c59d0c735
- Child:
- 8:64184a968e3b
diff -r 0bcec6272784 -r 78943b3945b5 GSwifi/GSwifi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GSwifi/GSwifi.cpp Sun Jan 27 14:31:19 2013 +0000 @@ -0,0 +1,669 @@ +/* Copyright (C) 2012 mbed.org, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +/* Copyright (C) 2013 gsfan, MIT License + * port to the GainSpan Wi-FI module GS1011 + */ + +#include "mbed.h" +#include "GSwifi.h" +#include <string> +#include <algorithm> + +GSwifi * GSwifi::_inst; + +GSwifi::GSwifi( PinName tx, PinName rx, PinName cts, PinName rts, PinName reset, const char * ssid, const char * phrase, Security sec): + _uart(tx, rx), _reset(reset), _buf_gswifi(CFG_CMD_SIZE) +{ + memset(&_state, 0, sizeof(_state)); + memset(&_con, 0, sizeof(_con)); + _state.sec = sec; + _state.acid = -1; + + // change all ' ' in '$' in the ssid and the passphrase + strncpy(_ssid, ssid, sizeof(_ssid)); + for (int i = 0; i < strlen(ssid); i++) { + if (_ssid[i] == ' ') + _ssid[i] = '$'; + } + strncpy(_phrase, phrase, sizeof(_phrase)); + for (int i = 0; i < strlen(phrase); i++) { + if (_phrase[i] == ' ') + _phrase[i] = '$'; + } + + _inst = this; + _state.mode = MODE_COMMAND; + +#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) + if (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 (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 (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 (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.baud(CFG_UART_BAUD); + _uart.attach(this, &GSwifi::handler_rx); + this->reset(); +} + +bool GSwifi::join() +{ + bool r; + char cmd[CFG_CMD_SIZE]; + + send("\r\n", 2); + if (sendCommand("ATE0") == false) return -1; + if (_rts) { + sendCommand("AT&K0"); + sendCommand("AT&R1"); + } + + disconnect(); + sendCommand("AT+WREGDOMAIN=" CFG_WREGDOMAIN); + sendCommand("AT+BDATA=1"); + sendCommand("AT+WM=0"); // infrastructure + wait_ms(100); + if (_state.dhcp && _state.sec != SEC_WPS_BUTTON) { + sendCommand("AT+NDHCP=1"); + } else { + sendCommand("AT+NDHCP=0"); + } + + switch (_state.sec) { + case SEC_NONE: + case SEC_OPEN: + case SEC_WEP: + sprintf(cmd, "AT+WAUTH=%d", _ssid); + sendCommand(cmd); + if (_state.sec != SEC_NONE) { + sprintf(cmd, "AT+WWEP1=%s", _phrase); + sendCommand(cmd); + wait_ms(100); + } + sprintf(cmd, "AT+WA=%s", _ssid); + for (int i= 0; i < MAX_TRY_JOIN; i++) { + r = sendCommand(cmd, RES_DHCP, CFG_TIMEOUT2); + if (r) break; + } + break; + case SEC_WPA_PSK: + case SEC_WPA2_PSK: + sendCommand("AT+WAUTH=0"); + sprintf(cmd, "AT+WPAPSK=%s,%s", _ssid, _phrase); + sendCommand(cmd, RES_NORMAL, CFG_TIMEOUT2); + wait_ms(100); + sprintf(cmd, "AT+WA=%s", _ssid); + for (int i= 0; i < MAX_TRY_JOIN; i++) { + r = sendCommand(cmd, RES_DHCP, CFG_TIMEOUT2); + if (r) break; + } + break; + case SEC_WPS_BUTTON: + sendCommand("AT+WAUTH=0"); + for (int i= 0; i < MAX_TRY_JOIN; i++) { + r = sendCommand("AT+WWPS=1", RES_WPS, CFG_TIMEOUT2); + if (r) break; + } + if (r && _state.dhcp) { + r = sendCommand("AT+NDHCP=1", RES_DHCP, CFG_TIMEOUT2); + } + break; + default: + DBG("Can't use security\r\n"); + r = false; + break; + } + + if (r) { + if (!_state.dhcp) { + sprintf(cmd, "AT+NSET=%s,%s,%s", _ip, _netmask, _gateway); + sendCommand(cmd); + sprintf(cmd, "AT+DNSSET=%s", _nameserver); + sendCommand(cmd); + } + + _state.associated = true; + INFO("ssid: %s\r\nphrase: %s\r\nsecurity: %d", _ssid, _phrase, _state.sec); + } + + return r; +} + + +bool GSwifi::gethostbyname(const char * host, char * ip) +{ + int i, flg = 0; + char cmd[CFG_CMD_SIZE]; + + for (i = 0; i < strlen(host); i ++) { + if ((host[i] < '0' || host[i] > '9') && host[i] != '.') { + flg = 1; + break; + } + } + if (!flg) { + strncpy(ip, host, 16); + return true; + } + + sprintf(cmd, "AT+DNSLOOKUP=%s", host); + if (sendCommand(cmd, RES_DNSLOOKUP)) { + strncpy(ip, _resolv, 16); + return true; + } + + return false; +} + + +void GSwifi::flush(int cid) +{ + if (cid < 0) { + return _buf_gswifi.flush(); + } else { + if (_con[cid].buf == NULL) + _con[cid].buf = new CircBuffer<char>(CFG_DATA_SIZE); + return _con[cid].buf->flush(); + } +} + +bool GSwifi::sendCommand(const char * cmd, Response res, int timeout) +{ + DBG("command: %s",cmd); + + send(cmd, strlen(cmd)); + if (send("\r\n", 2, res, timeout) == -1) { + ERR("sendCommand: cannot %s", cmd); + return false; + } + return true; +} + + +bool GSwifi::disconnect() +{ + // if already disconnected, return + if (!_state.associated) + return true; + + for (int i = 0; i < 16; i ++) { + if (_con[i].buf) + _con[i].buf->flush(); + } + sendCommand("AT+NCLOSEALL"); + sendCommand("AT+WD"); + sendCommand("AT+NDHCP=0"); + wait_ms(100); + + _state.associated = false; + return true; + +} + +bool GSwifi::is_connected(int cid) +{ + return _con[cid].connected; +} + + +void GSwifi::reset() +{ + _reset = 0; + wait_ms(100); + _reset = 1; + wait_ms(500); +} + + +int GSwifi::putc(char c) +{ + while (!_uart.writeable()); + return _uart.putc(c); +} + + +int GSwifi::readable(int cid) +{ + if (cid < 0) { + return _buf_gswifi.available(); + } else { + return _con[cid].buf->available(); + } +} + +int GSwifi::writeable() +{ + return _uart.writeable(); +} + +char GSwifi::getc(int cid) +{ + char c; + if (cid < 0) { + while (!_buf_gswifi.available()); + _buf_gswifi.dequeue(&c); + } else { + while (!_con[cid].buf->available()); + _con[cid].buf->dequeue(&c); + } + return c; +} + +void GSwifi::handler_rx(void) +{ + static int len, flg; + static char tmp[20]; + char dat; + + while (_uart.readable()) { + + dat = _uart.getc(); + + switch (_state.mode) { + case MODE_COMMAND: // command responce + if (_state.escape) { + // esc + switch (dat) { + case 'O': + DBG("ok"); + _state.retres = RES_OK; + _state.cmdres = RES_OK; + break; + case 'F': + DBG("failure"); + _state.retres = RES_FAILURE; + _state.cmdres = RES_FAILURE; + break; + case 'Z': + case 'H': + DBG("GSMODE_DATA_RX"); + _state.mode = MODE_DATA_RX; + flg = 0; + break; + case 'y': + DBG("GSMODE_DATA_RXUDP"); + _state.mode = MODE_DATA_RXUDP; + flg = 0; + break; + case 'S': + case 'u': + default: + WARN("unknown [ESC] %02x", dat); + break; + } + _state.escape = 0; + } else { + if (dat == 0x1b) { + _state.escape = 1; + } else + if (dat == '\n') { + parseResponse(); + } else + if (dat != '\r') { + // command + _buf_gswifi.queue(dat); + } + } + break; + + case MODE_DATA_RX: + case MODE_DATA_RXUDP: + switch (flg) { + case 0: + // CID + _state.cid = x2i(dat); + flg ++; + if (_state.mode == MODE_DATA_RX) { + flg = 3; + } + len = 0; + break; + case 1: + // IP (UDP) + if ((dat >= '0' && dat <= '9') || dat == '.') { + tmp[len] = dat; + len ++; + } else + if (len < sizeof(tmp) - 1) { + tmp[len] = 0; + strncpy(_con[_state.cid].ip, tmp, sizeof(_con[_state.cid].ip)); + flg ++; + len = 0; + } + break; + case 2: + // port + if (dat >= '0' && dat <= '9') { + tmp[len] = dat; + len ++; + } else { + tmp[len] = 0; + _con[_state.cid].port = atoi(tmp); + flg ++; + len = 0; + } + break; + case 3: + // length + tmp[len] = dat; + len ++; + if (len >= 4) { + tmp[len] = 0; + len = atoi(tmp); + flg ++; + } + break; + case 4: + // data + if (_con[_state.cid].buf != NULL) { + _con[_state.cid].buf->queue(dat); + } + len --; + + if (len == 0 || _con[_state.cid].buf->isFull()) { + DBG("recv binary %d", _state.cid); + _state.escape = 0; + _state.mode = MODE_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; + } + + break; + } + + } // while +} + +void GSwifi::parseResponse () { + int i; + char buf[CFG_CMD_SIZE]; + + while (_buf_gswifi.available()) { + i = 0; + while (_buf_gswifi.available() && i < sizeof(buf)) { + _buf_gswifi.dequeue(&buf[i]); + if (buf[i] == '\n') { + break; + } + i ++; + } + if (i == 0) continue; + buf[i] = 0; + DBG("parseResponse: %s", buf); + + if (_state.cmdres != RES_NULL) { + parseCmdResponse(buf); + DBG("parseCmdResponse %d %d", _state.cmdres, _state.retres); + } + + if (strncmp(buf, "CONNECT ", 8) == 0 && buf[8] >= '0' && buf[8] <= 'F' && buf[9] != 0) { + int cid; + char *tmp, *tmp2; + cid = x2i(buf[8]); + _state.acid = x2i(buf[10]); + tmp = buf + 12; + tmp2 = strstr(tmp, " "); + tmp2[0] = 0; + strncpy(_con[_state.acid].ip, tmp, sizeof(_con[_state.acid].ip)); + tmp = tmp2 + 1; + _con[_state.acid].port = atoi(tmp); + _con[_state.acid].parent = cid; + if (_con[_state.acid].buf == NULL) + _con[_state.acid].buf = new CircBuffer<char>(CFG_DATA_SIZE); + _con[_state.acid].buf->flush(); + _con[_state.acid].connected = true; + DBG("connect %d -> %d", cid, _state.acid); + } else + if (strncmp(buf, "DISCONNECT ", 11) == 0) { + int cid; + cid = x2i(buf[11]); + DBG("disconnect %d", cid); + _con[cid].connected = false; + } 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) { + _state.associated = false; + for (i = 0; i < 16; i ++) { + _con[i].connected = false; + } + } else + if (strncmp(buf, "Out of StandBy-Timer", 20) == 0 || + strncmp(buf, "Out of StandBy-Alarm", 20) == 0) { + _state.status = STAT_WAKEUP; + } else + if (strncmp(buf, "Out of Deep Sleep", 17) == 0 ) { + _state.status = STAT_READY; + } else + if (strncmp(buf, "Out of", 6) == 0) { + } + } +} + +void GSwifi::parseCmdResponse (char *buf) { + + if (strcmp(buf, "OK") == 0) { + _state.retres = RES_OK; + } else + if (strncmp(buf, "ERROR", 5) == 0) { + _state.retres = RES_FAILURE; + } + + switch(_state.cmdres) { + case RES_NORMAL: + _state.cmdres = RES_OK; + break; + case RES_WPS: + if (_state.n == 0 && strncmp(buf, "SSID", 4) == 0) { + _state.n ++; + } else + if (_state.n == 1 && strncmp(buf, "CHANNEL", 7) == 0) { + _state.n ++; + } else + if (_state.n == 2 && strncmp(buf, "PASSPHRASE", 10) == 0) { + _state.n ++; + _state.cmdres = RES_OK; + } + break; + case RES_CONNECT: + if (strncmp(buf, "CONNECT ", 8) == 0 && buf[9] == 0) { + _state.cid = x2i(buf[8]); + _state.cmdres = RES_OK; + if (_con[_state.cid].buf == NULL) + _con[_state.cid].buf = new CircBuffer<char>(CFG_DATA_SIZE); + _con[_state.cid].buf->flush(); + _con[_state.cid].connected = true; + INFO("connect: %d", _state.cid); + } + break; + case RES_DHCP: + if (_state.n == 0 && strstr(buf, "SubNet") && strstr(buf, "Gateway")) { + _state.n ++; + } else + if (_state.n == 1) { + char *tmp, *tmp2; + tmp = buf + 1; + tmp2 = strstr(tmp, ":"); + tmp2[0] = 0; + strncpy(_ip, tmp, sizeof(_ip)); + tmp = tmp2 + 2; + tmp2 = strstr(tmp, ":"); + tmp2[0] = 0; + strncpy(_netmask, tmp, sizeof(_netmask)); + tmp = tmp2 + 2; + strncpy(_gateway, tmp, sizeof(_gateway)); + _state.n ++; + _state.cmdres = RES_OK; + INFO("ip: %s\r\nnetmask: %s\r\ngateway: %s", _ip, _netmask, _gateway); + } + break; + case RES_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; +*/ + _state.cmdres = RES_OK; + } + break; + case RES_DNSLOOKUP: + if (strncmp(buf, "IP:", 3) == 0) { + strncpy(_resolv, &buf[3], sizeof(_resolv)); + _state.cmdres = RES_OK; + INFO("resolv: %s", _resolv); + } + break; + case RES_HTTP: + if (buf[0] >= '0' && buf[0] <= 'F') { + _state.cid = x2i(buf[0]); + _state.cmdres = RES_OK; + INFO("http: %d", _state.cid); + } + break; + case RES_RSSI: + if (buf[0] == '-' || (buf[0] >= '0' && buf[0] <= '9')) { + _rssi = atoi(buf); + _state.cmdres = RES_OK; + INFO("rssi: %d", _rssi); + } + break; + case RES_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); + _state.cmdres = RES_OK; + } + break; + } +} + +int GSwifi::send(const char * str, int len, Response res, int timeout) +{ + Timer tmr; + int result = 0; + + if (res == RES_NULL) { + for (int i = 0; i < len; i++) + result = (putc(str[i]) == str[i]) ? result + 1 : result; + } else { + _state.cmdres = res; + _state.retres = RES_NULL; + + tmr.start(); + for (int i = 0; i < len; i++) + result = (putc(str[i]) == str[i]) ? result + 1 : result; + + while (1) { + if (tmr.read_ms() > timeout || _state.retres == RES_FAILURE) { + result = -1; + break; + } + if (_state.retres == RES_OK && _state.cmdres != res) break; + } + } + + _state.cmdres = RES_NULL; + _state.retres = RES_NULL; + return result; +} + +bool GSwifi::readRemote(int cid, char **ip, int *port) { + *ip = _con[cid].ip; + *port = _con[cid].port; + return true; +} + +int GSwifi::readCID () { + return _state.cid; +} + +int GSwifi::readACID () { + int r = -1; + if (_state.acid >= 0 && _con[_state.acid].connected == true) { + r = _state.acid; + _state.acid = -1; + } + return r; +} + +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; +}