first full working version of WebSocketsServer

This commit is contained in:
Markus Sattler
2015-05-22 23:02:47 +02:00
parent cc60722ede
commit f1ecfa9d20
6 changed files with 265 additions and 59 deletions

View File

@ -0,0 +1,78 @@
/*
* WebSocketsServer.ino
*
* Created on: 22.05.2015
*
*/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WebSocketsServer.h>
#include <hash.h>
ESP8266WiFiMulti WiFiMulti;
WebSocketsServer webSocket = WebSocketsServer(81);
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght) {
switch(type) {
case WStype_DISCONNECTED:
Serial1.printf("[%d] Disconnected!\n", num);
break;
case WStype_CONNECTED:
Serial1.printf("[%d] Connected.\n", num);
break;
case WStype_TEXT:
Serial1.printf("[%d] get Text: %s\n", num, payload);
// echo data back to browser
webSocket.sendTXT(num, payload, lenght);
// send data to all connected clients
webSocket.broadcastTXT(payload, lenght);
break;
case WStype_BIN:
Serial1.printf("[%d] get binary.\n", num);
hexdump(payload, lenght);
// echo data back to browser
webSocket.sendBIN(num, payload, lenght);
break;
}
}
void setup() {
Serial.begin(921600);
Serial1.begin(921600);
//Serial.setDebugOutput(true);
Serial1.setDebugOutput(true);
Serial1.println();
Serial1.println();
Serial1.println();
for(uint8_t t = 4; t > 0; t--) {
Serial1.printf("[SETUP] BOOT WAIT %d...\n", t);
Serial1.flush();
delay(1000);
}
WiFiMulti.addAP("SSID", "passpasspass");
while(WiFiMulti.run() != WL_CONNECTED) {
delay(100);
}
webSocket.begin();
webSocket.onEvent(webSocketEvent);
}
void loop() {
webSocket.loop();
}

View File

