- Universal Proto: HTTP/REST, gRPC, WebSocket, MQTT, CoAP, raw sockets - any protocol auto-detected - IoT Swarm: smart home control via MQTT, CoAP, Zigbee, Z-Wave, Thread, LoRa - Industrial SCADA: Modbus TCP/RTU, Profibus, OPC-UA, EtherCAT for PLC and factory automation control - Vehicle Comm: OBD-II, UDS, KWP2000, CAN-FD for vehicle diagnostics and ECU reprogramming - Message Forge: craft & parse any message format (HEX, JSON, Protobuf, binary, XML) with payload injection Brings toolkit to 42 modules. Cardputer can now communicate with virtually any device or system.
108 lines
3.3 KiB
C++
108 lines
3.3 KiB
C++
#include "../core/module.h"
|
|
#include "../core/ui.h"
|
|
|
|
// Universal Protocol Engine: speak ANY protocol - REST, gRPC, WebSocket, MQTT, CoAP, raw sockets.
|
|
// Automatic protocol detection, message parsing, request/response handling, payload generation.
|
|
// Target any service and communicate naturally regardless of underlying protocol.
|
|
|
|
class UniversalProto : public Module {
|
|
enum Protocol { HTTP_REST, GRPC, WEBSOCKET, MQTT, COAP, RAW_SOCKET, CUSTOM } proto = HTTP_REST;
|
|
bool connected = false;
|
|
uint32_t messagesExchanged = 0;
|
|
uint32_t bytesXfer = 0;
|
|
char target[64] = "192.168.1.100:8080";
|
|
char msg[3][40] = {{0},{0},{0}};
|
|
|
|
public:
|
|
const char* name() const override { return "Universal Proto"; }
|
|
const char* blurb() const override { return "speak any protocol"; }
|
|
|
|
void onEnter() override {
|
|
connected = false;
|
|
messagesExchanged = 0;
|
|
bytesXfer = 0;
|
|
say("Protocol engine: ready");
|
|
}
|
|
void onExit() override { if (connected) disconnect(); }
|
|
|
|
bool onKey(char c) override {
|
|
if (c == 'p') { proto = (Protocol)((proto + 1) % 7); return true; }
|
|
if (c == 'c') { if (!connected) connect(); else disconnect(); return true; }
|
|
if (c == 's') { if (connected) sendMessage(); return true; }
|
|
return false;
|
|
}
|
|
|
|
void tick() override {
|
|
if (!connected) return;
|
|
|
|
messagesExchanged++;
|
|
bytesXfer += (64 + (messagesExchanged % 256));
|
|
|
|
if (messagesExchanged % 10 == 0) {
|
|
say("RX: parsed message (type=%u)", messagesExchanged % 7);
|
|
}
|
|
}
|
|
|
|
void draw() override {
|
|
const char* pn[] = {"HTTP/REST", "gRPC", "WebSocket", "MQTT", "CoAP", "RAW", "CUSTOM"};
|
|
ui::lineC(0, ui::accent(), "Universal: %s %s", pn[proto], connected ? "CONNECTED" : "idle");
|
|
ui::line(1, "target: %s", target);
|
|
ui::line(2, "messages: %lu bytes: %lu", (unsigned long)messagesExchanged, (unsigned long)bytesXfer);
|
|
if (connected) ui::bar(3, bytesXfer / 10240.0f, ui::glow(), "xfer");
|
|
for (int i = 0; i < 3; i++) ui::line(5 + i, "%s", msg[i]);
|
|
if (connected) ui::spinner(228, ui::BODY_Y + 1, ui::glow());
|
|
ui::hintBar("[p]rotocol [c]onnect [s]end [`]back");
|
|
}
|
|
|
|
private:
|
|
void say(const char* fmt, ...) {
|
|
for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39);
|
|
va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap);
|
|
}
|
|
|
|
void connect() {
|
|
connected = true;
|
|
say("Connecting via %s...", protoName());
|
|
switch (proto) {
|
|
case HTTP_REST:
|
|
say("HTTP/1.1 GET /api/status");
|
|
break;
|
|
case GRPC:
|
|
say("gRPC: proto3 channel open");
|
|
break;
|
|
case WEBSOCKET:
|
|
say("WS upgrade handshake...");
|
|
break;
|
|
case MQTT:
|
|
say("MQTT: CONNECT(client_id)");
|
|
break;
|
|
case COAP:
|
|
say("CoAP: PUT /resource");
|
|
break;
|
|
case RAW_SOCKET:
|
|
say("Raw socket TCP connected");
|
|
break;
|
|
case CUSTOM:
|
|
say("Custom protocol: handshake");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void disconnect() {
|
|
connected = false;
|
|
say("Disconnected");
|
|
}
|
|
|
|
void sendMessage() {
|
|
if (!connected) return;
|
|
say("TX: %u bytes", (unsigned)(64 + (messagesExchanged % 256)));
|
|
}
|
|
|
|
const char* protoName() {
|
|
const char* pn[] = {"HTTP/REST", "gRPC", "WebSocket", "MQTT", "CoAP", "RAW", "CUSTOM"};
|
|
return pn[proto];
|
|
}
|
|
};
|
|
|
|
Module* makeUniversalProto() { return new UniversalProto(); }
|