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.
Dependencies: FXAS21002 FXOS8700Q
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 Tue Jul 12 2022 20:21:02 by
