Skip to content

Commit d94fb00

Browse files
committed
Squash #2 and fixup String and types handling
TOTALLY UNTESTED
1 parent 71ed28e commit d94fb00

File tree

2 files changed

+177
-130
lines changed

2 files changed

+177
-130
lines changed

ArduinoCloudThing.cpp

+130-99
Original file line numberDiff line numberDiff line change
@@ -47,53 +47,59 @@ void ArduinoCloudThing::begin() {
4747
addPropertyReal(status, "status").readOnly();
4848
}
4949

50-
int ArduinoCloudThing::publish(CborArray& object, uint8_t* data, size_t size) {
51-
52-
ssize_t len = object.encode(data, size);
53-
54-
#ifdef TESTING_PROTOCOL
55-
decode(data, len);
56-
#endif
57-
58-
for (int i = 0; i < list.size(); i++) {
59-
ArduinoCloudPropertyGeneric *p = list.get(i);
60-
p->updateShadow();
61-
}
62-
63-
return len;
64-
}
65-
6650
int ArduinoCloudThing::poll(uint8_t* data, size_t size) {
6751

6852
// check if backing storage and cloud has diverged
6953
int diff = 0;
7054

7155
diff = checkNewData();
7256
if (diff > 0) {
73-
CborBuffer buffer(1024);
74-
CborArray object = CborArray(buffer);
75-
compress(object, buffer);
76-
diff = publish(object, data, size);
57+
CborError err;
58+
CborEncoder encoder, arrayEncoder;
59+
cbor_encoder_init(&encoder, data, size, 0);
60+
// create a cbor array containing the property that should be updated.
61+
err = cbor_encoder_create_array(&encoder, &arrayEncoder, CborIndefiniteLength);
62+
if (err) {
63+
Serial.println(cbor_error_string(err));
64+
return -1;
65+
}
66+
for (int i = 0; i < list.size(); i++) {
67+
ArduinoCloudPropertyGeneric *p = list.get(i);
68+
// If a property should be updated and has read permission from the Cloud point of view
69+
if (p->shouldBeUpdated() && p->canRead()) {
70+
// create a cbor object for the property and automatically add it into array
71+
p->append(&arrayEncoder);
72+
}
73+
}
74+
75+
err = cbor_encoder_close_container(&encoder, &arrayEncoder);
76+
// update properties shadow values, in order to check if variable has changed since last publish
77+
78+
for (int i = 0; i < list.size(); i++) {
79+
ArduinoCloudPropertyGeneric *p = list.get(i);
80+
p->updateShadow();
81+
}
82+
// return the number of byte of the CBOR encoded array
83+
return cbor_encoder_get_buffer_size(&encoder, data);
7784
}
7885

7986
#if defined(DEBUG_MEMORY) && defined(ARDUINO_ARCH_SAMD)
8087
PrintFreeRam();
8188
#endif
82-
89+
// If nothing has to be sent, return diff, that is 0 in this case
8390
return diff;
8491
}
8592

