/******************************************************************************* * @fn SensorTag_saveFactoryImage * * @brief Save the current image to external flash as a factory image * * @return none */ static bool SensorTag_saveFactoryImage(void) { bool success; success = extFlashOpen(); if (success) { uint32_t address; // Erase external flash for (address= 0; address<EFL_FLASH_SIZE; address+=EFL_PAGE_SIZE) { extFlashErase(address,EFL_PAGE_SIZE); } // Install factory image for (address=0; address<EFL_SIZE_RECOVERY && success; address+=EFL_PAGE_SIZE) { success = extFlashErase(EFL_ADDR_RECOVERY+address, EFL_PAGE_SIZE); if (success) { size_t offset; static uint8_t buf[256]; // RAM storage needed due to SPI/DMA limitation for (offset=0; offset<EFL_PAGE_SIZE; offset+=sizeof(buf)) { const uint8_t *pIntFlash; // Copy from internal to external flash pIntFlash = (const uint8_t*)address + offset; memcpy(buf,pIntFlash,sizeof(buf)); success = extFlashWrite(EFL_ADDR_RECOVERY+address+offset, sizeof(buf), buf); // Verify first few bytes if (success) { extFlashRead(EFL_ADDR_RECOVERY+address+offset, sizeof(buf), buf); success = buf[2] == pIntFlash[2] && buf[3] == pIntFlash[3]; } } } } extFlashClose(); } return success; }
/******************************************************************************* * @fn saveImageInfo * * @brief Save image information in the meta-data area * * @return none */ void saveImageInfo(void) { uint32_t addr; if (imgInfo.imgType == EFL_OAD_IMG_TYPE_APP) { addr = EFL_IMAGE_INFO_ADDR_APP; } else { addr = EFL_IMAGE_INFO_ADDR_BLE; } // Erase old meta data. extFlashErase(addr, HAL_FLASH_PAGE_SIZE); // Set status so that bootloader pull in the new image. imgInfo.status = 0xFF; // Write new meta data. extFlashWrite(addr, sizeof(ExtImageInfo_t), (uint8_t*)&imgInfo); }
/********************************************************************* * @fn OADTarget_imgBlockWrite * * @brief Process the Image Block Write. * * @param connHandle - connection message was received on * @param pValue - pointer to data to be written * * @return status */ bStatus_t OADTarget_imgBlockWrite(uint16_t connHandle, uint8_t *pValue) { volatile uint16_t blkNum; blkNum = BUILD_UINT16(pValue[0], pValue[1]); // First block of OAD which included image header and CRC and CRC shadow // values. Do a sanity check on the received image header if (blkNum == 0) { img_hdr_t ImgHdr; uint16_t blkTot; blkTot = BUILD_UINT16(pValue[8], pValue[9]) / (OAD_BLOCK_SIZE / HAL_FLASH_WORD_SIZE); // Read out running image's header. uint8_t *flashAddr = (uint8_t *)(APP_IMAGE_START + OAD_IMG_HDR_OSET); memcpy(&ImgHdr,flashAddr,sizeof(img_hdr_t)); // Note: if additional customer criteria was checked in the Image // Identification step, it may be important to check again here. if ((oadBlkNum != blkNum) || (oadBlkTot != blkTot) ) { // Cancel download OADTarget_rejectImage(connHandle, &ImgHdr); // NB! This is meaningless for a WriteNoResp operation return (ATT_ERR_WRITE_NOT_PERMITTED); } #ifdef POWER_SAVING Power_setConstraint(Power_SB_DISALLOW); #endif } // Check that this is the expected block number. if (oadBlkNum == blkNum && flashOk) { uint32_t addr; // Calculate address to write as (start of OAD range) + (offset) addr = APP_IMAGE_START + oadBlkNum * OAD_BLOCK_SIZE; // If address starts a new page, erase that page first. if ((addr % HAL_FLASH_PAGE_SIZE) == 0) { flashOk = extFlashErase(addr, HAL_FLASH_PAGE_SIZE); } // Write a 16 byte block to Flash. if (flashOk) { flashOk = extFlashWrite(addr, OAD_BLOCK_SIZE, pValue+2); // Increment received block count. if (flashOk) oadBlkNum++; } // Toggle Green LED for every 8th block if ( (oadBlkNum % 8) == 0) { GPIO_toggle(Board_LED2); } } else { img_hdr_t ImgHdr; // Toggle RED LED and sound buzzer when overflow GPIO_toggle(Board_LED1); GPIO_toggle(Board_BUZZER); #ifdef POWER_SAVING Power_releaseConstraint(Power_SB_DISALLOW); #endif // Cancel download ImgHdr.len = 0; // Don't care content OADTarget_rejectImage(connHandle, &ImgHdr); } // Check if the OAD Image is complete. if (oadBlkNum == oadBlkTot) { extFlashClose(); // Run CRC check on new image. if (checkDL()) { HAL_SYSTEM_RESET(); } else { GPIO_toggle(Board_LED1); } #ifdef POWER_SAVING Power_releaseConstraint(Power_SB_DISALLOW); #endif } else { // Request the next OAD Image block. OADTarget_getNextBlockReq(connHandle, oadBlkNum); } return (SUCCESS); }
/********************************************************************* * @fn OADTarget_eraseFlash * * @brief Erase selected flash page. * * @param page - the page to erase. * * @return None. */ void OADTarget_eraseFlash(uint8_t page) { extFlashErase(FLASH_ADDRESS(page,0), HAL_FLASH_PAGE_SIZE); }