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:
Cumulocity
Date:
Tue Jul 15 12:44:34 2014 +0000
Parent:
40:13c24225f189
Child:
42:104746744af8
Commit message:
refactoring of mbed agent

Changed in this revision

AccelerationMeasurement.cpp Show annotated file Show diff for this revision Revisions of this file
AccelerationMeasurement.h Show annotated file Show diff for this revision Revisions of this file
C027.lib Show diff for this revision Revisions of this file
DeviceBootstrap.cpp Show annotated file Show diff for this revision Revisions of this file
DeviceBootstrap.h Show annotated file Show diff for this revision Revisions of this file
DeviceIO.cpp Show annotated file Show diff for this revision Revisions of this file
DeviceIO.h Show annotated file Show diff for this revision Revisions of this file
DeviceInfo.cpp Show annotated file Show diff for this revision Revisions of this file
DeviceInfo.h Show annotated file Show diff for this revision Revisions of this file
DeviceIntegration.cpp Show annotated file Show diff for this revision Revisions of this file
DeviceIntegration.h 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
SignalQualityMeasurement.cpp Show annotated file Show diff for this revision Revisions of this file
SignalQualityMeasurement.h Show annotated file Show diff for this revision Revisions of this file
TemperatureMeasurement.cpp Show annotated file Show diff for this revision Revisions of this file
TemperatureMeasurement.h Show annotated file Show diff for this revision Revisions of this file
common.h Show diff for this revision Revisions of this file
io.cpp Show diff for this revision Revisions of this file
io.h Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
program.cpp Show diff for this revision Revisions of this file
utils/SmartRestTemplate.cpp Show annotated file Show diff for this revision Revisions of this file
utils/SmartRestTemplate.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AccelerationMeasurement.cpp	Tue Jul 15 12:44:34 2014 +0000
@@ -0,0 +1,56 @@
+#include "AccelerationMeasurement.h"
+#include "ComposedRecord.h"
+#include "CharValue.h"
+#include "IntegerValue.h"
+#include "FloatValue.h"
+
+AccelerationMeasurement::AccelerationMeasurement(SmartRest& client, SmartRestTemplate& tpl, long& deviceId, MMA7660& sensor) :
+    _client(client),
+    _tpl(tpl),
+    _deviceId(deviceId),
+    _sensor(sensor)
+{
+    _init = false;
+}
+
+bool AccelerationMeasurement::init()
+{
+    if (_init)
+        return false;
+    
+    // Insert measurement
+    // USAGE: 105,<DEVICE/ID>,<X>,<Y>,<Z>
+    if (!_tpl.add("10,106,POST,/measurement/measurements,application/vnd.com.nsn.cumulocity.measurement+json,application/vnd.com.nsn.cumulocity.measurement+json,%%,NOW UNSIGNED NUMBER NUMBER NUMBER,\"{\"\"time\"\":\"\"%%\"\",\"\"source\"\":{\"\"id\"\":\"\"%%\"\"},\"\"type\"\":\"\"c8y_MotionMeasurement\"\",\"\"c8y_MotionMeasurement\"\":{\"\"x\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"m^2/s\"\"},\"\"y\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"m^2/s\"\"},\"\"z\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"m^2/s\"\"}}}\"\r\n"))
+        return false;
+
+    _test = _sensor.testConnection();
+    _init = true;
+    return true;
+}
+
+bool AccelerationMeasurement::run()
+{
+    float data[3] = { 0.0, 0.0, 0.0 };
+    
+    if (!_test)
+        return false;
+        
+    _sensor.readData(data);
+
+    ComposedRecord record;
+    IntegerValue msgId(106);
+    IntegerValue devId(_deviceId);
+    FloatValue xValue(data[0], 2);
+    FloatValue yValue(data[1], 2);
+    FloatValue zValue(data[2], 2);
+    if ((!record.add(msgId)) || (!record.add(devId)) || (!record.add(xValue)) || (!record.add(yValue)) || (!record.add(zValue)))
+        return false;
+
+    if (_client.send(record) != SMARTREST_SUCCESS) {
+        puts("Signal measurement failed.");
+        _client.stop();
+        return false;
+    }
+    _client.stop();
+    return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AccelerationMeasurement.h	Tue Jul 15 12:44:34 2014 +0000
@@ -0,0 +1,24 @@
+#ifndef ACCELERATIONMEASUREMENT_H
+#define ACCELERATIONMEASUREMENT_H
+
+#include "SmartRest.h"
+#include "SmartRestTemplate.h"
+#include "MMA7660.h"
+
+class AccelerationMeasurement
+{
+public:
+    AccelerationMeasurement(SmartRest&, SmartRestTemplate&, long&, MMA7660&);
+    
+    bool init();
+    bool run();
+
+private:
+    bool _init, _test;
+    long& _deviceId;
+    SmartRestTemplate& _tpl;
+    SmartRest& _client;
+    MMA7660& _sensor;
+};
+
+#endif
\ No newline at end of file
--- a/C027.lib	Thu Jul 10 14:22:11 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/teams/ublox/code/C027/#89c45165ee87
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DeviceBootstrap.cpp	Tue Jul 15 12:44:34 2014 +0000
@@ -0,0 +1,146 @@
+#include "DeviceBootstrap.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "rtos.h"
+#include "ComposedRecord.h"
+#include "CharValue.h"
+#include "IntegerValue.h"
+#include "ParsedRecord.h"
+
+DeviceBootstrap::DeviceBootstrap(SmartRest& client, MDMSerial& mdm, DeviceInfo& deviceInfo) :
+    _client(client),
+    _mdm(mdm),
+    _deviceInfo(deviceInfo)
+{
+    *_username = *_password = '\0';
+}
+
+bool DeviceBootstrap::setUpCredentials()
+{
+    if (((*_username == '\0') || (*_password == '\0')) &&
+        (!obtainFromStorage())) {
+        if (!obtainFromPlatform())
+            return false;
+        if (!writeToStorage())
+            puts("Warning: Could not write credentials to file!");
+    }
+
+    printf("Credentials: %s : %s\n", _username, _password);
+    if (_client.setAuthorization(_username, _password) != SMARTREST_SUCCESS)
+        return false;
+    return true;
+}
+
+bool DeviceBootstrap::obtainFromStorage()
+{
+    char buf[DEVICE_BOOTSTRAP_CREDENTIALS_LENGTH*2+2], *ptr;
+
+    int res = _mdm.readFile(CREDENTIALS_FILE, buf, sizeof(buf));
+
+    if (res < 0)
+        return false;
+        
+    buf[res] = '\0';
+    if ((ptr = strchr(buf, '\n')) == NULL)
+        return false;
+    *ptr = '\0';
+    
+    ptr = buf;
+    strcpy(_username, ptr);
+    ptr += strlen(ptr)+1;
+    strcpy(_password, ptr);
+    return true;
+}
+
+bool DeviceBootstrap::obtainFromPlatform()
+{
+    uint8_t ret;
+
+    printf("Starting device bootstrap with '%s'\n", _deviceInfo.imei());
+    
+    ComposedRecord record;
+    ParsedRecord recvdRecord;
+
+    IntegerValue msgId(61);
+    CharValue identifier(_deviceInfo.imei());
+    if ((!record.add(msgId)) || (!record.add(identifier)))
+        return false;
+
+    // set authorization for bootstrap
+    if (_client.setAuthorization(DEVICE_BOOTSTRAP_USERNAME, DEVICE_BOOTSTRAP_PASSWORD) != SMARTREST_SUCCESS)
+        return false;
+
+    while (true) {
+        if (_client.send(record, "") != SMARTREST_SUCCESS) {
+            puts("Connection unsuccessful. Retrying.");
+            _client.stop();
+            Thread::wait(2000);
+            continue;
+        }
+        
+        if (_client.receive(recvdRecord) != SMARTREST_SUCCESS) {
+            puts("Receiving failure.");
+            _client.stop();
+            Thread::wait(2000);
+            continue;
+        }
+        
+        if ((recvdRecord.values() < 1) ||
+            (recvdRecord.value(0).integerValue() == 50)) {
+            puts("No credentials available yet. Retrying.");
+            Thread::wait(2000);
+            continue;
+        }
+        
+        if ((recvdRecord.value(0).integerValue() != 70) ||
+            (recvdRecord.values() != 6)) {
+            puts("Bad credentials received.");
+            return false;
+        }
+        
+        setCredentials(recvdRecord.value(3).characterValue(),
+                       recvdRecord.value(4).characterValue(),
+                       recvdRecord.value(5).characterValue());
+        
+        return true;
+    }
+    return false;
+}
+
+bool DeviceBootstrap::writeToStorage()
+{
+    char buf[DEVICE_BOOTSTRAP_CREDENTIALS_LENGTH*2+2], *ptr;
+    size_t len;
+
+    ptr = buf;
+    len = strlen(_username);
+    strcpy(ptr, _username);
+    ptr += len;
+    
+    *ptr++ = '\n';
+    len++;
+    
+    len += strlen(_password);
+    strcpy(ptr, _password);
+    
+    _mdm.delFile(CREDENTIALS_FILE);
+    _mdm.writeFile(CREDENTIALS_FILE, buf, len);
+    return true;
+}
+
+void DeviceBootstrap::setCredentials(const char *tenant, const char *username, const char *password)
+{
+    *_username = '\0';
+    if (tenant != NULL) {
+        strncpy(_username, tenant, DEVICE_BOOTSTRAP_CREDENTIALS_LENGTH);
+        _username[DEVICE_BOOTSTRAP_CREDENTIALS_LENGTH-1] = '\0';
+        if (strlen(_username)+1 < DEVICE_BOOTSTRAP_CREDENTIALS_LENGTH)
+            strcat(_username, "/");
+    }
+    strncat(_username, username, DEVICE_BOOTSTRAP_CREDENTIALS_LENGTH-strlen(_username));
+    _username[DEVICE_BOOTSTRAP_CREDENTIALS_LENGTH-1] = '\0';
+
+    strncpy(_password, password, DEVICE_BOOTSTRAP_CREDENTIALS_LENGTH);
+    _password[DEVICE_BOOTSTRAP_CREDENTIALS_LENGTH-1] = '\0';
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DeviceBootstrap.h	Tue Jul 15 12:44:34 2014 +0000
@@ -0,0 +1,42 @@
+#ifndef DEVICEBOOTSTRAP_H
+#define DEVICEBOOTSTRAP_H
+
+#include <stddef.h>
+#include "MDM.h"
+#include "SmartRest.h"
+#include "DeviceInfo.h"
+
+/** The username used for device bootstrapping. */
+#define DEVICE_BOOTSTRAP_USERNAME "management/devicebootstrap"
+
+/** The password used for device bootstrapping. */
+#define DEVICE_BOOTSTRAP_PASSWORD "Fhdt1bb1f"
+
+#define DEVICE_BOOTSTRAP_CREDENTIALS_LENGTH 256
+
+#define CREDENTIALS_FILE "001_CREDENTIALS"
+
+class DeviceBootstrap
+{
+public:
+    DeviceBootstrap(SmartRest&, MDMSerial&, DeviceInfo&);
+    
+    bool setUpCredentials();
+
+protected:
+    bool obtainFromStorage();
+    bool obtainFromPlatform();
+
+private:
+    bool writeToStorage();
+    void setCredentials(const char *, const char*, const char*);
+
+private:
+    SmartRest& _client;
+    MDMSerial& _mdm;
+    DeviceInfo& _deviceInfo;
+    char _username[DEVICE_BOOTSTRAP_CREDENTIALS_LENGTH],                    
+         _password[DEVICE_BOOTSTRAP_CREDENTIALS_LENGTH];
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DeviceIO.cpp	Tue Jul 15 12:44:34 2014 +0000
@@ -0,0 +1,30 @@
+#include "DeviceIO.h"
+
+DeviceIO::DeviceIO() :
+    _temperatureSensor(SDA,SCL),
+    _accelerometer(SDA,SCL),
+    _lcd(D11, D13, D12, D7, D10)
+{
+}
+
+LM75B& DeviceIO::temperatureSensor()
+{
+    return _temperatureSensor;
+}
+
+MMA7660& DeviceIO::accelerometer()
+{
+    return _accelerometer;
+}
+
+void DeviceIO::lcdPrint(const char *line1, const char *line2, const char *line3)
+{
+    _lcd.cls();
+    _lcd.locate(0, 0);
+    _lcd.printf("%s\n", line1);
+    if (line2 != NULL) {
+        _lcd.printf("%s\n", line2);
+        if (line3 != NULL)
+            _lcd.printf("%s\n", line3);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DeviceIO.h	Tue Jul 15 12:44:34 2014 +0000
@@ -0,0 +1,50 @@
+#ifndef DEVICEIO_H
+#define DEVICEIO_H
+
+#include "mbed.h"
+#include "LM75B.h"
+#include "MMA7660.h"
+#include "C12832.h"
+
+#define A0  P0_23
+#define A1  P0_24
+#define A2  P0_25
+#define A3  P0_26
+#define A4  P0_30
+#define A5  P1_31
+
+#define D0  P4_29
+#define D1  P4_28
+#define D2  P2_13
+#define D3  P2_0
+#define D4  P2_12
+#define D5  P2_1
+#define D6  P2_2
+#define D7  P2_11
+
+#define D8  P2_4
+#define D9  P2_3
+#define D10 P1_21
+#define D11 P1_24
+#define D12 P1_23
+#define D13 P1_20
+    
+#define SDA P0_0
+#define SCL P0_1
+
+class DeviceIO
+{
+public:
+    DeviceIO();
+
+    LM75B& temperatureSensor();
+    MMA7660& accelerometer();
+    void lcdPrint(const char*, const char* = NULL, const char* = NULL);
+
+private:
+    LM75B _temperatureSensor;
+    MMA7660 _accelerometer;
+    C12832 _lcd;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DeviceInfo.cpp	Tue Jul 15 12:44:34 2014 +0000
@@ -0,0 +1,56 @@
+#include "DeviceInfo.h"
+#include <stdlib.h>
+#include <string.h>
+
+DeviceInfo::DeviceInfo(MDMSerial& mdm, MDMParser::DevStatus& devStatus) :
+    _mdm(mdm)
+{
+    *_cellId = '\0';
+    memcpy(&_devStatus, &devStatus, sizeof(MDMParser::DevStatus));
+    memset(&_netStatus, 0, sizeof(MDMParser::NetStatus));
+    memset(&_signalQuality, 0, sizeof(DeviceInfo::SignalQuality));
+}
+
+const char * DeviceInfo::imsi()
+{
+    return _devStatus.imsi;
+}
+
+const char * DeviceInfo::imei()
+{
+    return _devStatus.imei;
+}
+
+const char * DeviceInfo::cellId()
+{
+    if (!refreshNetStatus())
+        return NULL;
+
+    if (snprintf(_cellId, sizeof(_cellId), "%X", _netStatus.ci) < 1)
+        return NULL;
+    return _cellId;
+}
+
+const char * DeviceInfo::iccid()
+{
+    return _devStatus.ccid;
+}
+
+DeviceInfo::SignalQuality * DeviceInfo::signalQuality()
+{
+    memset(&_signalQuality, 0, sizeof(DeviceInfo::SignalQuality));
+    if (!refreshNetStatus())
+        return NULL;
+    
+    if ((_netStatus.rssi == 0) || (_netStatus.ber == 0))
+        return NULL;
+
+    _signalQuality.rssi = _netStatus.rssi;
+    _signalQuality.ber = _netStatus.ber;
+    return &_signalQuality;
+}
+
+bool DeviceInfo::refreshNetStatus()
+{
+    return _mdm.checkNetStatus(&_netStatus);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DeviceInfo.h	Tue Jul 15 12:44:34 2014 +0000
@@ -0,0 +1,35 @@
+#ifndef DEVICEINFO_H
+#define DEVICEINFO_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include "MDM.h"
+
+class DeviceInfo
+{
+public:
+    DeviceInfo(MDMSerial& mdm, MDMParser::DevStatus& devStatus);
+    
+    typedef struct {
+        int rssi;  // RSSI in dBm
+        int ber; // BER in %
+    } SignalQuality;
+    
+    const char * imsi();
+    const char * imei();
+    const char * cellId();
+    const char * iccid();
+    SignalQuality * signalQuality();
+
+protected:
+    bool refreshNetStatus();
+
+private:
+    MDMSerial& _mdm;
+    MDMParser::DevStatus _devStatus;
+    MDMParser::NetStatus _netStatus;
+    char _cellId[9];
+    SignalQuality _signalQuality;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DeviceIntegration.cpp	Tue Jul 15 12:44:34 2014 +0000
@@ -0,0 +1,247 @@
+#include "DeviceIntegration.h"
+#include <stdio.h>
+#include "ComposedRecord.h"
+#include "CharValue.h"
+#include "IntegerValue.h"
+
+DeviceIntegration::DeviceIntegration(SmartRest& client, SmartRestTemplate& tpl, long& deviceId, DeviceInfo& deviceInfo) :
+    _client(client),
+    _tpl(tpl),
+    _deviceId(deviceId),
+    _deviceInfo(deviceInfo)
+{
+    _init = false;
+}
+
+bool DeviceIntegration::init()
+{
+    if (_init)
+        return false;
+    
+    // get device by identity
+    // Usage: 100,<SERIAL/NR>
+    if (!_tpl.add("10,100,GET,/identity/externalIds/c8y_Serial/%%,,application/vnd.com.nsn.cumulocity.externalId+json,%%,STRING,\r\n"))
+        return false;
+
+    // get device id from identity
+    // Response: 200,<DEVICE/ID>
+    if (!_tpl.add("11,200,\"$.managedObject\",,\"$.id\"\r\n"))
+        return false;
+
+    // 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_RequiredAvailability\"\":{ \"\"responseInterval\"\":15},\"\"c8y_IsDevice\"\":{}}\"\r\n"))
+        return false;
+
+    // Get device id
+    // Response: 201,<DEVICE/ID>
+    if (!_tpl.add("11,201,,\"$.c8y_IsDevice\",\"$.id\"\r\n"))
+        return false;
+
+    // Insert global ID
+    // Usage: 102,<DEVICE/ID>,<SERIAL/NR>
+    if (!_tpl.add("10,102,POST,/identity/globalIds/%%/externalIds,application/vnd.com.nsn.cumulocity.externalId+json,application/vnd.com.nsn.cumulocity.externalId+json,%%,UNSIGNED STRING,\"{\"\"type\"\":\"\"c8y_Serial\"\",\"\"externalId\"\":\"\"%%\"\"}\"\r\n"))
+        return false;
+
+    // Update IMEI, CellId and iccid
+    // Usage: 103,<DEVICE/ID>,<IMEI>,<CELL/ID>,<ICCID>
+    if (!_tpl.add("10,103,PUT,/inventory/managedObjects/%%,application/vnd.com.nsn.cumulocity.managedObject+json,application/vnd.com.nsn.cumulocity.managedObject+json,%%,UNSIGNED STRING STRING STRING,\"{\"\"c8y_Mobile\"\":{\"\"imei\"\":\"\"%%\"\",\"\"cellId\"\":\"\"%%\"\",\"\"iccid\"\":\"\"%%\"\"}}\"\r\n"))
+        return false;
+
+    _init = true;
+    _deviceId = 0;
+    return true;
+}
+
+bool DeviceIntegration::integrate()
+{
+    if (_deviceId != 0)
+        return false;
+
+    // template bootstrapping process
+    if (_client.bootstrap(_tpl) != SMARTREST_SUCCESS) {
+        puts("Template bootstrap failed.");
+        return 1;
+    }
+
+    puts("Hello.");
+    if (!deviceExisting()) {
+        puts("Creating device.");
+        if (!createDevice()) {
+            puts("Failed.");
+            return false;
+        }
+        puts("Adding global identifier.");
+        if (!addGlobalIdentifier()) {
+            puts("Failed.");
+            return false;
+        }
+    }
+
+    puts("Updating device data.");
+    if (!updateDevice()) {
+        puts("Failed.");
+        return false;
+    }
+
+    return true;
+}
+
+bool DeviceIntegration::deviceExisting()
+{
+    ComposedRecord record;
+    ParsedRecord received;
+
+    IntegerValue msgId(100);
+    CharValue imei(_deviceInfo.imei());
+    if ((!record.add(msgId)) || (!record.add(imei)))
+        return false;
+
+    if (_client.send(record) != SMARTREST_SUCCESS) {
+        puts("Send failed.");
+        _client.stop();
+        return false;
+    }
+
+    if (_client.receive(received) != SMARTREST_SUCCESS) {
+        puts("No device found.");
+        _client.stop();
+        return false;
+    }
+    _client.stop();
+
+    if (received.values() == 0) {
+        puts("Received no values.");
+        return false;
+    }
+
+    if (received.value(0).integerValue() == 50) {
+        return false;
+    }
+    
+    if (received.value(0).integerValue() != 200) {
+        puts("Bad response.");
+        return false;
+    }
+
+    _deviceId = received.value(2).integerValue();
+    
+    return true;
+}
+
+bool DeviceIntegration::createDevice()
+{
+    ComposedRecord record;
+    ParsedRecord received;
+
+    puts("Creating device...");
+
+    IntegerValue msgId(101);
+    CharValue imei(_deviceInfo.imei());
+    if ((!record.add(msgId)) || (!record.add(imei)))
+        return false;
+
+    if (_client.send(record) != SMARTREST_SUCCESS) {
+        puts("Send failed.");
+        _client.stop();
+        return 0;
+    }
+
+    if (_client.receive(received) != SMARTREST_SUCCESS) {
+        puts("No device found.");
+        _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;
+    }
+
+    _deviceId = received.value(2).integerValue();
+    return true;
+}
+
+bool DeviceIntegration::addGlobalIdentifier()
+{
+    ComposedRecord record;
+    ParsedRecord received;
+
+    puts("Adding global identifier...");
+
+    IntegerValue msgId(102);
+    IntegerValue deviceId(_deviceId);
+    CharValue imei(_deviceInfo.imei());
+    if ((!record.add(msgId)) || (!record.add(deviceId)) || (!record.add(imei)))
+        return false;
+
+    if (_client.send(record) != SMARTREST_SUCCESS) {
+        puts("Sending failed.");
+        _client.stop();
+        return false;
+    }
+
+    if (_client.receive(received) != SMARTREST_SUCCESS) {
+        puts("Failed.");
+        _client.stop();
+        return false;
+    }
+    _client.stop();
+
+    if (received.values() != 3) {
+        puts("Received bad data.");
+        return false;
+    }
+    
+    if (received.value(0).integerValue() != 200) {
+        puts("Received bad data.");
+        return false;
+    }
+
+    return true;
+}
+
+bool DeviceIntegration::updateDevice()
+{
+    ComposedRecord record;
+    ParsedRecord received;
+
+    IntegerValue msgId(103);
+    IntegerValue deviceId(_deviceId);
+    CharValue imei(_deviceInfo.imei());
+    CharValue cellId(_deviceInfo.cellId());
+    CharValue iccid(_deviceInfo.iccid());
+    if ((!record.add(msgId)) || (!record.add(deviceId)) || (!record.add(imei)) || (!record.add(cellId)) || (!record.add(iccid)))
+        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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DeviceIntegration.h	Tue Jul 15 12:44:34 2014 +0000
@@ -0,0 +1,30 @@
+#ifndef DEVICEINTEGRATION_H
+#define DEVICEINTEGRATION_H
+
+#include "SmartRest.h"
+#include "SmartRestTemplate.h"
+#include "DeviceInfo.h"
+
+class DeviceIntegration
+{
+public:
+    DeviceIntegration(SmartRest&, SmartRestTemplate&, long&, DeviceInfo&);
+    
+    bool init();
+    bool integrate();
+
+protected:
+    bool deviceExisting();
+    bool createDevice();
+    bool addGlobalIdentifier();
+    bool updateDevice();
+
+private:
+    bool _init;
+    long& _deviceId;
+    SmartRestTemplate& _tpl;
+    SmartRest& _client;
+    DeviceInfo& _deviceInfo;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MbedAgent.cpp	Tue Jul 15 12:44:34 2014 +0000
@@ -0,0 +1,69 @@
+#include "MbedAgent.h"
+#include "rtos.h"
+
+MbedAgent::MbedAgent(MDMSerial& mdm, DeviceInfo& deviceInfo) :
+    _mdm(mdm),
+    _deviceInfo(deviceInfo),
+    _client(MBED_AGENT_HOST, MBED_AGENT_PORT, MBED_AGENT_DEVICE_IDENTIFIER),
+    _bootstrap(_client, _mdm, _deviceInfo),
+    _integration(_client, _tpl, _deviceId, _deviceInfo),
+    _signalQualityMeasurement(_client, _tpl, _deviceId, _deviceInfo),
+    _temperatureMeasurement(_client, _tpl, _deviceId, _io.temperatureSensor()),
+    _accelerationMeasurement(_client, _tpl, _deviceId, _io.accelerometer()),
+    _deviceId(0)
+{
+}
+
+bool MbedAgent::init()
+{
+    if ((!_integration.init()) ||
+        (!_signalQualityMeasurement.init()) ||
+        (!_temperatureMeasurement.init()) ||
+        (!_accelerationMeasurement.init())) {
+        puts("Initialization failed.");
+        return false;
+    }
+    return true;
+}
+
+bool MbedAgent::run()
+{
+    // device bootstrapping process
+    _io.lcdPrint("BOOTSTRAP", _deviceInfo.imei());
+    if (!_bootstrap.setUpCredentials()) {
+        puts("Could not obtain credentials.");
+        return false;
+    }
+
+    _io.lcdPrint("INTEGRATION");
+    if (!_integration.integrate()) {
+        puts("Device integration process failed.");
+        return false;
+    }
+    
+    char status[60];
+    snprintf(status, sizeof(status), "ID: %ld", _deviceId);
+    _io.lcdPrint("INTEGRATED", status);
+    puts(status);
+
+    loop();
+    return true;
+}
+
+void MbedAgent::loop()
+{
+    Timer timer;
+    
+    timer.start();
+    while (true) {
+        timer.reset();
+        
+        _signalQualityMeasurement.run();
+        _temperatureMeasurement.run();
+        _accelerationMeasurement.run();
+        
+        while (timer.read() < MBED_AGENT_INTERVAL) {
+            Thread::yield();
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MbedAgent.h	Tue Jul 15 12:44:34 2014 +0000
@@ -0,0 +1,46 @@
+#ifndef MBEDAGENT_H
+#define MBEDAGENT_H
+
+#include <stddef.h>
+#include "MDM.h"
+#include "DeviceIO.h"
+#include "MbedSmartRest.h"
+#include "SmartRestTemplate.h"
+#include "DeviceInfo.h"
+#include "DeviceBootstrap.h"
+#include "DeviceIntegration.h"
+#include "SignalQualityMeasurement.h"
+#include "TemperatureMeasurement.h"
+#include "AccelerationMeasurement.h"
+
+#define MBED_AGENT_HOST "developer.cumulocity.com"
+#define MBED_AGENT_PORT 80
+#define MBED_AGENT_DEVICE_IDENTIFIER "com_cumulocity_MbedAgent_1.0.0"
+#define MBED_AGENT_INTERVAL 60.0
+
+class MbedAgent
+{
+public:
+    MbedAgent(MDMSerial&, DeviceInfo&);
+    
+    bool init();
+    bool run();
+
+protected:
+    void loop();
+    
+private:
+    DeviceIO _io;
+    MDMSerial& _mdm;
+    DeviceInfo& _deviceInfo;
+    MbedSmartRest _client;
+    SmartRestTemplate _tpl;
+    DeviceBootstrap _bootstrap;
+    DeviceIntegration _integration;
+    SignalQualityMeasurement _signalQualityMeasurement;
+    TemperatureMeasurement _temperatureMeasurement;
+    AccelerationMeasurement _accelerationMeasurement;
+    long _deviceId;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SignalQualityMeasurement.cpp	Tue Jul 15 12:44:34 2014 +0000
@@ -0,0 +1,52 @@
+#include "SignalQualityMeasurement.h"
+#include "ComposedRecord.h"
+#include "CharValue.h"
+#include "IntegerValue.h"
+#include "FloatValue.h"
+
+SignalQualityMeasurement::SignalQualityMeasurement(SmartRest& client, SmartRestTemplate& tpl, long& deviceId, DeviceInfo& deviceInfo) :
+    _client(client),
+    _tpl(tpl),
+    _deviceId(deviceId),
+    _deviceInfo(deviceInfo)
+{
+    _init = false;
+}
+
+bool SignalQualityMeasurement::init()
+{
+    if (_init)
+        return false;
+    
+    // Insert measurement
+    // USAGE: 104,<DEVICE/ID>,<RSSI>,<BER>
+    if (!_tpl.add("10,104,POST,/measurement/measurements,application/vnd.com.nsn.cumulocity.measurement+json,application/vnd.com.nsn.cumulocity.measurement+json,%%,NOW UNSIGNED NUMBER UNSIGNED,\"{\"\"time\"\":\"\"%%\"\",\"\"source\"\":{\"\"id\"\":\"\"%%\"\"},\"\"type\"\":\"\"c8y_SignalStrength\"\",\"\"c8y_SignalStrength\"\":{\"\"rssi\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"dBm\"\"},\"\"ber\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"%\"\"}}}\"\r\n"))
+        return false;
+
+    _init = true;
+    return true;
+}
+
+bool SignalQualityMeasurement::run()
+{
+    DeviceInfo::SignalQuality *signalQuality;
+    
+    if ((signalQuality = _deviceInfo.signalQuality()) == NULL)
+        return false;
+        
+    ComposedRecord record;
+    IntegerValue msgId(104);
+    IntegerValue devId(_deviceId);
+    IntegerValue rssi(signalQuality->rssi);
+    IntegerValue ber(signalQuality->ber);
+    if ((!record.add(msgId)) || (!record.add(devId)) || (!record.add(rssi)) || (!record.add(ber)))
+        return false;
+
+    if (_client.send(record) != SMARTREST_SUCCESS) {
+        puts("Signal measurement failed.");
+        _client.stop();
+        return false;
+    }
+    _client.stop();
+    return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SignalQualityMeasurement.h	Tue Jul 15 12:44:34 2014 +0000
@@ -0,0 +1,24 @@
+#ifndef SIGNALQUALITYMEASUREMENT_H
+#define SIGNALQUALITYMEASUREMENT_H
+
+#include "SmartRest.h"
+#include "SmartRestTemplate.h"
+#include "DeviceInfo.h"
+
+class SignalQualityMeasurement
+{
+public:
+    SignalQualityMeasurement(SmartRest&, SmartRestTemplate&, long&, DeviceInfo&);
+    
+    bool init();
+    bool run();
+
+private:
+    bool _init;
+    long& _deviceId;
+    SmartRestTemplate& _tpl;
+    SmartRest& _client;
+    DeviceInfo& _deviceInfo;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TemperatureMeasurement.cpp	Tue Jul 15 12:44:34 2014 +0000
@@ -0,0 +1,50 @@
+#include "TemperatureMeasurement.h"
+#include "ComposedRecord.h"
+#include "CharValue.h"
+#include "IntegerValue.h"
+#include "FloatValue.h"
+
+TemperatureMeasurement::TemperatureMeasurement(SmartRest& client, SmartRestTemplate& tpl, long& deviceId, LM75B& sensor) :
+    _client(client),
+    _tpl(tpl),
+    _deviceId(deviceId),
+    _sensor(sensor)
+{
+    _init = false;
+}
+
+bool TemperatureMeasurement::init()
+{
+    if (_init)
+        return false;
+    
+    // Insert measurement
+    // USAGE: 105,<DEVICE/ID>,<TEMPERATURE>
+    if (!_tpl.add("10,105,POST,/measurement/measurements,application/vnd.com.nsn.cumulocity.measurement+json,application/vnd.com.nsn.cumulocity.measurement+json,%%,NOW UNSIGNED NUMBER,\"{\"\"time\"\":\"\"%%\"\",\"\"source\"\":{\"\"id\"\":\"\"%%\"\"},\"\"type\"\":\"\"c8y_TemperatureMeasurement\"\",\"\"c8y_TemperatureMeasurement\"\":{\"\"T\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"C\"\"}}}\"\r\n"))
+        return false;
+
+    _open = _sensor.open();
+    _init = true;
+    return true;
+}
+
+bool TemperatureMeasurement::run()
+{
+    if (!_open)
+        return false;
+
+    ComposedRecord record;
+    IntegerValue msgId(105);
+    IntegerValue devId(_deviceId);
+    FloatValue temperature(_sensor.temp(), 1);
+    if ((!record.add(msgId)) || (!record.add(devId)) || (!record.add(temperature)))
+        return false;
+
+    if (_client.send(record) != SMARTREST_SUCCESS) {
+        puts("Signal measurement failed.");
+        _client.stop();
+        return false;
+    }
+    _client.stop();
+    return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TemperatureMeasurement.h	Tue Jul 15 12:44:34 2014 +0000
@@ -0,0 +1,24 @@
+#ifndef TEMPERATUREMEASUREMENT_H
+#define TEMPERATUREMEASUREMENT_H
+
+#include "SmartRest.h"
+#include "SmartRestTemplate.h"
+#include "LM75B.h"
+
+class TemperatureMeasurement
+{
+public:
+    TemperatureMeasurement(SmartRest&, SmartRestTemplate&, long&, LM75B&);
+    
+    bool init();
+    bool run();
+
+private:
+    bool _init, _open;
+    long& _deviceId;
+    SmartRestTemplate& _tpl;
+    SmartRest& _client;
+    LM75B& _sensor;
+};
+
+#endif
\ No newline at end of file
--- a/common.h	Thu Jul 10 14:22:11 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-#ifndef COMMON_H
-#define COMMON_H
-
-#include <stdint.h>
-#include <stddef.h>
-#include "mbed.h"
-#include "C027.h"
-#include "MbedSmartRest.h"
-#include "rtos.h"
-
-#define CREDENTIALS_FILE "001_CREDENTIALS"
-#define CREDENTIALS_BUFFER 256
-
-#define A0  P0_23
-#define A1  P0_24
-#define A2  P0_25
-#define A3  P0_26
-#define A4  P0_30
-#define A5  P1_31
-
-#define D0  P4_29
-#define D1  P4_28
-#define D2  P2_13
-#define D3  P2_0
-#define D4  P2_12
-#define D5  P2_1
-#define D6  P2_2
-#define D7  P2_11
-
-#define D8  P2_4
-#define D9  P2_3
-#define D10 P1_21
-#define D11 P1_24
-#define D12 P1_23
-#define D13 P1_20
-    
-#define SDA P0_0
-#define SCL P0_1
-
-
-/** signal quality type */
-typedef struct
-{
-    int8_t rssi;  // RSSI in dBm
-    uint8_t ber; // BER in %
-} sigq_t;
-
-typedef struct
-{
-    char username[128];
-    char password[128];
-} credentials_t;
-
-extern C027 c027;
-//extern UbloxUSBGSMModem modem;
-extern MbedSmartRest client;
-
-const char * imei();
-const char * imsi();
-const char * cellId();
-const char * iccid();
-sigq_t * signalQuality();
-void credentials_set(credentials_t *dst, const char *tenant, const char *username, const char *password);
-bool credentials_read(credentials_t *dst);
-void credentials_write(credentials_t *src);
-void credentials_reset();
-int program(void);
-
-#endif
\ No newline at end of file
--- a/io.cpp	Thu Jul 10 14:22:11 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +0,0 @@
-#include "io.h"
-#include "rtos.h"
-#include "mbed.h"
-
-void timer_callback(void const*);
-void lcd_update(void);
-
-// Using Arduino pin notation
-C12832 lcdDisplay(D11, D13, D12, D7, D10);
-MMA7660 accSensor(SDA,SCL);
-LM75B tempSensor(SDA,SCL);
-DigitalOut button(D4);
-AnalogIn meter0(A0);
-AnalogIn meter1(A1);
-
-RtosTimer *timer;
-
-bool tempFound = false, accFound = false;
-uint32_t count = 0;
-bool btnPressed = false;
-
-char cSignal[80] = "", cTenant[80] = "", cStatus[80] = "";
-
-void io_init(void)
-{
-    timer = new RtosTimer(&timer_callback, osTimerPeriodic);
-    timer->start(50);
-    tempFound = tempSensor.open();
-    accFound = accSensor.testConnection();
-    
-    if (!tempFound)
-        puts("Temperature sensor not found.");
-    if (!accFound)
-        puts("Accelerometer not found.");
-    
-    lcd_update();
-}
-
-float temperature()
-{
-    if (!tempFound)
-        return 0.0;
-
-    return tempSensor.temp();
-}
-
-acceleration_t acceleration()
-{
-    float data[3];
-    acceleration_t ret = { 0.0, 0.0, 0.0 };
-
-    if (accFound) {
-        accSensor.readData(data);
-        ret.x = data[0];
-        ret.y = data[1];
-        ret.z = data[2];
-    }
-
-    return ret;
-}
-
-uint32_t counter()
-{
-    return count;
-}
-
-double potentiometer(uint8_t n)
-{
-    switch (n) {
-        case 0: return (double)meter0;
-        case 1: return (double)meter1;
-        default: return 0.0;
-    }
-}
-
-void lcd_signal(int8_t rssi, uint8_t ber)
-{
-    if ((rssi == 0) && (ber == 0))
-        snprintf(cSignal, 80, "%s", "No signal");
-    else
-        snprintf(cSignal, 80, "RSSI: %d dBm  BER: %d %%", rssi, ber);
-    lcd_update();
-}
-
-void lcd_tenant(const char* tenant)
-{
-    snprintf(cTenant, 80, "Tenant: %s", tenant);
-    lcd_update();
-}
-
-void lcd_status(const char* status)
-{
-    snprintf(cStatus, 80, "%s", status);
-    lcd_update();
-}
-
-void timer_callback(void const*)
-{
-    if ((!btnPressed) && (button))
-        count++;
-    btnPressed = button;
-}
-
-void lcd_update(void)
-{
-    lcdDisplay.cls();
-    lcdDisplay.locate(0, 0);
-    lcdDisplay.printf("%s\n%s\n%s\n", cSignal, cTenant, cStatus);
-}
--- a/io.h	Thu Jul 10 14:22:11 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#ifndef IO_H
-#define IO_H
-
-#include "common.h"
-#include "LM75B.h"
-#include "MMA7660.h"
-#include "C12832.h"
-
-typedef struct
-{
-    float x, y, z;
-} acceleration_t;
-
-void io_init(void);
-float temperature();
-acceleration_t acceleration();
-uint32_t counter();
-double potentiometer(uint8_t n);
-void lcd_signal(int8_t rssi, uint8_t ber);
-void lcd_tenant(const char* tenant);
-void lcd_status(const char* status);
-
-#endif
\ No newline at end of file
--- a/main.cpp	Thu Jul 10 14:22:11 2014 +0000
+++ b/main.cpp	Tue Jul 15 12:44:34 2014 +0000
@@ -1,26 +1,16 @@
-#include "common.h"
+#include "mbed.h"
+#include "rtos.h"
+#include "MDM.h"
+#include "DeviceInfo.h"
+#include "MbedAgent.h"
 #include "apndb.h"
-#include "io.h"
-
-C027 c027;
-MDMSerial* pMdm;
-sigq_t sigQ = {};
-char cCellId[8+1];
-MDMParser::DevStatus devStatus = {};
-MDMParser::NetStatus netStatus = {};
 
 int main()
 {
-    int ret; size_t c;
-    
-    puts("Hello");
-
-    io_init();
-    puts("IO initialized.");
+    MDMParser::DevStatus devStatus;
 
     MDMSerial mdm;
     //mdm.setDebug(4);
-    pMdm = &mdm;
 
     if (!mdm.init(NULL, &devStatus)) {
         puts("Modem initialization failed. Check your PIN number.");
@@ -38,7 +28,7 @@
     printf("IMEI: %s\n", devStatus.imei);
     printf("IMSI: %s\n", devStatus.imsi);
 
-    if (!mdm.registerNet(&netStatus)) {
+    if (!mdm.registerNet()) {
         puts("Network registration failed.");
         return 1;
     }
@@ -50,116 +40,29 @@
         return 1;
     }
     
-    // Shown on display
-    signalQuality();
+    DeviceInfo deviceInfo(mdm, devStatus);
+    MbedAgent agent(mdm, deviceInfo);
 
-    puts("Starting program...");    
+    puts("Starting agent ...");
+    if (!agent.init()) {
+        puts("Initialization failure.");
+        mdm.disconnect();
+        return 1;
+    }
     
-    // restart program upon failure
+    size_t tries = 3;
+
     do {
-        ret = program();
-        if (ret)
-            puts("Restarting program...");
-    } while (ret);
+        puts("Running agent ...");
+
+        if (!agent.run()) {
+            puts("Agent failure.");
+            continue;
+        } else {
+            break;
+        }
+    } while (--tries > 0);
     
     mdm.disconnect();
-    c027.mdmPower(false);
-    
     return 0;
 }
-
-const char * imei()
-{
-    return devStatus.imei;
-}
-
-const char * imsi()
-{
-    return devStatus.imsi;
-}
-
-const char * cellId()
-{
-    if (!pMdm->checkNetStatus(&netStatus))
-        return NULL;
-
-    if (snprintf(cCellId, sizeof(cCellId), "%X", netStatus.ci) < 1)
-        return NULL;
-        
-    return cCellId;
-}
-
-const char * iccid()
-{
-    return devStatus.ccid;
-}
-
-sigq_t * signalQuality()
-{
-    sigQ.rssi = 0; sigQ.ber = 0;
-    if (!pMdm->checkNetStatus(&netStatus))
-        return NULL;
-
-    sigQ.rssi = netStatus.rssi;
-    sigQ.ber = netStatus.ber;
-    
-    lcd_signal(sigQ.rssi, sigQ.ber);
-    return &sigQ;
-}
-
-void credentials_set(credentials_t *dst, const char *tenant, const char *username, const char *password)
-{
-    char *ptr = dst->username;
-    
-    strcpy(ptr, tenant);
-    ptr += strlen(tenant);
-    strcpy(ptr++, "/");
-    strcpy(ptr, username);
-    strcpy(dst->password, password);
-}
-
-bool credentials_read(credentials_t *dst)
-{
-    char buf[CREDENTIALS_BUFFER], *ptr;
-
-    int res =  pMdm->readFile(CREDENTIALS_FILE, buf, CREDENTIALS_BUFFER);
-
-    if (res < 0)
-        return false;
-        
-    buf[res] = '\0';
-    if ((ptr = strchr(buf, '\n')) == NULL)
-        return false;
-    *ptr = '\0';
-    
-    ptr = buf;
-    strcpy(dst->username, ptr);
-    ptr += strlen(ptr)+1;
-    strcpy(dst->password, ptr);
-    return true;
-}
-
-void credentials_write(credentials_t *src)
-{
-    char buf[CREDENTIALS_BUFFER], *ptr;
-    size_t len;
-
-    ptr = buf;
-    len = strlen(src->username);
-    strcpy(ptr, src->username);
-    ptr += len;
-    
-    *ptr++ = '\n';
-    len++;
-    
-    len += strlen(src->password);
-    strcpy(ptr, src->password);
-    
-    pMdm->delFile(CREDENTIALS_FILE);
-    pMdm->writeFile(CREDENTIALS_FILE, buf, len);
-}
-
-void credentials_reset()
-{
-    pMdm->delFile(CREDENTIALS_FILE);
-}
--- a/program.cpp	Thu Jul 10 14:22:11 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,422 +0,0 @@
-#include "common.h"
-#include "io.h"
-#include "StaticData.h"
-#include "ComposedRecord.h"
-#include "CharValue.h"
-#include "IntegerValue.h"
-#include "FloatValue.h"
-#include "Aggregator.h"
-
-/************* CONFIGURATION *************/
-
-/* Credentials for device bootstrap authentification. */
-#define DEVICEBOOTSTRAP_USERNAME "management/devicebootstrap"
-#define DEVICEBOOTSTRAP_PASSWORD "Fhdt1bb1f"
-
-/* Uncomment and fill in credentials to turn off device bootstrapping. */
-//#define CREDENTIALS_USERNAME ""
-//#define CREDENTIALS_PASSWORD ""
-
-/* Template device identifier */
-#define TEMPLATE_DEVICE_IDENTIFIER "com_u-blox_C027_REV-A_0.10_Test1233123"
-
-/*****************************************/
-
-bool deviceBootstrap();
-long existing();
-long create();
-bool identify(long deviceId);
-bool update(long deviceId);
-void loop(long deviceId);
-void signalMeasurement(long deviceId, Aggregator& aggr);
-void temperatureMeasurement(long deviceId, Aggregator& aggr);
-void analogMeasurement(long deviceId, Aggregator& aggr);
-void motionMeasurement(long deviceId, Aggregator& aggr);
-
-credentials_t credentials = {};
-
-StaticData srtpl(
-// get device by identity
-// Usage: 100,<SERIAL/NR>
-"10,100,GET,/identity/externalIds/c8y_Serial/%%,,application/vnd.com.nsn.cumulocity.externalId+json,%%,STRING,\r\n"
-// get device id from identity
-// Response: 200,<DEVICE/ID>
-"11,200,\"$.managedObject\",,\"$.id\"\r\n"
-// Create device
-// Usage: 101,<SERIAL/NR>
-"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_RequiredAvailability\"\":{ \"\"responseInterval\"\":15},\"\"c8y_IsDevice\"\":{}}\"\r\n"
-// Get device id
-// Response: 201,<DEVICE/ID>
-"11,201,,\"$.c8y_IsDevice\",\"$.id\"\r\n"
-// Insert global ID
-// Usage: 102,<DEVICE/ID>,<SERIAL/NR>
-"10,102,POST,/identity/globalIds/%%/externalIds,application/vnd.com.nsn.cumulocity.externalId+json,application/vnd.com.nsn.cumulocity.externalId+json,%%,UNSIGNED STRING,\"{\"\"type\"\":\"\"c8y_Serial\"\",\"\"externalId\"\":\"\"%%\"\"}\"\r\n"
-// Update IMEI, CellId and iccid
-// Usage: 103,<DEVICE/ID>,<IMEI>,<CELL/ID>,<ICCID>
-"10,103,PUT,/inventory/managedObjects/%%,application/vnd.com.nsn.cumulocity.managedObject+json,application/vnd.com.nsn.cumulocity.managedObject+json,%%,UNSIGNED STRING STRING STRING,\"{\"\"c8y_Mobile\"\":{\"\"imei\"\":\"\"%%\"\",\"\"cellId\"\":\"\"%%\"\",\"\"iccid\"\":\"\"%%\"\"}}\"\r\n"
-// Insert measurement
-// USAGE: 104,<DEVICE/ID>,<RSSI>,<BER>
-"10,104,POST,/measurement/measurements,application/vnd.com.nsn.cumulocity.measurement+json,application/vnd.com.nsn.cumulocity.measurement+json,%%,NOW UNSIGNED NUMBER UNSIGNED,\"{\"\"time\"\":\"\"%%\"\",\"\"source\"\":{\"\"id\"\":\"\"%%\"\"},\"\"type\"\":\"\"c8y_SignalStrength\"\",\"\"c8y_SignalStrength\"\":{\"\"rssi\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"dBm\"\"},\"\"ber\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"%\"\"}}}\"\r\n"
-// Insert measurement
-// USAGE: 105,<DEVICE/ID>,<TEMPERATURE>
-"10,105,POST,/measurement/measurements,application/vnd.com.nsn.cumulocity.measurement+json,application/vnd.com.nsn.cumulocity.measurement+json,%%,NOW UNSIGNED NUMBER,\"{\"\"time\"\":\"\"%%\"\",\"\"source\"\":{\"\"id\"\":\"\"%%\"\"},\"\"type\"\":\"\"c8y_TemperatureMeasurement\"\",\"\"c8y_TemperatureMeasurement\"\":{\"\"T\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"C\"\"}}}\"\r\n"
-// Insert measurement
-// USAGE: 105,<DEVICE/ID>,<ANALOG0>,<ANALOG1>
-"10,106,POST,/measurement/measurements,application/vnd.com.nsn.cumulocity.measurement+json,application/vnd.com.nsn.cumulocity.measurement+json,%%,NOW UNSIGNED UNSIGNED UNSIGNED,\"{\"\"time\"\":\"\"%%\"\",\"\"source\"\":{\"\"id\"\":\"\"%%\"\"},\"\"type\"\":\"\"c8y_AnalogMeasurement\"\",\"\"c8y_AnalogMeasurement\"\":{\"\"analog0\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"%\"\"},\"\"analog1\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"%\"\"}}}\"\r\n"
-// Insert measurement
-// USAGE: 105,<DEVICE/ID>,<X>,<Y>,<Z>
-"10,107,POST,/measurement/measurements,application/vnd.com.nsn.cumulocity.measurement+json,application/vnd.com.nsn.cumulocity.measurement+json,%%,NOW UNSIGNED NUMBER NUMBER NUMBER,\"{\"\"time\"\":\"\"%%\"\",\"\"source\"\":{\"\"id\"\":\"\"%%\"\"},\"\"type\"\":\"\"c8y_MotionMeasurement\"\",\"\"c8y_MotionMeasurement\"\":{\"\"x\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"m^2/s\"\"},\"\"y\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"m^2/s\"\"},\"\"z\"\":{\"\"value\"\":%%,\"\"unit\"\":\"\"m^2/s\"\"}}}\"\r\n"
-);
-
-float interval = 120.0; // send measurements every two minutes
-
-MbedSmartRest client("developer.cumulocity.com", 80, TEMPLATE_DEVICE_IDENTIFIER);
-
-int program(void)
-{
-    long deviceId = 0; Timer timer;
-
-#ifndef CREDENTIALS_USERNAME
-    // read credentials from modem or make a device bootstrapping
-    if (!credentials_read(&credentials)) {
-        puts("Could not read credentials. Starting bootstrapping process.");
-        if (!deviceBootstrap()) {
-            puts("Device bootstrap failed.");
-            return 1;
-        }
-    }
-    client.setAuthorization(credentials.username, credentials.password);
-#else
-    client.setAuthorization(CREDENTIALS_USERNAME, CREDENTIALS_PASSWORD);
-#endif
-    
-    lcd_tenant(credentials.username);
-    puts("Hello!");
-    
-    puts("Bootstrapping");
-    lcd_status("Bootstrapping");
-    if (client.bootstrap(srtpl) != SMARTREST_SUCCESS) {
-        puts("Bootstrapping failed.");
-        lcd_status("Bootstrapping failed.");
-        return 2;
-    }
-   
-    puts("Starting action...");
-    
-    if ((deviceId = existing()) == 0) {
-        if (((deviceId = create()) == 0) || (!identify(deviceId))) {
-            lcd_status("Device creation failed.");
-            return 1;
-        }
-    }
-    update(deviceId);
-    printf("Device ID: %ld\r\n", deviceId);
-
-    timer.start();
-    while (true) {
-        timer.reset();
-        loop(deviceId);
-
-        lcd_status("Sleeping...");
-        // block remaining number of seconds
-        while (timer.read() < interval) {
-            Thread::yield();
-        }
-    }
-}
-
-bool deviceBootstrap()
-{
-    uint8_t ret;
-    
-    ComposedRecord record;
-    ParsedRecord received;
-    
-    IntegerValue msgId(60);
-    CharValue identifier(imei());
-    if ((!record.add(msgId)) || (!record.add(identifier)))
-        return false;
-
-    // copy credentials
-    client.setAuthorization(DEVICEBOOTSTRAP_USERNAME, DEVICEBOOTSTRAP_PASSWORD);
-    
-    while (true) {
-        if (client.send(record, "") != SMARTREST_SUCCESS) {
-            puts("Connection unsuccessful. Retrying.");
-            client.stop();
-            Thread::wait(2000);
-            continue;
-        }
-        
-        if (client.receive(received) != SMARTREST_SUCCESS) {
-            puts("Not received anything. Retrying.");
-            client.stop();
-            Thread::wait(2000);
-            continue;
-        }
-        client.stop();
-        
-        if (received.values() < 1) {
-            puts("Bad received values. Retrying.");
-            Thread::wait(2000);
-            continue;
-        }
-        
-        if (received.value(0).integerValue() == 50) {
-            puts("No credentials available yet. Retrying.");
-            Thread::wait(2000);
-            continue;
-        }
-        
-        if (received.value(0).integerValue() != 70) {
-            puts("Unknown received message identifier.");
-            return false;
-        }
-        
-        if (received.values() != 6) {
-            puts("Bad credentials received.");
-            return false;
-        }
-        
-        credentials_set(&credentials, received.value(3).characterValue(), received.value(4).characterValue(), received.value(5).characterValue());
-        
-        printf("Username: %s\nPassword: %s\n", credentials.username, credentials.password);
-        
-        credentials_write(&credentials);
-        
-        return true;
-    }
-}
-
-long existing()
-{
-    ComposedRecord newMoRec(true); // set copy=true b/c tmp objects
-    ParsedRecord received;
-
-    lcd_status("Checking device existance...");
-    puts("Checking for device existance...");
-
-    if ((!newMoRec.add(IntegerValue(100))) || (!newMoRec.add(CharValue(imei()))))
-        return 0;
-
-    if (client.send(newMoRec) != SMARTREST_SUCCESS) {
-        puts("Send failed.");
-        client.stop();
-        return 0;
-    }
-
-    if (client.receive(received) != SMARTREST_SUCCESS) {
-        puts("No device found.");
-        client.stop();
-        return 0;
-    }
-
-    if (received.values() == 0) {
-        puts("Received no values.");
-        client.stop();
-        return 0;
-    }
-
-    if (received.value(0).integerValue() == 50) {
-        client.stop();
-        return 0;
-    }
-    
-    if (received.value(0).integerValue() != 200) {
-        puts("Bad response.");
-        client.stop();
-        return 0;
-    }
-
-    client.stop();
-    return received.value(2).integerValue();
-}
-
-long create()
-{
-    ComposedRecord newMoRec(true); // set copy=true b/c tmp objects
-    ParsedRecord received;
-
-    lcd_status("Creating device...");
-    puts("Creating device...");
-
-    if ((!newMoRec.add(IntegerValue(101))) || (!newMoRec.add(CharValue(imei()))))
-        return 0;
-
-    if (client.send(newMoRec) != SMARTREST_SUCCESS) {
-        puts("Send failed.");
-        client.stop();
-        return 0;
-    }
-
-    if (client.receive(received) != SMARTREST_SUCCESS) {
-        puts("No device found.");
-        client.stop();
-        return 0;
-    }
-
-    if (received.values() != 3) {
-        puts("Bad received data.");
-        client.stop();
-        return 0;
-    }
-    
-    if (received.value(0).integerValue() != 201) {
-        puts("Bad received data.");
-        client.stop();
-        return 0;
-    }
-
-    client.stop();
-    return received.value(2).integerValue();
-}
-
-bool identify(long deviceId)
-{
-    ComposedRecord newMoRec(true); // set copy=true b/c tmp objects
-    ParsedRecord received;
-
-    puts("Adding global identifier...");
-
-    if ((!newMoRec.add(IntegerValue(102))) || (!newMoRec.add(IntegerValue(deviceId))) || (!newMoRec.add(CharValue(imei()))))
-        return 0;
-
-    if (client.send(newMoRec) != SMARTREST_SUCCESS) {
-        puts("Sending failed.");
-        client.stop();
-        return false;
-    }
-
-    if (client.receive(received) != SMARTREST_SUCCESS) {
-        puts("Failed.");
-        client.stop();
-        return false;
-    }
-
-    if (received.values() != 3) {
-        puts("Received bad data.");
-        client.stop();
-        return false;
-    }
-    
-    if (received.value(0).integerValue() != 200) {
-        puts("Received bad data.");
-        client.stop();
-        return false;
-    }
-
-    client.stop();
-    return true;
-}
-
-bool update(long deviceId)
-{
-    ComposedRecord newMoRec(true); // set copy=true b/c tmp objects
-    ParsedRecord received;
-
-    lcd_status("Updating device object...");
-    puts("Updating device data...");
-
-    if ((!newMoRec.add(IntegerValue(103))) || (!newMoRec.add(IntegerValue(deviceId))) || (!newMoRec.add(CharValue(imei()))) || (!newMoRec.add(CharValue(cellId()))) || (!newMoRec.add(CharValue(iccid()))))
-        return false;
-
-    if (client.send(newMoRec) != SMARTREST_SUCCESS) {
-        puts("Send failed.");
-        client.stop();
-        return false;
-    }
-
-    if (client.receive(received) != SMARTREST_SUCCESS) {
-        puts("Update failed.");
-        client.stop();
-        return false;
-    }
-
-    if (received.values() != 3) {
-        puts("Bad received data.");
-        client.stop();
-        return false;
-    }
-    
-    if (received.value(0).integerValue() != 201) {
-        puts("Bad received data.");
-        client.stop();
-        return false;
-    }
-
-    client.stop();
-    
-    return true;
-}
-
-void loop(long deviceId)
-{
-    Aggregator aggr(true);
-
-    lcd_status("Sending measurements...");
-    temperatureMeasurement(deviceId, aggr);
-    signalMeasurement(deviceId, aggr);
-    analogMeasurement(deviceId, aggr);
-    motionMeasurement(deviceId, aggr);
-
-    if (client.send(aggr) != SMARTREST_SUCCESS) {
-        puts("Loop send failed.");
-    }
-    client.stop();
-}
-
-void signalMeasurement(long deviceId, Aggregator& aggr)
-{
-    sigq_t *sq = signalQuality();
-    
-    if ((sq->rssi == 0) || (sq->ber == 0))
-        return;
-    
-    ComposedRecord measurement;
-    IntegerValue msgId(104);
-    IntegerValue devId(deviceId);
-    FloatValue rssi(sq->rssi, 0);
-    IntegerValue ber(sq->ber);
-    if ((!measurement.add(msgId)) || (!measurement.add(devId)) || (!measurement.add(rssi)) || (!measurement.add(ber)))
-        return;
-    aggr.add(measurement);
-}
-
-void temperatureMeasurement(long deviceId, Aggregator& aggr)
-{
-    ComposedRecord measurement;
-    IntegerValue msgId(105);
-    IntegerValue devId(deviceId);
-    FloatValue temp(temperature(), 1);
-    if ((!measurement.add(msgId)) || (!measurement.add(devId)) || (!measurement.add(temp)))
-        return;
-    aggr.add(measurement);
-}
-
-void analogMeasurement(long deviceId, Aggregator& aggr)
-{
-    long analog0 = (long)(potentiometer(0) * 100.0);
-    long analog1 = (long)(potentiometer(1) * 100.0);
-    ComposedRecord measurement;
-    IntegerValue msgId(106);
-    IntegerValue devId(deviceId);
-    IntegerValue an0(analog0);
-    IntegerValue an1(analog1);
-    if ((!measurement.add(msgId)) || (!measurement.add(devId)) || (!measurement.add(an0)) || (!measurement.add(an1)))
-        return;
-    aggr.add(measurement);
-}
-
-void motionMeasurement(long deviceId, Aggregator& aggr)
-{
-    acceleration_t acc = acceleration();
-    ComposedRecord measurement;
-    IntegerValue msgId(107);
-    IntegerValue devId(deviceId);
-    FloatValue x(acc.x, 2);
-    FloatValue y(acc.y, 2);
-    FloatValue z(acc.z, 2);
-    if ((!measurement.add(msgId)) || (!measurement.add(devId)) || (!measurement.add(x)) || (!measurement.add(y)) || (!measurement.add(z)))
-        return;
-    aggr.add(measurement);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utils/SmartRestTemplate.cpp	Tue Jul 15 12:44:34 2014 +0000
@@ -0,0 +1,39 @@
+#include "SmartRestTemplate.h"
+#include <string.h>
+
+SmartRestTemplate::SmartRestTemplate()
+{
+    _len = NULL;
+}
+
+bool SmartRestTemplate::add(const char *line)
+{
+    if (_len == SMARTREST_TEMPLATE_FIXED_SIZE)
+        return false;
+    _buffer[_len++] = line;
+}
+
+size_t SmartRestTemplate::writeTo(AbstractDataSink& sink) const
+{
+    size_t len = 0;
+    
+    for (size_t n = 0; n < _len; n++)
+        len += sink.write((char*)_buffer[n], strlen(_buffer[n]));
+    
+    return len;
+}
+
+size_t SmartRestTemplate::writtenLength() const
+{
+    size_t len = 0;
+    
+    for (size_t n = 0; n < _len; n++)
+        len += strlen(_buffer[n]);
+    
+    return len;
+}
+
+DataGenerator * SmartRestTemplate::copy() const
+{
+    return NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utils/SmartRestTemplate.h	Tue Jul 15 12:44:34 2014 +0000
@@ -0,0 +1,27 @@
+#ifndef SMARTRESTTEMPLATE_H
+#define SMARTRESTTEMPLATE_H
+
+#include "DataGenerator.h"
+
+#define SMARTREST_TEMPLATE_FIXED_SIZE 64
+
+/**
+ * A data generator implementation holding an array of template lines
+ * to send via .bootstrap().
+ */
+class SmartRestTemplate : public DataGenerator
+{
+public:
+    SmartRestTemplate();
+    bool add(const char*);
+    
+    size_t writeTo(AbstractDataSink&) const;
+    size_t writtenLength() const;
+    DataGenerator* copy() const;
+
+private:
+    const char *_buffer[SMARTREST_TEMPLATE_FIXED_SIZE];
+    size_t _len;
+};
+
+#endif
\ No newline at end of file