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

Dependencies:   EthernetNetIf mbed RingBuffer MbedJSONValue

Files at this revision

API Documentation at this revision

Comitter:
okini3939
Date:
Sat Nov 19 16:19:50 2011 +0000
Commit message:

Changed in this revision

CometClient.cpp Show annotated file Show diff for this revision Revisions of this file
CometClient.h Show annotated file Show diff for this revision Revisions of this file
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
RingBuffer.lib Show annotated file Show diff for this revision Revisions of this file
dbg.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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CometClient.cpp	Sat Nov 19 16:19:50 2011 +0000
@@ -0,0 +1,280 @@
+/*
+ * mbed pseudo Comet HTTP Client
+ * Copyright (c) 2011 Hiroshi Suga
+ * Released under the MIT License: http://mbed.org/license/mit
+ */
+
+/** @file
+ * @brief pseudo Comet HTTP Client
+ */
+
+#include "mbed.h"
+#include "EthernetNetIf.h"
+#include "TCPSocket.h"
+#include "DNSRequest.h"
+#include "RingBuffer.h"
+#include "CometClient.h"
+#include <ctype.h>
+
+#define DEBUG
+#include "dbg.h"
+
+
+static TCPSocket *http;
+static volatile int tcp_ready = 0, tcp_readable = 0, tcp_writable = 0;
+static volatile int tcp_busy = 0, mode = 0;
+static volatile int dns_status = 0;
+static Host remote;
+static RingBuffer fifo(1500);
+static char remoteuri[100];
+
+
+// Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+int base64enc(const char *input, unsigned int length, char *output, int len) {
+  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;
+}
+
+// Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+int urlencode(char *str, char *buf, int len) {
+  static const char to_hex[] = "0123456789ABCDEF";
+//  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) & 0x0f];
+      *pbuf++ = to_hex[*pstr & 0x0f];
+    }
+    pstr++;
+  }
+  *pbuf = '\0';
+  return 0;
+}
+
+
+void isr_http (TCPSocketEvent e) {
+
+    DBG("http(%d)\r\n", e);
+    switch(e) {
+    case TCPSOCKET_CONNECTED:
+        tcp_ready = 1;
+        tcp_busy = 0;
+        mode = 0;
+        break;
+
+    case TCPSOCKET_READABLE: //Incoming data
+        {
+        char buf[1500];
+        int i = 0, len;
+
+        len = http->recv(buf, sizeof(buf));
+        for (i = 0; i < len; i ++) {
+            switch (mode) {
+            case 0:
+                if (strncmp(buf, "HTTP/", 5) == 0 && atoi(&buf[9]) == 200) {
+                    mode = 1;
+                }
+                break;
+            case 1:
+            case 2:
+                if (buf[i] == '\r') {
+                    mode ++;
+                } else
+                if (buf[i] == '\n') {
+                } else {
+                    mode = 1;
+                }
+                break;
+            case 3:
+                if (buf[i] == 0x7f) {
+                    mode = 4;
+                }
+                break;
+            case 4:
+                fifo.put(buf[i]);
+                break;
+            }
+        }
+        } // Incoming data
+        tcp_readable = 1;
+        break;
+
+    case TCPSOCKET_WRITEABLE: //We can send data
+        tcp_writable = 1;
+        break;
+
+    case TCPSOCKET_CONTIMEOUT:
+    case TCPSOCKET_CONRST:
+    case TCPSOCKET_CONABRT:
+    case TCPSOCKET_ERROR:
+    case TCPSOCKET_DISCONNECTED:
+        http->close();
+        tcp_ready = 0;
+        tcp_readable = 0;
+        tcp_writable = 0;
+        tcp_busy = 0;
+        break;
+    }
+}
+
+void createauth (char *user, char *pwd, char *buf, int len) {
+    char tmp[80];
+
+    strncpy(buf, "Authorization: Basic ", len);
+    snprintf(tmp, sizeof(tmp), "%s:%s", user, pwd);
+    base64enc(tmp, strlen(tmp), &buf[strlen(buf)], len - strlen(buf));
+    strncat(buf, "\r\n", len - strlen(buf));
+}
+
+void isr_dns (DNSReply r) {
+
+    DBG("dns(%d)\r\n", r);
+    if (DNS_FOUND) {
+        dns_status = 1;
+    } else {
+        dns_status = -1;
+    }
+}
+
+void pollComet () {
+    Net::poll();
+
+    if (! tcp_ready && ! tcp_busy) {
+        tcp_busy = 1;
+        openComet(NULL, NULL, NULL, NULL);
+    }
+}
+
+int recvComet (char *buf, int size) {
+    int i, len;
+
+    len = fifo.use();
+    if (len == 0) return 0;
+    DBG("readComet %d\r\n", len);
+    if (len > size) len = size;
+
+    for (i = 0; i < len; i ++) {
+        if (fifo.get(&buf[i])) break;
+    }
+    tcp_readable = 0;
+    return len;
+}
+
+int sendComet (char *buf) {
+    while (tcp_busy) {
+        Net::poll();
+    }
+
+    tcp_busy = 1;
+    if (tcp_ready) {
+        DBG("sendComet close\r\n");
+        http->close();
+    }
+    DBG("sendComet open\r\n");
+    openComet(NULL, NULL, NULL, buf);
+    return 0;
+}
+
+int openComet (Host *host, char *uri, char *head, char *body) {
+    TCPSocketErr err;
+    Timer timeout;
+    char buf[1500];
+
+    tcp_busy = 1;
+    if (host) {
+      http = new TCPSocket;
+      http->setOnEvent(isr_http);
+
+      // connect
+      if (host->getIp().isNull()) {
+        // resolv
+        DNSRequest dns;
+        dns_status = 0;
+        dns.setOnReply(isr_dns);
+        if (dns.resolve(host) != DNS_OK) goto exit;
+        timeout.reset();
+        timeout.start();
+        while (timeout.read_ms() < HTTP_TIMEOUT) {
+            if (dns_status) break;
+            Net::poll();
+        }
+        timeout.stop();
+        if (dns_status <= 0) goto exit;
+        DBG("%s [%d.%d.%d.%d]\r\n", host->getName(), (unsigned char)host->getIp()[0], (unsigned char)host->getIp()[1], (unsigned char)host->getIp()[2], (unsigned char)host->getIp()[3]);
+      }
+      if (! host->getPort()) {
+        host->setPort(HTTP_PORT);
+      }
+
+      remote = *host;
+      strncpy(remoteuri, uri, sizeof(remoteuri));
+    } // if (host)
+
+    err = http->connect(remote);
+    if (err != TCPSOCKET_OK) goto exit;
+
+    // wait connect
+    timeout.reset();
+    timeout.start();
+    while (timeout.read_ms() < HTTP_TIMEOUT) {
+        if (tcp_ready) break;
+        Net::poll();
+    }
+    timeout.stop();
+    if (! tcp_ready) goto exit;
+
+    // send request
+    http->send("POST ", 5);
+    http->send(remoteuri, strlen(remoteuri));
+    http->send(" HTTP/1.1\r\nHost: ", 17);
+    http->send(remote.getName(), strlen(remote.getName()));
+    http->send("\r\n", 2);
+    http->send("Connection: close\r\n", 19);
+    http->send("Content-type: application/x-www-form-urlencoded\r\n", 49);
+    if (head) {
+        http->send(head, strlen(head));
+    }
+    sprintf(buf, "Content-Length: %d\r\n", strlen(body));
+    http->send(buf, strlen(buf));
+    http->send("\r\n", 2);
+
+    // post method
+    if (body) {
+        http->send(body, strlen(body));
+    }
+
+    Net::poll();
+    return 0;
+
+exit:
+    http->resetOnEvent();
+    http->close();
+    delete http;
+
+    return -1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CometClient.h	Sat Nov 19 16:19:50 2011 +0000
@@ -0,0 +1,43 @@
+/*
+ * mbed pseudo Comet HTTP Client
+ * Copyright (c) 2011 Hiroshi Suga
+ * Released under the MIT License: http://mbed.org/license/mit
+ */
+
+/** @file
+ * @brief pseud Comet HTTP Client
+ */
+
+#ifndef CometClient_h
+#define CometClient_h
+
+#define DEBUG
+
+#define HTTP_PORT 80
+#define HTTP_TIMEOUT 15000 // ms
+
+#define METHOD_GET 0
+#define METHOD_POST 1
+
+void pollComet ();
+
+int recvComet (char *buf, int size);
+
+int sendComet (char *buf);
+
+/** send http request
+ * @param host http server
+ * @param uri URI
+ * @param head http header (CR+LF) (or NULL)
+ * @param body POST body (or NULL)
+ * @return 0:ok, -1:failue
+ */
+int openComet (Host *host, char *uri, char *head, char *body);
+
+void createauth (char *user, char *pwd, char *buf, int len);
+
+int base64enc(const char *input, unsigned int length, char *output, int len);
+
+int urlencode(char *str, char *buf, int len);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EthernetNetIf.lib	Sat Nov 19 16:19:50 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/donatien/code/EthernetNetIf/#bc7df6da7589
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MbedJSONValue.lib	Sat Nov 19 16:19:50 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/samux/code/MbedJSONValue/#10a99cdf7846
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RingBuffer.lib	Sat Nov 19 16:19:50 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/okini3939/code/RingBuffer/#ea0c0a46dbdd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dbg.h	Sat Nov 19 16:19:50 2011 +0000
@@ -0,0 +1,7 @@
+//#define DEBUG
+
+#ifdef DEBUG 
+#define DBG(...) printf("" __VA_ARGS__) 
+#else 
+#define DBG(...) 
+#endif 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sat Nov 19 16:19:50 2011 +0000
@@ -0,0 +1,61 @@
+#include "mbed.h"
+#include "EthernetNetIf.h"
+#include "TCPSocket.h"
+#include "CometClient.h"
+#include <new>
+
+DigitalOut myled(LED1);
+Serial pc(USBTX, USBRX);
+EthernetNetIf eth;
+
+void HardFault_Handler() {
+    printf("Hard Fault!\n");
+    exit(-1);
+}
+
+void no_memory () {
+    printf("panic: can't allocate to memory!\r\n");
+    exit(-1);
+}
+
+int main () {
+    EthernetErr ethErr;
+    Host host;
+    int i, r;
+    char buf[100];
+
+    pc.baud(115200);
+    myled = 1;
+
+    set_new_handler(no_memory); // new handler function
+
+    ethErr = eth.setup();
+    if(ethErr) {
+        return -1;
+    }
+
+    host.setIp(IpAddr(49, 212, 96, 62));
+    r = openComet(&host, "/stream.php", NULL, "data=hello");
+    printf("status %d\r\n", r);
+
+    while (1) {
+        myled = 1;
+        pollComet();
+        myled = 0;
+        
+        i = recvComet(buf, 1000);
+        if (i) {
+            buf[i] = 0;
+            printf("RECV: %s\r\n", buf);
+        }
+        
+        if (pc.readable()) {
+            strcpy(buf, "data= ");
+            buf[5] = pc.getc();
+            printf("SEND: %s\r\n", buf);
+            sendComet(buf);
+        }
+    }
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sat Nov 19 16:19:50 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912