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.
ServiceClient.cpp
00001 // ---------------------------------------------------------------------------- 00002 // Copyright 2016-2017 ARM Ltd. 00003 // 00004 // SPDX-License-Identifier: Apache-2.0 00005 // 00006 // Licensed under the Apache License, Version 2.0 (the "License"); 00007 // you may not use this file except in compliance with the License. 00008 // You may obtain a copy of the License at 00009 // 00010 // http://www.apache.org/licenses/LICENSE-2.0 00011 // 00012 // Unless required by applicable law or agreed to in writing, software 00013 // distributed under the License is distributed on an "AS IS" BASIS, 00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 // See the License for the specific language governing permissions and 00016 // limitations under the License. 00017 // ---------------------------------------------------------------------------- 00018 00019 // Note: this macro is needed on armcc to get the the PRI*32 macros 00020 // from inttypes.h in a C++ code. 00021 #ifndef __STDC_FORMAT_MACROS 00022 #define __STDC_FORMAT_MACROS 00023 #endif 00024 #include <inttypes.h> 00025 00026 #include <string> 00027 #include "include/ServiceClient.h" 00028 #include "include/CloudClientStorage.h" 00029 #include "include/UpdateClientResources.h" 00030 #include "include/UpdateClient.h" 00031 #include "factory_configurator_client.h" 00032 #include "mbed-client/m2mconstants.h" 00033 #include "mbed-trace/mbed_trace.h" 00034 #include <assert.h> 00035 00036 #define TRACE_GROUP "mClt" 00037 00038 #define CONNECT 0 00039 #define ERROR_UPDATE "Update has failed, check MbedCloudClient::Error" 00040 00041 /* lookup table for printing hexadecimal values */ 00042 const uint8_t ServiceClient::hex_table[16] = { 00043 '0', '1', '2', '3', '4', '5', '6', '7', 00044 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' 00045 }; 00046 00047 ServiceClient::ServiceClient(ServiceClientCallback& callback) 00048 : _service_callback(callback), 00049 _service_uri(NULL), 00050 _stack(NULL), 00051 _client_objs(NULL), 00052 _current_state(State_Init), 00053 _event_generated(false), 00054 _state_engine_running(false), 00055 #ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE 00056 _setup_update_client(false), 00057 #endif 00058 _connector_client(this) 00059 { 00060 } 00061 00062 ServiceClient::~ServiceClient() 00063 { 00064 #ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE 00065 ARM_UC_HUB_Uninitialize(); 00066 #endif 00067 } 00068 00069 void ServiceClient::initialize_and_register(M2MBaseList& reg_objs) 00070 { 00071 tr_debug("ServiceClient::initialize_and_register"); 00072 if(_current_state == State_Init || 00073 _current_state == State_Unregister || 00074 _current_state == State_Failure) { 00075 _client_objs = ®_objs; 00076 00077 #ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE 00078 tr_debug("ServiceClient::initialize_and_register: update client supported"); 00079 00080 if(!_setup_update_client) { 00081 _setup_update_client = true; 00082 00083 #ifdef MBED_CLOUD_DEV_UPDATE_ID 00084 /* Overwrite values stored in KCM. This is for development only 00085 since these IDs should be provisioned in the factory. 00086 */ 00087 tr_debug("ServiceClient::initialize_and_register: update IDs defined"); 00088 00089 /* Delete VendorId */ 00090 ccs_delete_item("mbed.VendorId", CCS_CONFIG_ITEM); 00091 /* Store Vendor Id to mbed.VendorId. No conversion is performed. */ 00092 set_device_resource_value(M2MDevice::Manufacturer, 00093 (const char*) arm_uc_vendor_id, 00094 arm_uc_vendor_id_size); 00095 00096 /* Delete ClassId */ 00097 ccs_delete_item("mbed.ClassId", CCS_CONFIG_ITEM); 00098 /* Store Class Id to mbed.ClassId. No conversion is performed. */ 00099 set_device_resource_value(M2MDevice::ModelNumber, 00100 (const char*) arm_uc_class_id, 00101 arm_uc_class_id_size); 00102 #endif /* MBED_CLOUD_DEV_UPDATE_ID */ 00103 00104 #ifdef ARM_UPDATE_CLIENT_VERSION 00105 /* Inject Update Client version number if no other software 00106 version is present in the KCM. 00107 */ 00108 tr_debug("ServiceClient::initialize_and_register: update version defined"); 00109 ; 00110 const size_t buffer_size = 16; 00111 uint8_t buffer[buffer_size]; 00112 size_t size = 0; 00113 00114 /* check if software version is already set */ 00115 ccs_status_e status = ccs_get_item(KEY_DEVICE_SOFTWAREVERSION, 00116 buffer, buffer_size, &size, CCS_CONFIG_ITEM); 00117 00118 if (status == CCS_STATUS_KEY_DOESNT_EXIST) { 00119 tr_debug("ServiceClient::initialize_and_register: insert update version"); 00120 00121 /* insert value from Update Client Common */ 00122 ccs_set_item(KEY_DEVICE_SOFTWAREVERSION, 00123 (const uint8_t*) ARM_UPDATE_CLIENT_VERSION, 00124 sizeof(ARM_UPDATE_CLIENT_VERSION), 00125 CCS_CONFIG_ITEM); 00126 } 00127 #endif /* ARM_UPDATE_CLIENT_VERSION */ 00128 00129 /* Update Client adds the OMA LWM2M Firmware Update object */ 00130 UpdateClient::populate_object_list(*_client_objs); 00131 00132 /* Initialize Update Client */ 00133 FP1<void, int32_t> callback(this, &ServiceClient::update_error_callback); 00134 UpdateClient::UpdateClient(callback); 00135 } 00136 #endif /* MBED_CLOUD_CLIENT_SUPPORT_UPDATE */ 00137 00138 /* Device Object is mandatory. 00139 Get instance and add it to object list 00140 */ 00141 M2MDevice *device_object = device_object_from_storage(); 00142 00143 if (device_object) { 00144 M2MObjectInstance* instance = device_object->object_instance(0); 00145 if (instance) { 00146 M2MResource *res = instance->resource(DEVICE_MANUFACTURER); 00147 if (res) { 00148 res->publish_value_in_registration_msg(true); 00149 } 00150 res = instance->resource(DEVICE_MODEL_NUMBER); 00151 if (res) { 00152 res->publish_value_in_registration_msg(true); 00153 } 00154 res = instance->resource(DEVICE_SERIAL_NUMBER); 00155 if (res) { 00156 res->publish_value_in_registration_msg(true); 00157 } 00158 } 00159 /* Publish device object resource to mds */ 00160 M2MResourceList list = device_object->object_instance()->resources(); 00161 if(!list.empty()) { 00162 M2MResourceList::const_iterator it; 00163 it = list.begin(); 00164 for ( ; it != list.end(); it++ ) { 00165 (*it)->set_register_uri(true); 00166 } 00167 } 00168 00169 /* Add Device Object to object list. */ 00170 _client_objs->push_back(device_object); 00171 } 00172 00173 internal_event(State_Bootstrap); 00174 } else if (_current_state == State_Success) { 00175 state_success(); 00176 } 00177 } 00178 00179 ConnectorClient &ServiceClient::connector_client() 00180 { 00181 return _connector_client; 00182 } 00183 00184 const ConnectorClient &ServiceClient::connector_client() const 00185 { 00186 return _connector_client; 00187 } 00188 00189 // generates an internal event. called from within a state 00190 // function to transition to a new state 00191 void ServiceClient::internal_event(StartupMainState new_state) 00192 { 00193 tr_debug("ServiceClient::internal_event: state: %d -> %d", _current_state, new_state); 00194 00195 _event_generated = true; 00196 _current_state = new_state; 00197 00198 if (!_state_engine_running) { 00199 state_engine(); 00200 } 00201 } 00202 00203 // the state engine executes the state machine states 00204 void ServiceClient::state_engine(void) 00205 { 00206 tr_debug("ServiceClient::state_engine"); 00207 00208 // this simple flagging gets rid of recursive calls to this method 00209 _state_engine_running = true; 00210 00211 // while events are being generated keep executing states 00212 while (_event_generated) { 00213 _event_generated = false; // event used up, reset flag 00214 00215 state_function(_current_state); 00216 } 00217 00218 _state_engine_running = false; 00219 } 00220 00221 void ServiceClient::state_function(StartupMainState current_state) 00222 { 00223 switch (current_state) { 00224 case State_Init: // -> Goes to bootstrap state 00225 case State_Bootstrap: // -> State_Register OR State_Failure 00226 state_bootstrap(); 00227 break; 00228 case State_Register: // -> State_Succes OR State_Failure 00229 state_register(); 00230 break; 00231 case State_Success: // return success to user 00232 state_success(); 00233 break; 00234 case State_Failure: // return error to user 00235 state_failure(); 00236 break; 00237 case State_Unregister: // return error to user 00238 state_unregister(); 00239 break; 00240 } 00241 } 00242 00243 void ServiceClient::state_bootstrap() 00244 { 00245 tr_info("ServiceClient::state_bootstrap()"); 00246 bool credentials_ready = _connector_client.connector_credentials_available(); 00247 bool bootstrap = _connector_client.use_bootstrap(); 00248 tr_info("ServiceClient::state_bootstrap() - lwm2m credentials available: %d", credentials_ready); 00249 tr_info("ServiceClient::state_bootstrap() - use bootstrap: %d", bootstrap); 00250 if (credentials_ready || !bootstrap) { 00251 internal_event(State_Register); 00252 } else { 00253 _connector_client.start_bootstrap(); 00254 } 00255 } 00256 00257 void ServiceClient::state_register() 00258 { 00259 tr_info("ServiceClient::state_register()"); 00260 _connector_client.start_registration(_client_objs); 00261 } 00262 00263 void ServiceClient::registration_process_result(ConnectorClient::StartupSubStateRegistration status) 00264 { 00265 tr_debug("ServiceClient::registration_process_result(): status: %d", status); 00266 if (status == ConnectorClient::State_Registration_Success) { 00267 internal_event(State_Success); 00268 } else if(status == ConnectorClient::State_Registration_Failure || 00269 status == ConnectorClient::State_Bootstrap_Failure){ 00270 internal_event(State_Failure); // XXX: the status should be saved to eg. event object 00271 } 00272 if(status == ConnectorClient::State_Bootstrap_Success) { 00273 internal_event(State_Register); 00274 } 00275 if(status == ConnectorClient::State_Unregistered) { 00276 internal_event(State_Unregister); 00277 } 00278 if (status == ConnectorClient::State_Registration_Updated) { 00279 _service_callback.complete(ServiceClientCallback::Service_Client_Status_Register_Updated); 00280 } 00281 } 00282 00283 void ServiceClient::connector_error(M2MInterface::Error error, const char *reason) 00284 { 00285 tr_error("ServiceClient::connector_error() error %d", (int)error); 00286 if (_current_state == State_Register) { 00287 registration_process_result(ConnectorClient::State_Registration_Failure); 00288 } 00289 else if (_current_state == State_Bootstrap) { 00290 registration_process_result(ConnectorClient::State_Bootstrap_Failure); 00291 } 00292 _service_callback.error(int(error),reason); 00293 internal_event(State_Failure); 00294 } 00295 00296 void ServiceClient::value_updated(M2MBase *base, M2MBase::BaseType type) 00297 { 00298 tr_debug("ServiceClient::value_updated()"); 00299 _service_callback.value_updated(base, type); 00300 } 00301 00302 void ServiceClient::state_success() 00303 { 00304 tr_info("ServiceClient::state_success()"); 00305 // this is verified already at client API level, but this might still catch some logic failures 00306 _service_callback.complete(ServiceClientCallback::Service_Client_Status_Registered); 00307 } 00308 00309 void ServiceClient::state_failure() 00310 { 00311 tr_error("ServiceClient::state_failure()"); 00312 _service_callback.complete(ServiceClientCallback::Service_Client_Status_Failure); 00313 } 00314 00315 void ServiceClient::state_unregister() 00316 { 00317 tr_debug("ServiceClient::state_unregister()"); 00318 _service_callback.complete(ServiceClientCallback::Service_Client_Status_Unregistered); 00319 } 00320 00321 M2MDevice* ServiceClient::device_object_from_storage() 00322 { 00323 M2MDevice *device_object = M2MInterfaceFactory::create_device(); 00324 if (device_object == NULL) { 00325 return NULL; 00326 } 00327 00328 const size_t buffer_size = 128; 00329 uint8_t buffer[buffer_size]; 00330 size_t size = 0; 00331 00332 #ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE 00333 uint8_t guid[sizeof(arm_uc_guid_t)] = {0}; 00334 // Read out the binary Vendor UUID 00335 ccs_status_e status = (ccs_status_e)UpdateClient::getVendorId(guid, sizeof(arm_uc_guid_t), &size); 00336 00337 // Format the binary Vendor UUID into a hex string 00338 if (status == CCS_STATUS_SUCCESS) { 00339 size_t j = 0; 00340 for(size_t i = 0; i < size; i++) 00341 { 00342 buffer[j++] = hex_table[(guid[i] >> 4) & 0xF]; 00343 buffer[j++] = hex_table[(guid[i] >> 0) & 0xF]; 00344 } 00345 buffer[j] = '\0'; 00346 const String data((char*)buffer, size * 2); 00347 // create_resource() returns NULL if resource already exists 00348 if (device_object->create_resource(M2MDevice::Manufacturer, data) == NULL) { 00349 device_object->set_resource_value(M2MDevice::Manufacturer, data); 00350 } 00351 } 00352 00353 // Read out the binary Class UUID 00354 status = (ccs_status_e)UpdateClient::getClassId(guid, sizeof(arm_uc_guid_t), &size); 00355 00356 // Format the binary Class UUID into a hex string 00357 if (status == CCS_STATUS_SUCCESS) { 00358 size_t j = 0; 00359 for(size_t i = 0; i < size; i++) 00360 { 00361 buffer[j++] = hex_table[(guid[i] >> 4) & 0xF]; 00362 buffer[j++] = hex_table[(guid[i] >> 0) & 0xF]; 00363 } 00364 buffer[j] = '\0'; 00365 const String data((char*)buffer, size * 2); 00366 // create_resource() returns NULL if resource already exists 00367 if (device_object->create_resource(M2MDevice::ModelNumber, data) == NULL) { 00368 device_object->set_resource_value(M2MDevice::ModelNumber, data); 00369 } 00370 } 00371 #else 00372 // Read values to device object 00373 // create_resource() function returns NULL if resource already exists 00374 ccs_status_e status = ccs_get_item(g_fcc_manufacturer_parameter_name, buffer, buffer_size, &size, CCS_CONFIG_ITEM); 00375 if (status == CCS_STATUS_SUCCESS) { 00376 const String data((char*)buffer, size); 00377 if (device_object->create_resource(M2MDevice::Manufacturer, data) == NULL) { 00378 device_object->set_resource_value(M2MDevice::Manufacturer, data); 00379 } 00380 } 00381 status = ccs_get_item(g_fcc_model_number_parameter_name, buffer, buffer_size, &size, CCS_CONFIG_ITEM); 00382 if (status == CCS_STATUS_SUCCESS) { 00383 const String data((char*)buffer, size); 00384 if (device_object->create_resource(M2MDevice::ModelNumber, data) == NULL) { 00385 device_object->set_resource_value(M2MDevice::ModelNumber, data); 00386 } 00387 } 00388 #endif 00389 status = ccs_get_item(g_fcc_device_serial_number_parameter_name, buffer, buffer_size, &size, CCS_CONFIG_ITEM); 00390 if (status == CCS_STATUS_SUCCESS) { 00391 const String data((char*)buffer, size); 00392 if (device_object->create_resource(M2MDevice::SerialNumber, data) == NULL) { 00393 device_object->set_resource_value(M2MDevice::SerialNumber, data); 00394 } 00395 } 00396 00397 status = ccs_get_item(g_fcc_device_type_parameter_name, buffer, buffer_size, &size, CCS_CONFIG_ITEM); 00398 if (status == CCS_STATUS_SUCCESS) { 00399 const String data((char*)buffer, size); 00400 if (device_object->create_resource(M2MDevice::DeviceType, data) == NULL) { 00401 device_object->set_resource_value(M2MDevice::DeviceType, data); 00402 } 00403 } 00404 00405 status = ccs_get_item(g_fcc_hardware_version_parameter_name, buffer, buffer_size, &size, CCS_CONFIG_ITEM); 00406 if (status == CCS_STATUS_SUCCESS) { 00407 const String data((char*)buffer, size); 00408 if (device_object->create_resource(M2MDevice::HardwareVersion, data) == NULL) { 00409 device_object->set_resource_value(M2MDevice::HardwareVersion, data); 00410 } 00411 } 00412 00413 status = ccs_get_item(KEY_DEVICE_SOFTWAREVERSION, buffer, buffer_size, &size, CCS_CONFIG_ITEM); 00414 if (status == CCS_STATUS_SUCCESS) { 00415 const String data((char*)buffer, size); 00416 if (device_object->create_resource(M2MDevice::SoftwareVersion, data) == NULL) { 00417 device_object->set_resource_value(M2MDevice::SoftwareVersion, data); 00418 } 00419 } 00420 00421 uint8_t data[4] = {0}; 00422 uint32_t value; 00423 status = ccs_get_item(g_fcc_memory_size_parameter_name, data, 4, &size, CCS_CONFIG_ITEM); 00424 if (status == CCS_STATUS_SUCCESS) { 00425 memcpy(&value, data, 4); 00426 if (device_object->create_resource(M2MDevice::MemoryTotal, value) == NULL) { 00427 device_object->set_resource_value(M2MDevice::MemoryTotal, value); 00428 } 00429 tr_debug("ServiceClient::device_object_from_storage() - setting memory total value %" PRIu32 " (%s)", value, tr_array(data, 4)); 00430 } 00431 00432 status = ccs_get_item(g_fcc_current_time_parameter_name, data, 4, &size, CCS_CONFIG_ITEM); 00433 if (status == CCS_STATUS_SUCCESS) { 00434 memcpy(&value, data, 4); 00435 if (device_object->create_resource(M2MDevice::CurrentTime, value) == NULL) { 00436 device_object->set_resource_value(M2MDevice::CurrentTime, value); 00437 } 00438 tr_debug("ServiceClient::device_object_from_storage() - setting current time value %" PRIu32 " (%s)", value, tr_array(data, 4)); 00439 } 00440 00441 status = ccs_get_item(g_fcc_device_time_zone_parameter_name, buffer, buffer_size, &size, CCS_CONFIG_ITEM); 00442 if (status == CCS_STATUS_SUCCESS) { 00443 const String data((char*)buffer, size); 00444 if (device_object->create_resource(M2MDevice::Timezone, data) == NULL) { 00445 device_object->set_resource_value(M2MDevice::Timezone, data); 00446 } 00447 } 00448 00449 status = ccs_get_item(g_fcc_offset_from_utc_parameter_name, buffer, buffer_size, &size, CCS_CONFIG_ITEM); 00450 if (status == CCS_STATUS_SUCCESS) { 00451 const String data((char*)buffer, size); 00452 if (device_object->create_resource(M2MDevice::UTCOffset, data) == NULL) { 00453 device_object->set_resource_value(M2MDevice::UTCOffset, data); 00454 } 00455 } 00456 00457 return device_object; 00458 } 00459 00460 /** 00461 * \brief Set resource value in the Device Object 00462 * 00463 * \param resource Device enum to have value set. 00464 * \param value String object. 00465 * \return True if successful, false otherwise. 00466 */ 00467 bool ServiceClient::set_device_resource_value(M2MDevice::DeviceResource resource, 00468 const std::string& value) 00469 { 00470 return set_device_resource_value(resource, 00471 value.c_str(), 00472 value.size() - 1); 00473 } 00474 00475 /** 00476 * \brief Set resource value in the Device Object 00477 * 00478 * \param resource Device enum to have value set. 00479 * \param value Byte buffer. 00480 * \param length Buffer length. 00481 * \return True if successful, false otherwise. 00482 */ 00483 bool ServiceClient::set_device_resource_value(M2MDevice::DeviceResource resource, 00484 const char* value, 00485 uint32_t length) 00486 { 00487 bool retval = false; 00488 00489 /* sanity check */ 00490 if (value && (length < 256) && (length > 0)) 00491 { 00492 #ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE 00493 /* Pass resource value to Update Client. 00494 Used for validating the manifest. 00495 */ 00496 switch (resource) { 00497 case M2MDevice::Manufacturer: 00498 ARM_UC_SetVendorId((const uint8_t*) value, length); 00499 break; 00500 case M2MDevice::ModelNumber: 00501 ARM_UC_SetClassId((const uint8_t*) value, length); 00502 break; 00503 default: 00504 break; 00505 } 00506 #endif 00507 00508 /* Convert resource to printable string if necessary */ 00509 00510 /* Getting object instance from factory */ 00511 M2MDevice *device_object = M2MInterfaceFactory::create_device(); 00512 00513 /* Check device object and resource both are present */ 00514 if (device_object && device_object->is_resource_present(resource)) { 00515 /* set counter to not-zero */ 00516 uint8_t printable_length = 0xFF; 00517 00518 /* set printable_length to 0 if the buffer is not printable */ 00519 for (uint8_t index = 0; index < length; index++) { 00520 /* break if character is not printable */ 00521 if ((value[index] < ' ') || (value[index] > '~')) { 00522 printable_length = 0; 00523 break; 00524 } 00525 } 00526 00527 /* resource is a string */ 00528 if (printable_length != 0) { 00529 /* reset counter */ 00530 printable_length = 0; 00531 00532 /* find actual printable length */ 00533 for ( ; printable_length < length; printable_length++) { 00534 /* break prematurely if end-of-string character is found */ 00535 if (value[printable_length] == '\0') { 00536 break; 00537 } 00538 } 00539 00540 /* convert to string and set value in object */ 00541 String string_value(value, printable_length); 00542 retval = device_object->set_resource_value(resource, string_value); 00543 } 00544 else 00545 { 00546 /* resource is a byte array */ 00547 char value_buffer[0xFF] = { 0 }; 00548 00549 /* count length */ 00550 uint8_t index = 0; 00551 00552 /* convert byte array to string */ 00553 for ( ; 00554 (index < length) && ((2*index +1) < 0xFF); 00555 index++) { 00556 00557 uint8_t byte = value[index]; 00558 00559 value_buffer[2 * index] = hex_table[byte >> 4]; 00560 value_buffer[2 * index + 1] = hex_table[byte & 0x0F]; 00561 } 00562 00563 /* convert to string and set value in object */ 00564 String string_value(value_buffer, 2 * (index - 1)); 00565 retval = device_object->set_resource_value(resource, string_value); 00566 } 00567 } 00568 } 00569 00570 return retval; 00571 } 00572 00573 #ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE 00574 void ServiceClient::set_update_authorize_handler(void (*handler)(int32_t request)) 00575 { 00576 UpdateClient::set_update_authorize_handler(handler); 00577 } 00578 00579 void ServiceClient::update_authorize(int32_t request) 00580 { 00581 UpdateClient::update_authorize(request); 00582 } 00583 00584 void ServiceClient::set_update_progress_handler(void (*handler)(uint32_t progress, uint32_t total)) 00585 { 00586 UpdateClient::set_update_progress_handler(handler); 00587 } 00588 00589 void ServiceClient::update_error_callback(int32_t error) 00590 { 00591 _service_callback.error(error, ERROR_UPDATE); 00592 } 00593 #endif
Generated on Tue Jul 12 2022 16:24:20 by
1.7.2