Official reference client implementation for Cumulocity SmartREST on u-blox C027.

Dependencies:   C027_Support C12832 LM75B MMA7660 MbedSmartRest mbed-rtos mbed

Fork of MbedSmartRestMain by Vincent Wochnik

Files at this revision

API Documentation at this revision

Comitter:
vwochnik
Date:
Sat Dec 06 19:47:23 2014 +0000
Parent:
67:c360a2b2c948
Child:
69:237c01eb36c2
Commit message:
configuration for interval

Changed in this revision

DeviceIntegration.cpp Show annotated file Show diff for this revision Revisions of this file
MbedAgent.cpp Show annotated file Show diff for this revision Revisions of this file
MbedAgent.h Show annotated file Show diff for this revision Revisions of this file
config/ConfigurationProperties.cpp Show annotated file Show diff for this revision Revisions of this file
config/ConfigurationProperties.h Show annotated file Show diff for this revision Revisions of this file
config/ConfigurationSynchronization.cpp Show annotated file Show diff for this revision Revisions of this file
config/ConfigurationSynchronization.h Show annotated file Show diff for this revision Revisions of this file
config/DeviceConfiguration.cpp Show annotated file Show diff for this revision Revisions of this file
config/DeviceConfiguration.h Show annotated file Show diff for this revision Revisions of this file
io/DeviceMemory.cpp Show annotated file Show diff for this revision Revisions of this file
io/DeviceMemory.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
operation/OperationExecutor.cpp Show annotated file Show diff for this revision Revisions of this file
operation/OperationExecutor.h Show annotated file Show diff for this revision Revisions of this file
operation/OperationSupport.cpp Show annotated file Show diff for this revision Revisions of this file
operation/OperationSupport.h Show annotated file Show diff for this revision Revisions of this file
--- a/DeviceIntegration.cpp	Sun Nov 30 19:34:49 2014 +0000
+++ b/DeviceIntegration.cpp	Sat Dec 06 19:47:23 2014 +0000
@@ -30,7 +30,7 @@
 
     // Create device
     // Usage: 101,<SERIAL/NR>
-    if (!_tpl.add("10,101,POST,/inventory/managedObjects,application/vnd.com.nsn.cumulocity.managedObject+json,application/vnd.com.nsn.cumulocity.managedObject+json,%%,STRING,\"{\"\"name\"\":\"\"Mbed Test Device\"\",\"\"type\"\":\"\"com_ublox_C027_REV-A\"\",\"\"c8y_Hardware\"\":{\"\"revision\"\":\"\"1\"\",\"\"model\"\":\"\"Ublox C027\"\",\"\"serialNumber\"\":\"\"%%\"\"},\"\"c8y_SupportedMeasurements\"\":[\"\"c8y_SignalStrength\"\",\"\"c8y_TemperatureMeasurement\"\",\"\"c8y_AnalogMeasurement\"\",\"\"c8y_MotionMeasurement\"\",\"\"c8y_AnalogMeasurement\"\"],\"\"c8y_SupportedOperations\"\":[\"\"c8y_Relay\"\",\"\"c8y_Message\"\"],\"\"c8y_RequiredAvailability\"\":{ \"\"responseInterval\"\":15},\"\"c8y_IsDevice\"\":{},\"\"com_cumulocity_model_Agent\"\":{}}\"\r\n"))
+    if (!_tpl.add("10,101,POST,/inventory/managedObjects,application/vnd.com.nsn.cumulocity.managedObject+json,application/vnd.com.nsn.cumulocity.managedObject+json,%%,STRING,\"{\"\"name\"\":\"\"Mbed Test Device\"\",\"\"type\"\":\"\"com_ublox_C027_REV-A\"\",\"\"c8y_Hardware\"\":{\"\"revision\"\":\"\"1\"\",\"\"model\"\":\"\"Ublox C027\"\",\"\"serialNumber\"\":\"\"%%\"\"},\"\"c8y_SupportedMeasurements\"\":[\"\"c8y_SignalStrength\"\",\"\"c8y_TemperatureMeasurement\"\",\"\"c8y_AnalogMeasurement\"\",\"\"c8y_MotionMeasurement\"\",\"\"c8y_AnalogMeasurement\"\"],\"\"c8y_SupportedOperations\"\":[\"\"c8y_Relay\"\",\"\"c8y_Configuration\"\",\"\"c8y_Message\"\"],\"\"c8y_RequiredAvailability\"\":{ \"\"responseInterval\"\":15},\"\"c8y_IsDevice\"\":{},\"\"com_cumulocity_model_Agent\"\":{}}\"\r\n"))
         return false;
 
     // Get device id
