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