2013年8月4日日曜日

websocket RX63N その3

websocketでバイナリとテキストの送信と受信をやってみた。

ブラウザ等、クライアント側
プログレスバーを追加してみた。
http://www.html5.jp/library/progress.html

 <!DOCTYPE html>  
 <html>  
 <head>  
   <title>Websocket client</title>  
   <link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet">  
   <script src="http://code.jquery.com/jquery.js"></script>  
   <script src="../html5jp/progress.js"></script>  
 </head>  
 <body>  
   <div class="container">  
     <h1 class="page-header">Websocket client</h1>  
     <form action="" class="form-inline" id="connectForm">  
       <div class="input-append">  
         <input type="text" class="input-large" value="ws://192.168.1.63:8088/echo" id="wsServer">  
         <button class="btn" type="submit" id="connect">Connect</button>  
         <button class="btn" disabled="disabled" id="disconnect">Disconnect</button>  
       </div>  
     </form>  
     <form action="" id="sendForm">  
       <div class="input-append">  
         <input class="input-large" type="text" placeholder="message" id="message" disabled="disabled">  
         <button class="btn btn-primary" type="submit" id="send" disabled="disabled">send</button>  
       </div>  
     </form>  
     <form action="" id="ledForm">  
       <div class="input-append">  
         <button class="btn" value="1" disabled="disabled" id="led1">LED1</button>  
         <button class="btn" value="2" disabled="disabled" id="led2">LED2</button>  
       </div>  
     </form>   
     <hr>  
      <div id="sample"></div>  
     <hr>  
     <form name="mform">  
      <textarea name="messages" rows="5" cols="50"></textarea>  
     </form>  
     <hr>  
     <ul class="unstyled" id="log"></ul>  
   </div>  
   <script type="text/javascript">  
     $(document).ready(function() {  
       var ws;  
       var p = { to:50 };  
       var o = new html5jp.progress("sample",p);  
       o.draw();  
       $('#connectForm').on('submit', function() {  
         if ("WebSocket" in window) {  
           ws = new WebSocket($('#wsServer').val());  
           ws.binaryType = 'arraybuffer';  
           ws.onopen = function() {  
             $('#log').append('<li><span class="badge badge-success">websocket opened</span></li>');  
             $('#wsServer').attr('disabled', 'disabled');  
             $('#connect').attr('disabled', 'disabled');  
             $('#disconnect').removeAttr('disabled');  
             $('#led1').removeAttr('disabled');  
             $('#led2').removeAttr('disabled');  
             $('#message').removeAttr('disabled').focus();  
             $('#send').removeAttr('disabled');  
           };  
           ws.onerror = function() {  
             $('#log').append('<li><span class="badge badge-important">websocket error</span></li>');  
           };  
           ws.onmessage = function(event) {  
            if(typeof event.data == 'string') {  
            var str = "String:";  
            str += event.data;  
            var percent = parseInt(event.data);  
            if(percent != NaN){  
             o.set_val(percent);  
            }  
            } else if(typeof event.data == 'object') {  
             var byteArray = new Uint8Array(event.data);  
             var str = "Object:";  
             for( var n = 0;n < byteArray.length;n++){  
              str += " 0x" + ("0" + byteArray[n].toString(16)).slice(-2);  
             }  
            } else {  
             var str = "Unknown:";  
            }  
            var num = (document.mform.messages.value.match(/\n/g) || []).length + 1;  
            if(num > 4){  
              document.mform.messages.value = document.mform.messages.value.replace(/[\w\W]+?\n+?/,"");  
            }  
            document.mform.messages.value = document.mform.messages.value + '\r\n'+ str;  
            //$('#log').append('<li>received: <span class="badge">' + str + '</span></li>');  
           };  
           ws.onclose = function() {  
             $('#log').append('<li><span class="badge badge-important">websocket closed</span></li>');  
             $('#wsServer').removeAttr('disabled');  
             $('#connect').removeAttr('disabled');  
             $('#disconnect').attr('disabled', 'disabled');  
             $('#message').attr('disabled', 'disabled');  
             $('#send').attr('disabled', 'disabled');  
           };  
         } else {  
           $('#log').append('<li><span class="badge badge-important">WebSocket NOT supported in this browser</span></li>');  
         }  
         return false;  
       });  
       $('#sendForm').on('submit', function() {  
         var message = $('#message').val();  
         ws.send(message);  
         $('#log').append('<li>sended: <span class="badge">' + message + '</span></li>');  
         return false;  
       });  
       $('#led1').on('click', function() {  
         var buffer = new ArrayBuffer(2);  
         var byteArray = new Uint8Array(buffer);  
         byteArray[0] = 0xf8;  
         byteArray[1] = 0x01;  
         var str = "";  
         for( var n = 0; n<byteArray.length;n++){  
          str += " 0x"+ ("0" + byteArray[n].toString(16)).slice(-2);  
         }  
         ws.send(buffer);  
         var num = (document.mform.messages.value.match(/\n/g) || []).length + 1;  
         if(num > 4){  
           document.mform.messages.value = document.mform.messages.value.replace(/[\w\W]+?\n+?/,"");  
         }  
         document.mform.messages.value = document.mform.messages.value + '\r\n'+ str;  
         return false;  
       });  
       $('#led2').on('click', function() {  
         var message = $(this).attr('value');  
         ws.send(message);  
         var num = (document.mform.messages.value.match(/\n/g) || []).length + 1;  
         if(num > 4){  
            document.mform.messages.value = document.mform.messages.value.replace(/[\w\W]+?\n+?/,"");  
         }  
         document.mform.messages.value = document.mform.messages.value + '\r\n'+ message;  
         return false;  
       });  
       $('#disconnect').on('click', function() {  
         ws.close();  
         return false;  
       });  
     });  
   </script>  
 </body>  
 </html>  

