A simple interface to mbed Device Connector, where you just declare variables to push them to the cloud.

Dependents:   Wifi_Get_Test_V1 simple-mbed-client-example simple-client-app-shield simple-sensor-client

Fork of simple-mbed-client by Jan Jongboom

TL;DR? See simple-mbed-client-example to get started immediately.

This library is a simpler interface to mbed Client, making it trivial to expose sensors, actuators and other variables to the cloud. It does not require you to change how you write your code. You can take any local variable, swap it out for a call to Simple Mbed Client, and the variable will automatically be synchronised with mbed Cloud.

For example, here's how you expose the value of a light sensor to the cloud:

SimpleMbedClient client;

SimpleResourceInt light_value = client.define_resource("light/0/value", 0);     // create the var

AnalogIn light(A1);

void read_light_sensor() {
    // light_value behaves just like a normal variable that you can read and write to!
    light_value = light.read_u16();
}

// update every second
Ticker t;
t.attach(&read_light_sensor, 1.0f);

Setting up

First import this library to your project. As Simple Mbed Client also needs a way to talk to the outside world, you'll need a NetworkInterface-object. The easiest way is by using the easy-connect library, so add that to your project as well. See the easy-connect docs on how to specify the connectivity method.

We also need a way of authenticating with mbed Cloud. For this we need a security certificate. Go to mbed Cloud, and select 'GET MY DEVICE SECURITY CREDENTIALS'. Save the certificate as security.h in your project folder.

Now we can initiate Simple Mbed Client and connect it to the internet.

#include "mbed.h"
#include "security.h"
#include "easy-connect.h"
#include "simple-mbed-client.h"

SimpleMbedClient client;

DigitalOut led(LED1, 0);

void registered() {
    led = 1;
}

int main() {
    NetworkInterface* network = connect_to_network(); // if connection failed, network will be NULL
    client.setup(network); // returns a bool, check if it's true

    client.on_registered(&registered);

    while (1) {
        wait_ms(25000);
        client.keep_alive();
    }
}

Defining variables

You can define a new variable by a call to client.define_resource. This function takes five arguments:

  1. path - The URL on which your variable is exposed in mbed Cloud. Needs to be three (3) segments, split by a slash (/) in the form of 'sensor/0/value'. The second segment always needs to be numeric.
  2. defaultValue - The default value of the variable. Needs to be either a string or an integer. Depending on the type that you pass in here the type of the variable is defined.
  3. operation - Some variables might be read-only or write-only (seen from the cloud). Use the operation to define these constraints. It's of type M2MBase::Operation. Default is GET_PUT_ALLOWED.
  4. observable - If set to false, cloud applications cannot subscribe to updates on this variable. Default is true.
  5. callback - Function pointer which is called whenever the value of the variable is changed from the cloud.

The type returned by the function is either SimpleResourceInt or SimpleResourceString. You can assign and read from these variables like any normal local variable.

void name_updated(string new_value) {
    printf("Value is now %s\n", new_value.c_str());
}

SimpleResourceString name = client.define_resource("device/0/name", "jan", M2MBase::GET_PUT_ALLOWED, true, &name_updated);

// we can read and write to this variable, e.g.:
stringstream ss;
ss << name;

// or
name = "pietje";

// are all valid

Defining functions

You can define functions, which do not have a value, but can just be invoked from the cloud, by a call to client.define_function. This function takes two arguments:

  1. path - The URL on which your variable is exposed in mbed Cloud. Needs to be three (3) segments, split by a slash (/) in the form of 'sensor/0/value'. The second segment always needs to be numeric.
  2. callback - Function pointer which is invoked when the function is called. Takes in a pointer, which contains the data being passed in from the cloud.

void play(void* data) {
    if (data) { // data can be NULL!
        // cast it to something useful
    }
}

client.define_function("music/0/play", &play);

Accessing the underlying M2MResource

If you need access to the underlying M2MResource you can do so by calling get_resource on a variable, or by calling client.get_resource if it's a function.

SimpleResourceInt led = client.define_resource("led/0/value", true);

client.define_function("led/0/toggle", &toggleLed);

// now to get the resource
M2MResource* ledResource = led.get_resource();
M2MResource* toggleResource = client.get_resource("led/0/toggle");

Printing variables

Unfortunately printf is kind of dumb, and does not automatically cast the variables. If you want to print any of the Simple Mbed Client variables you'll need to cast yourself.

SimpleResourceInt led = client.define_resource("led/0/value", true);

printf("Value is currently %d\n", static_cast<int>(led));

Event Queue

Simple Mbed Client uses an mbed-events EventQueue - running on a separate RTOS thread - to handle incoming events without blocking the main loop. Both the thread and event queue are created when initializing the library. You can override this behavior by providing your own event queue. In this case no thread is created.

EventQueue myQueue;
SimpleMbedClient client(&myQueue);

You can also use the queue to process your own events, which is very useful when dealing with ISRs. The queue is accessible through the eventQueue() function on the client object and returns a pointer to the queue.

SimpleMbedClient client;

InterruptIn btn(D2);

int main() {
  btn.fall(client.eventQueue()->event(&fall));
}
Committer:
Jan Jongboom
Date:
Tue Feb 07 13:00:32 2017 +0100
Revision:
18:7b2882874f87
Parent:
17:200624714d15
Child:
19:cf570422d4dd
Add EventQueue, auto-update registration and make set() calls safe in ISR

Who changed what in which revision?

