Skip to content

Commit bd546c9

Browse files
implementing decoder interface
1 parent 66db68f commit bd546c9

File tree

2 files changed

+227
-0
lines changed

2 files changed

+227
-0
lines changed

src/cbor/CborDecoder.cpp

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
This file is part of the Arduino_CloudUtils library.
3+
4+
Copyright (c) 2024 Arduino SA
5+
6+
This Source Code Form is subject to the terms of the Mozilla Public
7+
License, v. 2.0. If a copy of the MPL was not distributed with this
8+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
#include "CborDecoder.h"
11+
12+
Decoder::Status CBORMessageDecoderSingleton::decode(Message* msg, const uint8_t* const buf, size_t &len) { // TODO do we need to propagate the maximum length?
13+
// prepare cbor structure
14+
CborValue iter;
15+
CborTag tag;
16+
CborParser parser;
17+
18+
if (cbor_parser_init(buf, len, 0, &parser, &iter) != CborNoError) {
19+
return Decoder::Status::Error;
20+
}
21+
22+
if (iter.type != CborTagType) {
23+
return Decoder::Status::Error;
24+
}
25+
26+
if (cbor_value_get_tag(&iter, &tag) != CborNoError) {
27+
return Decoder::Status::Error;
28+
}
29+
30+
if (cbor_value_advance(&iter) != CborNoError) {
31+
return Decoder::Status::Error;
32+
}
33+
34+
auto decoder_it = decoders.begin();
35+
36+
for(; decoder_it != decoders.end(); decoder_it++) {
37+
if(decoder_it->first == tag) {
38+
break;
39+
}
40+
}
41+
42+
// check if message.id exists on the decoders list or return error
43+
if(decoder_it == decoders.end()) {
44+
return Decoder::Status::Error;
45+
}
46+
47+
// encode the message
48+
if(decoder_it->second->_decode(&iter, msg) == Decoder::Status::Error) {
49+
return Decoder::Status::Error;
50+
}
51+
52+
return Decoder::Status::Complete;
53+
}
54+
55+
CBORMessageDecoderSingleton& CBORMessageDecoderSingleton::getInstance() {
56+
static CBORMessageDecoderSingleton singleton;
57+
58+
return singleton;
59+
}
60+
61+
void CBORMessageDecoderSingleton::append(CBORTag tag, CBORMessageDecoderInterface* decoder) {
62+
auto decoder_it = decoders.begin();
63+
64+
for(; decoder_it != decoders.end(); decoder_it++) {
65+
if(decoder_it->first == tag) {
66+
return;
67+
}
68+
}
69+
70+
decoders.push_back(
71+
std::make_pair(tag, decoder)
72+
);
73+
}
74+
75+
CBORMessageDecoderInterface::CBORMessageDecoderInterface(const CBORTag tag, const MessageId id)
76+
: tag(tag), id(id) {
77+
// call singleton/global variable and insert this decoder
78+
CBORMessageDecoderSingleton::getInstance().append(tag, this);
79+
}
80+
81+
Decoder::Status CBORMessageDecoderInterface::_decode(CborValue* iter, Message *msg) {
82+
CborValue array_iter;
83+
msg->id = this->id;
84+
85+
if (cbor_value_get_type(iter) != CborArrayType) {
86+
return Decoder::Status::Error;
87+
}
88+
89+
if (cbor_value_enter_container(iter, &array_iter) != CborNoError) {
90+
return Decoder::Status::Error;
91+
}
92+
93+
return decode(&array_iter, msg);
94+
}

