GainSpan Wi-Fi library see: http://mbed.org/users/gsfan/notebook/gainspan_wifi/

Fork of GSwifi_old by gs fan

GainSpan Wi-Fi library

The GS1011 is an ultra low power 802.11b wireless module from GainSpan.

see: http://mbed.org/users/gsfan/notebook/gainspan_wifi/

Information

Please change the baud rate in advance.

  • ATB=115200
  • AT&W0

It may be better and sometimes faster.
GSwifi gs(p13, p14, baud);

Heavily modified new library: http://mbed.org/users/gsfan/code/GSwifi

ゲインスパン Wi-Fi モジュール ライブラリ

ゲインスパン社の低電力 Wi-Fiモジュール(無線LAN) GS1011 シリーズ用のライブラリです。

解説: http://mbed.org/users/gsfan/notebook/gainspan_wifi/

Information

モジュールはあらかじめ次のコマンドでボーレートを変更しておく。

  • ATB=115200
  • AT&W0

場合によってはもっと高速の方がいいかもしれない。クラス宣言時にレート設定をする。
GSwifi gs(p13, p14, baud);

大幅に更新された新しいライブラリ: http://mbed.org/users/gsfan/code/GSwifi

GSwifi_httpd.cpp

Committer:
gsfan
Date:
2013-01-21
Revision:
23:a783c62c36d0
Parent:
22:9b077e2823ce
Child:
24:5c350ae2e703

File content as of revision 23:a783c62c36d0:

#include "dbg.h"
#include "mbed.h"
#include "GSwifi.h"
#include "sha1.h"
#include <string.h>

#ifdef GS_USE_HTTPD

#define MIMETABLE_NUM 8
struct {
    char ext[6];
    char type[24];
} mimetable[MIMETABLE_NUM] = {
    {".txt", "text/plain"},
    {".html", "text/html"},
    {".htm", "text/html"},
    {".css", "text/css"},
    {".js", "application/javascript"},
    {".jpg", "image/jpeg"},
    {".png", "image/png"},
    {".gif", "image/gif"},
};

int GSwifi::httpd (int port) {
    int i;
    char cmd[GS_CMD_SIZE];

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

    memset(&_httpd, 0, sizeof(_httpd));
    for (i = 0; i < 16; i ++) {
        _httpd[i].mode = GSHTTPDMODE_REQUEST;
    }
    _handler_count = 0;

    sprintf(cmd, "AT+NSTCP=%d", port);
    if (command(cmd, GSRES_CONNECT)) return -1;

    newSock(_cid, GSTYPE_SERVER, GSPROT_HTTPD, NULL);
/*
//    newSock(_cid, GSTYPE_SERVER, GSPROT_HTTPD, &GSwifi::poll_httpd);
//    newSock(_cid, GSTYPE_SERVER, GSPROT_HTTPD, reinterpret_cast<onGsReceiveFunc>(&GSwifi::poll_httpd));
    void (GSwifi::*f1)(int,int) = &GSwifi::poll_httpd;
    onGsReceiveFunc f2 = reinterpret_cast<onGsReceiveFunc>(f1);
    newSock(_cid, GSTYPE_SERVER, GSPROT_HTTPD, f2);
*/
    return _cid;
}

