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 arm_uc_paal_classic_pal.c Source File

arm_uc_paal_classic_pal.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 #include "update-client-paal/arm_uc_paal_update_api.h"
00020 
00021 #include "update-client-pal-filesystem/arm_uc_pal_extensions.h"
00022 #include "update-client-common/arm_uc_utilities.h"
00023 #include "update-client-common/arm_uc_metadata_header_v2.h"
00024 #include "arm_uc_pal_filesystem_utils.h"
00025 
00026 #include "pal.h"
00027 
00028 #include "mbed-trace/mbed_trace.h"
00029 #define TRACE_GROUP "UCPI"
00030 
00031 #include <stdio.h>
00032 
00033 #define ARM_UC_FIRMWARE_FOLDER_NAME "firmware"
00034 
00035 /* pointer to external callback handler */
00036 static ARM_UC_PAAL_UPDATE_SignalEvent_t arm_uc_pal_external_callback = NULL;
00037 
00038 static void arm_uc_pal_classic_signal_callback(uint32_t event)
00039 {
00040     if (arm_uc_pal_external_callback)
00041     {
00042         arm_uc_pal_external_callback(event);
00043     }
00044 }
00045 
00046 static void arm_uc_pal_classic_callback(palImageEvents_t event)
00047 {
00048     /*
00049         ARM_UC_PAAL_EVENT_INITIALIZE_DONE,
00050         ARM_UC_PAAL_EVENT_PREPARE_DONE,
00051         ARM_UC_PAAL_EVENT_WRITE_DONE,
00052         ARM_UC_PAAL_EVENT_FINALIZE_DONE,
00053         ARM_UC_PAAL_EVENT_READ_DONE,
00054         ARM_UC_PAAL_EVENT_ACTIVATE_DONE,
00055         ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE,
00056         ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE,
00057         ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE,
00058         ARM_UC_PAAL_EVENT_INITIALIZE_ERROR,
00059         ARM_UC_PAAL_EVENT_PREPARE_ERROR,
00060         ARM_UC_PAAL_EVENT_WRITE_ERROR,
00061         ARM_UC_PAAL_EVENT_FINALIZE_ERROR,
00062         ARM_UC_PAAL_EVENT_READ_ERROR,
00063         ARM_UC_PAAL_EVENT_ACTIVATE_ERROR,
00064         ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_ERROR,
00065         ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_ERROR,
00066         ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_ERROR,
00067     */
00068     tr_debug("arm_uc_pal_classic_callback");
00069 
00070     switch (event)
00071     {
00072         case PAL_IMAGE_EVENT_INIT:
00073             arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_INITIALIZE_DONE);
00074             break;
00075         case PAL_IMAGE_EVENT_PREPARE:
00076             arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_PREPARE_DONE);
00077             break;
00078         case PAL_IMAGE_EVENT_WRITE:
00079             arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_WRITE_DONE);
00080             break;
00081         case PAL_IMAGE_EVENT_FINALIZE:
00082             arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_FINALIZE_DONE);
00083             break;
00084         case PAL_IMAGE_EVENT_READTOBUFFER:
00085             arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_READ_DONE);
00086             break;
00087         case PAL_IMAGE_EVENT_ACTIVATE:
00088             arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_ACTIVATE_DONE);
00089             break;
00090         default:
00091             break;
00092     }
00093 }
00094 
00095 /**
00096  * @brief Initialize the underlying storage and set the callback handler.
00097  *
00098  * @param callback Function pointer to event handler.
00099  * @return Returns ERR_NONE on accept, and signals the event handler with
00100  *         either DONE or ERROR when complete.
00101  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00102  */
00103 arm_uc_error_t ARM_UC_Classic_PAL_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback)
00104 {
00105     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00106 
00107     if (callback)
00108     {
00109         palStatus_t status1 = pal_imageInitAPI(arm_uc_pal_classic_callback);
00110         arm_uc_error_t status2 = pal_ext_imageInitAPI(arm_uc_pal_classic_signal_callback);
00111 
00112         if ((status1 == PAL_SUCCESS) && (status2.error == ERR_NONE))
00113         {
00114             arm_uc_pal_external_callback = callback;
00115             arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_INITIALIZE_DONE);
00116 
00117             result.code = ERR_NONE;
00118         }
00119         else
00120         {
00121             result.code = ERR_NOT_READY;
00122         }
00123     }
00124 
00125     return result;
00126 }
00127 
00128 /**
00129  * @brief Get a bitmap indicating supported features.
00130  * @details The bitmap is used in conjunction with the firmware and
00131  *          installer details struct to indicate what fields are supported
00132  *          and which values are valid.
00133  *
00134  * @return Capability bitmap.
00135  */
00136 ARM_UC_PAAL_UPDATE_CAPABILITIES ARM_UC_Classic_PAL_GetCapabilities(void)
00137 {
00138     ARM_UC_PAAL_UPDATE_CAPABILITIES result = {
00139         .installer_arm_hash = 0,
00140         .installer_oem_hash = 0,
00141         .installer_layout   = 0,
00142         .firmware_hash      = 1,
00143         .firmware_hmac      = 0,
00144         .firmware_campaign  = 0,
00145         .firmware_version   = 1,
00146         .firmware_size      = 1
00147     };
00148 
00149     return result;
00150 }
00151 
00152 /**
00153  * @brief Get maximum number of supported storage locations.
00154  *
00155  * @return Number of storage locations.
00156  */
00157 uint32_t ARM_UC_Classic_PAL_GetMaxID(void)
00158 {
00159     return 1;
00160 }
00161 
00162 /**
00163  * @brief Prepare the storage layer for a new firmware image.
00164  * @details The storage location is set up to receive an image with
00165  *          the details passed in the details struct.
00166  *
00167  * @param location Storage location ID.
00168  * @param details Pointer to a struct with firmware details.
00169  * @param buffer Temporary buffer for formatting and storing metadata.
00170  * @return Returns ERR_NONE on accept, and signals the event handler with
00171  *         either DONE or ERROR when complete.
00172  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00173  */
00174 arm_uc_error_t ARM_UC_Classic_PAL_Prepare(uint32_t location,
00175                                           const arm_uc_firmware_details_t* details,
00176                                           arm_uc_buffer_t* buffer)
00177 {
00178     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00179 
00180     if (details && buffer)
00181     {
00182         /* encode firmware details in buffer */
00183         arm_uc_error_t header_status = arm_uc_create_external_header_v2(details,
00184                                                                         buffer);
00185 
00186         if (header_status.error == ERR_NONE)
00187         {
00188             /* format file name and path */
00189             char file_path[PAL_MAX_FILE_AND_FOLDER_LENGTH] = { 0 };
00190 
00191             result = arm_uc_pal_filesystem_get_path(location,
00192                                                     FIRMWARE_IMAGE_ITEM_HEADER,
00193                                                     file_path,
00194                                                     PAL_MAX_FILE_AND_FOLDER_LENGTH);
00195 
00196             if (result.code == ERR_NONE)
00197             {
00198                 tr_debug("file_path: %s", file_path);
00199 
00200                 palFileDescriptor_t file = 0;
00201 
00202                 /* open file and get file handler */
00203                 palStatus_t status = pal_fsFopen(file_path,
00204                                                  PAL_FS_FLAG_READWRITETRUNC,
00205                                                  &file);
00206 
00207                 if (status == PAL_SUCCESS)
00208                 {
00209                     size_t xfer_size = 0;
00210 
00211                     /* write buffer to file */
00212                     status = pal_fsFwrite(&file,
00213                                           buffer->ptr,
00214                                           buffer->size,
00215                                           &xfer_size);
00216 
00217                     tr_debug("written: %lu", (unsigned long)xfer_size);
00218 
00219                     /* call event hadnler and set return code if write was successful */
00220                     if ((status == PAL_SUCCESS) &&
00221                         (xfer_size == buffer->size))
00222                     {
00223                         result.code = ERR_NONE;
00224 
00225                         arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_PREPARE_DONE);
00226                     }
00227 
00228                     /* close file after write */
00229                     status = pal_fsFclose(&file);
00230 
00231                     if (status != PAL_SUCCESS)
00232                     {
00233                         tr_error("pal_fsFclose failed: %" PRId32, status);
00234                     }
00235                 }
00236                 else
00237                 {
00238                     tr_error("pal_fsFopen failed: %" PRId32, status);
00239                 }
00240             }
00241             else
00242             {
00243                 tr_error("file name and path too long");
00244             }
00245         }
00246         else
00247         {
00248             tr_error("header too large for buffer");
00249         }
00250     }
00251 
00252     return result;
00253 }
00254 
00255 /**
00256  * @brief Write a fragment to the indicated storage location.
00257  * @details The storage location must have been allocated using the Prepare
00258  *          call. The call is expected to write the entire fragment before
00259  *          signaling completion.
00260  *
00261  * @param location Storage location ID.
00262  * @param offset Offset in bytes to where the fragment should be written.
00263  * @param buffer Pointer to buffer struct with fragment.
00264  * @return Returns ERR_NONE on accept, and signals the event handler with
00265  *         either DONE or ERROR when complete.
00266  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00267  */
00268 arm_uc_error_t ARM_UC_Classic_PAL_Write(uint32_t location,
00269                                         uint32_t offset,
00270                                         const arm_uc_buffer_t* buffer)
00271 {
00272     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00273 
00274     if (buffer)
00275     {
00276         palStatus_t status = pal_imageWrite(location,
00277                                             offset,
00278                                             (palConstBuffer_t*) buffer);
00279 
00280         if (status == PAL_SUCCESS)
00281         {
00282             result.code = ERR_NONE;
00283         }
00284         else
00285         {
00286             result.code = ERR_NOT_READY;
00287         }
00288     }
00289 
00290     return result;
00291 }
00292 
00293 /**
00294  * @brief Close storage location for writing and flush pending data.
00295  *
00296  * @param location Storage location ID.
00297  * @return Returns ERR_NONE on accept, and signals the event handler with
00298  *         either DONE or ERROR when complete.
00299  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00300  */
00301 arm_uc_error_t ARM_UC_Classic_PAL_Finalize(uint32_t location)
00302 {
00303     arm_uc_error_t result = { .code = ERR_NOT_READY };
00304 
00305     palStatus_t status = pal_imageFinalize(location);
00306 
00307     if (status == PAL_SUCCESS)
00308     {
00309         result.code = ERR_NONE;
00310     }
00311 
00312     return result;
00313 }
00314 
00315 /**
00316  * @brief Read a fragment from the indicated storage location.
00317  * @details The function will read until the buffer is full or the end of
00318  *          the storage location has been reached. The actual amount of
00319  *          bytes read is set in the buffer struct.
00320  *
00321  * @param location Storage location ID.
00322  * @param offset Offset in bytes to read from.
00323  * @param buffer Pointer to buffer struct to store fragment. buffer->size
00324  *        contains the intended read size.
00325  * @return Returns ERR_NONE on accept, and signals the event handler with
00326  *         either DONE or ERROR when complete.
00327  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00328  *         buffer->size contains actual bytes read on return.
00329  */
00330 arm_uc_error_t ARM_UC_Classic_PAL_Read(uint32_t location,
00331                                        uint32_t offset,
00332                                        arm_uc_buffer_t* buffer)
00333 {
00334     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00335 
00336     if (buffer)
00337     {
00338         palStatus_t status = pal_imageReadToBuffer(location,
00339                                                    offset,
00340                                                    (palBuffer_t*) buffer);
00341 
00342         if (status == PAL_SUCCESS)
00343         {
00344             tr_debug("pal_imageReadToBuffer succeeded: %" PRIX32, buffer->size);
00345             result.code = ERR_NONE;
00346         }
00347         else
00348         {
00349             tr_error("pal_imageReadToBuffer failed");
00350             result.code = ERR_NOT_READY;
00351         }
00352     }
00353 
00354     return result;
00355 }
00356 
00357 /**
00358  * @brief Set the firmware image in the slot to be the new active image.
00359  * @details This call is responsible for initiating the process for
00360  *          applying a new/different image. Depending on the platform this
00361  *          could be:
00362  *           * An empty call, if the installer can deduce which slot to
00363  *             choose from based on the firmware details.
00364  *           * Setting a flag to indicate which slot to use next.
00365  *           * Decompressing/decrypting/installing the firmware image on
00366  *             top of another.
00367  *
00368  * @param location Storage location ID.
00369  * @return Returns ERR_NONE on accept, and signals the event handler with
00370  *         either DONE or ERROR when complete.
00371  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00372  */
00373 arm_uc_error_t ARM_UC_Classic_PAL_Activate(uint32_t location)
00374 {
00375     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00376 
00377     result = pal_ext_imageActivate(location);
00378 
00379     return result;
00380 }
00381 
00382 /**
00383  * @brief Get firmware details for the actively running firmware.
00384  * @details This call populates the passed details struct with information
00385  *          about the currently active firmware image. Only the fields
00386  *          marked as supported in the capabilities bitmap will have valid
00387  *          values.
00388  *
00389  * @param details Pointer to firmware details struct to be populated.
00390  * @return Returns ERR_NONE on accept, and signals the event handler with
00391  *         either DONE or ERROR when complete.
00392  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00393  */
00394 arm_uc_error_t ARM_UC_Classic_PAL_GetActiveFirmwareDetails(arm_uc_firmware_details_t* details)
00395 {
00396     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00397 
00398     if (details)
00399     {
00400         result = pal_ext_imageGetActiveDetails(details);
00401     }
00402 
00403     return result;
00404 }
00405 
00406 /**
00407  * @brief Get firmware details for the firmware image in the slot passed.
00408  * @details This call populates the passed details struct with information
00409  *          about the firmware image in the slot passed. Only the fields
00410  *          marked as supported in the capabilities bitmap will have valid
00411  *          values.
00412  *
00413  * @param details Pointer to firmware details struct to be populated.
00414  * @return Returns ERR_NONE on accept, and signals the event handler with
00415  *         either DONE or ERROR when complete.
00416  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00417  */
00418 arm_uc_error_t ARM_UC_Classic_PAL_GetFirmwareDetails(uint32_t location,
00419                                                      arm_uc_firmware_details_t* details)
00420 {
00421     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00422 
00423     if (details)
00424     {
00425         char file_path[PAL_MAX_FILE_AND_FOLDER_LENGTH+1] = { 0 };
00426 
00427         palStatus_t status = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY,
00428                                                  PAL_MAX_FILE_AND_FOLDER_LENGTH,
00429                                                  file_path);
00430 
00431         if (status == PAL_SUCCESS)
00432         {
00433             /* keep track of file and folder length */
00434             /* add mount point name length */
00435             int length = arm_uc_strnlen((const uint8_t *)file_path, PAL_MAX_FILE_AND_FOLDER_LENGTH);
00436 
00437             /* add slash if needed */
00438             if (( length == 0) || 
00439                 ((length < PAL_MAX_FILE_AND_FOLDER_LENGTH) &&
00440                     (file_path[length - 1] != '/')))
00441             {
00442                 file_path[length] = '/';
00443                 file_path[++length] = 0;
00444             }
00445             
00446 
00447             /* check that path didn't overrun */
00448             if (length < PAL_MAX_FILE_AND_FOLDER_LENGTH)
00449             {
00450                 /* start snprintf after the mount point name and add length */
00451                 length += snprintf(&file_path[length],
00452                                    PAL_MAX_FILE_AND_FOLDER_LENGTH - length,
00453                                    ARM_UC_FIRMWARE_FOLDER_NAME "/header_%" PRIu32 ".bin",
00454                                    location);
00455 
00456                 /* check that file path didn't overrun */
00457                 if (length < PAL_MAX_FILE_AND_FOLDER_LENGTH)
00458                 {
00459                     tr_debug("file_path: %d %s", length, file_path);
00460 
00461                     palFileDescriptor_t file = 0;
00462 
00463                     /* open metadata header file if it exists */
00464                     palStatus_t pal_rc = pal_fsFopen(file_path,
00465                                                      PAL_FS_FLAG_READONLY,
00466                                                      &file);
00467 
00468                     if (pal_rc == PAL_SUCCESS)
00469                     {
00470                         size_t xfer_size = 0;
00471 
00472                         /* read metadata header */
00473                         uint8_t read_buffer[ARM_UC_EXTERNAL_HEADER_SIZE_V2] = { 0 };
00474 
00475                         pal_rc = pal_fsFread(&file,
00476                                              read_buffer,
00477                                              ARM_UC_EXTERNAL_HEADER_SIZE_V2,
00478                                              &xfer_size);
00479 
00480                         /* check return code */
00481                         if ((pal_rc == PAL_SUCCESS) &&
00482                             (xfer_size == ARM_UC_EXTERNAL_HEADER_SIZE_V2))
00483                         {
00484                             tr_debug("read bytes: %lu", (unsigned long)xfer_size);
00485 
00486                             /* read out header magic */
00487                             uint32_t headerMagic = arm_uc_parse_uint32(&read_buffer[0]);
00488 
00489                             /* read out header magic */
00490                             uint32_t headerVersion = arm_uc_parse_uint32(&read_buffer[4]);
00491 
00492                             /* choose version to decode */
00493                             if ((headerMagic == ARM_UC_EXTERNAL_HEADER_MAGIC_V2) &&
00494                                 (headerVersion == ARM_UC_EXTERNAL_HEADER_VERSION_V2))
00495                             {
00496                                 result = arm_uc_parse_external_header_v2(read_buffer, details);
00497 
00498                                 tr_debug("version: %" PRIu64, details->version);
00499                                 tr_debug("size: %"PRIu64, details->size);
00500 
00501                                 if (result.error == ERR_NONE)
00502                                 {
00503                                     arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE);
00504                                 }
00505                             }
00506                             else
00507                             {
00508                                 /* invalid header format */
00509                                 tr_error("invalid header in slot %" PRIu32, location);
00510                             }
00511                         }
00512                         else if (xfer_size != ARM_UC_EXTERNAL_HEADER_SIZE_V2)
00513                         {
00514                             /* invalid header format */
00515                             tr_error("invalid header in slot %" PRIu32, location);
00516                         }
00517                         else
00518                         {
00519                             /* unsuccessful read */
00520                             tr_error("pal_fsFread returned 0x%" PRIX32, (uint32_t) pal_rc);
00521                         }
00522 
00523                         /* close file after use */
00524                         pal_rc = pal_fsFclose(&file);
00525 
00526                         if (pal_rc != PAL_SUCCESS)
00527                         {
00528                             tr_error("pal_fsFclose failed: %" PRId32, pal_rc);
00529                         }
00530                     }
00531                     else
00532                     {
00533                         /* header file not present, slot is either invalid or unused. */
00534                         result.code = ERR_NOT_READY;
00535                     }
00536                 }
00537             }
00538         }
00539     }
00540 
00541     return result;
00542 }
00543 
00544 /**
00545  * @brief Get details for the component responsible for installation.
00546  * @details This call populates the passed details struct with information
00547  *          about the local installer. Only the fields marked as supported
00548  *          in the capabilities bitmap will have valid values. The
00549  *          installer could be the bootloader, a recovery image, or some
00550  *          other component responsible for applying the new firmware
00551  *          image.
00552  *
00553  * @param details Pointer to installer details struct to be populated.
00554  * @return Returns ERR_NONE on accept, and signals the event handler with
00555  *         either DONE or ERROR when complete.
00556  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00557  */
00558 arm_uc_error_t ARM_UC_Classic_PAL_GetInstallerDetails(arm_uc_installer_details_t* details)
00559 {
00560     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00561 
00562     if (details)
00563     {
00564         result = pal_ext_installerGetDetails(details);
00565     }
00566 
00567     return result;
00568 }
00569 
00570 const ARM_UC_PAAL_UPDATE ARM_UCP_FILESYSTEM =
00571 {
00572     .Initialize                 = ARM_UC_Classic_PAL_Initialize,
00573     .GetCapabilities            = ARM_UC_Classic_PAL_GetCapabilities,
00574     .GetMaxID                   = ARM_UC_Classic_PAL_GetMaxID,
00575     .Prepare                    = ARM_UC_Classic_PAL_Prepare,
00576     .Write                      = ARM_UC_Classic_PAL_Write,
00577     .Finalize                   = ARM_UC_Classic_PAL_Finalize,
00578     .Read                       = ARM_UC_Classic_PAL_Read,
00579     .Activate                   = ARM_UC_Classic_PAL_Activate,
00580     .GetActiveFirmwareDetails   = ARM_UC_Classic_PAL_GetActiveFirmwareDetails,
00581     .GetFirmwareDetails         = ARM_UC_Classic_PAL_GetFirmwareDetails,
00582     .GetInstallerDetails        = ARM_UC_Classic_PAL_GetInstallerDetails
00583 };