From 4a2b70e172a68c1285ca7d0f25d30a83cc361ca1 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 31 Jul 2025 15:27:49 +0200 Subject: [PATCH 1/6] Fix crash when Arduino_RouterBridge is included but begin() not called --- src/bridge.h | 28 +++++++++++++++++++++------- src/monitor.h | 20 ++++++++++++-------- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/bridge.h b/src/bridge.h index 51482be..91d7548 100644 --- a/src/bridge.h +++ b/src/bridge.h @@ -37,11 +37,13 @@ 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; + bool started = false; + public: BridgeClass(HardwareSerial& serial) { @@ -49,6 +51,10 @@ class BridgeClass { transport = new SerialTransport(serial); } + operator bool() const { + return started; + } + // Initialize the bridge bool begin(unsigned long baud=DEFAULT_SERIAL_BAUD) { serial_ptr->begin(baud); @@ -67,7 +73,11 @@ class BridgeClass { UPDATE_THREAD_PRIORITY, 0, K_NO_WAIT); bool res; - return call(RESET_METHOD, res); + call(RESET_METHOD, res); + if (res) { + started = true; + } + return res; } template @@ -212,8 +222,10 @@ class BridgeClass { class BridgeClassUpdater { public: - static void safeUpdate(BridgeClass& bridge) { - bridge.update_safe(); // access private method + static void safeUpdate(BridgeClass* bridge) { + if (*bridge) { + bridge->update_safe(); + } } private: @@ -223,14 +235,16 @@ class BridgeClassUpdater { BridgeClass Bridge(Serial1); void updateEntryPoint(void *, void *, void *){ - while(1){ - Bridge.update(); + while (1) { + if (Bridge) { + Bridge.update(); + } k_msleep(1); } } static void safeUpdate(){ - BridgeClassUpdater::safeUpdate(Bridge); + BridgeClassUpdater::safeUpdate(&Bridge); } void __loopHook(){ diff --git a/src/monitor.h b/src/monitor.h index e4513b5..ff8049d 100644 --- a/src/monitor.h +++ b/src/monitor.h @@ -28,20 +28,23 @@ template class BridgeMonitor: public Stream { private: - BridgeClass& bridge; + BridgeClass* bridge; RingBufferN temp_buffer; struct k_mutex monitor_mutex; bool is_connected = false; public: - BridgeMonitor(BridgeClass& bridge): bridge(bridge) {} + BridgeMonitor(BridgeClass& bridge): bridge(&bridge) {} bool begin() { - return bridge.call(MON_CONNECTED_METHOD, is_connected); k_mutex_init(&monitor_mutex); + if (!bridge) { + bridge->begin(); + } + return bridge->call(MON_CONNECTED_METHOD, is_connected); } - bool isConnected() const { + operator bool() const { return is_connected; } @@ -73,6 +76,7 @@ class BridgeMonitor: public Stream { int peek() override { k_mutex_lock(&monitor_mutex, K_FOREVER); if (temp_buffer.available()) { + k_mutex_unlock(&monitor_mutex); return temp_buffer.peek(); } k_mutex_unlock(&monitor_mutex); @@ -95,7 +99,7 @@ class BridgeMonitor: public Stream { } size_t written; - bool ret = bridge.call(MON_WRITE_METHOD, written, send_buffer); + bool ret = bridge->call(MON_WRITE_METHOD, written, send_buffer); if (ret) { return written; } @@ -105,7 +109,7 @@ class BridgeMonitor: public Stream { bool reset() { bool res; - bool ok = bridge.call(MON_RESET_METHOD, res); + bool ok = bridge->call(MON_RESET_METHOD, res); if (ok && res) { is_connected = false; } @@ -114,7 +118,7 @@ class BridgeMonitor: public Stream { size_t write(String message) { size_t size; - bool ok = bridge.call(MON_WRITE_METHOD, size, message); + bool ok = bridge->call(MON_WRITE_METHOD, size, message); if (!ok) return 0; @@ -126,7 +130,7 @@ class BridgeMonitor: public Stream { if (size == 0) return 0; MsgPack::arr_t message; - bool ret = bridge.call(MON_READ_METHOD, message, size); + bool ret = bridge->call(MON_READ_METHOD, message, size); k_mutex_lock(&monitor_mutex, K_FOREVER); if (ret) { From 49d5a7760dd7147cb1b4be7071ac2c45f4089d26 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Fri, 1 Aug 2025 18:33:31 +0200 Subject: [PATCH 2/6] fix: Monitor begin alone crashes. mod: minor UNDER TESTING --- src/bridge.h | 12 ++++++------ src/monitor.h | 16 +++++----------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/bridge.h b/src/bridge.h index 91d7548..fbcc33e 100644 --- a/src/bridge.h +++ b/src/bridge.h @@ -33,7 +33,7 @@ class BridgeClass { RPCClient* client = nullptr; RPCServer* server = nullptr; HardwareSerial* serial_ptr = nullptr; - ITransport* transport; + ITransport* transport = nullptr; struct k_mutex read_mutex; struct k_mutex write_mutex; @@ -48,16 +48,16 @@ class BridgeClass { BridgeClass(HardwareSerial& serial) { serial_ptr = &serial; - transport = new SerialTransport(serial); } - operator bool() const { + explicit operator bool() const { return started; } // Initialize the bridge bool begin(unsigned long baud=DEFAULT_SERIAL_BAUD) { serial_ptr->begin(baud); + transport = new SerialTransport(*serial_ptr); k_mutex_init(&read_mutex); k_mutex_init(&write_mutex); @@ -175,11 +175,11 @@ class BridgeClass { } String get_error_message() const { - return (String) client->lastError.traceback; + return static_cast(client->lastError.traceback); } uint8_t get_error_code() const { - return (uint8_t) client->lastError.code; + return static_cast(client->lastError.code); } private: @@ -235,7 +235,7 @@ class BridgeClassUpdater { BridgeClass Bridge(Serial1); void updateEntryPoint(void *, void *, void *){ - while (1) { + while (true) { if (Bridge) { Bridge.update(); } diff --git a/src/monitor.h b/src/monitor.h index ff8049d..bf4ecdd 100644 --- a/src/monitor.h +++ b/src/monitor.h @@ -36,9 +36,11 @@ class BridgeMonitor: public Stream { public: BridgeMonitor(BridgeClass& bridge): bridge(&bridge) {} + using Print::write; + bool begin() { k_mutex_init(&monitor_mutex); - if (!bridge) { + if (!(*bridge)) { bridge->begin(); } return bridge->call(MON_CONNECTED_METHOD, is_connected); @@ -80,6 +82,7 @@ class BridgeMonitor: public Stream { return temp_buffer.peek(); } k_mutex_unlock(&monitor_mutex); + return -1; } size_t write(uint8_t c) override { @@ -92,7 +95,7 @@ class BridgeMonitor: public Stream { for (size_t i = 0; i < size; ++i) { #ifdef ARDUINO - send_buffer += (char)buffer[i]; + send_buffer += static_cast(buffer[i]); #else send_buffer.push_back(static_cast(buffer[i])); #endif @@ -116,15 +119,6 @@ class BridgeMonitor: public Stream { return (ok && res); } - size_t write(String message) { - size_t size; - bool ok = bridge->call(MON_WRITE_METHOD, size, message); - - if (!ok) return 0; - - return size; - } - int _read(size_t size) { if (size == 0) return 0; From f179f14efba2c42e01269660786941a1f78e97c9 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Mon, 4 Aug 2025 12:46:41 +0200 Subject: [PATCH 3/6] mod: minor bridge. monitor._read as void fix: monitor._read mux unlock --- src/bridge.h | 6 +++--- src/monitor.h | 12 +++++------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/bridge.h b/src/bridge.h index fbcc33e..d1a6afb 100644 --- a/src/bridge.h +++ b/src/bridge.h @@ -46,7 +46,7 @@ class BridgeClass { public: - BridgeClass(HardwareSerial& serial) { + explicit BridgeClass(HardwareSerial& serial) { serial_ptr = &serial; } @@ -234,7 +234,7 @@ class BridgeClassUpdater { BridgeClass Bridge(Serial1); -void updateEntryPoint(void *, void *, void *){ +inline void updateEntryPoint(void *, void *, void *){ while (true) { if (Bridge) { Bridge.update(); @@ -247,7 +247,7 @@ static void safeUpdate(){ BridgeClassUpdater::safeUpdate(&Bridge); } -void __loopHook(){ +inline void __loopHook(){ k_msleep(1); safeUpdate(); } diff --git a/src/monitor.h b/src/monitor.h index bf4ecdd..aed63b1 100644 --- a/src/monitor.h +++ b/src/monitor.h @@ -34,7 +34,7 @@ class BridgeMonitor: public Stream { bool is_connected = false; public: - BridgeMonitor(BridgeClass& bridge): bridge(&bridge) {} + explicit BridgeMonitor(BridgeClass& bridge): bridge(&bridge) {} using Print::write; @@ -46,7 +46,7 @@ class BridgeMonitor: public Stream { return bridge->call(MON_CONNECTED_METHOD, is_connected); } - operator bool() const { + explicit operator bool() const { return is_connected; } @@ -119,9 +119,9 @@ class BridgeMonitor: public Stream { return (ok && res); } - int _read(size_t size) { + void _read(size_t size) { - if (size == 0) return 0; + if (size == 0) return; MsgPack::arr_t message; bool ret = bridge->call(MON_READ_METHOD, message, size); @@ -131,15 +131,13 @@ class BridgeMonitor: public Stream { for (size_t i = 0; i < message.size(); ++i) { temp_buffer.store_char(static_cast(message[i])); } - return message.size(); } // if (bridge.lastError.code > NO_ERR) { // is_connected = false; // } - k_mutex_unlock(&monitor_mutex); - return 0; + k_mutex_unlock(&monitor_mutex); } From 4368f75c69e229cb8304d09601eacdfa06968800 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Tue, 5 Aug 2025 19:05:03 +0200 Subject: [PATCH 4/6] impr: bridge cleanup and get_last_client_error method fix: monitor trying to connect even if bridge begin fails + monitor._read is private mod: implementation is Arduino only, better mux usage --- src/bridge.h | 18 +++++++++++------- src/monitor.h | 23 +++++++++++------------ 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/bridge.h b/src/bridge.h index d1a6afb..d377b28 100644 --- a/src/bridge.h +++ b/src/bridge.h @@ -35,12 +35,12 @@ class BridgeClass { HardwareSerial* serial_ptr = nullptr; ITransport* transport = nullptr; - struct k_mutex read_mutex; - struct k_mutex write_mutex; + 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; + k_tid_t upd_tid{}; + k_thread_stack_t *upd_stack_area{}; + struct k_thread upd_thread_data{}; bool started = false; @@ -50,7 +50,7 @@ class BridgeClass { serial_ptr = &serial; } - explicit operator bool() const { + operator bool() const { return started; } @@ -133,7 +133,7 @@ class BridgeClass { } template - bool call(const MsgPack::str_t method, RType& result, Args&&... args) { + bool call(const MsgPack::str_t& method, RType& result, Args&&... args) { uint32_t msg_id_wait; @@ -182,6 +182,10 @@ class BridgeClass { return static_cast(client->lastError.code); } + RpcError& get_last_client_error() const { + return client->lastError; + } + private: void update_safe() { diff --git a/src/monitor.h b/src/monitor.h index aed63b1..c0b7bec 100644 --- a/src/monitor.h +++ b/src/monitor.h @@ -27,10 +27,9 @@ template class BridgeMonitor: public Stream { -private: BridgeClass* bridge; RingBufferN temp_buffer; - struct k_mutex monitor_mutex; + struct k_mutex monitor_mutex{}; bool is_connected = false; public: @@ -40,10 +39,12 @@ class BridgeMonitor: public Stream { bool begin() { k_mutex_init(&monitor_mutex); - if (!(*bridge)) { - bridge->begin(); + + bool bridge_started = (*bridge); + if (!bridge_started) { + bridge_started = bridge->begin(); } - return bridge->call(MON_CONNECTED_METHOD, is_connected); + return bridge_started && bridge->call(MON_CONNECTED_METHOD, is_connected); } explicit operator bool() const { @@ -91,18 +92,14 @@ class BridgeMonitor: public Stream { size_t write(const uint8_t* buffer, size_t size) override { - MsgPack::str_t send_buffer; + String send_buffer; for (size_t i = 0; i < size; ++i) { -#ifdef ARDUINO send_buffer += static_cast(buffer[i]); -#else - send_buffer.push_back(static_cast(buffer[i])); -#endif } size_t written; - bool ret = bridge->call(MON_WRITE_METHOD, written, send_buffer); + const bool ret = bridge->call(MON_WRITE_METHOD, written, send_buffer); if (ret) { return written; } @@ -119,14 +116,16 @@ class BridgeMonitor: public Stream { return (ok && res); } +private: void _read(size_t size) { if (size == 0) return; + k_mutex_lock(&monitor_mutex, K_FOREVER); + MsgPack::arr_t message; bool ret = bridge->call(MON_READ_METHOD, message, size); - k_mutex_lock(&monitor_mutex, K_FOREVER); if (ret) { for (size_t i = 0; i < message.size(); ++i) { temp_buffer.store_char(static_cast(message[i])); From 7990474b8b52273d84414647e0fc6d53e156d597 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Tue, 5 Aug 2025 19:06:35 +0200 Subject: [PATCH 5/6] feat: tcp_client.h implementation TBT --- src/tcp_client.h | 178 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 src/tcp_client.h diff --git a/src/tcp_client.h b/src/tcp_client.h new file mode 100644 index 0000000..7955bf2 --- /dev/null +++ b/src/tcp_client.h @@ -0,0 +1,178 @@ +/* + This file is part of the Arduino_RouterBridge library. + + Copyright (c) 2025 Arduino SA + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +*/ + +#pragma once + +#ifndef BRIDGE_TCP_CLIENT_H +#define BRIDGE_TCP_CLIENT_H + +#define TCP_CONNECT_METHOD "tcp/connect" +#define TCP_CLOSE_METHOD "tcp/close" +#define TCP_WRITE_METHOD "tcp/write" +#define TCP_READ_METHOD "tcp/read" + +#include +#include +#include "bridge.h" + +#define DEFAULT_TCP_CLIENT_BUF_SIZE 512 + +template +class BridgeTCPClient final: public Client { + + BridgeClass* bridge; + uint32_t connection_id{}; + RingBufferN temp_buffer; + struct k_mutex client_mutex{}; + bool _connected = false; + +public: + explicit BridgeTCPClient(BridgeClass& bridge): bridge(&bridge) {} + + bool begin() { + k_mutex_init(&client_mutex); + if (!(*bridge)) { + return bridge->begin(); + } + return true; + } + + int connect(IPAddress ip, uint16_t port) override { + return connect(ip.toString().c_str(), port); + } + + int connect(const char *host, uint16_t port) override { + + String send_buffer = host; + send_buffer += ":"; + send_buffer += String(port); + + k_mutex_lock(&client_mutex, K_FOREVER); + + const bool resp = bridge->call(TCP_CONNECT_METHOD, connection_id, send_buffer); + + if (!resp) { + _connected = false; + k_mutex_unlock(&client_mutex); + return -1; + } + _connected = true; + + k_mutex_unlock(&client_mutex); + + return 0; + } + + size_t write(uint8_t c) override { + return write(&c, 1); + } + + size_t write(const uint8_t *buf, size_t size) override { + String send_buffer; + + for (size_t i = 0; i < size; ++i) { + send_buffer += static_cast(buf[i]); + } + + size_t written; + const bool ret = bridge->call(TCP_WRITE_METHOD, written, send_buffer); + if (ret) { + return written; + } + + return 0; + } + + int available() override { + k_mutex_lock(&client_mutex, K_FOREVER); + const int size = temp_buffer.availableForStore(); + if (size > 0) _read(size); + const int available = temp_buffer.available(); + k_mutex_unlock(&client_mutex); + return available; + } + + int read() override { + uint8_t c; + read(&c, 1); + return c; + } + + int read(uint8_t *buf, size_t size) override { + k_mutex_lock(&client_mutex, K_FOREVER); + int i = 0; + while (temp_buffer.available() && i < size) { + buf[i++] = temp_buffer.read_char(); + } + k_mutex_unlock(&client_mutex); + return i; + } + + int peek() override { + k_mutex_lock(&client_mutex, K_FOREVER); + if (temp_buffer.available()) { + k_mutex_unlock(&client_mutex); + return temp_buffer.peek(); + } + k_mutex_unlock(&client_mutex); + return -1; + } + + void flush() override { + // No-op: flush is implemented for Client subclasses using an output buffer + } + + void stop() override { + k_mutex_lock(&client_mutex, K_FOREVER); + String msg; + const bool resp = bridge->call(TCP_CLOSE_METHOD, msg, connection_id); + if (resp) { + _connected = false; + } + k_mutex_unlock(&client_mutex); + } + + uint8_t connected() override { + if (_connected) return 1; + return 0; + } + + operator bool() override { + return available() || connected(); + } + +private: + void _read(size_t size) { + + if (size == 0 || !_connected) return; + + k_mutex_lock(&client_mutex, K_FOREVER); + + MsgPack::arr_t message; + const bool ret = bridge->call(TCP_READ_METHOD, message, size); + + if (ret) { + for (size_t i = 0; i < message.size(); ++i) { + temp_buffer.store_char(static_cast(message[i])); + } + } + + if (bridge->get_last_client_error().code > NO_ERR) { + _connected = false; + } + + k_mutex_unlock(&client_mutex); + } + +}; + + +#endif //BRIDGE_TCP_CLIENT_H From e1055d22dda5d4a08d83fb0aa14875fda0c11b18 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Wed, 6 Aug 2025 10:32:49 +0200 Subject: [PATCH 6/6] ver: 0.1.3 RC --- library.json | 2 +- library.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index 30b5c46..7e8cf3c 100644 --- a/library.json +++ b/library.json @@ -11,7 +11,7 @@ "url": "https://github.com/bcmi-labs/Arduino_RouterBridge", "maintainer": true }, - "version": "0.1.2", + "version": "0.1.3", "license": "MPL2.0", "frameworks": "arduino", "platforms": "*", diff --git a/library.properties b/library.properties index ca1c9ed..38562b0 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Arduino_RouterBridge -version=0.1.2 +version=0.1.3 author=BCMI-labs maintainer=BCMI-labs sentence=A RPC bridge for Arduino UNO Q boards