86-
void ArduinoCloudThing::compress(CborArray& object, CborBuffer& buffer) {
87-
93+
// It return the index of the property, inside the local array, with the name passed as parameter. (-1 if it does not exist.)
94+
int ArduinoCloudThing::findPropertyByName(String &name) {
8895
for (int i = 0; i < list.size(); i++) {
8996
ArduinoCloudPropertyGeneric *p = list.get(i);
90-
if (p->shouldBeUpdated() && p->canRead()) {
91-
CborObject child = CborObject(buffer);
92-
p->append(child);
93-
CborVariant variant = CborVariant(buffer, child);
94-
object.add(variant);
97+
// Check the property existance just comparing its name with existent ones
98+
if (p->getName() == name) {
99+
return i;
95100
}
96101
}
102+
return -1;
97103
}
98104

99105
int ArduinoCloudThing::checkNewData() {
@@ -144,88 +150,113 @@ ArduinoCloudPropertyGeneric& ArduinoCloudThing::addPropertyReal(float& property,
144150
return *(reinterpret_cast<ArduinoCloudPropertyGeneric*>(thing));
145151
}
146152

147-
void ArduinoCloudThing::decode(uint8_t * payload, size_t length) {
148-
CborBuffer buffer(200);
149-
CborVariant total = buffer.decode(payload, length);
153+
ArduinoCloudPropertyGeneric& ArduinoCloudThing::addPropertyReal(String& property, String name) {
154+
if (ArduinoCloudPropertyGeneric* p = exists(name)) {
155+
return *p;
156+
}
157+
ArduinoCloudProperty<String> *thing = new ArduinoCloudProperty<String>(property, name);
158+
list.add(thing);
159+
return *(reinterpret_cast<ArduinoCloudPropertyGeneric*>(thing));
160+
}
150161

151-
CborArray array = total.asArray();
162+
void ArduinoCloudThing::decode(uint8_t * payload, size_t length) {
163+
CborError err;
164+
CborParser parser;
165+
CborValue recursedMap, propValue, dataArray;
166+
int propId; String propType, propName;
167+
168+
err = cbor_parser_init(payload, length, 0, &parser, &dataArray);
169+
if (err) {
170+
return;
171+
}
152172

153-
for (int i=0; ;i++) {
154-
CborVariant variant = array.get(i);
173+
// parse cbor data only if a cbor array is received.
174+
if (dataArray.type != CborArrayType)
175+
return;
176+
177+
// main loop through the cbor array elements
178+
while (!cbor_value_at_end(&dataArray)) {
179+
// parse cbor object
180+
cbor_value_enter_container(&dataArray, &recursedMap);
181+
CborType type = cbor_value_get_type(&recursedMap);
182+
if (type != CborMapType) {
183+
// stop the decode when 1st item thai is not a cbor map is found.
184+
cbor_value_advance(&dataArray);
185+
continue;
186+
} else {
187+
188+
while (!cbor_value_at_end(&recursedMap)) {
189+
// if the current element is not a cbor object as expected, skip it and go ahead.
190+
if (cbor_value_get_type(&recursedMap) != CborMapType) {
191+
cbor_value_advance(&recursedMap);
192+
continue;
193+
}
155194

156-
if (!variant.isValid()) {
157-
break;
158-
}
195+
CborValue name;
196+
// chechk for the if the a property has a name, if yes Cbor value name will properly updated
197+
cbor_value_map_find_value(&recursedMap, "n", &name);
198+
// check if a property has a name, of string type, if not do nothin and skip curtrent property
199+
if (name.type != CborTextStringType) {
200+
cbor_value_advance(&recursedMap);
201+
continue;
202+
}
159203

204+
// get the property name from cbor map as char* string
205+
char *nameVal; size_t nameValSize;
206+
err = cbor_value_dup_text_string(&name, &nameVal, &nameValSize, NULL);
207+
if (err) {
208+
break; // couldn't get the value of the field
209+
}
210+
// get the name of the received property as String object
211+
propName = String(nameVal);
212+
// used to avoid memory leaks (cbor_value_dup_text_string automatically perform a malloc)
213+
free(nameVal);
214+
// Search for the index of the device property with that name
215+
propId = findPropertyByName(propName);
216+
// If property does not exist, skip it and do nothing.
217+
if (propId < 0) {
218+
cbor_value_advance(&recursedMap);
219+
continue;
220+
}
160221

161-
CborObject object = variant.asObject();
222+
ArduinoCloudPropertyGeneric* property = list.get(propId);
223+
// Check for the property type, write method internally check for the permission
162224

163-
String name = "";
164-
if (object.get("n").isValid()) {
165-
name = object.get("n").asString();
166-
// search for the property with the same name
167-
for (int idx = 0; idx < list.size(); idx++) {
168-
ArduinoCloudPropertyGeneric *p = list.get(idx);
169-
if (p->getName() == name) {
170-
currentListIndex = idx;
171-
break;
225+
if (propValue.type == CborDoubleType) {
226+
double val;
227+
// get the value of the property as a double
228+
cbor_value_get_double(&propValue, &val);
229+
reinterpret_cast<ArduinoCloudProperty<float>*>(property)->write((float)val);
172230
}
173-
if (idx == list.size()) {
174-
currentListIndex = -1;
231+
// if no key proper key was found, do nothing
232+
if (propValue.type == CborIntegerType) {
233+
int val;
234+
cbor_value_get_int(&propValue, &val);
235+
reinterpret_cast<ArduinoCloudProperty<int>*>(property)->write(val);
175236
}
176-
}
177-
}
178-
179-
if (object.get("t").isValid()) {
180-
int tag = object.get("t").asInteger();
181-
if (name != "") {
182-
list.get(currentListIndex)->setTag(tag);
183-
} else {
184-
for (int idx = 0; idx < list.size(); idx++) {
185-
ArduinoCloudPropertyGeneric *p = list.get(idx);
186-
if (p->getTag() == tag) {
187-
// if name == "" associate name and tag, otherwise set current list index
188-
currentListIndex = idx;
189-
break;
190-
}
191-
if (idx == list.size()) {
192-
Serial.println("Property not found, skipping");
193-
currentListIndex = -1;
237+
if (propValue.type == CborBooleanType) {
238+
bool val;
239+
cbor_value_get_boolean(&propValue, &val);
240+
reinterpret_cast<ArduinoCloudProperty<bool>*>(property)->write(val);
241+
}
242+
if (propValue.type == CborTextStringType) {
243+
char *val; size_t valSize;
244+
err = cbor_value_dup_text_string(&propValue, &val, &valSize, &propValue);
245+
// Char* string transformed into array
246+
reinterpret_cast<ArduinoCloudProperty<String>*>(property)->write(String((char*)val));
247+
free(val);
248+
}
249+
// If the property has been changed call its callback
250+
if (property->newData()) {
251+
if (property->callback != NULL) {
252+
property->callback();
194253
}
195254
}
255+
// Continue to scan the cbor map
256+
cbor_value_advance(&recursedMap);
196257
}
197258
}
198-
199-
if (object.get("i").isValid()) {
200-
int value_i = object.get("i").asInteger();
201-
reinterpret_cast<ArduinoCloudProperty<int>*>(list.get(currentListIndex))->write(value_i);
202-
}
203-
204-
if (object.get("b").isValid()) {
205-
bool value_b = object.get("b").asInteger();
206-
reinterpret_cast<ArduinoCloudProperty<bool>*>(list.get(currentListIndex))->write(value_b);
207-
}
208-
/*
209-
if (object.get("f").isValid()) {
210-
float value_f = object.get("f").asFloat();
211-
reinterpret_cast<ArduinoCloudProperty<bool>*>(list.get(currentListIndex))->write(value_f);
212-
}
213-
*/
214-
if (object.get("s").isValid()) {
215-
String value_s = object.get("s").asString();
216-
reinterpret_cast<ArduinoCloudProperty<String>*>(list.get(currentListIndex))->write(value_s);
217-
}
218-
219-
if (object.get("p").isValid()) {
220-
permissionType value_p = (permissionType)object.get("p").asInteger();
221-
list.get(currentListIndex)->setPermission(value_p);
222-
}
223-
224-
if (list.get(currentListIndex)->newData()) {
225-
// call onUpdate()
226-
if (list.get(currentListIndex)->callback != NULL) {
227-
list.get(currentListIndex)->callback();
228-
}
229-
}
259+
// Leave the current cbor object, and advance to the next one
260+
err = cbor_value_leave_container(&dataArray, &recursedMap);
230261
}
231262
}

0 commit comments

Comments
 (0)