Simple interface for Mbed Cloud Client
Embed:
(wiki syntax)
Show/hide line numbers
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