Skip to content

Commit 7e6a314

Browse files
committed
Merge branch 'main' into refactoring_opt
revert rpclite_utils removal fix: multiple definition compile error fix: notifications can stall server
2 parents 92c2212 + cbc002e commit 7e6a314

File tree

10 files changed

+268
-158
lines changed

10 files changed

+268
-158
lines changed

.github/workflows/compile-examples.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,8 @@ jobs:
2323
build:
2424
name: ${{ matrix.board.fqbn }}
2525
runs-on: ubuntu-latest
26-
permissions: {
26+
permissions:
2727
contents: read
28-
}
2928

3029
env:
3130
LIBRARIES: |
@@ -75,7 +74,6 @@ jobs:
7574
uses: arduino/compile-sketches@v1
7675
with:
7776
github-token: ${{ secrets.GITHUB_TOKEN }}
78-
platforms: ${{ matrix.platforms }}
7977
fqbn: ${{ matrix.board.fqbn }}
8078
libraries: ${{ env.LIBRARIES }}
8179
sketch-paths: ${{ env.SKETCH_PATHS }}

README.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,84 @@
22

33
A MessagePack RPC library for Arduino allows to create a client/server architecture using MessagePack as the serialization format. It follows the [MessagePack-RPC protocol specification](https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md). It is designed to be lightweight and easy to use, making it suitable for embedded systems and IoT applications.
44

5+
6+
## Server
7+
8+
```cpp
9+
#include <Arduino_RPClite.h>
10+
11+
RPCServer server(Serial1);
12+
13+
int add(int a, int b){
14+
return a+b;
15+
}
16+
17+
String loopback(String message){
18+
return message;
19+
}
20+
21+
void setup() {
22+
Serial1.begin(115200);
23+
while(!Serial1);
24+
25+
Serial.begin(9600);
26+
while(!Serial);
27+
28+
server.bind("add", add);
29+
server.bind("loopback", loopback);
30+
31+
}
32+
33+
void loop() {
34+
server.run();
35+
}
36+
37+
```
38+
39+
40+
## Client
41+
42+
```cpp
43+
#include <Arduino_RPClite.h>
44+
45+
RPCClient client(Serial1);
46+
47+
void setup() {
48+
Serial1.begin(115200);
49+
while(!Serial1);
50+
51+
pinMode(LED_BUILTIN, OUTPUT);
52+
53+
Serial.begin(9600);
54+
while(!Serial);
55+
}
56+
57+
void loop() {
58+
59+
bool ok;
60+
61+
String response;
62+
ok = client.call("loopback", response, "Sending a greeting");
63+
if (ok) Serial.println(str_res);
64+
65+
int sum_result;
66+
ok = client.call("add", sum_result, 2. 3);
67+
if (ok) Serial.println(sum_result); // must print 5
68+
69+
// ERROR handling
70+
float result;
71+
bool ok = client.call("unbound_method", result, 10.0);
72+
if (!ok) {
73+
Serial.print("Testing Server-side exception OK. ERR code: ");
74+
Serial.print(client.lastError.code);
75+
Serial.print(" ERR trace: ");
76+
Serial.println(client.lastError.traceback);
77+
}
78+
79+
}
80+
81+
```
82+
583
### Credits
684

785
This library is based on the MsgPack library by @hideakitai.

examples/rpc_lite_client/rpc_lite_client.ino

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
#include <Arduino_RPClite.h>
22

3-
SerialTransport transport(&Serial1);
4-
RPCClient client(transport);
3+
RPCClient client(Serial1);
54

65
void setup() {
76
Serial1.begin(115200);
8-
transport.begin();
7+
while(!Serial1);
8+
99
pinMode(LED_BUILTIN, OUTPUT);
10+
1011
Serial.begin(9600);
1112
while(!Serial);
1213
}

examples/rpc_lite_server/rpc_lite_server.ino

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
#include <Arduino_RPClite.h>
22

3-
SerialTransport transport(&Serial1);
4-
RPCServer server(transport);
3+
RPCServer server(Serial1);
54

65
int add(int a, int b){
76
return a+b;
87
}
98