RX63N側サーバー
1)受信したら、送り返す動作。
バイナリとテキストを区別しています。
2)定期的にテキストで送信。
freecounterの値
------------
 ...略
 #include "websocket.h"  
 #define BUF_LEN 512  
 void clientWorker(ID cepid);  
 /******************************************************************************  
 Exported global variables and functions (to be accessed by other files)  
 ******************************************************************************/  
 void error(const char *msg)  
 {  
      //  perror(msg);  
      return;  
      //  exit(EXIT_FAILURE);  
 }  
 int safeSend(ID cepid, const uint8_t *buffer, size_t bufferSize)  
 {  
      ER written;  
      written = tcp_snd_dat(cepid, buffer, bufferSize, 100);  
      if (written < 0) {  
           return EXIT_FAILURE;  
      }  
      return EXIT_SUCCESS;  
 }  
 static uint8_t freecounter=0;  
 void clientWorker(ID cepid)  
 {  
      uint8_t buffer[BUF_LEN];  
      uint8_t txbuffer[12];  
      int i;  
      memset(buffer, 0, BUF_LEN);  
      size_t readedLength = 0;  
      size_t frameSize = BUF_LEN;  
      enum wsState state = WS_STATE_OPENING;  
      uint8_t *data = NULL;  
      size_t dataSize = 0;  
      enum wsFrameType frameType = WS_INCOMPLETE_FRAME;  
      struct handshake hs;  
      nullHandshake(&hs);  
 #define prepareBuffer frameSize = BUF_LEN; memset(buffer, 0, BUF_LEN);  
 #define initNewFrame frameType = WS_INCOMPLETE_FRAME; readedLength = 0; memset(buffer, 0, BUF_LEN);  
      while (frameType == WS_INCOMPLETE_FRAME) {  
           ER readed = tcp_rcv_dat(cepid, buffer+readedLength, BUF_LEN-readedLength, 100);  
           if(readed == E_TMOUT){  
                readed = sprintf((char *)txbuffer,  
                     "%d",freecounter);  
                freecounter++;  
                if(freecounter > 99) freecounter = 0;  
                prepareBuffer;  
                wsMakeFrame(txbuffer, readed, buffer, &frameSize, WS_TEXT_FRAME);  
                if (safeSend(cepid, buffer, frameSize) == EXIT_FAILURE)  
                     break;  
                initNewFrame;  
                readed=0;  
           } else if (readed <= 0) {  
                return;  
           }  
           if(readed){  
                printk("(%3d)",readed);  
                for(i=0;(i<16) && (i < readed);i++){  
                     printk(" %02x",buffer[i]);       
                }  
                printk("\n");  
           }  
           readedLength+= readed;  
           if (state == WS_STATE_OPENING) {  
                frameType = wsParseHandshake(buffer, readedLength, &hs);  
           } else {  
                dataSize=0;  
                frameType = wsParseInputFrame(buffer, readedLength, &data, &dataSize);  
                if(dataSize){  
                     printk("[%3d]",dataSize);  
                     for(i=0;(i<16) && (i < dataSize);i++){  
                          printk(" %02x",data[i]);       
                     }  
                     printk("\n");  
                }  
           }  
           if ((frameType == WS_INCOMPLETE_FRAME && readedLength == BUF_LEN) || frameType == WS_ERROR_FRAME) {  
                if (frameType == WS_INCOMPLETE_FRAME)  
                     printk("buffer too small\n");  
                else  
                     printk("error in incoming frame\n");  
                if (state == WS_STATE_OPENING) {  
                     prepareBuffer;  
                     frameSize = sprintf((char *)buffer,  
                          "HTTP/1.1 400 Bad Request\r\n"  
                          "%s%s\r\n\r\n",  
                          versionField,  
                          version);  
                     safeSend(cepid, buffer, frameSize);  
                     break;  
                } else {  
                     prepareBuffer;  
                     wsMakeFrame(NULL, 0, buffer, &frameSize, WS_CLOSING_FRAME);  
                     if (safeSend(cepid, buffer, frameSize) == EXIT_FAILURE)  
                          break;  
                     state = WS_STATE_CLOSING;  
                     initNewFrame;  
                }  
           }  
           if (state == WS_STATE_OPENING) {  
                //assert(frameType == WS_OPENING_FRAME);  
                if (frameType == WS_OPENING_FRAME) {  
                     // if resource is right, generate answer handshake and send it  
                     if (strcmp(hs.resource, "/echo") != 0) {  
                          frameSize = sprintf((char *)buffer, "HTTP/1.1 404 Not Found\r\n\r\n");  
                          if (safeSend(cepid, buffer, frameSize) == EXIT_FAILURE)  
                               break;  
                     }  
                     prepareBuffer;  
                     wsGetHandshakeAnswer(&hs, buffer, &frameSize);  
                     if (safeSend(cepid, buffer, frameSize) == EXIT_FAILURE)  
                          break;  
                     state = WS_STATE_NORMAL;  
                     initNewFrame;  
                }  
           } else {  
                if (frameType == WS_CLOSING_FRAME) {  
                     if (state == WS_STATE_CLOSING) {  
                          break;  
                     } else {  
                          prepareBuffer;  
                          wsMakeFrame(NULL, 0, buffer, &frameSize, WS_CLOSING_FRAME);  
                          safeSend(cepid, buffer, frameSize);  
                          return;  
                     }  
                } else if (frameType == WS_TEXT_FRAME) {  
                     uint8_t *recievedString = NULL;  
                     recievedString = malloc(dataSize+1);  
                     //assert(recievedString);  
                     memcpy(recievedString, data, dataSize);  
                     recievedString[ dataSize ] = 0;  
                     prepareBuffer;  
                     wsMakeFrame(recievedString, dataSize, buffer, &frameSize, WS_TEXT_FRAME);  
                     if (safeSend(cepid, buffer, frameSize) == EXIT_FAILURE)  
                          break;  
                     initNewFrame;  
                } else if (frameType == WS_BINARY_FRAME) {  
                     uint8_t *recievedString = NULL;  
                     recievedString = malloc(dataSize+1);  
                     //assert(recievedString);  
                     memcpy(recievedString, data, dataSize);  
                     recievedString[ dataSize ] = 0;  
                     prepareBuffer;  
                     wsMakeFrame(recievedString, dataSize, buffer, &frameSize, WS_BINARY_FRAME);  
                     if (safeSend(cepid, buffer, frameSize) == EXIT_FAILURE)  
                          break;  
                     initNewFrame;  
                }  
           }  
      } // read/write cycle  
 }  
 void websocket_srv(ID id)  
 {  
      ID cepid, repid;  
      ER ercd;  
      T_IPV4EP dst_addr;  
      /* setting of reception point and communucation end point */  
      cepid = id;  
      repid = id;  
      /* TCP wait connection */  
      printk("wait tcp_acp_cep\n");  
      ercd = tcp_acp_cep(cepid, repid, &dst_addr, TMO_FEVR);  
      printk("connect\n");  
      if (ercd == E_OK)  
      {  
           clientWorker(cepid);  
      }  
      /* shutdown */  
      tcp_sht_cep(cepid);  
      tcp_cls_cep(cepid, 100);  
      printk("shutdown\n");  
      return;  
 }