Skip to content

Commit 880b3e4

Browse files
committed
feat: decoder attempt linear buf TBT
1 parent d750f99 commit 880b3e4

File tree

6 files changed

+216
-30
lines changed

6 files changed

+216
-30
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include <Arduino_RPClite.h>
2+
3+
void blink_before(){
4+
digitalWrite(LED_BUILTIN, HIGH);
5+
delay(200);
6+
digitalWrite(LED_BUILTIN, LOW);
7+
delay(200);
8+
digitalWrite(LED_BUILTIN, HIGH);
9+
delay(200);
10+
digitalWrite(LED_BUILTIN, LOW);
11+
delay(200);
12+
digitalWrite(LED_BUILTIN, HIGH);
13+
delay(200);
14+
digitalWrite(LED_BUILTIN, LOW);
15+
delay(200);
16+
}
17+
18+
MsgPack::Packer packer;
19+
MsgPack::Unpacker unpacker;
20+
21+
void setup() {
22+
Serial.begin(9600);
23+
}
24+
25+
void loop() {
26+
27+
blink_before();
28+
MsgPack::arr_size_t req_sz(4);
29+
MsgPack::arr_size_t par_sz(2);
30+
packer.serialize(req_sz, 0, 1, "method", par_sz, 1.0, 2.0);
31+
32+
DummyTransport dummy_transport(packer.data(), packer.size());
33+
RpcDecoder<> decoder(dummy_transport);
34+
35+
while (!decoder.packet_available()){
36+
Serial.println("Packet not ready");
37+
decoder.advance();
38+
}
39+
40+
Serial.println("packet ready");
41+
42+
}

src/Arduino_RPClite.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "server.h"
1616
#include "wrapper.h"
1717
#include "dispatcher.h"
18+
#include "decoder.h"
1819

1920
#include "DummyTransport.h"
2021
#include "SerialTransport.h"

src/DummyTransport.h

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,55 @@
22
// Created by lucio on 4/8/25.
33
//
44

5-
#ifndef DUMMYTRANSPORT_H
6-
#define DUMMYTRANSPORT_H
5+
#ifndef DUMMY_TRANSPORT_H
6+
#define DUMMY_TRANSPORT_H
77
#include "transport.h"
88

