- Added readSerial(Stream &stream) method to allow reading from any Stream-compatible transport. - Introduced readChar(char inChar) method for processing individual characters. - Updated command matching logic to enhance debugging output. - Improved buffer handling and command execution flow. Enhance platformio.ini for better compatibility and added libraries - Added NimBLE-Arduino and WebSockets libraries for BLE and WiFi support. - Updated upload and monitor ports for better compatibility with macOS. Integrate WiFi and BLE protocol interfaces - Implemented startWebInterface() to initialize WiFi protocol alongside existing web server. - Added BLE support with a new EggBot BLE Serial Protocol for command handling over BLE. - Created WebSocket server for WiFi communication, maintaining compatibility with existing command protocols. Refactor command handling in Functions.cpp - Replaced direct Serial.print calls with protocolWrite for consistent output handling. - Updated command registration to use a lambda function for better readability and maintainability. Add documentation for EggBot protocols - Created separate markdown files for BLE, WiFi, and Serial protocols detailing command structures and usage. - Provided examples of command transactions for better developer guidance. Implement BLE and WiFi protocol handling in respective source files - Developed BLE_Interface.cpp for managing BLE connections and data transmission. - Created WiFi_Protocol.cpp for handling WebSocket communication and data reception.
157 lines
3.0 KiB
C++
157 lines
3.0 KiB
C++
#include "EggDuino.h"
|
|
|
|
#ifdef ESP32
|
|
#include <WebSocketsServer.h>
|
|
|
|
namespace
|
|
{
|
|
constexpr uint16_t kWifiProtocolPort = 1337;
|
|
constexpr uint8_t kInvalidWifiClientId = 0xFF;
|
|
constexpr size_t kWifiRxQueueSize = 1024;
|
|
|
|
struct WifiRxByte
|
|
{
|
|
uint8_t value;
|
|
};
|
|
|
|
WebSocketsServer g_wifiProtocolSocket(kWifiProtocolPort);
|
|
WifiRxByte g_wifiRxQueue[kWifiRxQueueSize];
|
|
size_t g_wifiRxHead = 0;
|
|
size_t g_wifiRxTail = 0;
|
|
bool g_wifiRxOverflow = false;
|
|
bool g_wifiProtocolStarted = false;
|
|
uint8_t g_wifiProtocolClientId = kInvalidWifiClientId;
|
|
|
|
bool queueWifiByte(uint8_t value)
|
|
{
|
|
const size_t nextHead = (g_wifiRxHead + 1) % kWifiRxQueueSize;
|
|
if (nextHead == g_wifiRxTail)
|
|
{
|
|
g_wifiRxOverflow = true;
|
|
return false;
|
|
}
|
|
|
|
g_wifiRxQueue[g_wifiRxHead].value = value;
|
|
g_wifiRxHead = nextHead;
|
|
return true;
|
|
}
|
|
|
|
bool dequeueWifiByte(WifiRxByte *byte)
|
|
{
|
|
if ((byte == NULL) || (g_wifiRxHead == g_wifiRxTail))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
*byte = g_wifiRxQueue[g_wifiRxTail];
|
|
g_wifiRxTail = (g_wifiRxTail + 1) % kWifiRxQueueSize;
|
|
return true;
|
|
}
|
|
|
|
void handleWifiSocketEvent(uint8_t clientId, WStype_t type, uint8_t *payload, size_t length)
|
|
{
|
|
(void)payload;
|
|
|
|
switch (type)
|
|
{
|
|
case WStype_CONNECTED:
|
|
if (g_wifiProtocolClientId == kInvalidWifiClientId)
|
|
{
|
|
g_wifiProtocolClientId = clientId;
|
|
}
|
|
Log(String("WiFi protocol client connected: ") + clientId);
|
|
break;
|
|
|
|
case WStype_DISCONNECTED:
|
|
if (g_wifiProtocolClientId == clientId)
|
|
{
|
|
g_wifiProtocolClientId = kInvalidWifiClientId;
|
|
}
|
|
Log(String("WiFi protocol client disconnected: ") + clientId);
|
|
break;
|
|
|
|
case WStype_TEXT:
|
|
case WStype_BIN:
|
|
if (g_wifiProtocolClientId == kInvalidWifiClientId)
|
|
{
|
|
g_wifiProtocolClientId = clientId;
|
|
}
|
|
if (clientId != g_wifiProtocolClientId)
|
|
{
|
|
break;
|
|
}
|
|
for (size_t i = 0; i < length; ++i)
|
|
{
|
|
queueWifiByte(payload[i]);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
} // namespace
|
|
|
|
void startWifiProtocolInterface()
|
|
{
|
|
if (g_wifiProtocolStarted)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (WiFi.status() != WL_CONNECTED)
|
|
{
|
|
return;
|
|
}
|
|
|
|
g_wifiProtocolSocket.begin();
|
|
g_wifiProtocolSocket.onEvent(handleWifiSocketEvent);
|
|
g_wifiProtocolStarted = true;
|
|
|
|
Log(String("WiFi EggBot protocol ws://") + WiFi.localIP().toString() + ":" + kWifiProtocolPort);
|
|
}
|
|
|
|
void handleWifiProtocolInterface()
|
|
{
|
|
if (!g_wifiProtocolStarted)
|
|
{
|
|
if (WiFi.status() == WL_CONNECTED)
|
|
{
|
|
startWifiProtocolInterface();
|
|
}
|
|
return;
|
|
}
|
|
|
|
g_wifiProtocolSocket.loop();
|
|
|
|
if (g_wifiRxOverflow)
|
|
{
|
|
g_wifiRxOverflow = false;
|
|
Log("WiFi protocol RX queue overflow");
|
|
}
|
|
|
|
WifiRxByte byte = {0};
|
|
while (dequeueWifiByte(&byte))
|
|
{
|
|
setActiveProtocolContext(&g_WifiCmd, PROTOCOL_TRANSPORT_WIFI);
|
|
g_WifiCmd.readChar(static_cast<char>(byte.value));
|
|
}
|
|
}
|
|
|
|
bool wifiProtocolWrite(const char *message)
|
|
{
|
|
if (!g_wifiProtocolStarted || (message == NULL))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ((g_wifiProtocolClientId == kInvalidWifiClientId) || !g_wifiProtocolSocket.clientIsConnected(g_wifiProtocolClientId))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return g_wifiProtocolSocket.sendTXT(g_wifiProtocolClientId, message);
|
|
}
|
|
|
|
#endif
|