/** *! * \file b_srv_transfile.c * \version v0.0.1 * \date 2023/08/27 * \author Bean(notrynohigh@outlook.com) ******************************************************************************* * @attention * * Copyright (c) 2023 Bean * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. ******************************************************************************* */ /*Includes ----------------------------------------------*/ #include "services/inc/b_srv_transfile.h" #if (defined(_TRANSFILE_SERVICE_ENABLE) && (_TRANSFILE_SERVICE_ENABLE == 1)) #include "algorithm/inc/algo_crc.h" #include "core/inc/b_core.h" #include "core/inc/b_sem.h" #include "core/inc/b_task.h" #include "drivers/inc/b_driver.h" #include "hal/inc/b_hal.h" /** * \addtogroup BABYOS * \{ */ /** * \addtogroup SERVICES * \{ */ /** * \addtogroup TRANSFILE * \{ */ /** * \defgroup TRANSFILE_Private_TypesDefinitions * \{ */ /** * \} */ /** * \defgroup TRANSFILE_Private_Defines * \{ */ #ifndef TRANSFILE_TIMEOUT_S #define TRANSFILE_TIMEOUT_S (30) #endif #define TFL_KLV_FILENAME_ID (0xAA01) #define TFL_KLV_FILEVALUE_ID (0xAA02) /** * \} */ /** * \defgroup TRANSFILE_Private_Macros * \{ */ /** * \} */ /** * \defgroup TRANSFILE_Private_Variables * \{ */ static bProtSrvId_t bProtocolId = NULL; static bTFLSrvSendData_t bProtocolSend = NULL; static uint32_t bFileOffset = 0; static bProtoFileInfo_t bCurrentFileInfo = { .size = 0, .fcrc32 = 0, }; static bProtoFileLocation_t bCurrentLocation = { .dev = 0, }; B_TASK_CREATE_ATTR(bTFLTaskAttr); B_SEM_CREATE_ATTR(bTFLSemAttr); static bTaskId_t bTFLTaskId = NULL; static bSemId_t bTFLSemId = NULL; static bProtSrvSubscribe_t bSubInfo = { .number = 0, }; const static bProtoCmd_t bCmdTable[] = {B_PROTO_TRANS_FILE_INFO, B_PROTO_SET_FILE_LOCATION, B_PROTO_FILE_DATA}; /** * \} */ /** * \defgroup TRANSFILE_Private_FunctionPrototypes * \{ */ /** * \} */ /** * \defgroup TRANSFILE_Private_Functions * \{ */ static int _bTFLSendResult(uint8_t result) { uint8_t buf[128]; uint16_t olen = 0; buf[0] = result; olen = bProtSrvPackage(bProtocolId, B_PROTO_TRANS_FILE_RESULT, buf, sizeof(buf)); if (olen > 0 && bProtocolSend != NULL) { bProtocolSend(buf, olen); } return 0; } static void _bTFLEnd() { bProtSrvUnsubscribe(bProtocolId, &bSubInfo); bTaskRemove(bTFLTaskId); bTFLTaskId = NULL; memset(&bCurrentFileInfo, 0, sizeof(bCurrentFileInfo)); memset(&bCurrentLocation, 0, sizeof(bCurrentLocation)); bProtocolId = NULL; } static int _bTFLCheck() { uint32_t tmp_len = 0; uint8_t tmp[64]; uint32_t r_len = 0; CRC_REG_SBS_HANDLE(tmp_crc, ALGO_CRC32); int fd = bOpen(bCurrentLocation.dev, BCORE_FLAG_RW); if (fd == -1) { return -1; } bLseek(fd, bCurrentLocation.offset); while (tmp_len < bCurrentFileInfo.size) { r_len = ((bCurrentFileInfo.size - tmp_len) > 64) ? 64 : (bCurrentFileInfo.size - tmp_len); bRead(fd, tmp, r_len); crc_calculate_sbs(&tmp_crc, tmp, r_len); tmp_len += r_len; } bClose(fd); if (tmp_crc.crc != bCurrentFileInfo.fcrc32) { return -1; } return 0; } PT_THREAD(bTFLTaskFunc)(struct pt *pt, void *arg) { uint8_t buf[128]; uint16_t len = 0; bProtoReqFileData_t *p_req = (bProtoReqFileData_t *)buf; static uint32_t timeout = 0; B_TASK_INIT_BEGIN(); timeout = bHalGetSysTick(); B_TASK_INIT_END(); PT_BEGIN(pt); while (1) { bTaskDelayMs(pt, 200); if (bCurrentLocation.dev == 0 || bCurrentFileInfo.size == 0) { bTaskRestart(pt); } if (bFileOffset >= bCurrentFileInfo.size) { if (_bTFLCheck() == 0) { _bTFLSendResult(B_PROTO_TRANS_RESULT_OK); } else { _bTFLSendResult(B_PROTO_TRANS_RESULT_CHECKSUM_FAIL); } _bTFLEnd(); bTaskRestart(pt); } p_req->offset = bFileOffset; p_req->size = 512; len = bProtSrvPackage(bProtocolId, B_PROTO_REQ_FILE_DATA, buf, sizeof(buf)); bProtocolSend(buf, len); bSemAcquireBlock(pt, bTFLSemId, 3000); if (PT_WAIT_IS_TIMEOUT(pt)) { if (TICK_DIFF_BIT32(timeout, bHalGetSysTick()) >= (MS2TICKS(TRANSFILE_TIMEOUT_S * 1000))) { _bTFLSendResult(B_PROTO_TRANS_RESULT_TIMEOUT); _bTFLEnd(); bTaskRestart(pt); } } else { timeout = bHalGetSysTick(); } } PT_END(pt); } static int _TFLProtCallback(bProtoCmd_t cmd, void *param) { if (cmd == B_PROTO_TRANS_FILE_INFO) { bProtoFileInfo_t *pinfo = (bProtoFileInfo_t *)param; if (pinfo->size == 0) { return -1; } memcpy(&bCurrentFileInfo, param, sizeof(bCurrentFileInfo)); bFileOffset = 0; } else if (cmd == B_PROTO_SET_FILE_LOCATION) { bProtoFileLocation_t *plocation = (bProtoFileLocation_t *)param; if (plocation->dev == 0) { return -1; } memcpy(&bCurrentLocation, plocation, sizeof(bCurrentLocation)); bFileOffset = 0; } else if (cmd == B_PROTO_FILE_DATA) { if (bCurrentLocation.dev == 0 || bCurrentFileInfo.size == 0) { return -1; } bProtoFileData_t *pFileData = (bProtoFileData_t *)param; if (pFileData->size > 0 && pFileData->offset == bFileOffset) { int fd = -1; fd = bOpen(bCurrentLocation.dev, BCORE_FLAG_RW); if (fd < 0) { return -1; } if (bFileOffset == 0) { uint32_t sector_size = 0; bCtl(fd, bCMD_GET_SECTOR_SIZE, §or_size); if (sector_size == 0) { bClose(fd); return -1; } bFlashErase_t eparam; eparam.addr = bCurrentLocation.offset; eparam.num = (bCurrentFileInfo.size + sector_size - 1) / sector_size; bCtl(fd, bCMD_ERASE_SECTOR, &eparam); } bLseek(fd, bCurrentLocation.offset + bFileOffset); uint32_t w_len = ((bCurrentFileInfo.size - bFileOffset) > pFileData->size) ? pFileData->size : (bCurrentFileInfo.size - bFileOffset); bWrite(fd, pFileData->dat, w_len); bFileOffset += w_len; bClose(fd); bSemRelease(bTFLSemId); } } return 0; } /** * \} */ /** * \addtogroup TRANSFILE_Exported_Functions * \{ */ int bTFLSrvInit(bProtSrvId_t protocol_id, bTFLSrvSendData_t send) { int ret = 0; if (protocol_id == NULL || send == NULL) { return -1; } bProtocolId = protocol_id; bProtocolSend = send; bFileOffset = 0; bSubInfo.number = sizeof(bCmdTable) / sizeof(bProtoCmd_t); bSubInfo.pcmd_table = &bCmdTable[0]; bSubInfo.callback = _TFLProtCallback; bProtSrvSubscribe(protocol_id, &bSubInfo); memset(&bCurrentFileInfo, 0, sizeof(bCurrentFileInfo)); memset(&bCurrentLocation, 0, sizeof(bCurrentLocation)); if (bTFLTaskId == NULL) { bTFLTaskId = bTaskCreate("transfile", bTFLTaskFunc, NULL, &bTFLTaskAttr); } if (bTFLSemId == NULL) { bTFLSemId = bSemCreate(1, 0, &bTFLSemAttr); } bSemAcquireNonblock(bTFLSemId); return 0; } int bTFLSrvDeinit() { int ret = -1; if (bProtocolId == NULL) { return -1; } _bTFLEnd(); return 0; } int bTFLSrvGetFileInfo(uint32_t dev_no, uint32_t base_addr, const char *filename, bTFLSrvFileInfo_t *pinfo) { uint16_t key = 0; uint32_t len = 0; uint8_t tmp_buf[16]; uint8_t file_name_ok = 0; uint8_t i = 0; if (dev_no == 0 || filename == NULL || pinfo == NULL) { return -1; } int fd = -1; int filename_len = strlen(filename); fd = bOpen(dev_no, BCORE_FLAG_RW); if (fd < 0) { return -1; } while (1) { bLseek(fd, base_addr); bRead(fd, (uint8_t *)&key, sizeof(key)); base_addr += sizeof(key); key = B_SWAP_16(key); if (key != TFL_KLV_FILENAME_ID && key != TFL_KLV_FILEVALUE_ID) { bClose(fd); return -1; } bRead(fd, (uint8_t *)&len, sizeof(len)); base_addr += sizeof(len); len = B_SWAP_32(len); if (key == TFL_KLV_FILENAME_ID && len == filename_len) { int tmp_i = 0; while (tmp_i < len) { bRead(fd, tmp_buf, 16); for (i = 0; i < 16; i++) { if (filename[tmp_i + i] == '\0') { file_name_ok = 1; break; } if (filename[tmp_i + i] != tmp_buf[i]) { break; } } if (i < 16) { break; } tmp_i += 16; } } else if (key == TFL_KLV_FILEVALUE_ID && file_name_ok == 1) { pinfo->addr = base_addr; pinfo->len = len; break; } base_addr += len; } bClose(fd); return 0; } /** * \} */ /** * \} */ /** * \} */ /** * \} */ #endif /************************ Copyright (c) 2023 Bean *****END OF FILE****/