@ -27,19 +27,13 @@
/** /**
* *
* @param client WSclient_t * ptr to the client struct * @param client WSclient_t * ptr to the client struct
* @param code * @param code uint16_t see RFC
* @param reason * @param reason
* @param reasonLen * @param reasonLen
*/ */
void WebSockets::clientDisconnect(WSclient_t * client, uint16_t code, char * reason, size_t reasonLen) { void WebSockets::clientDisconnect(WSclient_t * client, uint16_t code, char * reason, size_t reasonLen) {
if(client->status == WSC_CONNECTED && code) { if(client->status == WSC_CONNECTED && code) {
//todo send reason to client sendFrame(client, WSop_close, (uint8_t *) reason, reasonLen);
if(reasonLen > 0 && reason) {
} else {
}
} }
clientDisconnect(client); clientDisconnect(client);
} }
@ -49,9 +43,9 @@ void WebSockets::clientDisconnect(WSclient_t * client, uint16_t code, char * rea
* @param client WSclient_t * ptr to the client struct * @param client WSclient_t * ptr to the client struct
* @param opcode WSopcode_t * @param opcode WSopcode_t
* @param payload uint8_t * * @param payload uint8_t *
* @param lenght size_t * @param length size_t
*/ */
void WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t lenght) { void WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length) {
uint8_t buffer[16] = { 0 }; uint8_t buffer[16] = { 0 };
uint8_t i = 0; uint8_t i = 0;
@ -61,31 +55,32 @@ void WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * pay
buffer[i] = bit(7); // set Fin buffer[i] = bit(7); // set Fin
buffer[i++] |= opcode; // set opcode buffer[i++] |= opcode; // set opcode
if(lenght < 126) { if(length < 126) {
buffer[i++] = lenght; buffer[i++] = length;
} else if(lenght < 0xFFFF) { } else if(length < 0xFFFF) {
buffer[i++] = 126; buffer[i++] = 126;
buffer[i++] = ((lenght >> 8) & 0xFF); buffer[i++] = ((length >> 8) & 0xFF);
buffer[i++] = (lenght & 0xFF); buffer[i++] = (length & 0xFF);
} else { } else {
// normaly we never get here (to less memory)
buffer[i++] = 127; buffer[i++] = 127;
buffer[i++] = 0x00; buffer[i++] = 0x00;
buffer[i++] = 0x00; buffer[i++] = 0x00;
buffer[i++] = 0x00; buffer[i++] = 0x00;
buffer[i++] = 0x00; buffer[i++] = 0x00;
buffer[i++] = ((lenght >> 24) & 0xFF); buffer[i++] = ((length >> 24) & 0xFF);
buffer[i++] = ((lenght >> 16) & 0xFF); buffer[i++] = ((length >> 16) & 0xFF);
buffer[i++] = ((lenght >> 8) & 0xFF); buffer[i++] = ((length >> 8) & 0xFF);
buffer[i++] = (lenght & 0xFF); buffer[i++] = (length & 0xFF);
} }
// send header // send header
client->tcp.write(&buffer[0], i); client->tcp.write(&buffer[0], i);
if(payload && lenght > 0) { if(payload && length > 0) {
// send payload // send payload
client->tcp.write(&payload[0], lenght); client->tcp.write(&payload[0], length);
} }
} }
@ -136,7 +131,7 @@ void WebSockets::handleWebsocket(WSclient_t * client) {
} }
payloadLen = buffer[0] << 8 | buffer[1]; payloadLen = buffer[0] << 8 | buffer[1];
} else if(payloadLen == 127) { } else if(payloadLen == 127) {
// read 64bit inteager as Lenght // read 64bit inteager as length
if(!readWait(client, buffer, 8)) { if(!readWait(client, buffer, 8)) {
//timeout //timeout
clientDisconnect(client, 1002); clientDisconnect(client, 1002);
@ -191,31 +186,23 @@ void WebSockets::handleWebsocket(WSclient_t * client) {
switch(opCode) { switch(opCode) {
case WSop_text: case WSop_text:
DEBUG_WEBSOCKETS("[WS-Server][%d][handleWebsocket] text: %s\n", client->num, payload) DEBUG_WEBSOCKETS("[WS-Server][%d][handleWebsocket] text: %s\n", client->num, payload);
; // no break here!
// todo API for user to get message may callback
// send the frame back!
sendFrame(client, WSop_text, payload, payloadLen);
break;
case WSop_binary: case WSop_binary:
// todo API for user to get message may callback messageRecived(client, opCode, payload, payloadLen);
break; break;
case WSop_ping: case WSop_ping:
// todo send pong // send pong back
sendFrame(client, WSop_pong, payload, payloadLen);
break; break;
case WSop_pong: case WSop_pong:
DEBUG_WEBSOCKETS("[WS-Server][%d][handleWebsocket] get pong from Client (%s)\n", client->num, payload) DEBUG_WEBSOCKETS("[WS-Server][%d][handleWebsocket] get pong from Client (%s)\n", client->num, payload);
;
break; break;
case WSop_close: { case WSop_close:
{
uint16_t reasonCode = buffer[0] << 8 | buffer[1]; uint16_t reasonCode = buffer[0] << 8 | buffer[1];
DEBUG_WEBSOCKETS("[WS-Server][%d][handleWebsocket] client ask for close. Code: %d (%s)\n", client->num, reasonCode, (payload + 2)); DEBUG_WEBSOCKETS("[WS-Server][%d][handleWebsocket] client ask for close. Code: %d (%s)\n", client->num, reasonCode, (payload + 2));
clientDisconnect(client, 1000);
// todo send confimation to client
clientDisconnect(client, 1000, (char *) (payload + 2), payloadLen - 2);
} }
break; break;
case WSop_continuation: case WSop_continuation:

View File

@ -37,7 +37,7 @@
#endif #endif
#endif #endif
#define DEBUG_WEBSOCKETS(...) Serial1.printf( __VA_ARGS__ ); Serial1.flush() //#define DEBUG_WEBSOCKETS(...) Serial1.printf( __VA_ARGS__ );
#ifndef DEBUG_WEBSOCKETS #ifndef DEBUG_WEBSOCKETS
#define DEBUG_WEBSOCKETS(...) #define DEBUG_WEBSOCKETS(...)
@ -95,9 +95,10 @@ class WebSockets {
virtual void clientDisconnect(WSclient_t * client); virtual void clientDisconnect(WSclient_t * client);
virtual bool clientIsConnected(WSclient_t * client); virtual bool clientIsConnected(WSclient_t * client);
virtual void messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length);
void clientDisconnect(WSclient_t * client, uint16_t code, char * reason = NULL, size_t reasonLen = 0); void clientDisconnect(WSclient_t * client, uint16_t code, char * reason = NULL, size_t reasonLen = 0);
void sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload = NULL, size_t lenght = 0); void sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload = NULL, size_t length = 0);
void handleWebsocket(WSclient_t * client); void handleWebsocket(WSclient_t * client);

View File

@ -34,12 +34,18 @@ extern "C" {
WebSocketsServer::WebSocketsServer(uint16_t port) { WebSocketsServer::WebSocketsServer(uint16_t port) {
_port = port; _port = port;
_server = new WiFiServer(port); _server = new WiFiServer(port);
_cbEvent = NULL;
} }
WebSocketsServer::~WebSocketsServer() { WebSocketsServer::~WebSocketsServer() {
// todo how to close server? // todo how to close server?
} }
/**
* calles to init the Websockets server
*/
void WebSocketsServer::begin(void) { void WebSocketsServer::begin(void) {
WSclient_t * client; WSclient_t * client;
@ -71,13 +77,116 @@ void WebSocketsServer::loop(void) {
} }
/**
* set callback function
* @param cbEvent WebSocketServerEvent
*/
void WebSocketsServer::onEvent(WebSocketServerEvent cbEvent) {
WebSocketsServer::_cbEvent = cbEvent;
}
/**
* send text data to client
* @param num uint8_t client id
* @param payload uint8_t *
* @param length size_t
*/
void WebSocketsServer::sendTXT(uint8_t num, uint8_t * payload, size_t length) {
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
return;
}
WSclient_t * client = &_clients[num];
if(clientIsConnected(client)) {
sendFrame(client, WSop_text, payload, length);
}
}
void WebSocketsServer::sendTXT(uint8_t num, String payload) {
sendTXT(num, (uint8_t *)payload.c_str(), payload.length());
}
/**
* send text data to client all
* @param payload uint8_t *
* @param length size_t
*/
void WebSocketsServer::broadcastTXT(uint8_t * payload, size_t length) {
WSclient_t * client;
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
client = &_clients[i];
if(clientIsConnected(client)) {
sendFrame(client, WSop_text, payload, length);
}
}
}
void WebSocketsServer::broadcastTXT(String payload) {
broadcastTXT((uint8_t *)payload.c_str(), payload.length());
}
/**
* send binary data to client
* @param num uint8_t client id
* @param payload uint8_t *
* @param length size_t
*/
void WebSocketsServer::sendBIN(uint8_t num, uint8_t * payload, size_t length) {
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
return;
}
WSclient_t * client = &_clients[num];
if(clientIsConnected(client)) {
sendFrame(client, WSop_binary, payload, length);
}
}
/**
* send binary data to client all
* @param payload uint8_t *
* @param length size_t
*/
void WebSocketsServer::broadcastBIN(uint8_t * payload, size_t length) {
WSclient_t * client;
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
client = &_clients[i];
if(clientIsConnected(client)) {
sendFrame(client, WSop_binary, payload, length);
}
}
}
//################################################################################# //#################################################################################
//################################################################################# //#################################################################################
//################################################################################# //#################################################################################
/**
*
* @param client WSclient_t * ptr to the client struct
* @param opcode WSopcode_t
* @param payload uint8_t *
* @param lenght size_t
*/
void WebSocketsServer::messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t lenght) {
WStype_t type = WStype_ERROR;
switch(opcode) {
case WSop_text:
type = WStype_TEXT;
break;
case WSop_binary:
type = WStype_BIN;
break;
}
if(_cbEvent) {
_cbEvent(client->num, type, payload, lenght);
}
}
/** /**
* Disconnect an client * Disconnect an client
* @param client WSclients_t * ptr to the client struct * @param client WSclient_t * ptr to the client struct
*/ */
void WebSocketsServer::clientDisconnect(WSclient_t * client) { void WebSocketsServer::clientDisconnect(WSclient_t * client) {
@ -98,11 +207,14 @@ void WebSocketsServer::clientDisconnect(WSclient_t * client) {
DEBUG_WEBSOCKETS("[WS-Server][%d] client disconnected.\n", client->num); DEBUG_WEBSOCKETS("[WS-Server][%d] client disconnected.\n", client->num);
if(_cbEvent) {
_cbEvent(client->num, WStype_DISCONNECTED, NULL, 0);
}
} }
/** /**
* get client state * get client state
* @param client WSclients_t * ptr to the client struct * @param client WSclient_t * ptr to the client struct
* @return true = conneted * @return true = conneted
*/ */
bool WebSocketsServer::clientIsConnected(WSclient_t * client) { bool WebSocketsServer::clientIsConnected(WSclient_t * client) {
@ -189,7 +301,7 @@ void WebSocketsServer::handleClientData(void) {
/** /**
* handle the WebSocket header reading * handle the WebSocket header reading
* @param client WSclients_t * ptr to the client struct * @param client WSclient_t * ptr to the client struct
*/ */
void WebSocketsServer::handleHeader(WSclient_t * client) { void WebSocketsServer::handleHeader(WSclient_t * client) {
@ -225,13 +337,7 @@ void WebSocketsServer::handleHeader(WSclient_t * client) {
} else { } else {
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Header read fin.\n", client->num); DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Header read fin.\n", client->num);
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cURL: %s\n", client->num, client->cUrl.c_str()); DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cURL: %s\n", client->num, client->cUrl.c_str());DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cIsUpgrade: %d\n", client->num, client->cIsUpgrade);DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cIsWebsocket: %d\n", client->num, client->cIsWebsocket);DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cKey: %s\n", client->num, client->cKey.c_str());DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cProtocol: %s\n", client->num, client->cProtocol.c_str());DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cExtensions: %s\n", client->num, client->cExtensions.c_str());DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cVersion: %d\n", client->num, client->cVersion);
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cIsUpgrade: %d\n", client->num, client->cIsUpgrade);
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cIsWebsocket: %d\n", client->num, client->cIsWebsocket);
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cKey: %s\n", client->num, client->cKey.c_str());
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cProtocol: %s\n", client->num, client->cProtocol.c_str());
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cExtensions: %s\n", client->num, client->cExtensions.c_str());
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cVersion: %d\n", client->num, client->cVersion);
bool ok = (client->cIsUpgrade && client->cIsWebsocket); bool ok = (client->cIsUpgrade && client->cIsWebsocket);
@ -287,6 +393,10 @@ void WebSocketsServer::handleHeader(WSclient_t * client) {
// header end // header end
client->tcp.write("\r\n"); client->tcp.write("\r\n");
if(_cbEvent) {
_cbEvent(client->num, WStype_CONNECTED, NULL, 0);
}
} else { } else {
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] no Websocket connection close.\n", client->num); DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] no Websocket connection close.\n", client->num);
client->tcp.write("HTTP/1.1 400 Bad Request\r\n" client->tcp.write("HTTP/1.1 400 Bad Request\r\n"
@ -302,5 +412,3 @@ void WebSocketsServer::handleHeader(WSclient_t * client) {
} }
} }

View File

@ -42,14 +42,38 @@
#define WEBSOCKETS_SERVER_CLIENT_MAX (5) #define WEBSOCKETS_SERVER_CLIENT_MAX (5)
typedef enum {
WStype_ERROR,
WStype_DISCONNECTED,
WStype_CONNECTED,
WStype_TEXT,
WStype_BIN
} WStype_t;
class WebSocketsServer: private WebSockets { class WebSocketsServer: private WebSockets {
public: public:
typedef void (*WebSocketServerEvent)(uint8_t num, WStype_t type, uint8_t * payload, size_t length);
WebSocketsServer(uint16_t port); WebSocketsServer(uint16_t port);
~WebSocketsServer(void); ~WebSocketsServer(void);
void begin(void); void begin(void);
void loop(void); void loop(void);
void onEvent(WebSocketServerEvent cbEvent);
void sendTXT(uint8_t num, uint8_t * payload, size_t length);
void broadcastTXT(uint8_t * payload, size_t length);
void sendTXT(uint8_t num, String payload);
void broadcastTXT(String payload);
void sendBIN(uint8_t num, uint8_t * payload, size_t length);
void broadcastBIN(uint8_t * payload, size_t length);
private: private:
uint16_t _port; uint16_t _port;
@ -65,6 +89,10 @@ private:
WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX]; WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX];
WebSocketServerEvent _cbEvent;
void messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length);
void clientConnected(WSclient_t * client);
void clientDisconnect(WSclient_t * client); void clientDisconnect(WSclient_t * client);
bool clientIsConnected(WSclient_t * client); bool clientIsConnected(WSclient_t * client);

View File

@ -17,6 +17,10 @@ connection.onmessage = function (e) {
console.log('Server: ', e.data); console.log('Server: ', e.data);
}; };
setInterval(function() {
connection.send('Message from Browser to ESP8266 yay its Working!!');
}, 10000);
</script> </script>
</head> </head>