Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

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 
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(M2MBaseList& 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 = {0};
00280     event.receiver = update_client_tasklet_id;
00281     event.sender = 0;
00282     event.event_type = UPDATE_CLIENT_EVENT_PROCESS_QUEUE;
00283     event.event_id = 0;
00284     event.data_ptr = NULL;
00285     event.priority = ARM_LIB_LOW_PRIORITY_EVENT;
00286     event.event_data = 0;
00287 
00288     eventOS_event_send(&event);
00289 }
00290 
00291 static void UpdateClient::error_handler(int32_t error)
00292 {
00293     tr_info("error reported: %" PRIi32, error);
00294 
00295     /* add warning base if less severe than error */
00296     if (error < ARM_UC_ERROR)
00297     {
00298         error_callback.call(WarningBase + error);
00299     }
00300     /* add error base if less severe than fatal */
00301     else if (error < ARM_UC_FATAL)
00302     {
00303         error_callback.call(ErrorBase + error);
00304     }
00305     /* add fatal base */
00306     else
00307     {
00308         error_callback.call(FatalBase + error);
00309     }
00310 }
00311 
00312 int UpdateClient::getVendorId(uint8_t* buffer, size_t buffer_size_max, size_t* value_size)
00313 {
00314     arm_uc_error_t err = ARM_UC_GetVendorId(buffer, buffer_size_max, value_size);
00315     if (err.code == ARM_UC_DI_ERR_SIZE)
00316     {
00317         return CCS_STATUS_MEMORY_ERROR;
00318     }
00319     if (err.error == ERR_NONE)
00320     {
00321         *value_size = 16;
00322         return CCS_STATUS_SUCCESS;
00323     }
00324     return CCS_STATUS_KEY_DOESNT_EXIST;
00325 }
00326 int UpdateClient::getClassId(uint8_t* buffer, size_t buffer_size_max, size_t* value_size)
00327 {
00328     arm_uc_error_t err = ARM_UC_GetClassId(buffer, buffer_size_max, value_size);
00329     if (err.code == ARM_UC_DI_ERR_SIZE)
00330     {
00331         return CCS_STATUS_MEMORY_ERROR;
00332     }
00333     if (err.error == ERR_NONE)
00334     {
00335         *value_size = 16;
00336         return CCS_STATUS_SUCCESS;
00337     }
00338     return CCS_STATUS_KEY_DOESNT_EXIST;
00339 }
00340 int UpdateClient::getDeviceId(uint8_t* buffer, size_t buffer_size_max, size_t* value_size)
00341 {
00342     arm_uc_error_t err = ARM_UC_GetDeviceId(buffer, buffer_size_max, value_size);
00343     if (err.code == ARM_UC_DI_ERR_SIZE)
00344     {
00345         return CCS_STATUS_MEMORY_ERROR;
00346     }
00347     if (err.error == ERR_NONE)
00348     {
00349         *value_size = 16;
00350         return CCS_STATUS_SUCCESS;
00351     }
00352     return CCS_STATUS_KEY_DOESNT_EXIST;
00353 }
00354 
00355 #endif