Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers update_client_hub_state_machine.c Source File

update_client_hub_state_machine.c

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 // This is needed for PRIu64 on FreeRTOS. Note: the relative location is
00020 // important, do not move this to "correct" location, ie. after local includes.
00021 #include <stdio.h>
00022 
00023 #include "update_client_hub_state_machine.h"
00024 #include "update_client_hub_error_handler.h"
00025 #include "update-client-hub/update_client_hub.h"
00026 
00027 #include "update-client-common/arm_uc_common.h"
00028 #include "update-client-common/arm_uc_hw_plat.h"
00029 #include "update-client-firmware-manager/arm_uc_firmware_manager.h"
00030 #include "update-client-manifest-manager/update-client-manifest-manager.h"
00031 #include "update-client-source-manager/arm_uc_source_manager.h"
00032 #include "update-client-control-center/arm_uc_control_center.h"
00033 #include "update-client-control-center/arm_uc_pre_shared_key.h"
00034 
00035 #include "mbedtls/aes.h"
00036 
00037 #include <inttypes.h>
00038 
00039 // Rootless update, stage 1: manifest must be written to a file. Include the
00040 // header of the WriteManifest API
00041 #if defined(ARM_UC_FEATURE_ROOTLESS_STAGE_1) && (ARM_UC_FEATURE_ROOTLESS_STAGE_1 == 1)
00042 #include "update-client-pal-linux/arm_uc_pal_linux_ext.h"
00043 #endif // ARM_UC_FEATURE_ROOTLESS_STAGE_1
00044 
00045 /*****************************************************************************/
00046 /* Global variables                                                          */
00047 /*****************************************************************************/
00048 
00049 // state of the hub state machine
00050 static arm_uc_hub_state_t arm_uc_hub_state = ARM_UC_HUB_STATE_UNINITIALIZED;
00051 
00052 // the call back function registered by the user to signal end of initialisation
00053 static void (*arm_uc_hub_init_cb)(uintptr_t) = NULL;
00054 
00055 // The hub uses a double buffer system to speed up firmware download and storage
00056 #define BUFFER_SIZE_MAX (ARM_UC_BUFFER_SIZE / 2) //  define size of the double buffers
00057 static uint8_t message[BUFFER_SIZE_MAX];
00058 static arm_uc_buffer_t front_buffer = {
00059     .size_max = BUFFER_SIZE_MAX,
00060     .size = 0,
00061     .ptr = message
00062 };
00063 
00064 static uint8_t message2[BUFFER_SIZE_MAX];
00065 static arm_uc_buffer_t back_buffer = {
00066     .size_max = BUFFER_SIZE_MAX,
00067     .size = 0,
00068     .ptr = message2
00069 };
00070 
00071 // version (timestamp) of the current running application
00072 static arm_uc_firmware_details_t arm_uc_active_details = { 0 };
00073 static bool arm_uc_active_details_available = false;
00074 
00075 // bootloader information
00076 static arm_uc_installer_details_t arm_uc_installer_details = { 0 };
00077 
00078 // variable to keep track of the offset into the firmware image during download
00079 static uint32_t firmware_offset = 0;
00080 
00081 // variable to store the firmware config during firmware manager setup
00082 // Initialisation with an enum silences a compiler warning for ARM ("188-D: enumerated type mixed with another type").
00083 static ARM_UCFM_Setup_t arm_uc_hub_firmware_config = { UCFM_MODE_UNINIT };
00084 
00085 // buffer to store the decoded firmware key
00086 #define PLAIN_FIRMWARE_KEY_SIZE 16
00087 static uint8_t plainFirmwareKey[PLAIN_FIRMWARE_KEY_SIZE];
00088 static arm_uc_buffer_t arm_uc_hub_plain_key = {
00089     .size_max = PLAIN_FIRMWARE_KEY_SIZE,
00090     .size     = PLAIN_FIRMWARE_KEY_SIZE,
00091     .ptr      = plainFirmwareKey
00092 };
00093 
00094 static arm_uc_mmContext_t manifestManagerContext = { 0 };
00095 arm_uc_mmContext_t *pManifestManagerContext = &manifestManagerContext;
00096 static manifest_firmware_info_t fwinfo = { 0 };
00097 
00098 // buffer to store a uri struct
00099 #define URI_STRING_LEN 256
00100 static uint8_t uri_buffer[URI_STRING_LEN] = {0};
00101 
00102 static arm_uc_uri_t uri = {
00103     .size_max = sizeof(uri_buffer),
00104     .size     = 0,
00105     .ptr      = uri_buffer,
00106     .port     = 0,
00107     .scheme   = URI_SCHEME_NONE,
00108     .host     = NULL,
00109     .path     = NULL,
00110 };
00111 
00112 // true if the hub initialization callback was called, false otherwise
00113 static bool init_cb_called = false;
00114 
00115 /*****************************************************************************/
00116 /* Debug                                                                     */
00117 /*****************************************************************************/
00118 
00119 #if ARM_UC_HUB_TRACE_ENABLE
00120 static void arm_uc_hub_debug_output()
00121 {
00122     printf("Manifest timestamp: %" PRIu64 "\r\n", fwinfo.timestamp);
00123 
00124     if (uri.scheme == URI_SCHEME_HTTP) {
00125         printf("Firmware URL http://%s:%" PRIu16 "%s\r\n",
00126                uri.host, uri.port, uri.path);
00127     }
00128 
00129     printf("Firmware size: %" PRIu32 "\r\n", fwinfo.size);
00130 
00131     printf("Firmware hash (%" PRIu32 "): ", fwinfo.hash.size);
00132     for (unsigned i = 0; i < fwinfo.hash.size; i++) {
00133         printf("%02" PRIx8, fwinfo.hash.ptr[i]);
00134     }
00135     printf("\r\n");
00136 
00137     if (fwinfo.cipherMode == ARM_UC_MM_CIPHERMODE_PSK) {
00138         printf("PSK ID: ");
00139         for (unsigned i = 0; i < fwinfo.psk.keyID.size; i++) {
00140             printf("%02" PRIx8, *(fwinfo.psk.keyID.ptr + i));
00141         }
00142         printf("\r\n");
00143 
00144         printf("cipherKey(16): ");
00145         for (unsigned i = 0; i < 16; i++) {
00146             printf("%02" PRIx8, *(fwinfo.psk.cipherKey.ptr + i));
00147         }
00148         printf("\r\n");
00149 
00150         printf("Decrypted Firmware Symmetric Key(16): ");
00151         for (unsigned i = 0; i < 16; i++) {
00152             printf("%02" PRIx8, arm_uc_hub_plain_key.ptr[i]);
00153         }
00154         printf("\r\n");
00155 
00156         printf("fwinfo.initVector\r\n");
00157         for (unsigned i = 0; i < 16; i++) {
00158             printf("%02" PRIx8, *(fwinfo.initVector.ptr + i));
00159         }
00160         printf("\r\n");
00161     }
00162 
00163     printf("Storage location: %" PRIu32 "\r\n",
00164            arm_uc_hub_firmware_config.package_id);
00165 }
00166 #endif
00167 
00168 /*****************************************************************************/
00169 /* State machine                                                             */
00170 /*****************************************************************************/
00171 
00172 /* Short hand for simple error handling code */
00173 #define HANDLE_ERROR(retval, msg, ...)                  \
00174     if (retval.error != ERR_NONE)                       \
00175     {                                                   \
00176         UC_HUB_ERR_MSG(msg " error code %s",            \
00177                        ##__VA_ARGS__,                   \
00178                        ARM_UC_err2Str(retval));         \
00179         new_state = ARM_UC_HUB_STATE_IDLE;              \
00180         break;                                          \
00181     }
00182 
00183 arm_uc_hub_state_t ARM_UC_HUB_getState()
00184 {
00185     return arm_uc_hub_state;
00186 }
00187 
00188 void ARM_UC_HUB_setInitializationCallback(void (*callback)(uintptr_t))
00189 {
00190     arm_uc_hub_init_cb = callback;
00191 }
00192 
00193 /**
00194  * @brief Return the active firmware details or NULL if they're not yet available.
00195  */
00196 arm_uc_firmware_details_t *ARM_UC_HUB_getActiveFirmwareDetails(void)
00197 {
00198     return arm_uc_active_details_available ? &arm_uc_active_details : NULL;
00199 }
00200 
00201 void ARM_UC_HUB_setState(arm_uc_hub_state_t new_state)
00202 {
00203     arm_uc_error_t retval;
00204 
00205     /* Loop until state is unchanged.
00206        First loop is mandatory regardless of current state.
00207     */
00208     do {
00209         /* store new stage */
00210         arm_uc_hub_state = new_state;
00211 
00212         switch (arm_uc_hub_state) {
00213             /*****************************************************************/
00214             /* Initialization                                                */
00215             /*****************************************************************/
00216             case ARM_UC_HUB_STATE_INITIALIZED:
00217                 UC_HUB_TRACE("ARM_UC_HUB_STATE_INITIALIZED");
00218 
00219                 /* report the active firmware hash to the Cloud in parallel
00220                    with the main user application.
00221                 */
00222                 arm_uc_active_details_available = false;
00223                 new_state = ARM_UC_HUB_STATE_GET_ACTIVE_FIRMWARE_DETAILS;
00224                 break;
00225 
00226             case ARM_UC_HUB_STATE_INITIALIZING:
00227                 UC_HUB_TRACE("ARM_UC_HUB_STATE_INITIALIZING");
00228                 break;
00229 
00230             /*****************************************************************/
00231             /* Report current firmware hash                                  */
00232             /*****************************************************************/
00233             case ARM_UC_HUB_STATE_GET_ACTIVE_FIRMWARE_DETAILS:
00234                 UC_HUB_TRACE("ARM_UC_HUB_STATE_GET_ACTIVE_FIRMWARE_DETAILS");
00235 
00236                 retval = ARM_UC_FirmwareManager.GetActiveFirmwareDetails(&arm_uc_active_details);
00237                 HANDLE_ERROR(retval, "Firmware manager GetActiveFirmwareDetails failed");
00238                 break;
00239 
00240             case ARM_UC_HUB_STATE_REPORT_ACTIVE_HASH:
00241                 UC_HUB_TRACE("ARM_UC_HUB_STATE_REPORT_ACTIVE_HASH");
00242 
00243                 /* copy hash to buffer */
00244                 memcpy(front_buffer.ptr,
00245                        arm_uc_active_details.hash,
00246                        ARM_UC_SHA256_SIZE);
00247 
00248                 front_buffer.size = ARM_UC_SHA256_SIZE;
00249 
00250                 /* send hash to update service */
00251                 ARM_UC_ControlCenter_ReportName(&front_buffer);
00252 
00253                 /* signal to the API that the firmware details are now available */
00254                 arm_uc_active_details_available = true;
00255 
00256                 new_state = ARM_UC_HUB_STATE_REPORT_ACTIVE_VERSION;
00257                 break;
00258 
00259             /*****************************************************************/
00260             /* Report current firmware version                               */
00261             /*****************************************************************/
00262             case ARM_UC_HUB_STATE_REPORT_ACTIVE_VERSION:
00263                 UC_HUB_TRACE("ARM_UC_HUB_STATE_REPORT_ACTIVE_VERSION");
00264 
00265                 UC_HUB_TRACE("Active version: %" PRIu64,
00266                              arm_uc_active_details.version);
00267 
00268                 /* send timestamp to update service */
00269                 ARM_UC_ControlCenter_ReportVersion(arm_uc_active_details.version);
00270 
00271                 new_state = ARM_UC_HUB_STATE_GET_INSTALLER_DETAILS;
00272                 break;
00273 
00274             /*****************************************************************/
00275             /* Report bootloader information                                 */
00276             /*****************************************************************/
00277             case ARM_UC_HUB_STATE_GET_INSTALLER_DETAILS:
00278                 UC_HUB_TRACE("ARM_UC_HUB_STATE_GET_INSTALLER_DETAILS");
00279 
00280                 retval = ARM_UC_FirmwareManager.GetInstallerDetails(&arm_uc_installer_details);
00281                 HANDLE_ERROR(retval, "Firmware manager GetInstallerDetails failed");
00282                 break;
00283 
00284             case ARM_UC_HUB_STATE_REPORT_INSTALLER_DETAILS: {
00285                 UC_HUB_TRACE("ARM_UC_HUB_STATE_REPORT_INSTALLER_DETAILS");
00286 
00287 #if 0
00288                 printf("bootloader: ");
00289                 for (uint32_t index = 0; index < 20; index++) {
00290                     printf("%02X", arm_uc_installer_details.arm_hash[index]);
00291                 }
00292                 printf("\r\n");
00293 
00294                 printf("layout: %" PRIu32 "\r\n", arm_uc_installer_details.layout);
00295 #endif
00296 
00297                 /* report installer details to mbed cloud */
00298                 arm_uc_buffer_t bootloader_hash = {
00299                     .size_max = ARM_UC_SHA256_SIZE,
00300                     .size = ARM_UC_SHA256_SIZE,
00301                     .ptr = (arm_uc_installer_details.arm_hash)
00302                 };
00303                 ARM_UC_ControlCenter_ReportBootloaderHash(&bootloader_hash);
00304 
00305                 bootloader_hash.ptr = (arm_uc_installer_details.oem_hash);
00306                 ARM_UC_ControlCenter_ReportOEMBootloaderHash(&bootloader_hash);
00307 
00308                 /* set new state */
00309                 new_state = ARM_UC_HUB_STATE_IDLE;
00310                 break;
00311             }
00312 
00313             /*****************************************************************/
00314             /* Idle                                                          */
00315             /*****************************************************************/
00316             case ARM_UC_HUB_STATE_IDLE:
00317                 UC_HUB_TRACE("ARM_UC_UPDATE_STATE_IDLE");
00318 
00319                 /* signal monitor that device has entered IDLE state */
00320                 ARM_UC_ControlCenter_ReportState(ARM_UC_UPDATE_STATE_IDLE);
00321 
00322                 /* signal that the Hub is initialized if needed */
00323                 if (!init_cb_called) {
00324                     if (arm_uc_hub_init_cb) {
00325                         arm_uc_hub_init_cb(ARM_UC_INIT_DONE);
00326                     }
00327                     init_cb_called = true;
00328                 }
00329 
00330                 break;
00331 
00332             /*****************************************************************/
00333             /* Download manifest                                             */
00334             /*****************************************************************/
00335             case ARM_UC_HUB_STATE_NOTIFIED:
00336                 UC_HUB_TRACE("ARM_UC_HUB_STATE_NOTIFIED");
00337 
00338                 /* notification received of a new manifest, hence go get said manifest */
00339                 retval = ARM_UC_SourceManager.GetManifest(&front_buffer, 0);
00340                 HANDLE_ERROR(retval, "Source manager GetManifest failed");
00341                 break;
00342 
00343             case ARM_UC_HUB_STATE_MANIFEST_FETCHED:
00344                 UC_HUB_TRACE("ARM_UC_HUB_STATE_MANIFEST_FETCHED");
00345 
00346                 /* Save the manifest for later */
00347                 memcpy(&fwinfo.manifestBuffer, front_buffer.ptr,
00348                        ARM_UC_util_min(sizeof(fwinfo.manifestBuffer), front_buffer.size));
00349                 /* Save the manifest size for later */
00350                 fwinfo.manifestSize = front_buffer.size;
00351                 /* insert the manifest we just fetched into manifest manager */
00352                 retval = ARM_UC_mmInsert(&pManifestManagerContext, &front_buffer, &back_buffer,  NULL);
00353                 new_state = ARM_UC_HUB_STATE_MANIFEST_AWAIT_INSERT;
00354                 if (retval.code != MFST_ERR_PENDING) {
00355                     HANDLE_ERROR(retval, "Manifest manager Insert failed")
00356                 }
00357                 break;
00358 
00359             case ARM_UC_HUB_STATE_MANIFEST_AWAIT_INSERT:
00360                 UC_HUB_TRACE("ARM_UC_HUB_STATE_MANIFEST_AWAIT_INSERT");
00361                 break;
00362 
00363             case ARM_UC_HUB_STATE_MANIFEST_INSERT_DONE:
00364                 UC_HUB_TRACE("ARM_UC_HUB_STATE_MANIFEST_INSERT_DONE");
00365                 ARM_UC_ControlCenter_ReportState(ARM_UC_UPDATE_STATE_PROCESSING_MANIFEST);
00366                 new_state = ARM_UC_HUB_STATE_MANIFEST_AWAIT_MONITOR_REPORT_DONE;
00367                 break;
00368 
00369             case ARM_UC_HUB_STATE_MANIFEST_AWAIT_MONITOR_REPORT_DONE:
00370                 UC_HUB_TRACE("ARM_UC_HUB_STATE_MANIFEST_AWAIT_MONITOR_REPORT_DONE");
00371                 break;
00372 
00373             /*****************************************************************/
00374             /* Rollback protection                                           */
00375             /*****************************************************************/
00376             case ARM_UC_HUB_STATE_MANIFEST_COMPLETE:
00377                 UC_HUB_TRACE("ARM_UC_HUB_STATE_MANIFEST_COMPLETE");
00378 
00379                 /* get the firmware info out of the manifest we just inserted
00380                    into the manifest manager
00381                 */
00382                 retval = ARM_UC_mmFetchFirmwareInfo(&pManifestManagerContext, &fwinfo, NULL);
00383                 if (retval.code != MFST_ERR_PENDING) {
00384                     HANDLE_ERROR(retval, "Manifest manager fetch info failed")
00385                 }
00386                 break;
00387 
00388             case ARM_UC_HUB_STATE_CHECK_VERSION:
00389                 UC_HUB_TRACE("ARM_UC_HUB_STATE_CHECK_VERSION");
00390 
00391                 /* give up if the format is unsupported */
00392                 if (!ARM_UC_mmCheckFormatUint32(&fwinfo.format, ARM_UC_MM_FORMAT_RAW_BINARY)) {
00393                     ARM_UC_SET_ERROR(retval, MFST_ERR_FORMAT);
00394                     HANDLE_ERROR(retval, "Firmware Format unsupported");
00395                 }
00396                 /* only continue if timestamp is newer than active version */
00397                 else if (fwinfo.timestamp > arm_uc_active_details.version) {
00398                     /* set new state */
00399                     new_state = ARM_UC_HUB_STATE_PREPARE_FIRMWARE_SETUP;
00400                 } else {
00401                     UC_HUB_ERR_MSG("version: %" PRIu64 " <= %" PRIu64,
00402                                    fwinfo.timestamp,
00403                                    arm_uc_active_details.version);
00404 
00405                     /* signal warning through external handler */
00406                     ARM_UC_HUB_ErrorHandler(HUB_ERR_ROLLBACK_PROTECTION,
00407                                             ARM_UC_HUB_STATE_CHECK_VERSION);
00408 
00409                     /* set new state */
00410                     new_state = ARM_UC_HUB_STATE_IDLE;
00411                 }
00412                 break;
00413 
00414             /*****************************************************************/
00415             /* Parse manifest                                                */
00416             /*****************************************************************/
00417             case ARM_UC_HUB_STATE_PREPARE_FIRMWARE_SETUP:
00418                 UC_HUB_TRACE("ARM_UC_HUB_STATE_PREPARE_FIRMWARE_SETUP");
00419 
00420                 /* store pointer to hash */
00421                 arm_uc_hub_firmware_config.hash = &fwinfo.hash;
00422 
00423                 /* parse the url string into a arm_uc_uri_t struct */
00424                 retval = arm_uc_str2uri(fwinfo.uri.ptr, fwinfo.uri.size, &uri);
00425 
00426                 /* URI-based errors are propagated to monitor */
00427                 if (retval.error != ERR_NONE) {
00428                     /* make sure that the URI string is always 0-terminated */
00429                     fwinfo.uri.ptr[fwinfo.uri.size_max - 1] = '\0';
00430                     UC_HUB_ERR_MSG("Unable to parse URI string %s", fwinfo.uri.ptr);
00431 
00432                     /* signal warning through external handler */
00433                     ARM_UC_HUB_ErrorHandler(SOMA_ERR_INVALID_URI,
00434                                             ARM_UC_HUB_STATE_PREPARE_FIRMWARE_SETUP);
00435 
00436                     /* set new state */
00437                     new_state = ARM_UC_HUB_STATE_IDLE;
00438                     break;
00439                 }
00440 
00441                 /* store firmware size */
00442                 arm_uc_hub_firmware_config.package_size = fwinfo.size;
00443 
00444                 /* read cryptography mode to determine if firmware is encrypted */
00445                 switch (fwinfo.cipherMode) {
00446                     case ARM_UC_MM_CIPHERMODE_NONE:
00447                         arm_uc_hub_firmware_config.mode = UCFM_MODE_NONE_SHA_256;
00448                         break;
00449 
00450 #if defined(ARM_UC_FEATURE_MANIFEST_PSK) && (ARM_UC_FEATURE_MANIFEST_PSK == 1)
00451                     case ARM_UC_MM_CIPHERMODE_PSK: {
00452                         /* Get pre-shared-key from the Control Center */
00453                         /* TODO: this call should be asynchronous */
00454                         const uint8_t *arm_uc_pre_shared_key = NULL;
00455                         retval = ARM_UC_PreSharedKey_GetSecret(&arm_uc_pre_shared_key, 128);
00456                         HANDLE_ERROR(retval, "Unable to get PSK");
00457 
00458                         /* Decode the firmware key to be used to decode the firmware */
00459                         UC_HUB_TRACE("Decoding firmware AES key...");
00460                         mbedtls_aes_context ctx;
00461                         mbedtls_aes_init(&ctx);
00462                         mbedtls_aes_setkey_dec(&ctx, arm_uc_pre_shared_key, 128);
00463                         mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_DECRYPT, fwinfo.psk.cipherKey.ptr, arm_uc_hub_plain_key.ptr);
00464 
00465                         arm_uc_hub_firmware_config.mode = UCFM_MODE_AES_CTR_128_SHA_256;
00466                         arm_uc_hub_firmware_config.key  = &arm_uc_hub_plain_key;
00467                         arm_uc_hub_firmware_config.iv   = &fwinfo.initVector;
00468                     }
00469                     break;
00470 #endif /* ARM_UC_FEATURE_MANIFEST_PSK */
00471 
00472                     case ARM_UC_MM_CIPHERMODE_CERT_CIPHERKEY:
00473                     case ARM_UC_MM_CIPHERMODE_CERT_KEYTABLE:
00474                     default:
00475                         retval.code = MFST_ERR_CRYPTO_MODE;
00476                         HANDLE_ERROR(retval, "Unsupported AES Key distribution mode...");
00477                         break;
00478                 }
00479 
00480                 /* check if storage ID has been set */
00481                 if (fwinfo.strgId.size == 0 || fwinfo.strgId.ptr == NULL) {
00482                     /* no storage ID set, use default value 0 */
00483                     arm_uc_hub_firmware_config.package_id = 0;
00484                 } else {
00485                     /* check if storage ID is "default" */
00486                     uint32_t location = arm_uc_strnstrn(fwinfo.strgId.ptr,
00487                                                         fwinfo.strgId.size,
00488                                                         (const uint8_t *) "default",
00489                                                         7);
00490 
00491                     if (location != UINT32_MAX) {
00492                         arm_uc_hub_firmware_config.package_id = 0;
00493                     } else {
00494                         /* parse storage ID */
00495                         bool success = false;
00496                         arm_uc_hub_firmware_config.package_id =
00497                             arm_uc_str2uint32(fwinfo.strgId.ptr,
00498                                               fwinfo.strgId.size,
00499                                               &success);
00500                     }
00501                 }
00502 
00503 #if ARM_UC_HUB_TRACE_ENABLE
00504                 arm_uc_hub_debug_output();
00505 #endif
00506 
00507                 /* Set new state */
00508                 new_state = ARM_UC_HUB_STATE_REQUEST_DOWNLOAD_AUTHORIZATION;
00509                 break;
00510 
00511             /*****************************************************************/
00512             /* Download authorization                                        */
00513             /*****************************************************************/
00514             case ARM_UC_HUB_STATE_REQUEST_DOWNLOAD_AUTHORIZATION:
00515                 UC_HUB_TRACE("ARM_UC_HUB_STATE_REQUEST_DOWNLOAD_AUTHORIZATION");
00516 
00517                 /* Signal control center */
00518                 ARM_UC_ControlCenter_GetAuthorization(ARM_UCCC_REQUEST_DOWNLOAD);
00519                 ARM_UC_ControlCenter_ReportState(ARM_UC_UPDATE_STATE_AWAITING_DOWNLOAD_APPROVAL);
00520 
00521                 /* Set new state */
00522                 new_state = ARM_UC_HUB_STATE_WAIT_FOR_DOWNLOAD_AUTHORIZATION;
00523                 break;
00524 
00525             case ARM_UC_HUB_STATE_WAIT_FOR_DOWNLOAD_AUTHORIZATION:
00526                 UC_HUB_TRACE("ARM_UC_HUB_STATE_WAIT_FOR_DOWNLOAD_AUTHORIZATION");
00527                 break;
00528 
00529             case ARM_UC_HUB_STATE_DOWNLOAD_AUTHORIZED:
00530                 UC_HUB_TRACE("ARM_UC_HUB_STATE_DOWNLOAD_AUTHORIZED");
00531 
00532                 /* Set new state */
00533                 break;
00534 
00535             /*****************************************************************/
00536             /* Download firmware                                             */
00537             /*****************************************************************/
00538 
00539             /* The firmware is downloaded in fragments. While one fragment is
00540                written to storage, the next fragment is being downloaded.
00541 
00542                In the ARM_UC_HUB_STATE_FETCH_FIRST_FRAGMENT state, the first
00543                fragment is being downloaded. Once completed, the first fragment
00544                will be in the front_buffer and both the network stack and
00545                storage stack will be idle.
00546 
00547                In the ARM_UC_HUB_STATE_STORE_AND_DOWNLOAD state, the front and
00548                back buffers are swapped. The front buffer is being used for
00549                downloading the next fragment while the back buffer is being
00550                written to storage.
00551 
00552                ARM_UC_FirmwareManager.Write and
00553                ARM_UC_SourceManager.GetFirmwareFragment will both finish
00554                asynchronously generating two events:
00555                ARM_UC_SM_EVENT_FIRMWARE and UCFM_EVENT_UPDATE_DONE.
00556 
00557                If the ARM_UC_SM_EVENT_FIRMWARE event is generated first, the
00558                system enters the ARM_UC_HUB_STATE_WAIT_FOR_STORAGE state.
00559                If the UCFM_EVENT_UPDATE_DONE event is generated first, the
00560                system enters the ARM_UC_HUB_STATE_WAIT_FOR_NETWORK state.
00561                The second generated event will move the system back to the
00562                ARM_UC_HUB_STATE_STORE_AND_DOWNLOAD state.
00563 
00564                The download will stop once the fragment offset is larger than
00565                the firmware size written in the manifest. This moves the system
00566                to the ARM_UC_HUB_STATE_STORE_LAST_FRAGMENT state.
00567 
00568                Once the last fragment is written, the newly written firmware
00569                committed in the ARM_UC_HUB_STATE_FINALIZE_STORAGE state.
00570             */
00571             case ARM_UC_HUB_STATE_SETUP_FIRMWARE: {
00572                 UC_HUB_TRACE("ARM_UC_HUB_STATE_SETUP_FIRMWARE");
00573 
00574                 /* store the firmware info in the manifest_firmware_info_t struct */
00575                 arm_uc_firmware_details_t arm_uc_hub_firmware_details = { 0 };
00576 
00577                 /* use manifest timestamp as firmware header version */
00578                 arm_uc_hub_firmware_details.version = fwinfo.timestamp;
00579                 arm_uc_hub_firmware_details.size    = fwinfo.size;
00580                 /* copy hash */
00581                 memcpy(arm_uc_hub_firmware_details.hash,
00582                        fwinfo.hash.ptr,
00583                        ARM_UC_SHA256_SIZE);
00584 #if 0
00585                 memcpy(arm_uc_hub_firmware_details.campaign,
00586                        configuration.campaign,
00587                        ARM_UC_GUID_SIZE);
00588 #endif
00589                 // initialise offset here so we can always resume with FIRST_FRAGMENT.
00590                 firmware_offset = 0;
00591                 /* setup the firmware manager to get ready for firmware storage */
00592                 retval = ARM_UC_FirmwareManager.Prepare(&arm_uc_hub_firmware_config,
00593                                                         &arm_uc_hub_firmware_details,
00594                                                         &front_buffer);
00595                 new_state = ARM_UC_HUB_STATE_AWAIT_FIRMWARE_SETUP;
00596                 if (retval.code != ERR_NONE) {
00597                     HANDLE_ERROR(retval, "ARM_UC_FirmwareManager Setup failed")
00598                 }
00599             }
00600             break;
00601 
00602             case ARM_UC_HUB_STATE_AWAIT_FIRMWARE_SETUP:
00603                 UC_HUB_TRACE("ARM_UC_HUB_STATE_AWAIT_FIRMWARE_SETUP");
00604                 break;
00605 
00606             case ARM_UC_HUB_STATE_FIRMWARE_SETUP_DONE:
00607                 UC_HUB_TRACE("ARM_UC_HUB_STATE_FIRMWARE_SETUP_DONE");
00608                 /* set state to Downloading after setup has been done */
00609                 UC_HUB_TRACE("Setting Monitor State: ARM_UC_UPDATE_STATE_DOWNLOADING_UPDATE");
00610                 ARM_UC_ControlCenter_ReportState(ARM_UC_UPDATE_STATE_DOWNLOADING_UPDATE);
00611                 new_state = ARM_UC_HUB_STATE_AWAIT_FIRMWARE_MONITOR_REPORT_DONE;
00612                 break;
00613 
00614             case ARM_UC_HUB_STATE_AWAIT_FIRMWARE_MONITOR_REPORT_DONE:
00615                 UC_HUB_TRACE("ARM_UC_HUB_STATE_AWAIT_FIRMWARE_MONITOR_REPORT_DONE");
00616                 break;
00617 
00618             case ARM_UC_HUB_STATE_FETCH_FIRST_FRAGMENT:
00619                 UC_HUB_TRACE("ARM_UC_HUB_STATE_FETCH_FIRST_FRAGMENT");
00620 
00621                 /* Check firmware size before entering the download state machine.
00622                    An empty firmware is used for erasing a slot.
00623                    If true, then send next state to monitor service, close storage slot.
00624                 */
00625                 if (fwinfo.size == 0) {
00626                     UC_HUB_TRACE("Firmware empty, skip download phase and finalize");
00627                     UC_HUB_TRACE("Setting Monitor State: ARM_UC_UPDATE_STATE_DOWNLOADED_UPDATE");
00628                     ARM_UC_ControlCenter_ReportState(ARM_UC_UPDATE_STATE_DOWNLOADED_UPDATE);
00629                     new_state = ARM_UC_HUB_STATE_FINALIZE_STORAGE;
00630                 } else {
00631                     UC_HUB_TRACE("loading %" PRIu32 " byte first fragment at %" PRIu32,
00632                                  front_buffer.size_max, firmware_offset);
00633                     /* reset download values */
00634                     front_buffer.size = 0;
00635                     back_buffer.size = 0;
00636                     retval = ARM_UC_SourceManager.GetFirmwareFragment(&uri, &front_buffer, firmware_offset);
00637                     HANDLE_ERROR(retval, "GetFirmwareFragment failed")
00638                 }
00639                 break;
00640 
00641             case ARM_UC_HUB_STATE_STORE_AND_DOWNLOAD:
00642                 UC_HUB_TRACE("ARM_UC_HUB_STATE_STORE_AND_DOWNLOAD");
00643 
00644                 /* swap the front and back buffers
00645                    the back buffer contained just downloaded firmware chunk
00646                    the front buffer can now be cleared and used to download new chunk
00647                 */
00648                 {
00649                     arm_uc_buffer_t temp_buf_ptr = front_buffer;
00650                     front_buffer = back_buffer;
00651                     back_buffer = temp_buf_ptr;
00652                 }
00653                 /* store the downloaded chunk in the back buffer */
00654                 if (back_buffer.size > 0) {
00655                     UC_HUB_TRACE("writing %" PRIu32 " byte fragment at %" PRIu32,
00656                                  back_buffer.size, firmware_offset);
00657 
00658                     /* increase offset by the amount that we just downloaded */
00659                     firmware_offset += back_buffer.size;
00660                     retval = ARM_UC_FirmwareManager.Write(&back_buffer);
00661                     HANDLE_ERROR(retval, "ARM_UC_FirmwareManager Update failed")
00662                 }
00663                 /* go fetch a new chunk using the front buffer if more are expected */
00664                 if (firmware_offset < fwinfo.size) {
00665                     front_buffer.size = 0;
00666                     UC_HUB_TRACE("Getting next fragment at offset: %" PRIu32, firmware_offset);
00667                     retval = ARM_UC_SourceManager.GetFirmwareFragment(&uri, &front_buffer, firmware_offset);
00668                     HANDLE_ERROR(retval, "GetFirmwareFragment failed")
00669                 } else {
00670                     // Terminate the process, but first ensure the last fragment has been stored.
00671                     UC_HUB_TRACE("Last fragment fetched.");
00672                     new_state = ARM_UC_HUB_STATE_AWAIT_LAST_FRAGMENT_STORED;
00673                 }
00674                 /* report progress */
00675                 ARM_UC_ControlCenter_ReportProgress(firmware_offset, fwinfo.size);
00676                 break;
00677 
00678             case ARM_UC_HUB_STATE_WAIT_FOR_STORAGE:
00679                 UC_HUB_TRACE("ARM_UC_HUB_STATE_WAIT_FOR_STORAGE");
00680                 break;
00681 
00682             case ARM_UC_HUB_STATE_WAIT_FOR_NETWORK:
00683                 UC_HUB_TRACE("ARM_UC_HUB_STATE_WAIT_FOR_NETWORK");
00684                 break;
00685 
00686             case ARM_UC_HUB_STATE_AWAIT_LAST_FRAGMENT_STORED:
00687                 UC_HUB_TRACE("ARM_UC_HUB_STATE_AWAIT_LAST_FRAGMENT_STORED");
00688                 break;
00689 
00690             case ARM_UC_HUB_STATE_LAST_FRAGMENT_STORE_DONE:
00691                 UC_HUB_TRACE("ARM_UC_HUB_STATE_LAST_FRAGMENT_STORE_DONE");
00692 
00693                 /* set state to downloaded when the full size of the firmware has been fetched. */
00694                 UC_HUB_TRACE("Setting Monitor State: ARM_UC_UPDATE_STATE_DOWNLOADED_UPDATE");
00695                 ARM_UC_ControlCenter_ReportState(ARM_UC_UPDATE_STATE_DOWNLOADED_UPDATE);
00696                 new_state = ARM_UC_HUB_STATE_AWAIT_LAST_FRAGMENT_MONITOR_REPORT_DONE;
00697                 break;
00698 
00699             case ARM_UC_HUB_STATE_AWAIT_LAST_FRAGMENT_MONITOR_REPORT_DONE:
00700                 UC_HUB_TRACE("ARM_UC_HUB_STATE_AWAIT_LAST_FRAGMENT_MONITOR_REPORT_DONE");
00701                 break;
00702 
00703             case ARM_UC_HUB_STATE_FINALIZE_STORAGE:
00704                 UC_HUB_TRACE("ARM_UC_HUB_STATE_FINALIZE_STORAGE");
00705 
00706                 retval = ARM_UC_FirmwareManager.Finalize(&front_buffer, &back_buffer);
00707                 HANDLE_ERROR(retval, "ARM_UC_FirmwareManager Finalize failed")
00708                 break;
00709 
00710             /*****************************************************************/
00711             /* Install authorization                                         */
00712             /*****************************************************************/
00713             case ARM_UC_HUB_STATE_STORAGE_FINALIZED:
00714                 UC_HUB_TRACE("ARM_UC_HUB_STATE_STORAGE_FINALIZED");
00715 
00716 #if defined(ARM_UC_FEATURE_ROOTLESS_STAGE_1) && (ARM_UC_FEATURE_ROOTLESS_STAGE_1 == 1)
00717                 {
00718                     /* the manifest must be saved in a file, because it will be used later
00719                     by the second stage of the update client */
00720                     arm_uc_buffer_t manifest_buffer = {
00721                         .size_max = fwinfo.manifestSize,
00722                         .size = fwinfo.manifestSize,
00723                         .ptr = fwinfo.manifestBuffer
00724                     };
00725 
00726                     retval = ARM_UC_PAL_Linux_WriteManifest(arm_uc_hub_firmware_config.package_id,
00727                                                             &manifest_buffer);
00728                     HANDLE_ERROR(retval, "Uanble to write manifest to file system");
00729                 }
00730 #endif
00731 
00732                 /* Signal control center */
00733                 ARM_UC_ControlCenter_GetAuthorization(ARM_UCCC_REQUEST_INSTALL);
00734 
00735                 /* Set new state */
00736                 new_state = ARM_UC_HUB_STATE_WAIT_FOR_INSTALL_AUTHORIZATION;
00737                 break;
00738 
00739             case ARM_UC_HUB_STATE_WAIT_FOR_INSTALL_AUTHORIZATION:
00740                 UC_HUB_TRACE("ARM_UC_HUB_STATE_WAIT_FOR_INSTALL_AUTHORIZATION");
00741                 ARM_UC_ControlCenter_ReportState(ARM_UC_UPDATE_STATE_AWAITING_INSTALL_APPROVAL);
00742                 break;
00743 
00744             case ARM_UC_HUB_STATE_INSTALL_AUTHORIZED:
00745                 UC_HUB_TRACE("ARM_UC_HUB_STATE_INSTALL_AUTHORIZED");
00746 
00747                 UC_HUB_TRACE("Setting Monitor State: ARM_UC_UPDATE_STATE_INSTALLING_UPDATE");
00748                 ARM_UC_ControlCenter_ReportState(ARM_UC_UPDATE_STATE_INSTALLING_UPDATE);
00749 
00750                 /* TODO: set timeout on ReportState before relying on callback to progress state machine */
00751                 break;
00752 
00753             case ARM_UC_HUB_STATE_ACTIVATE_FIRMWARE:
00754                 UC_HUB_TRACE("ARM_UC_HUB_STATE_ACTIVATE_FIRMWARE");
00755 
00756                 /* Firmware verification passes, activate firmware image.
00757                 */
00758                 ARM_UC_FirmwareManager.Activate(arm_uc_hub_firmware_config.package_id);
00759                 break;
00760 
00761             case ARM_UC_HUB_STATE_PREP_REBOOT:
00762                 UC_HUB_TRACE("ARM_UC_HUB_STATE_PREP_REBOOT");
00763 
00764                 ARM_UC_ControlCenter_ReportState(ARM_UC_UPDATE_STATE_REBOOTING);
00765                 break;
00766 
00767             case ARM_UC_HUB_STATE_REBOOT:
00768                 UC_HUB_TRACE("ARM_UC_HUB_STATE_REBOOT");
00769 
00770                 // Firmware activated, now reboot the system to apply the new image.
00771 #if defined(ARM_UC_PROFILE_MBED_CLIENT_LITE) && (ARM_UC_PROFILE_MBED_CLIENT_LITE == 1)
00772                 arm_uc_plat_reboot();
00773 #else
00774                 pal_osReboot();
00775 #endif
00776 
00777                 /* Reboot not implemented on this platform.
00778                    Go to idle state.
00779                 */
00780                 new_state = ARM_UC_HUB_STATE_IDLE;
00781                 break;
00782 
00783             /*****************************************************************/
00784             /* Error                                                         */
00785             /*****************************************************************/
00786             case ARM_UC_HUB_STATE_ERROR_FIRMWARE_MANAGER:
00787                 UC_HUB_TRACE("ARM_UC_HUB_STATE_ERROR_FIRMWARE_MANAGER");
00788                 new_state = ARM_UC_HUB_STATE_IDLE;
00789                 break;
00790 
00791             case ARM_UC_HUB_STATE_ERROR_MANIFEST_MANAGER:
00792                 UC_HUB_TRACE("ARM_UC_HUB_STATE_ERROR_MANIFEST_MANAGER");
00793                 new_state = ARM_UC_HUB_STATE_IDLE;
00794                 break;
00795 
00796             case ARM_UC_HUB_STATE_ERROR_SOURCE_MANAGER:
00797                 UC_HUB_TRACE("ARM_UC_HUB_STATE_ERROR_SOURCE_MANAGER");
00798                 new_state = ARM_UC_HUB_STATE_IDLE;
00799                 break;
00800 
00801             case ARM_UC_HUB_STATE_ERROR_CONTROL_CENTER:
00802                 UC_HUB_TRACE("ARM_UC_HUB_STATE_ERROR_CONTROL_CENTER");
00803                 new_state = ARM_UC_HUB_STATE_IDLE;
00804                 break;
00805 
00806             case ARM_UC_HUB_STATE_WAIT_FOR_ERROR_ACK:
00807                 UC_HUB_TRACE("ARM_UC_HUB_STATE_WAIT_FOR_ERROR_ACK");
00808                 /* Don't change state. The only place where this state is set is in
00809                    update_client_hub_error_handler.c, right after reporting the update
00810                    result, so we wait for a "report done" event (ARM_UCCC_EVENT_MONITOR_SEND_DONE
00811                    in arm_uc_hub_event_handlers.c). The handler for this particular
00812                    event will then set the state to 'idle' */
00813                 break;
00814 
00815             case ARM_UC_HUB_STATE_UNINITIALIZED:
00816                 UC_HUB_TRACE("ARM_UC_HUB_STATE_UNINITIALIZED");
00817                 /* do nothing and wait for ARM_UC_HUB_Initialize call to change the state */
00818                 break;
00819 
00820             default:
00821                 new_state = ARM_UC_HUB_STATE_IDLE;
00822                 break;
00823         }
00824     } while (arm_uc_hub_state != new_state);
00825 }