9-
class DummyTransport : public ITransport {
10-
std::vector<uint8_t> inbuf, outbuf;
11-
12-
public:
13-
size_t write(const uint8_t* data, size_t size) override {
14-
outbuf.insert(outbuf.end(), data, data + size);
15-
return size;
16-
}
17-
18-
size_t read(uint8_t* buffer, size_t size) override {
19-
if (inbuf.size() < size) return 0;
20-
std::copy(inbuf.begin(), inbuf.begin() + size, buffer);
21-
inbuf.erase(inbuf.begin(), inbuf.begin() + size);
22-
return size;
23-
}
24-
25-
size_t read_byte(uint8_t& r) override {
26-
uint8_t b[1];
27-
if (read(b, 1) != 1){
28-
return 0;
29-
};
30-
r = b[0];
31-
return 1;
32-
}
33-
34-
void push_data(const std::vector<uint8_t>& data) { inbuf.insert(inbuf.end(), data.begin(), data.end()); }
35-
const std::vector<uint8_t>& get_output() const { return outbuf; }
9+
class DummyTransport: public ITransport {
10+
11+
const uint8_t* _dummy_buf;
12+
size_t _dummy_buf_size = 0;
13+
14+
public:
15+
16+
DummyTransport(const uint8_t* buf, size_t size): _dummy_buf(buf), _dummy_buf_size(size){}
17+
18+
void begin(){}
19+
20+
bool available() override {
21+
return _dummy_buf_size > 0;
22+
}
23+
24+
size_t write(const uint8_t* data, size_t size) override {
25+
// Mock write
26+
return size;
27+
}
28+
29+
size_t read(uint8_t* buffer, size_t size) override {
30+
if (_dummy_buf_size == 0) return 0;
31+
32+
size_t r_size = 0;
33+
for (size_t i = 0; i < _dummy_buf_size; i++){
34+
buffer[r_size] = _dummy_buf[i];
35+
delay(1);
36+
r_size++;
37+
if (r_size == size) break;
38+
}
39+
40+
_dummy_buf_size = _dummy_buf_size - r_size;
41+
return r_size;
42+
43+
}
44+
45+
size_t read_byte(uint8_t& r) override {
46+
uint8_t b[1];
47+
if (read(b, 1) != 1){
48+
return 0;
49+
};
50+
r = b[0];
51+
return 1;
52+
}
53+
3654
};
3755

38-
#endif //DUMMYTRANSPORT_H
56+
#endif //SERIALTRANSPORT_H

src/SerialTransport.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ class SerialTransport: public ITransport {
1616

1717
void begin(){}
1818

19+
bool available() override {
20+
return _stream->available();
21+
}
22+
1923
size_t write(const uint8_t* data, size_t size) override {
2024

2125
for (size_t i=0; i<size; i++){

src/decoder.h

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
#ifndef RPCLITE_DECODER_H
2+
#define RPCLITE_DECODER_H
3+
#include "transport.h"
4+
#include "MsgPack.h"
5+
6+
7+
#define CALL_MSG 0
8+
#define RESP_MSG 1
9+
#define NOTIFY_MSG 2
10+
11+
#define MAX_BUFFER_SIZE 1024
12+
#define CHUNK_SIZE 32
13+
14+
template<size_t BufferSize = MAX_BUFFER_SIZE>
15+
class RpcDecoder {
16+
17+
public:
18+
RpcDecoder(ITransport& transport) : _transport(transport) {}
19+
20+
21+
void process(){
22+
if (advance()) return parse_packet();
23+
}
24+
25+
// Fill the raw buffer to its capacity
26+
bool advance() {
27+
28+
uint8_t temp_buf[CHUNK_SIZE];
29+
30+
if (_transport.available() && !buffer_full()){
31+
int bytes_read = _transport.read(temp_buf, CHUNK_SIZE);
32+
if (bytes_read <= 0) return false;
33+
34+
for (int i = 0; i < bytes_read; ++i) {
35+
_raw_buffer[_bytes_stored] = temp_buf[i];
36+
_bytes_stored++;
37+
while (buffer_full()){
38+
delay(1);
39+
}
40+
}
41+
}
42+
return true;
43+
}
44+
45+
// Tries to parse the first packet only
46+
void parse_packet(){
47+
48+
// Nop in case 1st packet is ready... waiting to deliver
49+
if (_packet_ready){return;}
50+
51+
size_t bytes_checked = 0;
52+
53+
MsgPack::Unpacker unpacker;
54+
while (bytes_checked < _bytes_stored) {
55+
if (unpacker.feed(_raw_buffer, bytes_checked)) {
56+
_packet_ready = true;
57+
_packet_size = bytes_checked + 1;
58+
return;
59+
} else {
60+
bytes_checked++;
61+
}
62+
}
63+
64+
}
65+
66+
// Check if a packet is available
67+
bool packet_available() const { return _packet_ready; }
68+
69+
// Get the oldest packet (returns false if no packet available)
70+
bool get_next_packet(MsgPack::Unpacker& unpacker) {
71+
if (!_packet_ready) return false;
72+
return unpacker.feed(_raw_buffer, _packet_size);
73+
}
74+
75+
// Try to recover buffer error condition
76+
void recover() {
77+
// ensure parsing was attempted
78+
parse_packet();
79+
if (buffer_full() && !_packet_ready){
80+
flush_buffer();
81+
}
82+
}
83+
84+
// Discard the oldest packet. Returns the number of freed_bytes
85+
size_t pop_packet() {
86+
87+
if (!_packet_ready) return false;
88+
89+
const size_t remaining_bytes = _bytes_stored - _packet_size;
90+
91+
// Shift remaining data forward (manual memmove for compatibility)
92+
for (size_t i = 0; i < remaining_bytes; i++) {
93+
_raw_buffer[i] = _raw_buffer[_packet_size + i];
94+
}
95+
96+
_bytes_stored = remaining_bytes;
97+
_packet_ready = false;
98+
_packet_size = 0; // Reset packet state
99+
100+
return _packet_size;
101+
}
102+
103+
private:
104+
ITransport& _transport;
105+
uint8_t _raw_buffer[BufferSize];
106+
size_t _bytes_stored = 0;
107+
108+
bool _packet_ready = false;
109+
size_t _packet_size = 0;
110+
111+
inline bool buffer_full() const { return _bytes_stored == BufferSize; }
112+
inline bool buffer_empy() const { return _bytes_stored == 0;}
113+
inline void flush_buffer() {
114+
uint8_t* discard_buf;
115+
while (_transport.read(discard_buf, CHUNK_SIZE) > 0);
116+
_bytes_stored = 0;
117+
}
118+
};
119+
120+
#endif

src/transport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class ITransport {
1414
virtual size_t write(const uint8_t* data, size_t size) = 0;
1515
virtual size_t read(uint8_t* buffer, size_t size) = 0;
1616
virtual size_t read_byte(uint8_t& r) = 0;
17+
virtual bool available() = 0;
1718
//virtual ~ITransport() = default;
1819
};
1920

0 commit comments

Comments
 (0)