From ea00370bdb4ac917206b2ab5a5cd8b32d1b0a390 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 22 Apr 2024 15:12:15 +0100 Subject: [PATCH] Improvements to HostEd (#2768) This PR proposes some changes to the Hosted classes **Update simpleRPC to master** With clang-tidy #2648 some failures occur in the `simpleRPC` library. Updating this to current master solves the issues. I've also put all the code into the `simpleRPC` namespace which sorts out the conflict with `Vector` but makes it available for use if required. **Tidy HostTests module** Also decode the anonymous 'packet' blob so we can see what's in it and compare with spec. should we wish to update it. **Use abstract base class for callbacks** Simplifies implementation since usually all callbacks are required. Compiler ensures all methods have implementations. `clang-tidy` gave potential memory leak indication because of Delegates. Not sure if that's real but this fixes it. --- .../Components/hostlib/include/hostlib/init.h | 30 ---- Sming/Arch/Host/Components/hostlib/init.cpp | 27 ---- .../Arch/Host/Components/hostlib/startup.cpp | 5 +- Sming/Arch/Host/app.mk | 4 +- Sming/Components/Hosted/README.rst | 8 +- Sming/Components/Hosted/component.mk | 16 +- .../Components/Hosted/include/Hosted/Client.h | 29 ++-- .../Components/Hosted/include/Hosted/Serial.h | 1 - .../include/Hosted/Transport/BaseTransport.h | 8 +- .../Hosted/Transport/SerialTransport.h | 8 +- .../Hosted/Transport/TcpClientStream.h | 12 +- .../Hosted/Transport/TcpClientTransport.h | 10 +- .../Hosted/Transport/TcpServerTransport.h | 12 +- .../include/Hosted/Transport/TcpTransport.h | 8 +- .../Hosted/init/serial/InitClient.cpp | 20 ++- .../Components/Hosted/init/tcp/InitClient.cpp | 23 ++- .../Hosted/samples/serial/app/application.cpp | 39 ++--- .../Hosted/samples/tcp/app/application.cpp | 2 +- .../Hosted/samples/tcp/component.mk | 2 +- Sming/Components/Hosted/src/Util.cpp | 2 +- .../simpleRPC/include/simpleRPC/parser.h | 28 ++-- Sming/Components/simpleRPC/simpleRPC | 2 +- Sming/Components/simpleRPC/simpleRPC.patch | 69 ++++----- Sming/Components/simpleRPC/src/parser.cpp | 50 +++--- .../modules/Network/Arch/Host/Hosted.cpp | 143 +++++++++--------- 25 files changed, 238 insertions(+), 320 deletions(-) delete mode 100644 Sming/Arch/Host/Components/hostlib/include/hostlib/init.h delete mode 100644 Sming/Arch/Host/Components/hostlib/init.cpp diff --git a/Sming/Arch/Host/Components/hostlib/include/hostlib/init.h b/Sming/Arch/Host/Components/hostlib/include/hostlib/init.h deleted file mode 100644 index 6b73b8afbc..0000000000 --- a/Sming/Arch/Host/Components/hostlib/include/hostlib/init.h +++ /dev/null @@ -1,30 +0,0 @@ -/**** - * hostlib.h - * - * Copyright 2019 mikee47 - * - * This file is part of the Sming Framework Project - * - * This library is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, version 3 or later. - * - * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with SHEM. - * If not, see . - * - ****/ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -void host_init(); - -#ifdef __cplusplus -} -#endif diff --git a/Sming/Arch/Host/Components/hostlib/init.cpp b/Sming/Arch/Host/Components/hostlib/init.cpp deleted file mode 100644 index 4246269810..0000000000 --- a/Sming/Arch/Host/Components/hostlib/init.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/** - * init.cpp - Sming Host Emulator startup code - * - * Copyright 2019 mikee47 - * - * This file is part of the Sming Framework Project - * - * This library is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, version 3 or later. - * - * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with SHEM. - * If not, see . - * - ****/ - -#include "include/hostlib/init.h" - -extern void init(); - -void host_init() -{ - init(); -} diff --git a/Sming/Arch/Host/Components/hostlib/startup.cpp b/Sming/Arch/Host/Components/hostlib/startup.cpp index 8bb37fe968..4286327055 100644 --- a/Sming/Arch/Host/Components/hostlib/startup.cpp +++ b/Sming/Arch/Host/Components/hostlib/startup.cpp @@ -32,7 +32,6 @@ #include #include #include -#include "include/hostlib/init.h" #include "include/hostlib/emu.h" #include "include/hostlib/hostlib.h" #include "include/hostlib/CommandLine.h" @@ -43,6 +42,8 @@ #include #endif +extern void init(); + namespace { static int exitCode; @@ -286,7 +287,7 @@ int main(int argc, char* argv[]) System.initialize(); - host_init(); + init(); while(!done) { int due = host_main_loop(); diff --git a/Sming/Arch/Host/app.mk b/Sming/Arch/Host/app.mk index 795589309a..a2a92ebb85 100644 --- a/Sming/Arch/Host/app.mk +++ b/Sming/Arch/Host/app.mk @@ -14,7 +14,9 @@ TARGET_OUT_0 := $(FW_BASE)/$(APP_NAME)$(TOOL_EXT) # Hosted Settings ifneq ($(ENABLE_HOSTED),) - COMPONENTS_AR := $(USER_LIBDIR)/$(CLIB_PREFIX)Hosted-Lib-$(CMP_Hosted-Lib_LIBHASH).a $(COMPONENTS_AR) +COMPONENTS_AR := \ + $(CMP_Hosted-Lib_TARGETS) \ + $(COMPONENTS_AR) endif # Target definitions diff --git a/Sming/Components/Hosted/README.rst b/Sming/Components/Hosted/README.rst index 6acc1b9f58..d167327cf9 100644 --- a/Sming/Components/Hosted/README.rst +++ b/Sming/Components/Hosted/README.rst @@ -6,8 +6,10 @@ HostEd The hosted component allows Sming's host emulator to run parts of the commands on an actual microcontroller. The communication is done via `simplePRC `_ and the microcontroller has to be flashed with a special application. + Overview -------- + Sming's host emulator allows easier debugging and development of embedded applications. This component named "Hosted" extends the host emulator and facilitates testing functionality that only a real microcontroller can provide as for example digital I/O operations or SPI operations. @@ -24,7 +26,7 @@ We need to compile and flash also a special application on the desired microcont This application will act as an RPC Server and will execute the commands from the host emulator on the microcontroller. In the ``samples`` directory you will find the sample applications that will turn your microcontroller into -an RCP server. +an RPC server. The compilation and flashing for ESP32, for example, can be done using the following commands:: @@ -33,7 +35,8 @@ The compilation and flashing for ESP32, for example, can be done using the follo make flash If you replace ``SMING_ARCH=Esp32`` with ``SMING_ARCH=Esp8266`` then the hosted application will be compiled and flashed on a ESP8266 microcontroller. -Make sure to replace the values of  WIFI_SSID and WIFI_PWD with the actual name and password for the Access Point (AP). +Make sure to replace the values of WIFI_SSID and WIFI_PWD with the actual name and password for the Access Point (AP). + Communication ------------- @@ -42,6 +45,7 @@ can be done using TCP or serial interface. The ``transport`` classes are located under ``include/Hosted/Transport``. + Configuration ------------- diff --git a/Sming/Components/Hosted/component.mk b/Sming/Components/Hosted/component.mk index 4d19f5a640..9916e6aedb 100644 --- a/Sming/Components/Hosted/component.mk +++ b/Sming/Components/Hosted/component.mk @@ -11,7 +11,7 @@ ENABLE_HOSTED ?= ifneq ($(ENABLE_HOSTED),) COMPONENT_SRCDIRS += init/$(ENABLE_HOSTED) - EXTRA_LDFLAGS := $(call Wrap,host_init) + EXTRA_LDFLAGS := $(call Wrap,_Z4initv) COMPONENT_DEPENDS += SerialLib ifeq ($(ENABLE_HOSTED),tcp) COMPONENT_DEPENDS += Network @@ -20,13 +20,17 @@ ifneq ($(ENABLE_HOSTED),) endif endif -COMPONENT_RELINK_VARS += HOSTED_SERVER_IP +COMPONENT_RELINK_VARS += \ + HOSTED_SERVER_IP \ + HOSTED_COM_PORT \ + HOSTED_COM_SPEED -COMPONENT_RELINK_VARS += HOSTED_COM_PORT HOSTED_COM_PORT ?= $(COM_PORT) - -COMPONENT_RELINK_VARS += HOSTED_COM_SPEED HOSTED_COM_SPEED ?= 115200 -COMPONENT_CFLAGS = -DHOSTED_SERVER_IP=$(HOSTED_SERVER_IP) -DHOSTED_COM_PORT="\"$(HOSTED_COM_PORT)"\" -DHOSTED_COM_SPEED=$(HOSTED_COM_SPEED) +COMPONENT_CFLAGS = \ + -DHOSTED_SERVER_IP=$(HOSTED_SERVER_IP) \ + -DHOSTED_COM_PORT="\"$(HOSTED_COM_PORT)"\" \ + -DHOSTED_COM_SPEED=$(HOSTED_COM_SPEED) + COMPONENT_CXXFLAGS := $(COMPONENT_CFLAGS) diff --git a/Sming/Components/Hosted/include/Hosted/Client.h b/Sming/Components/Hosted/include/Hosted/Client.h index 55c981c904..d7e76f91a7 100644 --- a/Sming/Components/Hosted/include/Hosted/Client.h +++ b/Sming/Components/Hosted/include/Hosted/Client.h @@ -26,13 +26,11 @@ #include #include "Util.h" -using namespace simpleRPC; - namespace Hosted { constexpr int COMMAND_NOT_FOUND = -1; -class Client +class Client : private simpleRPC::ParserCallbacks { public: using RemoteCommands = HashMap; @@ -64,7 +62,7 @@ class Client return false; } - rpcPrint(stream, uint8_t(functionId), args...); + simpleRPC::rpcPrint(stream, uint8_t(functionId), args...); stream.flush(); return true; @@ -120,17 +118,12 @@ class Client { host_debug_i("Getting remote RPC commands \033[5m...\033[0m"); + using namespace simpleRPC; + uint8_t head = 0xff; stream.write(&head, 1); char buffer[512]; - ParserSettings settings; - settings.startMethods = ParserSettings::SimpleMethod(&Client::startMethods, this); - settings.startMethod = ParserSettings::SimpleMethod(&Client::startMethod, this); - settings.methodSignature = ParserSettings::CharMethod(&Client::methodSignature, this); - settings.methodName = ParserSettings::CharMethod(&Client::methodName, this); - settings.endMethod = ParserSettings::SimpleMethod(&Client::endMethod, this); - settings.endMethods = ParserSettings::SimpleMethod(&Client::endMethods, this); - settings.state = ParserState::ready; + ParserSettings settings{*this}; do { stream.flush(); @@ -172,29 +165,29 @@ class Client String signature; char methodEndsWith; - void startMethods() + void startMethods() override { methodPosition = 0; commands.clear(); } - void startMethod() + void startMethod() override { name = ""; signature = ""; } - void methodSignature(char ch) + void methodSignature(char ch) override { signature += ch; } - void methodName(char ch) + void methodName(char ch) override { name += ch; } - void endMethod() + void endMethod() override { if(!commands.contains(name) || signature == ":") { commands[name] = methodPosition; @@ -202,7 +195,7 @@ class Client commands[name + "(" + signature + ")"] = methodPosition++; } - void endMethods() + void endMethods() override { fetchCommands = false; } diff --git a/Sming/Components/Hosted/include/Hosted/Serial.h b/Sming/Components/Hosted/include/Hosted/Serial.h index 3f65340e8b..f5d703580f 100644 --- a/Sming/Components/Hosted/include/Hosted/Serial.h +++ b/Sming/Components/Hosted/include/Hosted/Serial.h @@ -116,7 +116,6 @@ class Serial : public Stream private: String ttyDevice; - serialib transport; }; diff --git a/Sming/Components/Hosted/include/Hosted/Transport/BaseTransport.h b/Sming/Components/Hosted/include/Hosted/Transport/BaseTransport.h index 484a568c02..186db741bf 100644 --- a/Sming/Components/Hosted/include/Hosted/Transport/BaseTransport.h +++ b/Sming/Components/Hosted/include/Hosted/Transport/BaseTransport.h @@ -16,9 +16,7 @@ #include #include -namespace Hosted -{ -namespace Transport +namespace Hosted::Transport { class BaseTransport { @@ -38,6 +36,4 @@ class BaseTransport DataHandler handler; }; -} // namespace Transport - -} // namespace Hosted +} // namespace Hosted::Transport diff --git a/Sming/Components/Hosted/include/Hosted/Transport/SerialTransport.h b/Sming/Components/Hosted/include/Hosted/Transport/SerialTransport.h index 6dca2b1510..e044ca9057 100644 --- a/Sming/Components/Hosted/include/Hosted/Transport/SerialTransport.h +++ b/Sming/Components/Hosted/include/Hosted/Transport/SerialTransport.h @@ -16,9 +16,7 @@ #include #include "BaseTransport.h" -namespace Hosted -{ -namespace Transport +namespace Hosted::Transport { class SerialTransport : public BaseTransport { @@ -35,6 +33,4 @@ class SerialTransport : public BaseTransport } }; -} // namespace Transport - -} // namespace Hosted +} // namespace Hosted::Transport diff --git a/Sming/Components/Hosted/include/Hosted/Transport/TcpClientStream.h b/Sming/Components/Hosted/include/Hosted/Transport/TcpClientStream.h index 1d43fcc872..d1809f4078 100644 --- a/Sming/Components/Hosted/include/Hosted/Transport/TcpClientStream.h +++ b/Sming/Components/Hosted/include/Hosted/Transport/TcpClientStream.h @@ -16,15 +16,13 @@ #include #include -namespace Hosted -{ -namespace Transport +namespace Hosted::Transport { class TcpClientStream : public Stream { public: TcpClientStream(TcpClient& client, size_t cbufferSize = 1024, size_t threshold = 400) - : cBuffer(cbufferSize), client(client), pendingBytes(0), threshold(threshold) + : cBuffer(cbufferSize), client(client), threshold(threshold) { client.setReceiveDelegate(TcpClientDataDelegate(&TcpClientStream::store, this)); } @@ -87,7 +85,7 @@ class TcpClientStream : public Stream private: CircularBuffer cBuffer; TcpClient& client; - size_t pendingBytes; + size_t pendingBytes{0}; size_t threshold; bool store(TcpClient& client, char* data, int size) @@ -96,6 +94,4 @@ class TcpClientStream : public Stream } }; -} // namespace Transport - -} // namespace Hosted +} // namespace Hosted::Transport diff --git a/Sming/Components/Hosted/include/Hosted/Transport/TcpClientTransport.h b/Sming/Components/Hosted/include/Hosted/Transport/TcpClientTransport.h index 0971b0c496..d9c7b53409 100644 --- a/Sming/Components/Hosted/include/Hosted/Transport/TcpClientTransport.h +++ b/Sming/Components/Hosted/include/Hosted/Transport/TcpClientTransport.h @@ -18,14 +18,12 @@ #include "TcpClientStream.h" #include -namespace Hosted -{ -namespace Transport +namespace Hosted::Transport { class TcpClientTransport : public TcpTransport { public: - TcpClientTransport(TcpClient& client) : stream(new TcpClientStream(client)) + TcpClientTransport(TcpClient& client) : stream(std::make_unique(client)) { client.setReceiveDelegate(TcpClientDataDelegate(&TcpClientTransport::process, this)); } @@ -44,6 +42,4 @@ class TcpClientTransport : public TcpTransport std::unique_ptr stream; }; -} // namespace Transport - -} // namespace Hosted +} // namespace Hosted::Transport diff --git a/Sming/Components/Hosted/include/Hosted/Transport/TcpServerTransport.h b/Sming/Components/Hosted/include/Hosted/Transport/TcpServerTransport.h index 6e85cafc43..bfd387ea8b 100644 --- a/Sming/Components/Hosted/include/Hosted/Transport/TcpServerTransport.h +++ b/Sming/Components/Hosted/include/Hosted/Transport/TcpServerTransport.h @@ -18,15 +18,11 @@ #include "TcpTransport.h" #include "TcpClientStream.h" -namespace Hosted -{ -namespace Transport +namespace Hosted::Transport { class TcpServerTransport : public TcpTransport { public: - using ClientMap = ObjectMap; - TcpServerTransport(TcpServer& server) { server.setClientReceiveHandler(TcpClientDataDelegate(&TcpServerTransport::process, this)); @@ -52,9 +48,9 @@ class TcpServerTransport : public TcpTransport } private: + using ClientMap = ObjectMap; + ClientMap map; }; -} // namespace Transport - -} // namespace Hosted +} // namespace Hosted::Transport diff --git a/Sming/Components/Hosted/include/Hosted/Transport/TcpTransport.h b/Sming/Components/Hosted/include/Hosted/Transport/TcpTransport.h index 9553430592..3099167f75 100644 --- a/Sming/Components/Hosted/include/Hosted/Transport/TcpTransport.h +++ b/Sming/Components/Hosted/include/Hosted/Transport/TcpTransport.h @@ -16,9 +16,7 @@ #include #include "BaseTransport.h" -namespace Hosted -{ -namespace Transport +namespace Hosted::Transport { class TcpTransport : public BaseTransport { @@ -26,6 +24,4 @@ class TcpTransport : public BaseTransport virtual bool process(TcpClient& client, char* data, int size) = 0; }; -} // namespace Transport - -} // namespace Hosted +} // namespace Hosted::Transport diff --git a/Sming/Components/Hosted/init/serial/InitClient.cpp b/Sming/Components/Hosted/init/serial/InitClient.cpp index f1ecbed542..91eb3a7177 100644 --- a/Sming/Components/Hosted/init/serial/InitClient.cpp +++ b/Sming/Components/Hosted/init/serial/InitClient.cpp @@ -22,27 +22,25 @@ #define HOSTED_COM_SPEED 115200 #endif -Hosted::Client* hostedClient{nullptr}; +Hosted::Client* hostedClient; -extern void init(); - -extern "C" { -void __real_host_init(); -void __wrap_host_init(); -} +extern "C" void __real__Z4initv(); +namespace +{ Hosted::Serial hostedSerial(HOSTED_COM_PORT); +} -void __wrap_host_init() +extern "C" void __wrap__Z4initv() { host_printf("Connecting to: %s ...\r\n", HOSTED_COM_PORT); - bool serialReady = false; - while(!(serialReady = hostedSerial.begin(HOSTED_COM_SPEED))) { + while(!hostedSerial.begin(HOSTED_COM_SPEED)) { msleep(50); } hostedClient = new Hosted::Client(hostedSerial, '>'); hostedClient->getRemoteCommands(); - init(); + + __real__Z4initv(); } diff --git a/Sming/Components/Hosted/init/tcp/InitClient.cpp b/Sming/Components/Hosted/init/tcp/InitClient.cpp index 3e4dce3bc7..dce5a33439 100644 --- a/Sming/Components/Hosted/init/tcp/InitClient.cpp +++ b/Sming/Components/Hosted/init/tcp/InitClient.cpp @@ -11,11 +11,12 @@ * ****/ -#include +#include +#include #include #include -Hosted::Client* hostedClient{nullptr}; +Hosted::Client* hostedClient; #ifndef WIFI_SSID #define WIFI_SSID "PleaseEnterSSID" // Put your SSID and password here @@ -30,19 +31,14 @@ Hosted::Client* hostedClient{nullptr}; #define REMOTE_IP STRINGIFY(HOSTED_SERVER_IP) #endif -extern "C" { -void __real_host_init(); -void __wrap_host_init(); -} - -extern void init(); +extern "C" void __real__Z4initv(); namespace { -TcpClient* tcpClient = nullptr; -Hosted::Transport::TcpClientStream* stream = nullptr; +TcpClient* tcpClient; +Hosted::Transport::TcpClientStream* stream; -static void ready(IpAddress ip, IpAddress mask, IpAddress gateway) +void ready(IpAddress ip, IpAddress mask, IpAddress gateway) { if(hostedClient != nullptr) { return; @@ -59,12 +55,13 @@ static void ready(IpAddress ip, IpAddress mask, IpAddress gateway) hostedClient = new Hosted::Client(*stream, '>'); hostedClient->getRemoteCommands(); - init(); + + __real__Z4initv(); } } // namespace -void __wrap_host_init() +extern "C" void __wrap__Z4initv() { WifiEvents.onStationGotIP(ready); WifiStation.enable(true); diff --git a/Sming/Components/Hosted/samples/serial/app/application.cpp b/Sming/Components/Hosted/samples/serial/app/application.cpp index 5f5c0288d4..734f88221f 100644 --- a/Sming/Components/Hosted/samples/serial/app/application.cpp +++ b/Sming/Components/Hosted/samples/serial/app/application.cpp @@ -8,14 +8,15 @@ using namespace Hosted::Transport; -SerialTransport* transport = nullptr; +SerialTransport transport(Serial); void init() { Serial.begin(SERIAL_BAUD_RATE); - transport = new SerialTransport(Serial); - transport->onData([](Stream& stream) { + using namespace simpleRPC; + + transport.onData([](Stream& stream) { // clang-format off interface(stream, /* @@ -28,25 +29,25 @@ void init() digitalWrite, F("digitalWrite> Write to a digital pin. @pin: Pin number. @value: Pin value."), pulseIn, F("pulseIn> Measure duration of pulse on pin. @pin: Pin number. @state: State of pulse to measure. @timeout: Maximum duration of pulse. @return: Pulse duration in microseconds)"), // void TwoWire::begin(uint8_t sda, uint8_t scl) - pack(&Wire, (void(TwoWire::*)(uint8_t,uint8_t))&TwoWire::begin), F("TwoWire::begin> Starts two-wire communication. @sda: Data pin. @scl: Clock pin."), + makeTuple(&Wire, static_cast(&TwoWire::begin)), F("TwoWire::begin> Starts two-wire communication. @sda: Data pin. @scl: Clock pin."), // void TwoWire::begin() - pack(&Wire, (void(TwoWire::*)(void))&TwoWire::begin), F("TwoWire::begin> Starts two-wire communication."), - pack(&Wire, &TwoWire::pins), F("TwoWire::pins> Starts two-wire communication. @sda: Data pin. @scl: Clock pin."), - pack(&Wire, &TwoWire::status), F("TwoWire::status> Get status."), - pack(&Wire, &TwoWire::end), F("TwoWire::end> Ends two-wire communication."), - pack(&Wire, &TwoWire::setClock), F("TwoWire::setClock> Sets clock frequency. @freq: clock frequency."), - pack(&Wire, &TwoWire::setClockStretchLimit), F("TwoWire::setClockStretchLimit> Sts clock stretch limit. @limit: stretch limit."), - pack(&Wire, &TwoWire::requestFrom), F("TwoWire::requestFrom> Request from. @address: Address. @size: Size. @sendStop flag. @return: uint8_t."), - pack(&Wire, &TwoWire::beginTransmission), F("TwoWire::beginTransmission> Begin transmission. @address: Address."), - pack(&Wire, &TwoWire::endTransmission), F("TwoWire::endTransmission> End transmission. @sendStop: flag. @return: error code"), + makeTuple(&Wire, static_cast(&TwoWire::begin)), F("TwoWire::begin> Starts two-wire communication."), + makeTuple(&Wire, &TwoWire::pins), F("TwoWire::pins> Starts two-wire communication. @sda: Data pin. @scl: Clock pin."), + makeTuple(&Wire, &TwoWire::status), F("TwoWire::status> Get status."), + makeTuple(&Wire, &TwoWire::end), F("TwoWire::end> Ends two-wire communication."), + makeTuple(&Wire, &TwoWire::setClock), F("TwoWire::setClock> Sets clock frequency. @freq: clock frequency."), + makeTuple(&Wire, &TwoWire::setClockStretchLimit), F("TwoWire::setClockStretchLimit> Sts clock stretch limit. @limit: stretch limit."), + makeTuple(&Wire, &TwoWire::requestFrom), F("TwoWire::requestFrom> Request from. @address: Address. @size: Size. @sendStop flag. @return: uint8_t."), + makeTuple(&Wire, &TwoWire::beginTransmission), F("TwoWire::beginTransmission> Begin transmission. @address: Address."), + makeTuple(&Wire, &TwoWire::endTransmission), F("TwoWire::endTransmission> End transmission. @sendStop: flag. @return: error code"), // size_t TwoWire::write(uint8_t data) - pack(&Wire, (size_t(TwoWire::*)(uint8_t))&TwoWire::write), F("TwoWire::write> Write byte. @data: byte. @return: written bytes"), + makeTuple(&Wire, static_cast(&TwoWire::write)), F("TwoWire::write> Write byte. @data: byte. @return: written bytes"), // size_t TwoWire::write(const uint8_t* data, size_t quantity) - pack(&Wire, (size_t(TwoWire::*)(const uint8_t*, size_t))&TwoWire::write), F("TwoWire::write> Write bytes. @data: data pointer. @quantity: data size. @return: written bytes"), - pack(&Wire, &TwoWire::available), F("TwoWire::available> Available bytes. @return: count"), - pack(&Wire, &TwoWire::read), F("TwoWire::read> Read a byte. @return: byte"), - pack(&Wire, &TwoWire::peek), F("TwoWire::peek> Peek. @return: byte without advancing the internal pointer."), - pack(&Wire, &TwoWire::flush), F("TwoWire::flush> Flush.") + makeTuple(&Wire, static_cast(&TwoWire::write)), F("TwoWire::write> Write bytes. @data: data pointer. @quantity: data size. @return: written bytes"), + makeTuple(&Wire, &TwoWire::available), F("TwoWire::available> Available bytes. @return: count"), + makeTuple(&Wire, &TwoWire::read), F("TwoWire::read> Read a byte. @return: byte"), + makeTuple(&Wire, &TwoWire::peek), F("TwoWire::peek> Peek. @return: byte without advancing the internal pointer."), + makeTuple(&Wire, &TwoWire::flush), F("TwoWire::flush> Flush.") ); // clang-format on diff --git a/Sming/Components/Hosted/samples/tcp/app/application.cpp b/Sming/Components/Hosted/samples/tcp/app/application.cpp index 54ceb15e6e..a7e264cd19 100644 --- a/Sming/Components/Hosted/samples/tcp/app/application.cpp +++ b/Sming/Components/Hosted/samples/tcp/app/application.cpp @@ -38,7 +38,7 @@ void connectOk(IpAddress ip, IpAddress mask, IpAddress gateway) transport = new TcpServerTransport(*server); transport->onData([](Stream& stream) { // clang-format off - interface(stream, + simpleRPC::interface(stream, /* * Below we are exporting the following remote commands: * - pinMode diff --git a/Sming/Components/Hosted/samples/tcp/component.mk b/Sming/Components/Hosted/samples/tcp/component.mk index 8883932d4c..26c10562da 100644 --- a/Sming/Components/Hosted/samples/tcp/component.mk +++ b/Sming/Components/Hosted/samples/tcp/component.mk @@ -4,7 +4,7 @@ ENABLE_HOSTED := # If set the application should connect to a WIFI access point # otherwise it will set its own access point -COMPONENT_RELINK_VARS := CONNECT_TO_WIFI +CONFIG_VARS := CONNECT_TO_WIFI CONNECT_TO_WIFI ?= 0 APP_CFLAGS = -DCONNECT_TO_WIFI=$(CONNECT_TO_WIFI) diff --git a/Sming/Components/Hosted/src/Util.cpp b/Sming/Components/Hosted/src/Util.cpp index dde76ac755..11d9c6ecb5 100644 --- a/Sming/Components/Hosted/src/Util.cpp +++ b/Sming/Components/Hosted/src/Util.cpp @@ -36,7 +36,7 @@ char convertType(const String& type) // TODO: ... add all types... if(type != "void") { - debug_w("Unknown type: %s", type); + debug_w("Unknown type: %s", type.c_str()); } // void and unknown diff --git a/Sming/Components/simpleRPC/include/simpleRPC/parser.h b/Sming/Components/simpleRPC/include/simpleRPC/parser.h index d797cbc51f..2c43bfd890 100644 --- a/Sming/Components/simpleRPC/include/simpleRPC/parser.h +++ b/Sming/Components/simpleRPC/include/simpleRPC/parser.h @@ -14,6 +14,7 @@ #pragma once #include +#include namespace simpleRPC { @@ -47,19 +48,28 @@ enum class ParserState { finished }; -struct ParserSettings { - using SimpleMethod = Delegate; - using CharMethod = Delegate; +class ParserCallbacks +{ +public: + virtual ~ParserCallbacks() + { + } + + virtual void startMethods() = 0; + virtual void startMethod() = 0; + virtual void methodSignature(char c) = 0; + virtual void methodName(char c) = 0; + virtual void endMethod() = 0; + virtual void endMethods() = 0; +}; - SimpleMethod startMethods; - SimpleMethod startMethod; - CharMethod methodSignature; - CharMethod methodName; - SimpleMethod endMethod; - SimpleMethod endMethods; +struct ParserSettings { + ParserCallbacks& callbacks; ParserState state = ParserState::ready; }; ParserResult parse(ParserSettings& settings, const char* buffer, size_t length, char nameEndsWith = ':'); +String toString(ParserResult result); + } // namespace simpleRPC diff --git a/Sming/Components/simpleRPC/simpleRPC b/Sming/Components/simpleRPC/simpleRPC index 609e739742..12d58ac910 160000 --- a/Sming/Components/simpleRPC/simpleRPC +++ b/Sming/Components/simpleRPC/simpleRPC @@ -1 +1 @@ -Subproject commit 609e7397428a973e83a97b2d5cf75c4321b8d26f +Subproject commit 12d58ac9100ea4121a2a3bd34a02828f79516eae diff --git a/Sming/Components/simpleRPC/simpleRPC.patch b/Sming/Components/simpleRPC/simpleRPC.patch index f19e3c2aa3..004a144383 100644 --- a/Sming/Components/simpleRPC/simpleRPC.patch +++ b/Sming/Components/simpleRPC/simpleRPC.patch @@ -1,48 +1,41 @@ diff --git a/src/defs.h b/src/defs.h -index c5b9ccf..9b2367d 100644 +index 54347e9..b977b19 100644 --- a/src/defs.h +++ b/src/defs.h -@@ -1,6 +1,6 @@ +@@ -1,6 +1,8 @@ #pragma once -#include +#include ++#include ++using std::min; + + char const PROTOCOL_[] {"simpleRPC"}; + char const VERSION_[] {"\x03\x00\x00"}; +diff --git a/src/simpleRPC.h b/src/simpleRPC.h +index dea278c..da3394e 100644 +--- a/src/simpleRPC.h ++++ b/src/simpleRPC.h +@@ -1,6 +1,10 @@ + #pragma once - #define _PROTOCOL "simpleRPC" - #define _VERSION "\3\0\0" -diff --git a/src/read.tcc b/src/read.tcc -index b32699e..3f03cde 100644 ---- a/src/read.tcc -+++ b/src/read.tcc -@@ -2,7 +2,6 @@ - - #include "defs.h" - #include "tuple.tcc" --#include "vector.tcc" - - //! \defgroup read - -diff --git a/src/types.tcc b/src/types.tcc -index b0de8d9..aca5f07 100644 ---- a/src/types.tcc -+++ b/src/types.tcc -@@ -2,7 +2,6 @@ - - #include "print.tcc" - #include "tuple.tcc" --#include "vector.tcc" - - //! \defgroup types - -diff --git a/src/write.tcc b/src/write.tcc -index 1f018c4..727f81f 100644 ---- a/src/write.tcc -+++ b/src/write.tcc -@@ -2,7 +2,6 @@ - - #include "print.tcc" - #include "tuple.tcc" --#include "vector.tcc" ++namespace simpleRPC ++{ + #include "interface.tcc" + + // I/O plugins. + #include "plugins/half_duplex/stream.h" ++ ++} // namespace simpleRPC +diff --git a/src/vector.tcc b/src/vector.tcc +index 49e1d27..a2d6352 100644 +--- a/src/vector.tcc ++++ b/src/vector.tcc +@@ -1,7 +1,5 @@ + #pragma once - //! \defgroup write +-#include +- + template + void swap_(T& a, T& b) noexcept { diff --git a/Sming/Components/simpleRPC/src/parser.cpp b/Sming/Components/simpleRPC/src/parser.cpp index adfce7d5a4..b7a8daebe4 100644 --- a/Sming/Components/simpleRPC/src/parser.cpp +++ b/Sming/Components/simpleRPC/src/parser.cpp @@ -36,9 +36,11 @@ namespace simpleRPC ParserResult parse(ParserSettings& settings, const char* buffer, size_t length, char nameEndsWith) { auto& state = settings.state; + auto& callbacks = settings.callbacks; + /* - * See: https://simplerpc.readthedocs.io/en/latest/protocol.html# -00000000 ff . + * See: https://simplerpc.readthedocs.io/en/latest/protocol.html# + 00000000 ff . 00000000 73 s 00000001 69 i 00000002 6d m @@ -73,7 +75,7 @@ ParserResult parse(ParserSettings& settings, const char* buffer, size_t length, 000000E1 65 72 2e 20 40 76 61 6c 75 65 3a 20 50 69 6e 20 er. @val ue: Pin 000000F1 76 61 6c 75 65 2e 00 value.. 00 . -*/ + */ bool hasError = false; for(const char* p = buffer; p != buffer + length; p++) { char ch = *p; @@ -129,9 +131,7 @@ ParserResult parse(ParserSettings& settings, const char* buffer, size_t length, goto ERROR; } - if(settings.startMethods) { - settings.startMethods(); - } + callbacks.startMethods(); state = ParserState::extract_method_start; break; } @@ -141,9 +141,7 @@ ParserResult parse(ParserSettings& settings, const char* buffer, size_t length, goto REENTER; } - if(settings.startMethod) { - settings.startMethod(); - } + callbacks.startMethod(); state = ParserState::extract_method_signature; /* fall-through */ } @@ -153,9 +151,7 @@ ParserResult parse(ParserSettings& settings, const char* buffer, size_t length, break; } - if(settings.methodSignature) { - settings.methodSignature(ch); - } + callbacks.methodSignature(ch); break; } case ParserState::extract_method_name: { @@ -164,23 +160,17 @@ ParserResult parse(ParserSettings& settings, const char* buffer, size_t length, break; } - if(settings.methodName) { - settings.methodName(ch); - } + callbacks.methodName(ch); break; } case ParserState::extract_method_end: { SKIP_UNTIL('\0', ParserState::extract_method_start); - if(settings.endMethod) { - settings.endMethod(); - } + callbacks.endMethod(); break; } case ParserState::end_methods: { - if(settings.endMethods) { - settings.endMethods(); - } + callbacks.endMethods(); state = ParserState::finished; /* fall through */ } @@ -195,11 +185,21 @@ ParserResult parse(ParserSettings& settings, const char* buffer, size_t length, } // end for ERROR: - if(hasError) { - return ParserResult::error; - } + return hasError ? ParserResult::error : ParserResult::more; +} - return ParserResult::more; +String toString(ParserResult result) +{ + using namespace simpleRPC; + switch(result) { + case ParserResult::finished: + return F("finished"); + case ParserResult::more: + return F("more"); + case ParserResult::error: + return F("error"); + } + return nullptr; } } // namespace simpleRPC diff --git a/tests/HostTests/modules/Network/Arch/Host/Hosted.cpp b/tests/HostTests/modules/Network/Arch/Host/Hosted.cpp index fa01c930e9..9f194841c5 100644 --- a/tests/HostTests/modules/Network/Arch/Host/Hosted.cpp +++ b/tests/HostTests/modules/Network/Arch/Host/Hosted.cpp @@ -8,6 +8,8 @@ #include #include +namespace +{ using namespace simpleRPC; static uint32_t plusCommand(uint8_t a, uint16_t b) @@ -40,48 +42,72 @@ class TheWire TheWire theWire; -class HostedTest : public TestGroup +class TestParseHandler : public ParserCallbacks { public: using RemoteCommands = HashMap; - HostedTest() : TestGroup(_F("Hosted")) + RemoteCommands commands; + uint8_t methodPosition = 0; + String parsedCommand; + + void startMethods() override { + methodPosition = 0; + commands.clear(); } - void execute() override + void startMethod() override + { + parsedCommand = ""; + } + + void methodSignature(char c) override + { + } + + void methodName(char ch) override + { + parsedCommand += ch; + } + + void endMethod() override + { + commands[parsedCommand] = methodPosition++; + } + + void endMethods() override + { + } +}; + +class HostedTest : public TestGroup +{ +public: + HostedTest() : TestGroup("Hosted") { - char packet[] = { - 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x50, 0x43, 0x00, 0x03, 0x00, 0x00, 0x3c, 0x49, 0x00, 0x3a, 0x20, - 0x48, 0x20, 0x42, 0x3b, 0x70, 0x69, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x3a, 0x20, 0x53, 0x65, 0x74, 0x73, 0x20, - 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x70, 0x69, - 0x6e, 0x2e, 0x20, 0x40, 0x70, 0x69, 0x6e, 0x3a, 0x20, 0x50, 0x69, 0x6e, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x2c, 0x20, 0x40, 0x6d, 0x6f, 0x64, 0x65, 0x3a, 0x20, 0x4d, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x79, 0x70, - 0x65, 0x2e, 0x00, 0x42, 0x3a, 0x20, 0x48, 0x3b, 0x64, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x61, - 0x64, 0x3a, 0x20, 0x52, 0x65, 0x61, 0x64, 0x20, 0x64, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x70, 0x69, - 0x6e, 0x2e, 0x20, 0x40, 0x70, 0x69, 0x6e, 0x3a, 0x20, 0x50, 0x69, 0x6e, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x2e, 0x20, 0x40, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3a, 0x20, 0x50, 0x69, 0x6e, 0x20, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x2e, 0x00, 0x3a, 0x20, 0x48, 0x20, 0x42, 0x3b, 0x64, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, - 0x57, 0x72, 0x69, 0x74, 0x65, 0x3a, 0x20, 0x57, 0x72, 0x69, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, - 0x64, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x70, 0x69, 0x6e, 0x2e, 0x20, 0x40, 0x70, 0x69, 0x6e, 0x3a, - 0x20, 0x50, 0x69, 0x6e, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x2e, 0x20, 0x40, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x20, 0x50, 0x69, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x00, 0x00}; - - ParserSettings settings; - settings.startMethods = ParserSettings::SimpleMethod(&HostedTest::startMethods, this); - settings.startMethod = ParserSettings::SimpleMethod(&HostedTest::startMethod, this); - settings.methodName = ParserSettings::CharMethod(&HostedTest::methodName, this); - settings.endMethod = ParserSettings::SimpleMethod(&HostedTest::endMethod, this); - settings.endMethods = ParserSettings::SimpleMethod(&HostedTest::endMethods, this); - settings.state = ParserState::ready; + } + void execute() override + { TEST_CASE("simpleRPC::parse()") { - REQUIRE(parse(settings, packet, sizeof(packet)) == ParserResult::finished); - REQUIRE(commands.count() == 3); - REQUIRE(commands["digitalWrite"] == 2); - REQUIRE(commands["pinMode"] != 2); - REQUIRE(commands["pinMode"] == 0); + char packet[]{"simpleRPC\0" // protocol identifier + "\3\0\0" // version + "listen(4031); server->setTimeOut(USHRT_MAX); // disable connection timeout server->setKeepAlive(USHRT_MAX); // disable connection timeout @@ -108,10 +134,10 @@ class HostedTest : public TestGroup plusCommand, "plusCommand> Sum two numbers. @a: number one. @b: number two.", /* class methods */ // uint8_t TwoWire::begin(uint8_t sda, uint8_t scl) - pack(&theWire, (uint8_t(TheWire::*)(uint8_t,uint8_t))&TheWire::begin), "TheWire::begin> Starts two-wire communication. @sda: Data pin. @scl: Clock pin.", + makeTuple(&theWire, static_cast(&TheWire::begin)), "TheWire::begin> Starts two-wire communication. @sda: Data pin. @scl: Clock pin.", // void TheWire::begin() - pack(&theWire, (void(TheWire::*)())&TheWire::begin), "TheWire::begin> Starts two-wire communication.", - pack(&theWire, (uint8_t(TheWire::*)())&TheWire::getCalled), "TheWire::getCalled> Gets times called. @return: Result." + makeTuple(&theWire, static_cast(&TheWire::begin)), "TheWire::begin> Starts two-wire communication.", + makeTuple(&theWire, &TheWire::getCalled), "TheWire::getCalled> Gets times called. @return: Result." ); // clang-format on @@ -120,6 +146,7 @@ class HostedTest : public TestGroup // RPC Client + TcpClient client{false}; client.connect(WifiStation.getIP(), 4031); Hosted::Transport::TcpClientStream stream(client, 1024); @@ -128,8 +155,8 @@ class HostedTest : public TestGroup TEST_CASE("Client::getRemoteCommands()") { REQUIRE(hostedClient.getRemoteCommands() == true); - REQUIRE(hostedClient.getFunctionId("plusCommand") == 2); - REQUIRE(hostedClient.getFunctionId("uint8_t TheWire::begin(uint8_t, uint8_t)") == 3); + REQUIRE_EQ(hostedClient.getFunctionId("plusCommand"), 2); + REQUIRE_EQ(hostedClient.getFunctionId("uint8_t TheWire::begin(uint8_t, uint8_t)"), 3); } TEST_CASE("Client::send and wait()") @@ -137,7 +164,7 @@ class HostedTest : public TestGroup ElapseTimer timer; REQUIRE(hostedClient.send("plusCommand", uint8_t(3), uint16_t(2)) == true); - REQUIRE(hostedClient.wait() == 5); + REQUIRE_EQ(hostedClient.wait(), 5); debug_i("PlusCommand Roundtrip Time: %s", timer.elapsedTime().toString().c_str()); } @@ -145,48 +172,18 @@ class HostedTest : public TestGroup TEST_CASE("Client::send and check class method") { REQUIRE(hostedClient.send("uint8_t TheWire::begin(uint8_t, uint8_t)", uint8_t(3), uint8_t(3)) == true); - REQUIRE(hostedClient.wait() == 6); + REQUIRE_EQ(hostedClient.wait(), 6); REQUIRE(hostedClient.send("uint8_t TheWire::getCalled()") == true); - REQUIRE(hostedClient.wait() == 6); + REQUIRE_EQ(hostedClient.wait(), 6); } - } - -private: - RemoteCommands commands; - uint8_t methodPosition = 0; - String parsedCommand; - - TcpServer* server{nullptr}; - TcpClient client{false}; - Hosted::Transport::TcpClientStream* stream{nullptr}; - - void startMethods() - { - methodPosition = 0; - commands.clear(); - } - - void startMethod() - { - parsedCommand = ""; - } - void methodName(char ch) - { - parsedCommand += ch; - } - - void endMethod() - { - commands[parsedCommand] = methodPosition++; - } - - void endMethods() - { + server->shutdown(); } }; +} // namespace + void REGISTER_TEST(Hosted) { registerGroup();