/************************************************************************************************** * Copyright (c) Fenda Technologies Co., Ltd. 2020-2021. All rights reserved. * Description: 蓝牙文件传输协议 * Author: leon.sunzhen * Create: 2020-12-23 ************************************************************************************************/ #include "FreeRTOS.h" #include "timers.h" #include "am_util_debug.h" #include "sys_config.h" #include "ble_file_trans.h" #include "ble_file_trans_server.h" #include "amotas_api.h" #include "amota_api.h" #include "ble_management_server.h" #include "ble_data_transmission.h" #include "sys_memory.h" #include "fs_api.h" #define ENABLE_STATIC_PRINT true extern uint32_t am_util_stdio_printf(const char *pcFmt, ...); #define static_print_remind(...) am_util_stdio_printf(__VA_ARGS__) #if ENABLE_STATIC_PRINT #define static_print_info(...) am_util_stdio_printf(__VA_ARGS__) #else #define static_print_info(...) #endif const p_func_t FileTransServerFunc[FILE_TRANS_ACTION_MAX] = { NULL, BLE_FileTransFileInfo, //4.11.1 BLE_FileTransRequestCheck, //4.11.2 BLE_FileTransRequestData, //4.11.3 BLE_FileTransReturnData, //4.11.4 NULL, //4.11.5 NULL, //4.11.6 NULL, //4.11.7 NULL, //4.11.8 BLE_FileTransAllComplete, //4.11.9 NULL, //4.11.A NULL, //4.11.B NULL, //4.11.C NULL, //4.11.D NULL, //4.11.E NULL, //4.11.F NULL, //4.11.10 NULL, //4.11.11 NULL, //4.11.12 NULL, //4.11.13 NULL, //4.11.14 NULL, //4.11.15 BLE_FileTransAppGetInfo, //4.11.16 NULL, //4.11.17 BLE_FileTransAppRequestData, //4.11.18 NULL, //4.11.19 BLE_FileTransAppRcvComplete, //4.11.20 BLE_FileTransAppCancel, //4.11.21 }; //APP下发文件: /***************************************************************************** 4.11.1 app发送文件信息 *****************************************************************************/ void BLE_FileTransFileInfo(uint8_t *inData, uint16_t inLen, uint8_t *outData, uint16_t *outLen) { protocol_data_info_t dataInfo = {0}; uint8_t fileId; uint8_t version[32] = {0}; char fileName[128] = {0}; uint32_t fileSize; uint8_t fileAction; uint32_t fileCreateTime; uint8_t model; static_print_info("BLE_FileTransFileInfo\r\n"); if(inData == NULL || inLen == 0) { return; } do { user_get_data_info(&dataInfo, &inData, &inLen); switch((dataInfo.type & 0x7F)) { case FT_FILE_INFO_TYPE_FILE_ID: fileId = *dataInfo.p_data; static_print_info("fileId=%d\r\n", fileId); break; case FT_FILE_INFO_TYPE_VERSION: memcpy(version, dataInfo.p_data, dataInfo.len); version[31] = 0; static_print_info("version=%s\r\n", version); break; case FT_FILE_INFO_TYPE_FILE_NAME: memcpy(fileName, dataInfo.p_data, dataInfo.len); fileName[127] = 0; static_print_info("fileName=%s\r\n", fileName); break; case FT_FILE_INFO_TYPE_FILE_LENGTH: if(dataInfo.len == 4) { fileSize = (dataInfo.p_data[0] << 24) + \ (dataInfo.p_data[1] << 16) + \ (dataInfo.p_data[2] << 8) + \ dataInfo.p_data[3]; static_print_info("fileSize=%d\r\n", fileSize); } break; case FT_FILE_INFO_TYPE_FILE_ACTION: fileAction = *dataInfo.p_data; static_print_info("fileAction=%d\r\n", fileAction); break; case FT_FILE_INFO_TYPE_FILE_CREATE_TIME: if(dataInfo.len == 4) { fileCreateTime = (dataInfo.p_data[0] << 24) + \ (dataInfo.p_data[1] << 16) + \ (dataInfo.p_data[2] << 8) + \ dataInfo.p_data[3]; static_print_info("fileCreateTime=%d\r\n", fileCreateTime); } break; case FT_FILE_INFO_TYPE_MODEL: model = *dataInfo.p_data; static_print_info("model=%d\r\n", model); break; default: break; } inData = dataInfo.p_data; inData += (dataInfo.len); inLen -= (2 + dataInfo.len); if(inLen > FRAM_MAX_SIZ) { inLen = 0; } } while(inLen); file_trans_start(fileId, fileName, fileSize, (FileActionType)fileAction); Ltv_t ltvArray[3] = {0}; FrameInfo_t frameInfo; //回复 //file id ltvArray[0].len = 3; ltvArray[0].type = FT_FILE_INFO_TYPE_FILE_ID; ltvArray[0].value = fileId; ltvArray[1].len = 3; ltvArray[1].type = FT_FILE_INFO_TYPE_MTU; ltvArray[1].value = user_app_mtu_get(); ltvArray[2].len = 4; ltvArray[2].type = FT_FILE_INFO_TYPE_FRAME; ltvArray[2].value = 5000; frameInfo.serviceId = BLE_FILE_TRANS_SERVER; frameInfo.commandId = FILE_TRANS_FILE_INFO; frameInfo.frameType.value = 0; BLE_SendLtvArray(&frameInfo, ltvArray, 3); vTaskDelay(50); //请求CRC ltvArray[0].len = 3; ltvArray[0].type = FT_REQUEST_CHECK_TYPE_FILE_ID; ltvArray[0].value = fileId; ltvArray[1].len = 3; ltvArray[1].type = FT_REQUEST_CHECK_TYPE_CHECK_TYPE; ltvArray[1].value = 2; //请求crc frameInfo.serviceId = BLE_FILE_TRANS_SERVER; frameInfo.commandId = FILE_TRANS_REQUEST_CHECK; frameInfo.frameType.value = 0; BLE_SendLtvArray(&frameInfo, ltvArray, 2); } /***************************************************************************** 4.11.2 设备端请求文件校验值 *****************************************************************************/ void BLE_FileTransRequestCheck(uint8_t *inData, uint16_t inLen, uint8_t *outData, uint16_t *outLen) { protocol_data_info_t dataInfo = {0}; uint8_t checkType = 0; static_print_info("BLE_FileTransRequestCheck\r\n"); if(inData == NULL || inLen == 0) { return; } do { user_get_data_info(&dataInfo, &inData, &inLen); switch((dataInfo.type & 0x7F)) { case FT_REQUEST_CHECK_TYPE_FILE_ID: break; case FT_REQUEST_CHECK_TYPE_CHECK_TYPE: checkType = *dataInfo.p_data; static_print_info("checkType=%d\r\n", checkType); break; case FT_REQUEST_CHECK_TYPE_CHECK_VALUE: if(checkType == FT_CHECK_TYPE_CRC) { uint32_t crc = *dataInfo.p_data; FileTransSetCrc(crc); } else if(checkType == FT_CHECK_TYPE_MD5) { FileTransSetMd5(dataInfo.p_data); } break; default: break; } inData = dataInfo.p_data; inData += (dataInfo.len); inLen -= (2 + dataInfo.len); if(inLen > FRAM_MAX_SIZ) { inLen = 0; } } while(inLen); BLE_SendFileTransRequestData(); } /***************************************************************************** 4.11.3 设备请求一帧文件 *****************************************************************************/ void BLE_SendFileTransRequestData(void) { FileTransCtrlBlock_t ctrlBlock; Ltv_t ltvArray[6] = {0}; FrameInfo_t frameInfo; file_trans_get_ctrl_block(&ctrlBlock); ltvArray[0].len = 3; ltvArray[0].type = FT_REQUEST_DATA_TYPE_FILE_ID; ltvArray[0].value = ctrlBlock.fileId; ltvArray[1].len = 6; ltvArray[1].type = FT_REQUEST_DATA_TYPE_OFFSET; ltvArray[1].value = ctrlBlock.offset; ltvArray[2].len = 6; ltvArray[2].type = FT_REQUEST_DATA_TYPE_LENGTH; ltvArray[2].value = ctrlBlock.nextPkgSize; ltvArray[3].len = 4; ltvArray[3].type = FT_REQUEST_DATA_TYPE_PSN; ltvArray[3].value = ctrlBlock.psn; ltvArray[4].len = 6; ltvArray[4].type = FT_REQUEST_DATA_TYPE_FILE_SIZE; ltvArray[4].value = ctrlBlock.fileSize; ltvArray[5].len = 6; ltvArray[5].type = FT_REQUEST_DATA_TYPE_FILE_RECEIVED; ltvArray[5].value = ctrlBlock.offset; frameInfo.serviceId = BLE_FILE_TRANS_SERVER; frameInfo.commandId = FILE_TRANS_REQUEST_DATA; frameInfo.frameType.value = 0; BLE_SendLtvArray(&frameInfo, ltvArray, 6); } void BLE_FileTransRequestData(uint8_t *inData, uint16_t inLen, uint8_t *outData, uint16_t *outLen) { static_print_info("BLE_FileTransRequestData\r\n"); } /***************************************************************************** 4.11.4 app传输一帧文件到设备 *****************************************************************************/ void BLE_FileTransReturnData(uint8_t *inData, uint16_t inLen, uint8_t *outData, uint16_t *outLen) { int32_t ret; ret = file_trans_write_pkg(inData, inLen); if (ret == FILE_WRITE_PKG_NO_REQUEST) {//do nothing. return; } if(ret > 0) { BLE_SendFileTransRequestData(); } else if (ret == FILE_WRITE_PKG_COMPLETE) { BLE_FileTransComplete(); file_trans_succ(); } else { amota_conn_param_update(CONN_PARAM_LOW_POWER); vTaskDelay(10); BLE_FileTransReportRcvState(-ret); FileTransDisconn(); } } /***************************************************************************** 4.11.6 设备端回复文件接收完毕 *****************************************************************************/ void BLE_FileTransComplete(void) { static_print_info("BLE_FileTransComplete\r\n"); Ltv_t ltvArray[2] = {0}; FrameInfo_t frameInfo; FileTransCtrlBlock_t ctrlBlock; file_trans_get_ctrl_block(&ctrlBlock); ltvArray[0].len = 3; ltvArray[0].type = FT_RCV_COMPLETE_TYPE_FILE_ID; ltvArray[0].value = ctrlBlock.fileId; ltvArray[1].len = 3; ltvArray[1].type = FT_REPORT_RCV_STATE_TYPE_ERROR_CODE; ltvArray[1].value = 0; frameInfo.serviceId = BLE_FILE_TRANS_SERVER; frameInfo.commandId = FILE_TRANS_RCV_COMPLETE; frameInfo.frameType.value = 0; BLE_SendLtvArray(&frameInfo, ltvArray, 2); } /***************************************************************************** 4.11.7 设备端主动上报接收状态 *****************************************************************************/ void BLE_FileTransReportRcvState(uint16_t errCode) { static_print_info("BLE_FileTransReportRcvState\r\n"); Ltv_t ltvArray[2] = {0}; FrameInfo_t frameInfo; FileTransCtrlBlock_t ctrlBlock; file_trans_get_ctrl_block(&ctrlBlock); ltvArray[0].len = 3; ltvArray[0].type = FT_REPORT_RCV_STATE_TYPE_FILE_ID; ltvArray[0].value = ctrlBlock.fileId; ltvArray[1].len = 4; ltvArray[1].type = FT_REPORT_RCV_STATE_TYPE_ERROR_CODE; ltvArray[1].value = (BLE_FILE_TRANS_SERVER << 8) | errCode; frameInfo.serviceId = BLE_FILE_TRANS_SERVER; frameInfo.commandId = FILE_TRANS_REPORT_RCV_STATE; frameInfo.frameType.value = 0; BLE_SendLtvArray(&frameInfo, ltvArray, 2); } /* static osThreadId_t UpdateFileTaskHandle = NULL; static void UpdateFilesTask(void) { UpdateAllRcvFiles(false); osThreadExit(); UpdateFileTaskHandle = NULL; } static void UpdateFilesTaskCreate(void) { const osThreadAttr_t attributes = { .name = "updateFilesTask", .priority = (osPriority_t)8, .stack_size = 1024 * 10, }; UpdateFileTaskHandle = osThreadNew((osThreadFunc_t)UpdateFilesTask, NULL, &attributes); if(UpdateFileTaskHandle == NULL) { PRINT_ERR("create update file task failed\n"); } } */ /***************************************************************************** 4.11.9 APP告诉设备本轮逻辑的文件已传输完成 *****************************************************************************/ void BLE_FileTransAllComplete(uint8_t *inData, uint16_t inLen, uint8_t *outData, uint16_t *outLen) { static_print_info("\r\n BLE_FileTransAllComplete \r\n"); FileTransOver(); } //APP请求文件: static FileTransUploadFileInfo_t *g_pFileList = NULL; static uint8_t g_uploadFileNum; /***************************************************************************** 4.11.16 APP获取设备文件信息 *****************************************************************************/ void BLE_FileTransAppGetInfo(uint8_t *inData, uint16_t inLen, uint8_t *outData, uint16_t *outLen) { protocol_data_info_t dataInfo = {0}; uint8_t fileAction = 3; //默认为log文件 uint8_t fileTrans; //传输类型,0-后台,1-前台。暂不处理,目前上传都是后台 static_print_info("BLE_FileTransAppGetInfo\r\n"); if(inData == NULL || inLen == 0) { return; } do { user_get_data_info(&dataInfo, &inData, &inLen); switch((dataInfo.type & 0x7F)) { case FT_UPLOAD_FILE_INFO_TYPE_GET_FILE: fileAction = *dataInfo.p_data; static_print_info("fileAction=%d\r\n", fileAction); break; case FT_UPLOAD_FILE_INFO_TYPE_TRANS: fileTrans = *dataInfo.p_data; static_print_info("fileTrans=%d\r\n", fileTrans); break; default: break; } inData = dataInfo.p_data; inData += (dataInfo.len); inLen -= (2 + dataInfo.len); if(inLen > FRAM_MAX_SIZ) { inLen = 0; } } while(inLen); //1. 根据fileAction遍历文件,存放在g_pFileList内,g_pFileList的生命周期为下一次遍历之前 if(g_pFileList) { vPortFree(g_pFileList); } g_uploadFileNum = GetFileListByAction((FileActionType)fileAction, &g_pFileList); static_print_info("upload file num=%d\r\n", g_uploadFileNum); if(g_pFileList == NULL) { static_print_info("GetFileListByAction failed\r\n"); return; } //2. 根据遍历的文件大小malloc出ltvArray Ltv_t *ltvArray = pvPortMalloc(sizeof(Ltv_t) * (5 * g_uploadFileNum + 1)); if(ltvArray == NULL) { static_print_info("EXT_MALLOC failed\r\n"); return; } memset(ltvArray, 0, sizeof(Ltv_t) * (5 * g_uploadFileNum + 1)); //3. 填充ltvArray,并发送 uint32_t fileListSize; ltvArray[0].len = 3; ltvArray[0].type = FT_UPLOAD_FILE_INFO_TYPE_FILES; ltvArray[0].value = g_uploadFileNum; for(uint32_t i = 0; i < g_uploadFileNum; i++) { fileListSize = 0; //file name ltvArray[i * 5 + 2].len = strlen(g_pFileList[i].filePathName) + 2; // 因为传输同名文件,APP会覆盖,修改为传输路径 ltvArray[i * 5 + 2].type = FT_UPLOAD_FILE_INFO_TYPE_FILE_NAME; ltvArray[i * 5 + 2].pValue = (uint8_t *)g_pFileList[i].filePathName; fileListSize += ltvArray[i * 5 + 2].len; //file size ltvArray[i * 5 + 3].len = 6; ltvArray[i * 5 + 3].type = FT_UPLOAD_FILE_INFO_TYPE_FILE_LENGTH; ltvArray[i * 5 + 3].value = g_pFileList[i].fileSize; fileListSize += ltvArray[i * 5 + 3].len; //file frames ltvArray[i * 5 + 4].len = 4; ltvArray[i * 5 + 4].type = FT_UPLOAD_FILE_INFO_TYPE_FILE_FRAMES; ltvArray[i * 5 + 4].value = g_pFileList[i].fileFrames; fileListSize += ltvArray[i * 5 + 4].len; //file id ltvArray[i * 5 + 5].len = 3; ltvArray[i * 5 + 5].type = FT_UPLOAD_FILE_INFO_TYPE_FILE_ID; ltvArray[i * 5 + 5].value = g_pFileList[i].fileId; fileListSize += ltvArray[i * 5 + 5].len; //file list ltvArray[i * 5 + 1].len = 3; ltvArray[i * 5 + 1].type = FT_UPLOAD_FILE_INFO_TYPE_FILE_LIST; ltvArray[i * 5 + 1].value = fileListSize; } FrameInfo_t frameInfo; frameInfo.serviceId = BLE_FILE_TRANS_SERVER; frameInfo.commandId = FILE_TRANS_APP_GET_INFO; frameInfo.frameType.value = 0; BLE_SendLtvArray(&frameInfo, ltvArray, 5 * g_uploadFileNum + 1); vPortFree(ltvArray); } /***************************************************************************** 4.11.18 APP通过文件信息请求一帧数据 *****************************************************************************/ void BLE_FileTransAppRequestData(uint8_t *inData, uint16_t inLen, uint8_t *outData, uint16_t *outLen) { protocol_data_info_t dataInfo = {0}; uint8_t fileId; uint16_t receivedFrame; uint16_t frame = 0; FrameInfo_t frameInfo; static_print_info("BLE_FileTransAppRequestData\r\n"); if(inData == NULL || inLen == 0) { return; } do { user_get_data_info(&dataInfo, &inData, &inLen); switch((dataInfo.type & 0x7F)) { case FT_UPLOAD_REQUEST_DATA_FILE_ID: fileId = *dataInfo.p_data; static_print_info("fileId=%d\r\n", fileId); break; case FT_UPLOAD_REQUEST_DATA_FILE_RECEIVED_FRAME: receivedFrame = (dataInfo.p_data[0] << 8) + dataInfo.p_data[1]; static_print_info("receivedFrame=%d\r\n", receivedFrame); break; case FT_UPLOAD_REQUEST_DATA_FILE_FRAME: frame = (dataInfo.p_data[0] << 8) + dataInfo.p_data[1]; static_print_info("frame=%d\r\n", frame); break; default: break; } inData = dataInfo.p_data; inData += (dataInfo.len); inLen -= (2 + dataInfo.len); if(inLen > FRAM_MAX_SIZ) { inLen = 0; } } while(inLen); if(g_pFileList == NULL) { static_print_info("file list does not exist!\r\n"); return; } if(fileId >= g_uploadFileNum) { static_print_info("fileId err,fileId=%d,g_uploadFileNum=%d\r\n", fileId, g_uploadFileNum); return; } uint32_t offset = frame * FILE_UPLOAD_FRAME_SIZE; uint8_t *readData = pvPortMalloc(FILE_UPLOAD_FRAME_SIZE + 3); if(readData == NULL) { static_print_info("readData malloc failed\r\n"); return; } readData[0] = fileId; readData[1] = frame << 8; readData[2] = frame; int ret = fs_api_file_load(g_pFileList[fileId].filePathName, offset, readData + 3, FILE_UPLOAD_FRAME_SIZE); if(ret > 0) { frameInfo.serviceId = BLE_FILE_TRANS_SERVER; frameInfo.commandId = FILE_TRANS_APP_RETURN_DATA; //回复4.11.19 frameInfo.frameType.value = 0; BLE_SendFrame(&frameInfo, readData, ret + 3); #if 0 /* 若是log文件则同步完成后删除 */ if(strncmp(g_pFileList[fileId].filePathName, DIR_DATA_LOG, strlen(DIR_DATA_LOG)) == 0) { if(g_pFileList[fileId].fileFrames == frame + 1) { static_print_info("get full frame\r\n"); fs_api_unlink(g_pFileList[fileId].filePathName); } } #endif } else { static_print_info("FSFileLoad err,ret=%d\r\n", ret); } vPortFree(readData); } /***************************************************************************** 4.11.20 APP通知设备已接收完一个文件 *****************************************************************************/ void BLE_FileTransAppRcvComplete(uint8_t *inData, uint16_t inLen, uint8_t *outData, uint16_t *outLen) { //设备端不做处理 static_print_info("BLE_FileTransAppRcvComplete\r\n"); } /***************************************************************************** 4.11.21 APP取消传输 *****************************************************************************/ void BLE_FileTransAppCancel(uint8_t *inData, uint16_t inLen, uint8_t *outData, uint16_t *outLen) { //设备端不做处理 static_print_info("BLE_FileTransAppCancel\r\n"); }