10-
MsgPack::str_t greet(){
11-
return MsgPack::str_t ("Hello Friend");
9+
String greet(){
10+
return String("Hello Friend");
1211
}
1312

14-
MsgPack::str_t loopback(MsgPack::str_t message){
13+
String loopback(String message){
1514
return message;
1615
}
1716

@@ -27,13 +26,16 @@ public:
2726

2827
void setup() {
2928
Serial1.begin(115200);
30-
transport.begin();
29+
while(!Serial1);
30+
3131
pinMode(LED_BUILTIN, OUTPUT);
32+
3233
Serial.begin(9600);
3334
while(!Serial);
3435

3536
server.bind("add", add);
3637
server.bind("greet", greet);
38+
server.bind("loopback", loopback);
3739
server.bind("another_greeting", [] {return MsgPack::str_t ("This is a lambda greeting");});
3840
server.bind("object_multi", &multiplier::mult);
3941

src/SerialTransport.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ class SerialTransport: public ITransport {
1414

1515
SerialTransport(Stream* stream): _stream(stream){}
1616

17+
SerialTransport(Stream& stream): _stream(&stream){}
18+
1719
void begin(){}
1820

1921
bool available() override {

src/client.h

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,40 @@
66
#define RPCLITE_CLIENT_H
77
#include "error.h"
88
#include "decoder_manager.h"
9+
#include "SerialTransport.h"
10+
911

1012
class RPCClient {
11-
ITransport& transport;
12-
RpcDecoder<>& decoder;
13+
RpcDecoder<>* decoder = nullptr;
1314

1415
public:
1516
RpcError lastError;
1617

17-
RPCClient(ITransport& t) : transport(t), decoder(RpcDecoderManager<>::getDecoder(t)) {}
18+
RPCClient(ITransport& t) : decoder(&RpcDecoderManager<>::getDecoder(t)) {}
19+
20+
RPCClient(Stream& stream) {
21+
ITransport* transport = (ITransport*) new SerialTransport(stream);
22+
decoder = &RpcDecoderManager<>::getDecoder(*transport);
23+
}
1824

1925
template<typename... Args>
2026
void notify(const MsgPack::str_t method, Args&&... args) {
2127
int _id;
22-
decoder.send_call(NOTIFY_MSG, method, _id, std::forward<Args>(args)...);
28+
decoder->send_call(NOTIFY_MSG, method, _id, std::forward<Args>(args)...);
2329
}
2430

2531
template<typename RType, typename... Args>
2632
bool call(const MsgPack::str_t method, RType& result, Args&&... args) {
2733

2834
int msg_id;
29-
if (!decoder.send_call(CALL_MSG, method, msg_id, std::forward<Args>(args)...)){
35+
if (!decoder->send_call(CALL_MSG, method, msg_id, std::forward<Args>(args)...)){
3036
}
3137

3238
RpcError error;
3339
// blocking call
34-
while (!decoder.get_response(msg_id, result, error)){
35-
if (!decoder.process()) {
36-
delay(1);
37-
}
40+
while (!decoder->get_response(msg_id, result, error)){
41+
decoder->process();
42+
delay(1);
3843
}
3944

4045
lastError.code = error.code;

src/decoder.h

Lines changed: 7 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
#include "MsgPack.h"
55
#include "transport.h"
66
#include "dispatcher.h"
7+
#include "rpclite_utils.h"
78

9+
using namespace RpcUtils::detail;
810

911
#define NO_MSG -1
1012
#define CALL_MSG 0
@@ -168,22 +170,18 @@ class RpcDecoder {
168170

169171
}
170172

171-
bool process(){
172-
if (advance()) {
173-
parse_packet();
174-
return true;
175-
}
176-
return false;
173+
void process(){
174+
advance();
175+
parse_packet();
177176
}
178177

179178
// Fill the raw buffer to its capacity
180-
bool advance() {
179+
void advance() {
181180

182181
uint8_t temp_buf[CHUNK_SIZE];
183182

184183
if (_transport.available() && !buffer_full()){
185184
int bytes_read = _transport.read(temp_buf, CHUNK_SIZE);
186-
if (bytes_read <= 0) return false;
187185

188186
for (int i = 0; i < bytes_read; ++i) {
189187
_raw_buffer[_bytes_stored] = temp_buf[i];
@@ -192,9 +190,8 @@ class RpcDecoder {
192190
delay(1);
193191
}
194192
}
195-
return true;
196193
}
197-
return false;
194+
198195
}
199196

200197
void parse_packet(){
@@ -298,91 +295,6 @@ class RpcDecoder {
298295
return 0;
299296
}
300297

301-
bool unpackArray(MsgPack::Unpacker& unpacker, size_t& size) {
302-
MsgPack::arr_size_t sz;
303-
unpacker.deserialize(sz);
304-
305-
size = 0;
306-
for (size_t i=0; i<sz.size(); i++){
307-
if (unpackObject(unpacker)){
308-
size++;
309-
} else {
310-
return false;
311-
}
312-
}
313-
314-
return true;
315-
316-
}
317-
318-
bool unpackMap(MsgPack::Unpacker& unpacker, size_t& size) {
319-
MsgPack::map_size_t sz;
320-
unpacker.deserialize(sz);
321-
322-
size = 0;
323-
for (size_t i=0; i<sz.size(); i++){
324-
if (unpackObject(unpacker) && unpackObject(unpacker)){ // must unpack key&value
325-
size++;
326-
} else {
327-
return false;
328-
}
329-
}
330-
331-
return true;
332-
333-
}
334-
335-
bool unpackObject(MsgPack::Unpacker& unpacker){
336-
337-
if (unpacker.isNil()){
338-
static MsgPack::object::nil_t nil;
339-
return unpacker.deserialize(nil);
340-
}
341-
if (unpacker.isBool()){
342-
static bool b;
343-
return unpacker.deserialize(b);
344-
}
345-
if (unpacker.isUInt() || unpacker.isInt()){
346-
static int integer;
347-
return unpacker.deserialize(integer);
348-
}
349-
if (unpacker.isFloat32()){
350-
static float num32;
351-
return unpacker.deserialize(num32);
352-
}
353-
if (unpacker.isFloat64()){
354-
static double num64;
355-
return unpacker.deserialize(num64);
356-
}
357-
if (unpacker.isStr()){
358-
static MsgPack::str_t string;
359-
return unpacker.deserialize(string);
360-
}
361-
if (unpacker.isBin()){
362-
static MsgPack::bin_t<uint8_t> bytes;
363-
return unpacker.deserialize(bytes);
364-
}
365-
if (unpacker.isArray()){
366-
static size_t arr_sz;
367-
return unpackArray(unpacker, arr_sz);
368-
}
369-
if (unpacker.isMap()){
370-
static size_t map_sz;
371-
return unpackMap(unpacker, map_sz);
372-
}
373-
if (unpacker.isFixExt() || unpacker.isExt()){
374-
static MsgPack::object::ext e;
375-
return unpacker.deserialize(e);
376-
}
377-
if (unpacker.isTimestamp()){
378-
static MsgPack::object::timespec t;
379-
return unpacker.deserialize(t);
380-
}
381-
382-
return false;
383-
}
384-
385-
386298
};
387299

388300
#endif

0 commit comments

Comments
 (0)