src/cbor/CborDecoder.h

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
This file is part of the Arduino_CloudUtils library.
3+
4+
Copyright (c) 2024 Arduino SA
5+
6+
This Source Code Form is subject to the terms of the Mozilla Public
7+
License, v. 2.0. If a copy of the MPL was not distributed with this
8+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
#pragma once
11+
12+
#include <vector>
13+
#include "../interfaces/Decoder.h"
14+
#include "CBOR.h"
15+
#include "../interfaces/message.h"
16+
#include "./tinycbor/cbor-lib.h"
17+
18+
// forward declaration
19+
class CBORMessageDecoderSingleton;
20+
21+
/*
22+
* This library collects the interfaces used to decode Messages. Messages are C structs
23+
* that are identified by a uint32 id after which they can contain anything.
24+
* The objective of this library is to be modular and extensible in other libraries.
25+
*
26+
* In order to do so one have to extend the class `CBORMessageDecoderInterface`,
27+
* provide the associated CBORTag and MessageId and provide a way to decode the message
28+
* specific data. MessageId must be univocal across all DecoderInterfaces instantiated.
29+
* The class implemented must be instantiated somewhere (using extern may be helpful)
30+
* and that is enough to have it included in the decode process.
31+
*
32+
* In order to decode a message one can instantiate `CBORMessageDecoder` and
33+
* call the decode function.
34+
*/
35+
36+
/**
37+
* CBORMessageDecoderInterface class is an abstract class one has to implement
38+
* in order to provide the instructions needed to decode a buffer contasining
39+
* a message specific data.
40+
*/
41+
class CBORMessageDecoderInterface {
42+
public:
43+
44+
/**
45+
* Constructor that initializes the CBORMessageDecoderInterface by providing the associated
46+
* CBORTag and MessageId. The constructor also appends the object into CBORMessageDecoderSingleton
47+
* allowing it to be used in CBORMessageDecoderSingleton::decode
48+
*
49+
* @param tag the cbor tag the message is associated with
50+
* @param id the message id the message is associated with
51+
*/
52+
CBORMessageDecoderInterface(const CBORTag tag, const MessageId id);
53+
virtual ~CBORMessageDecoderInterface() {}
54+
55+
protected:
56+
57+
/**
58+
* Abstract decode function one must implement to decode the Message meaningful
59+
* information present into the provided buffer
60+
*
61+
* @param iter tinycbor iterator to the buffer provided to CBORMessageDecoderSingleton::decode
62+
* @param msg The message to which data must be applied to. Casting may be needed
63+
*/
64+
virtual Decoder::Status decode(CborValue* iter, Message *msg) = 0;
65+
66+
private:
67+
const CBORTag tag;
68+
const MessageId id;
69+
70+
friend CBORMessageDecoderSingleton;
71+
72+
/**
73+
* Decode wrapper function that opens the cbor array and calls the abstract decode function
74+
*
75+
* @param iter tinycbor iterator to the buffer provided to CBORMessageDecoderSingleton::decode
76+
* @param msg The message to which data must be applied to. Casting may be needed
77+
*/
78+
Decoder::Status _decode(CborValue* iter, Message *msg);
79+
};
80+
81+
/**
82+
* This class is a singleton. It collects CBORMessageDecoderInterfaces implementations to decode
83+
* all possible CBOR encoded messages
84+
*/
85+
class CBORMessageDecoderSingleton: public Decoder {
86+
public:
87+
/**
88+
* Get the singleton instance
89+
*/
90+
static CBORMessageDecoderSingleton& getInstance();
91+
92+
/**
93+
* Add a new decoder to the singleton instance associating it to the provided cbor tag
94+
*
95+
* @param tag the tag to which we associate the decoder
96+
* @param decoder the instance of decoder to append
97+
*/
98+
void append(CBORTag tag, CBORMessageDecoderInterface* decoder);
99+
100+
/**
101+
* Decode a buffer and put the contents into a message. The message should be big enough
102+
* to accommodate the content of the buffer.
103+
*
104+
* @param[out] msg A struct that embeds struct Message onto which the content of buf is copied
105+
* @param[in] buf The input buffer containing a cbor encoded message
106+
* @param[in out] len The length of the buffer
107+
*/
108+
Decoder::Status decode(Message* msg, const uint8_t* const buf, size_t &len);
109+
private:
110+
CBORMessageDecoderSingleton() {}
111+
112+
std::vector<std::pair<CBORTag, CBORMessageDecoderInterface*>> decoders;
113+
};
114+
115+
/**
116+
* In order to decode a message one can instantiate `CBORMessageDecoder` and
117+
* call the decode function. In the future this class will contain decode session related
118+
* information, in order to allow streaming decoding
119+
*/
120+
class CBORMessageDecoder: public Decoder {
121+
public:
122+
/**
123+
* Decode a buffer and put the contents into a message. The message should be big enough
124+
* to accommodate the content of the buffer.
125+
*
126+
* @param[out] msg A struct that embeds struct Message onto which the content of buf is copied
127+
* @param[in] buf The input buffer containing a cbor encoded message
128+
* @param[in out] len The length of the buffer
129+
*/
130+
inline Decoder::Status decode(Message* msg, const uint8_t* const buf, size_t &len) {
131+
return CBORMessageDecoderSingleton::getInstance().decode(msg, buf, len);
132+
}
133+
};

0 commit comments

Comments
 (0)