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