Skip to content

Commit

Permalink
Squash #2 and fixup String and types handling
Browse files Browse the repository at this point in the history
TOTALLY UNTESTED
  • Loading branch information
facchinm committed Aug 21, 2018
1 parent 71ed28e commit d94fb00
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 130 deletions.
229 changes: 130 additions & 99 deletions ArduinoCloudThing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,53 +47,59 @@ void ArduinoCloudThing::begin() {
addPropertyReal(status, "status").readOnly();
}

int ArduinoCloudThing::publish(CborArray& object, uint8_t* data, size_t size) {

ssize_t len = object.encode(data, size);

#ifdef TESTING_PROTOCOL
decode(data, len);
#endif

for (int i = 0; i < list.size(); i++) {
ArduinoCloudPropertyGeneric *p = list.get(i);
p->updateShadow();
}

return len;
}

int ArduinoCloudThing::poll(uint8_t* data, size_t size) {

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

diff = checkNewData();
if (diff > 0) {
CborBuffer buffer(1024);
CborArray object = CborArray(buffer);
compress(object, buffer);
diff = publish(object, data, size);
CborError err;
CborEncoder encoder, arrayEncoder;
cbor_encoder_init(&encoder, data, size, 0);
// create a cbor array containing the property that should be updated.
err = cbor_encoder_create_array(&encoder, &arrayEncoder, CborIndefiniteLength);
if (err) {
Serial.println(cbor_error_string(err));
return -1;
}
for (int i = 0; i < list.size(); i++) {
ArduinoCloudPropertyGeneric *p = list.get(i);
// If a property should be updated and has read permission from the Cloud point of view
if (p->shouldBeUpdated() && p->canRead()) {
// create a cbor object for the property and automatically add it into array
p->append(&arrayEncoder);
}
}

err = cbor_encoder_close_container(&encoder, &arrayEncoder);
// update properties shadow values, in order to check if variable has changed since last publish

for (int i = 0; i < list.size(); i++) {
ArduinoCloudPropertyGeneric *p = list.get(i);
p->updateShadow();
}
// return the number of byte of the CBOR encoded array
return cbor_encoder_get_buffer_size(&encoder, data);
}

#if defined(DEBUG_MEMORY) && defined(ARDUINO_ARCH_SAMD)
PrintFreeRam();
#endif

// If nothing has to be sent, return diff, that is 0 in this case
return diff;
}

