Skip to content

Commit 2a077f6

Browse files
implementing decoder interface
1 parent a7716ad commit 2a077f6

File tree

2 files changed

+224
-0
lines changed

2 files changed

+224
-0
lines changed

src/cbor/CborDecoder.cpp

Lines changed: 94 additions & 0 deletions
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 == msg->id) {
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

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

0 commit comments

Comments
 (0)