http://mbed.org/users/okini3939/notebook/node_websocket/
Dependencies: EthernetNetIf mbed MbedJSONValue
Revision 0:236a084b1d6b, committed 2011-11-02
- Comitter:
- okini3939
- Date:
- Wed Nov 02 02:56:07 2011 +0000
- Commit message:
Changed in this revision
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