mbed client
Fork of simple-mbed-client by
Diff: simple-mbed-client.h
- Revision:
- 3:ce2322965a27
- Parent:
- 2:0a015df677a4
- Child:
- 4:0f9eae5739dd
--- a/simple-mbed-client.h Tue May 17 00:15:11 2016 +0000 +++ b/simple-mbed-client.h Tue May 24 14:59:28 2016 -0500 @@ -17,20 +17,29 @@ #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-classic/m2mnetwork.h" #include "mbed-client-wrapper.h" using namespace std; +class SimpleResourceBase { +public: + virtual void update(string v); +}; + class SimpleMbedClientBase { public: - SimpleMbedClientBase() : output(USBTX, USBRX) { - + SimpleMbedClientBase(bool aDebug = true) + : output(USBTX, USBRX), debug(aDebug) + { + } + ~SimpleMbedClientBase() {} struct MbedClientOptions get_default_options() { @@ -42,67 +51,69 @@ options.DeviceType = "test"; options.SocketMode = M2MInterface::UDP; options.ServerAddress = "coap://api.connector.mbed.com:5684"; - + return options; } - bool init(NetworkInterface* iface) { - // does this automatically handle everything? weird yo. - M2MNetwork network(iface); - - output.printf("[SMC] Device name %s\r\n", MBED_ENDPOINT_NAME); - + 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(); - + 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(NetworkInterface* iface) { - output.printf("[SMC] In mbed_client_setup\r\n"); + bool setup(NetworkStack* iface) { + debug_msg("[SMC] In mbed_client_setup\r\n"); if (client) { - output.printf("[SMC] [ERROR] mbed_client_setup called, but mbed_client is already instantiated\r\n"); + debug_msg("[SMC] [ERROR] mbed_client_setup called, but mbed_client is already instantiated\r\n"); return false; } - + struct MbedClientOptions options = get_default_options(); - - client = new MbedClient(options); + + FP1<void, string> updateFp(this, &SimpleMbedClientBase::resource_updated); + client = new MbedClient(options, updateFp, debug); + return init(iface); } - bool setup(MbedClientOptions options, NetworkInterface* iface) { + bool setup(MbedClientOptions options, NetworkStack* iface) { if (client) { - output.printf("[SMC] [ERROR] mbed_client_setup called, but mbed_client is already instantiated\r\n"); + debug_msg("[SMC] [ERROR] mbed_client_setup called, but mbed_client is already instantiated\r\n"); return false; } - client = new MbedClient(options); + + FP1<void, string> updateFp(this, &SimpleMbedClientBase::resource_updated); + client = new MbedClient(options, updateFp, debug); + return init(iface); } @@ -112,7 +123,7 @@ } template<typename T> - void on_registered(T *object, void (T::*member)(void)) { + void on_registered(T *object, void (T::*member)(void)) { FunctionPointer fp(object, member); client->set_registered_function(fp); } @@ -123,7 +134,7 @@ } template<typename T> - void on_unregistered(T *object, void (T::*member)(void)) { + void on_unregistered(T *object, void (T::*member)(void)) { FunctionPointer fp(object, member); client->set_unregistered_function(fp); } @@ -132,15 +143,14 @@ if (!define_resource_internal(route, string(), M2MBase::POST_ALLOWED, false)) { return false; } - + string route_str(route); if (!resources.count(route_str)) { - output.printf("[SMC] [ERROR] Should be created, but no such route (%s)\r\n", route); + debug_msg("[SMC] [ERROR] Should be created, but no such route (%s)\r\n", route); return false; } - - FunctionPointerArg1<void, void*>* fp = new FunctionPointerArg1<void, void*>(fn); - resources[route_str]->set_execute_function(execute_callback(fp, &FunctionPointerArg1<void, void*>::call)); + + resources[route_str]->set_execute_function(execute_callback_2(fn)); return true; } @@ -148,41 +158,39 @@ if (!define_resource_internal(route, string(), M2MBase::POST_ALLOWED, false)) { return false; } - + string route_str(route); if (!resources.count(route_str)) { - output.printf("[SMC] [ERROR] Should be created, but no such route (%s)\r\n", route); + 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)) { - output.printf("[SMC] [ERROR] No such route (%s)\r\n", route_str.c_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. - // so we put the set() in an updateQueue and then we'll see... - if (!resources.count(route_str)) { - output.printf("[SMC] [ERROR] No such route (%s)\r\n", route_str.c_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; @@ -192,61 +200,63 @@ 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) { - output.printf("[SMC] [ERROR] mbed_client_define_resource, Can only define resources before mbed_client_setup is called!\r\n"); + 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) { - output.printf("[SMC] [ERROR] mbed_client_define_resource, Route needs to have three segments, split by '/' (%s)\r\n", route); + debug_msg("[SMC] [ERROR] mbed_client_define_resource, Route needs to have three segments, split by '/' (%s)\r\n", route); return false; } - - int inst_id = 0; -// try { -// inst_id = stoi(segments.at(1)); -// } -// catch (const std::invalid_argument& ia) { -// output.printf("[SMC] [ERROR] mbed_client_define_resource, second route segment should be numeric, but was not (%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))) { - output.printf("Found object... %s\r\n", segments.at(0).c_str()); + debug_msg("Found object... %s\r\n", segments.at(0).c_str()); inst = objectInstances[segments.at(0)]; } else { - output.printf("Create new object... %s\r\n", segments.at(0).c_str()); + 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); @@ -259,21 +269,31 @@ 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; - // @todo: write this - // map<string, FunctionPointerArg1<void, void*> updateValues; + bool debug; + + map<string, SimpleResourceBase*> updateValues; }; -class SimpleResourceString { +class SimpleResourceString : public SimpleResourceBase { public: - SimpleResourceString(SimpleMbedClientBase* aSimpleClient, string aRoute) : - simpleClient(aSimpleClient), route(aRoute) {} + SimpleResourceString(SimpleMbedClientBase* aSimpleClient, string aRoute, FunctionPointerArg1<void, string> aOnUpdate) : + simpleClient(aSimpleClient), route(aRoute), onUpdate(aOnUpdate) {} string operator=(const string& newValue) { simpleClient->set(route, newValue); @@ -283,15 +303,20 @@ return simpleClient->get(route); }; + virtual void update(string v) { + if (onUpdate) onUpdate(v); + } + private: SimpleMbedClientBase* simpleClient; string route; + FunctionPointerArg1<void, string> onUpdate; }; -class SimpleResourceInt { +class SimpleResourceInt : public SimpleResourceBase { public: - SimpleResourceInt(SimpleMbedClientBase* aSimpleClient, string aRoute) : - simpleClient(aSimpleClient), route(aRoute) {} + SimpleResourceInt(SimpleMbedClientBase* aSimpleClient, string aRoute, FunctionPointerArg1<void, int> aOnUpdate) : + simpleClient(aSimpleClient), route(aRoute), onUpdate(aOnUpdate) {} int operator=(int newValue) { simpleClient->set(route, newValue); @@ -300,13 +325,20 @@ 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 { @@ -315,86 +347,99 @@ // @todo: macro this up SimpleResourceString define_resource( - const char* route, - string v, - M2MBase::Operation opr = M2MBase::GET_PUT_ALLOWED, + 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); - return *(new SimpleResourceString(this, route)); + 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, + const char* route, + string v, + M2MBase::Operation opr, bool observable, - void(*onUpdate)(string)) + void(*onUpdate)(string)) { FunctionPointerArg1<void, string> fp; fp.attach(onUpdate); return define_resource(route, v, opr, observable, fp); } - + SimpleResourceString define_resource( - const char* route, + const char* route, string v, - FunctionPointerArg1<void, string> onUpdate = NULL) + FunctionPointerArg1<void, string> onUpdate = NULL) { return define_resource(route, v, M2MBase::GET_PUT_ALLOWED, true, onUpdate); } SimpleResourceString define_resource( - const char* route, + const char* route, string v, - void(*onUpdate)(string)) + 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, + const char* route, + int v, + M2MBase::Operation opr = M2MBase::GET_PUT_ALLOWED, bool observable = true, - FunctionPointerArg1<void, int> onUpdate = NULL) + 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); - return *(new SimpleResourceInt(this, route)); + 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, + const char* route, + int v, + M2MBase::Operation opr, bool observable, - void(*onUpdate)(int)) + void(*onUpdate)(int)) { FunctionPointerArg1<void, int> fp; fp.attach(onUpdate); return define_resource(route, v, opr, observable, fp); } - + SimpleResourceInt define_resource( - const char* route, + const char* route, int v, - FunctionPointerArg1<void, int> onUpdate = NULL) + FunctionPointerArg1<void, int> onUpdate = NULL) { return define_resource(route, v, M2MBase::GET_PUT_ALLOWED, true, onUpdate); } SimpleResourceInt define_resource( - const char* route, + const char* route, int v, - void(*onUpdate)(int)) + void(*onUpdate)(int)) { FunctionPointerArg1<void, int> fp; fp.attach(onUpdate); @@ -402,4 +447,4 @@ } }; -#endif // __SIMPLE_MBED_CLIENT_H__ \ No newline at end of file +#endif // __SIMPLE_MBED_CLIENT_H__