void GSwifi::poll_httpd (int cid, int len) {
    int i, j, flg = 0;
    char c;

    if (len == 0) {
        // start request
        _httpd[cid].mode = GSHTTPDMODE_REQUEST;
        _httpd[cid].len = 0;
        _httpd[cid].keepalive = 0;
#ifdef GS_USE_WEBSOCKET
        _httpd[cid].websocket = 0;
#endif
        return;
    }

#ifdef GS_USE_WEBSOCKET
    if (_httpd[cid].mode >= GSHTTPDMODE_WEBSOCKET) {
        poll_websocket(cid, len);
        return;
    }
#endif

  while (_gs_sock[cid].connect && _gs_sock[cid].data->use()) {
    flg = 0;
    if (_httpd[cid].buf == NULL) {
        _httpd[cid].buf = new char[HTTPD_BUF_SIZE];
    }
    // get 1 line
    for (j = 0; j < len; j ++) {
        _gs_sock[cid].data->get(&c);
        if (c == '\r') continue;
        if (c == '\n' && _httpd[cid].mode != GSHTTPDMODE_BODY) break;
        
        if (_httpd[cid].len < HTTPD_BUF_SIZE - 1) {
            _httpd[cid].buf[_httpd[cid].len] = c; 
        }
        _httpd[cid].len ++;
        if (_httpd[cid].mode == GSHTTPDMODE_BODY && _httpd[cid].len >= _httpd[cid].length) break; // end of body
    }
    if (j >= len) return; // continue
    if (_httpd[cid].len < HTTPD_BUF_SIZE) {
        _httpd[cid].buf[_httpd[cid].len] = 0;
        DBG("httpd %d: %d %s (%d)\r\n", cid, _httpd[cid].mode, _httpd[cid].buf, _httpd[cid].len);
    }

    // parse
    switch (_httpd[cid].mode) {
    case GSHTTPDMODE_REQUEST:
        if (strnicmp(_httpd[cid].buf, "GET ", 4) == 0) {
            _httpd[cid].type = GSPROT_HTTPGET;
            j = 4;
        } else
        if (strnicmp(_httpd[cid].buf, "POST ", 5) == 0) {
            _httpd[cid].type = GSPROT_HTTPPOST;
            j = 5;
        } else {
            _httpd[cid].mode = GSHTTPDMODE_ERROR;
            break;
        }

        // get uri
        for (i = j; i < _httpd[cid].len; i ++) {
            if (_httpd[cid].buf[i] == ' ') break;
        }
        i = i - j;
        if (i) {
            if (_httpd[cid].uri == NULL) {
                _httpd[cid].uri = new char[HTTPD_URI_SIZE];
            }
            strncpy(_httpd[cid].uri, &_httpd[cid].buf[j], i);
            _httpd[cid].uri[i] = 0;
        }
        _httpd[cid].mode = GSHTTPDMODE_HEAD;
        _httpd[cid].length = 0;
        DBG("uri: %s\r\n", _httpd[cid].uri);
        break;
        
    case GSHTTPDMODE_HEAD:
        if (_httpd[cid].len == 0) {
            // blank line (end of header)
            _httpd[cid].mode = GSHTTPDMODE_BODY;
            if (_httpd[cid].length == 0) flg = 1; // no body
#ifdef GS_USE_WEBSOCKET
            if (_httpd[cid].websocket && _httpd[cid].websocket_key) {
                // enter websocket
                _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET;
                _httpd[cid].len = 0;
                flg = 1;
            }
#endif
        } else
        if (strnicmp(_httpd[cid].buf, "Content-Length: ", 16) == 0) {
            _httpd[cid].length = atoi(&_httpd[cid].buf[16]);
        } else
        if (strnicmp(_httpd[cid].buf, "Connection: Keep-Alive", 22) == 0) {
            if (! _httpd[cid].keepalive) {
                _httpd[cid].keepalive = HTTPD_KEEPALIVE;
            }
#ifdef GS_USE_WEBSOCKET
        } else
        if (strnicmp(_httpd[cid].buf, "Upgrade: websocket", 18) == 0) {
            if (! _httpd[cid].websocket) _httpd[cid].websocket = 1;
        } else
        if (strnicmp(_httpd[cid].buf, "Sec-WebSocket-Version: ", 23) == 0) {
            _httpd[cid].websocket = atoi(&_httpd[cid].buf[23]);
        } else
        if (strnicmp(_httpd[cid].buf, "Sec-WebSocket-Key: ", 19) == 0) {
            if (_httpd[cid].websocket_key == NULL) {
                _httpd[cid].websocket_key = new char[30];
            }
            strncpy(_httpd[cid].websocket_key, &_httpd[cid].buf[19], 30);
#endif
        }
        break;

    case GSHTTPDMODE_BODY:
        if (_httpd[cid].len >= _httpd[cid].length) {
            DBG("body: %s\r\n", _httpd[cid].buf);
            flg = 1;
        }
        break;

    }

#ifdef GS_USE_WEBSOCKET
    if (flg && _httpd[cid].mode == GSHTTPDMODE_WEBSOCKET) {
        // websocket
        send_websocket_accept(cid);
        break; // break while

    } else
#endif
    if (flg) {
        // http request
        _httpd[cid].buf[_httpd[cid].len] = 0;

        i = get_handler(_httpd[cid].uri);
        if (i >= 0) {
            _httpd[cid].host = _gs_sock[cid].host;
            j = strlen(_handler[i].uri);
            _httpd[cid].file = &_httpd[cid].uri[j];
            _httpd[cid].query = NULL;
            for (; j < strlen(_httpd[cid].uri); j ++) {
                if (_httpd[cid].uri[j] == '?') {
                    // query string
                    _httpd[cid].uri[j] = 0;
                    _httpd[cid].query = &_httpd[cid].uri[j + 1];
                    break;
                }
            }

            if (_handler[i].dir) {
                // file
                httpd_request(cid, &_httpd[cid], _handler[i].dir);
                flg = 1;
            } else
            if (_handler[i].onHttpCgi) {
                // cgi
                _handler[i].onHttpCgi(cid, &_httpd[cid]);
                _httpd[cid].keepalive = 0;
                LOG("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]);
                LOG("%s %s %d 200 -\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length);
                flg = 1;
            }
        } else {
            // not found
            send_httpd_error(cid, 403);
        }
        
        if (_httpd[cid].keepalive) {
            _httpd[cid].mode = GSHTTPDMODE_REQUEST;
            _httpd[cid].len = 0;
            _httpd[cid].length = 0;
            _httpd[cid].keepalive --;
        } else {
            close(cid);
        }
    }

    if (_httpd[cid].mode == GSHTTPDMODE_ERROR) {
        send_httpd_error(cid, 400);
    }

    _httpd[cid].len = 0;
  } // while
}

int GSwifi::get_handler (char *uri) {
    int i, j;

    for (i = 0; i < _handler_count; i ++) {
        j = strlen(_handler[i].uri);
        if (strncmp(uri, _handler[i].uri, j) == NULL) {
            // found
            return i;
        }
    }
    return -1;
}

int GSwifi::httpd_request (int cid, GS_httpd *gshttpd, char *dir) {
    FILE *fp;
    int i, len;
    char buf[HTTPD_BUF_SIZE];
    char file[HTTPD_URI_SIZE];

    strcpy(file, dir);
    strcat(file, gshttpd->file);
    if (file[strlen(file) - 1] == '/') {
        strcat(file, "index.htm");
    }
    DBG("file: %s\r\n", file);
    
    fp = fopen(file, "r");
    if (fp) {
        send(cid, "HTTP/1.1 200 OK\r\n", 17);
        {
            // file size
            i = ftell(fp);
            fseek(fp, 0, SEEK_END);
            len = ftell(fp);
            fseek(fp, i, SEEK_SET);
        }
        sprintf(buf, "Content-Length: %d\r\n", len);
        send(cid, buf, strlen(buf));
        sprintf(buf, "Content-Type: %s\r\n", mimetype(file));
        send(cid, buf, strlen(buf));
        if (gshttpd->keepalive) {
            strcpy(buf, "Connection: Keep-Alive\r\n");
        } else {
            strcpy(buf, "Connection: close\r\n");
        }
        send(cid, buf, strlen(buf));
        strcpy(buf, "Server: GSwifi httpd\r\n");
        send(cid, buf, strlen(buf));
        send(cid, "\r\n", 2);

        for (;;) {
            i = fread(buf, sizeof(char), sizeof(buf), fp);
            if (i <= 0) break;
            if (! _gs_sock[cid].connect) break;
            send(cid, buf, i);
#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
            if (feof(fp)) break;
#endif
        }
        fclose(fp);
        LOG("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]);
        LOG("%s %s %d 200 %d\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length, len);
        return 0;
    }

    send_httpd_error(cid, 404);
    return -1;
}

char *GSwifi::mimetype (char *file) {
    int i, j;

    DBG("<%s>\r\n", file);
    for (i = 0; i < MIMETABLE_NUM; i ++) {
        j = strlen(mimetable[i].ext);
        if (strnicmp(&file[strlen(file) - j], mimetable[i].ext, j) == NULL) {
            return mimetable[i].type;
        }
    }
    return mimetable[0].type;
}

int GSwifi::strnicmp (char *p1, char *p2, int n) {
    int i, r;
    char c1, c2;
    
    for (i = 0; i < n; i ++) {
        c1 = (p1[i] >= 'a' && p1[i] <= 'z') ? p1[i] - ('a' - 'A'): p1[i];
        c2 = (p2[i] >= 'a' && p2[i] <= 'z') ? p2[i] - ('a' - 'A'): p2[i];
        r = c1 - c2;
        if (r) break;
    }
    return r;
}

void GSwifi::send_httpd_error (int cid, int err) {
    char buf[100], msg[30];
    
    switch (err) {
    case 400:
        strcpy(msg, "Bad Request");
        break;
    case 403:
        strcpy(msg, "Forbidden");
        break;
    case 404:
        strcpy(msg, "Not Found");
        break;
    case 500:
    default:
        strcpy(msg, "Internal Server Error");
        break;
    }
    DBG("httpd error: %d %d %s\r\n", cid, err, msg);
    
    sprintf(buf, "HTTP/1.1 %d %s\r\n", err, msg);
    send(cid, buf, strlen(buf));
    strcpy(buf, "Content-Type: text/html\r\n");
    send(cid, buf, strlen(buf));
    send(cid, "\r\n", 2);

    sprintf(buf, "<html><head><title>%d %s</title></head>\r\n", err, msg);
    send(cid, buf, strlen(buf));
    sprintf(buf, "<body><h1>%s</h1></body></html>\r\n", msg);
    send(cid, buf, strlen(buf));
    close(cid);
    LOG("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]);
    LOG("%s %s %d %d -\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length, err);
}

int GSwifi::attach_httpd (const char *uri, const char *dir) {
    if (_handler_count < HTTPD_HANDLE) {
        _handler[_handler_count].uri = new char[strlen(uri) + 1];
        strcpy(_handler[_handler_count].uri, uri);
        _handler[_handler_count].dir = new char[strlen(dir) + 1];
        strcpy(_handler[_handler_count].dir, dir);
        _handler[_handler_count].onHttpCgi = NULL;
        _handler_count ++;
        return 0;
    } else {
        return -1;
    }
}

int GSwifi::attach_httpd (const char *uri, onHttpdCgiFunc ponHttpCgi) {
    if (_handler_count < HTTPD_HANDLE) {
        _handler[_handler_count].uri = new char[strlen(uri) + 1];
        strcpy(_handler[_handler_count].uri, uri);
        _handler[_handler_count].dir = NULL;
        _handler[_handler_count].onHttpCgi = ponHttpCgi;
        _handler_count ++;
        return 0;
    } else {
        return -1;
    }
}

#ifdef GS_USE_WEBSOCKET
void GSwifi::poll_websocket (int cid, int len) {
    int i, j, flg;
    unsigned char c;

    while (_gs_sock[cid].connect && _gs_sock[cid].data->use()) {
        flg = 0;
        // get 1 line
        for (j = 0; j < len; j ++) {
            _gs_sock[cid].data->get((char*)&c);
//            DBG("_%c", c);

            switch (_httpd[cid].mode) {
            case GSHTTPDMODE_WEBSOCKET:
                if (_httpd[cid].len == 0) {
                    _httpd[cid].type = c & 0x0f;
                    _httpd[cid].websocket_flg = c << 8;
                    _httpd[cid].len ++;
                } else
                if (_httpd[cid].len == 1) {
                    _httpd[cid].websocket_flg |= c;
                    _httpd[cid].length = c & 0x7f;
                    _httpd[cid].len ++;
                    if (_httpd[cid].length < 126) {
                        _httpd[cid].len = 0;
                        if (_httpd[cid].websocket_flg & 0x0080) {
                            _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET_MASK;
                        } else {
                            _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET_BODY;
                        }
                        DBG("ws length %d\r\n", _httpd[cid].length);
                    }
                } else {
                    // length 16bit,64bit
                    if (_httpd[cid].len == 2) {
                        _httpd[cid].length = c;
                        _httpd[cid].len ++;
                    } else
                    if (_httpd[cid].len < 9 && (_httpd[cid].websocket_flg & 0x7f) == 127) {
                        // 64bit
                        _httpd[cid].length = (_httpd[cid].length << 8) | c;
                        _httpd[cid].len ++;
                    } else {
                        _httpd[cid].length = (_httpd[cid].length << 8) | c;
                        _httpd[cid].len = 0;
                        if (_httpd[cid].websocket_flg & 0x0080) {
                            _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET_MASK;
                        } else {
                            _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET_BODY;
                        }
                        DBG("ws length2 %d\r\n", _httpd[cid].length);
                    }
                }
                break;

            case GSHTTPDMODE_WEBSOCKET_MASK:
                _httpd[cid].websocket_mask[_httpd[cid].len] = c;
                _httpd[cid].len ++;
                if (_httpd[cid].len >= 4) {
                    _httpd[cid].len = 0;
                    _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET_BODY;
                    DBG("ws mask\r\n");
                }
                break;

            case GSHTTPDMODE_WEBSOCKET_BODY:
                if (_httpd[cid].len < HTTPD_BUF_SIZE - 1) {
                    if (_httpd[cid].websocket_flg & 0x0080) {
                        _httpd[cid].buf[_httpd[cid].len] = c ^ _httpd[cid].websocket_mask[_httpd[cid].len & 0x03]; 
                    } else {
                        _httpd[cid].buf[_httpd[cid].len] = c; 
                    }
                    _httpd[cid].len ++;
                }
                break;
            }

            if (_httpd[cid].mode == GSHTTPDMODE_WEBSOCKET_BODY && _httpd[cid].len >= _httpd[cid].length) {
                flg = 1;
                break;
            }
        }
        if (j >= len) return; // continue
        if (_httpd[cid].len < HTTPD_BUF_SIZE) {
            _httpd[cid].buf[_httpd[cid].len] = 0;
            DBG("websocket %d: (%d)\r\n", cid, _httpd[cid].len);
        }

    if (flg) {
        // websocket request
      DBG("ws type %d\r\n", _httpd[cid].type);
      switch (_httpd[cid].type) {
      case 0x00: // continuation
      case 0x01: // text
      case 0x02: // binary
        i = get_handler(_httpd[cid].uri);
        if (i >= 0) {
            _httpd[cid].host = _gs_sock[cid].host;
            j = strlen(_handler[i].uri);
            _httpd[cid].file = &_httpd[cid].uri[j];
            _httpd[cid].query = NULL;

            if (_handler[i].onHttpCgi) {
                // cgi
                _handler[i].onHttpCgi(cid, &_httpd[cid]);
                LOG("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]);
                LOG("%s %s %d 200 -\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length);
                flg = 1;
            }
        }
        break;

      case 0x08: // close
        close(cid);
        break;

      case 0x09: // ping
        _gs_putc(0x8a); // pong
        _gs_putc(0x04);
        for (i = 0; i < _httpd[cid].len; i ++) {
            _gs_putc(_httpd[cid].buf[i]);
        }
        break;

      case 0x0a: // pong
        break;
      }
      _httpd[cid].mode = GSHTTPDMODE_WEBSOCKET;
      _httpd[cid].len = 0;
      _httpd[cid].length = 0;
    }
    } // while
}

int GSwifi::send_websocket (int cid, const char *buf, int len) {
    int r;
    char tmp[10];

    tmp[0] = 0x81; // single, text frame
    if (len < 126) {
        tmp[1] = len;
        r = send(cid, tmp, 2);
    } else {
        tmp[1] = 126;
        tmp[2] = (len >> 8) & 0xff;
        tmp[3] = len & 0xff;
        r = send(cid, tmp, 4);
    }
    if (r == 0) {
        r = send(cid, buf, len);
    }
    return r;
}

void GSwifi::send_websocket_accept (int cid) {
    char buf[100], buf2[20];
    
    DBG("websocket accept: %d\r\n", cid);

    send(cid, "HTTP/1.1 101 Switching Protocols\r\n", 34);
    send(cid, "Upgrade: websocket\r\n", 20);
    send(cid, "Connection: Upgrade\r\n", 21);

    send(cid, "Sec-WebSocket-Accept: ", 22);
    strcpy(buf, _httpd[cid].websocket_key);
    strcat(buf, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
    sha1(buf, strlen(buf), buf2);
    base64encode(buf2, 20, buf, sizeof(buf));
    send(cid, buf, strlen(buf));
    send(cid, "\r\n", 2);

//    send(cid, "Sec-WebSocket-Protocol: chat\r\n", 30);
    send(cid, "\r\n", 2);
    LOG("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]);
    LOG("%s %s %d 101 - %s\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length, buf);
}
#endif

#endif