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.
Fork of simple-mbed-client by
simple-mbed-client.h
00001 /* 00002 * Copyright (c) 2015 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #ifndef __SIMPLE_MBED_CLIENT_H__ 00018 #define __SIMPLE_MBED_CLIENT_H__ 00019 00020 #define debug_msg(...) if (debug) output.printf(__VA_ARGS__) 00021 00022 #include <map> 00023 #include <string> 00024 #include <sstream> 00025 #include <vector> 00026 #include "mbed-client-wrapper.h" 00027 00028 using namespace std; 00029 00030 class SimpleResourceBase { 00031 public: 00032 virtual void update(string v) {} 00033 }; 00034 00035 class SimpleMbedClientBase { 00036 public: 00037 SimpleMbedClientBase(bool aDebug = true) 00038 : output(USBTX, USBRX), debug(aDebug) 00039 { 00040 00041 } 00042 00043 ~SimpleMbedClientBase() {} 00044 00045 struct MbedClientOptions get_default_options() { 00046 struct MbedClientOptions options; 00047 options.Manufacturer = "Manufacturer_String"; 00048 options.Type = "Type_String"; 00049 options.ModelNumber = "ModelNumber_String"; 00050 options.SerialNumber = "SerialNumber_String"; 00051 options.DeviceType = "test"; 00052 options.SocketMode = M2MInterface::TCP; 00053 options.ServerAddress = "coap://api.connector.mbed.com:5684"; 00054 00055 return options; 00056 } 00057 00058 bool init(NetworkInterface* iface) { 00059 debug_msg("[SMC] Device name %s\r\n", MBED_ENDPOINT_NAME); 00060 00061 // Create endpoint interface to manage register and unregister 00062 client->create_interface(iface); 00063 00064 // Create Objects of varying types, see simpleclient.h for more details on implementation. 00065 M2MSecurity* register_object = client->create_register_object(); // server object specifying connector info 00066 M2MDevice* device_object = client->create_device_object(); // device resources object 00067 00068 // Create list of Objects to register 00069 M2MObjectList object_list; 00070 00071 // Add objects to list 00072 object_list.push_back(device_object); 00073 00074 map<string, M2MObject*>::iterator it; 00075 for (it = objects.begin(); it != objects.end(); it++) 00076 { 00077 object_list.push_back(it->second); 00078 } 00079 00080 // Set endpoint registration object 00081 client->set_register_object(register_object); 00082 00083 // Issue register command. 00084 client->test_register(register_object, object_list); 00085 00086 // @todo: no idea if this works 00087 Ticker updateRegister; 00088 updateRegister.attach(client, &MbedClient::test_update_register, 25.0f); 00089 00090 return true; 00091 } 00092 00093 bool setup(NetworkInterface* iface) { 00094 debug_msg("[SMC] In mbed_client_setup\r\n"); 00095 if (client) { 00096 debug_msg("[SMC] [ERROR] mbed_client_setup called, but mbed_client is already instantiated\r\n"); 00097 return false; 00098 } 00099 00100 struct MbedClientOptions options = get_default_options(); 00101 00102 Callback<void(string)> updateFp(this, &SimpleMbedClientBase::resource_updated); 00103 client = new MbedClient(options, updateFp, debug); 00104 00105 return init(iface); 00106 } 00107 00108 bool setup(MbedClientOptions options, NetworkInterface* iface) { 00109 if (client) { 00110 debug_msg("[SMC] [ERROR] mbed_client_setup called, but mbed_client is already instantiated\r\n"); 00111 return false; 00112 } 00113 00114 Callback<void(string)> updateFp(this, &SimpleMbedClientBase::resource_updated); 00115 client = new MbedClient(options, updateFp, debug); 00116 00117 return init(iface); 00118 } 00119 00120 void on_registered(void(*fn)(void)) { 00121 Callback<void()> fp(fn); 00122 client->set_registered_function(fp); 00123 } 00124 00125 template<typename T> 00126 void on_registered(T *object, void (T::*member)(void)) { 00127 Callback<void()> fp(object, member); 00128 client->set_registered_function(fp); 00129 } 00130 00131 void on_unregistered(void(*fn)(void)) { 00132 Callback<void()> fp(fn); 00133 client->set_unregistered_function(fp); 00134 } 00135 00136 template<typename T> 00137 void on_unregistered(T *object, void (T::*member)(void)) { 00138 Callback<void()> fp(object, member); 00139 client->set_unregistered_function(fp); 00140 } 00141 00142 bool define_function(const char* route, void(*fn)(void*)) { 00143 if (!define_resource_internal(route, string(), M2MBase::POST_ALLOWED, false)) { 00144 return false; 00145 } 00146 00147 string route_str(route); 00148 if (!resources.count(route_str)) { 00149 debug_msg("[SMC] [ERROR] Should be created, but no such route (%s)\r\n", route); 00150 return false; 00151 } 00152 00153 resources[route_str]->set_execute_function(execute_callback_2(fn)); 00154 return true; 00155 } 00156 00157 bool define_function(const char* route, execute_callback fn) { 00158 if (!define_resource_internal(route, string(), M2MBase::POST_ALLOWED, false)) { 00159 return false; 00160 } 00161 00162 string route_str(route); 00163 if (!resources.count(route_str)) { 00164 debug_msg("[SMC] [ERROR] Should be created, but no such route (%s)\r\n", route); 00165 return false; 00166 } 00167 // No clue why this is not working?! It works with class member, but not with static function... 00168 resources[route_str]->set_execute_function(fn); 00169 return true; 00170 } 00171 00172 string get(string route_str) { 00173 if (!resources.count(route_str)) { 00174 debug_msg("[SMC] [ERROR] No such route (%s)\r\n", route_str.c_str()); 00175 return string(); 00176 } 00177 00178 // otherwise ask mbed Client... 00179 uint8_t* buffIn = NULL; 00180 uint32_t sizeIn; 00181 resources[route_str]->get_value(buffIn, sizeIn); 00182 00183 string s((char*)buffIn, sizeIn); 00184 return s; 00185 } 00186 00187 bool set(string route_str, string v) { 00188 // Potentially set() happens in InterruptContext. That's not good. 00189 if (!resources.count(route_str)) { 00190 debug_msg("[SMC] [ERROR] No such route (%s)\r\n", route_str.c_str()); 00191 return false; 00192 } 00193 00194 if (v.length() == 0) { 00195 resources[route_str]->clear_value(); 00196 } 00197 else { 00198 resources[route_str]->set_value((uint8_t*)v.c_str(), v.length()); 00199 } 00200 00201 return true; 00202 } 00203 00204 bool set(string route, const int& v) { 00205 stringstream ss; 00206 ss << v; 00207 std::string stringified = ss.str(); 00208 00209 return set(route, stringified); 00210 } 00211 00212 bool define_resource_internal(const char* route, std::string v, M2MBase::Operation opr, bool observable) { 00213 if (client) { 00214 debug_msg("[SMC] [ERROR] mbed_client_define_resource, Can only define resources before mbed_client_setup is called!\r\n"); 00215 return false; 00216 } 00217 00218 vector<string> segments = parse_route(route); 00219 if (segments.size() != 3) { 00220 debug_msg("[SMC] [ERROR] mbed_client_define_resource, Route needs to have three segments, split by '/' (%s)\r\n", route); 00221 return false; 00222 } 00223 00224 // segments[1] should be one digit and numeric 00225 char n = segments.at(1).c_str()[0]; 00226 if (n < '0' || n > '9') { 00227 debug_msg("[SMC] [ERROR] mbed_client_define_resource, second route segment should be numeric, but was not (%s)\r\n", route); 00228 return false; 00229 } 00230 00231 int inst_id = atoi(segments.at(1).c_str()); 00232 00233 M2MObjectInstance* inst; 00234 if (objectInstances.count(segments.at(0))) { 00235 inst = objectInstances[segments.at(0)]; 00236 } 00237 else { 00238 M2MObject* obj = M2MInterfaceFactory::create_object(segments.at(0).c_str()); 00239 inst = obj->create_object_instance(inst_id); 00240 objects.insert(std::pair<string, M2MObject*>(segments.at(0), obj)); 00241 objectInstances.insert(std::pair<string, M2MObjectInstance*>(segments.at(0), inst)); 00242 } 00243 00244 // @todo check if the resource exists yet 00245 M2MResource* res = inst->create_dynamic_resource(segments.at(2).c_str(), "", 00246 M2MResourceInstance::STRING, observable); 00247 res->set_operation(opr); 00248 res->set_value((uint8_t*)v.c_str(), v.length()); 00249 00250 string route_str(route); 00251 resources.insert(pair<string, M2MResource*>(route_str, res)); 00252 00253 return true; 00254 } 00255 00256 void keep_alive() { 00257 client->test_update_register(); 00258 } 00259 00260 void register_update_callback(string route, SimpleResourceBase* simpleResource) { 00261 updateValues[route] = simpleResource; 00262 } 00263 00264 M2MResource* get_resource(string route) { 00265 if (!resources.count(route)) { 00266 debug_msg("[SMC] [ERROR] No such route (%s)\r\n", route.c_str()); 00267 return NULL; 00268 } 00269 00270 return resources[route]; 00271 } 00272 00273 private: 00274 vector<string> parse_route(const char* route) { 00275 string s(route); 00276 vector<string> v; 00277 stringstream ss(s); 00278 string item; 00279 while (getline(ss, item, '/')) { 00280 v.push_back(item); 00281 } 00282 return v; 00283 } 00284 00285 void resource_updated(string uri) { 00286 if (updateValues.count(uri) == 0) return; 00287 00288 string v = get(uri); 00289 if (v.empty()) return; 00290 00291 updateValues[uri]->update(v); 00292 } 00293 00294 Serial output; 00295 00296 MbedClient* client; 00297 map<string, M2MObject*> objects; 00298 map<string, M2MObjectInstance*> objectInstances; 00299 map<string, M2MResource*> resources; 00300 00301 bool debug; 00302 00303 map<string, SimpleResourceBase*> updateValues; 00304 }; 00305 00306 class SimpleResourceString : public SimpleResourceBase { 00307 public: 00308 SimpleResourceString(SimpleMbedClientBase* aSimpleClient, string aRoute, Callback<void(string)> aOnUpdate) : 00309 simpleClient(aSimpleClient), route(aRoute), onUpdate(aOnUpdate) {} 00310 00311 string operator=(const string& newValue) { 00312 simpleClient->set(route, newValue); 00313 return newValue; 00314 }; 00315 operator string() const { 00316 return simpleClient->get(route); 00317 }; 00318 00319 virtual void update(string v) { 00320 if (onUpdate) onUpdate(v); 00321 } 00322 00323 M2MResource* get_resource() { 00324 return simpleClient->get_resource(route); 00325 } 00326 00327 private: 00328 SimpleMbedClientBase* simpleClient; 00329 string route; 00330 Callback<void(string)> onUpdate; 00331 }; 00332 00333 class SimpleResourceInt : public SimpleResourceBase { 00334 public: 00335 SimpleResourceInt(SimpleMbedClientBase* aSimpleClient, string aRoute, Callback<void(int)> aOnUpdate) : 00336 simpleClient(aSimpleClient), route(aRoute), onUpdate(aOnUpdate) {} 00337 00338 int operator=(int newValue) { 00339 simpleClient->set(route, newValue); 00340 return newValue; 00341 }; 00342 operator int() const { 00343 string v = simpleClient->get(route); 00344 if (v.empty()) return 0; 00345 00346 return atoi((const char*)v.c_str()); 00347 }; 00348 00349 virtual void update(string v) { 00350 if (!onUpdate) return; 00351 00352 onUpdate(atoi((const char*)v.c_str())); 00353 } 00354 00355 M2MResource* get_resource() { 00356 return simpleClient->get_resource(route); 00357 } 00358 00359 private: 00360 SimpleMbedClientBase* simpleClient; 00361 string route; 00362 Callback<void(int)> onUpdate; 00363 }; 00364 00365 class SimpleMbedClient : public SimpleMbedClientBase { 00366 public: 00367 00368 // @todo: macro this up 00369 00370 SimpleResourceString define_resource( 00371 const char* route, 00372 string v, 00373 M2MBase::Operation opr = M2MBase::GET_PUT_ALLOWED, 00374 bool observable = true, 00375 Callback<void(string)> onUpdate = NULL) 00376 { 00377 SimpleResourceString* simpleResource = new SimpleResourceString(this, route, onUpdate); 00378 bool res = define_resource_internal(route, v, opr, observable); 00379 if (!res) { 00380 printf("Error while creating %s\n", route); 00381 } 00382 else { 00383 register_update_callback(route, simpleResource); 00384 } 00385 return *simpleResource; 00386 } 00387 00388 SimpleResourceString define_resource( 00389 const char* route, 00390 string v, 00391 M2MBase::Operation opr, 00392 bool observable, 00393 void(*onUpdate)(string)) 00394 { 00395 Callback<void(string)> fp; 00396 fp.attach(onUpdate); 00397 return define_resource(route, v, opr, observable, fp); 00398 } 00399 00400 SimpleResourceString define_resource( 00401 const char* route, 00402 string v, 00403 Callback<void(string)> onUpdate) 00404 { 00405 return define_resource(route, v, M2MBase::GET_PUT_ALLOWED, true, onUpdate); 00406 } 00407 00408 SimpleResourceString define_resource( 00409 const char* route, 00410 string v, 00411 void(*onUpdate)(string)) 00412 { 00413 Callback<void(string)> fp; 00414 fp.attach(onUpdate); 00415 return define_resource(route, v, M2MBase::GET_PUT_ALLOWED, true, fp); 00416 } 00417 00418 SimpleResourceInt define_resource( 00419 const char* route, 00420 int v, 00421 M2MBase::Operation opr = M2MBase::GET_PUT_ALLOWED, 00422 bool observable = true, 00423 Callback<void(int)> onUpdate = NULL) 00424 { 00425 SimpleResourceInt* simpleResource = new SimpleResourceInt(this, route, onUpdate); 00426 00427 stringstream ss; 00428 ss << v; 00429 std::string stringified = ss.str(); 00430 bool res = define_resource_internal(route, stringified, opr, observable); 00431 if (!res) { 00432 printf("Error while creating %s\n", route); 00433 } 00434 else { 00435 register_update_callback(route, simpleResource); 00436 } 00437 return *simpleResource; 00438 } 00439 00440 SimpleResourceInt define_resource( 00441 const char* route, 00442 int v, 00443 M2MBase::Operation opr, 00444 bool observable, 00445 void(*onUpdate)(int)) 00446 { 00447 Callback<void(int)> fp; 00448 fp.attach(onUpdate); 00449 return define_resource(route, v, opr, observable, fp); 00450 } 00451 00452 SimpleResourceInt define_resource( 00453 const char* route, 00454 int v, 00455 Callback<void(int)> onUpdate) 00456 { 00457 return define_resource(route, v, M2MBase::GET_PUT_ALLOWED, true, onUpdate); 00458 } 00459 00460 SimpleResourceInt define_resource( 00461 const char* route, 00462 int v, 00463 void(*onUpdate)(int)) 00464 { 00465 Callback<void(int)> fp; 00466 fp.attach(onUpdate); 00467 return define_resource(route, v, M2MBase::GET_PUT_ALLOWED, true, fp); 00468 } 00469 }; 00470 00471 #endif // __SIMPLE_MBED_CLIENT_H__
Generated on Mon Jul 18 2022 15:56:01 by
1.7.2