void ArduinoCloudThing::compress(CborArray& object, CborBuffer& buffer) {

// It return the index of the property, inside the local array, with the name passed as parameter. (-1 if it does not exist.)
int ArduinoCloudThing::findPropertyByName(String &name) {
for (int i = 0; i < list.size(); i++) {
ArduinoCloudPropertyGeneric *p = list.get(i);
if (p->shouldBeUpdated() && p->canRead()) {
CborObject child = CborObject(buffer);
p->append(child);
CborVariant variant = CborVariant(buffer, child);
object.add(variant);
// Check the property existance just comparing its name with existent ones
if (p->getName() == name) {
return i;
}
}
return -1;
}

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

void ArduinoCloudThing::decode(uint8_t * payload, size_t length) {
CborBuffer buffer(200);
CborVariant total = buffer.decode(payload, length);
ArduinoCloudPropertyGeneric& ArduinoCloudThing::addPropertyReal(String& property, String name) {
if (ArduinoCloudPropertyGeneric* p = exists(name)) {
return *p;
}
ArduinoCloudProperty<String> *thing = new ArduinoCloudProperty<String>(property, name);
list.add(thing);
return *(reinterpret_cast<ArduinoCloudPropertyGeneric*>(thing));
}

CborArray array = total.asArray();
void ArduinoCloudThing::decode(uint8_t * payload, size_t length) {
CborError err;
CborParser parser;
CborValue recursedMap, propValue, dataArray;
int propId; String propType, propName;

err = cbor_parser_init(payload, length, 0, &parser, &dataArray);
if (err) {
return;
}

for (int i=0; ;i++) {
CborVariant variant = array.get(i);
// parse cbor data only if a cbor array is received.
if (dataArray.type != CborArrayType)
return;

// main loop through the cbor array elements
while (!cbor_value_at_end(&dataArray)) {
// parse cbor object
cbor_value_enter_container(&dataArray, &recursedMap);
CborType type = cbor_value_get_type(&recursedMap);
if (type != CborMapType) {
// stop the decode when 1st item thai is not a cbor map is found.
cbor_value_advance(&dataArray);
continue;
} else {

while (!cbor_value_at_end(&recursedMap)) {
// if the current element is not a cbor object as expected, skip it and go ahead.
if (cbor_value_get_type(&recursedMap) != CborMapType) {
cbor_value_advance(&recursedMap);
continue;
}

if (!variant.isValid()) {
break;
}
CborValue name;
// chechk for the if the a property has a name, if yes Cbor value name will properly updated
cbor_value_map_find_value(&recursedMap, "n", &name);
// check if a property has a name, of string type, if not do nothin and skip curtrent property
if (name.type != CborTextStringType) {
cbor_value_advance(&recursedMap);
continue;
}

// get the property name from cbor map as char* string
char *nameVal; size_t nameValSize;
err = cbor_value_dup_text_string(&name, &nameVal, &nameValSize, NULL);
if (err) {
break; // couldn't get the value of the field
}
// get the name of the received property as String object
propName = String(nameVal);
// used to avoid memory leaks (cbor_value_dup_text_string automatically perform a malloc)
free(nameVal);
// Search for the index of the device property with that name
propId = findPropertyByName(propName);
// If property does not exist, skip it and do nothing.
if (propId < 0) {
cbor_value_advance(&recursedMap);
continue;
}

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

String name = "";
if (object.get("n").isValid()) {
name = object.get("n").asString();
// search for the property with the same name
for (int idx = 0; idx < list.size(); idx++) {
ArduinoCloudPropertyGeneric *p = list.get(idx);
if (p->getName() == name) {
currentListIndex = idx;
break;
if (propValue.type == CborDoubleType) {
double val;
// get the value of the property as a double
cbor_value_get_double(&propValue, &val);
reinterpret_cast<ArduinoCloudProperty<float>*>(property)->write((float)val);
}
if (idx == list.size()) {
currentListIndex = -1;
// if no key proper key was found, do nothing
if (propValue.type == CborIntegerType) {
int val;
cbor_value_get_int(&propValue, &val);
reinterpret_cast<ArduinoCloudProperty<int>*>(property)->write(val);
}
}
}

if (object.get("t").isValid()) {
int tag = object.get("t").asInteger();
if (name != "") {
list.get(currentListIndex)->setTag(tag);
} else {
for (int idx = 0; idx < list.size(); idx++) {
ArduinoCloudPropertyGeneric *p = list.get(idx);
if (p->getTag() == tag) {
// if name == "" associate name and tag, otherwise set current list index
currentListIndex = idx;
break;
}
if (idx == list.size()) {
Serial.println("Property not found, skipping");
currentListIndex = -1;
if (propValue.type == CborBooleanType) {
bool val;
cbor_value_get_boolean(&propValue, &val);
reinterpret_cast<ArduinoCloudProperty<bool>*>(property)->write(val);
}
if (propValue.type == CborTextStringType) {
char *val; size_t valSize;
err = cbor_value_dup_text_string(&propValue, &val, &valSize, &propValue);
// Char* string transformed into array
reinterpret_cast<ArduinoCloudProperty<String>*>(property)->write(String((char*)val));
free(val);
}
// If the property has been changed call its callback
if (property->newData()) {
if (property->callback != NULL) {
property->callback();
}
}
// Continue to scan the cbor map
cbor_value_advance(&recursedMap);
}
}

if (object.get("i").isValid()) {
int value_i = object.get("i").asInteger();
reinterpret_cast<ArduinoCloudProperty<int>*>(list.get(currentListIndex))->write(value_i);
}

if (object.get("b").isValid()) {
bool value_b = object.get("b").asInteger();
reinterpret_cast<ArduinoCloudProperty<bool>*>(list.get(currentListIndex))->write(value_b);
}
/*
if (object.get("f").isValid()) {
float value_f = object.get("f").asFloat();
reinterpret_cast<ArduinoCloudProperty<bool>*>(list.get(currentListIndex))->write(value_f);
}
*/
if (object.get("s").isValid()) {
String value_s = object.get("s").asString();
reinterpret_cast<ArduinoCloudProperty<String>*>(list.get(currentListIndex))->write(value_s);
}

if (object.get("p").isValid()) {
permissionType value_p = (permissionType)object.get("p").asInteger();
list.get(currentListIndex)->setPermission(value_p);
}

if (list.get(currentListIndex)->newData()) {
// call onUpdate()
if (list.get(currentListIndex)->callback != NULL) {
list.get(currentListIndex)->callback();
}
}
// Leave the current cbor object, and advance to the next one
err = cbor_value_leave_container(&dataArray, &recursedMap);
}
}
Loading

0 comments on commit d94fb00

Please sign in to comment.