
Simple WebSocket server to control a tank.
Dependencies: SNICInterface_mod WebSocketServer mbed-rtos mbed PowerControl C12832
au Firefox OS WoTハッカソン on ホワイトデーで使用した、タンクを動かすプログラムです。 ゲームパッドでタンクを操縦します。
ゲームパッドは PC に接続し、ブラウザ上の Web アプリから Gamepad API で入力を取得します。 取得した入力データは WebSocket で mbed 上の WebSocket サーバに送信します。
WebSocket サーバのコードはライブラリ化したので、他のプログラムでもインポートして使えます。
使用した機材
- LPC1768
- Murata TypeYD
- LPC1768 用アプリケーションボード
- TAMIYA トラック&ホイールセット
- TAMIYA ダブルキヤボックス(左右独立4速タイプ)
- TAMIYA ユニバーサルプレート
- TOSHIBA TA7291P x 2
- その他、モバイルバッテリー、電池ボックス等
左右のモータードライバにそれぞれ LPC1768 の p12, p13 と p14, p15 のピンを割り当てていますが、必要に応じてコードを変更してください。
コントローラー側(Webアプリ)
https://github.com/chikoski/wotxwot-control
Firefox ブラウザで動作確認しています(他のブラウザでは動かないかも)。 ゲームパッドの左右のスティックの前後の操作が左右それぞれのモータの前転・後転に対応しています。
動いているところの動画
https://www.facebook.com/video.php?v=456620974491805
ハッカソンでは ARM 賞をいただきました!
(参考) au Firefox OS WoTハッカソン on ホワイトデー
http://au-fx.kddi.com/event/20150314/wot_hackathon0314.html
Revision 7:6cfe0638b957, committed 2015-03-14
- Comitter:
- flatbird
- Date:
- Sat Mar 14 00:14:40 2015 +0900
- Parent:
- 6:79ecd4e53456
- Child:
- 8:6635ca3b5a5c
- Commit message:
- add websocket data frame handling.
Changed in this revision
WebSocketServer.cpp | Show annotated file Show diff for this revision Revisions of this file |
WebSocketServer.h | Show annotated file Show diff for this revision Revisions of this file |
--- a/WebSocketServer.cpp Fri Mar 13 11:55:55 2015 +0000 +++ b/WebSocketServer.cpp Sat Mar 14 00:14:40 2015 +0900 @@ -25,20 +25,20 @@ } void WebSocketServer::run() { - TCPSocketConnection connection; + // TCPSocketConnection connection; char buf[1024]; while (true) { bool isWebSocket = false; - int ret = mTCPSocketServer.accept(connection); + int ret = mTCPSocketServer.accept(mConnection); if (ret != 0) { continue; } printf("New connection\r\n"); - connection.set_blocking(true); + mConnection.set_blocking(true); - while (connection.is_connected()) { - ret = connection.receive(buf, sizeof(buf) - 1); + while (mConnection.is_connected()) { + ret = mConnection.receive(buf, sizeof(buf) - 1); if (ret == 0) { // printf("No data to receive\r\n"); continue; @@ -48,7 +48,7 @@ break; } if (!isWebSocket) { - if (this->handleHTTP(buf, ret, connection)) { + if (this->handleHTTP(buf, ret)) { isWebSocket = true; } else { printf("ERROR: Non websocket\r\n"); @@ -61,11 +61,12 @@ } } printf("closed\r\n"); - connection.close(); + mConnection.close(); } } bool WebSocketServer::setHandler(const char* path, WebSocketHandler* handler) { + mHandler = handler; // support only one handler now return true; } @@ -73,7 +74,7 @@ #define SEC_WEBSOCKET_KEY "Sec-WebSocket-Key:" #define MAGIC_NUMBER "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" -bool WebSocketServer::handleHTTP(char* buf, int size, TCPSocketConnection& connection) { +bool WebSocketServer::handleHTTP(char* buf, int size) { char* line = &buf[0]; char key[128]; bool isUpgradeWebSocket = false; @@ -109,16 +110,70 @@ } if (isUpgradeWebSocket && isSecWebSocketKeyFound) { - this->sendUpgradeResponse(key, connection); + this->sendUpgradeResponse(key); return true; } return false; } +#define OP_CONT 0x0 +#define OP_TEXT 0x1 +#define OP_BINARY 0x2 +#define OP_CLOSE 0x8 +#define OP_PING 0x9 +#define OP_PONG 0xA + bool WebSocketServer::handleWebSocket(char* buf, int size) { - buf[size] = '\0'; - printf("%s\r\n", buf); + uint8_t* ptr = (uint8_t*)buf; + + bool fin = (*ptr & 0x80) == 0x80; + uint8_t opcode = *ptr & 0xF; + + printf("opcode=%d\r\n", opcode); + if (opcode == OP_PING) { + *ptr = ((*ptr & 0xF0) | OP_PONG); + mConnection.send_all(buf, size); + return true; + } + if (opcode == OP_CLOSE) { + return false; + } + ptr++; + + mPrevFin = fin; + if (!fin || !mPrevFin) { + printf("WARN: Data consists of multiple frame not supported\r\n"); + return true; // not an error, just discard it + } + + bool mask = (*ptr & 0x80) == 1; + uint8_t len = *ptr & 0x7F; + ptr++; + + if (len > 125) { + printf("WARN: Extended payload lenght not supported\r\n"); + return true; // not an error, just discard it + } + + char* data; + if (mask) { + char* maskingKey = (char*)ptr; + data = (char*)(ptr + 4); + for (int i = 0; i < len; i++) { + data[i] = data[i] ^ maskingKey[(i % 4)]; + } + } else { + data = (char*)ptr; + } + if (mHandler) { + if (opcode == OP_TEXT) { + data[len] = '\0'; + mHandler->onMessage(data); + } else if (opcode == OP_BINARY) { + mHandler->onMessage(data, len); + } + } return true; } @@ -169,7 +224,7 @@ return encoded_data; } -bool WebSocketServer::sendUpgradeResponse(char* key, TCPSocketConnection& connection) { +bool WebSocketServer::sendUpgradeResponse(char* key) { char buf[128]; if (strlen(key) + sizeof(MAGIC_NUMBER) > sizeof(buf)) { @@ -191,7 +246,7 @@ strcpy(ptr, encoded); strcpy(ptr+strlen(encoded), "\r\n\r\n"); - int ret = connection.send_all(resp, strlen(resp)); + int ret = mConnection.send_all(resp, strlen(resp)); if (ret < 0) { printf("ERROR: Failed to send response\r\n"); return false;
--- a/WebSocketServer.h Fri Mar 13 11:55:55 2015 +0000 +++ b/WebSocketServer.h Sat Mar 14 00:14:40 2015 +0900 @@ -8,7 +8,8 @@ public: virtual void onOpen() = 0; virtual void onClose() = 0; - virtual void onMessage() = 0; + virtual void onMessage(char* text) = 0; + virtual void onMessage(char* data, size_t size) = 0; virtual void onError() = 0; }; @@ -23,11 +24,14 @@ bool setHandler(const char* path, WebSocketHandler* handler); private: - bool handleHTTP(char* buf, int size, TCPSocketConnection& connection); + bool handleHTTP(char* buf, int size); bool handleWebSocket(char* buf, int size); - bool sendUpgradeResponse(char* key, TCPSocketConnection& connection); + bool sendUpgradeResponse(char* key); TCPSocketServer mTCPSocketServer; + TCPSocketConnection mConnection; + WebSocketHandler* mHandler; // support only one handler now + bool mPrevFin; }; #endif \ No newline at end of file