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
Parent:
6:79ecd4e53456
Child:
8:6635ca3b5a5c
--- 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;