mbed client

Fork of simple-mbed-client by sandbox

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__