UserRevisionLine numberNew contents of line
janjongboom 0:9fa3f3028773 1 /*
janjongboom 0:9fa3f3028773 2 * Copyright (c) 2015 ARM Limited. All rights reserved.
janjongboom 0:9fa3f3028773 3 * SPDX-License-Identifier: Apache-2.0
janjongboom 0:9fa3f3028773 4 * Licensed under the Apache License, Version 2.0 (the License); you may
janjongboom 0:9fa3f3028773 5 * not use this file except in compliance with the License.
janjongboom 0:9fa3f3028773 6 * You may obtain a copy of the License at
janjongboom 0:9fa3f3028773 7 *
janjongboom 0:9fa3f3028773 8 * http://www.apache.org/licenses/LICENSE-2.0
janjongboom 0:9fa3f3028773 9 *
janjongboom 0:9fa3f3028773 10 * Unless required by applicable law or agreed to in writing, software
janjongboom 0:9fa3f3028773 11 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
janjongboom 0:9fa3f3028773 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
janjongboom 0:9fa3f3028773 13 * See the License for the specific language governing permissions and
janjongboom 0:9fa3f3028773 14 * limitations under the License.
janjongboom 0:9fa3f3028773 15 */
janjongboom 0:9fa3f3028773 16
janjongboom 0:9fa3f3028773 17 #ifndef __SIMPLE_MBED_CLIENT_H__
janjongboom 0:9fa3f3028773 18 #define __SIMPLE_MBED_CLIENT_H__
janjongboom 0:9fa3f3028773 19
Jan Jongboom 18:7b2882874f87 20 #define smc_debug_msg(...) if (debug) output.printf(__VA_ARGS__)
Jan Jongboom 3:ce2322965a27 21
janjongboom 0:9fa3f3028773 22 #include <map>
janjongboom 0:9fa3f3028773 23 #include <string>
janjongboom 0:9fa3f3028773 24 #include <vector>
janjongboom 0:9fa3f3028773 25 #include "mbed-client-wrapper.h"
janjongboom 0:9fa3f3028773 26
janjongboom 0:9fa3f3028773 27 using namespace std;
janjongboom 0:9fa3f3028773 28
Jan Jongboom 3:ce2322965a27 29 class SimpleResourceBase {
Jan Jongboom 3:ce2322965a27 30 public:
janjongboom 10:3fecd642d506 31 virtual void update(string v) {}
Jan Jongboom 18:7b2882874f87 32 virtual void clear_pending_value() {}
Jan Jongboom 3:ce2322965a27 33 };
Jan Jongboom 3:ce2322965a27 34
janjongboom 0:9fa3f3028773 35 class SimpleMbedClientBase {
janjongboom 0:9fa3f3028773 36 public:
Jan Jongboom 17:200624714d15 37
Jan Jongboom 3:ce2322965a27 38 SimpleMbedClientBase(bool aDebug = true)
Jan Jongboom 18:7b2882874f87 39 : output(USBTX, USBRX), evQueue(new EventQueue()), evThread(new Thread()), debug(aDebug)
Jan Jongboom 18:7b2882874f87 40 {
Jan Jongboom 18:7b2882874f87 41 evThread->start(callback(evQueue, &EventQueue::dispatch_forever));
Jan Jongboom 18:7b2882874f87 42 }
Jan Jongboom 18:7b2882874f87 43
Jan Jongboom 18:7b2882874f87 44 SimpleMbedClientBase(EventQueue* aQueue, bool aDebug = true)
Jan Jongboom 18:7b2882874f87 45 : output(USBTX, USBRX), evQueue(aQueue), debug(aDebug)
Jan Jongboom 3:ce2322965a27 46 {
Jan Jongboom 3:ce2322965a27 47
janjongboom 0:9fa3f3028773 48 }
Jan Jongboom 3:ce2322965a27 49
Jan Jongboom 18:7b2882874f87 50 ~SimpleMbedClientBase() {
Jan Jongboom 18:7b2882874f87 51 if (evThread) {
Jan Jongboom 18:7b2882874f87 52 delete evQueue;
Jan Jongboom 18:7b2882874f87 53 delete evThread;
Jan Jongboom 18:7b2882874f87 54 }
Jan Jongboom 18:7b2882874f87 55 // if no evThread then evQueue is not owned by us
Jan Jongboom 18:7b2882874f87 56 }
janjongboom 0:9fa3f3028773 57
janjongboom 0:9fa3f3028773 58 struct MbedClientOptions get_default_options() {
janjongboom 0:9fa3f3028773 59 struct MbedClientOptions options;
janjongboom 0:9fa3f3028773 60 options.Manufacturer = "Manufacturer_String";
janjongboom 0:9fa3f3028773 61 options.Type = "Type_String";
janjongboom 0:9fa3f3028773 62 options.ModelNumber = "ModelNumber_String";
janjongboom 0:9fa3f3028773 63 options.SerialNumber = "SerialNumber_String";
janjongboom 0:9fa3f3028773 64 options.DeviceType = "test";
Jan Jongboom 14:680c2a46cc8a 65 options.SocketMode = M2MInterface::TCP;
Jan Jongboom 17:200624714d15 66 #ifdef MBED_SERVER_ADDRESS
Jan Jongboom 17:200624714d15 67 options.ServerAddress = MBED_SERVER_ADDRESS;
Jan Jongboom 17:200624714d15 68 #else
janjongboom 0:9fa3f3028773 69 options.ServerAddress = "coap://api.connector.mbed.com:5684";
Jan Jongboom 17:200624714d15 70 #endif
Jan Jongboom 3:ce2322965a27 71
janjongboom 0:9fa3f3028773 72 return options;
janjongboom 0:9fa3f3028773 73 }
janjongboom 0:9fa3f3028773 74
Jan Jongboom 4:0f9eae5739dd 75 bool init(NetworkInterface* iface) {
Jan Jongboom 18:7b2882874f87 76 smc_debug_msg("[SMC] Device name %s\r\n", MBED_ENDPOINT_NAME);
Jan Jongboom 3:ce2322965a27 77
janjongboom 0:9fa3f3028773 78 // Create endpoint interface to manage register and unregister
Jan Jongboom 3:ce2322965a27 79 client->create_interface(iface);
Jan Jongboom 3:ce2322965a27 80
janjongboom 0:9fa3f3028773 81 // Create Objects of varying types, see simpleclient.h for more details on implementation.
janjongboom 0:9fa3f3028773 82 M2MSecurity* register_object = client->create_register_object(); // server object specifying connector info
janjongboom 0:9fa3f3028773 83 M2MDevice* device_object = client->create_device_object(); // device resources object
Jan Jongboom 3:ce2322965a27 84
janjongboom 0:9fa3f3028773 85 // Create list of Objects to register
janjongboom 0:9fa3f3028773 86 M2MObjectList object_list;
Jan Jongboom 3:ce2322965a27 87
janjongboom 0:9fa3f3028773 88 // Add objects to list
janjongboom 0:9fa3f3028773 89 object_list.push_back(device_object);
Jan Jongboom 3:ce2322965a27 90
janjongboom 0:9fa3f3028773 91 map<string, M2MObject*>::iterator it;
janjongboom 0:9fa3f3028773 92 for (it = objects.begin(); it != objects.end(); it++)
janjongboom 0:9fa3f3028773 93 {
janjongboom 0:9fa3f3028773 94 object_list.push_back(it->second);
janjongboom 0:9fa3f3028773 95 }
Jan Jongboom 3:ce2322965a27 96
janjongboom 0:9fa3f3028773 97 // Set endpoint registration object
janjongboom 0:9fa3f3028773 98 client->set_register_object(register_object);
Jan Jongboom 3:ce2322965a27 99
janjongboom 0:9fa3f3028773 100 // Issue register command.
janjongboom 0:9fa3f3028773 101 client->test_register(register_object, object_list);
Jan Jongboom 3:ce2322965a27 102
Jan Jongboom 18:7b2882874f87 103 // Keep alive ticker (every 25 seconds)
Jan Jongboom 18:7b2882874f87 104 evQueue->call_every(MBED_CONF_SIMPLE_MBED_CLIENT_UPDATE_INTERVAL,
Jan Jongboom 18:7b2882874f87 105 callback(this, &SimpleMbedClientBase::keep_alive));
Jan Jongboom 18:7b2882874f87 106
janjongboom 0:9fa3f3028773 107 return true;
janjongboom 0:9fa3f3028773 108 }
janjongboom 0:9fa3f3028773 109
Jan Jongboom 4:0f9eae5739dd 110 bool setup(NetworkInterface* iface) {
Jan Jongboom 18:7b2882874f87 111 smc_debug_msg("[SMC] In mbed_client_setup\r\n");
janjongboom 0:9fa3f3028773 112 if (client) {
Jan Jongboom 18:7b2882874f87 113 smc_debug_msg("[SMC] [ERROR] mbed_client_setup called, but mbed_client is already instantiated\r\n");
janjongboom 0:9fa3f3028773 114 return false;
janjongboom 0:9fa3f3028773 115 }
Jan Jongboom 3:ce2322965a27 116
janjongboom 0:9fa3f3028773 117 struct MbedClientOptions options = get_default_options();
Jan Jongboom 3:ce2322965a27 118
Jan Jongboom 12:26810c6b58e1 119 Callback<void(string)> updateFp(this, &SimpleMbedClientBase::resource_updated);
Jan Jongboom 3:ce2322965a27 120 client = new MbedClient(options, updateFp, debug);
Jan Jongboom 3:ce2322965a27 121
janjongboom 0:9fa3f3028773 122 return init(iface);
janjongboom 0:9fa3f3028773 123 }
janjongboom 0:9fa3f3028773 124
Jan Jongboom 4:0f9eae5739dd 125 bool setup(MbedClientOptions options, NetworkInterface* iface) {
janjongboom 0:9fa3f3028773 126 if (client) {
Jan Jongboom 18:7b2882874f87 127 smc_debug_msg("[SMC] [ERROR] mbed_client_setup called, but mbed_client is already instantiated\r\n");
janjongboom 0:9fa3f3028773 128 return false;
janjongboom 0:9fa3f3028773 129 }
Jan Jongboom 3:ce2322965a27 130
Jan Jongboom 12:26810c6b58e1 131 Callback<void(string)> updateFp(this, &SimpleMbedClientBase::resource_updated);
Jan Jongboom 3:ce2322965a27 132 client = new MbedClient(options, updateFp, debug);
Jan Jongboom 3:ce2322965a27 133
janjongboom 0:9fa3f3028773 134 return init(iface);
janjongboom 0:9fa3f3028773 135 }
janjongboom 0:9fa3f3028773 136
janjongboom 0:9fa3f3028773 137 void on_registered(void(*fn)(void)) {
Jan Jongboom 12:26810c6b58e1 138 Callback<void()> fp(fn);
janjongboom 0:9fa3f3028773 139 client->set_registered_function(fp);
janjongboom 0:9fa3f3028773 140 }
janjongboom 0:9fa3f3028773 141
Jan Jongboom 15:b7360c7e0f7f 142 void on_registered(Callback<void()> fp) {
Jan Jongboom 15:b7360c7e0f7f 143 client->set_registered_function(fp);
Jan Jongboom 15:b7360c7e0f7f 144 }
Jan Jongboom 15:b7360c7e0f7f 145
janjongboom 0:9fa3f3028773 146 template<typename T>
Jan Jongboom 3:ce2322965a27 147 void on_registered(T *object, void (T::*member)(void)) {
Jan Jongboom 12:26810c6b58e1 148 Callback<void()> fp(object, member);
janjongboom 0:9fa3f3028773 149 client->set_registered_function(fp);
janjongboom 0:9fa3f3028773 150 }
janjongboom 0:9fa3f3028773 151
janjongboom 0:9fa3f3028773 152 void on_unregistered(void(*fn)(void)) {
Jan Jongboom 12:26810c6b58e1 153 Callback<void()> fp(fn);
janjongboom 0:9fa3f3028773 154 client->set_unregistered_function(fp);
janjongboom 0:9fa3f3028773 155 }
janjongboom 0:9fa3f3028773 156
Jan Jongboom 15:b7360c7e0f7f 157 void on_unregistered(Callback<void()> fp) {
Jan Jongboom 15:b7360c7e0f7f 158 client->set_unregistered_function(fp);
Jan Jongboom 15:b7360c7e0f7f 159 }
Jan Jongboom 15:b7360c7e0f7f 160
janjongboom 0:9fa3f3028773 161 template<typename T>
Jan Jongboom 3:ce2322965a27 162 void on_unregistered(T *object, void (T::*member)(void)) {
Jan Jongboom 12:26810c6b58e1 163 Callback<void()> fp(object, member);
janjongboom 0:9fa3f3028773 164 client->set_unregistered_function(fp);
janjongboom 0:9fa3f3028773 165 }
janjongboom 0:9fa3f3028773 166
janjongboom 0:9fa3f3028773 167 bool define_function(const char* route, void(*fn)(void*)) {
janjongboom 0:9fa3f3028773 168 if (!define_resource_internal(route, string(), M2MBase::POST_ALLOWED, false)) {
janjongboom 0:9fa3f3028773 169 return false;
janjongboom 0:9fa3f3028773 170 }
Jan Jongboom 3:ce2322965a27 171
janjongboom 0:9fa3f3028773 172 string route_str(route);
janjongboom 0:9fa3f3028773 173 if (!resources.count(route_str)) {
Jan Jongboom 18:7b2882874f87 174 smc_debug_msg("[SMC] [ERROR] Should be created, but no such route (%s)\r\n", route);
janjongboom 0:9fa3f3028773 175 return false;
janjongboom 0:9fa3f3028773 176 }
Jan Jongboom 3:ce2322965a27 177
Jan Jongboom 3:ce2322965a27 178 resources[route_str]->set_execute_function(execute_callback_2(fn));
janjongboom 0:9fa3f3028773 179 return true;
janjongboom 0:9fa3f3028773 180 }
janjongboom 0:9fa3f3028773 181
janjongboom 0:9fa3f3028773 182 bool define_function(const char* route, execute_callback fn) {
janjongboom 0:9fa3f3028773 183 if (!define_resource_internal(route, string(), M2MBase::POST_ALLOWED, false)) {
janjongboom 0:9fa3f3028773 184 return false;
janjongboom 0:9fa3f3028773 185 }
Jan Jongboom 3:ce2322965a27 186
janjongboom 0:9fa3f3028773 187 string route_str(route);
janjongboom 0:9fa3f3028773 188 if (!resources.count(route_str)) {
Jan Jongboom 18:7b2882874f87 189 smc_debug_msg("[SMC] [ERROR] Should be created, but no such route (%s)\r\n", route);
janjongboom 0:9fa3f3028773 190 return false;
janjongboom 0:9fa3f3028773 191 }
janjongboom 0:9fa3f3028773 192 // No clue why this is not working?! It works with class member, but not with static function...
janjongboom 0:9fa3f3028773 193 resources[route_str]->set_execute_function(fn);
janjongboom 0:9fa3f3028773 194 return true;
janjongboom 0:9fa3f3028773 195 }
Jan Jongboom 3:ce2322965a27 196
janjongboom 0:9fa3f3028773 197 string get(string route_str) {
janjongboom 0:9fa3f3028773 198 if (!resources.count(route_str)) {
Jan Jongboom 18:7b2882874f87 199 smc_debug_msg("[SMC] [ERROR] No such route (%s)\r\n", route_str.c_str());
janjongboom 0:9fa3f3028773 200 return string();
janjongboom 0:9fa3f3028773 201 }
Jan Jongboom 3:ce2322965a27 202
janjongboom 2:0a015df677a4 203 // otherwise ask mbed Client...
janjongboom 2:0a015df677a4 204 uint8_t* buffIn = NULL;
janjongboom 0:9fa3f3028773 205 uint32_t sizeIn;
janjongboom 0:9fa3f3028773 206 resources[route_str]->get_value(buffIn, sizeIn);
Jan Jongboom 3:ce2322965a27 207
janjongboom 2:0a015df677a4 208 string s((char*)buffIn, sizeIn);
janjongboom 0:9fa3f3028773 209 return s;
janjongboom 0:9fa3f3028773 210 }
janjongboom 0:9fa3f3028773 211
Jan Jongboom 18:7b2882874f87 212 void set(string route_str, string v) {
Jan Jongboom 18:7b2882874f87 213 evQueue->call(callback(this, &SimpleMbedClientBase::internal_set_str), route_str, v);
janjongboom 0:9fa3f3028773 214 }
janjongboom 0:9fa3f3028773 215
Jan Jongboom 18:7b2882874f87 216 void set(string route_str, const int& v) {
Jan Jongboom 18:7b2882874f87 217 evQueue->call(callback(this, &SimpleMbedClientBase::internal_set_int), route_str, v);
janjongboom 0:9fa3f3028773 218 }
janjongboom 0:9fa3f3028773 219
Jan Jongboom 16:cb980bd39e32 220 bool define_resource_internal(const char* route, string v, M2MBase::Operation opr, bool observable) {
janjongboom 0:9fa3f3028773 221 if (client) {
Jan Jongboom 18:7b2882874f87 222 smc_debug_msg("[SMC] [ERROR] mbed_client_define_resource, Can only define resources before mbed_client_setup is called!\r\n");
janjongboom 0:9fa3f3028773 223 return false;
janjongboom 0:9fa3f3028773 224 }
Jan Jongboom 3:ce2322965a27 225
janjongboom 0:9fa3f3028773 226 vector<string> segments = parse_route(route);
janjongboom 0:9fa3f3028773 227 if (segments.size() != 3) {
Jan Jongboom 18:7b2882874f87 228 smc_debug_msg("[SMC] [ERROR] mbed_client_define_resource, Route needs to have three segments, split by '/' (%s)\r\n", route);
janjongboom 0:9fa3f3028773 229 return false;
janjongboom 0:9fa3f3028773 230 }
janjongboom 0:9fa3f3028773 231
Jan Jongboom 3:ce2322965a27 232 // segments[1] should be one digit and numeric
janjongboom 10:3fecd642d506 233 char n = segments.at(1).c_str()[0];
janjongboom 10:3fecd642d506 234 if (n < '0' || n > '9') {
Jan Jongboom 18:7b2882874f87 235 smc_debug_msg("[SMC] [ERROR] mbed_client_define_resource, second route segment should be numeric, but was not (%s)\r\n", route);
Jan Jongboom 3:ce2322965a27 236 return false;
Jan Jongboom 3:ce2322965a27 237 }
Jan Jongboom 3:ce2322965a27 238
Jan Jongboom 3:ce2322965a27 239 int inst_id = atoi(segments.at(1).c_str());
Jan Jongboom 3:ce2322965a27 240
janjongboom 0:9fa3f3028773 241 M2MObjectInstance* inst;
janjongboom 0:9fa3f3028773 242 if (objectInstances.count(segments.at(0))) {
janjongboom 0:9fa3f3028773 243 inst = objectInstances[segments.at(0)];
janjongboom 0:9fa3f3028773 244 }
janjongboom 0:9fa3f3028773 245 else {
janjongboom 0:9fa3f3028773 246 M2MObject* obj = M2MInterfaceFactory::create_object(segments.at(0).c_str());
janjongboom 0:9fa3f3028773 247 inst = obj->create_object_instance(inst_id);
janjongboom 0:9fa3f3028773 248 objects.insert(std::pair<string, M2MObject*>(segments.at(0), obj));
janjongboom 0:9fa3f3028773 249 objectInstances.insert(std::pair<string, M2MObjectInstance*>(segments.at(0), inst));
janjongboom 0:9fa3f3028773 250 }
Jan Jongboom 3:ce2322965a27 251
janjongboom 0:9fa3f3028773 252 // @todo check if the resource exists yet
janjongboom 0:9fa3f3028773 253 M2MResource* res = inst->create_dynamic_resource(segments.at(2).c_str(), "",
janjongboom 0:9fa3f3028773 254 M2MResourceInstance::STRING, observable);
janjongboom 0:9fa3f3028773 255 res->set_operation(opr);
janjongboom 0:9fa3f3028773 256 res->set_value((uint8_t*)v.c_str(), v.length());
Jan Jongboom 3:ce2322965a27 257
janjongboom 0:9fa3f3028773 258 string route_str(route);
janjongboom 2:0a015df677a4 259 resources.insert(pair<string, M2MResource*>(route_str, res));
Jan Jongboom 3:ce2322965a27 260
janjongboom 0:9fa3f3028773 261 return true;
janjongboom 0:9fa3f3028773 262 }
Jan Jongboom 3:ce2322965a27 263
Jan Jongboom 3:ce2322965a27 264 void register_update_callback(string route, SimpleResourceBase* simpleResource) {
Jan Jongboom 3:ce2322965a27 265 updateValues[route] = simpleResource;
Jan Jongboom 3:ce2322965a27 266 }
Jan Jongboom 3:ce2322965a27 267
Jan Jongboom 6:a1a766d45957 268 M2MResource* get_resource(string route) {
Jan Jongboom 6:a1a766d45957 269 if (!resources.count(route)) {
Jan Jongboom 18:7b2882874f87 270 smc_debug_msg("[SMC] [ERROR] No such route (%s)\r\n", route.c_str());
Jan Jongboom 6:a1a766d45957 271 return NULL;
Jan Jongboom 6:a1a766d45957 272 }
Jan Jongboom 6:a1a766d45957 273
Jan Jongboom 6:a1a766d45957 274 return resources[route];
Jan Jongboom 6:a1a766d45957 275 }
Jan Jongboom 6:a1a766d45957 276
Jan Jongboom 18:7b2882874f87 277 EventQueue* eventQueue() const {
Jan Jongboom 18:7b2882874f87 278 return evQueue;
Jan Jongboom 18:7b2882874f87 279 }
Jan Jongboom 18:7b2882874f87 280
janjongboom 0:9fa3f3028773 281 private:
janjongboom 0:9fa3f3028773 282 vector<string> parse_route(const char* route) {
Jan Jongboom 16:cb980bd39e32 283 const string s(route);
janjongboom 0:9fa3f3028773 284 vector<string> v;
Jan Jongboom 16:cb980bd39e32 285
Jan Jongboom 16:cb980bd39e32 286 split(s, '/', v);
Jan Jongboom 16:cb980bd39e32 287
Jan Jongboom 16:cb980bd39e32 288 return v;
Jan Jongboom 16:cb980bd39e32 289 }
Jan Jongboom 16:cb980bd39e32 290
Jan Jongboom 16:cb980bd39e32 291 void split(const string& s, char delim, vector<string>& v) {
Jan Jongboom 16:cb980bd39e32 292 size_t i = 0;
Jan Jongboom 16:cb980bd39e32 293 size_t pos = s.find(delim);
Jan Jongboom 16:cb980bd39e32 294 while (pos != string::npos) {
Jan Jongboom 16:cb980bd39e32 295 v.push_back(s.substr(i, pos - i));
Jan Jongboom 16:cb980bd39e32 296 i = ++pos;
Jan Jongboom 16:cb980bd39e32 297 pos = s.find(delim, pos);
Jan Jongboom 16:cb980bd39e32 298
Jan Jongboom 16:cb980bd39e32 299 if (pos == string::npos) {
Jan Jongboom 16:cb980bd39e32 300 v.push_back(s.substr(i, s.length()));
Jan Jongboom 16:cb980bd39e32 301 }
janjongboom 0:9fa3f3028773 302 }
janjongboom 0:9fa3f3028773 303 }
janjongboom 0:9fa3f3028773 304
Jan Jongboom 3:ce2322965a27 305 void resource_updated(string uri) {
Jan Jongboom 3:ce2322965a27 306 if (updateValues.count(uri) == 0) return;
Jan Jongboom 3:ce2322965a27 307
Jan Jongboom 3:ce2322965a27 308 string v = get(uri);
Jan Jongboom 3:ce2322965a27 309 if (v.empty()) return;
Jan Jongboom 3:ce2322965a27 310
Jan Jongboom 18:7b2882874f87 311 // Schedule this on the other thread, to avoid blocking this thread
Jan Jongboom 18:7b2882874f87 312 evQueue->call(callback(updateValues[uri], &SimpleResourceBase::update), v);
Jan Jongboom 18:7b2882874f87 313 }
Jan Jongboom 18:7b2882874f87 314
Jan Jongboom 18:7b2882874f87 315 // These operations have side effects, they should not be called immediately,
Jan Jongboom 18:7b2882874f87 316 // but always through the eventqueue
Jan Jongboom 18:7b2882874f87 317 void internal_set_str(string route_str, string v) {
Jan Jongboom 18:7b2882874f87 318 if (!resources.count(route_str)) {
Jan Jongboom 18:7b2882874f87 319 smc_debug_msg("[SMC] [ERROR] No such route (%s)\r\n", route_str.c_str());
Jan Jongboom 18:7b2882874f87 320 return;
Jan Jongboom 18:7b2882874f87 321 }
Jan Jongboom 18:7b2882874f87 322
Jan Jongboom 18:7b2882874f87 323 if (v.length() == 0) {
Jan Jongboom 18:7b2882874f87 324 resources[route_str]->clear_value();
Jan Jongboom 18:7b2882874f87 325 }
Jan Jongboom 18:7b2882874f87 326 else {
Jan Jongboom 18:7b2882874f87 327 resources[route_str]->set_value((uint8_t*)v.c_str(), v.length());
Jan Jongboom 18:7b2882874f87 328 }
Jan Jongboom 18:7b2882874f87 329
Jan Jongboom 18:7b2882874f87 330 updateValues[route_str]->clear_pending_value();
Jan Jongboom 18:7b2882874f87 331 }
Jan Jongboom 18:7b2882874f87 332
Jan Jongboom 18:7b2882874f87 333 void internal_set_int(string route, const int& v) {
Jan Jongboom 18:7b2882874f87 334 char str[13];
Jan Jongboom 18:7b2882874f87 335 sprintf(str, "%d", v);
Jan Jongboom 18:7b2882874f87 336
Jan Jongboom 18:7b2882874f87 337 internal_set_str(route, string(str));
Jan Jongboom 18:7b2882874f87 338 }
Jan Jongboom 18:7b2882874f87 339
Jan Jongboom 18:7b2882874f87 340 void keep_alive() {
Jan Jongboom 18:7b2882874f87 341 client->test_update_register();
Jan Jongboom 3:ce2322965a27 342 }
Jan Jongboom 3:ce2322965a27 343
janjongboom 0:9fa3f3028773 344 Serial output;
Jan Jongboom 3:ce2322965a27 345
janjongboom 0:9fa3f3028773 346 MbedClient* client;
janjongboom 0:9fa3f3028773 347 map<string, M2MObject*> objects;
janjongboom 0:9fa3f3028773 348 map<string, M2MObjectInstance*> objectInstances;
janjongboom 0:9fa3f3028773 349 map<string, M2MResource*> resources;
janjongboom 2:0a015df677a4 350
Jan Jongboom 18:7b2882874f87 351 EventQueue* evQueue;
Jan Jongboom 18:7b2882874f87 352 Thread* evThread;
Jan Jongboom 18:7b2882874f87 353
Jan Jongboom 3:ce2322965a27 354 bool debug;
Jan Jongboom 3:ce2322965a27 355
Jan Jongboom 3:ce2322965a27 356 map<string, SimpleResourceBase*> updateValues;
janjongboom 0:9fa3f3028773 357 };
janjongboom 0:9fa3f3028773 358
Jan Jongboom 3:ce2322965a27 359 class SimpleResourceString : public SimpleResourceBase {
janjongboom 0:9fa3f3028773 360 public:
Jan Jongboom 12:26810c6b58e1 361 SimpleResourceString(SimpleMbedClientBase* aSimpleClient, string aRoute, Callback<void(string)> aOnUpdate) :
Jan Jongboom 3:ce2322965a27 362 simpleClient(aSimpleClient), route(aRoute), onUpdate(aOnUpdate) {}
janjongboom 0:9fa3f3028773 363
janjongboom 0:9fa3f3028773 364 string operator=(const string& newValue) {
Jan Jongboom 18:7b2882874f87 365 pendingValue = newValue;
Jan Jongboom 18:7b2882874f87 366 hasPendingValue = true;
Jan Jongboom 18:7b2882874f87 367
janjongboom 0:9fa3f3028773 368 simpleClient->set(route, newValue);
janjongboom 0:9fa3f3028773 369 return newValue;
janjongboom 0:9fa3f3028773 370 };
Jan Jongboom 18:7b2882874f87 371
janjongboom 0:9fa3f3028773 372 operator string() const {
Jan Jongboom 18:7b2882874f87 373 if (hasPendingValue) {
Jan Jongboom 18:7b2882874f87 374 return pendingValue;
Jan Jongboom 18:7b2882874f87 375 }
Jan Jongboom 18:7b2882874f87 376
janjongboom 0:9fa3f3028773 377 return simpleClient->get(route);
janjongboom 0:9fa3f3028773 378 };
janjongboom 0:9fa3f3028773 379
Jan Jongboom 3:ce2322965a27 380 virtual void update(string v) {
Jan Jongboom 3:ce2322965a27 381 if (onUpdate) onUpdate(v);
Jan Jongboom 3:ce2322965a27 382 }
Jan Jongboom 3:ce2322965a27 383
Jan Jongboom 6:a1a766d45957 384 M2MResource* get_resource() {
Jan Jongboom 6:a1a766d45957 385 return simpleClient->get_resource(route);
Jan Jongboom 6:a1a766d45957 386 }
Jan Jongboom 6:a1a766d45957 387
Jan Jongboom 18:7b2882874f87 388 virtual void clear_pending_value() {
Jan Jongboom 18:7b2882874f87 389 hasPendingValue = false;
Jan Jongboom 18:7b2882874f87 390 }
Jan Jongboom 18:7b2882874f87 391
janjongboom 0:9fa3f3028773 392 private:
janjongboom 0:9fa3f3028773 393 SimpleMbedClientBase* simpleClient;
janjongboom 0:9fa3f3028773 394 string route;
Jan Jongboom 12:26810c6b58e1 395 Callback<void(string)> onUpdate;
Jan Jongboom 18:7b2882874f87 396
Jan Jongboom 18:7b2882874f87 397 // set() is async (because on the event queue, so store the pending value here...)
Jan Jongboom 18:7b2882874f87 398 bool hasPendingValue = false;
Jan Jongboom 18:7b2882874f87 399 string pendingValue;
janjongboom 0:9fa3f3028773 400 };
janjongboom 0:9fa3f3028773 401
Jan Jongboom 3:ce2322965a27 402 class SimpleResourceInt : public SimpleResourceBase {
janjongboom 0:9fa3f3028773 403 public:
Jan Jongboom 12:26810c6b58e1 404 SimpleResourceInt(SimpleMbedClientBase* aSimpleClient, string aRoute, Callback<void(int)> aOnUpdate) :
Jan Jongboom 18:7b2882874f87 405 simpleClient(aSimpleClient), route(aRoute), onUpdate(aOnUpdate), pendingValue(0) {}
janjongboom 0:9fa3f3028773 406
janjongboom 0:9fa3f3028773 407 int operator=(int newValue) {
Jan Jongboom 18:7b2882874f87 408 pendingValue = newValue;
Jan Jongboom 18:7b2882874f87 409 hasPendingValue = true;
Jan Jongboom 18:7b2882874f87 410
janjongboom 0:9fa3f3028773 411 simpleClient->set(route, newValue);
janjongboom 0:9fa3f3028773 412 return newValue;
janjongboom 0:9fa3f3028773 413 };
janjongboom 0:9fa3f3028773 414 operator int() const {
Jan Jongboom 18:7b2882874f87 415 if (hasPendingValue) {
Jan Jongboom 18:7b2882874f87 416 return pendingValue;
Jan Jongboom 18:7b2882874f87 417 }
Jan Jongboom 18:7b2882874f87 418
janjongboom 0:9fa3f3028773 419 string v = simpleClient->get(route);
janjongboom 0:9fa3f3028773 420 if (v.empty()) return 0;
Jan Jongboom 3:ce2322965a27 421
janjongboom 0:9fa3f3028773 422 return atoi((const char*)v.c_str());
janjongboom 0:9fa3f3028773 423 };
janjongboom 0:9fa3f3028773 424
Jan Jongboom 3:ce2322965a27 425 virtual void update(string v) {
Jan Jongboom 3:ce2322965a27 426 if (!onUpdate) return;
Jan Jongboom 3:ce2322965a27 427
Jan Jongboom 3:ce2322965a27 428 onUpdate(atoi((const char*)v.c_str()));
Jan Jongboom 3:ce2322965a27 429 }
Jan Jongboom 3:ce2322965a27 430
Jan Jongboom 6:a1a766d45957 431 M2MResource* get_resource() {
Jan Jongboom 6:a1a766d45957 432 return simpleClient->get_resource(route);
Jan Jongboom 6:a1a766d45957 433 }
Jan Jongboom 6:a1a766d45957 434
Jan Jongboom 18:7b2882874f87 435 virtual void clear_pending_value() {
Jan Jongboom 18:7b2882874f87 436 hasPendingValue = false;
Jan Jongboom 18:7b2882874f87 437 }
Jan Jongboom 18:7b2882874f87 438
janjongboom 0:9fa3f3028773 439 private:
janjongboom 0:9fa3f3028773 440 SimpleMbedClientBase* simpleClient;
janjongboom 0:9fa3f3028773 441 string route;
Jan Jongboom 12:26810c6b58e1 442 Callback<void(int)> onUpdate;
Jan Jongboom 18:7b2882874f87 443
Jan Jongboom 18:7b2882874f87 444 // set() is async (because on the event queue, so store the pending value here...)
Jan Jongboom 18:7b2882874f87 445 bool hasPendingValue = false;
Jan Jongboom 18:7b2882874f87 446 int pendingValue;
janjongboom 0:9fa3f3028773 447 };
janjongboom 0:9fa3f3028773 448
janjongboom 0:9fa3f3028773 449 class SimpleMbedClient : public SimpleMbedClientBase {
janjongboom 0:9fa3f3028773 450 public:
janjongboom 1:75015f627e89 451
Jan Jongboom 17:200624714d15 452 SimpleMbedClient(bool aDebug = true)
Jan Jongboom 17:200624714d15 453 : SimpleMbedClientBase(aDebug)
Jan Jongboom 17:200624714d15 454 {
Jan Jongboom 17:200624714d15 455
Jan Jongboom 17:200624714d15 456 }
Jan Jongboom 17:200624714d15 457
Jan Jongboom 18:7b2882874f87 458 SimpleMbedClient(EventQueue* aQueue, bool aDebug = true)
Jan Jongboom 18:7b2882874f87 459 : SimpleMbedClientBase(aQueue, aDebug)
Jan Jongboom 18:7b2882874f87 460 {
Jan Jongboom 18:7b2882874f87 461
Jan Jongboom 18:7b2882874f87 462 }
Jan Jongboom 18:7b2882874f87 463
janjongboom 1:75015f627e89 464 // @todo: macro this up
janjongboom 1:75015f627e89 465
janjongboom 1:75015f627e89 466 SimpleResourceString define_resource(
Jan Jongboom 3:ce2322965a27 467 const char* route,
Jan Jongboom 3:ce2322965a27 468 string v,
Jan Jongboom 3:ce2322965a27 469 M2MBase::Operation opr = M2MBase::GET_PUT_ALLOWED,
janjongboom 1:75015f627e89 470 bool observable = true,
Jan Jongboom 12:26810c6b58e1 471 Callback<void(string)> onUpdate = NULL)
janjongboom 1:75015f627e89 472 {
Jan Jongboom 3:ce2322965a27 473 SimpleResourceString* simpleResource = new SimpleResourceString(this, route, onUpdate);
janjongboom 0:9fa3f3028773 474 bool res = define_resource_internal(route, v, opr, observable);
Jan Jongboom 3:ce2322965a27 475 if (!res) {
Jan Jongboom 3:ce2322965a27 476 printf("Error while creating %s\n", route);
Jan Jongboom 3:ce2322965a27 477 }
Jan Jongboom 3:ce2322965a27 478 else {
Jan Jongboom 3:ce2322965a27 479 register_update_callback(route, simpleResource);
Jan Jongboom 3:ce2322965a27 480 }
Jan Jongboom 3:ce2322965a27 481 return *simpleResource;
janjongboom 0:9fa3f3028773 482 }
janjongboom 1:75015f627e89 483
janjongboom 1:75015f627e89 484 SimpleResourceString define_resource(
Jan Jongboom 3:ce2322965a27 485 const char* route,
Jan Jongboom 3:ce2322965a27 486 string v,
Jan Jongboom 3:ce2322965a27 487 M2MBase::Operation opr,
janjongboom 1:75015f627e89 488 bool observable,
Jan Jongboom 3:ce2322965a27 489 void(*onUpdate)(string))
janjongboom 1:75015f627e89 490 {
Jan Jongboom 12:26810c6b58e1 491 Callback<void(string)> fp;
janjongboom 1:75015f627e89 492 fp.attach(onUpdate);
janjongboom 1:75015f627e89 493 return define_resource(route, v, opr, observable, fp);
janjongboom 1:75015f627e89 494 }
Jan Jongboom 3:ce2322965a27 495
janjongboom 1:75015f627e89 496 SimpleResourceString define_resource(
Jan Jongboom 3:ce2322965a27 497 const char* route,
janjongboom 1:75015f627e89 498 string v,
Jan Jongboom 12:26810c6b58e1 499 Callback<void(string)> onUpdate)
janjongboom 1:75015f627e89 500 {
janjongboom 1:75015f627e89 501 return define_resource(route, v, M2MBase::GET_PUT_ALLOWED, true, onUpdate);
janjongboom 1:75015f627e89 502 }
janjongboom 1:75015f627e89 503
janjongboom 1:75015f627e89 504 SimpleResourceString define_resource(
Jan Jongboom 3:ce2322965a27 505 const char* route,
janjongboom 1:75015f627e89 506 string v,
Jan Jongboom 3:ce2322965a27 507 void(*onUpdate)(string))
janjongboom 1:75015f627e89 508 {
Jan Jongboom 12:26810c6b58e1 509 Callback<void(string)> fp;
janjongboom 1:75015f627e89 510 fp.attach(onUpdate);
janjongboom 1:75015f627e89 511 return define_resource(route, v, M2MBase::GET_PUT_ALLOWED, true, fp);
janjongboom 1:75015f627e89 512 }
Jan Jongboom 3:ce2322965a27 513
janjongboom 1:75015f627e89 514 SimpleResourceInt define_resource(
Jan Jongboom 3:ce2322965a27 515 const char* route,
Jan Jongboom 3:ce2322965a27 516 int v,
Jan Jongboom 3:ce2322965a27 517 M2MBase::Operation opr = M2MBase::GET_PUT_ALLOWED,
janjongboom 1:75015f627e89 518 bool observable = true,
Jan Jongboom 12:26810c6b58e1 519 Callback<void(int)> onUpdate = NULL)
janjongboom 1:75015f627e89 520 {
Jan Jongboom 3:ce2322965a27 521 SimpleResourceInt* simpleResource = new SimpleResourceInt(this, route, onUpdate);
Jan Jongboom 3:ce2322965a27 522
Jan Jongboom 16:cb980bd39e32 523 char str[13];
Jan Jongboom 16:cb980bd39e32 524 sprintf(str, "%d", v);
Jan Jongboom 16:cb980bd39e32 525
Jan Jongboom 16:cb980bd39e32 526 bool res = define_resource_internal(route, string(str), opr, observable);
Jan Jongboom 3:ce2322965a27 527 if (!res) {
Jan Jongboom 3:ce2322965a27 528 printf("Error while creating %s\n", route);
Jan Jongboom 3:ce2322965a27 529 }
Jan Jongboom 3:ce2322965a27 530 else {
Jan Jongboom 3:ce2322965a27 531 register_update_callback(route, simpleResource);
Jan Jongboom 3:ce2322965a27 532 }
Jan Jongboom 3:ce2322965a27 533 return *simpleResource;
janjongboom 0:9fa3f3028773 534 }
Jan Jongboom 3:ce2322965a27 535
janjongboom 1:75015f627e89 536 SimpleResourceInt define_resource(
Jan Jongboom 3:ce2322965a27 537 const char* route,
Jan Jongboom 3:ce2322965a27 538 int v,
Jan Jongboom 3:ce2322965a27 539 M2MBase::Operation opr,
janjongboom 1:75015f627e89 540 bool observable,
Jan Jongboom 3:ce2322965a27 541 void(*onUpdate)(int))
janjongboom 1:75015f627e89 542 {
Jan Jongboom 12:26810c6b58e1 543 Callback<void(int)> fp;
janjongboom 1:75015f627e89 544 fp.attach(onUpdate);
janjongboom 1:75015f627e89 545 return define_resource(route, v, opr, observable, fp);
janjongboom 1:75015f627e89 546 }
Jan Jongboom 3:ce2322965a27 547
janjongboom 1:75015f627e89 548 SimpleResourceInt define_resource(
Jan Jongboom 3:ce2322965a27 549 const char* route,
janjongboom 1:75015f627e89 550 int v,
Jan Jongboom 12:26810c6b58e1 551 Callback<void(int)> onUpdate)
janjongboom 1:75015f627e89 552 {
janjongboom 1:75015f627e89 553 return define_resource(route, v, M2MBase::GET_PUT_ALLOWED, true, onUpdate);
janjongboom 1:75015f627e89 554 }
janjongboom 1:75015f627e89 555
janjongboom 1:75015f627e89 556 SimpleResourceInt define_resource(
Jan Jongboom 3:ce2322965a27 557 const char* route,
janjongboom 1:75015f627e89 558 int v,
Jan Jongboom 3:ce2322965a27 559 void(*onUpdate)(int))
janjongboom 1:75015f627e89 560 {
Jan Jongboom 12:26810c6b58e1 561 Callback<void(int)> fp;
janjongboom 1:75015f627e89 562 fp.attach(onUpdate);
janjongboom 1:75015f627e89 563 return define_resource(route, v, M2MBase::GET_PUT_ALLOWED, true, fp);
janjongboom 1:75015f627e89 564 }
janjongboom 0:9fa3f3028773 565 };
janjongboom 0:9fa3f3028773 566
Jan Jongboom 3:ce2322965a27 567 #endif // __SIMPLE_MBED_CLIENT_H__