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