http://mbed.org/users/okini3939/notebook/node_websocket/

Dependencies:   EthernetNetIf mbed MbedJSONValue

Files at this revision

API Documentation at this revision

Comitter:
okini3939
Date:
Wed Nov 02 02:56:07 2011 +0000
Commit message:

Changed in this revision

EthernetNetIf.lib Show annotated file Show diff for this revision Revisions of this file
MbedJSONValue.lib Show annotated file Show diff for this revision Revisions of this file
Websocket/Websocket.cpp Show annotated file Show diff for this revision Revisions of this file
Websocket/Websocket.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 236a084b1d6b EthernetNetIf.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EthernetNetIf.lib	Wed Nov 02 02:56:07 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/donatien/code/EthernetNetIf/#bc7df6da7589
diff -r 000000000000 -r 236a084b1d6b MbedJSONValue.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MbedJSONValue.lib	Wed Nov 02 02:56:07 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/samux/code/MbedJSONValue/#10a99cdf7846
diff -r 000000000000 -r 236a084b1d6b Websocket/Websocket.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Websocket/Websocket.cpp	Wed Nov 02 02:56:07 2011 +0000
@@ -0,0 +1,456 @@
+/*
+ * modify by Suga
+ */
+#include "Websocket.h"
+#include <string>
+
+#ifdef WIFLY
+Websocket::Websocket(char * url, Wifly * wifi) {
+    this->wifi = wifi;
+    netif = WIF;
+    fillFields(url);
+}
+#endif
+
+void Websocket::isr_dns (DNSReply r) {
+    if (DNS_FOUND) {
+        dns_status = 1;
+    } else {
+        dns_status = -1;
+    }
+}
+
+Websocket::Websocket(char * url, EthernetNetIf *e) {
+    server_ip = NULL;
+    netif = ETH;
+    eth_writeable = false;
+    eth_readable = false;
+    eth_connected = false;
+    response_server_eth = false;
+    new_msg = false;
+    fillFields(url);
+
+#ifdef ETH_SETUP
+    eth = new EthernetNetIf();
+#else
+    eth = e;
+#endif
+    sock = new TCPSocket();
+
+#ifdef ETH_SETUP
+    EthernetErr ethErr = eth->setup();
+#ifdef DEBUG
+    if (ethErr) {
+        printf("\r\nERROR %d in setup.\r\n", ethErr);
+    }
+#endif
+#endif
+
+    //we must use dnsresolver to find the ip address
+    if (server_ip == NULL) {
+/*
+        DNSResolver dr;
+        server_ip = new IpAddr();
+        *server_ip = dr.resolveName(ip_domain.c_str());
+*/
+        DNSRequest dns;
+        Timer timeout;
+        server_ip = new IpAddr();
+        dns_status = 0;
+        dns.setOnReply(this, &Websocket::isr_dns);
+        if (dns.resolve(ip_domain.c_str()) != DNS_OK) return;
+        timeout.reset();
+        timeout.start();
+        while (timeout.read_ms() < 15000) {
+            if (dns_status) break;
+            Net::poll();
+        }
+        timeout.stop();
+        if (dns_status <= 0) return;
+        dns.getResult(server_ip);
+        dns.close();
+#ifdef DEBUG
+        printf("\r\nserver with dns=%i.%i.%i.%i\r\n",server_ip[0],server_ip[1],server_ip[2],server_ip[3]);
+#endif
+
+    }
+
+    IpAddr ipt = eth->getIp();
+#ifdef DEBUG
+    printf("\r\nmbed IP Address is %d.%d.%d.%d\r\n", ipt[0], ipt[1], ipt[2], ipt[3]);
+#endif
+
+    sock->setOnEvent(this, &Websocket::onTCPSocketEvent);
+}
+
+
+void Websocket::fillFields(char * url) {
+    char *res = NULL;
+    char *res1 = NULL;
+
+    char buf[50];
+    strcpy(buf, url);
+
+    res = strtok(buf, ":");
+    if (strcmp(res, "ws")) {
+#ifdef DEBUG
+        printf("\r\nFormat error: please use: \"ws://ip-or-domain[:port]/path\"\r\n\r\n");
+#endif
+    } else {
+        //ip_domain and port
+        res = strtok(NULL, "/");
+
+        //path
+        res1 = strtok(NULL, " ");
+        if (res1 != NULL) {
+            path = res1;
+        }
+
+        //ip_domain
+        res = strtok(res, ":");
+
+        //port
+        res1 = strtok(NULL, " ");
+        //port
+        if (res1 != NULL) {
+            port = res1;
+        } else {
+            port = "80";
+        }
+
+        if (res != NULL) {
+            ip_domain = res;
+
+            //if we use ethernet, we must decode ip address or use dnsresolver
+            if (netif == ETH) {
+                strcpy(buf, res);
+
+                //we try to decode the ip address
+                if (buf[0] >= '0' && buf[0] <= '9') {
+                    res = strtok(buf, ".");
+                    int i = 0;
+                    int ip[4];
+                    while (res != NULL) {
+                        ip[i] = atoi(res);
+                        res = strtok(NULL, ".");
+                        i++;
+                    }
+                    server_ip = new IpAddr(ip[0], ip[1], ip[2], ip[3]);
+#ifdef DEBUG
+                    printf("server without dns=%i.%i.%i.%i\n",(*server_ip)[0],(*server_ip)[1],(*server_ip)[2],(*server_ip)[3]);
+#endif
+                }
+            }
+        }
+    }
+}
+
+
+bool Websocket::connect() {
+    char cmd[50];
+#ifdef WIFLY
+    if (netif == WIF) {
+        wifi->send("exit\r", "NO");
+        //enter in cmd mode
+        while (!wifi->send("$$$", "CMD")) {
+#ifdef DEBUG
+            printf("cannot enter in CMD mode\r\n");
+#endif
+            wifi->exit();
+        }
+
+
+        //open the connection
+        sprintf(cmd, "open %s %s\r\n", ip_domain.c_str(), port.c_str());
+        if (!wifi->send(cmd, "OPEN*")) {
+#ifdef DEBUG
+            printf("Websocket::connect cannot open\r\n");
+#endif
+            return false;
+        }
+
+
+        //send websocket HTTP header
+        sprintf(cmd, "GET /%s HTTP/1.1\r\n", path.c_str());
+        wifi->send(cmd, "NO");
+
+        sprintf(cmd, "Host: %s:%s\r\n", ip_domain.c_str(), port.c_str());
+        wifi->send(cmd, "NO");
+
+        wifi->send("Upgrade: WebSocket\r\n", "NO");
+
+        sprintf(cmd, "Origin: http:%s:%s\r\n", ip_domain.c_str(), port.c_str());
+        wifi->send(cmd, "NO");
+
+
+        wifi->send("Connection: Upgrade\r\n", "NO");
+        wifi->send("Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n", "NO");
+        wifi->send("Sec-WebSocket-key2: 12998 5 Y3 1  .P00\r\n\r\n", "NO");
+        if (!wifi->send("^n:ds[4U", "8jKS'y:G*Co,Wxa-"))
+            return false;
+#ifdef DEBUG
+        printf("\r\nip_domain: %s\r\npath: /%s\r\nport: %s\r\n\r\n",this->ip_domain.c_str(), this->path.c_str(), this->port.c_str());
+#endif
+        return true;
+    } else
+#endif
+    if (netif == ETH) {
+        Host server (*server_ip, atoi(port.c_str()));
+        sock->close();
+        TCPSocketErr bindErr = sock->connect(server);
+        if (bindErr) {
+#ifdef DEBUG
+            printf("\r\nERROR binderr: %d\r\n", bindErr);
+#endif
+            return false;
+        }
+
+        Timer tmr;
+        tmr.start();
+
+        Timer stop;
+        stop.start();
+
+        int i = 0;
+        while (true) {
+            Net::poll();
+            if (stop.read() > 3)
+                return false;
+            if (tmr.read() > 0.01) {
+                tmr.reset();
+                if (eth_connected) {
+                    switch (i) {
+                        case 0:
+                            sprintf(cmd, "GET /%s HTTP/1.1\r\n", path.c_str());
+                            sock->send(cmd, strlen(cmd));
+                            i++;
+                            break;
+                        case 1:
+                            sprintf(cmd, "Host: %s:%s\r\n", ip_domain.c_str(), port.c_str());
+                            sock->send(cmd, strlen(cmd));
+                            i++;
+                            break;
+                        case 2:
+                            sprintf(cmd, "Upgrade: WebSocket\r\n");
+                            sock->send(cmd, strlen(cmd));
+                            i++;
+                            break;
+                        case 3:
+                            sprintf(cmd, "Origin: http:%s:%s\r\n", ip_domain.c_str(), port.c_str());
+                            sock->send(cmd, strlen(cmd));
+                            i++;
+                            break;
+                        case 4:
+                            sprintf(cmd, "Connection: Upgrade\r\n");
+                            sock->send(cmd, strlen(cmd));
+                            i++;
+                            break;
+                        case 5:
+                            sprintf(cmd, "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n");
+                            sock->send(cmd, strlen(cmd));
+                            i++;
+                            break;
+                        case 6:
+                            sprintf(cmd, "Sec-WebSocket-key2: 12998 5 Y3 1  .P00\r\n\r\n");
+                            sock->send(cmd, strlen(cmd));
+                            i++;
+                            break;
+                        case 7:
+                            sock->send("^n:ds[4U", 8);
+                            i++;
+                            break;
+                        case 8:
+                            if (response_server_eth)
+                                i++;
+                            else
+                                break;
+
+                        default:
+                            break;
+                    }
+                }
+                if (i==9) {
+#ifdef DEBUG
+                    printf("\r\nip_domain: %s\r\npath: /%s\r\nport: %s\r\n\r\n",this->ip_domain.c_str(), this->path.c_str(), this->port.c_str());
+#endif
+                    return true;
+                }
+            }
+        }
+    }
+    //the program shouldn't be here
+    return false;
+}
+
+void Websocket::send(char * str) {
+#ifdef WIFLY
+    if (netif == WIF) {
+        wifi->putc('\x00');
+        wifi->send(str, "NO");
+        wifi->putc('\xff');
+    } else
+#endif
+    if (netif == ETH) {
+        char c = '\x00';
+        Net::poll();
+        sock->send(&c, 1);
+        sock->send(str, strlen(str));
+        c = '\xff';
+        sock->send(&c, 1);
+    }
+}
+
+bool Websocket::read(char * message) {
+    int i = 0;
+
+#ifdef WIFLY
+    if (netif == WIF) {
+        if (!wifi->read(message))
+            return false;
+
+        //we check if the first byte is 0x00
+        if (message == NULL || message[0] != 0x00) {
+            message = NULL;
+            return false;
+        }
+
+        while (message[i + 1] != 0xff && i < strlen(message + 1))
+            i++;
+
+        if (message[i+1] == 0xff) {
+            message[i+1] = 0;
+            memcpy(message, message + 1, strlen(message + 1) + 1);
+            return true;
+        } else {
+            message = NULL;
+            return false;
+        }
+    } else
+#endif
+    if (netif == ETH) {
+        Net::poll();
+
+        if (new_msg) {
+            if (eth_rx[0] != 0x00) {
+                message = NULL;
+                return false;
+            }
+            while (eth_rx[i + 1] != 0xff) {
+                message[i] = eth_rx[i + 1];
+                i++;
+            }
+            message[i] = 0;
+            new_msg = false;
+            return true;
+        }
+        return false;
+    }
+    //the program shouldn't be here
+    return false;
+}
+
+bool Websocket::close() {
+#ifdef WIFLY
+    if (netif == WIF) {
+        if (!wifi->cmdMode()) {
+#ifdef DEBUG
+            printf("Websocket::close: cannot enter in cmd mode\r\n");
+#endif
+            return false;
+        }
+
+        wifi->send("close\r", "NO");
+
+        if (!wifi->exit())
+            return false;
+    } else
+#endif
+    if (netif == ETH) {
+
+        if (sock->close())
+            return false;
+        return true;
+    }
+    //the program shouldn't be here
+    return false;
+}
+
+
+
+bool Websocket::connected() {
+#ifdef WIFLY
+    if (netif == WIF) {
+        char str[10];
+
+        wait(0.25);
+        if (!wifi->cmdMode()) {
+#ifdef DEBUG
+            printf("Websocket::connected: cannot enter in cmd mode\r\n");
+#endif
+            return false;
+        }
+        wait(0.25);
+
+        wifi->send("show c\r\n", "NO", str);
+
+        if (str[3] == '1') {
+            if (!wifi->exit()) {
+#ifdef DEBUG
+                printf("Websocket::connected: cannot exit\r\n");
+#endif
+                return false;
+            }
+            return true;
+        }
+        if (!wifi->exit()) {
+#ifdef DEBUG
+            printf("Websocket::connected: cannot exit\r\n");
+#endif
+        }
+        return false;
+    } else
+#endif
+    if (netif == ETH) {
+
+        return eth_connected;
+    }
+    //the program shouldn't be here
+    return false;
+}
+
+std::string Websocket::getPath()
+{
+    return path;
+}
+
+
+
+
+void Websocket::onTCPSocketEvent(TCPSocketEvent e) {
+    if (e == TCPSOCKET_CONNECTED) {
+        eth_connected = true;
+#ifdef DEBUG
+        printf("TCP Socket Connected\r\n");
+#endif
+    } else if (e == TCPSOCKET_WRITEABLE) {
+    } else if (e == TCPSOCKET_READABLE) {
+        int len = sock->recv(eth_rx, 512);
+        eth_rx[len] = 0;
+        new_msg = true;
+        if (!response_server_eth) {
+            string checking;
+            size_t found = string::npos;
+            checking = eth_rx;
+            found = checking.find("HTTP");
+            if (found != string::npos)
+                response_server_eth = true;
+        }
+    } else {
+#ifdef DEBUG
+        printf("TCP Socket Fail\r\n");
+#endif
+        eth_connected = false;
+    }
+}
+
+
diff -r 000000000000 -r 236a084b1d6b Websocket/Websocket.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Websocket/Websocket.h	Wed Nov 02 02:56:07 2011 +0000
@@ -0,0 +1,220 @@
+/**
+* @author Samuel Mokrani
+*
+* @section LICENSE
+*
+* Copyright (c) 2011 mbed
+*
+* 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.
+*
+* @section DESCRIPTION
+*    Simple websocket client
+*
+*/ 
+/*
+ * modify by Suga
+ */
+
+#ifndef WEBSOCKET_H
+#define WEBSOCKET_H
+
+//#define WIFLY
+//#define ETH_SETUP
+
+#include "mbed.h"
+#ifdef WIFLY
+#include "Wifly.h"
+#endif
+#include <string>
+
+#include "EthernetNetIf.h"
+#include "TCPSocket.h"
+//#include "dnsresolve.h"
+#include "DNSRequest.h"
+
+/** Websocket client Class. 
+ *
+ * Warning: you must use a wifi module (Wifly RN131-C) or an ethernet network to use this class
+ *
+ * Example (wifi network):
+ * @code
+ * #include "mbed.h"
+ * #include "Wifly.h"
+ * #include "Websocket.h"
+ * 
+ * Serial pc(USBTX, USBRX);
+ * Wifly * wifly;
+ * Websocket * ws;
+ *
+ * int main()
+ * {
+ *   wifly = new Wifly(p9, p10, p20, "network", "password", true);
+ *   ws = new Websocket("ws://ip_domain/path", wifly);
+ *   
+ *   if(wifly->join())
+ *   {
+ *       if(ws->connect())
+ *       {
+ *           pc.printf("ws connected\r\n");
+ *           while(1)
+ *           {
+ *               wait(0.1);
+ *               ws->send("test");
+ *           }
+ *       }
+ *       else
+ *           pc.printf("ws not connected\r\n");
+ *   }
+ *   else
+ *       pc.printf("join network failed\r\n");
+ *       
+ * }
+ * @endcode
+ *
+ *
+ *
+ * Example (ethernet network):
+ * @code
+ * #include "mbed.h"
+ * #include "Websocket.h"
+ * 
+ * Serial pc(USBTX, USBRX);
+ * Websocket * ws;
+ *
+ * int main()
+ * {
+ *   ws = new Websocket("ws://ip_domain/path");
+ *   
+ *   if(ws->connect())
+ *   {
+ *      pc.printf("ws connected\r\n");
+ *      while(1)
+ *      {
+ *         wait(0.1);
+ *         ws->send("test");
+ *      }
+ *   }
+ *   else
+ *      pc.printf("ws not connected\r\n");
+ * }
+ * @endcode
+ */
+class Websocket
+{
+    public:
+        /**
+        * Constructor
+        *
+        * @param url The Websocket url in the form "ws://ip_domain[:port]/path"  (by default: port = 80)
+        * @param wifi pointer to a wifi module (the communication will be establish by this module)
+        */
+#ifdef WIFLY
+        Websocket(char * url, Wifly * wifi);
+#endif
+        
+        /**
+        * Constructor for an ethernet communication
+        *
+        * @param url The Websocket url in the form "ws://ip_domain[:port]/path" (by default: port = 80)
+        */
+        Websocket(char * url, EthernetNetIf *e);
+        
+        /**
+        * Connect to the websocket url
+        *
+        *@return true if the connection is established, false otherwise
+        */
+        bool connect();
+        
+        /**
+        * Send a string according to the websocket format: 00 str ff
+        *
+        * @param str string to be sent
+        */
+        void send(char * str);
+        
+        /**
+        * Read a websocket message
+        *
+        * @param message pointer to the string to be read (null if drop frame)
+        *
+        * @return true if a string has been read, false otherwise
+        */
+        bool read(char * message);
+        
+        /**
+        * To see if there is a websocket connection active
+        *
+        * @return true if there is a connection active
+        */
+        bool connected();
+        
+        /**
+        * Close the websocket connection
+        *
+        * @return true if the connection has been closed, false otherwise
+        */
+        bool close();
+        
+        /**
+        * Accessor: get path from the websocket url
+        *
+        * @return path
+        */
+        std::string getPath();
+        
+        enum Type {
+            WIF,
+            ETH
+        };
+        
+    
+    private:
+    
+        
+        void fillFields(char * url);
+        void isr_dns (DNSReply r);
+        
+        std::string ip_domain;
+        std::string path;
+        std::string port;
+        
+#ifdef WIFLY
+        Wifly * wifi;
+#endif
+        
+        void onTCPSocketEvent(TCPSocketEvent e);
+        bool eth_connected;
+        bool eth_readable;
+        bool eth_writeable;
+        char eth_rx[512];
+        bool response_server_eth;
+        bool new_msg;
+        int dns_status;
+        
+        EthernetNetIf * eth;
+        TCPSocket * sock;
+        IpAddr * server_ip;
+        
+        Type netif;
+        
+
+};
+
+#endif
\ No newline at end of file
diff -r 000000000000 -r 236a084b1d6b main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Nov 02 02:56:07 2011 +0000
@@ -0,0 +1,60 @@
+#include "mbed.h"
+#include "Websocket.h"
+#include "MbedJSONValue.h"
+#include "EthernetNetIf.h"
+
+#define BASE_URL "ws://host.domain.name:8080/"
+
+DigitalOut myled(LED1);
+Serial pc(USBTX, USBRX);
+
+EthernetNetIf *eth;
+Websocket *ws;
+
+int main() {
+    int i = 0;
+    char buf[100];
+    MbedJSONValue json;
+    Timer timer;
+
+    eth = new EthernetNetIf();
+    EthernetErr ethErr = eth->setup();
+    if (ethErr) {
+        pc.printf("\r\nERROR %d in setup.\r\n", ethErr);
+    }
+
+    ws = new Websocket(BASE_URL "test", eth);
+
+    pc.printf("begin\r\n");
+
+    json["hello"] = "mbed";
+    json["num"] = i;
+
+    while(! ws->connect()) {
+        pc.printf("cannot connect websocket, retrying...\r\n");
+        wait(2);
+    }
+
+    timer.start();
+    while(1) {
+        Net::poll();
+
+        if (timer.read_ms() >= 2000) {
+            json["num"] = i ++;
+            ws->send((char*)json.serialize().c_str());
+            timer.reset();
+            myled = myled ? 0 : 1;
+       }
+        
+        if (ws->read(buf)) {
+            pc.printf("recv: %s\r\n", buf);
+        }
+
+        Net::poll();
+
+        if (! ws->connected()) {
+            pc.printf("disconnected\r\n");
+            break;
+        }
+    }
+}
diff -r 000000000000 -r 236a084b1d6b mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Nov 02 02:56:07 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912