Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: Wifi_Get_Test_V1 simple-mbed-client-example simple-client-app-shield simple-sensor-client
Fork of simple-mbed-client by
simple-mbed-client.h
- Committer:
- Jan Jongboom
- Date:
- 2016-05-24
- Revision:
- 3:ce2322965a27
- Parent:
- 2:0a015df677a4
- Child:
- 4:0f9eae5739dd
File content as of revision 3:ce2322965a27:
/*
* Copyright (c) 2015 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __SIMPLE_MBED_CLIENT_H__
#define __SIMPLE_MBED_CLIENT_H__
#define debug_msg(...) if (debug) output.printf(__VA_ARGS__)
#include <map>
#include <string>
#include <sstream>
#include <vector>
#include "mbed-client-wrapper.h"
using namespace std;
class SimpleResourceBase {
public:
virtual void update(string v);
};
class SimpleMbedClientBase {
public:
SimpleMbedClientBase(bool aDebug = true)
: output(USBTX, USBRX), debug(aDebug)
{
}
~SimpleMbedClientBase() {}
struct MbedClientOptions get_default_options() {
struct MbedClientOptions options;
options.Manufacturer = "Manufacturer_String";
options.Type = "Type_String";
options.ModelNumber = "ModelNumber_String";
options.SerialNumber = "SerialNumber_String";
options.DeviceType = "test";
options.SocketMode = M2MInterface::UDP;
options.ServerAddress = "coap://api.connector.mbed.com:5684";
return options;
}
bool init(NetworkStack* iface) {
debug_msg("[SMC] Device name %s\r\n", MBED_ENDPOINT_NAME);
// Create endpoint interface to manage register and unregister
client->create_interface(iface);
// Create Objects of varying types, see simpleclient.h for more details on implementation.
M2MSecurity* register_object = client->create_register_object(); // server object specifying connector info
M2MDevice* device_object = client->create_device_object(); // device resources object
// Create list of Objects to register
M2MObjectList object_list;
// Add objects to list
object_list.push_back(device_object);
map<string, M2MObject*>::iterator it;
for (it = objects.begin(); it != objects.end(); it++)
{
object_list.push_back(it->second);
}
// Set endpoint registration object
client->set_register_object(register_object);
// Issue register command.
client->test_register(register_object, object_list);
// @todo: no idea if this works
Ticker updateRegister;
updateRegister.attach(client, &MbedClient::test_update_register, 25.0f);
return true;
}
bool setup(NetworkStack* iface) {
debug_msg("[SMC] In mbed_client_setup\r\n");
if (client) {
debug_msg("[SMC] [ERROR] mbed_client_setup called, but mbed_client is already instantiated\r\n");
return false;
}
struct MbedClientOptions options = get_default_options();
FP1<void, string> updateFp(this, &SimpleMbedClientBase::resource_updated);
client = new MbedClient(options, updateFp, debug);
return init(iface);
}
bool setup(MbedClientOptions options, NetworkStack* iface) {
if (client) {
debug_msg("[SMC] [ERROR] mbed_client_setup called, but mbed_client is already instantiated\r\n");
return false;
}
FP1<void, string> updateFp(this, &SimpleMbedClientBase::resource_updated);
client = new MbedClient(options, updateFp, debug);
return init(iface);
}
void on_registered(void(*fn)(void)) {
FunctionPointer fp(fn);
client->set_registered_function(fp);
}
template<typename T>
void on_registered(T *object, void (T::*member)(void)) {
FunctionPointer fp(object, member);
client->set_registered_function(fp);
}
void on_unregistered(void(*fn)(void)) {
FunctionPointer fp(fn);
client->set_unregistered_function(fp);
}
template<typename T>
void on_unregistered(T *object, void (T::*member)(void)) {
FunctionPointer fp(object, member);
client->set_unregistered_function(fp);
}
bool define_function(const char* route, void(*fn)(void*)) {
if (!define_resource_internal(route, string(), M2MBase::POST_ALLOWED, false)) {
return false;
}
string route_str(route);
if (!resources.count(route_str)) {
debug_msg("[SMC] [ERROR] Should be created, but no such route (%s)\r\n", route);
return false;
}
resources[route_str]->set_execute_function(execute_callback_2(fn));
return true;
}
bool define_function(const char* route, execute_callback fn) {
if (!define_resource_internal(route, string(), M2MBase::POST_ALLOWED, false)) {
return false;
}
string route_str(route);
if (!resources.count(route_str)) {
debug_msg("[SMC] [ERROR] Should be created, but no such route (%s)\r\n", route);
return false;
}
// No clue why this is not working?! It works with class member, but not with static function...
resources[route_str]->set_execute_function(fn);
return true;
}
string get(string route_str) {
if (!resources.count(route_str)) {
debug_msg("[SMC] [ERROR] No such route (%s)\r\n", route_str.c_str());
return string();
}
// otherwise ask mbed Client...
uint8_t* buffIn = NULL;
uint32_t sizeIn;
resources[route_str]->get_value(buffIn, sizeIn);
string s((char*)buffIn, sizeIn);
return s;
}
bool set(string route_str, string v) {
// Potentially set() happens in InterruptContext. That's not good.
if (!resources.count(route_str)) {
debug_msg("[SMC] [ERROR] No such route (%s)\r\n", route_str.c_str());
return false;
}
resources[route_str]->set_value((uint8_t*)v.c_str(), v.length());
return true;
}
bool set(string route, const int& v) {
stringstream ss;
ss << v;
std::string stringified = ss.str();
return set(route, stringified);
}
bool define_resource_internal(const char* route, std::string v, M2MBase::Operation opr, bool observable) {
if (client) {
debug_msg("[SMC] [ERROR] mbed_client_define_resource, Can only define resources before mbed_client_setup is called!\r\n");
return false;
}
vector<string> segments = parse_route(route);
if (segments.size() != 3) {
debug_msg("[SMC] [ERROR] mbed_client_define_resource, Route needs to have three segments, split by '/' (%s)\r\n", route);
return false;
}
// segments[1] should be one digit and numeric
if (!isdigit(segments.at(1).c_str()[0])) {
debug_msg("[SMC] [ERROR] mbed_client_define_resource, second route segment should be numeric, but was not (%s)\r\n", route);
return false;
}
int inst_id = atoi(segments.at(1).c_str());
M2MObjectInstance* inst;
if (objectInstances.count(segments.at(0))) {
debug_msg("Found object... %s\r\n", segments.at(0).c_str());
inst = objectInstances[segments.at(0)];
}
else {
debug_msg("Create new object... %s\r\n", segments.at(0).c_str());
M2MObject* obj = M2MInterfaceFactory::create_object(segments.at(0).c_str());
inst = obj->create_object_instance(inst_id);
objects.insert(std::pair<string, M2MObject*>(segments.at(0), obj));
objectInstances.insert(std::pair<string, M2MObjectInstance*>(segments.at(0), inst));
}
// @todo check if the resource exists yet
M2MResource* res = inst->create_dynamic_resource(segments.at(2).c_str(), "",
M2MResourceInstance::STRING, observable);
res->set_operation(opr);
res->set_value((uint8_t*)v.c_str(), v.length());
string route_str(route);
resources.insert(pair<string, M2MResource*>(route_str, res));
return true;
}
void keep_alive() {
client->test_update_register();
}
void register_update_callback(string route, SimpleResourceBase* simpleResource) {
updateValues[route] = simpleResource;
}
private:
vector<string> parse_route(const char* route) {
string s(route);
vector<string> v;
stringstream ss(s);
string item;
while (getline(ss, item, '/')) {
v.push_back(item);
}
return v;
}
void resource_updated(string uri) {
if (updateValues.count(uri) == 0) return;
string v = get(uri);
if (v.empty()) return;
updateValues[uri]->update(v);
}
Serial output;
MbedClient* client;
map<string, M2MObject*> objects;
map<string, M2MObjectInstance*> objectInstances;
map<string, M2MResource*> resources;
bool debug;
map<string, SimpleResourceBase*> updateValues;
};
class SimpleResourceString : public SimpleResourceBase {
public:
SimpleResourceString(SimpleMbedClientBase* aSimpleClient, string aRoute, FunctionPointerArg1<void, string> aOnUpdate) :
simpleClient(aSimpleClient), route(aRoute), onUpdate(aOnUpdate) {}
string operator=(const string& newValue) {
simpleClient->set(route, newValue);
return newValue;
};
operator string() const {
return simpleClient->get(route);
};
virtual void update(string v) {
if (onUpdate) onUpdate(v);
}
private:
SimpleMbedClientBase* simpleClient;
string route;
FunctionPointerArg1<void, string> onUpdate;
};
class SimpleResourceInt : public SimpleResourceBase {
public:
SimpleResourceInt(SimpleMbedClientBase* aSimpleClient, string aRoute, FunctionPointerArg1<void, int> aOnUpdate) :
simpleClient(aSimpleClient), route(aRoute), onUpdate(aOnUpdate) {}
int operator=(int newValue) {
simpleClient->set(route, newValue);
return newValue;
};
operator int() const {
string v = simpleClient->get(route);
if (v.empty()) return 0;
return atoi((const char*)v.c_str());
};
virtual void update(string v) {
if (!onUpdate) return;
onUpdate(atoi((const char*)v.c_str()));
}
private:
SimpleMbedClientBase* simpleClient;
string route;
FunctionPointerArg1<void, int> onUpdate;
};
class SimpleMbedClient : public SimpleMbedClientBase {
public:
// @todo: macro this up
SimpleResourceString define_resource(
const char* route,
string v,
M2MBase::Operation opr = M2MBase::GET_PUT_ALLOWED,
bool observable = true,
FunctionPointerArg1<void, string> onUpdate = NULL)
{
SimpleResourceString* simpleResource = new SimpleResourceString(this, route, onUpdate);
bool res = define_resource_internal(route, v, opr, observable);
if (!res) {
printf("Error while creating %s\n", route);
}
else {
register_update_callback(route, simpleResource);
}
return *simpleResource;
}
SimpleResourceString define_resource(
const char* route,
string v,
M2MBase::Operation opr,
bool observable,
void(*onUpdate)(string))
{
FunctionPointerArg1<void, string> fp;
fp.attach(onUpdate);
return define_resource(route, v, opr, observable, fp);
}
SimpleResourceString define_resource(
const char* route,
string v,
FunctionPointerArg1<void, string> onUpdate = NULL)
{
return define_resource(route, v, M2MBase::GET_PUT_ALLOWED, true, onUpdate);
}
SimpleResourceString define_resource(
const char* route,
string v,
void(*onUpdate)(string))
{
FunctionPointerArg1<void, string> fp;
fp.attach(onUpdate);
return define_resource(route, v, M2MBase::GET_PUT_ALLOWED, true, fp);
}
SimpleResourceInt define_resource(
const char* route,
int v,
M2MBase::Operation opr = M2MBase::GET_PUT_ALLOWED,
bool observable = true,
FunctionPointerArg1<void, int> onUpdate = NULL)
{
SimpleResourceInt* simpleResource = new SimpleResourceInt(this, route, onUpdate);
stringstream ss;
ss << v;
std::string stringified = ss.str();
bool res = define_resource_internal(route, stringified, opr, observable);
if (!res) {
printf("Error while creating %s\n", route);
}
else {
register_update_callback(route, simpleResource);
}
return *simpleResource;
}
SimpleResourceInt define_resource(
const char* route,
int v,
M2MBase::Operation opr,
bool observable,
void(*onUpdate)(int))
{
FunctionPointerArg1<void, int> fp;
fp.attach(onUpdate);
return define_resource(route, v, opr, observable, fp);
}
SimpleResourceInt define_resource(
const char* route,
int v,
FunctionPointerArg1<void, int> onUpdate = NULL)
{
return define_resource(route, v, M2MBase::GET_PUT_ALLOWED, true, onUpdate);
}
SimpleResourceInt define_resource(
const char* route,
int v,
void(*onUpdate)(int))
{
FunctionPointerArg1<void, int> fp;
fp.attach(onUpdate);
return define_resource(route, v, M2MBase::GET_PUT_ALLOWED, true, fp);
}
};
#endif // __SIMPLE_MBED_CLIENT_H__
