/************************************************************************************************** * @fn sbImgValid * * @brief Check validity of the run-code image. * * input parameters * * None. * * output parameters * * None. * * @return TRUE or FALSE for image valid. ************************************************************************************************** */ uint8 sbImgValid(void) { uint16 crc[2]; HalFlashRead(HAL_SB_CRC_ADDR / HAL_FLASH_PAGE_SIZE, HAL_SB_CRC_ADDR % HAL_FLASH_PAGE_SIZE, (uint8 *)crc, sizeof(crc)); if ((crc[0] == 0xFFFF) || (crc[0] == 0x0000)) { return FALSE; } if (crc[0] != crc[1]) { crc[1] = calcCRC(); HalFlashWrite((HAL_SB_CRC_ADDR / HAL_FLASH_WORD_SIZE), (uint8 *)crc, 1); HalFlashRead( HAL_SB_CRC_ADDR / HAL_FLASH_PAGE_SIZE, HAL_SB_CRC_ADDR % HAL_FLASH_PAGE_SIZE, (uint8 *)crc, sizeof(crc)); } return ((crc[0] == crc[1]) && (crc[0] != 0xFFFF) && (crc[0] != 0x0000)); }
/********************************************************************* * @fn Onboard_soft_reset * * @brief Effect a soft reset. * * @param none * * @return none * *********************************************************************/ __near_func void Onboard_soft_reset( void ) { #if (defined MAKE_CRC_SHDW) || (defined FAKE_CRC_SHDW) // If built for bootloader // If bootloader code exists - need to tell the bootloader that this is a soft reset, // so it should not do anything, and just pass the control to the main app immediately uint16 sblCmdAddr; uint32 sblSig; HalFlashRead(SBL_SIG_ADDR / HAL_FLASH_PAGE_SIZE, SBL_SIG_ADDR % HAL_FLASH_PAGE_SIZE, (uint8 *)&sblSig, sizeof(sblSig)); if (sblSig == SBL_SIGNATURE) { HalFlashRead(SBL_CMD_ADDR / HAL_FLASH_PAGE_SIZE, SBL_CMD_ADDR % HAL_FLASH_PAGE_SIZE, (uint8 *)&sblCmdAddr, sizeof(sblCmdAddr)); if (sblCmdAddr != 0xFFFF) { *(uint32 *)sblCmdAddr = MAIN_APP_CMD_PASS_THROUGH; } } #endif HAL_DISABLE_INTERRUPTS(); // Abort all DMA channels to insure that ongoing operations do not // interfere with re-configuration. DMAARM = 0x80 | 0x1F; asm("LJMP 0x0"); }
/************************************************************************************************** * @fn checkDL * * @brief Check validity of the downloaded image. * * input parameters * * None. * * output parameters * * None. * * @return TRUE or FALSE for image valid. ************************************************************************************************** */ static uint8 checkDL(void) { uint16 crc[2]; HalFlashRead(OAD_IMG_D_PAGE, OAD_IMG_CRC_OSET, (uint8 *)crc, sizeof(crc)); if ((crc[0] == 0xFFFF) || (crc[0] == 0x0000)) { return FALSE; } if (crc[1] == 0xFFFF) { //P0DIR |= 1; //P0_0 = 0; //P0_0 = 1; //P0_0 = 0; //P0_0 = 1; //P0_0 = 0; //P0_0 = 1; crc[1] = crcCalcDLDMA(); //P0_0 = 0; #if defined FEATURE_OAD_BIM // If download image is made to run in-place, enable it here. uint16 addr = OAD_IMG_D_PAGE * OAD_FLASH_PAGE_MULT + OAD_IMG_CRC_OSET / HAL_FLASH_WORD_SIZE; crc[0] = 0xFFFF; HalFlashWrite(addr, (uint8 *)crc, 1); HalFlashRead(OAD_IMG_D_PAGE, OAD_IMG_CRC_OSET, (uint8 *)crc, sizeof(crc)); #endif } return (crc[0] == crc[1]); }
/************************************************************************************************** * @fn crcCalc * * @brief Run the CRC16 Polynomial calculation over the image specified. * * input parameters * * @param page - Flash page on which to beging the CRC calculation. * * output parameters * * None. * * @return The CRC16 calculated. ************************************************************************************************** */ static uint16 crcCalc(uint8 page) { HalFlashRead(page, 0, pgBuf, HAL_FLASH_PAGE_SIZE); const img_hdr_t *pImgHdr = (const img_hdr_t *)(pgBuf + BIM_HDR_OSET); uint8 pageBeg = page; uint8 pageEnd = pImgHdr->len / (HAL_FLASH_PAGE_SIZE / HAL_FLASH_WORD_SIZE); uint16 osetEnd = (pImgHdr->len - (pageEnd * (HAL_FLASH_PAGE_SIZE / HAL_FLASH_WORD_SIZE))) * HAL_FLASH_WORD_SIZE; pageEnd += pageBeg; if (pageBeg == BIM_IMG_A_PAGE) { pageEnd += BIM_IMG_B_AREA; } ADCCON1 &= 0xF3; // CRC configuration of LRSR. // CRC seed of 0x0000. RNDL = 0x00; RNDL = 0x00; while(1) { for (uint16 oset = 0; oset < HAL_FLASH_PAGE_SIZE; oset++) { if ((page == pageBeg) && (oset == BIM_CRC_OSET)) { oset += 3; // Skip the CRC and shadow. } else if ((page == pageEnd) && (oset == osetEnd)) { uint16 crc = RNDH; crc = (crc << 8) | RNDL; return crc; } else { RNDH = pgBuf[oset]; } } if (++page == BIM_IMG_B_PAGE) { page += BIM_IMG_B_AREA; } HalFlashRead(page, 0, pgBuf, HAL_FLASH_PAGE_SIZE); } }
uint8_t persistent_pwrmgmt_get_latest(struct pwrmgmt_data *pwr_ptr) { uint8_t count; uint32_t pwr_idx_bits, u32; u32 = (uint32)&(((struct persistent_page *)0)->pwr_idx_bits[0]); HalFlashRead(pidx, (uint16_t)u32, (uint8_t *)&pwr_idx_bits, 4); count = __persistent_get_idx_from_bit_map((uint8_t *)&pwr_idx_bits, 4); if (count == 0 || count > PERSISTENT_PWR_MAX) { return FAIL; } u32 = (uint32)&(((struct persistent_page *)0)->pwr_log[count - 1]); HalFlashRead(pidx, (uint16_t)u32, (uint8_t *)pwr_ptr, sizeof(struct pwrmgmt_data)); return SUCCESS; }
/********************************************************************* * @fn oadImgIdentifyWrite * * @brief Process the Image Identify Write. * * @param connHandle - connection message was received on * @param pValue - pointer to data to be written * * @return status */ static bStatus_t oadImgIdentifyWrite( uint16 connHandle, uint8 *pValue ) { img_hdr_t rxHdr; img_hdr_t ImgHdr; rxHdr.ver = BUILD_UINT16( pValue[0], pValue[1] ); rxHdr.len = BUILD_UINT16( pValue[2], pValue[3] ); (void)osal_memcpy(rxHdr.uid, pValue+4, sizeof(rxHdr.uid)); HalFlashRead(OAD_IMG_R_PAGE, OAD_IMG_HDR_OSET, (uint8 *)&ImgHdr, sizeof(img_hdr_t)); oadBlkTot = rxHdr.len / (OAD_BLOCK_SIZE / HAL_FLASH_WORD_SIZE); if ( (OAD_IMG_ID( ImgHdr.ver ) != OAD_IMG_ID( rxHdr.ver )) && // TBD: add customer criteria for initiating OAD here. (oadBlkTot <= OAD_BLOCK_MAX) && (oadBlkTot != 0) ) { oadBlkNum = 0; oadImgBlockReq(connHandle, 0); } else { oadImgIdentifyReq(connHandle, &ImgHdr); } return ( SUCCESS ); }
/********************************************************************* * @fn oadManagerSendImgNotify * * @brief OAD device discovery. * * @return none */ static void oadManagerSendImgNotify(void) { attWriteReq_t req; img_hdr_t ImgHdr; HalFlashRead(OAD_IMG_B_PAGE, OAD_IMG_HDR_OSET, (uint8 *)&ImgHdr, sizeof(img_hdr_t)); req.handle = oadManagerHandles[OAD_CHAR_IMG_IDENTIFY]; req.len = OAD_IMG_HDR_SIZE; req.value[0] = LO_UINT16(ImgHdr.ver); req.value[1] = HI_UINT16(ImgHdr.ver); req.value[2] = LO_UINT16(ImgHdr.len); req.value[3] = HI_UINT16(ImgHdr.len); (void)osal_memcpy(req.value+4, ImgHdr.uid, sizeof(ImgHdr.uid)); req.sig = FALSE; req.cmd = TRUE; VOID GATT_WriteNoRsp(oadManagerConnHandle, &req); // Save the total number of blocks oadBlkTot = ImgHdr.len / (OAD_BLOCK_SIZE / HAL_FLASH_WORD_SIZE); }
/************************************************************************************************** * @fn imgAuth * * @brief Run the AES CTR decryption over the image area specified. * @brief Run the AES CRC-MAC calculation over the image specified and set the image * ready-to-run if the Signature is verified. * * input parameters * * @param imgSel - Image select: 0 for Image-A and 1 for Image-B. * @param imgHdr - Pointer to the Image Header corresponding to the image select. * * output parameters * * None. * * @return TRUE if the image Signature verifies; FALSE otherwise. */ static uint8 imgAuth(uint8 imgSel, img_hdr_t *imgHdr) { if ((imgHdr->crc0 == 0) || (imgHdr->crc0 == 0xFFFF)) { return FALSE; } if (imgHdr->crc0 != imgHdr->crc1) { aesLoadKey(); aes_hdr_t aesHdr; HalFlashRead(ImgPageBeg[imgSel], BEM_AES_OSET, (uint8 *)&aesHdr, sizeof(aes_hdr_t)); // Image length in 3 bytes, MSB to LSB order - the Signature bytes are not to be included. uint32 imageLen = (uint32)HAL_FLASH_PAGE_SIZE * imgHdr->res[0] - KEY_BLENGTH; aesHdr.spare[0] = ((uint8 *)&imageLen)[0]; aesHdr.spare[1] = ((uint8 *)&imageLen)[1]; aesHdr.spare[2] = ((uint8 *)&imageLen)[2]; aesHdr.spare[3] = imgHdr->res[0]; if (aesSignature(imgSel, &aesHdr)) { uint16 crc[2] = { 0xFFFF, imgHdr->crc0 }; BEM_NVM_SET(ImgPageBeg[imgSel], (uint8 *)crc, 4); BEM_NVM_GET(ImgPageBeg[imgSel], (uint8 *)&imgHdr, 4); } } return (imgHdr->crc0 == imgHdr->crc1); }
void main(void) { HAL_BOARD_INIT(); #if HAL_OTA_XNV_IS_SPI XNV_SPI_INIT(); #endif /* This is in place of calling HalDmaInit() which would require init of the * other 4 DMA descriptors in addition to just Channel 0. */ HAL_DMA_SET_ADDR_DESC0( &dmaCh0 ); while (1) { HalFlashRead(HAL_OTA_CRC_ADDR / HAL_FLASH_PAGE_SIZE, HAL_OTA_CRC_ADDR % HAL_FLASH_PAGE_SIZE, (uint8 *)&OTA_crcControl, sizeof(OTA_crcControl)); if (OTA_crcControl.crc[0] == OTA_crcControl.crc[1]) { break; } else if ((OTA_crcControl.crc[0] != 0) && (OTA_crcControl.crc[0] == crcCalc())) { OTA_crcControl.crc[1] = OTA_crcControl.crc[0]; HalFlashWrite((HAL_OTA_CRC_ADDR / HAL_FLASH_WORD_SIZE), (uint8 *)OTA_crcControl.crc, 1); } else { dl2rc(); } } // Simulate a reset for the Application code by an absolute jump to location 0x0800. asm("LJMP 0x800\n"); }
/********************************************************************* * @fn erasePage * * @brief Erases a page in Flash. * * @param pg - Valid NV page to erase. * * @return none */ static void erasePage( uint8 pg ) { if ( !OSAL_NV_CHECK_BUS_VOLTAGE || failF) { failF = TRUE; return; } HalFlashErase(pg); { // Verify the erase operation uint16 offset; uint8 tmp; for (offset = 0; offset < OSAL_NV_PAGE_SIZE; offset ++) { HalFlashRead(pg, offset, &tmp, 1); if (tmp != OSAL_NV_ERASED) { failF = TRUE; break; } } } }
// Max length of device name: 20 (excluding tailing null) // This function prepare contents for the backup page void persistent_flash_backup_prepare(uint16_t offset, uint8_t *buf, uint16_t len) { uint32_t buf32[64]; uint8_t i, j; HalFlashErase(pidx + 1); for (i = 0; i < 4; i++) { HalFlashRead(pidx, i * 256, (uint8_t *)buf32, 256); if (i == 0) { buf32[0] = 0xFFFFADDE; } // Cleanup old power mgmt data if (offset == 520) { if (i == 2) { for (j = 2; j < 64; j++) { buf32[j] = 0xFFFFFFFF; } } else if (i == 3) { for (j = 0; j < 64; j++) { buf32[j] = 0xFFFFFFFF; } } } if ((offset / 256) == (uint16_t)i) { memcpy((((uint8_t *)buf32) + (uint32_t)(offset % 256)), buf, len); } HalFlashWrite((pidx + 1), i * 256, (uint8_t *)buf32, 256); } buf32[0] = 0xEFBEADDE; HalFlashWrite((pidx + 1), 0, (uint8_t *)buf32, 4); }
/************************************************************************************************** * @fn calcCRC * * @brief Run the CRC16 Polynomial calculation over the RC image. * * input parameters * * None. * * output parameters * * None. * * @return The CRC16 calculated. ************************************************************************************************** */ static uint16 calcCRC(void) { uint32 addr; uint16 crc = 0; // Run the CRC calculation over the active body of code. for (addr = HAL_SB_IMG_ADDR; addr < HAL_SB_IMG_ADDR + HAL_SB_IMG_SIZE; addr++) { if (addr == HAL_SB_CRC_ADDR) { addr += 3; } else { uint8 buf; HalFlashRead(addr / HAL_FLASH_PAGE_SIZE, addr % HAL_FLASH_PAGE_SIZE, &buf, 1); crc = runPoly(crc, buf); } } // IAR note explains that poly must be run with value zero for each byte of crc. crc = runPoly(crc, 0); crc = runPoly(crc, 0); return crc; }
void persistent_init(void) { uint8_t i, j; uint8_t buf[16], buf2[4]; uint32_t magic32 = 0xEFBEADDE; // reverse DEADBEEF uint32_t ido2Name1 = 0x326F4469; // reverse iDo2 uint32_t ido2Name2 = 0x00000000; // string end uint32_t tmp32; uint32_t buf32[64]; __debug_sizeof_persistent_page = sizeof(struct persistent_page); pidx = (uint8_t)PERSISTENT_PAGE_IDX; HalFlashRead(pidx, 0, buf, 4); HalFlashRead((pidx + 1), 0, buf2, 4); if (memcmp(buf2, PERSISTENT_MAGIC, 4) == 0) { if (memcmp(buf, PERSISTENT_MAGIC, 4) != 0) { ble_flash_page_erase(pidx); for (i = 0; i < 4; i++) { HalFlashRead((pidx + 1), (uint16_t)i * 256, (uint8_t *)buf32, 256); for (j = 0; j < 64; j++) { flash_word_unprotected_write((uint32_t *)((uint32_t)pidx * 1024 + (uint32_t)i * 256 + (uint32_t)j * 4), buf32[j]); } } } ble_flash_page_erase(pidx + 1); } else { if (memcmp(buf, PERSISTENT_MAGIC, 4) != 0) { // This is invoked before softdevice and radio ble_flash_page_erase(pidx); flash_word_unprotected_write((uint32_t *)((uint32_t)pidx * 1024), magic32); flash_word_unprotected_write((uint32_t *)((uint32_t)pidx * 1024 + 4), ido2Name1); flash_word_unprotected_write((uint32_t *)((uint32_t)pidx * 1024 + 8), ido2Name2); } } // Update boot count HalFlashRead(pidx, 24, buf, 16); boot_cnt = __persistent_mark_bit_map(buf, 16); // Write back for (i = 0; i < 4; i++) { tmp32 = ((uint32_t)buf[i * 4 + 3] << 24) | ((uint32_t)buf[i * 4 + 2] << 16) | ((uint32_t)buf[i * 4 + 1] << 8) | (uint32_t)buf[i * 4]; flash_word_unprotected_write((uint32_t *)((uint32_t)pidx * 1024 + 24 + i * 4), tmp32); } }
/************************************************************************************************** * @fn main * * @brief C-code main function. * * input parameters * * None. * * output parameters * * None. * * @return None. ************************************************************************************************** */ void main(void) { uint16 crc[2]; // Prefer to run Image-B over Image-A so that Image-A does not have to invalidate itself. HalFlashRead(BIM_IMG_B_PAGE, BIM_CRC_OSET, (uint8 *)crc, 4); if ((crc[0] != 0xFFFF) && (crc[0] != 0x0000)) { if (crc[0] == crc[1]) { JumpToImageAorB = 1; // Simulate a reset for the Application code by an absolute jump to the expected INTVEC addr. asm("LJMP 0x4030"); HAL_SYSTEM_RESET(); // Should not get here. } /* This check is disruptive when an OAD process to Image-A is interrupted - this check must * complete before the still good Image-A is run. else if (crc[1] == 0xFFFF) // If first run of an image that was physically downloaded.*/ { crcCheck(BIM_IMG_B_PAGE, crc); } /**/ } HalFlashRead(BIM_IMG_A_PAGE, BIM_CRC_OSET, (uint8 *)crc, 4); if ((crc[0] != 0xFFFF) && (crc[0] != 0x0000)) { if (crc[0] == crc[1]) { JumpToImageAorB = 0; // Simulate a reset for the Application code by an absolute jump to the expected INTVEC addr. asm("LJMP 0x0830"); HAL_SYSTEM_RESET(); // Should not get here. } else if (crc[1] == 0xFFFF) // If first run of an image that was physically downloaded. { crcCheck(BIM_IMG_A_PAGE, crc); } } SLEEPCMD |= 0x03; // PM3, All clock oscillators off, voltage regulator off. halSleepExec(); HAL_SYSTEM_RESET(); // Should not get here. }
/********************************************************************* * @fn setChk * * @brief Set the item header checksum given the data buffer offset. * * @param pg - Valid NV page. * @param offset - Valid offset into the page of the item data - the header * offset is calculated from this. * @param chk - The checksum to set. * * @return The checksum read back. */ static uint16 setChk( uint8 pg, uint16 offset, uint16 chk ) { offset -= OSAL_NV_WORD_SIZE; writeWordH( pg, offset, (uint8 *)&chk ); HalFlashRead( pg, offset, (uint8 *)(&chk), sizeof( chk ) ); return chk; }
/********************************************************************* * @fn xferBuf * * @brief Xfers an NV buffer from one location to another, enforcing OSAL_NV_WORD_SIZE writes. * * @return none */ static void xferBuf( uint8 srcPg, uint16 srcOff, uint8 dstPg, uint16 dstOff, uint16 len ) { uint8 rem = dstOff % OSAL_NV_WORD_SIZE; uint8 tmp[OSAL_NV_WORD_SIZE]; if ( rem ) { dstOff -= rem; HalFlashRead(dstPg, dstOff, tmp, OSAL_NV_WORD_SIZE); while ( (rem < OSAL_NV_WORD_SIZE) && len ) { HalFlashRead(srcPg, srcOff, tmp+rem, 1); srcOff++; rem++; len--; } writeWord( dstPg, dstOff, tmp ); dstOff += OSAL_NV_WORD_SIZE; } rem = len % OSAL_NV_WORD_SIZE; len /= OSAL_NV_WORD_SIZE; while ( len-- ) { HalFlashRead(srcPg, srcOff, tmp, OSAL_NV_WORD_SIZE); srcOff += OSAL_NV_WORD_SIZE; writeWord( dstPg, dstOff, tmp ); dstOff += OSAL_NV_WORD_SIZE; } if ( rem ) { uint8 idx = 0; HalFlashRead(dstPg, dstOff, tmp, OSAL_NV_WORD_SIZE); while ( rem-- ) { HalFlashRead(srcPg, srcOff, tmp+idx, 1); srcOff++; idx++; } writeWord( dstPg, dstOff, tmp ); } }
/********************************************************************* * @fn oadManagerHandleNoti * * @brief Handle Notifications and Indications. * * @return none */ static void oadManagerHandleNoti(attHandleValueNoti_t *pNoti) { if (pNoti->handle == oadManagerHandles[OAD_CHAR_IMG_IDENTIFY]) { #if (defined HAL_LCD && (HAL_LCD == TRUE)) uint16 ver = BUILD_UINT16(pNoti->value[0], pNoti->value[1]); uint8 userId[12] = "UserId "; osal_memcpy(&(userId[7]), &(pNoti->value[4]), 4); userId[11] = '\0'; if ( OAD_IMG_ID( ver ) == 0 ) { HalLcdWriteStringValueValue("ImgA Id", OAD_VER_NUM( ver ), 16, BUILD_UINT16(pNoti->value[2], pNoti->value[3]), 16, HAL_LCD_LINE_2); } else { HalLcdWriteStringValueValue("ImgB Id", OAD_VER_NUM( ver ), 16, BUILD_UINT16(pNoti->value[2], pNoti->value[3]), 16, HAL_LCD_LINE_2); } HalLcdWriteString((char*)userId, HAL_LCD_LINE_3); #endif } else if (pNoti->handle == oadManagerHandles[OAD_CHAR_IMG_BLOCK]) { oadBlkNum = BUILD_UINT16(pNoti->value[0], pNoti->value[1]); attWriteReq_t req; req.handle = oadManagerHandles[OAD_CHAR_IMG_BLOCK]; req.len = 2 + OAD_BLOCK_SIZE; req.sig = FALSE; req.cmd = TRUE; req.value[0] = LO_UINT16(oadBlkNum); req.value[1] = HI_UINT16(oadBlkNum); uint8 page = oadBlkNum / OAD_BLOCKS_PER_PAGE; uint16 oset = (oadBlkNum - (OAD_BLOCKS_PER_PAGE * page)) * OAD_BLOCK_SIZE; HalFlashRead(page+OAD_IMG_B_PAGE, oset, req.value+2, OAD_BLOCK_SIZE); #if (defined HAL_LCD) && (HAL_LCD == TRUE) if (oadBlkNum == 0) { HalLcdWriteString("", HAL_LCD_LINE_3); } HalLcdDisplayPercentBar( "OAD Progress...", (oadBlkNum / (oadBlkTot / 100)) ); #endif VOID GATT_WriteNoRsp(oadManagerConnHandle, &req); VOID osal_start_timerEx( oadManagerTaskId, OAD_DOWNLOAD_EVT, OAD_DOWNLOAD_TIMEOUT ); } }
/********************************************************************* * @fn writeItem * * @brief Writes an item header/data combo to the specified NV page. * * @param pg - Valid NV Flash page. * @param id - Valid NV item Id. * @param len - Byte count of the data to write. * @param buf - The data to write. If NULL, no data/checksum write. * @param flag - TRUE if the checksum should be written, FALSE otherwise. * * @return TRUE if header/data to write matches header/data read back, else FALSE. */ static uint8 writeItem( uint8 pg, uint16 id, uint16 len, void *buf, uint8 flag ) { uint16 offset = pgOff[pg-OSAL_NV_PAGE_BEG]; uint8 rtrn = FALSE; osalNvHdr_t hdr; hdr.id = id; hdr.len = len; writeWord( pg, offset, (uint8 *)&hdr ); HalFlashRead(pg, offset, (uint8 *)(&hdr), OSAL_NV_HDR_SIZE); if ( (hdr.id == id) && (hdr.len == len) ) { if ( flag ) { hdr.chk = calcChkB( len, buf ); offset += OSAL_NV_HDR_SIZE; if ( buf != NULL ) { writeBuf( pg, offset, len, buf ); } if ( hdr.chk == calcChkF( pg, offset, len ) ) { if ( hdr.chk == setChk( pg, offset, hdr.chk ) ) { hotItemUpdate(pg, offset, hdr.id); rtrn = TRUE; } } } else { rtrn = TRUE; } len = OSAL_NV_ITEM_SIZE( hdr.len ); } else { len = OSAL_NV_ITEM_SIZE( hdr.len ); if (len > (OSAL_NV_PAGE_SIZE - pgOff[pg - OSAL_NV_PAGE_BEG])) { len = (OSAL_NV_PAGE_SIZE - pgOff[pg - OSAL_NV_PAGE_BEG]); } pgLost[pg - OSAL_NV_PAGE_BEG] += len; } pgOff[pg - OSAL_NV_PAGE_BEG] += len; return rtrn; }
// Caller provide dev name buffer, at least 21 bytes void persistent_get_dev_name(uint8_t *buf) { uint8_t buf_flash[20]; uint8_t idx; HalFlashRead(pidx, 4, buf_flash, 20); for (idx = 0; idx < 20; idx++) { buf[idx] = buf_flash[idx]; } buf[idx] = 0; }
/********************************************************************* * @fn writeBuf * * @brief Writes a data buffer to NV. * * @param dstPg - A valid NV Flash page. * @param offset - A valid offset into the page. * @param len - Byte count of the data to write. * @param buf - The data to write. * * @return TRUE if data buf checksum matches read back checksum, else FALSE. */ static void writeBuf( uint8 dstPg, uint16 dstOff, uint16 len, uint8 *buf ) { uint8 rem = dstOff % OSAL_NV_WORD_SIZE; uint8 tmp[OSAL_NV_WORD_SIZE]; if ( rem ) { dstOff = (dstOff / OSAL_NV_WORD_SIZE) * OSAL_NV_WORD_SIZE; HalFlashRead(dstPg, dstOff, tmp, OSAL_NV_WORD_SIZE); while ( (rem < OSAL_NV_WORD_SIZE) && len ) { tmp[rem++] = *buf++; len--; } writeWord( dstPg, dstOff, tmp ); dstOff += OSAL_NV_WORD_SIZE; } rem = len % OSAL_NV_WORD_SIZE; len /= OSAL_NV_WORD_SIZE; if ( len ) { writeWordM( dstPg, dstOff, buf, len ); dstOff += OSAL_NV_WORD_SIZE * len; buf += OSAL_NV_WORD_SIZE * len; } if ( rem ) { uint8 idx = 0; HalFlashRead(dstPg, dstOff, tmp, OSAL_NV_WORD_SIZE); while ( rem-- ) { tmp[idx++] = *buf++; } writeWord( dstPg, dstOff, tmp ); } }
/********************************************************************* * @fn osal_nv_read * * @brief Read data from NV. This function can be used to read an entire item from NV or * an element of an item by indexing into the item with an offset. * Read data is copied into *buf. * * @param id - Valid NV item Id. * @param ndx - Index offset into item * @param len - Length of data to read. * @param *buf - Data is read into this buffer. * * @return SUCCESS if NV data was copied to the parameter 'buf'. * Otherwise, NV_OPER_FAILED for failure. */ uint8 osal_nv_read( uint16 id, uint16 ndx, uint16 len, void *buf ) { uint16 offset; uint8 hotIdx; if ((hotIdx = hotItem(id)) < OSAL_NV_MAX_HOT) { HalFlashRead(hotPg[hotIdx], hotOff[hotIdx]+ndx, buf, len); return SUCCESS; } if ((offset = findItem(id)) == OSAL_NV_ITEM_NULL) { return NV_OPER_FAILED; } else { HalFlashRead(findPg, offset+ndx, buf, len); return SUCCESS; } }
/********************************************************************* * @fn xferItem * * @brief Copy an NV item from the active page to a designated page. * * @param pg - NV page where to copy the item to. * @param offset - NV page offset where to copy the item to. * @param alignedLen - Length of data to write, aligned in flash word * boundary. * @param srcOff - NV page offset of the original data in active page * * @return none. */ static void xferItem( uint8 pg, uint16 offset, uint16 alignedLen, uint16 srcOff ) { uint8 tmp[OSAL_NV_WORD_SIZE]; uint16 i = 0; // Copy over the data while (i <= alignedLen) { HalFlashRead(activePg, srcOff + i, tmp, OSAL_NV_WORD_SIZE); writeWord(pg, offset + i, tmp); i += OSAL_NV_WORD_SIZE; } }
/********************************************************************* * @fn cleanErasedPage * * @brief Erases a page in Flash if the page is not completely erased. * * @param pg - Valid NV page to erase. * * @return none */ static void cleanErasedPage( uint8 pg ) { uint8 buf; uint16 offset; for (offset = 0; offset < OSAL_NV_PAGE_SIZE; offset ++) { HalFlashRead(pg, offset, &buf, 1); if (buf != OSAL_NV_ERASED) { erasePage(pg); break; } } }
/************************************************************************************************** * @fn crcCalcDMA * * @brief Run the CRC16 Polynomial calculation over the image specified, * using DMA to read the flash memory into the CRC register * * input parameters * * @param page - Flash page on which to beging the CRC calculation. * * output parameters * * None. * * @return The CRC16 calculated. ************************************************************************************************** */ static uint16 crcCalcDMA(uint8 page) { uint16 crc; uint8 pageBeg; uint8 pageEnd; const img_hdr_t *pImgHdr; HalFlashRead(page, 0, pgBuf, HAL_FLASH_PAGE_SIZE); pImgHdr = (const img_hdr_t *)(pgBuf + BIM_HDR_OSET); pageBeg = page; pageEnd = pImgHdr->len / (HAL_FLASH_PAGE_SIZE / HAL_FLASH_WORD_SIZE); // One page is used for BIM, so we move this image's last page forward pageEnd += pageBeg; // If image A, set last page to be ImgA size + ImgB size if (pageBeg == BIM_IMG_A_PAGE) { pageEnd += BIM_IMG_B_AREA; } ADCCON1 &= 0xF3; // CRC configuration of LRSR. // CRC seed of 0x0000. RNDL = 0x00; RNDL = 0x00; // Handle first page differently to skip CRC and CRC shadow when calculating DMAExecCrc(pageBeg, 4, HAL_FLASH_PAGE_SIZE-4); // Do remaining pages for (uint8 pg = pageBeg + 1; pg < pageEnd; pg++) { if (pg == BIM_IMG_B_PAGE) { pg += BIM_IMG_B_AREA; } DMAExecCrc(pg, 0, HAL_FLASH_PAGE_SIZE); } crc = RNDH; crc = (crc << 8) | RNDL; return crc; }
// FIXME: currently only device name void custom_init(void) { uint8 buf[CUSTOM_DN_MAGIC_LEN + CUSTOM_DN_LEN]; uint8 idx = 0; HalFlashRead(CUSTOM_DN_PAGE_IDX, CUSTOM_DN_MGIC_OFFSET, buf, (CUSTOM_DN_MAGIC_LEN + CUSTOM_DN_LEN)); if (osal_memcmp(buf, dn_magic, CUSTOM_DN_MAGIC_LEN) != TRUE) { HalFlashErase(CUSTOM_DN_PAGE_IDX); for (idx = 0; idx < (CUSTOM_DN_MAGIC_LEN + CUSTOM_DN_LEN); idx++) { buf[idx] = 0; } osal_memcpy(buf, dn_magic, CUSTOM_DN_MAGIC_LEN); osal_memcpy((buf + CUSTOM_DN_MAGIC_LEN), dn_default, 3); HalFlashWrite((((uint32)CUSTOM_DN_PAGE_IDX * (uint32)2048 + CUSTOM_DN_MGIC_OFFSET) / 4), buf, (CUSTOM_DN_MAGIC_LEN + CUSTOM_DN_LEN) / 4); } }
/********************************************************************* * @fn findOffset * * @brief find an offset of an empty space in active page * where to write a new item to. * * @param None * * @return none */ static void findOffset(void) { uint16 offset; for (offset = OSAL_NV_PAGE_SIZE - OSAL_NV_WORD_SIZE; offset >= OSAL_NV_PAGE_HDR_SIZE; offset -= OSAL_NV_WORD_SIZE) { uint32 tmp; HalFlashRead(activePg, offset, (uint8 *)&tmp, OSAL_NV_WORD_SIZE); if (tmp != 0xFFFFFFFF) { break; } } pgOff = offset + OSAL_NV_WORD_SIZE; }
/************************************************************************************************** * @fn sblExec * * @brief Act on the SB command and received buffer. * * @param pBuf - A pointer to the RPC command buffer received. * * None. * * output parameters * * None. * * @return None. ************************************************************************************************** */ static void sblExec(uint8 *pBuf) { uint16 t16 = BUILD_UINT16(pBuf[SBL_REQ_ADDR_LSB],pBuf[SBL_REQ_ADDR_MSB]) + OAD_DONGLE_SBL_IMG_BEG; uint8 len = 1; uint8 rsp = SBL_SUCCESS; switch (pBuf[RPC_POS_CMD1]) { case SBL_WRITE_CMD: if ((t16 >= OAD_DONGLE_SBL_IMG_END) || (t16 < OAD_DONGLE_SBL_IMG_BEG)) { rsp = SBL_FAILURE; break; } if ((t16 % SBL_PAGE_SIZE) == 0) { HalFlashErase(t16 / SBL_PAGE_SIZE); } HalFlashWrite(t16, (pBuf + SBL_REQ_DAT0), (SBL_RW_BUF_LEN / HAL_FLASH_WORD_SIZE)); break; case SBL_READ_CMD: len = SBL_RW_BUF_LEN + SBL_READ_HDR_LEN; pBuf[SBL_RSP_ADDR_MSB] = pBuf[SBL_REQ_ADDR_MSB]; pBuf[SBL_RSP_ADDR_LSB] = pBuf[SBL_REQ_ADDR_LSB]; HalFlashRead(t16 / SBL_PAGE_SIZE, (t16 % SBL_PAGE_SIZE) << 2, (pBuf + SBL_RSP_DAT0), SBL_RW_BUF_LEN); break; case SBL_ENABLE_CMD: // Bootload master must verify download by read back - no room for CRC checking code in dongle. break; case SBL_HANDSHAKE_CMD: break; default: rsp = SBL_FAILURE; break; } pBuf[RPC_POS_LEN] = len; pBuf[RPC_POS_CMD1] |= SBL_RSP_MASK; pBuf[RPC_POS_DAT0] = rsp; }
/************************************************************************************************** * @fn crcCalcDL * * @brief Run the CRC16 Polynomial calculation over the DL image. * * input parameters * * None. * * output parameters * * None. * * @return The CRC16 calculated. ************************************************************************************************** */ static uint16 crcCalcDL(void) { uint8 pageEnd = oadBlkTot / OAD_BLOCKS_PER_PAGE; uint16 osetEnd = (oadBlkTot - (pageEnd * OAD_BLOCKS_PER_PAGE)) * OAD_BLOCK_SIZE; #if defined HAL_IMAGE_B pageEnd += OAD_IMG_D_PAGE + OAD_IMG_B_AREA; #else pageEnd += OAD_IMG_D_PAGE; #endif HalCRCInit(0x0000); // Seed thd CRC calculation with zero. for (uint8 page = OAD_IMG_D_PAGE; ; page++) { #if defined HAL_IMAGE_B // Skip the Image-B area which lies between the lower & upper Image-A parts. if (page == OAD_IMG_B_PAGE) { page += OAD_IMG_B_AREA; } #endif for (uint16 oset = 0; oset < HAL_FLASH_PAGE_SIZE; oset += HAL_FLASH_WORD_SIZE) { if ((page == OAD_IMG_D_PAGE) && (oset == OAD_IMG_CRC_OSET)) { continue; // Skip the CRC and shadow. } else if ((page == pageEnd) && (oset == osetEnd)) { return HalCRCCalc(); } else { uint8 buf[HAL_FLASH_WORD_SIZE]; HalFlashRead(page, oset, buf, HAL_FLASH_WORD_SIZE); for (uint8 idx = 0; idx < HAL_FLASH_WORD_SIZE; idx++) { HalCRCExec(buf[idx]); } } } } }
/********************************************************************* * @fn verifyWordM * * @brief verify the written word. * * @param pg - A valid NV Flash page. * @param offset - A valid offset into the page. * @param pBuf - Pointer to source buffer. * @param cnt - Number of 4-byte blocks to verify. * * @return none */ static void verifyWordM( uint8 pg, uint16 offset, uint8 *pBuf, osalSnvLen_t cnt ) { uint8 tmp[OSAL_NV_WORD_SIZE]; while (cnt--) { // Reading byte per byte will reduce code size but will slow down // and not sure it will meet the timing requirements. HalFlashRead(pg, offset, tmp, OSAL_NV_WORD_SIZE); if (FALSE == osal_memcmp(tmp, pBuf, OSAL_NV_WORD_SIZE)) { failF = TRUE; return; } offset += OSAL_NV_WORD_SIZE; pBuf += OSAL_NV_WORD_SIZE; } }
void persistent_pwrmgmt_set_latest(struct pwrmgmt_data *pwr_ptr) { uint8_t count; uint32_t pwr_idx_bits, u32; u32 = (uint32)&(((struct persistent_page *)0)->pwr_idx_bits[0]); HalFlashRead(pidx, (uint16_t)u32, (uint8_t *)&pwr_idx_bits, 4); count = __persistent_get_idx_from_bit_map((uint8_t *)&pwr_idx_bits, 4); if (count < PERSISTENT_PWR_MAX) { u32 = (uint32)&(((struct persistent_page *)0)->pwr_log[count]); HalFlashWrite(pidx, (uint16_t)u32, (uint8_t *)pwr_ptr, sizeof(struct pwrmgmt_data)); __persistent_mark_bit_map((uint8_t *)&pwr_idx_bits, 4); u32 = (uint32)&(((struct persistent_page *)0)->pwr_idx_bits[0]); HalFlashWrite(pidx, (uint16_t)u32, (uint8_t *)&pwr_idx_bits, 4); } else { flash_trigger_refresh_pwr_mgmt_info(pwr_ptr); } }