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
UpdateClient.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 // Needed for PRIu64 on FreeRTOS 00020 #include <stdio.h> 00021 // Note: this macro is needed on armcc to get the the limit macros like UINT16_MAX 00022 #ifndef __STDC_LIMIT_MACROS 00023 #define __STDC_LIMIT_MACROS 00024 #endif 00025 00026 // Note: this macro is needed on armcc to get the the PRI*32 macros 00027 // from inttypes.h in a C++ code. 00028 #ifndef __STDC_FORMAT_MACROS 00029 #define __STDC_FORMAT_MACROS 00030 #endif 00031 00032 #ifdef MBED_CLOUD_CLIENT_USER_CONFIG_FILE 00033 #include MBED_CLOUD_CLIENT_USER_CONFIG_FILE 00034 #endif 00035 00036 #ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE 00037 #include "update-client-hub/update_client_hub.h" 00038 00039 #include "update-client-source-http/arm_uc_source_http.h" 00040 #include "update-client-lwm2m/lwm2m-source.h" 00041 #include "update-client-lwm2m/lwm2m-monitor.h" 00042 #include "update-client-lwm2m/lwm2m-control.h" 00043 #include "update-client-lwm2m/FirmwareUpdateResource.h" 00044 #include "update-client-lwm2m/DeviceMetadataResource.h" 00045 00046 #include "eventOS_scheduler.h" 00047 #include "eventOS_event.h" 00048 00049 #include "include/UpdateClient.h" 00050 #include "include/UpdateClientResources.h" 00051 #include "include/CloudClientStorage.h" 00052 #include "include/ServiceClient.h" 00053 00054 #include "pal.h" 00055 00056 #if (!defined(MBED_CONF_MBED_TRACE_ENABLE) || MBED_CONF_MBED_TRACE_ENABLE == 0) \ 00057 && ARM_UC_ALL_TRACE_ENABLE == 1 00058 #define tr_info(...) { printf(__VA_ARGS__); printf("\r\n"); } 00059 #else 00060 #include "mbed-trace/mbed_trace.h" 00061 #define TRACE_GROUP "uccc" 00062 #endif 00063 00064 /* To be removed once update storage is defined in user config file. 00065 Default to filesystem in the meantime. 00066 */ 00067 #ifndef MBED_CLOUD_CLIENT_UPDATE_STORAGE 00068 #define MBED_CLOUD_CLIENT_UPDATE_STORAGE ARM_UCP_FILESYSTEM 00069 #endif 00070 00071 #ifdef MBED_CLOUD_CLIENT_UPDATE_STORAGE 00072 extern ARM_UC_PAAL_UPDATE MBED_CLOUD_CLIENT_UPDATE_STORAGE; 00073 #else 00074 #error Update client storage must be defined in user configuration file 00075 #endif 00076 00077 namespace UpdateClient 00078 { 00079 enum UpdateClientEventType { 00080 UPDATE_CLIENT_EVENT_INITIALIZE, 00081 UPDATE_CLIENT_EVENT_PROCESS_QUEUE 00082 }; 00083 00084 static int8_t update_client_tasklet_id = -1; 00085 static FP1<void, int32_t> error_callback; 00086 00087 static void certificate_done(arm_uc_error_t error, 00088 const arm_uc_buffer_t* fingerprint); 00089 static void initialization(void); 00090 static void initialization_done(uintptr_t); 00091 static void event_handler(arm_event_s* event); 00092 static void queue_handler(void); 00093 static void schedule_event(void); 00094 static void error_handler(int32_t error); 00095 static M2MInterface *_m2m_interface; 00096 static ServiceClient *_service; 00097 } 00098 00099 void UpdateClient::UpdateClient(FP1<void, int32_t> callback, M2MInterface *m2mInterface, ServiceClient *service) 00100 { 00101 tr_info("Update Client External Initialization: %p", (void*)pal_osThreadGetId()); 00102 00103 /* store callback handler */ 00104 error_callback = callback; 00105 00106 if (m2mInterface) { 00107 _m2m_interface = m2mInterface; 00108 } 00109 if (service) { 00110 _service = service; 00111 } 00112 00113 /* create event */ 00114 eventOS_scheduler_mutex_wait(); 00115 if (update_client_tasklet_id == -1) { 00116 update_client_tasklet_id = eventOS_event_handler_create(UpdateClient::event_handler, 00117 UPDATE_CLIENT_EVENT_INITIALIZE); 00118 00119 tr_info("UpdateClient::update_client_tasklet_id: %d", 00120 update_client_tasklet_id); 00121 } 00122 eventOS_scheduler_mutex_release(); 00123 } 00124 00125 /** 00126 * @brief Populate M2MObjectList with Update Client objects. 00127 */ 00128 void UpdateClient::populate_object_list(M2MBaseList& list) 00129 { 00130 /* Setup Firmware Update LWM2M object */ 00131 list.push_back(FirmwareUpdateResource::getObject()); 00132 list.push_back(DeviceMetadataResource::getObject()); 00133 } 00134 00135 void UpdateClient::set_update_authorize_handler(void (*handler)(int32_t request)) 00136 { 00137 ARM_UC_SetAuthorizeHandler(handler); 00138 } 00139 00140 void UpdateClient::update_authorize(int32_t request) 00141 { 00142 switch (request) 00143 { 00144 case RequestDownload: 00145 ARM_UC_Authorize(ARM_UCCC_REQUEST_DOWNLOAD); 00146 break; 00147 case RequestInstall: 00148 ARM_UC_Authorize(ARM_UCCC_REQUEST_INSTALL); 00149 break; 00150 case RequestInvalid: 00151 default: 00152 break; 00153 } 00154 } 00155 00156 void UpdateClient::set_update_progress_handler(void (*handler)(uint32_t progress, uint32_t total)) 00157 { 00158 ARM_UC_SetProgressHandler(handler); 00159 } 00160 00161 static void UpdateClient::initialization(void) 00162 { 00163 tr_info("internal initialization: %p", (void*)pal_osThreadGetId()); 00164 00165 /* Register sources */ 00166 #if defined(MBED_CONF_MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL) && MBED_CONF_MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL == MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL_COAP 00167 static const ARM_UPDATE_SOURCE* sources[] = { 00168 &ARM_UCS_LWM2M_SOURCE 00169 }; 00170 #else 00171 static const ARM_UPDATE_SOURCE* sources[] = { 00172 &ARM_UCS_HTTPSource, 00173 &ARM_UCS_LWM2M_SOURCE 00174 }; 00175 #endif 00176 00177 ARM_UC_HUB_SetSources(sources, sizeof(sources)/sizeof(ARM_UPDATE_SOURCE*)); 00178 00179 #if defined(MBED_CONF_MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL) && MBED_CONF_MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL == MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL_COAP 00180 /* LWM2M Source needs to have access to M2MInterface for calling 00181 API M2MInterface::get_data_request() for firmware over COAP 00182 Blockwise transfer 00183 */ 00184 ARM_UC_CONTROL_SetM2MInterface(_m2m_interface); 00185 #endif 00186 00187 /* Register sink for telemetry */ 00188 ARM_UC_HUB_AddMonitor(&ARM_UCS_LWM2M_MONITOR); 00189 00190 /* Register local error handler */ 00191 ARM_UC_HUB_AddErrorCallback(UpdateClient::error_handler); 00192 00193 /* Link internal queue with external scheduler. 00194 The callback handler is called whenever a task is posted to 00195 an empty queue. This will trigger the queue to be processed. 00196 */ 00197 ARM_UC_HUB_AddNotificationHandler(UpdateClient::queue_handler); 00198 00199 /* The override function enables the LWM2M Firmware Update Object 00200 to authorize both download and installation. The intention is 00201 that a buggy user application can't block an update. 00202 */ 00203 ARM_UC_CONTROL_SetOverrideCallback(ARM_UC_OverrideAuthorization); 00204 00205 #ifdef MBED_CLOUD_CLIENT_UPDATE_STORAGE 00206 /* Set implementation for storing firmware */ 00207 ARM_UC_HUB_SetStorage(&MBED_CLOUD_CLIENT_UPDATE_STORAGE); 00208 #endif 00209 00210 #ifdef MBED_CLOUD_DEV_UPDATE_PSK 00211 /* Add pre shared key */ 00212 ARM_UC_AddPreSharedKey(arm_uc_default_psk, arm_uc_default_psk_bits); 00213 #endif 00214 00215 /* Insert default certificate if defined otherwise initialze 00216 Update client immediately. 00217 */ 00218 #ifdef MBED_CLOUD_DEV_UPDATE_CERT 00219 /* Add verification certificate */ 00220 arm_uc_error_t result = ARM_UC_AddCertificate(arm_uc_default_certificate, 00221 arm_uc_default_certificate_size, 00222 arm_uc_default_fingerprint, 00223 arm_uc_default_fingerprint_size, 00224 UpdateClient::certificate_done); 00225 00226 /* Certificate insertion failed, most likely because the certificate 00227 has already been inserted once before. 00228 00229 Continue initialization regardlessly, since the Update Client can still 00230 work if verification certificates are inserted through the Factory 00231 Client or by other means. 00232 */ 00233 if (result.code != ERR_NONE) 00234 { 00235 tr_info("ARM_UC_AddCertificate failed"); 00236 00237 ARM_UC_HUB_Initialize(UpdateClient::initialization_done); 00238 } 00239 #else 00240 ARM_UC_HUB_Initialize(UpdateClient::initialization_done); 00241 #endif 00242 } 00243 00244 static void UpdateClient::certificate_done(arm_uc_error_t error, 00245 const arm_uc_buffer_t* fingerprint) 00246 { 00247 (void) fingerprint; 00248 00249 /* Certificate insertion failure is not necessarily fatal. 00250 If verification certificates have been injected by other means 00251 it is still possible to perform updates, which is why the 00252 Update client initializes anyway. 00253 */ 00254 if (error.code != ERR_NONE) 00255 { 00256 error_callback.call(WarningCertificateInsertion); 00257 } 00258 00259 ARM_UC_HUB_Initialize(UpdateClient::initialization_done); 00260 } 00261 00262 static void UpdateClient::initialization_done(uintptr_t result) 00263 { 00264 tr_info("internal initialization done: %" PRIu32 " %p", result, (void*)pal_osThreadGetId()); 00265 if (_service) { 00266 _service->finish_initialization(); 00267 } 00268 } 00269 00270 static void UpdateClient::event_handler(arm_event_s* event) 00271 { 00272 switch (event->event_type) 00273 { 00274 case UPDATE_CLIENT_EVENT_INITIALIZE: 00275 UpdateClient::initialization(); 00276 break; 00277 00278 case UPDATE_CLIENT_EVENT_PROCESS_QUEUE: 00279 { 00280 /* process a single callback, for better cooperability */ 00281 bool queue_not_empty = ARM_UC_ProcessSingleCallback(); 00282 00283 if (queue_not_empty) 00284 { 00285 /* reschedule event handler, if queue is not empty */ 00286 UpdateClient::schedule_event(); 00287 } 00288 } 00289 break; 00290 00291 default: 00292 break; 00293 } 00294 } 00295 00296 static void UpdateClient::queue_handler(void) 00297 { 00298 /* warning: queue_handler can be called from interrupt context. 00299 */ 00300 UpdateClient::schedule_event(); 00301 } 00302 00303 static void UpdateClient::schedule_event() 00304 { 00305 /* schedule event */ 00306 arm_event_s event = {0}; 00307 event.receiver = update_client_tasklet_id; 00308 event.sender = 0; 00309 event.event_type = UPDATE_CLIENT_EVENT_PROCESS_QUEUE; 00310 event.event_id = 0; 00311 event.data_ptr = NULL; 00312 event.priority = ARM_LIB_LOW_PRIORITY_EVENT; 00313 event.event_data = 0; 00314 00315 eventOS_event_send(&event); 00316 } 00317 00318 static void UpdateClient::error_handler(int32_t error) 00319 { 00320 tr_info("error reported: %" PRIi32, error); 00321 00322 /* add warning base if less severe than error */ 00323 if (error < ARM_UC_ERROR) 00324 { 00325 error_callback.call(WarningBase + error); 00326 } 00327 /* add error base if less severe than fatal */ 00328 else if (error < ARM_UC_FATAL) 00329 { 00330 error_callback.call(ErrorBase + error); 00331 } 00332 /* add fatal base */ 00333 else 00334 { 00335 error_callback.call(FatalBase + error); 00336 } 00337 } 00338 00339 int UpdateClient::getVendorId(uint8_t* buffer, size_t buffer_size_max, size_t* value_size) 00340 { 00341 arm_uc_error_t err = ARM_UC_GetVendorId(buffer, buffer_size_max, value_size); 00342 if (err.code == ARM_UC_DI_ERR_SIZE) 00343 { 00344 return CCS_STATUS_MEMORY_ERROR; 00345 } 00346 if (err.error == ERR_NONE) 00347 { 00348 *value_size = 16; 00349 return CCS_STATUS_SUCCESS; 00350 } 00351 return CCS_STATUS_KEY_DOESNT_EXIST; 00352 } 00353 int UpdateClient::getClassId(uint8_t* buffer, size_t buffer_size_max, size_t* value_size) 00354 { 00355 arm_uc_error_t err = ARM_UC_GetClassId(buffer, buffer_size_max, value_size); 00356 if (err.code == ARM_UC_DI_ERR_SIZE) 00357 { 00358 return CCS_STATUS_MEMORY_ERROR; 00359 } 00360 if (err.error == ERR_NONE) 00361 { 00362 *value_size = 16; 00363 return CCS_STATUS_SUCCESS; 00364 } 00365 return CCS_STATUS_KEY_DOESNT_EXIST; 00366 } 00367 int UpdateClient::getDeviceId(uint8_t* buffer, size_t buffer_size_max, size_t* value_size) 00368 { 00369 arm_uc_error_t err = ARM_UC_GetDeviceId(buffer, buffer_size_max, value_size); 00370 if (err.code == ARM_UC_DI_ERR_SIZE) 00371 { 00372 return CCS_STATUS_MEMORY_ERROR; 00373 } 00374 if (err.error == ERR_NONE) 00375 { 00376 *value_size = 16; 00377 return CCS_STATUS_SUCCESS; 00378 } 00379 return CCS_STATUS_KEY_DOESNT_EXIST; 00380 } 00381 00382 #endif
Generated on Tue Jul 12 2022 20:21:04 by
