Simulated product dispenser
Fork of mbed-cloud-workshop-connect-HTS221 by
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 19:12:15 by 1.7.2