--- a/MbedAgent.cpp	Sun Nov 30 19:34:49 2014 +0000
+++ b/MbedAgent.cpp	Sat Dec 06 19:47:23 2014 +0000
@@ -6,15 +6,17 @@
     _mdm(mdm),
     _deviceInfo(deviceInfo),
     _deviceMemory(deviceMemory),
+    _configurationProperties(_deviceConfiguration),
     _client(MBED_AGENT_HOST, MBED_AGENT_PORT, MBED_AGENT_DEVICE_IDENTIFIER),
     _bootstrap(_client, _io, _deviceInfo, _deviceMemory),
     _integration(_client, _tpl, _deviceId, _deviceInfo),
+    _configurationSynchronization(_client, _tpl, _deviceId, _deviceMemory, _deviceConfiguration, _configurationProperties),
     _signalQualityMeasurement(_client, _tpl, _deviceId, _deviceInfo),
     _temperatureMeasurement(_client, _tpl, _deviceId, _io.temperatureSensor()),
     _accelerationMeasurement(_client, _tpl, _deviceId, _io.accelerometer()),
     _analogMeasurement(_client, _tpl, _deviceId, _io.analog1(), _io.analog2()),
     _locationUpdate(_client, _tpl, _deviceId, _io.gpsTracker()),
-    _operationSupport(_client, _tpl, _deviceId, _io),
+    _operationSupport(_client, _tpl, _deviceId, _configurationSynchronization, _io),
     _deviceId(0)
 {
 }
