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.
Diff: mbed-cloud-client/source/UpdateClient.cpp
- Revision:
- 0:276e7a263c35
diff -r 000000000000 -r 276e7a263c35 mbed-cloud-client/source/UpdateClient.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-cloud-client/source/UpdateClient.cpp Mon Jul 02 06:30:39 2018 +0000
@@ -0,0 +1,356 @@
+// ----------------------------------------------------------------------------
+// Copyright 2016-2017 ARM Ltd.
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------
+
+// Needed for PRIu64 on FreeRTOS
+#include <stdio.h>
+// Note: this macro is needed on armcc to get the the limit macros like UINT16_MAX
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+
+// Note: this macro is needed on armcc to get the the PRI*32 macros
+// from inttypes.h in a C++ code.
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS
+#endif
+
+#ifdef MBED_CLOUD_CLIENT_USER_CONFIG_FILE
+#include MBED_CLOUD_CLIENT_USER_CONFIG_FILE
+#endif
+
+#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE
+#include "update-client-hub/update_client_hub.h"
+
+#include "update-client-source-http/arm_uc_source_http.h"
+#include "update-client-lwm2m/lwm2m-source.h"
+#include "update-client-lwm2m/lwm2m-monitor.h"
+#include "update-client-lwm2m/lwm2m-control.h"
+#include "update-client-lwm2m/FirmwareUpdateResource.h"
+#include "update-client-lwm2m/DeviceMetadataResource.h"
+
+#include "eventOS_scheduler.h"
+#include "eventOS_event.h"
+
+#include "include/UpdateClient.h"
+#include "include/UpdateClientResources.h"
+#include "include/CloudClientStorage.h"
+
+#include "pal.h"
+
+#if (!defined(MBED_CONF_MBED_TRACE_ENABLE) || MBED_CONF_MBED_TRACE_ENABLE == 0) \
+ && ARM_UC_ALL_TRACE_ENABLE == 1
+#define tr_info(...) { printf(__VA_ARGS__); printf("\r\n"); }
+#else
+#include "mbed-trace/mbed_trace.h"
+#define TRACE_GROUP "uccc"
+#endif
+
+/* To be removed once update storage is defined in user config file.
+ Default to filesystem in the meantime.
+*/
+#ifndef MBED_CLOUD_CLIENT_UPDATE_STORAGE
+#define MBED_CLOUD_CLIENT_UPDATE_STORAGE ARM_UCP_FILESYSTEM
+#endif
+
+#ifdef MBED_CLOUD_CLIENT_UPDATE_STORAGE
+extern ARM_UC_PAAL_UPDATE MBED_CLOUD_CLIENT_UPDATE_STORAGE;
+#else
+#error Update client storage must be defined in user configuration file
+#endif
+
+namespace UpdateClient
+{
+ enum UpdateClientEventType {
+ UPDATE_CLIENT_EVENT_INITIALIZE,
+ UPDATE_CLIENT_EVENT_PROCESS_QUEUE
+ };
+
+ static int8_t update_client_tasklet_id = -1;
+ static FP1<void, int32_t> error_callback;
+
+ static void certificate_done(arm_uc_error_t error,
+ const arm_uc_buffer_t* fingerprint);
+ static void initialization(void);
+ static void initialization_done(int32_t);
+ static void event_handler(arm_event_s* event);
+ static void queue_handler(void);
+ static void schedule_event(void);
+ static void error_handler(int32_t error);
+}
+
+void UpdateClient::UpdateClient(FP1<void, int32_t> callback)
+{
+ tr_info("Update Client External Initialization: %p", (void*)pal_osThreadGetId());
+
+ /* store callback handler */
+ error_callback = callback;
+
+ /* create event */
+ eventOS_scheduler_mutex_wait();
+ if (update_client_tasklet_id == -1) {
+ update_client_tasklet_id = eventOS_event_handler_create(UpdateClient::event_handler,
+ UPDATE_CLIENT_EVENT_INITIALIZE);
+
+ tr_info("UpdateClient::update_client_tasklet_id: %d",
+ update_client_tasklet_id);
+ }
+ eventOS_scheduler_mutex_release();
+}
+
+/**
+ * @brief Populate M2MObjectList with Update Client objects.
+ */
+void UpdateClient::populate_object_list(M2MObjectList& list)
+{
+ /* Setup Firmware Update LWM2M object */
+ list.push_back(FirmwareUpdateResource::getObject());
+ list.push_back(DeviceMetadataResource::getObject());
+}
+
+void UpdateClient::set_update_authorize_handler(void (*handler)(int32_t request))
+{
+ ARM_UC_SetAuthorizeHandler(handler);
+}
+
+void UpdateClient::update_authorize(int32_t request)
+{
+ switch (request)
+ {
+ case RequestDownload:
+ ARM_UC_Authorize(ARM_UCCC_REQUEST_DOWNLOAD);
+ break;
+ case RequestInstall:
+ ARM_UC_Authorize(ARM_UCCC_REQUEST_INSTALL);
+ break;
+ case RequestInvalid:
+ default:
+ break;
+ }
+}
+
+void UpdateClient::set_update_progress_handler(void (*handler)(uint32_t progress, uint32_t total))
+{
+ ARM_UC_SetProgressHandler(handler);
+}
+
+static void UpdateClient::initialization(void)
+{
+ tr_info("internal initialization: %p", (void*)pal_osThreadGetId());
+
+ /* Register sources */
+ static const ARM_UPDATE_SOURCE* sources[] = {
+ &ARM_UCS_HTTPSource,
+ &ARM_UCS_LWM2M_SOURCE
+ };
+
+ ARM_UC_HUB_SetSources(sources, sizeof(sources)/sizeof(ARM_UPDATE_SOURCE*));
+
+ /* Register sink for telemetry */
+ ARM_UC_HUB_AddMonitor(&ARM_UCS_LWM2M_MONITOR);
+
+ /* Register local error handler */
+ ARM_UC_HUB_AddErrorCallback(UpdateClient::error_handler);
+
+ /* Link internal queue with external scheduler.
+ The callback handler is called whenever a task is posted to
+ an empty queue. This will trigger the queue to be processed.
+ */
+ ARM_UC_HUB_AddNotificationHandler(UpdateClient::queue_handler);
+
+ /* The override function enables the LWM2M Firmware Update Object
+ to authorize both download and installation. The intention is
+ that a buggy user application can't block an update.
+ */
+ ARM_UC_CONTROL_SetOverrideCallback(ARM_UC_OverrideAuthorization);
+
+#ifdef MBED_CLOUD_CLIENT_UPDATE_STORAGE
+ /* Set implementation for storing firmware */
+ ARM_UC_HUB_SetStorage(&MBED_CLOUD_CLIENT_UPDATE_STORAGE);
+#endif
+
+#ifdef MBED_CLOUD_DEV_UPDATE_PSK
+ /* Add pre shared key */
+ ARM_UC_AddPreSharedKey(arm_uc_default_psk, arm_uc_default_psk_bits);
+#endif
+
+ /* Insert default certificate if defined otherwise initialze
+ Update client immediately.
+ */
+#ifdef MBED_CLOUD_DEV_UPDATE_CERT
+ /* Add verification certificate */
+ arm_uc_error_t result = ARM_UC_AddCertificate(arm_uc_default_certificate,
+ arm_uc_default_certificate_size,
+ arm_uc_default_fingerprint,
+ arm_uc_default_fingerprint_size,
+ UpdateClient::certificate_done);
+
+ /* Certificate insertion failed, most likely because the certificate
+ has already been inserted once before.
+
+ Continue initialization regardlessly, since the Update Client can still
+ work if verification certificates are inserted through the Factory
+ Client or by other means.
+ */
+ if (result.code != ARM_UC_CM_ERR_NONE)
+ {
+ tr_info("ARM_UC_AddCertificate failed");
+
+ ARM_UC_HUB_Initialize(UpdateClient::initialization_done);
+ }
+#else
+ ARM_UC_HUB_Initialize(UpdateClient::initialization_done);
+#endif
+}
+
+static void UpdateClient::certificate_done(arm_uc_error_t error,
+ const arm_uc_buffer_t* fingerprint)
+{
+ (void) fingerprint;
+
+ /* Certificate insertion failure is not necessarily fatal.
+ If verification certificates have been injected by other means
+ it is still possible to perform updates, which is why the
+ Update client initializes anyway.
+ */
+ if (error.code != ARM_UC_CM_ERR_NONE)
+ {
+ error_callback.call(WarningCertificateInsertion);
+ }
+
+ ARM_UC_HUB_Initialize(UpdateClient::initialization_done);
+}
+
+static void UpdateClient::initialization_done(int32_t result)
+{
+ tr_info("internal initialization done: %" PRIu32 " %p", result, (void*)pal_osThreadGetId());
+}
+
+static void UpdateClient::event_handler(arm_event_s* event)
+{
+ switch (event->event_type)
+ {
+ case UPDATE_CLIENT_EVENT_INITIALIZE:
+ UpdateClient::initialization();
+ break;
+
+ case UPDATE_CLIENT_EVENT_PROCESS_QUEUE:
+ {
+ /* process a single callback, for better cooperability */
+ bool queue_not_empty = ARM_UC_ProcessSingleCallback();
+
+ if (queue_not_empty)
+ {
+ /* reschedule event handler, if queue is not empty */
+ UpdateClient::schedule_event();
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void UpdateClient::queue_handler(void)
+{
+ /* warning: queue_handler can be called from interrupt context.
+ */
+ UpdateClient::schedule_event();
+}
+
+static void UpdateClient::schedule_event()
+{
+ /* schedule event */
+ arm_event_s event = {
+ .receiver = update_client_tasklet_id,
+ .sender = 0,
+ .event_type = UPDATE_CLIENT_EVENT_PROCESS_QUEUE,
+ .event_id = 0,
+ .data_ptr = NULL,
+ .priority = ARM_LIB_LOW_PRIORITY_EVENT,
+ .event_data = 0,
+ };
+
+ eventOS_event_send(&event);
+}
+
+static void UpdateClient::error_handler(int32_t error)
+{
+ tr_info("error reported: %" PRIi32, error);
+
+ /* add warning base if less severe than error */
+ if (error < ARM_UC_ERROR)
+ {
+ error_callback.call(WarningBase + error);
+ }
+ /* add error base if less severe than fatal */
+ else if (error < ARM_UC_FATAL)
+ {
+ error_callback.call(ErrorBase + error);
+ }
+ /* add fatal base */
+ else
+ {
+ error_callback.call(FatalBase + error);
+ }
+}
+
+int UpdateClient::getVendorId(uint8_t* buffer, size_t buffer_size_max, size_t* value_size)
+{
+ arm_uc_error_t err = ARM_UC_GetVendorId(buffer, buffer_size_max, value_size);
+ if (err.code == ARM_UC_DI_ERR_SIZE)
+ {
+ return CCS_STATUS_MEMORY_ERROR;
+ }
+ if (err.error == ERR_NONE)
+ {
+ *value_size = 16;
+ return CCS_STATUS_SUCCESS;
+ }
+ return CCS_STATUS_KEY_DOESNT_EXIST;
+}
+int UpdateClient::getClassId(uint8_t* buffer, size_t buffer_size_max, size_t* value_size)
+{
+ arm_uc_error_t err = ARM_UC_GetClassId(buffer, buffer_size_max, value_size);
+ if (err.code == ARM_UC_DI_ERR_SIZE)
+ {
+ return CCS_STATUS_MEMORY_ERROR;
+ }
+ if (err.error == ERR_NONE)
+ {
+ *value_size = 16;
+ return CCS_STATUS_SUCCESS;
+ }
+ return CCS_STATUS_KEY_DOESNT_EXIST;
+}
+int UpdateClient::getDeviceId(uint8_t* buffer, size_t buffer_size_max, size_t* value_size)
+{
+ arm_uc_error_t err = ARM_UC_GetDeviceId(buffer, buffer_size_max, value_size);
+ if (err.code == ARM_UC_DI_ERR_SIZE)
+ {
+ return CCS_STATUS_MEMORY_ERROR;
+ }
+ if (err.error == ERR_NONE)
+ {
+ *value_size = 16;
+ return CCS_STATUS_SUCCESS;
+ }
+ return CCS_STATUS_KEY_DOESNT_EXIST;
+}
+
+#endif