This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC1352P7: ZR_SW_OTA_CLIENT_ONCHIP problem

Part Number: CC1352P7
Other Parts Discussed in Thread: CC2652R7, UNIFLASH, SYSCONFIG

HI TI!!!

I am testing the OTA in zr_sw_ota_client_onchip_LP_CC1352P7_4 and zr_sw_ota_client_offchip_LP_CC1352P7_4.

I am using LPCC1352P7_4 SDK:6_41_00_17

zr_sw_ota_client_offchip_LP_CC1352P7_4 works perfectly!!! The firmware is downloaded and run the new firmware. 

but I have a problem with zr_sw_ota_client_onchip_LP_CC1352P7_4, the firmware is downloaded, but the new firmware are no running, the active firmware on CC1352P7 is the old firmware. 

Do you have any idea what I might be doing wrong?

Thank yuo very much!

  • Hi albgarc,

    There are very specific instructions inside of the "Dual Image OTA Configuration" section of the zr_sw_ota_client_onchip README which will need to be followed.  You will also need to ensure that the dual-image configuration of the on-chip BIM is loaded alongside the application.

    Regards,
    Ryan

  • Hi Ryan!!!

    Thank you very much!

    I am loading the bim.hex file only on the first load of the program via JTAG. Then after with OTA I only load the application file. Do you mean that I have to load the BIM and the application file via OTA?

  • You cannot load the BIM through OTA, this has to be done with the JTAG interface.  You cannot use the same BIM for on-chip and off-chip applications, thus it is not possible to switch between off and on-chip versions using solely OTA.  You must ensure that the dual image configuration of the on-chip BIM is loaded alongside the initial on-chip application.

    Regards,
    Ryan

  • Hi Ryan, Thank you very much!

    I have read the project readme, I can't find anything to suggest what I might be doing wrong except the possibility to build for slot A or slot B.

    I am using CC1352P7, so I should not modify the image-double constants in the bim_onchip_main.c, right? This is only for CC2652R7.

    The default zr_sw_otaclient_onchip project is builded for slot B. The image I am going to transfer by OTA should be builded for slot A?

    The steps I am following are as follows:
    1-) Build the project zr_sw_otaclient_onchip as it is in the sdk without change with OTA_APP_VERSION=0x00000001.
    2-) With uniflash erase the memory of the chip.
    3-) With uniflash load the firmwares bim_onchip_LP (as it is in the sdk without change) and zr_sw_otaclient_onchip.
    4-) Rebuild the project zr_sw_otaclient_onchip as it is in the sdk without change with OTA_APP_VERSION=0x00000002.
    5-) Execute OTA (Previously the application file was prepared for OTA).

    Note: the application file transfers perfectly, but the new application does not run OTA_APP_VERSION always has value 0x00000001.

    Could there be a predefined symbol missing?

    Any symbol to verify valid image, double image ...?

    Than you very much. Best regards.

  • You should modify the BIM dual-image configuration as instructed for both the CC1352P7 and CC2652R7 as they have the same memory footprint.  The bim_onchip_main.c changes provided in the instructions are essential for the BIM to find the correct image headers before/after an OTA image update.

    The original application loaded into the device alongside the BIM will be slot B, and the first image to be transferred by OTA should be built for slot A.  Building for slot A means swapping NVS Region Bases, adding reset Vector addresses to the SysConfig file via text editor, and defining OAD_IMG_A inside the Linker Preprocessor Project options.  All of these instructions are given in the README.  It is not enough just to change the OTA_APP_VERSION.

    Regards,
    Ryan

  • Hi Ryan!

    Is this what I need to do to change the vector?

  • That appears to be correct.

    Regards,
    Ryan

  • Hello Ryan.
    Following Alberto's comments. We are working with on_chip firmware. Trying to do the OTA update, the image is transferred correctly. However, when the last "Upgrade End Response" message is sent, the device does not respond with the "Default Response". Also, it usually takes a while between the last "Image Block" message and the "Upgrade End Request". As you can see in the following image, everything happens fast, so I would say that the update is not performed correctly or even just started. Does this tell you something about the possible error that is happening to us?

    BR,

    Randy

  • Hi Randy,

    So essentially the zr_sw_ota_client_onchip_LP_CC1352P7_4 device is unresponsive?  How long is the update running before this occurs?  The update has started since there are multiple Image Block Requests but the entire OTA upgrade process will take a matter of minutes.  If the necessary changes from the README for image A are not followed in entirety then there could be a flash memory mismatch which causes unexpected behavior.

    Regards,
    Ryan

  • Hi Randy, Alberto,

    I've just tested the application using SDK v6.41 and the LP-CC1352P7-4 and confirmed that OTA update completes successfully after using the instructions provided, however there is a bug in the BIM dual-image code that must first be corrected.  I can either provide corrections here or you can wait until the v7.10 SDK releases to further evaluate this solution.

    Regards,
    Ryan

  • Hi Ryan, could you provide us with the BIM image for us to test with SDK 6.41 or tell us where to find it? So we can fully test our device before v7.10

    BR,

    Randy

  • Replace the attached files in your BIM on-chip project and no longer set Hwi.resetVectorAddress = system.utils.bigInt("0x540A8") inside zr_sw_ota_client_onchip.syscfg

    bim_onchip_main.c
    /******************************************************************************
    
     @file  bim_main.c
    
     @brief This module contains the definitions for the main functionality of a
            Boot  Image Manager for on chip OAD.
    
     Group: CMCU
     $Target Device: DEVICES $
    
     ******************************************************************************
     $License: BSD3 2018 $
     ******************************************************************************
     $Release Name: PACKAGE NAME $
     $Release Date: PACKAGE RELEASE DATE $
     *****************************************************************************/
    
    /*******************************************************************************
     *                                          Includes
     */
    #include <stdint.h>
    #include <string.h>
    #include <ti/devices/DeviceFamily.h>
    #include DeviceFamily_constructPath(driverlib/flash.h)
    #include DeviceFamily_constructPath(driverlib/watchdog.h)
    #include DeviceFamily_constructPath(inc/hw_prcm.h)
    
    #include "ti/common/cc26xx/crc/crc32.h"
    #include "ti/common/cc26xx/flash_interface/flash_interface.h"
    #include "ti/common/cc26xx/bim/bim_util.h"
    #include "ti/common/cc26xx/oad/oad_image_header.h"
    
    #ifdef __IAR_SYSTEMS_ICC__
    #include <intrinsics.h>
    #endif
    
    #if defined(DEBUG_BIM) || defined(BIM_BLINK_LED_NO_VALID_IMAGE)
    #include DeviceFamily_constructPath(driverlib/gpio.h)
    #include "ti/common/flash/no_rtos/extFlash/bsp.h"
    #include "ti/common/cc26xx/debug/led_debug.h"
    #endif
    
    #if defined(SECURITY)
    #include "sign_util.h"
    #if defined(DeviceFamily_CC26X2) || defined(DeviceFamily_CC13X2) || defined(DeviceFamily_CC13X2X7) || defined(DeviceFamily_CC26X2X7)
    #include "sha2_driverlib.h"
    #else
    #include DeviceFamily_constructPath(driverlib/rom_sha256.h)
    #endif /* DeviceFamily_CC26X2 || DeviceFamily_CC13X2 || DeviceFamily_CC13X2X7 || DeviceFamily_CC26X2X7 */
    #endif
    
    #if defined(BIM_DUAL_ONCHIP_IMAGE)
    #if defined(DEBUG_BIM) || !defined(SECURITY)
        // DUAL Image BIM is considered a strictly production ready variant. DEBUG_BIM cannot be used as
        // it would skip key security steps.
        #error "Error: DUAL ON CHIP BIM needs the macro SECURITY to be enabled & DEBUG_BIM to be disabled!"
    #endif
    #endif
    /*******************************************************************************
     *                                          Constants
     */
    
    /* Customer to update these as per their images */
    #ifdef BIM_DUAL_ONCHIP_IMAGE
    #define IMAGE_1_HDR_START_PAGE_NUM (0)
    #define IMAGE_2_HDR_START_PAGE_NUM (42)
    #if(IMAGE_2_HDR_START_PAGE_NUM <= IMAGE_1_HDR_START_PAGE_NUM)
        #error "Error: Ensure Image 2 Header starts at a higher flash page as compared to Image 1 Header!"
    #endif
    
    /* Customer to update these as per their images */
    /* In the current example:*/
    /* Flash pages 0 to 20 is slot 1 */
    /* Flash pages 21 & 22 are being used as shared NV between both the images */
    /* Flash pages 23 to 42 is slot 2 */
    /* Flash page 43 is BIM + CCFG */
    /* Total flash pages on CC26x2, CC13x2 is 44 pages */
    #define IMAGE_1_START_FLASH_PAGE_NUM (IMAGE_1_HDR_START_PAGE_NUM)
    #define IMAGE_1_END_FLASH_PAGE_NUM   (41)
    #define IMAGE_2_START_FLASH_PAGE_NUM (IMAGE_2_HDR_START_PAGE_NUM)
    #define IMAGE_2_END_FLASH_PAGE_NUM   (83)
    
    #if(IMAGE_2_START_FLASH_PAGE_NUM <= IMAGE_1_START_FLASH_PAGE_NUM)
        #error "Error: Ensure Image 2 starts at a higher flash page as compared to Image 1!"
    #endif
    #if(IMAGE_1_END_FLASH_PAGE_NUM <= IMAGE_1_START_FLASH_PAGE_NUM)
        #error "Error: Incorrect image 1: end flash page number is less than start flash page number!"
    #endif
    #if(IMAGE_2_END_FLASH_PAGE_NUM <= IMAGE_2_START_FLASH_PAGE_NUM)
        #error "Error: Incorrect image 2: end flash page number is less than start flash page number!"
    #endif
    #if(IMAGE_2_END_FLASH_PAGE_NUM <= IMAGE_1_END_FLASH_PAGE_NUM)
        #error "Error: Ensure Image 2 ends at a higher flash page as compared to Image 1!"
    #endif
    #if(IMAGE_2_END_FLASH_PAGE_NUM > 86)
        #error "Error: CC13x2/26x2 devices have only 44 flash pages & 43th flash page is reserved for BIM + CCFG !"
    #endif
    
    #define IMG_TYPE_NO_IMAGE_PRESENT           (uint8_t)(0x00)
    #define IMG_TYPE_IMAGE_PRESENT              (uint8_t)(0x01)
    #define IMG_TYPE_INVALID_APPSTACKLIB_IMG    (uint8_t)(0x00)
    #define IMG_TYPE_VALID_APPSTACKLIB_IMG      (uint8_t)(0x02)
    
    #define IMG_PRESENT_MASK  (uint8_t)(0x01)
    #define IMG_VALIDITY_MASK (uint8_t)(0x02)
    
    #define BIM_ONCHIP_MAX_NUM_SEARCHES (2)
    #endif //BIM_DUAL_ONCHIP_IMAGE
    
    
    #if defined (SECURITY)
    #define SHA_BUF_SZ                      EFL_PAGE_SIZE
    #endif
    
    #define SUCCESS                         0
    #define FAIL                           -1
    
    /*******************************************************************************
     * LOCAL VARIABLES
     */
    
    #ifndef DEBUG_BIM
    static uint32_t intFlashPageSize;       /* Size of internal flash page */
    #endif
    
    #ifdef BIM_DUAL_ONCHIP_IMAGE
    uint8_t img1_status = IMG_TYPE_NO_IMAGE_PRESENT;
    uint8_t img2_status = IMG_TYPE_NO_IMAGE_PRESENT;
    #endif
    
    #if (defined(SECURITY))
    
    #if defined(__IAR_SYSTEMS_ICC__)
    __no_init uint8_t shaBuf[SHA_BUF_SZ];
    #elif defined(__TI_COMPILER_VERSION__) || defined(__clang__)
    uint8_t shaBuf[SHA_BUF_SZ];
    #endif
    
    /* Cert element stored in flash where public keys in Little Endian format*/
    #ifdef __TI_COMPILER_VERSION__
    #pragma DATA_SECTION(_secureCertElement, ".cert_element")
    #pragma RETAIN(_secureCertElement)
    const certElement_t _secureCertElement =
    #elif __clang__
    const certElement_t _secureCertElement __attribute__((section(".cert_element"))) =
    #elif  defined(__IAR_SYSTEMS_ICC__)
    #pragma location=".cert_element"
    const certElement_t _secureCertElement @ ".cert_element" =
    #endif
    {
      .version    = SECURE_SIGN_TYPE,
      .len        = SECURE_CERT_LENGTH,
      .options    = SECURE_CERT_OPTIONS,
      .signerInfo = {0xb0,0x17,0x7d,0x51,0x1d,0xec,0x10,0x8b},
      .certPayload.eccKey.pubKeyX = {0xd8,0x51,0xbc,0xa2,0xed,0x3d,0x9e,0x19,0xb7,0x33,0xa5,0x2f,0x33,0xda,0x05,0x40,0x4d,0x13,0x76,0x50,0x3d,0x88,0xdf,0x5c,0xd0,0xe2,0xf2,0x58,0x30,0x53,0xc4,0x2a},
      .certPayload.eccKey.pubKeyY = {0xb9,0x2a,0xbe,0xef,0x66,0x5f,0xec,0xcf,0x56,0x16,0xcc,0x36,0xef,0x2d,0xc9,0x5e,0x46,0x2b,0x7c,0x3b,0x09,0xc1,0x99,0x56,0xd9,0xaf,0x95,0x81,0x63,0x23,0x7b,0xe7}
     };
    
    uint32_t eccWorkzone[SECURE_FW_ECC_NIST_P256_WORKZONE_LEN_IN_BYTES + SECURE_FW_ECC_BUF_TOTAL_LEN(SECURE_FW_ECC_NIST_P256_KEY_LEN_IN_BYTES)*5] = {0};
    uint8_t headerBuf[HDR_LEN_WITH_SECURITY_INFO];
    
    #endif
    
    /*******************************************************************************
     * EXTERN FUNCTIONS
     */
    
    
    /*******************************************************************************
     * LOCAL FUNCTIONS
     */
    static void Bim_findImage(uint8_t flashPageNum, uint8_t imgType);
    
    #ifdef BIM_DUAL_ONCHIP_IMAGE
    inline static void BIM_updateImgStatus(uint8_t flashPageNum, uint8_t status);
    static void Bim_UpdateExecValidImg();
    #ifdef BIM_ERASE_INVALID_IMAGE
    static uint8_t Bim_EraseOnchipFlashPages(uint8_t startPage, uint8_t endPage);
    #else
    inline static void Bim_updateVerifStatus(uint8_t flashPageNum, uint8_t secStatus);
    #endif //BIM_ERASE_INVALID_IMAGE
    #endif //BIM_DUAL_ONCHIP_IMAGE
    
    #if defined(SECURITY)
    
    #ifndef DEBUG_BIM
    
    static bool    Bim_checkForSecSegmnt(uint32_t iflStartAddr, uint32_t imgLen);
    static uint8_t Bim_verifyImage(uint32_t iflStartAddr);
    
    #endif
    
    // Function which is used to verify the authenticity of the OAD commands
    int8_t Bim_payloadVerify(uint8_t ver, uint32_t cntr, uint32_t payloadlen,
                              uint8_t  *dataPayload, uint8_t *signPayload,
                              ecdsaSigVerifyBuf_t *ecdsaSigVerifyBuf);
    
    // Creating a section for the function pointer, so that it can be easily accessed by OAD application(s)
    #ifdef __TI_COMPILER_VERSION__
    #pragma DATA_SECTION(_fnPtr, ".fnPtr")
    #pragma RETAIN(_fnPtr)
    const uint32_t _fnPtr = (uint32_t)&Bim_payloadVerify;
    #elif  defined(__IAR_SYSTEMS_ICC__)
    #pragma location=".fnPtr"
    const uint32_t _fnPtr @ ".fnPtr" = (uint32_t)&Bim_payloadVerify;
    #endif // #ifdef __TI_COMPILER_VERSION__
    
    #endif //#if defined (SECURITY)
    
    
    #if defined(SECURITY)
    #ifndef DEBUG_BIM
    /*******************************************************************************
     * @fn         Bim_checkForSecSegmnt
    *
    *  @brief      Check for Security Segment. Reads through the headers in the .bin
    *              file. If a security header is found the function checks to see if
    *              the header has a populated segment.
    *
    *  @param       iFlStrAddr - The start address in internal flash of the binary image
    *  @param       imgLen - Length of the image over which presence of security segment
    *               is searched
    *  @return      0  - valid security segment not found
    *  @return      1  - valid security segment found
    *
    */
    static bool Bim_checkForSecSegmnt(uint32_t iFlStrAddr, uint32_t imgLen)
    {
        bool securityFound = false;
        uint8_t endOfSegment = 0;
        uint8_t segmentType = DEFAULT_STATE;
        uint32_t segmentLength = 0;
        uint32_t searchAddr =  iFlStrAddr+OAD_IMG_HDR_LEN;
    
        while(!endOfSegment)
        {
            //extFlashRead(searchAddr, 1, &segmentType);
            readFlash(searchAddr, &segmentType, 1);
    
            if(segmentType == IMG_SECURITY_SEG_ID)
            {
                /* In this version of BIM, the security header will ALWAYS be present
                   But the payload will sometimes not be there. If this finds the
                   header, the payload is also checked for existence. */
                searchAddr += SIG_OFFSET;
                uint32_t sigVal = 0;
                readFlash(searchAddr, (uint8_t *)&sigVal, sizeof(uint32_t));
    
                if(sigVal != 0) //Indicates the presence of a signature
                {
                    endOfSegment = 1;
                    securityFound = true;
                }
                else
                {
                    break;
                }
            }
            else
            {
                searchAddr += SEG_LEN_OFFSET;
                if((searchAddr + sizeof(uint32_t)) > (iFlStrAddr + imgLen))
                {
                    break;
                }
                //extFlashRead(searchAddr, sizeof(uint32_t), (uint8_t *)&segmentLength);
                readFlash(searchAddr, (uint8_t *)&segmentLength, sizeof(uint32_t));
    
                searchAddr += (segmentLength - SEG_LEN_OFFSET);
                if((searchAddr) > (iFlStrAddr + imgLen))
                {
                    break;
                }
            }
        }
    
        return securityFound;
    }//end of function
    
    /*******************************************************************************
     * @fn      Bim_verifyImage
     *
     * @brief   Verifies the image stored on internal flash using ECDSA-SHA256
     *
     * @param   iflStartAddr - internal flash address of the image to be verified.
     *
     * @return  Zero when successful. Non-zero, otherwise..
     */
    static uint8_t Bim_verifyImage(uint32_t iflStartAddr)
    {
        uint8_t verifyStatus = (uint8_t)FAIL;
    
        /* clear the ECC work zone Buffer */
        uint32_t *eccPayloadWorkzone = eccWorkzone;
        memset(eccPayloadWorkzone, 0, sizeof(eccWorkzone));
    
        /* Read in the header to get the image signature */
        readFlash(iflStartAddr, headerBuf, HDR_LEN_WITH_SECURITY_INFO);
    
        // First verify signerInfo
        verifyStatus = verifyCertElement(&headerBuf[SEG_SIGERINFO_OFFSET]);
        if(verifyStatus != SUCCESS)
        {
            return verifyStatus;
        }
    
        // Get the hash of the image
        uint8_t *finalHash;
    
        finalHash = computeSha2Hash(iflStartAddr, shaBuf, SHA_BUF_SZ, false);
    
        if(NULL == finalHash)
        {
            verifyStatus = (uint8_t)FAIL;
            return verifyStatus;
        }
    
        // Verify the hash
        // Create temp buffer used for ECDSA sign verify, it should 6*ECDSA_KEY_LEN
        uint8_t tempWorkzone[ECDSA_SHA_TEMPWORKZONE_LEN];
        memset(tempWorkzone, 0, ECDSA_SHA_TEMPWORKZONE_LEN);
    
        verifyStatus = bimVerifyImage_ecc(_secureCertElement.certPayload.eccKey.pubKeyX,
                                          _secureCertElement.certPayload.eccKey.pubKeyY,
                                           finalHash,
                                           &headerBuf[SEG_SIGNR_OFFSET],
                                           &headerBuf[SEG_SIGNS_OFFSET],
                                           eccWorkzone,
                                           tempWorkzone);
    
        if(verifyStatus == SECURE_FW_ECC_STATUS_VALID_SIGNATURE)
        {
            verifyStatus = SUCCESS;
        }
        else
        {
            verifyStatus = (uint8_t)FAIL;
        }
        return verifyStatus;
    
    }//end of function
    
    #endif // DEBUG_BIM
    
    /*******************************************************************************
     * @fn      Bim_payloadVerify
     *
     * @brief   Function in BIM to verify the payload of an OTA command.
     *
     * @param   ver - version of the security algorithm
     *          cntr - time-stamp /counter value use to verify the payload
     *          payloadlen - payload length in bytes
     *          dataPayload - pointer to data payload to be verified
     *          signPayload - pointer to sign payload
     *          eccPayloadWorkzone - pointer to the workzone used to verify the command
     *          shaPayloadWorkzone - pointer to the workzone used to generate a hash of the command
     *
     *
     * @return  Zero when successful. Non-zero, otherwise..
     */
    int8_t Bim_payloadVerify(uint8_t ver, uint32_t cntr, uint32_t payloadlen,
                             uint8_t  *dataPayload, uint8_t *signPayload,
                             ecdsaSigVerifyBuf_t *ecdsaSigVerifyBuf)
    {
        signPld_ECDSA_P256_t *signPld = (signPld_ECDSA_P256_t*)signPayload;
    
        uint8_t *sig1 = signPld->signature;
        uint8_t *sig2 = &signPld->signature[32];
        int8_t status = FAIL;
        int8_t verifyStatus = FAIL;
        uint8_t *finalHash = ecdsaSigVerifyBuf->tempWorkzone;
    
        memset(ecdsaSigVerifyBuf->tempWorkzone, 0, sizeof(ECDSA_SHA_TEMPWORKZONE_LEN));
    
        if (ver == 1)
        {
    #if defined(DeviceFamily_CC26X2) || defined(DeviceFamily_CC13X2) || defined(DeviceFamily_CC13X2X7) || defined(DeviceFamily_CC26X2X7)
            SHA2_open();
            SHA2_addData(dataPayload, payloadlen);
            SHA2_finalize(finalHash);
            SHA2_close();
    #else
            SHA256_Workzone sha256_workzone;
            SHA256_init(&sha256_workzone);
            SHA256_full(&sha256_workzone, finalHash, dataPayload, payloadlen);
    #endif /* DeviceFamily_CC26X2 || DeviceFamily_CC13X2 || DeviceFamily_CC13X2X7 || DeviceFamily_CC26X2X7 */
    
            // First verify signerInfo
            verifyStatus = verifyCertElement(signPld->signerInfo);
            if(verifyStatus != SUCCESS)
            {
                return FAIL;
            }
    
            verifyStatus = bimVerifyImage_ecc(_secureCertElement.certPayload.eccKey.pubKeyX,
                                              _secureCertElement.certPayload.eccKey.pubKeyY,
                                               finalHash, sig1, sig2,
                                               ecdsaSigVerifyBuf->eccWorkzone,
                                               (ecdsaSigVerifyBuf->tempWorkzone + ECDSA_KEY_LEN));
            if(verifyStatus == (int8_t)SECURE_FW_ECC_STATUS_VALID_SIGNATURE)
            {
                status = SUCCESS;
            }
        }
        return status;
    }//end of function
    
    #endif /* if defined(SECURITY) */
    
    
    /*******************************************************************************
     * @fn     Bim_findImage
     *
     * @brief  Performs various checks on the image, if present at
     *         flash page number. In case on non-dual onchip case,
     *         it jumps to a certain image if all checks pass. In
     *         dual image on-chip case, the image status variables
     *         are updated based on checks performed.
     *
     * @param  flashPageNum - flash page number
     *         imgType      - image type to be searched
     *
     * @return None.
     */
    static void Bim_findImage(uint8_t flashPageNum, uint8_t imgType)
    {
        imgHdr_t imgHdr;
    #ifndef BIM_DUAL_ONCHIP_IMAGE
        uint8_t securityStatus = VERIFY_FAIL;
    #else
        uint8_t imgStatus;
    #endif //BIM_DUAL_ONCHIP_IMAGE
    
        /* Read flash to find OAD image identification value */
        readFlashPg(flashPageNum, 0, &imgHdr.fixedHdr.imgID[0], OAD_IMG_ID_LEN);
    
        /* Check imageID bytes */
        if ((imgIDCheck(&(imgHdr.fixedHdr)) != true))
        {
    #ifdef BIM_DUAL_ONCHIP_IMAGE
           imgStatus = IMG_TYPE_NO_IMAGE_PRESENT;
           BIM_updateImgStatus(flashPageNum, imgStatus);
    #endif
            /* return so that same process can be repeated*/
            return;
        }
        else //valid OAD image ID value is found
        {
            /* Read whole of fixed header in the image header */
            readFlashPg(flashPageNum, 0, (uint8_t *)&imgHdr, OAD_IMG_HDR_LEN);
    
            if(imgType != imgHdr.fixedHdr.imgType || (evenBitCount(imgHdr.fixedHdr.imgVld) == false))
            {
    #ifdef BIM_DUAL_ONCHIP_IMAGE
                imgStatus = (IMG_TYPE_IMAGE_PRESENT | IMG_TYPE_INVALID_APPSTACKLIB_IMG);
                BIM_updateImgStatus(flashPageNum, imgStatus);
    #endif
                /* didn't find the image type we are looking for */
                /* Or the image we found is considered 'invalid' */
                /* return so that same process can be repeated */
                return;
            }
    
            /* Image type matched: proceed with further checks */
    
            /* check BIM and Metadata version and CRC status (if need be). If DEBUG_BIM is enabled
             * skip the crc checking and updating the crc status- as crc wouldn't have been
             * calculated at the first place */
    
            if( (imgHdr.fixedHdr.bimVer != BIM_VER  || imgHdr.fixedHdr.metaVer != META_VER) /* Invalid metadata version */
    #ifndef DEBUG_BIM
                  ||
               (imgHdr.fixedHdr.crcStat == 0xFC)  /* Invalid CRC */
    #endif
              )
            {
    #ifdef BIM_DUAL_ONCHIP_IMAGE
                imgStatus = (IMG_TYPE_IMAGE_PRESENT | IMG_TYPE_INVALID_APPSTACKLIB_IMG);
                BIM_updateImgStatus(flashPageNum, imgStatus);
    #endif
                /* return so that same process can be repeated*/
                return;
            }
    #ifdef AUTHENTICATE_PERSISTENT_IMG
            else if((imgHdr.fixedHdr.imgType == OAD_IMG_TYPE_APPSTACKLIB || imgHdr.fixedHdr.imgType == OAD_IMG_TYPE_PERSISTENT_APP)
                    && imgHdr.fixedHdr.crcStat == 0xFF) /* CRC not calculated yet */
    #else
            else if(imgHdr.fixedHdr.imgType == OAD_IMG_TYPE_APPSTACKLIB
                    && imgHdr.fixedHdr.crcStat == 0xFF) /* CRC not calculated yet */
    #endif
    
            {
    #ifndef DEBUG_BIM
    
                /* Calculate the CRC over the data buffer and update status */
                uint32_t crc32 = 0;
                uint8_t  crcstat = CRC_VALID;
                crc32 = CRC32_calc(flashPageNum, intFlashPageSize, 0, imgHdr.fixedHdr.len, false);
    
                /* Check if calculated CRC matched with the image header */
                if (crc32 != imgHdr.fixedHdr.crc32)
                {
                    /* Update CRC status */
                    crcstat = CRC_INVALID;
                    writeFlashPg(flashPageNum, CRC_STAT_OFFSET, (uint8_t *)&crcstat, 1);
    
    #ifdef BIM_DUAL_ONCHIP_IMAGE
                    imgStatus = (IMG_TYPE_IMAGE_PRESENT | IMG_TYPE_INVALID_APPSTACKLIB_IMG);
                    BIM_updateImgStatus(flashPageNum, imgStatus);
    #endif
                    /* return so that same process can be repeated */
                    return;
    
                } /* if (crc32 != imgHdr.crc32) */
    
                /* if we have come here: CRC check has passed */
                /* Update CRC status */
                writeFlashPg(flashPageNum, CRC_STAT_OFFSET, (uint8_t *)&crcstat, 1);
    #endif
            } /* else if(imgHdr.crcStat == 0xFF) */
    
    
    #if defined(SECURITY)
            /* populate the start address of the image in the internal flash */
            uint32_t iFlStrAddr = FLASH_ADDRESS(flashPageNum, 0);
    
            /* Verify the start address and the img is within internal flash bounds */
    #ifndef BIM_DUAL_ONCHIP_IMAGE
            if ((iFlStrAddr + imgHdr.fixedHdr.len) > (MAX_ONCHIP_FLASH_PAGES * INTFLASH_PAGE_SIZE))
            {
                /* return so that same process can be repeated */
                return;
            }
    #else
    
            /* verify that start address + length of image is less than the slot boundary */
            if (((iFlStrAddr == IMAGE_1_START_FLASH_PAGE_NUM * INTFLASH_PAGE_SIZE) && /* if slot 1 image */
                 ((iFlStrAddr + imgHdr.fixedHdr.len) > IMAGE_2_START_FLASH_PAGE_NUM * INTFLASH_PAGE_SIZE)) ||
                ((iFlStrAddr != IMAGE_1_START_FLASH_PAGE_NUM * INTFLASH_PAGE_SIZE) && /* if slot 2 image */
                 ((iFlStrAddr + imgHdr.fixedHdr.len) > MAX_ONCHIP_FLASH_PAGES * INTFLASH_PAGE_SIZE)))
            {
                imgStatus = (IMG_TYPE_IMAGE_PRESENT | IMG_TYPE_INVALID_APPSTACKLIB_IMG);
                BIM_updateImgStatus(flashPageNum, imgStatus);
                /* return so that same process can be repeated */
                return;
            }
    #endif //BIM_DUAL_ONCHIP_IMAGE
    
    
    #ifndef DEBUG_BIM //during debug: the sign is not populated to even verify
            int8_t signVrfyStatus = FAIL;
    
    #ifdef AUTHENTICATE_PERSISTENT_IMG
            if(imgHdr.fixedHdr.imgType == OAD_IMG_TYPE_APPSTACKLIB ||
                    imgHdr.fixedHdr.imgType == OAD_IMG_TYPE_PERSISTENT_APP)
    #else
            if(imgHdr.fixedHdr.imgType == OAD_IMG_TYPE_APPSTACKLIB)
    #endif
            {
                uint8_t securityPresence = false;
    
                /* check if security segment is present or not in the image */
                securityPresence = Bim_checkForSecSegmnt(iFlStrAddr, imgHdr.fixedHdr.len);
    
                if(securityPresence)
                {
                    /* Calculate the SHA256 of the image */
                    uint8_t readSecurityByte[SEC_VERIF_STAT_OFFSET + 1];
    
                    /* Read in the header to check if the signature has already been denied */
                    readFlashPg(flashPageNum, 0, &readSecurityByte[0], (SEC_VERIF_STAT_OFFSET + 1));
    
    #ifndef BIM_DUAL_ONCHIP_IMAGE
                    if(readSecurityByte[SEC_VERIF_STAT_OFFSET] == DEFAULT_STATE)
    #else
                    if(readSecurityByte[SEC_VERIF_STAT_OFFSET] != VERIFY_FAIL)
    #endif
                    {
                        signVrfyStatus = Bim_verifyImage(iFlStrAddr);
    
                        /* If the signature is invalid, update the sign verification status */
                        if((uint8_t)signVrfyStatus != SUCCESS)
                        {
                            readSecurityByte[SEC_VERIF_STAT_OFFSET] = VERIFY_FAIL;
                            writeFlashPg(flashPageNum, SEC_VERIF_STAT_OFFSET,  &readSecurityByte[SEC_VERIF_STAT_OFFSET], 1);
                        }
    #ifndef BIM_DUAL_ONCHIP_IMAGE
                        else
                        {
                            readSecurityByte[SEC_VERIF_STAT_OFFSET] = VERIFY_PASS;
                            writeFlashPg(flashPageNum, SEC_VERIF_STAT_OFFSET,  &readSecurityByte[SEC_VERIF_STAT_OFFSET], 1);
                        }
                    }
                    else if (readSecurityByte[SEC_VERIF_STAT_OFFSET] == VERIFY_PASS)
                    {
                        signVrfyStatus = SUCCESS;
    #endif
                    }
                } /* if(securityPresence) */
            }
    #ifndef AUTHENTICATE_PERSISTENT_IMG
            else
            {
                signVrfyStatus = SUCCESS;
            }
    #endif
    
            /*
             * sign verification has failed or
             * didn't find the security segment in the first place or
             * iFlStrAddr is outside of the authenticated flash space
             */
    #ifdef AUTHENTICATE_PERSISTENT_IMG
            /*
             * In the case that  AUTHENTICATE_PERSISTENT_IMG is defined,
             * all image types should be authenticated and therefore no
             * logic for imgType is necessary.
             */
            if((uint8_t)signVrfyStatus != SUCCESS ||
                    (imgHdr.fixedHdr.prgEntry < iFlStrAddr) ||
                    (imgHdr.fixedHdr.prgEntry > (iFlStrAddr + imgHdr.fixedHdr.len)))
    #else
            /*
             *  In the case that AUTHENTICATE_PERSISTENT_IMG is NOT defined,
             *  only imgType == OAD_IMG_TYPE_APPSTACKLIB should be authenticated.
             */
            if((uint8_t)signVrfyStatus != SUCCESS ||
                    ((imgHdr.fixedHdr.imgType == OAD_IMG_TYPE_APPSTACKLIB) &&
                    ((imgHdr.fixedHdr.prgEntry < iFlStrAddr) ||
                    (imgHdr.fixedHdr.prgEntry > (iFlStrAddr + imgHdr.fixedHdr.len)))))
    #endif
            {
    #ifdef BIM_DUAL_ONCHIP_IMAGE
                imgStatus = (IMG_TYPE_IMAGE_PRESENT | IMG_TYPE_INVALID_APPSTACKLIB_IMG);
                BIM_updateImgStatus(flashPageNum, imgStatus);
    #endif
                /* return so that same process can be repeated */
                return;
            }
            else
            {
    #ifndef BIM_DUAL_ONCHIP_IMAGE
                securityStatus = VERIFY_PASS;
    #endif
            }
    
    #else //DEBUG_BIM is defined
    #ifndef BIM_DUAL_ONCHIP_IMAGE
            securityStatus = VERIFY_PASS;
    #endif
    #endif
    
    #else //SECURITY not defined
    #ifndef BIM_DUAL_ONCHIP_IMAGE
            securityStatus = VERIFY_PASS;
    #endif
    #endif
    
    #ifndef BIM_DUAL_ONCHIP_IMAGE
            /*if we get here, its highly likely we found a valid image to boot to */
            if (VERIFY_PASS == securityStatus)
            {
    
                jumpToPrgEntry((uint32_t*)imgHdr.fixedHdr.prgEntry);
    
            }
            else
            {
                /* return so that same process can be repeated */
                return;
            }
    #else
            /*if we get here, its highly likely we found a valid image */
            imgStatus = (IMG_TYPE_IMAGE_PRESENT | IMG_TYPE_VALID_APPSTACKLIB_IMG);
            BIM_updateImgStatus(flashPageNum, imgStatus);
    #endif //BIM_DUAL_ONCHIP_IMAGE
        }//valid imageID found
    
        return;
    }
    
    #ifdef BIM_DUAL_ONCHIP_IMAGE
    /*******************************************************************************
     * @fn     BIM_updateImgStatus
     *
     * @brief  Updates the imgX_status variable based on if
     *         the image being checked is in slot 1 or slot 2.
     *         These global variables will be later consumed in
     *         Bim_UpdateExecValidImg() function.
     *
     * @param  flashPageNum - flash page number
     *
     * @return None.
     */
    inline static void BIM_updateImgStatus(uint8_t flashPageNum, uint8_t status)
    {
        if( IMAGE_1_HDR_START_PAGE_NUM == flashPageNum ) /* 1st slot */
        {
            img1_status = status;
        }
        else /* 2nd slot */
        {
            img2_status = status;
        }
    }
    
    /*******************************************************************************
     * @fn     Bim_updateVerifStatus
     *
     * @brief  Based on the img_status fields populated by Bim_findImage
     *         & anti-roll back check, decide which image to boot to &
     *         update the verifStatus fields in the security header
     *         of the images appropriately.
     *         Also, Jump into the decided upon image.
     *
     * @param  flashPageNum - flash page where the image header starts.
     * @param  secStatus - value to be written into verifStatus field.
     *
     * @return None.
     */
    inline static void Bim_updateVerifStatus(uint8_t flashPageNum, uint8_t secStatus)
    {
        writeFlashPg(flashPageNum, SEC_VERIF_STAT_OFFSET,  (uint8_t *)&secStatus, 1);
    }
    
    #ifdef BIM_ERASE_INVALID_IMAGE
    /*******************************************************************************
     * @fn     Bim_EraseOnchipFlashPages
     *
     * @brief  It Erases the onchip flash pages.
     *
     * @param  startPage - Starting page on on-chip flash to be erased
     * @param  endPage  - End page on on-chip flash to be erased
     * @param  pageSize  - flash page size
     *
     * @return - SUCCESS on successful erasure else
     *           FAIL
     */
    static uint8_t Bim_EraseOnchipFlashPages(uint8_t startPage, uint8_t endPage)
    {
        int8_t status = SUCCESS;
    
        // Erase the correct amount of pages
        for(uint8_t page = startPage; page <= endPage; ++page)
        {
            uint8_t flashStat = eraseFlashPg(page);
            if(flashStat == FLASH_FAILURE)
            {
                // If we fail to pre-erase, then halt the process
                status = FAIL;
                break;
            }
        }
        return status;
    }
    #endif // BIM_ERASE_INVALID_IMAGE
    
    /*******************************************************************************
     * @fn     Bim_UpdateExecValidImg
     *
     * @brief  Based on the img_status fields populated by Bim_findImage
     *         & anti-roll back check, decide which image to boot to &
     *         update the verifStatus fields in the security header
     *         of the images appropriately.
     *         Also, Jump into the decided upon image.
     *
     * @param  None.
     *
     * @return None.
     */
    static void Bim_UpdateExecValidImg()
    {
        /* Declare local variables used in the main function */
        imgHdr_t imgHdr_1, imgHdr_2;
        uint8_t secVer_1 = 0, secVer_2 = 0, verifStat_1 = 0, verifStat_2 = 0;
        uint8_t isPresImg_1 = img1_status & IMG_PRESENT_MASK;
        uint8_t isPresImg_2 = img2_status & IMG_PRESENT_MASK;
        uint8_t isValidImg_1 = img1_status & IMG_VALIDITY_MASK;
        uint8_t isValidImg_2 = img2_status & IMG_VALIDITY_MASK;
    
        if((isValidImg_1) && !(isValidImg_2)) /* first image is valid & 2nd image is not valid */
        {
            /* mark the verifStatus fields accordingly */
            if(isPresImg_2)
            {
    #ifdef BIM_ERASE_INVALID_IMAGE
                Bim_EraseOnchipFlashPages(IMAGE_2_START_FLASH_PAGE_NUM, IMAGE_2_END_FLASH_PAGE_NUM);
    #else
                Bim_updateVerifStatus(IMAGE_2_HDR_START_PAGE_NUM, VERIFY_FAIL);
    #endif
            }
            Bim_updateVerifStatus(IMAGE_1_HDR_START_PAGE_NUM, VERIFY_PASS_CURRENT);
            readFlashPg(IMAGE_1_HDR_START_PAGE_NUM, 0, (uint8_t *)&imgHdr_1, OAD_IMG_HDR_LEN);
            /* jump to the image */
            jumpToPrgEntry((uint32_t*)imgHdr_1.fixedHdr.prgEntry);
        }
        else if(!(isValidImg_1) && (isValidImg_2))
        {
            /* mark the verifStatus fields accordingly */
            if(isPresImg_1)
            {
    #ifdef BIM_ERASE_INVALID_IMAGE
                Bim_EraseOnchipFlashPages(IMAGE_1_START_FLASH_PAGE_NUM, IMAGE_1_END_FLASH_PAGE_NUM);
    #else
                Bim_updateVerifStatus(IMAGE_1_HDR_START_PAGE_NUM, VERIFY_FAIL);
    #endif
            }
            Bim_updateVerifStatus(IMAGE_2_HDR_START_PAGE_NUM, VERIFY_PASS_CURRENT);
            /* jump to the image */
            readFlashPg(IMAGE_2_HDR_START_PAGE_NUM, 0, (uint8_t *)&imgHdr_2, OAD_IMG_HDR_LEN);
            jumpToPrgEntry((uint32_t*)imgHdr_2.fixedHdr.prgEntry);
        }
        else if((isValidImg_1) && (isValidImg_2)) /* both the images are valid so far */
        {
            readFlashPg(IMAGE_1_HDR_START_PAGE_NUM, 0, (uint8_t *)&imgHdr_1, (OAD_IMG_HDR_LEN + sizeof(securityInfoSeg_t)));
            readFlashPg(IMAGE_2_HDR_START_PAGE_NUM, 0, (uint8_t *)&imgHdr_2, (OAD_IMG_HDR_LEN + sizeof(securityInfoSeg_t)));
    
            secVer_1 = imgHdr_1.secInfoSeg.secVer;
            secVer_2 = imgHdr_2.secInfoSeg.secVer;
    
            verifStat_1 = imgHdr_1.secInfoSeg.verifStat ;
            verifStat_2 = imgHdr_2.secInfoSeg.verifStat ;
    
            /* image 1 is new */
            if((DEFAULT_STATE == verifStat_1) && (DEFAULT_STATE != verifStat_2))
            {
                if(secVer_1 > secVer_2)
                {
    
    #ifdef BIM_ERASE_INVALID_IMAGE
                    Bim_EraseOnchipFlashPages(IMAGE_2_START_FLASH_PAGE_NUM, IMAGE_2_END_FLASH_PAGE_NUM);
    #else
                    Bim_updateVerifStatus(IMAGE_2_HDR_START_PAGE_NUM, VERIFY_FAIL);
    #endif
                    /* switch to new image */
                    Bim_updateVerifStatus(IMAGE_1_HDR_START_PAGE_NUM, VERIFY_PASS_CURRENT);
                    jumpToPrgEntry((uint32_t*)imgHdr_1.fixedHdr.prgEntry);
                }
                else if( secVer_1 < secVer_2)
                {
    #ifdef BIM_ERASE_INVALID_IMAGE
                    Bim_EraseOnchipFlashPages(IMAGE_1_START_FLASH_PAGE_NUM, IMAGE_1_END_FLASH_PAGE_NUM);
    #else
                    Bim_updateVerifStatus(IMAGE_1_HDR_START_PAGE_NUM, VERIFY_FAIL);
    #endif
                    /* Do not switch to new image */
                    Bim_updateVerifStatus(IMAGE_2_HDR_START_PAGE_NUM, VERIFY_PASS_CURRENT);
                    jumpToPrgEntry((uint32_t*)imgHdr_2.fixedHdr.prgEntry);
                }
                else /* same sec version */
                {
                    /* switch to new image */
                    Bim_updateVerifStatus(IMAGE_2_HDR_START_PAGE_NUM,  VERIFY_PASS_NOT_CURRENT);
                    Bim_updateVerifStatus(IMAGE_1_HDR_START_PAGE_NUM, VERIFY_PASS_CURRENT);
                    jumpToPrgEntry((uint32_t*)imgHdr_1.fixedHdr.prgEntry);
                }
            } /* end of if image 1 is new */
            /* image 2 is new */
            else if((DEFAULT_STATE != verifStat_1) && (DEFAULT_STATE == verifStat_2))
            {
                if(secVer_2 > secVer_1)
                {
    #ifdef BIM_ERASE_INVALID_IMAGE
                    Bim_EraseOnchipFlashPages(IMAGE_1_START_FLASH_PAGE_NUM, IMAGE_1_END_FLASH_PAGE_NUM);
    #else
                    Bim_updateVerifStatus(IMAGE_1_HDR_START_PAGE_NUM, VERIFY_FAIL);
    #endif
                    /* switch to new image */
                    Bim_updateVerifStatus(IMAGE_2_HDR_START_PAGE_NUM, VERIFY_PASS_CURRENT);
                    jumpToPrgEntry((uint32_t*)imgHdr_2.fixedHdr.prgEntry);
                }
                else if( secVer_2 < secVer_1)
                {
    #ifdef BIM_ERASE_INVALID_IMAGE
                    Bim_EraseOnchipFlashPages(IMAGE_2_START_FLASH_PAGE_NUM, IMAGE_2_END_FLASH_PAGE_NUM);
    #else
                    Bim_updateVerifStatus(IMAGE_2_HDR_START_PAGE_NUM, VERIFY_FAIL);
    #endif
                    /* Do not switch to new image */
                    Bim_updateVerifStatus(IMAGE_1_HDR_START_PAGE_NUM, VERIFY_PASS_CURRENT);
                    jumpToPrgEntry((uint32_t*)imgHdr_1.fixedHdr.prgEntry);
                }
                else /* same sec version */
                {
                    /* switch to new image */
                    Bim_updateVerifStatus(IMAGE_1_HDR_START_PAGE_NUM,  VERIFY_PASS_NOT_CURRENT);
                    Bim_updateVerifStatus(IMAGE_2_HDR_START_PAGE_NUM, VERIFY_PASS_CURRENT);
                    jumpToPrgEntry((uint32_t*)imgHdr_2.fixedHdr.prgEntry);
                }
            } /* end of if image 2 is new */
            /* neither of the images are new */
            else if((DEFAULT_STATE != verifStat_1) & (DEFAULT_STATE != verifStat_2))
            {
    #ifdef FEATURE_SWITCH_VALID_IMAGES
                /* pick the one with higher number of bits in imgVld field */
                if(imgHdr_1.fixedHdr.imgVld > imgHdr_2.fixedHdr.imgVld )
                {
                    /* no need to update the status fields */
                    /* jump to the image */
                    jumpToPrgEntry((uint32_t*)imgHdr_1.fixedHdr.prgEntry);
                }
                else if(imgHdr_1.fixedHdr.imgVld < imgHdr_2.fixedHdr.imgVld)
                {
                    /* no need to update the status fields */
                    /* jump to the image */
                    jumpToPrgEntry((uint32_t*)imgHdr_2.fixedHdr.prgEntry);
                }
                else /*both are equal*/
    #endif
                {
                    /* boot into image that has been marked as the current image previously */
                    if((VERIFY_PASS_CURRENT == imgHdr_1.secInfoSeg.verifStat) &&
                       (VERIFY_PASS_NOT_CURRENT == imgHdr_2.secInfoSeg.verifStat))
                    {
                        jumpToPrgEntry((uint32_t*)imgHdr_1.fixedHdr.prgEntry);
                    }
                    else if((VERIFY_PASS_CURRENT == imgHdr_2.secInfoSeg.verifStat) &&
                            (VERIFY_PASS_NOT_CURRENT == imgHdr_1.secInfoSeg.verifStat))
                    {
                        jumpToPrgEntry((uint32_t*)imgHdr_2.fixedHdr.prgEntry);
                    }
                    /* else: any other case: something is wrong */
                }
    
            } /* if neither of the images are new */
    
        } /* both the images are valid */
    
    } /* end of function Bim_UpdateExecValidImg */
    
    
    #endif // BIM_DUAL_ONCHIP_IMAGE
    
    
    
    /*******************************************************************************
     * @fn          main
     *
     * @brief       C-code main function.
     *
     * input parameters
     *
     * None.
     *
     * output parameters
     *
     * None.
     *
     * @return      None.
     */
    int main(void)
    {
    #ifdef __IAR_SYSTEMS_ICC__
      __set_CONTROL(0);
    #endif
    
    #ifndef DEBUG_BIM
        /* Read and populate the static variable intFlashPageSize */
        intFlashPageSize = FlashSectorSizeGet();
    #endif
        uint8_t imgType;
        uint8_t flashPgNum;
    
    #ifndef BIM_DUAL_ONCHIP_IMAGE
         /* First look for an application image*/
        imgType = OAD_IMG_TYPE_APPSTACKLIB;
    #ifdef APP_HDR_LOC
        flashPgNum = APP_HDR_ADDR/ intFlashPageSize;
    #else
        flashPgNum = 0x00;
    #endif
    
        Bim_findImage(flashPgNum, imgType);
    
        /* If the application image isn't found, look for a persistent image */
        imgType = OAD_IMG_TYPE_PERSISTENT_APP;
    #ifdef PERSIST_HDR_LOC
        flashPgNum = PERSIST_HDR_ADDR / intFlashPageSize;
    
        Bim_findImage(flashPgNum, imgType);
    #else
        flashPgNum++;
    
        while(flashPgNum < MAX_ONCHIP_FLASH_PAGES)
        {
            Bim_findImage(flashPgNum, imgType);
            flashPgNum++;
        }
    #endif
    #else // BIM_DUAL_ONCHIP_IMAGE
    
        /* Check if image is present in slot 1, if yes, do checks on it */
        imgType = OAD_IMG_TYPE_APPSTACKLIB;
        flashPgNum = IMAGE_1_HDR_START_PAGE_NUM;
        Bim_findImage(flashPgNum, imgType);
    
        /* Check if image is present in slot 2, if yes, do checks on it */
        flashPgNum = IMAGE_2_HDR_START_PAGE_NUM;
        Bim_findImage(flashPgNum, imgType);
    
        /* once here, do checks on which image to boot to & boot into it */
        Bim_UpdateExecValidImg();
    #endif
    
        /* If we get here, that means there is an Issue: No valid image found */
    #if defined(DEBUG_BIM) || defined(BIM_BLINK_LED_NO_VALID_IMAGE)
    
        powerUpGpio();
        while(1)
        {
            lightRedLed();
        }
    
    #else /* ifdef DEBUG_BIM */
        /* Set the device to the lowest power state. Does not return. */
        setLowPowerMode();
    
        return(0);
    #endif
    
    } /* end of main function */
    
    /**************************************************************************************************
    */
    
     

    bim_util.c
    /******************************************************************************
    
     @file  bim_util.c
    
     @brief This module contains the definitions for the main functionality of a
            Boot  Image Manager.
    
     Group: CMCU
     $Target Device: DEVICES $
    
     ******************************************************************************
     $License: BSD3 2012 $
     ******************************************************************************
     $Release Name: PACKAGE NAME $
     $Release Date: PACKAGE RELEASE DATE $
     *****************************************************************************/
    
    /*******************************************************************************
     *                                          Includes
     */
    
    #include <ti/devices/DeviceFamily.h>
    #include DeviceFamily_constructPath(driverlib/sys_ctrl.h)
    #include DeviceFamily_constructPath(driverlib/aon_event.h)
    #include DeviceFamily_constructPath(driverlib/osc.h)
    #include DeviceFamily_constructPath(driverlib/setup.h)
    #include DeviceFamily_constructPath(driverlib/pwr_ctrl.h)
    
    #include "ti/common/cc26xx/oad/oad_image_header.h"
    #include "ti/common/cc26xx/crc/crc32.h"
    #include "ti/common/cc26xx/flash_interface/flash_interface.h"
    
    /*******************************************************************************
     * LOCAL VARIABLES
     */
    
    const uint8_t OAD_IMG_ID[OAD_IMG_ID_LEN] = OAD_IMG_ID_VAL;
    
    #ifndef BIM_ONCHIP /* used for off-chip case only */
    const uint8_t OAD_EXTFL_ID[OAD_IMG_ID_LEN] = OAD_EXTFL_ID_VAL;
    #endif //#ifdef BIM_ONCHIP
    
    /*******************************************************************************
     * LOCAL FUNCTIONS
     */
    
    /*******************************************************************************
     * @fn          jumpToPrgEntry
     *
     * @brief       This function jumps the execution to program entry to execute
     *              application
     *
     * @param       vectorTable - address of application vector table.
     *
     * @return      None.
     */
    
    void jumpToPrgEntry(uint32_t *vectorTable)
    {
        /* The following code resets the SP to the value specified in the
         * provided vector table, and then the Reset Handler is invoked.
         *
         * Per ARM Cortex specification:
         *
         *           ARM Cortex VTOR
         *
         *
         *   Offset             Vector
         *
         * 0x00000000  ++++++++++++++++++++++++++
         *             |    Initial SP value    |
         * 0x00000004  ++++++++++++++++++++++++++
         *             |         Reset          |
         * 0x00000008  ++++++++++++++++++++++++++
         *             |          NMI           |
         *             ++++++++++++++++++++++++++
         *             |           .            |
         *             |           .            |
         *             |           .            |
         *
         * */
    
        /* Reset the SP with the value stored at vector_table[0] */
        __asm volatile ("MSR msp, %0" : : "r" (vectorTable[0]) : );
    
        /* Jump to the Reset Handler address at vector_table[1] */
    
        ( (void (*)(void)) (*(vectorTable + 1)) )();
    }
    
    /*******************************************************************************
     * @fn          imgIDCheck
     *
     * @brief       This function check if the buffer contains OAD image
     *              identification value.
     *
     * @param       imgHdr - pointer to image identification header buffer.
     *
     * @return      None.
     */
    bool imgIDCheck(imgFixedHdr_t *imgHdr)
    {
        uint8_t* pBuff = imgHdr->imgID;
    
        int8_t idLen = OAD_IMG_ID_LEN - 1;
        while( idLen >= 0)
        {
            if (pBuff[idLen] != OAD_IMG_ID[idLen])
            {
                return(false);
            }
            idLen--;
        }
        return(true);
    }
    
    /*******************************************************************************
     * @fn     setLowPowerMode
     *
     * @brief  This function sets the device to the lowest power mode, and does not
     *         return.
     */
    void setLowPowerMode()
    {
        /* Disable interrupts */
        IntMasterDisable();
    
        /*  - Freeze the IOs on the boundary between MCU and AON
         *  - Make sure AON writes take effect
         *  - Request power off of every PD in the MCU voltage domain
         *  - Ensure that no clocks are forced on in Crypto, DMA and I2S
         *  - Gate running deep sleep clocks for Crypto, DMA and I2S
         *  - Load the new clock settings
         *  - Configure the VIMS power domain mode to power up flash
         *    again after coming out of standby.
         *  - Request uLDO during standby
         *  - Use recharge comparator
         *  - Ensure all writes have taken effect
         *  - Ensure UDMA, Crypto and I2C clocks are turned off
         *  - Ensure all non-CPU power domains are turned off
         *  - Turn off cache retention if requested
         *  - Invoke deep sleep to go to standby
         */
        SysCtrlStandby(false,
                       VIMS_ON_CPU_ON_MODE,
                       SYSCTRL_PREFERRED_RECHARGE_MODE);
    
        /* Should never return from SysCtrlStandby */
    }
    
    #ifndef BIM_ONCHIP /* used for off-chip case only */
    /*******************************************************************************
     * @fn          metadataIDCheck
     *
     * @brief       This function check if the buffer contains external flash OAD
     *              metadata identification value.
     *
     * @param       imgHdr - pointer to flash metadata header buffer.
     *
     * @return      None.
     */
    bool metadataIDCheck(imgFixedHdr_t *imgHdr)
    {
        uint8_t* pBuff = imgHdr->imgID;
    
        int8_t idLen = OAD_IMG_ID_LEN - 1;
        while( idLen >= 0)
        {
            if (pBuff[idLen] != OAD_EXTFL_ID[idLen])
            {
                return(false);
            }
            idLen--;
        }
        return(true);
    }
    
    #endif // #ifndef BIM_ONCHIP
    
    
    #ifdef BIM_ONCHIP /* used for on-chip case only */
    /*******************************************************************************
     * @fn     evenBitCount
     *
     * @brief  Finds if the value field has even number of bits set to 1's.
     *
     * @param  value  - input field on which to calculate the even number of 1's.
     *
     * @return True when the value field has even number of 1's, otherwise returns
     *         False.
     */
    bool evenBitCount(uint32_t value)
    {
      uint8_t count;
    
      for (count = 0; value; count++)
      {
        value &= value - 1;
      }
    
      if (count % 2)
      {
        return false;
      }
      else
      {
        return true;
      }
    }
    
    #endif //#ifdef BIM_ONCHIP
    
    /*******************************************************************************
    */
    

    Regards,
    Ryan

  • Thanks Ryan. We will test and get back to you with the result asap.

    BR,

    Randy

  • HI Ryan!

    I have did the changes but I still can't get OTA. 

    When the coordinator sends the Image Notify my device respond Image Notify: Unsupported cluster comand. 

    In the zcl.h command list I can't find anything similar. 

    Please, What should I do to resolve this?

    Thank very much!

    Best Regards.

  • You should rebase your test project since it appears that you've somehow inadvertently removed OTA functionality.  Your UI should be operational and have OTA information displayed.

    Regards,
    Ryan

  • Hi Ryan!

    Going back seems works!

    Best regards.

  • Hi Ryan!

    Going back seems works!

    The firmware transfer via OTA reaches 100%.
    But the new application never runs.

    I am trying with the changes to the bim file you suggested above, without the changes to the bim file you suggested (as described in the readme of zr_sw_ota_client_onchip_xxx). I always have the same result. It never runs the new app, even if I do a reset after finishing OTA, it always runs the original app.

    After completion, the firmware transfer via OTA is automatically executed again. I imagine that by not running the new application, it detects that there is still a valid update available. 

    Please, what could be happening?

    Best regards.

  • You will need to perform debugging, first on the zr_sw_ota_client_onchip to confirm that OAD_markSwitch invalidate the original image through crcStat and second on the bim_onchip to confirm that BIM_findImage locates the correct updated image based on the crcStat contents, or otherwise the processing of Bim_UpdateExecValidImg. 

    Regards,
    Ryan

  • Hi Ryan!

    The OTA issue is the only thing we have left to deal with.

    To remove any issues that may introduce my code or hardware I am testing with original TI firmware and launchpads.

    I am using SDK 7.10.

    I did the following tests:
    Test 1:
    CC1352P-2LP -> as coordinator ota server.
    CC1352P7-4LP -> as router ota client on chip
    Result: OTA transfer is done and reaches 100% but the firmware is never updated to the transferred image.
    Test 2:
    CC1352P-2LP -> as coordinator ota server.
    CC1352P7-4LP -> as router ota client off chip
    Result: The transfer starts and quickly you get an error (Download Failed ZOtaAbort).
    Test 3:
    CC1352P-2LP -> as coordinator ota server.
    CC1352P-2LP -> as router ota client off chip
    Result: OTA works perfectly.

    Why with CC1352P7 I can't get OTA working? Please, any ideas, suggestions, ....

  • Hi albgarc,

    I am not observing similar issues on the LP-CC1352P7-4 platform. Please install the latest SDK and confirm that you are erasing all Simplelink device memory before starting these tests.  Focus on the off-chip version (Test 2) to start and make sure to load the BIM consecutively with the application image using Uniflash.  The *.ota file should should be generated from a LP-CC1352P7-4 OTA example and include updated image version numbers.  After this is successful, confirm operation of the on-chip version next after applying the BIM changes provided in this thread.

    Regards,
    Ryan

  • Hi Ryan, 

    Thank you very much!

    A question, please

    I must do something to ensure that the BIM project is built with the Dual_Image option.

    Best reagrds

  • That is correct.  For on-chip BIM projects using Zigbee applications, the Dual_image Build Configuration must be set.  You will also need to replace bim_main and bim_util as described earlier in this thread.

    Regards,
    Ryan

  • Part Number: CC1352P7

    Hi Ryan!!!

    Thank you very much!

    I'm sorry but I closed the previous thread wrongly.

    In addition to updating the bim_main and bim_util files, should I do anything else with the Predefined Symbols (add or remove BIM_DUAL_ONCHIP_IMAGE, SECURITY, .... or something else)? 

    Thank you very much. Best Regards!

  • Hi albgarc,

    The previous thread is not closed and you can continue to reply to it. I will merge this thread accordingly.  Please set the active Build Configuration to Dual_image to automatically populate the correct Predefined Symbols.

    Regards,
    Ryan

  • HI Ryan! 

    Please, after set the Dual_image as Active I get the following errors. 

  • I am not observing the same. As the first expected a semicolon I imagine files were not altered correctly.  Please try again with a new project whose default you have already confirmed will build correctly.

    Regards,
    Ryan

  • Hi Ryan!

    SDK 7_10_00_98

    I load the BIM_ONCHIP project in CCS, it builds perfectly.
    Properties -> Manage Configuration -> Dual_image -> Set Active / Properties -> Configuration -> Dual_image

    Same as the image I showed you above. When I build I get the same errors as before.

  • Delete your project and try again, or explore the issues and resolve them.

    Regards,
    Ryan

  • Hi Ryan!!!

    We have OTA on chip working!!!

    Sincerely thank you very much!!!

    Best Regards.