Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
.idea
.vscode
.vscode

CMakeLists.txt
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"url": "https://github.com/eigen-value",
"maintainer": true
},
"version": "0.1.2",
"version": "0.1.3",
"license": "MPL2.0",
"frameworks": "arduino",
"platforms": "*",
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=Arduino_RPClite
version=0.1.2
version=0.1.3
author=Arduino, Lucio Rossi (eigen-value)
maintainer=Arduino, Lucio Rossi (eigen-value)
sentence=A MessagePack RPC library for Arduino
Expand Down
3 changes: 3 additions & 0 deletions src/Arduino_RPClite.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

#include "Arduino.h"

#define DECODER_BUFFER_SIZE 1024
#define RPCLITE_MAX_TRANSPORTS 3

//#define HANDLE_RPC_ERRORS
#include "transport.h"
#include "client.h"
Expand Down
8 changes: 3 additions & 5 deletions src/SerialTransport.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,15 @@
#define SERIALTRANSPORT_H
#include "transport.h"

class SerialTransport: public ITransport {
class SerialTransport final : public ITransport {

Stream* _stream;

public:

SerialTransport(Stream* stream): _stream(stream){}
explicit SerialTransport(Stream* stream): _stream(stream){}

SerialTransport(Stream& stream): _stream(&stream){}

void begin(){}
explicit SerialTransport(Stream& stream): _stream(&stream){}

bool available() override {
return _stream->available();
Expand Down
17 changes: 5 additions & 12 deletions src/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,24 @@
#define RPCLITE_CLIENT_H
#include "error.h"
#include "decoder_manager.h"
#include "SerialTransport.h"


class RPCClient {
RpcDecoder<>* decoder = nullptr;
RpcDecoder<>* decoder;

public:
RpcError lastError;

RPCClient(ITransport& t) : decoder(&RpcDecoderManager<>::getDecoder(t)) {}

// This constructor was removed because it leads to decoder duplication
// RPCClient(Stream& stream) {
// ITransport* transport = (ITransport*) new SerialTransport(stream);
// decoder = &RpcDecoderManager<>::getDecoder(*transport);
// }
explicit RPCClient(ITransport& t) : decoder(&RpcDecoderManager<>::getDecoder(t)) {}

template<typename... Args>
void notify(const MsgPack::str_t method, Args&&... args) {
void notify(const MsgPack::str_t& method, Args&&... args) {
uint32_t _id;
decoder->send_call(NOTIFY_MSG, method, _id, std::forward<Args>(args)...);
}

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

uint32_t msg_id_wait;

Expand All @@ -57,7 +50,7 @@ class RPCClient {
}

template<typename... Args>
bool send_rpc(const MsgPack::str_t method, uint32_t& wait_id, Args&&... args) {
bool send_rpc(const MsgPack::str_t& method, uint32_t& wait_id, Args&&... args) {
uint32_t msg_id;
if (decoder->send_call(CALL_MSG, method, msg_id, std::forward<Args>(args)...)) {
wait_id = msg_id;
Expand Down
36 changes: 17 additions & 19 deletions src/decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,16 @@
using namespace RpcUtils::detail;

#define MIN_RPC_BYTES 4

#define MAX_BUFFER_SIZE 1024
#define CHUNK_SIZE 32

template<size_t BufferSize = MAX_BUFFER_SIZE>
template<size_t BufferSize = DECODER_BUFFER_SIZE>
class RpcDecoder {

public:
RpcDecoder(ITransport& transport) : _transport(transport) {}
explicit RpcDecoder(ITransport& transport) : _transport(&transport) {}

template<typename... Args>
bool send_call(const int call_type, const MsgPack::str_t method, uint32_t& msg_id, Args&&... args) {
bool send_call(const int call_type, const MsgPack::str_t& method, uint32_t& msg_id, Args&&... args) {

if (call_type!=CALL_MSG && call_type!=NOTIFY_MSG) return false;

Expand Down Expand Up @@ -89,7 +87,7 @@ class RpcDecoder {

}

bool send_response(const MsgPack::Packer& packer) {
bool send_response(const MsgPack::Packer& packer) const {
return send(reinterpret_cast<const uint8_t*>(packer.data()), packer.size()) == packer.size();
}

Expand All @@ -111,7 +109,6 @@ class RpcDecoder {
};

int msg_type;
uint32_t msg_id;
MsgPack::str_t method;
MsgPack::arr_size_t req_size;

Expand All @@ -122,6 +119,7 @@ class RpcDecoder {
}

if (msg_type == CALL_MSG && req_size.size() == REQUEST_SIZE) {
uint32_t msg_id;
if (!unpacker.deserialize(msg_id, method)) {
consume(_packet_size);
reset_packet();
Expand Down Expand Up @@ -160,8 +158,8 @@ class RpcDecoder {
// Fill the raw buffer to its capacity
void advance() {

if (_transport.available() && !buffer_full()) {
size_t bytes_read = _transport.read(_raw_buffer + _bytes_stored, BufferSize - _bytes_stored);
if (_transport->available() && !buffer_full()) {
size_t bytes_read = _transport->read(_raw_buffer + _bytes_stored, BufferSize - _bytes_stored);
_bytes_stored += bytes_read;
}

Expand Down Expand Up @@ -204,35 +202,35 @@ class RpcDecoder {

}

inline bool packet_incoming() const { return _packet_size >= MIN_RPC_BYTES; }
bool packet_incoming() const { return _packet_size >= MIN_RPC_BYTES; }

inline int packet_type() const { return _packet_type; }
int packet_type() const { return _packet_type; }

size_t get_packet_size() const { return _packet_size;}

inline size_t size() const {return _bytes_stored;}
size_t size() const {return _bytes_stored;}

friend class DecoderTester;

private:
ITransport& _transport;
uint8_t _raw_buffer[BufferSize];
ITransport* _transport;
uint8_t _raw_buffer[BufferSize]{};
size_t _bytes_stored = 0;
int _packet_type = NO_MSG;
size_t _packet_size = 0;
uint32_t _msg_id = 0;

inline bool buffer_full() const { return _bytes_stored == BufferSize; }
bool buffer_full() const { return _bytes_stored == BufferSize; }

inline bool buffer_empty() const { return _bytes_stored == 0;}
bool buffer_empty() const { return _bytes_stored == 0;}

// This is a blocking send, under the assumption _transport.write will always succeed eventually
inline size_t send(const uint8_t* data, const size_t size) {
// This is a blocking send, under the assumption _transport->write will always succeed eventually
size_t send(const uint8_t* data, const size_t size) const {

size_t offset = 0;

while (offset < size) {
size_t bytes_written = _transport.write(data + offset, size - offset);
size_t bytes_written = _transport->write(data + offset, size - offset);
offset += bytes_written;
}

Expand Down
5 changes: 1 addition & 4 deletions src/decoder_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,13 @@
#ifndef RPCLITE_DECODER_MANAGER_H
#define RPCLITE_DECODER_MANAGER_H

#define RPCLITE_MAX_TRANSPORTS 3

#include <array>
#include "transport.h"
#include "decoder.h"

template<size_t MaxTransports = RPCLITE_MAX_TRANSPORTS>
class RpcDecoderManager {
public:
// todo parametrize so the RpcDecoder returned has a user defined buffer size ?
static RpcDecoder<>& getDecoder(ITransport& transport) {
for (auto& entry : decoders_) {
if (entry.transport == &transport) {
Expand Down Expand Up @@ -51,7 +48,7 @@ class RpcDecoderManager {
struct DecoderStorage {
union {
RpcDecoder<> instance;
uint8_t raw[sizeof(RpcDecoder<>)];
uint8_t raw[sizeof(RpcDecoder<>)]{};
};

DecoderStorage() {}
Expand Down
9 changes: 6 additions & 3 deletions src/dispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ struct DispatchEntry {
template<size_t N>
class RpcFunctionDispatcher {
public:

RpcFunctionDispatcher() = default;

template<typename F>
bool bind(MsgPack::str_t name, F&& f, MsgPack::str_t tag="") {
if (_count >= N) return false;
Expand All @@ -34,7 +37,7 @@ class RpcFunctionDispatcher {
return true;
}

bool isBound(MsgPack::str_t name) const {
bool isBound(const MsgPack::str_t& name) const {
for (size_t i = 0; i < _count; ++i) {
if (_entries[i].name == name) {
return true;
Expand All @@ -43,7 +46,7 @@ class RpcFunctionDispatcher {
return false;
}

bool hasTag(MsgPack::str_t name, MsgPack::str_t tag) const {
bool hasTag(const MsgPack::str_t& name, MsgPack::str_t& tag) const {
for (size_t i = 0; i < _count; ++i) {
if (_entries[i].name == name && _entries[i].tag == tag) {
return true;
Expand All @@ -52,7 +55,7 @@ class RpcFunctionDispatcher {
return false;
}

bool call(MsgPack::str_t name, MsgPack::Unpacker& unpacker, MsgPack::Packer& packer) {
bool call(const MsgPack::str_t& name, MsgPack::Unpacker& unpacker, MsgPack::Packer& packer) {
for (size_t i = 0; i < _count; ++i) {
if (_entries[i].name == name) {
return (*_entries[i].fn)(unpacker, packer);
Expand Down
6 changes: 4 additions & 2 deletions src/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#ifndef RPCLITE_ERROR_H
#define RPCLITE_ERROR_H

#include <utility>

#include "MsgPack.h"

#define NO_ERR 0x00
Expand All @@ -29,8 +31,8 @@ struct RpcError {
traceback = "";
}

RpcError(int c, const MsgPack::str_t& tb)
: code(c), traceback(tb) {}
RpcError(const int c, MsgPack::str_t tb)
: code(c), traceback(std::move(tb)) {}

MSGPACK_DEFINE(code, traceback); // -> [code, traceback]
};
Expand Down
17 changes: 4 additions & 13 deletions src/request.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#ifndef RPCLITE_REQUEST_H
#define RPCLITE_REQUEST_H

#define DEFAULT_RPC_BUFFER_SIZE 256
#define DEFAULT_RPC_BUFFER_SIZE (DECODER_BUFFER_SIZE / 4)


#include "rpclite_utils.h"
Expand All @@ -21,24 +21,15 @@ template<size_t BufferSize = DEFAULT_RPC_BUFFER_SIZE>
class RPCRequest {

public:
uint8_t buffer[BufferSize];
uint8_t buffer[BufferSize]{};
size_t size = 0;
int type = NO_MSG;
uint32_t msg_id = 0;
MsgPack::str_t method;
MsgPack::Packer packer;
MsgPack::Unpacker unpacker;

// void print(){

// Serial.print("internal buffer ");
// for (size_t i=0; i<size; i++){
// Serial.print(buffer[i], HEX);
// }
// Serial.println("");
// }

size_t get_buffer_size() const {
static size_t get_buffer_size() {
return BufferSize;
}

Expand Down Expand Up @@ -94,4 +85,4 @@ class RPCRequest {

};

#endif RPCLITE_REQUEST_H
#endif //RPCLITE_REQUEST_H
26 changes: 14 additions & 12 deletions src/rpclite_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
namespace RpcUtils {
namespace detail {

#define WRONG_MSG -2
#define NO_MSG -1
#define TYPE_ERROR (-1)
#define WRONG_MSG (-2)
#define NO_MSG (-1)
#define CALL_MSG 0
#define RESP_MSG 1
#define NOTIFY_MSG 2
Expand Down Expand Up @@ -48,12 +49,12 @@ inline bool unpackTypedArray(MsgPack::Unpacker& unpacker, size_t& size, int& typ

size = 0;
for (size_t i=0; i<sz.size(); i++){
if ((i==0)) {
if (i==0) {
if (unpacker.isInt() || unpacker.isUInt()) {
unpacker.deserialize(rpc_type);
type = rpc_type;
size++;
continue; // First element must be the type
continue; // the First element must be the type
} else {
type = WRONG_MSG; // Not a valid type
}
Expand Down Expand Up @@ -165,10 +166,10 @@ inline bool unpackObject(MsgPack::Unpacker& unpacker){
}

template<typename T>
inline bool deserialize_single(MsgPack::Unpacker& unpacker, T& value) {
if (!unpacker.unpackable(value)) return false;
int deserialize_single(MsgPack::Unpacker& unpacker, T& value) {
if (!unpacker.unpackable(value)) return TYPE_ERROR;
unpacker.deserialize(value);
return true;
return 0;
}


Expand All @@ -177,21 +178,22 @@ inline bool deserialize_single(MsgPack::Unpacker& unpacker, T& value) {
/////////////////////////////

template<std::size_t I = 0, typename... Ts>
inline typename std::enable_if<I == sizeof...(Ts), bool>::type
typename std::enable_if<I == sizeof...(Ts), int>::type
deserialize_tuple(MsgPack::Unpacker&, std::tuple<Ts...>&) {
return true;
return 0;
}

template<std::size_t I = 0, typename... Ts>
inline typename std::enable_if<I < sizeof...(Ts), bool>::type
typename std::enable_if<I < sizeof...(Ts), int>::type
deserialize_tuple(MsgPack::Unpacker& unpacker, std::tuple<Ts...>& out) {
if (!deserialize_single(unpacker, std::get<I>(out))) return false;
const int res = deserialize_single(unpacker, std::get<I>(out));
if (res==TYPE_ERROR) return TYPE_ERROR-I;
return deserialize_tuple<I + 1>(unpacker, out);
}

// Helper to invoke a function with a tuple of arguments
template<typename F, typename Tuple, std::size_t... I>
inline auto invoke_with_tuple(F&& f, Tuple&& t, arx::stdx::index_sequence<I...>)
auto invoke_with_tuple(F&& f, Tuple&& t, arx::stdx::index_sequence<I...>)
-> decltype(f(std::get<I>(std::forward<Tuple>(t))...)) {
return f(std::get<I>(std::forward<Tuple>(t))...);
}
Expand Down
Loading