Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UpdateClient.cpp Source File

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