From 2c098c351d17546fdb518af2848f8905ab03bda0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christopher=20M=C3=A9ndez?= <49886387+mcmchris@users.noreply.github.com> Date: Thu, 20 Nov 2025 17:16:24 -0400 Subject: [PATCH 1/7] Router update started --- .../uno-q/tutorials/01.user-manual/content.md | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md b/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md index 921cbd32bd..e59bb162eb 100644 --- a/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md +++ b/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md @@ -785,6 +785,35 @@ The `Bridge` library provides a communication layer built on top of the `Arduino - **MPU side (Qualcomm QRB, Linux)**: Runs higher-level services and can remotely invoke MCU functions. - **MCU side (STM32, Zephyr RTOS)**: Handles time-critical tasks and exposes functions to the MPU via RPC. +#### The Arduino Router (Infrastructure) + +Under the hood, the communication is managed by a background Linux service called the Arduino Router (`arduino-router`). + +While the `Bridge` library is what you use in your code, the Router is the traffic controller that makes it possible. It implements a **Star Topology** network using MessagePack RPC. + +**Key Features:** + +- **Multipoint Communication:** Unlike simple serial communication (which is typically point-to-point), the Router allows multiple Linux processes to communicate with the MCU simultaneously. For example, you could have a Python script reading sensor data while a separate C++ application commands motors, both interacting with the same running Sketch. + +- **Service Discovery:** Clients (like your Python script or the MCU Sketch) "register" functions they want to expose. The Router keeps a directory of these functions and routes calls to the correct destination. + +**Managing the Router Service** + +The arduino-router runs automatically as a system service. In most cases, you do not need to interact with it directly. However, if you are debugging advanced issues or need to restart the communication stack, you can control it via the Linux terminal: + +**Check Status** To see if the router is running and connected: +```bash +systemctl status arduino-router +``` +**Restart the Service** If the communication seems stuck, you can restart the router without rebooting the board: +```bash +sudo systemctl restart arduino-router +``` +**View Logs** To view the real-time logs for debugging (e.g., to see if RPC messages are being rejected or if a client has disconnected): +```bash +journalctl -u arduino-router -f +``` + #### Core Components `BridgeClass` From ea9675ed1eb5a205c5056f3ed78cb3750f7e102a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christopher=20M=C3=A9ndez?= <49886387+mcmchris@users.noreply.github.com> Date: Fri, 21 Nov 2025 10:49:26 -0400 Subject: [PATCH 2/7] Methods update --- .../uno-q/tutorials/01.user-manual/content.md | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md b/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md index e59bb162eb..ca54253aa6 100644 --- a/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md +++ b/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md @@ -816,20 +816,24 @@ journalctl -u arduino-router -f #### Core Components -`BridgeClass` -- Main class managing RPC clients and servers. Provides methods to: -- Initialize the bridge (`begin()`) -- Call remote procedures (`call()`) -- Notify without waiting for a response (`notify()`) -- Expose local functions for remote execution (`provide()`, `provide_safe()`) -- Process incoming requests (`update()`) +`BridgeClass` The main class managing RPC clients and servers. +- `begin()`: Initializes the bridge and the internal serial transport. +- `call(method, args...)`: Invokes a function on the Linux side and waits for a result. +- `notify(method, args...)`: Invokes a function on the Linux side without waiting for a response (fire-and-forget). +- `provide(name, function)`: Exposes a local MCU function to Linux. Note: The function executes in the high-priority background RPC thread. Keep these functions short and thread-safe. +- `provide_safe(name, function)`: Exposes a local MCU function, but ensures it executes within the main `loop()` context. Use this if your function interacts with standard Arduino APIs (like `digitalWrite` or `Serial`) to avoid concurrency crashes. +- `update()`: Process incoming requests. +`RpcCall` +- Helper class representing an asynchronous RPC. If its `.result` method is invoked, it waits for the response, extracts the return value, and propagates error codes if needed. -`RpcResult` -- Helper class representing the result of a remote call. It waits for the response, extracts the return value, and propagates error codes if needed. +`Monitor` +- The library includes a pre-defined Monitor object. This allows the Linux side to send text streams to the MCU (acting like a virtual Serial Monitor) via the RPC method mon/write. **Threading and Safety** - The bridge uses Zephyr mutexes (`k_mutex`) to guarantee safe concurrent access when reading/writing over the transport. Updates are handled by a background thread that continuously polls for requests. +- **Incoming Updates**: Handled by a dedicated background thread (`updateEntryPoint`) that continuously polls for requests. +- **Safe Execution**: The provide_safe mechanism hooks into the main loop (`__loopHook`) to execute user callbacks safely when the processor is idle. #### Usage Example From b6fd667b91d8a6063f021b2526e360a28bdb4e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christopher=20M=C3=A9ndez?= <49886387+mcmchris@users.noreply.github.com> Date: Fri, 21 Nov 2025 12:00:08 -0400 Subject: [PATCH 3/7] Review suggestions applied 1/2 --- .../uno-q/tutorials/01.user-manual/content.md | 56 ++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md b/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md index ca54253aa6..b3565c6346 100644 --- a/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md +++ b/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md @@ -793,7 +793,11 @@ While the `Bridge` library is what you use in your code, the Router is the traff **Key Features:** -- **Multipoint Communication:** Unlike simple serial communication (which is typically point-to-point), the Router allows multiple Linux processes to communicate with the MCU simultaneously. For example, you could have a Python script reading sensor data while a separate C++ application commands motors, both interacting with the same running Sketch. +- **Multipoint Communication:** Unlike simple serial communication (which is typically point-to-point), the Router allows multiple Linux processes to communicate with the MCU simultaneously (and with each other). + + **Linux ↔ MCU:** Multiple Linux processes can interact with the MCU simultaneously (e.g., a Python script reading sensors while a separate C++ application commands motors). + + **Linux ↔ Linux:** You can use the Router to bridge different applications running on the MPU. For example, a Python script can expose an RPC function that another Python or C++ application calls directly, allowing services to exchange data without involving the MCU at all. - **Service Discovery:** Clients (like your Python script or the MCU Sketch) "register" functions they want to expose. The Router keeps a directory of these functions and routes calls to the correct destination. @@ -814,6 +818,55 @@ sudo systemctl restart arduino-router journalctl -u arduino-router -f ``` +To capture more detailed information in the logs, you can append the `--verbose` argument to the systemd service configuration. + +- Open the service file for editing: + ```bash + sudo nano /etc/systemd/system/arduino-router.service + ``` + +- Locate the line beginning with `ExecStart=` and append `--verbose` to the end of the command. The updated service file should look like this: + + ```bash + [Unit] + Description=Arduino Router Service + After=network-online.target + Wants=network-online.target + Requires= + + [Service] + # Put the micro in a ready state. + ExecStartPre=-/usr/bin/gpioset -c /dev/gpiochip1 -t0 37=0 + ExecStart=/usr/bin/arduino-router --unix-port /var/run/arduino-router.sock --serial-port /dev/ttyHS1 --serial-baudrate 115200 --verbose # <--- ADD THIS + # End the boot animation after the router is started. + ExecStartPost=/usr/bin/gpioset -c /dev/gpiochip1 -t0 70=1 + StandardOutput=journal + StandardError=journal + Restart=always + RestartSec=3 + + [Install] + WantedBy=multi-user.target + ``` + +- You must reload the systemd daemon for the configuration changes to take effect. + + ```bash + sudo systemctl daemon-reload + ``` + +- Restart the Router: + + ```bash + sudo systemctl restart arduino-router + ``` + +- View the verbose logs: + + ```bash + journalctl -u arduino-router -f + ``` + #### Core Components `BridgeClass` The main class managing RPC clients and servers. @@ -822,7 +875,6 @@ journalctl -u arduino-router -f - `notify(method, args...)`: Invokes a function on the Linux side without waiting for a response (fire-and-forget). - `provide(name, function)`: Exposes a local MCU function to Linux. Note: The function executes in the high-priority background RPC thread. Keep these functions short and thread-safe. - `provide_safe(name, function)`: Exposes a local MCU function, but ensures it executes within the main `loop()` context. Use this if your function interacts with standard Arduino APIs (like `digitalWrite` or `Serial`) to avoid concurrency crashes. -- `update()`: Process incoming requests. `RpcCall` - Helper class representing an asynchronous RPC. If its `.result` method is invoked, it waits for the response, extracts the return value, and propagates error codes if needed. From 73f6fdd0b39152b3e42ad4c873337f993d0d9405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christopher=20M=C3=A9ndez?= <49886387+mcmchris@users.noreply.github.com> Date: Fri, 21 Nov 2025 14:17:05 -0400 Subject: [PATCH 4/7] Provide functions warning --- .../02.uno/boards/uno-q/tutorials/01.user-manual/content.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md b/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md index b3565c6346..87d27a134c 100644 --- a/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md +++ b/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md @@ -876,6 +876,8 @@ To capture more detailed information in the logs, you can append the `--verbose` - `provide(name, function)`: Exposes a local MCU function to Linux. Note: The function executes in the high-priority background RPC thread. Keep these functions short and thread-safe. - `provide_safe(name, function)`: Exposes a local MCU function, but ensures it executes within the main `loop()` context. Use this if your function interacts with standard Arduino APIs (like `digitalWrite` or `Serial`) to avoid concurrency crashes. +***__Warning:__ Do not use `Bridge.call()` or `Monitor.print()` inside `provide()` functions. Initiating a new communication while responding to one causes system deadlocks.*** + `RpcCall` - Helper class representing an asynchronous RPC. If its `.result` method is invoked, it waits for the response, extracts the return value, and propagates error codes if needed. From 2fa4c910617004973bea652870dbf3181eefc9df Mon Sep 17 00:00:00 2001 From: TaddyHC <94547080+TaddyHC@users.noreply.github.com> Date: Fri, 21 Nov 2025 14:42:00 -0600 Subject: [PATCH 5/7] Update content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md --- .../02.uno/boards/uno-q/tutorials/01.user-manual/content.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md b/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md index 87d27a134c..5c88e5af6f 100644 --- a/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md +++ b/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md @@ -795,7 +795,7 @@ While the `Bridge` library is what you use in your code, the Router is the traff - **Multipoint Communication:** Unlike simple serial communication (which is typically point-to-point), the Router allows multiple Linux processes to communicate with the MCU simultaneously (and with each other). - **Linux ↔ MCU:** Multiple Linux processes can interact with the MCU simultaneously (e.g., a Python script reading sensors while a separate C++ application commands motors). + **Linux ↔ MCU:** Multiple Linux processes can interact with the MCU simultaneously (e.g., a Python® script reading sensors while a separate C++ application commands motors). **Linux ↔ Linux:** You can use the Router to bridge different applications running on the MPU. For example, a Python script can expose an RPC function that another Python or C++ application calls directly, allowing services to exchange data without involving the MCU at all. From fcc47694a2f6f55066a69a373dae2adbaf9f9e6c Mon Sep 17 00:00:00 2001 From: TaddyHC <94547080+TaddyHC@users.noreply.github.com> Date: Fri, 21 Nov 2025 14:42:09 -0600 Subject: [PATCH 6/7] Update content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md --- .../02.uno/boards/uno-q/tutorials/01.user-manual/content.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md b/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md index 5c88e5af6f..504ef16549 100644 --- a/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md +++ b/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md @@ -797,7 +797,7 @@ While the `Bridge` library is what you use in your code, the Router is the traff **Linux ↔ MCU:** Multiple Linux processes can interact with the MCU simultaneously (e.g., a Python® script reading sensors while a separate C++ application commands motors). - **Linux ↔ Linux:** You can use the Router to bridge different applications running on the MPU. For example, a Python script can expose an RPC function that another Python or C++ application calls directly, allowing services to exchange data without involving the MCU at all. + **Linux ↔ Linux:** You can use the Router to bridge different applications running on the MPU. For example, a Python script can expose an RPC function that another Python® or C++ application calls directly, allowing services to exchange data without involving the MCU at all. - **Service Discovery:** Clients (like your Python script or the MCU Sketch) "register" functions they want to expose. The Router keeps a directory of these functions and routes calls to the correct destination. From 4c6e489748667115e252bd3cea5e4e9040c5c841 Mon Sep 17 00:00:00 2001 From: TaddyHC <94547080+TaddyHC@users.noreply.github.com> Date: Fri, 21 Nov 2025 14:42:14 -0600 Subject: [PATCH 7/7] Update content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md --- .../02.uno/boards/uno-q/tutorials/01.user-manual/content.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md b/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md index 504ef16549..5bb7425c39 100644 --- a/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md +++ b/content/hardware/02.uno/boards/uno-q/tutorials/01.user-manual/content.md @@ -799,7 +799,7 @@ While the `Bridge` library is what you use in your code, the Router is the traff **Linux ↔ Linux:** You can use the Router to bridge different applications running on the MPU. For example, a Python script can expose an RPC function that another Python® or C++ application calls directly, allowing services to exchange data without involving the MCU at all. -- **Service Discovery:** Clients (like your Python script or the MCU Sketch) "register" functions they want to expose. The Router keeps a directory of these functions and routes calls to the correct destination. +- **Service Discovery:** Clients (like your Python® script or the MCU Sketch) "register" functions they want to expose. The Router keeps a directory of these functions and routes calls to the correct destination. **Managing the Router Service**