Skip to content

Commit bf18094

Browse files
authored
Merge pull request #28 from arduino-libraries/27-rpcresult-improvements
27 rpcresult improvements
2 parents 5189ec5 + 3f06c40 commit bf18094

File tree

6 files changed

+28
-21
lines changed

6 files changed

+28
-21
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: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,27 @@
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-
34+
class RpcCall {
3535
public:
36-
RpcError error;
36+
RpcError error{GENERIC_ERR, "This call is not executed yet"};
3737

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)...)) {}
38+
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)...)) {}
3939

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

4349
while (true) {
4450
if (k_mutex_lock(write_mutex, K_MSEC(10)) == 0) {
@@ -69,7 +75,7 @@ class RpcResult {
6975
k_yield();
7076
}
7177
}
72-
_executed = true;
78+
7379
return error.code == NO_ERR;
7480
}
7581

@@ -78,7 +84,7 @@ class RpcResult {
7884
return result(nil);
7985
}
8086

81-
~RpcResult(){
87+
~RpcCall(){
8288
result();
8389
}
8490

@@ -88,7 +94,7 @@ class RpcResult {
8894

8995
private:
9096
uint32_t msg_id_wait{};
91-
bool _executed = false;
97+
atomic_t _executed = ATOMIC_INIT(0);;
9298

9399
MsgPack::str_t method;
94100
RPCClient* client;
@@ -210,8 +216,8 @@ class BridgeClass {
210216
}
211217

212218
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)...);
219+
RpcCall<Args...> call(const MsgPack::str_t& method, Args&&... args) {
220+
return RpcCall<Args...>(method, client, &read_mutex, &write_mutex, std::forward<Args>(args)...);
215221
}
216222

217223
template<typename... Args>

src/monitor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ class BridgeMonitor: public Stream {
142142
}
143143

144144
MsgPack::arr_t<uint8_t> message;
145-
RpcResult async_rpc = bridge->call(MON_READ_METHOD, size);
145+
RpcCall async_rpc = bridge->call(MON_READ_METHOD, size);
146146
const bool ret = async_rpc.result(message);
147147

148148
if (ret) {

src/tcp_client.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ class BridgeTCPClient : public Client {
193193
}
194194

195195
MsgPack::arr_t<uint8_t> message;
196-
RpcResult async_rpc = bridge->call(TCP_READ_METHOD, connection_id, size);
196+
RpcCall async_rpc = bridge->call(TCP_READ_METHOD, connection_id, size, read_timeout);
197197
const bool ret = async_rpc.result(message);
198198

199199
if (ret) {

0 commit comments

Comments
 (0)