From 6a3b1f83a371437f510cdf2d3758d515da138b6a Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Fri, 11 Jul 2025 10:17:41 +0200 Subject: [PATCH 01/12] feat: zephyr mutexes and thread example --- examples/zephyr_thread/zephyr_thread.ino | 10 ++ src/bridge.h | 112 +++++++++++++++++++++-- 2 files changed, 114 insertions(+), 8 deletions(-) create mode 100644 examples/zephyr_thread/zephyr_thread.ino diff --git a/examples/zephyr_thread/zephyr_thread.ino b/examples/zephyr_thread/zephyr_thread.ino new file mode 100644 index 0000000..36a418c --- /dev/null +++ b/examples/zephyr_thread/zephyr_thread.ino @@ -0,0 +1,10 @@ +#include + + +void setup() { + BRIDGE.begin(); +} + +void loop() { + delay(10); +} \ No newline at end of file diff --git a/src/bridge.h b/src/bridge.h index afa0992..cd0dd95 100644 --- a/src/bridge.h +++ b/src/bridge.h @@ -6,6 +6,7 @@ #define RESET_METHOD "$/reset" #define BIND_METHOD "$/register" +#include #include @@ -15,14 +16,22 @@ class Bridge { RPCServer* server = nullptr; ITransport* transport; + struct k_mutex read_mutex; + struct k_mutex write_mutex; + public: Bridge(ITransport& t) : transport(&t) {} + Bridge(Stream& stream) { transport = new SerialTransport(stream); } // Initialize the bridge bool begin() { + + k_mutex_init(&read_mutex); + k_mutex_init(&write_mutex); + client = new RPCClient(*transport); server = new RPCServer(*transport); bool res; @@ -38,19 +47,60 @@ class Bridge { return server->bind(name, func); } + template + bool provide_safe(const MsgPack::str_t& name, F&& func) { + bool res; + if (!call(BIND_METHOD, res, name)) { + return false; + } + + return server->bind(name, func, "__safe__"); + + } + void update() { - // Protect the following calls with a mutex if necessary - // server->read_request(); // <- inbound - // server->serve(); // -> outbound - server->run(); + + // Lock read mutex + while(1){ + k_mutex_lock(&read_mutex, K_FOREVER); + if (server->get_rpc()) { + k_mutex_unlock(&read_mutex); + break; + } + k_mutex_unlock(&read_mutex); + k_msleep(1); + } + + server->process_request(); + + // Lock write mutex + k_mutex_lock(&write_mutex, K_FOREVER); + server->send_response(); + k_mutex_unlock(&write_mutex); + } template bool call(const MsgPack::str_t method, RType& result, Args&&... args) { - // Protect the following calls with a mutex if necessary - // client->send_call(); // -> outbound - // client->read_response(); // <- inbound - return client->call(method, result, std::forward(args)...); + + // Lock write mutex + k_mutex_lock(&write_mutex, K_FOREVER); + client->send_rpc(method, std::forward(args)...); + k_mutex_unlock(&write_mutex); + + // Lock read mutex + while(1) { + k_mutex_lock(&read_mutex, K_FOREVER); + if (client->get_response(result)) { + k_mutex_unlock(&read_mutex); + break; + } + k_mutex_unlock(&read_mutex); + k_msleep(1); + } + + return (client->lastError.code == NO_ERR); + } template @@ -66,6 +116,52 @@ class Bridge { return (uint8_t) client->lastError.code; } +private: + + void update_safe() { + + // Lock read mutex + while(1){ + k_mutex_lock(&read_mutex, K_FOREVER); + if (server->get_rpc()) { + k_mutex_unlock(&read_mutex); + break; + } + k_mutex_unlock(&read_mutex); + k_msleep(1); + } + + server->process_request("__safe__"); + + // Lock write mutex + k_mutex_lock(&write_mutex, K_FOREVER); + server->send_response(); + k_mutex_unlock(&write_mutex); + + } + + friend class BridgeUpdater; + }; +class BridgeUpdater { +public: + static void safeUpdate(Bridge& bridge) { + bridge.update_safe(); // access private method + } + +private: + BridgeUpdater() = delete; // prevents instantiation +}; + +Bridge BRIDGE(Serial1); + +static void safeUpdate(){ + BridgeUpdater::safeUpdate(BRIDGE); +} + +void __loopHook(){ + safeUpdate(); +} + #endif // BRIDGE_IMOLA_H \ No newline at end of file From 7788eed3d4d2f237d1b05004405af3ea3f76a138 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Fri, 11 Jul 2025 12:58:43 +0200 Subject: [PATCH 02/12] feat: setup hook spawning a BRIDGE.update thread --- src/bridge.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/bridge.h b/src/bridge.h index cd0dd95..a0376a9 100644 --- a/src/bridge.h +++ b/src/bridge.h @@ -6,6 +6,9 @@ #define RESET_METHOD "$/reset" #define BIND_METHOD "$/register" +#define UPDATE_THREAD_STACK_SIZE 500 +#define UPDATE_THREAD_PRIORITY 5 + #include #include @@ -160,6 +163,24 @@ static void safeUpdate(){ BridgeUpdater::safeUpdate(BRIDGE); } + +void updateEntryPoint(void *, void *, void *){ + BRIDGE.update(); +} + +static k_tid_t upd_tid; +static k_thread_stack_t *upd_stack_area; +static struct k_thread upd_thread_data; + +void __setupHook(){ + upd_stack_area = k_thread_stack_alloc(UPDATE_THREAD_STACK_SIZE, 0); + upd_tid = k_thread_create(&upd_thread_data, upd_stack_area, + UPDATE_THREAD_STACK_SIZE, + updateEntryPoint, + NULL, NULL, NULL, + UPDATE_THREAD_PRIORITY, 0, K_NO_WAIT); +} + void __loopHook(){ safeUpdate(); } From f2f0473331962c3d4b47d0c85eefe2b09aaae15a Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Fri, 11 Jul 2025 13:05:42 +0200 Subject: [PATCH 03/12] update(): don't lock if get_rpc is false --- src/bridge.h | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/bridge.h b/src/bridge.h index a0376a9..6f8f436 100644 --- a/src/bridge.h +++ b/src/bridge.h @@ -63,19 +63,17 @@ class Bridge { void update() { + k_msleep(1); // Lock read mutex - while(1){ - k_mutex_lock(&read_mutex, K_FOREVER); - if (server->get_rpc()) { - k_mutex_unlock(&read_mutex); - break; - } + k_mutex_lock(&read_mutex, K_FOREVER); + if (!server->get_rpc()) { k_mutex_unlock(&read_mutex); - k_msleep(1); + return; } + k_mutex_unlock(&read_mutex); server->process_request(); - + // Lock write mutex k_mutex_lock(&write_mutex, K_FOREVER); server->send_response(); @@ -124,18 +122,16 @@ class Bridge { void update_safe() { // Lock read mutex - while(1){ - k_mutex_lock(&read_mutex, K_FOREVER); - if (server->get_rpc()) { - k_mutex_unlock(&read_mutex); - break; - } + k_msleep(1); + k_mutex_lock(&read_mutex, K_FOREVER); + if (!server->get_rpc()) { k_mutex_unlock(&read_mutex); - k_msleep(1); + return; } + k_mutex_unlock(&read_mutex); server->process_request("__safe__"); - + // Lock write mutex k_mutex_lock(&write_mutex, K_FOREVER); server->send_response(); From 16b69337e7208c6ec5b19464128430907a6ee033 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Fri, 11 Jul 2025 17:17:03 +0200 Subject: [PATCH 04/12] mod: naming convention --- desired.ino | 16 +++++++- examples/simple_bridge/simple_bridge.ino | 47 ++++++++++++----------- examples/zephyr_thread/zephyr_thread.ino | 2 +- src/bridge.h | 48 +++++++++++++----------- 4 files changed, 65 insertions(+), 48 deletions(-) diff --git a/desired.ino b/desired.ino index 073f19d..7c36693 100644 --- a/desired.ino +++ b/desired.ino @@ -11,9 +11,20 @@ void setup() { // ERRORE ignorato Bridge.provide("greet", greet); // -> rpc.call("$/register", res, "greet"); + Bridge.provide("get_index", get_index); // metodi forniti con provide possono ricevere anche notifiche (semplicemente il risultato non viene restituito) + + Bridge.provide_safe("get_index", get_index); +} + +int index; + +int get_index() { + return index; } + + bool set_led(bool state) { digitalWrite(LED_BUILTIN, state); return state; @@ -28,6 +39,9 @@ String greet() { } void loop() { + + index++; + float res; if (!Bridge.call("multiply", res, 1.0, 2.0)) { // ERRORE! @@ -36,5 +50,5 @@ void loop() { Bridge.notify("signal", 200); // update viene chiamato automaticamente in un thread separato - // Bridge.update(); -> server.run(); + Bridge.update(); // -> server->run(); } diff --git a/examples/simple_bridge/simple_bridge.ino b/examples/simple_bridge/simple_bridge.ino index 7437b8d..d8b8100 100644 --- a/examples/simple_bridge/simple_bridge.ino +++ b/examples/simple_bridge/simple_bridge.ino @@ -1,6 +1,18 @@ #include -Bridge bridge(Serial1); + +bool set_led(bool state) { + digitalWrite(LED_BUILTIN, state); + return state; +} + +int add(int a, int b) { + return a + b; +} + +String greet() { + return String("Hello Friend"); +} void setup() { Serial.begin(115200); @@ -11,48 +23,35 @@ void setup() { pinMode(LED_BUILTIN, OUTPUT); - if (!bridge.begin()) { - Serial.println("Error initializing bridge"); + if (!Bridge.begin()) { + Serial.println("Error initializing Bridge"); while(1); } else { Serial.println("Bridge initialized successfully"); } - if (!bridge.provide("set_led", set_led)) { + if (!Bridge.provide("set_led", set_led)) { Serial.println("Error providing method: set_led"); } else { Serial.println("Registered method: set_led"); } - bridge.provide("add", add); + Bridge.provide("add", add); - bridge.provide("greet", greet); + Bridge.provide("greet", greet); } -bool set_led(bool state) { - digitalWrite(LED_BUILTIN, state); - return state; -} - -int add(int a, int b) { - return a + b; -} - -String greet() { - return String("Hello Friend"); -} - void loop() { float res; - if (!bridge.call("multiply", res, 1.0, 2.0)) { + if (!Bridge.call("multiply", res, 1.0, 2.0)) { Serial.println("Error calling method: multiply"); - Serial.println(bridge.get_error_code()); - Serial.println(bridge.get_error_message()); + Serial.println(Bridge.get_error_code()); + Serial.println(Bridge.get_error_message()); delay(1000); }; - bridge.notify("signal", 200); + Bridge.notify("signal", 200); - bridge.update(); + //Bridge.update(); } diff --git a/examples/zephyr_thread/zephyr_thread.ino b/examples/zephyr_thread/zephyr_thread.ino index 36a418c..3feb118 100644 --- a/examples/zephyr_thread/zephyr_thread.ino +++ b/examples/zephyr_thread/zephyr_thread.ino @@ -2,7 +2,7 @@ void setup() { - BRIDGE.begin(); + Bridge.begin(); } void loop() { diff --git a/src/bridge.h b/src/bridge.h index 6f8f436..44e15c6 100644 --- a/src/bridge.h +++ b/src/bridge.h @@ -13,7 +13,7 @@ #include -class Bridge { +class BridgeClass { RPCClient* client = nullptr; RPCServer* server = nullptr; @@ -23,9 +23,9 @@ class Bridge { struct k_mutex write_mutex; public: - Bridge(ITransport& t) : transport(&t) {} + BridgeClass(ITransport& t) : transport(&t) {} - Bridge(Stream& stream) { + BridgeClass(Stream& stream) { transport = new SerialTransport(stream); } @@ -63,17 +63,19 @@ class Bridge { void update() { - k_msleep(1); // Lock read mutex - k_mutex_lock(&read_mutex, K_FOREVER); - if (!server->get_rpc()) { + while(1){ + k_mutex_lock(&read_mutex, K_FOREVER); + if (server->get_rpc()) { + k_mutex_unlock(&read_mutex); + break; + } k_mutex_unlock(&read_mutex); - return; + k_msleep(1); } - k_mutex_unlock(&read_mutex); server->process_request(); - + // Lock write mutex k_mutex_lock(&write_mutex, K_FOREVER); server->send_response(); @@ -122,16 +124,18 @@ class Bridge { void update_safe() { // Lock read mutex - k_msleep(1); - k_mutex_lock(&read_mutex, K_FOREVER); - if (!server->get_rpc()) { + while(1){ + k_mutex_lock(&read_mutex, K_FOREVER); + if (server->get_rpc()) { + k_mutex_unlock(&read_mutex); + break; + } k_mutex_unlock(&read_mutex); - return; + k_msleep(1); } - k_mutex_unlock(&read_mutex); server->process_request("__safe__"); - + // Lock write mutex k_mutex_lock(&write_mutex, K_FOREVER); server->send_response(); @@ -139,29 +143,29 @@ class Bridge { } - friend class BridgeUpdater; + friend class BridgeClassUpdater; }; -class BridgeUpdater { +class BridgeClassUpdater { public: - static void safeUpdate(Bridge& bridge) { + static void safeUpdate(BridgeClass& bridge) { bridge.update_safe(); // access private method } private: - BridgeUpdater() = delete; // prevents instantiation + BridgeClassUpdater() = delete; // prevents instantiation }; -Bridge BRIDGE(Serial1); +BridgeClass Bridge(Serial1); static void safeUpdate(){ - BridgeUpdater::safeUpdate(BRIDGE); + BridgeClassUpdater::safeUpdate(Bridge); } void updateEntryPoint(void *, void *, void *){ - BRIDGE.update(); + Bridge.update(); } static k_tid_t upd_tid; From 350d5fee0f96906c04de79b66ae555a5d7108240 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Mon, 14 Jul 2025 11:44:38 +0200 Subject: [PATCH 05/12] doc: README with usage example ver: 0.1.0 --- README.md | 61 ++++++++++++++++++++++++ examples/simple_bridge/simple_bridge.ino | 5 +- examples/zephyr_thread/zephyr_thread.ino | 10 ---- library.json | 4 +- library.properties | 4 +- 5 files changed, 67 insertions(+), 17 deletions(-) delete mode 100644 examples/zephyr_thread/zephyr_thread.ino diff --git a/README.md b/README.md index 0e68776..f31c090 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,64 @@ In this repo it will be implemented an Arduino library wrapper for RPClite to be The desired API is shown in https://github.com/bcmi-labs/Arduino_BridgeImola/blob/main/desired.ino. This is WIP. Expects changes soon. + +## The Bridge object ## + +Including Arduino_BridgeImola.h gives the user access to a Bridge object that can be used both as a RPC client and/or server to execute and serve RPCs to/from the CPU Host running a GOLANG router. + +- The Bridge object is defined on Serial1 +- The Bridge.call method is blocking and works the same as in RPClite +- The Bridge can provide callbacks to incoming RPC requests both in a thread-unsafe and thread-safe fashion (provide & provide_safe) +- Thread-safe methods execution is granted in the main loop thread where update_safe is called. By design users cannot access .update_safe() freely +- Thread-unsafe methods are served in an update callback, whose execution is granted in a separate thread. Nonetheless users can access .update() freely with caution + + +```cpp +bool set_led(bool state) { + digitalWrite(LED_BUILTIN, state); + return state; +} + +String greet() { + return String("Hello Friend"); +} + +void setup() { + Serial.begin(115200); + while (!Serial); + + Serial1.begin(115200); + while (!Serial1); + + pinMode(LED_BUILTIN, OUTPUT); + + if (!Bridge.begin()) { + Serial.println("Error initializing Bridge"); + while(1); + } else { + Serial.println("Bridge initialized successfully"); + } + + if (!Bridge.provide("set_led", set_led)) { + Serial.println("Error providing method: set_led"); + } else { + Serial.println("Registered method: set_led"); + } + + Bridge.provide_safe("greet", greet); + +} + +void loop() { + float res; + if (!Bridge.call("multiply", res, 1.0, 2.0)) { + Serial.println("Error calling method: multiply"); + Serial.println(Bridge.get_error_code()); + Serial.println(Bridge.get_error_message()); + }; + + Bridge.notify("signal", 200); + + //Bridge.update(); // Thread-unsafe update execution is granted in its own thread. It can be called manually with caution +} +``` diff --git a/examples/simple_bridge/simple_bridge.ino b/examples/simple_bridge/simple_bridge.ino index d8b8100..6e7e615 100644 --- a/examples/simple_bridge/simple_bridge.ino +++ b/examples/simple_bridge/simple_bridge.ino @@ -38,7 +38,7 @@ void setup() { Bridge.provide("add", add); - Bridge.provide("greet", greet); + Bridge.provide_safe("greet", greet); } @@ -48,10 +48,9 @@ void loop() { Serial.println("Error calling method: multiply"); Serial.println(Bridge.get_error_code()); Serial.println(Bridge.get_error_message()); - delay(1000); }; Bridge.notify("signal", 200); - //Bridge.update(); + //Bridge.update(); // Thread-unsafe update execution is granted in its own thread. It can be called manually with caution } diff --git a/examples/zephyr_thread/zephyr_thread.ino b/examples/zephyr_thread/zephyr_thread.ino deleted file mode 100644 index 3feb118..0000000 --- a/examples/zephyr_thread/zephyr_thread.ino +++ /dev/null @@ -1,10 +0,0 @@ -#include - - -void setup() { - Bridge.begin(); -} - -void loop() { - delay(10); -} \ No newline at end of file diff --git a/library.json b/library.json index 7967d64..9ff7d1d 100644 --- a/library.json +++ b/library.json @@ -11,12 +11,12 @@ "url": "https://github.com/bcmi-labs/Arduino_BridgeImola", "maintainer": true }, - "version": "0.0.1", + "version": "0.1.0", "license": "MIT", "frameworks": "arduino", "platforms": "*", "dependencies": { - "bcmi-labs/Arduino_RPClite": ">=0.0.1" + "bcmi-labs/Arduino_RPClite": ">=0.1.0" } } diff --git a/library.properties b/library.properties index f092c0d..4d11ca1 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Arduino_BridgeImola -version=0.0.1 +version=0.1.0 author=BCMI-labs maintainer=BCMI-labs sentence=A RPC bridge for Imola boards @@ -7,4 +7,4 @@ paragraph=This library provides a simple RPC bridge for Imola boards, allowing c category=Communication url=https://www.arduino.cc/ architectures=* -depends=Arduino_RPClite (>=0.0.1) +depends=Arduino_RPClite (>=0.1.0) From 17b41e3b84f660f182958e10167aedc53005773a Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Mon, 14 Jul 2025 12:23:04 +0200 Subject: [PATCH 06/12] fix: regression locking get_rpc --- src/bridge.h | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/bridge.h b/src/bridge.h index 44e15c6..889281f 100644 --- a/src/bridge.h +++ b/src/bridge.h @@ -63,19 +63,17 @@ class BridgeClass { void update() { + k_msleep(1); // Lock read mutex - while(1){ - k_mutex_lock(&read_mutex, K_FOREVER); - if (server->get_rpc()) { - k_mutex_unlock(&read_mutex); - break; - } + k_mutex_lock(&read_mutex, K_FOREVER); + if (!server->get_rpc()) { k_mutex_unlock(&read_mutex); - k_msleep(1); + return; } + k_mutex_unlock(&read_mutex); server->process_request(); - + // Lock write mutex k_mutex_lock(&write_mutex, K_FOREVER); server->send_response(); @@ -124,18 +122,16 @@ class BridgeClass { void update_safe() { // Lock read mutex - while(1){ - k_mutex_lock(&read_mutex, K_FOREVER); - if (server->get_rpc()) { - k_mutex_unlock(&read_mutex); - break; - } + k_msleep(1); + k_mutex_lock(&read_mutex, K_FOREVER); + if (!server->get_rpc()) { k_mutex_unlock(&read_mutex); - k_msleep(1); + return; } + k_mutex_unlock(&read_mutex); server->process_request("__safe__"); - + // Lock write mutex k_mutex_lock(&write_mutex, K_FOREVER); server->send_response(); From e4319bf396f05a8dd34833372487447b52eefbc3 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Mon, 14 Jul 2025 14:36:30 +0200 Subject: [PATCH 07/12] feat: global Bridge hardcoded Serial1 dependency --- README.md | 12 +----------- examples/simple_bridge/simple_bridge.ino | 10 ---------- src/bridge.h | 7 +++++++ 3 files changed, 8 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index f31c090..7e0302c 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ This is WIP. Expects changes soon. Including Arduino_BridgeImola.h gives the user access to a Bridge object that can be used both as a RPC client and/or server to execute and serve RPCs to/from the CPU Host running a GOLANG router. -- The Bridge object is defined on Serial1 +- The Bridge object is pre-defined on Serial1 and automatically initialized inside the main setup() - The Bridge.call method is blocking and works the same as in RPClite - The Bridge can provide callbacks to incoming RPC requests both in a thread-unsafe and thread-safe fashion (provide & provide_safe) - Thread-safe methods execution is granted in the main loop thread where update_safe is called. By design users cannot access .update_safe() freely @@ -28,19 +28,9 @@ String greet() { void setup() { Serial.begin(115200); while (!Serial); - - Serial1.begin(115200); - while (!Serial1); pinMode(LED_BUILTIN, OUTPUT); - if (!Bridge.begin()) { - Serial.println("Error initializing Bridge"); - while(1); - } else { - Serial.println("Bridge initialized successfully"); - } - if (!Bridge.provide("set_led", set_led)) { Serial.println("Error providing method: set_led"); } else { diff --git a/examples/simple_bridge/simple_bridge.ino b/examples/simple_bridge/simple_bridge.ino index 6e7e615..f24a614 100644 --- a/examples/simple_bridge/simple_bridge.ino +++ b/examples/simple_bridge/simple_bridge.ino @@ -17,19 +17,9 @@ String greet() { void setup() { Serial.begin(115200); while (!Serial); - - Serial1.begin(115200); - while (!Serial1); pinMode(LED_BUILTIN, OUTPUT); - if (!Bridge.begin()) { - Serial.println("Error initializing Bridge"); - while(1); - } else { - Serial.println("Bridge initialized successfully"); - } - if (!Bridge.provide("set_led", set_led)) { Serial.println("Error providing method: set_led"); } else { diff --git a/src/bridge.h b/src/bridge.h index 889281f..e14e022 100644 --- a/src/bridge.h +++ b/src/bridge.h @@ -9,6 +9,8 @@ #define UPDATE_THREAD_STACK_SIZE 500 #define UPDATE_THREAD_PRIORITY 5 +#define SERIAL1_BAUD 115200 + #include #include @@ -169,6 +171,11 @@ static k_thread_stack_t *upd_stack_area; static struct k_thread upd_thread_data; void __setupHook(){ + + Serial1.begin(SERIAL1_BAUD); + + Bridge.begin(); + upd_stack_area = k_thread_stack_alloc(UPDATE_THREAD_STACK_SIZE, 0); upd_tid = k_thread_create(&upd_thread_data, upd_stack_area, UPDATE_THREAD_STACK_SIZE, From 6fec689374139d3bc691b3a8dee296abce781c9c Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Tue, 15 Jul 2025 08:46:38 +0200 Subject: [PATCH 08/12] fix: Bridge.update called only once in setup-spawned thread --- src/bridge.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bridge.h b/src/bridge.h index e14e022..98a5bed 100644 --- a/src/bridge.h +++ b/src/bridge.h @@ -163,7 +163,9 @@ static void safeUpdate(){ void updateEntryPoint(void *, void *, void *){ - Bridge.update(); + while(1){ + Bridge.update(); + } } static k_tid_t upd_tid; From a923a97796caa942711d6dfd8d65c09e250e42d6 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Tue, 15 Jul 2025 10:47:40 +0200 Subject: [PATCH 09/12] feat: Bridge obj with configurable/default baud --- src/bridge.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/bridge.h b/src/bridge.h index 98a5bed..46eeaf0 100644 --- a/src/bridge.h +++ b/src/bridge.h @@ -9,7 +9,7 @@ #define UPDATE_THREAD_STACK_SIZE 500 #define UPDATE_THREAD_PRIORITY 5 -#define SERIAL1_BAUD 115200 +#define DEFAULT_SERIAL_BAUD 115200 #include #include @@ -19,20 +19,22 @@ class BridgeClass { RPCClient* client = nullptr; RPCServer* server = nullptr; + HardwareSerial* serial_ptr = nullptr; ITransport* transport; struct k_mutex read_mutex; struct k_mutex write_mutex; public: - BridgeClass(ITransport& t) : transport(&t) {} - BridgeClass(Stream& stream) { - transport = new SerialTransport(stream); + BridgeClass(HardwareSerial& serial) { + serial_ptr = &serial; + transport = new SerialTransport(serial); } // Initialize the bridge - bool begin() { + bool begin(unsigned long baud=DEFAULT_SERIAL_BAUD) { + serial_ptr->begin(baud); k_mutex_init(&read_mutex); k_mutex_init(&write_mutex); @@ -174,8 +176,6 @@ static struct k_thread upd_thread_data; void __setupHook(){ - Serial1.begin(SERIAL1_BAUD); - Bridge.begin(); upd_stack_area = k_thread_stack_alloc(UPDATE_THREAD_STACK_SIZE, 0); From 2457da634518f616d8a919a6f178dabf29c33e37 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Tue, 15 Jul 2025 11:34:47 +0200 Subject: [PATCH 10/12] mod: rem setup hook --- examples/simple_bridge/simple_bridge.ino | 1 + src/bridge.h | 41 ++++++++++++------------ 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/examples/simple_bridge/simple_bridge.ino b/examples/simple_bridge/simple_bridge.ino index f24a614..a8bb5bc 100644 --- a/examples/simple_bridge/simple_bridge.ino +++ b/examples/simple_bridge/simple_bridge.ino @@ -1,5 +1,6 @@ #include +//BridgeClass Bridge(Serial1); bool set_led(bool state) { digitalWrite(LED_BUILTIN, state); diff --git a/src/bridge.h b/src/bridge.h index 46eeaf0..109b6d6 100644 --- a/src/bridge.h +++ b/src/bridge.h @@ -9,12 +9,14 @@ #define UPDATE_THREAD_STACK_SIZE 500 #define UPDATE_THREAD_PRIORITY 5 -#define DEFAULT_SERIAL_BAUD 115200 +#define DEFAULT_SERIAL_BAUD 115200 #include #include +void updateEntryPoint(void *, void *, void *); + class BridgeClass { RPCClient* client = nullptr; @@ -24,6 +26,10 @@ class BridgeClass { struct k_mutex read_mutex; struct k_mutex write_mutex; + + k_tid_t upd_tid; + k_thread_stack_t *upd_stack_area; + struct k_thread upd_thread_data; public: @@ -41,6 +47,14 @@ class BridgeClass { client = new RPCClient(*transport); server = new RPCServer(*transport); + + upd_stack_area = k_thread_stack_alloc(UPDATE_THREAD_STACK_SIZE, 0); + upd_tid = k_thread_create(&upd_thread_data, upd_stack_area, + UPDATE_THREAD_STACK_SIZE, + updateEntryPoint, + NULL, NULL, NULL, + UPDATE_THREAD_PRIORITY, 0, K_NO_WAIT); + bool res; return call(RESET_METHOD, res); } @@ -157,12 +171,11 @@ class BridgeClassUpdater { BridgeClassUpdater() = delete; // prevents instantiation }; +#if defined(UNOQ) || defined(ARDUINO_UNOQ) BridgeClass Bridge(Serial1); - -static void safeUpdate(){ - BridgeClassUpdater::safeUpdate(Bridge); -} - +#else +extern BridgeClass Bridge; +#endif void updateEntryPoint(void *, void *, void *){ while(1){ @@ -170,20 +183,8 @@ void updateEntryPoint(void *, void *, void *){ } } -static k_tid_t upd_tid; -static k_thread_stack_t *upd_stack_area; -static struct k_thread upd_thread_data; - -void __setupHook(){ - - Bridge.begin(); - - upd_stack_area = k_thread_stack_alloc(UPDATE_THREAD_STACK_SIZE, 0); - upd_tid = k_thread_create(&upd_thread_data, upd_stack_area, - UPDATE_THREAD_STACK_SIZE, - updateEntryPoint, - NULL, NULL, NULL, - UPDATE_THREAD_PRIORITY, 0, K_NO_WAIT); +static void safeUpdate(){ + BridgeClassUpdater::safeUpdate(Bridge); } void __loopHook(){ From 627630a49434ec921082f741bc7efa91ccfb45f2 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Tue, 15 Jul 2025 11:43:25 +0200 Subject: [PATCH 11/12] mod: naming convention --- README.md | 6 +-- desired.ino | 54 ------------------------ examples/simple_bridge/simple_bridge.ino | 2 +- library.json | 8 ++-- library.properties | 6 +-- src/Arduino_BridgeImola.h | 7 --- src/Arduino_RouterBridge.h | 7 +++ src/bridge.h | 6 +-- 8 files changed, 21 insertions(+), 75 deletions(-) delete mode 100644 desired.ino delete mode 100644 src/Arduino_BridgeImola.h create mode 100644 src/Arduino_RouterBridge.h diff --git a/README.md b/README.md index 7e0302c..64792b7 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -In this repo it will be implemented an Arduino library wrapper for RPClite to be run on Imola boards. +In this repo it will be implemented an Arduino library wrapper for RPClite to be run on Arduino UNO Q boards. -The desired API is shown in https://github.com/bcmi-labs/Arduino_BridgeImola/blob/main/desired.ino. +The desired API is shown in https://github.com/bcmi-labs/Arduino_RouterBridge/blob/main/desired.ino. This is WIP. Expects changes soon. ## The Bridge object ## -Including Arduino_BridgeImola.h gives the user access to a Bridge object that can be used both as a RPC client and/or server to execute and serve RPCs to/from the CPU Host running a GOLANG router. +Including Arduino_RouterBridge.h gives the user access to a Bridge object that can be used both as a RPC client and/or server to execute and serve RPCs to/from the CPU Host running a GOLANG router. - The Bridge object is pre-defined on Serial1 and automatically initialized inside the main setup() - The Bridge.call method is blocking and works the same as in RPClite diff --git a/desired.ino b/desired.ino deleted file mode 100644 index 7c36693..0000000 --- a/desired.ino +++ /dev/null @@ -1,54 +0,0 @@ -// Bridge.begin(); <- statica nel loader di zephyr / core -// -> rpc.call("$/reset", res); - -void setup() { - pinMode(LED_BUILTIN, OUTPUT); - - if (!Bridge.provide("set_led", set_led)) { // -> rpc.call("$/register", res, "set_led"); - // ERRORE! - }; - Bridge.provide("add", add); // -> rpc.call("$/register", res, "add"); - // ERRORE ignorato - Bridge.provide("greet", greet); // -> rpc.call("$/register", res, "greet"); - - Bridge.provide("get_index", get_index); - // metodi forniti con provide possono ricevere anche notifiche (semplicemente il risultato non viene restituito) - - Bridge.provide_safe("get_index", get_index); -} - -int index; - -int get_index() { - return index; -} - - - -bool set_led(bool state) { - digitalWrite(LED_BUILTIN, state); - return state; -} - -int add(int a, int b) { - return a + b; -} - -String greet() { - return String("Hello Friend"); -} - -void loop() { - - index++; - - float res; - if (!Bridge.call("multiply", res, 1.0, 2.0)) { - // ERRORE! - }; - - Bridge.notify("signal", 200); - - // update viene chiamato automaticamente in un thread separato - Bridge.update(); // -> server->run(); -} diff --git a/examples/simple_bridge/simple_bridge.ino b/examples/simple_bridge/simple_bridge.ino index a8bb5bc..24ea246 100644 --- a/examples/simple_bridge/simple_bridge.ino +++ b/examples/simple_bridge/simple_bridge.ino @@ -1,4 +1,4 @@ -#include +#include //BridgeClass Bridge(Serial1); diff --git a/library.json b/library.json index 9ff7d1d..ce24b6d 100644 --- a/library.json +++ b/library.json @@ -1,14 +1,14 @@ { - "name": "Arduino_BridgeImola", + "name": "Arduino_RouterBridge", "keywords": "rpclite,msgpack", - "description": "A RPC bridge for Imola boards", + "description": "A RPC bridge for Arduino UNO Q boards", "repository": { "type": "git", - "url": "https://github.com/bcmi-labs/Arduino_BridgeImola" + "url": "https://github.com/bcmi-labs/Arduino_RouterBridge" }, "authors": { "name": "BCMI-labs", - "url": "https://github.com/bcmi-labs/Arduino_BridgeImola", + "url": "https://github.com/bcmi-labs/Arduino_RouterBridge", "maintainer": true }, "version": "0.1.0", diff --git a/library.properties b/library.properties index 4d11ca1..9e0dfb5 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ -name=Arduino_BridgeImola +name=Arduino_RouterBridge version=0.1.0 author=BCMI-labs maintainer=BCMI-labs -sentence=A RPC bridge for Imola boards -paragraph=This library provides a simple RPC bridge for Imola boards, allowing communication between the board and other devices using MsgPack serialization. +sentence=A RPC bridge for Arduino UNO Q boards +paragraph=This library provides a simple RPC bridge for Arduino UNO Q boards, allowing communication between the board and other devices using MsgPack serialization. category=Communication url=https://www.arduino.cc/ architectures=* diff --git a/src/Arduino_BridgeImola.h b/src/Arduino_BridgeImola.h deleted file mode 100644 index 8af38ad..0000000 --- a/src/Arduino_BridgeImola.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef ARDUINO_BRIDGE_IMOLA_H -#define ARDUINO_BRIDGE_IMOLA_H - -#include "Arduino.h" -#include "bridge.h" - -#endif //ARDUINO_BRIDGE_IMOLA_H diff --git a/src/Arduino_RouterBridge.h b/src/Arduino_RouterBridge.h new file mode 100644 index 0000000..be9da6e --- /dev/null +++ b/src/Arduino_RouterBridge.h @@ -0,0 +1,7 @@ +#ifndef ARDUINO_ROUTER_BRIDGE_H +#define ARDUINO_ROUTER_BRIDGE_H + +#include "Arduino.h" +#include "bridge.h" + +#endif //ARDUINO_ROUTER_BRIDGE_H diff --git a/src/bridge.h b/src/bridge.h index 109b6d6..7c9e5c5 100644 --- a/src/bridge.h +++ b/src/bridge.h @@ -1,7 +1,7 @@ #pragma once -#ifndef BRIDGE_IMOLA_H -#define BRIDGE_IMOLA_H +#ifndef ROUTER_BRIDGE_H +#define ROUTER_BRIDGE_H #define RESET_METHOD "$/reset" #define BIND_METHOD "$/register" @@ -191,4 +191,4 @@ void __loopHook(){ safeUpdate(); } -#endif // BRIDGE_IMOLA_H \ No newline at end of file +#endif // ROUTER_BRIDGE_H \ No newline at end of file From 63d1bf0f9ca80683fb6586a1aeaa06067980d7db Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Tue, 15 Jul 2025 12:48:45 +0200 Subject: [PATCH 12/12] mod: back to hardcoded Bridge-Serial1 dependency --- src/bridge.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/bridge.h b/src/bridge.h index 7c9e5c5..afc1d25 100644 --- a/src/bridge.h +++ b/src/bridge.h @@ -171,11 +171,7 @@ class BridgeClassUpdater { BridgeClassUpdater() = delete; // prevents instantiation }; -#if defined(UNOQ) || defined(ARDUINO_UNOQ) BridgeClass Bridge(Serial1); -#else -extern BridgeClass Bridge; -#endif void updateEntryPoint(void *, void *, void *){ while(1){