@@ -22,6 +24,7 @@
 bool MbedAgent::init()
 {
     if ((!_integration.init()) ||
+        (!_configurationSynchronization.init()) ||
         (!_signalQualityMeasurement.init()) ||
         (!_temperatureMeasurement.init()) ||
         (!_accelerationMeasurement.init()) ||
@@ -47,22 +50,28 @@
         return false;
     }
     
+    if (!_configurationSynchronization.integrate()) {
+        return false;
+    }
+    
     char status[60];
     snprintf(status, sizeof(status), "ID: %ld", _deviceId);
     _io.lcdPrint("INTEGRATED", status);
 
     loop();
+
     return true;
 }
 
 void MbedAgent::loop()
 {
-    Timer timer;
+    Timer timer; int interval;
     
     timer.start();
     while (true) {
         timer.reset();
         
+        _configurationSynchronization.run();
         _signalQualityMeasurement.run();
         _temperatureMeasurement.run();
         _accelerationMeasurement.run();
@@ -70,7 +79,10 @@
         _locationUpdate.run();
         _operationSupport.run();
         
-        while (timer.read() < MBED_AGENT_INTERVAL) {
+        if ((interval = _configurationProperties.readInterval()) == 0)
+            break;
+
+        while (timer.read() < interval) {
             Thread::yield();
         }
     }
--- a/MbedAgent.h	Sun Nov 30 19:34:49 2014 +0000
+++ b/MbedAgent.h	Sat Dec 06 19:47:23 2014 +0000
@@ -10,6 +10,9 @@
 #include "DeviceMemory.h"
 #include "DeviceBootstrap.h"
 #include "DeviceIntegration.h"
+#include "DeviceConfiguration.h"
+#include "ConfigurationProperties.h"
+#include "ConfigurationSynchronization.h"
 #include "SignalQualityMeasurement.h"
 #include "TemperatureMeasurement.h"
 #include "AccelerationMeasurement.h"
@@ -19,8 +22,7 @@
 
 #define MBED_AGENT_HOST "developer.cumulocity.com"
 #define MBED_AGENT_PORT 80
-#define MBED_AGENT_DEVICE_IDENTIFIER "com_cumulocity_MbedAgent_1.4.2"
-#define MBED_AGENT_INTERVAL 30.0
+#define MBED_AGENT_DEVICE_IDENTIFIER "com_cumulocity_MbedAgent_1.5.0"
 
 class MbedAgent
 {
@@ -38,10 +40,13 @@
     MDMSerial& _mdm;
     DeviceInfo& _deviceInfo;
     DeviceMemory& _deviceMemory;
+    DeviceConfiguration _deviceConfiguration;
+    ConfigurationProperties _configurationProperties;
     RtosSmartRest _client;
     SmartRestTemplate _tpl;
     DeviceBootstrap _bootstrap;
     DeviceIntegration _integration;
+    ConfigurationSynchronization _configurationSynchronization;
     SignalQualityMeasurement _signalQualityMeasurement;
     TemperatureMeasurement _temperatureMeasurement;
     AccelerationMeasurement _accelerationMeasurement;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/ConfigurationProperties.cpp	Sat Dec 06 19:47:23 2014 +0000
@@ -0,0 +1,28 @@
+#include "ConfigurationProperties.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+ConfigurationProperties::ConfigurationProperties(DeviceConfiguration& deviceConfiguration) :
+    _deviceConfiguration(deviceConfiguration)
+{
+}
+
+bool ConfigurationProperties::resetConfiguration()
+{
+    return _deviceConfiguration.set("interval", CONFIGURATION_PROPERTY_INTERVAL);
+}
+
+int ConfigurationProperties::readInterval()
+{
+    const char *prop; int res, ln;
+    
+    if ((prop = _deviceConfiguration.get("interval")) == NULL)
+        prop = CONFIGURATION_PROPERTY_INTERVAL;
+    
+    ln = -1;
+    if ((sscanf(prop, "%d%n", &res, &ln) != 1) || (ln != strlen(prop)))
+        return 0;
+
+    return res;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/ConfigurationProperties.h	Sat Dec 06 19:47:23 2014 +0000
@@ -0,0 +1,22 @@
+#ifndef CONFIGURATIONPROPERTIES_H
+#define CONFIGURATIONPROPERTIES_H
+
+#include <stddef.h>
+#include "DeviceConfiguration.h"
+
+#define CONFIGURATION_PROPERTY_INTERVAL "300"
+
+class ConfigurationProperties
+{
+public:
+    ConfigurationProperties(DeviceConfiguration&);
+    
+    bool resetConfiguration();
+    
+    int readInterval();
+
+private:
+    DeviceConfiguration& _deviceConfiguration;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/ConfigurationSynchronization.cpp	Sat Dec 06 19:47:23 2014 +0000
@@ -0,0 +1,133 @@
+#include "ConfigurationSynchronization.h"
+#include <stdio.h>
+#include "ComposedRecord.h"
+#include "CharValue.h"
+#include "IntegerValue.h"
+
+ConfigurationSynchronization::ConfigurationSynchronization(AbstractSmartRest& client, SmartRestTemplate& tpl, long& deviceId, DeviceMemory& deviceMemory, DeviceConfiguration& deviceConfiguration, ConfigurationProperties& configurationProperties) :
+    _client(client),
+    _tpl(tpl),
+    _deviceId(deviceId),
+    _deviceMemory(deviceMemory),
+    _deviceConfiguration(deviceConfiguration),
+    _configurationProperties(configurationProperties)
+{
+    _init = false;
+    _changed = false;
+}
+
+bool ConfigurationSynchronization::init()
+{
+    if (_init)
+        return false;
+    
+    // Update Configuration
+    // Usage: 130,<DEVICE/ID>,<CONFIG/STRING>
+    if (!_tpl.add("10,130,PUT,/inventory/managedObjects/%%,application/vnd.com.nsn.cumulocity.managedObject+json,application/vnd.com.nsn.cumulocity.managedObject+json,%%,UNSIGNED STRING,\"{\"\"c8y_Configuration\"\":{\"\"config\"\":\"\"%%\"\"}}\"\r\n"))
+        return false;
+
+    _init = true;
+    return true;
+}
+
+bool ConfigurationSynchronization::integrate()
+{
+    if (!loadConfiguration()) {
+        if ((!_configurationProperties.resetConfiguration()) || (!updateDeviceObject()) || (!saveConfiguration()))
+            return false;
+    } else {
+        if (!updateDeviceObject())
+            return false;
+    }
+
+    return true;
+}
+
+bool ConfigurationSynchronization::run()
+{
+    if (!_changed)
+        return true;
+
+    if ((!updateDeviceObject()) || (!saveConfiguration()))
+        return false;
+    
+    _changed = false;
+    return true;
+}
+
+bool ConfigurationSynchronization::updateConfiguration(const char *cfg)
+{
+    if (!_deviceConfiguration.read(cfg))
+        return false;
+    
+    _changed = true;
+    return true;
+}
+
+bool ConfigurationSynchronization::updateDeviceObject()
+{
+    char buf[256];
+    
+    if (!_deviceConfiguration.write(buf, sizeof(buf)))
+        return false;
+
+    ComposedRecord record;
+    ParsedRecord received;
+
+    IntegerValue msgId(130);
+    IntegerValue deviceId(_deviceId);
+    CharValue config(buf);
+    if ((!record.add(msgId)) || (!record.add(deviceId)) || (!record.add(config)))
+        return false;
+
+    if (_client.send(record) != SMARTREST_SUCCESS) {
+        puts("Send failed.");
+        _client.stop();
+        return false;
+    }
+
+    if (_client.receive(received) != SMARTREST_SUCCESS) {
+        puts("Update failed.");
+        _client.stop();
+        return false;
+    }
+    _client.stop();
+
+    if (received.values() != 3) {
+        puts("Bad received data.");
+        return false;
+    }
+    
+    if (received.value(0).integerValue() != 201) {
+        puts("Bad received data.");
+        return false;
+    }
+
+    return true;
+}
+
+bool ConfigurationSynchronization::loadConfiguration()
+{
+    char buf[256];
+    
+    if (!_deviceMemory.loadConfiguration(buf, sizeof(buf)))
+        return false;
+    
+    if (!_deviceConfiguration.read(buf))
+        return false;
+
+    return true;
+}
+
+bool ConfigurationSynchronization::saveConfiguration()
+{
+    char buf[256];
+    
+    if (!_deviceConfiguration.write(buf, sizeof(buf)))
+        return false;
+    
+    if (!_deviceMemory.saveConfiguration(buf))
+        return false;
+    
+    return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/ConfigurationSynchronization.h	Sat Dec 06 19:47:23 2014 +0000
@@ -0,0 +1,37 @@
+#ifndef CONFIGURATIONSYNCHRONIZATION_H
+#define CONFIGURATIONSYNCHRONIZATION_H
+
+#include "AbstractSmartRest.h"
+#include "SmartRestTemplate.h"
+#include "DeviceConfiguration.h"
+#include "ConfigurationProperties.h"
+#include "DeviceMemory.h"
+
+class ConfigurationSynchronization
+{
+public:
+    ConfigurationSynchronization(AbstractSmartRest&, SmartRestTemplate&, long&, DeviceMemory&, DeviceConfiguration&, ConfigurationProperties&);
+    
+    bool init();
+    bool integrate();
+    bool run();
+    
+    bool updateConfiguration(const char*);
+
+protected:
+    bool updateDeviceObject();
+    bool loadConfiguration();
+    bool saveConfiguration();
+
+private:
+    bool _init;
+    long& _deviceId;
+    bool _changed;
+    SmartRestTemplate& _tpl;
+    AbstractSmartRest& _client;
+    DeviceMemory& _deviceMemory;
+    DeviceConfiguration& _deviceConfiguration;
+    ConfigurationProperties& _configurationProperties;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/DeviceConfiguration.cpp	Sat Dec 06 19:47:23 2014 +0000
@@ -0,0 +1,183 @@
+#include "DeviceConfiguration.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+DeviceConfiguration::DeviceConfiguration()
+{
+    size_t i;
+    
+    for (i = 0; i < DEVICE_CONFIGURATION_SIZE; i++) {
+        _items[i].key = NULL;
+        _items[i].value = NULL;
+    }
+}
+
+DeviceConfiguration::~DeviceConfiguration()
+{
+    clear();
+}
+
+bool DeviceConfiguration::read(const char *str)
+{
+    const char *ptr, *ptr2, *ptr3; size_t i, j, len1, len2;
+    DeviceConfiguration::KeyValue items[DEVICE_CONFIGURATION_SIZE];
+    
+    for (i = 0; i < DEVICE_CONFIGURATION_SIZE; i++) {
+        items[i].key = NULL;
+        items[i].value = NULL;
+    }
+
+    ptr = str;
+    i = 0;
+    while ((*ptr != '\0') && (i < DEVICE_CONFIGURATION_SIZE)) {
+        if (((ptr2 = strchr(ptr, '=')) == NULL) ||
+            ((ptr3 = strchr(ptr2+1, ';')) == NULL))
+            goto failure;
+        
+        len1 = ptr2-ptr;
+        len2 = ptr3-ptr2 - 1;
+        
+        if ((memchr(ptr, ';', len1) != NULL) ||
+            (memchr(ptr2+1, '=', len2) != NULL))
+            goto failure;
+        
+        for (j = 0; j < DEVICE_CONFIGURATION_SIZE; j++) {
+            if ((items[j].key != NULL) && (strlen(items[j].key) == len1) && (strncmp(items[j].key, ptr, len1) == 0))
+                goto failure;
+        }
+
+        if ((items[i].key = (char*)malloc(len1+1)) == NULL)
+            goto failure;
+        if ((items[i].value = (char*)malloc(len2+1)) == NULL) {
+            free(items[i].key);
+            items[i].key = NULL;
+            goto failure;
+        }
+        
+        strncpy(items[i].key, ptr, len1);
+        strncpy(items[i].value, ptr2+1, len2);
+        items[i].key[len1] = '\0';
+        items[i].value[len2] = '\0';
+
+        i++;
+        ptr = ptr3+1;
+    }
+    
+    if (*ptr != '\0')
+        goto failure;
+    
+    clear();
+    memcpy(_items, items, sizeof(DeviceConfiguration::KeyValue)*DEVICE_CONFIGURATION_SIZE);
+    return true;
+
+failure:
+    for (i = 0; i < DEVICE_CONFIGURATION_SIZE; i++) {
+        if (items[i].key != NULL) {
+            free(items[i].key);
+            free(items[i].value);
+        }
+    }
+    
+    return false;
+}
+
+bool DeviceConfiguration::write(char *buf, size_t len)
+{
+    char *ptr; size_t i; int ret, ln;
+    
+    ptr = buf;
+    for (i = 0; i < DEVICE_CONFIGURATION_SIZE; i++) {
+        if (_items[i].key == NULL)
+            continue;
+
+        ret = snprintf(ptr, len, "%s=%s;%n", _items[i].key, _items[i].value, &ln);
+        if ((ret < 0) || (ret >= len))
+            return false;
+
+        ptr += ln;
+        len -= ln;
+    }
+    
+    return true;
+}
+
+bool DeviceConfiguration::set(const char *key, const char *value)
+{
+    KeyValue *item; size_t i;
+    
+    if ((item = search(key)) == NULL) {
+        for (i = 0; (i < DEVICE_CONFIGURATION_SIZE) && (item == NULL); i++) {
+            if (_items[i].key == NULL)
+                item = &_items[i];
+        }
+    }
+    
+    if (item == NULL)
+        return false;
+    
+    if ((item->key = (char*)malloc(strlen(key)+1)) == NULL)
+        return false;
+    if ((item->value = (char*)malloc(strlen(value)+1)) == NULL) {
+        free(item->key);
+        item->key = NULL;
+        return false;
+    }
+    
+    strcpy(item->key, key);
+    strcpy(item->value, value);
+    return true;
+}
+
+const char * DeviceConfiguration::get(const char *key)
+{
+    KeyValue *item;
+    
+    if ((item = search(key)) == NULL)
+        return NULL;
+    
+    return item->value;
+}
+
+bool DeviceConfiguration::unset(const char *key)
+{
+    KeyValue *item;
+    
+    if ((item = search(key)) == NULL)
+        return false;
+    
+    free(item->key);
+    free(item->value);
+    item->key = NULL;
+    item->value = NULL;
+    return true;
+}
+
+bool DeviceConfiguration::has(const char *key)
+{
+    return (search(key) != NULL);
+}
+
+void DeviceConfiguration::clear()
+{
+    size_t i;
+    
+    for (i = 0; i < DEVICE_CONFIGURATION_SIZE; i++) {
+        if (_items[i].key != NULL) {
+            free(_items[i].key);
+            free(_items[i].value);
+        }
+    }
+}
+
+DeviceConfiguration::KeyValue * DeviceConfiguration::search(const char *key)
+{
+    size_t i;
+    
+    for (i = 0; i < DEVICE_CONFIGURATION_SIZE; i++) {
+        if (strcmp(key, _items[i].key) == 0)
+            return &_items[i];
+    }
+    
+    return NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/DeviceConfiguration.h	Sat Dec 06 19:47:23 2014 +0000
@@ -0,0 +1,36 @@
+#ifndef DEVICECONFIGURATION_H
+#define DEVICECONFIGURATION_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define DEVICE_CONFIGURATION_SIZE 8
+
+class DeviceConfiguration
+{
+public:
+    DeviceConfiguration();
+    ~DeviceConfiguration();
+    
+    bool read(const char*);
+    bool write(char*, size_t);
+    
+    bool set(const char*, const char*);
+    const char * get(const char*);
+    bool unset(const char*);
+    bool has(const char*);
+    void clear();
+    
+protected:
+    struct KeyValue {
+        char *key;
+        char *value;
+    };
+
+    KeyValue * search(const char*);
+
+private:
+    KeyValue _items[DEVICE_CONFIGURATION_SIZE];
+};
+
+#endif
\ No newline at end of file
--- a/io/DeviceMemory.cpp	Sun Nov 30 19:34:49 2014 +0000
+++ b/io/DeviceMemory.cpp	Sat Dec 06 19:47:23 2014 +0000
@@ -4,6 +4,7 @@
 #include <string.h>
 
 #define PLATFORM_CREDENTIALS_FILE "001_CREDENTIALS"
+#define CONFIGURATION_FILE "002_CONFIGURATION"
 
 DeviceMemory::DeviceMemory(MDMSerial& mdm) :
     _mdm(mdm)
@@ -30,10 +31,35 @@
     if ((res < 0) || (res >= sizeof(buffer)))
         return false;
 
-    return res == _mdm.writeFile(PLATFORM_CREDENTIALS_FILE, buffer, res);
+    return ((_mdm.delFile(PLATFORM_CREDENTIALS_FILE)) && (res == _mdm.writeFile(PLATFORM_CREDENTIALS_FILE, buffer, res)));
 }
 
 bool DeviceMemory::resetPlatformCredentials()
 {
     return _mdm.delFile(PLATFORM_CREDENTIALS_FILE);
 }
+
+
+bool DeviceMemory::loadConfiguration(char *cfg, size_t len)
+{
+    int res;
+
+    if ((res = _mdm.readFile(CONFIGURATION_FILE, cfg, len)) < 0)
+        return false;
+    
+    cfg[(size_t)res] = '\0';
+    return true;
+}
+
+bool DeviceMemory::saveConfiguration(char *cfg)
+{
+    size_t len;
+    
+    len = strlen(cfg);
+    return ((_mdm.delFile(CONFIGURATION_FILE)) && (_mdm.writeFile(CONFIGURATION_FILE, cfg, len) == len));
+}
+
+bool DeviceMemory::resetConfiguration()
+{
+    return _mdm.delFile(CONFIGURATION_FILE);
+}
--- a/io/DeviceMemory.h	Sun Nov 30 19:34:49 2014 +0000
+++ b/io/DeviceMemory.h	Sat Dec 06 19:47:23 2014 +0000
@@ -21,6 +21,15 @@
     /** removes credentials from persistent memory */
     bool resetPlatformCredentials();
     
+    /** loads configuration from persistent memory */
+    bool loadConfiguration(char*, size_t);
+    
+    /** saves configuration to persistent memory */
+    bool saveConfiguration(char*);
+    
+    /** removes configuration from persistent memory */
+    bool resetConfiguration();
+
 private:
     MDMSerial& _mdm;
 };
--- a/main.cpp	Sun Nov 30 19:34:49 2014 +0000
+++ b/main.cpp	Sat Dec 06 19:47:23 2014 +0000
@@ -7,6 +7,8 @@
 #include "MbedAgent.h"
 #include "GPSTracker.h"
 
+#include "DeviceConfiguration.h"
+
 #include <stdio.h>
 
 /**
@@ -30,7 +32,7 @@
     MDMRtos<MDMSerial> mdm;
     GPSI2C gps;
     
-    mdm.setDebug(4);
+    //mdm.setDebug(4);
 
     if (!mdm.init(SIM_PIN, &devStatus))
         status = 1;
--- a/operation/OperationExecutor.cpp	Sun Nov 30 19:34:49 2014 +0000
+++ b/operation/OperationExecutor.cpp	Sat Dec 06 19:47:23 2014 +0000
@@ -7,10 +7,12 @@
 
 #define FOUND_RELAY 1
 #define FOUND_MESSAGE 2
+#define FOUND_CONFIGURATION 3
 
-OperationExecutor::OperationExecutor(AbstractSmartRest& client, SmartRestTemplate& tpl, long& deviceId, DeviceIO& io) :
+OperationExecutor::OperationExecutor(AbstractSmartRest& client, SmartRestTemplate& tpl, long& deviceId, ConfigurationSynchronization& configurationSynchronization, DeviceIO& io) :
     _client(client),
     _tpl(tpl),
+    _configurationSynchronization(configurationSynchronization),
     _deviceId(deviceId),
     _io(io)
 {
@@ -37,13 +39,18 @@
     if (!_tpl.add("11,221,,\"$.c8y_Message\",\"$.id\",\"$.c8y_Message.text\"\r\n"))
         return false;
 
+    // Configuration operation response
+    // Response: 222,<OPERATION/ID>,<CONFIGURATION/STRING>
+    if (!_tpl.add("11,222,,\"$.c8y_Configuration\",\"$.id\",\"$.c8y_Configuration.config\"\r\n"))
+        return false;
+
     _init = true;
     return true;
 }
 
 bool OperationExecutor::executeOperation(OperationStore::Operation& op)
 {
-    uint8_t ret; uint8_t found; bool relayState; char message[128];
+    uint8_t ret; uint8_t found; bool relayState; char message[256];
     ComposedRecord record;
     ParsedRecord received;
     
@@ -81,6 +88,18 @@
             found = FOUND_MESSAGE;
             break;
         }
+        
+        if ((received.values() == 4) &&
+            (received.value(0).valueType() == VALUE_INTEGER) &&
+            (received.value(0).integerValue() == 222) &&
+            (received.value(2).valueType() == VALUE_INTEGER) &&
+            (received.value(2).integerValue() == op.identifier) &&
+            (received.value(3).valueType() == VALUE_CHARACTER)) {
+            strncpy(message, received.value(3).characterValue(), 256);
+            message[255] = '\0';
+            found = FOUND_CONFIGURATION;
+            break;
+        }
     }
     _client.stop();
 
@@ -89,6 +108,8 @@
         return executeRelayStateUpdate(relayState);
     case FOUND_MESSAGE:
         return executeMessageDisplay(message);
+    case FOUND_CONFIGURATION:
+        return executeUpdateConfiguration(message);
     default:
         return false;
     }
@@ -108,3 +129,8 @@
     _io.lcdPrint(message);
     return true;
 }
+
+bool OperationExecutor::executeUpdateConfiguration(const char *config)
+{
+    return _configurationSynchronization.updateConfiguration(config);
+}
--- a/operation/OperationExecutor.h	Sun Nov 30 19:34:49 2014 +0000
+++ b/operation/OperationExecutor.h	Sat Dec 06 19:47:23 2014 +0000
@@ -5,11 +5,12 @@
 #include "SmartRestTemplate.h"
 #include "OperationStore.h"
 #include "DeviceIO.h"
+#include "ConfigurationSynchronization.h"
 
 class OperationExecutor
 {
 public:
-    OperationExecutor(AbstractSmartRest&, SmartRestTemplate&, long&, DeviceIO&);
+    OperationExecutor(AbstractSmartRest&, SmartRestTemplate&, long&, ConfigurationSynchronization&, DeviceIO&);
     
     bool init();
     bool executeOperation(OperationStore::Operation&);
@@ -17,12 +18,14 @@
 protected:
     bool executeRelayStateUpdate(bool relayState);
     bool executeMessageDisplay(const char *message);
+    bool executeUpdateConfiguration(const char *config);
 
 private:
     bool _init;
     long& _deviceId;
     SmartRestTemplate& _tpl;
     AbstractSmartRest& _client;
+    ConfigurationSynchronization& _configurationSynchronization;
     DeviceIO& _io;
 };
 
--- a/operation/OperationSupport.cpp	Sun Nov 30 19:34:49 2014 +0000
+++ b/operation/OperationSupport.cpp	Sat Dec 06 19:47:23 2014 +0000
@@ -10,11 +10,11 @@
 CharValue aOperationStateSuccessful("SUCCESSFUL");
 CharValue aOperationStateFailed("FAILED");
 
-OperationSupport::OperationSupport(AbstractSmartRest& client, SmartRestTemplate& tpl, long& deviceId, DeviceIO& io) :
+OperationSupport::OperationSupport(AbstractSmartRest& client, SmartRestTemplate& tpl, long& deviceId, ConfigurationSynchronization& configurationSynchronization, DeviceIO& io) :
     _client(client),
     _tpl(tpl),
     _deviceId(deviceId),
-    _executor(client, tpl, deviceId, io),
+    _executor(client, tpl, deviceId, configurationSynchronization, io),
     _thread1(OperationSupport::thread1_func, this),
     _thread2(OperationSupport::thread2_func, this),
     _thread3(OperationSupport::thread3_func, this)
@@ -59,10 +59,11 @@
 {
     if (_firstRun) {
         _firstRun = false;
-        return true;
-        if (!requestPendingOperations())
-            return false;
+        //TODO: only request pending until push operation works
     }
+
+    if (!requestPendingOperations())
+        return false;
         
     return true;
 }
@@ -228,7 +229,7 @@
 
 void OperationSupport::thread3()
 {
-    char bayeuxId[33];
+/*    char bayeuxId[33];
 
     ComposedRecord record;
     ParsedRecord received;
@@ -257,7 +258,7 @@
     }
 
     while (true) {
-    }
+    }*/
 }
 
 void OperationSupport::thread1_func(void const *arg)
--- a/operation/OperationSupport.h	Sun Nov 30 19:34:49 2014 +0000
+++ b/operation/OperationSupport.h	Sat Dec 06 19:47:23 2014 +0000
@@ -2,6 +2,7 @@
 #define OPERATIONSUPPORT_H
 
 #include "rtos.h"
+#include "ConfigurationSynchronization.h"
 #include "DeviceIO.h"
 #include "OperationExecutor.h"
 #include "AbstractSmartRest.h"
@@ -14,7 +15,7 @@
 class OperationSupport
 {
 public:
-    OperationSupport(AbstractSmartRest&, SmartRestTemplate&, long&, DeviceIO&);
+    OperationSupport(AbstractSmartRest&, SmartRestTemplate&, long&, ConfigurationSynchronization&, DeviceIO&);
     
     bool init();
     bool run();