Skip to content

Commit 190f7b7

Browse files
committed
API: RpcResult -> RpcCall
fix: RpcCall.result needs thread protected single execution
1 parent 3a47f86 commit 190f7b7

File tree

6 files changed

+27
-19
lines changed

6 files changed

+27
-19
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ In this repo it will be implemented an Arduino library wrapper for RPClite to be
55
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.
66

77
- The Bridge object is pre-defined on Serial1 and automatically initialized inside the main setup()
8-
- The Bridge.call method is non-blocking and returns a RpcResult async object
9-
- RpcResult class implements a blocking .result method that waits for the RPC response and returns true if the RPC returned with no errors
8+
- The Bridge.call method is non-blocking and returns a RpcCall async object
9+
- RpcCall class implements a blocking .result method that waits for the RPC response and returns true if the RPC returned with no errors
10+
- The RpcCall.result will return - by reference - the result value of that call *exactly once*. Subsequent calls to .result will return an error condition
1011
- The Bridge can provide callbacks to incoming RPC requests both in a thread-unsafe and thread-safe fashion (provide & provide_safe)
1112
- Thread-safe methods execution is granted in the main loop thread where update_safe is called. By design users cannot access .update_safe() freely
1213
- 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
@@ -52,7 +53,7 @@ void loop() {
5253
};
5354

5455
// Async call
55-
RpcResult async_rpc = Bridge.call("add", 3.0, 4.5);
56+
RpcCall async_rpc = Bridge.call("add", 3.0, 4.5);
5657
if (!async_rpc.result(sum)) {
5758
Monitor.println("Error calling method: add");
5859
Monitor.print("Error code: ");

examples/simple_bridge/simple_bridge.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ void loop() {
5252
};
5353

5454
// Call with deferred response check
55-
RpcResult outcome = Bridge.call("multiply", 5.0, 7.0);
55+
RpcCall outcome = Bridge.call("multiply", 5.0, 7.0);
5656
Serial.println("RPC called");
5757
delay(10);
5858
if (outcome.result(res)) {

examples/test/test.ino

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ void loop() {
6060
}
6161

6262
float pow;
63-
RpcResult async_res = Bridge.call("1_args_float_result", 2.0, 3.0); // passing 2 args to a function expecting 1
63+
RpcCall async_res = Bridge.call("1_args_float_result", 2.0, 3.0); // passing 2 args to a function expecting 1
6464
if (async_res.result(pow)) {
6565
Monitor.println("Result of assignment and then result: "+String(pow)); // returns true, so the right result
6666
} else {
@@ -69,7 +69,7 @@ void loop() {
6969
}
7070

7171
float div = 0;
72-
RpcResult async_res1 = Bridge.call("2_args_float_result", 2.0); // passing 1 arg when 2 are expected
72+
RpcCall async_res1 = Bridge.call("2_args_float_result", 2.0); // passing 1 arg when 2 are expected
7373
if (async_res1.result(div)) {
7474
Monitor.println("Result of assignment and then result: "+String(div)); // returns true, so the right result
7575
} else {
@@ -78,7 +78,7 @@ void loop() {
7878
}
7979

8080
div = 0;
81-
RpcResult async_res2 = Bridge.call("2_args_float_result", 2.0, "invalid"); // passing a wrong type arg
81+
RpcCall async_res2 = Bridge.call("2_args_float_result", 2.0, "invalid"); // passing a wrong type arg
8282
if (async_res2.result(div)) {
8383
Monitor.println("Result of assignment and then result: "+String(div)); // returns true, so the right result
8484
} else {
@@ -87,7 +87,7 @@ void loop() {
8787
}
8888

8989
x = false;
90-
RpcResult async_res3 = Bridge.call("0_args_bool_result");
90+
RpcCall async_res3 = Bridge.call("0_args_bool_result");
9191
if (async_res3.result(x)) {
9292
Monitor.println("Result of assignment and then result: "+String(x)); // returns true, so the right result
9393
} else {
@@ -96,7 +96,7 @@ void loop() {
9696

9797
// Avoid the following:
9898
// the call happens in the destructor falling back to the "no_result" case (a type mismatch here)
99-
RpcResult async_res4 = Bridge.call("0_args_bool_result");
99+
RpcCall async_res4 = Bridge.call("0_args_bool_result");
100100

101101
delay(1000);
102102
}

src/bridge.h

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,28 @@
2424
#define DEFAULT_SERIAL_BAUD 115200
2525

2626
#include <zephyr/kernel.h>
27+
#include <zephyr/sys/atomic.h>
2728
#include <Arduino_RPClite.h>
2829

2930

3031
void updateEntryPoint(void *, void *, void *);
3132

3233
template<typename... Args>
33-
class RpcResult {
34+
class RpcCall {
3435

3536
public:
3637
RpcError error;
3738

38-
RpcResult(const MsgPack::str_t& m, RPCClient* c, struct k_mutex* rm, struct k_mutex* wm, Args&&... args): method(m), client(c), read_mutex(rm), write_mutex(wm), callback_params(std::forward_as_tuple(std::forward<Args>(args)...)) {}
39+
RpcCall(const MsgPack::str_t& m, RPCClient* c, struct k_mutex* rm, struct k_mutex* wm, Args&&... args): method(m), client(c), read_mutex(rm), write_mutex(wm), callback_params(std::forward_as_tuple(std::forward<Args>(args)...)) {}
3940

4041
template<typename RType> bool result(RType& result) {
41-
if (_executed) return error.code == NO_ERR;
42+
43+
if (!atomic_cas(&_executed, 0, 1)){
44+
// this thread lost the race
45+
error.code = GENERIC_ERR;
46+
error.traceback = "This call result is no longer available";
47+
return false;
48+
}
4249

4350
while (true) {
4451
if (k_mutex_lock(write_mutex, K_MSEC(10)) == 0) {
@@ -69,7 +76,7 @@ class RpcResult {
6976
k_yield();
7077
}
7178
}
72-
_executed = true;
79+
7380
return error.code == NO_ERR;
7481
}
7582

@@ -78,7 +85,7 @@ class RpcResult {
7885
return result(nil);
7986
}
8087

81-
~RpcResult(){
88+
~RpcCall(){
8289
result();
8390
}
8491

@@ -88,7 +95,7 @@ class RpcResult {
8895

8996
private:
9097
uint32_t msg_id_wait{};
91-
bool _executed = false;
98+
atomic_t _executed = ATOMIC_INIT(0);;
9299

93100
MsgPack::str_t method;
94101
RPCClient* client;
@@ -210,8 +217,8 @@ class BridgeClass {
210217
}
211218

212219
template<typename... Args>
213-
RpcResult<Args...> call(const MsgPack::str_t& method, Args&&... args) {
214-
return RpcResult<Args...>(method, client, &read_mutex, &write_mutex, std::forward<Args>(args)...);
220+
RpcCall<Args...> call(const MsgPack::str_t& method, Args&&... args) {
221+
return RpcCall<Args...>(method, client, &read_mutex, &write_mutex, std::forward<Args>(args)...);
215222
}
216223

217224
template<typename... Args>

src/monitor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ class BridgeMonitor: public Stream {
137137
k_mutex_lock(&monitor_mutex, K_FOREVER);
138138

139139
MsgPack::arr_t<uint8_t> message;
140-
RpcResult async_rpc = bridge->call(MON_READ_METHOD, size);
140+
RpcCall async_rpc = bridge->call(MON_READ_METHOD, size);
141141
const bool ret = _connected && async_rpc.result(message);
142142

143143
if (ret) {

src/tcp_client.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ class BridgeTCPClient : public Client {
179179
k_mutex_lock(&client_mutex, K_FOREVER);
180180

181181
MsgPack::arr_t<uint8_t> message;
182-
RpcResult async_rpc = bridge->call(TCP_READ_METHOD, connection_id, size);
182+
RpcCall async_rpc = bridge->call(TCP_READ_METHOD, connection_id, size);
183183
const bool ret = _connected && async_rpc.result(message);
184184

185185
if (ret) {

0 commit comments

Comments
 (0)