mcu_hi3321_watch/tjd/ble/ble_protocol_file_download.c
2025-05-26 20:15:20 +08:00

866 lines
45 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*----------------------------------------------------------------------------
* Copyright (c) Fenda Technologies Co., Ltd. 2022. All rights reserved.
*
* Description: ble_protocol_file_upload.c
*
* Author: saimen
*
* Create: 2024-12-03
*--------------------------------------------------------------------------*/
#include "ble_port_protocol.h"
#include "ble_api.h"
#include "ble_port.h"
#include "bts_br_gap.h"
#include "bts_gatt_server.h"
#include "bts_le_gap.h"
#include "ctype.h"
#include "osal_addr.h"
#include "rtc_api.h"
#include "securec.h"
#include "sql_all.h"
#include "stdlib.h"
#include "string.h"
#include "sys_config.h"
#include "sys_typedef.h"
#include "time.h"
// #include "TjdUiMessagePopUpPage.h"
#include "fcntl.h"
#include "fs_api_ext.h"
#include "fs_user_common.h"
#include "linux/crc32.h"
#include "los_ringbuf.h"
#include "sys/statfs.h"
#include "unistd.h"
#include <sys/stat.h>
#include "power_display_service.h"
#include "service_bt.h"
#include "thread_init.h"
// #include "semaphore.h"
#include "upg_porting.h"
#include "osal_task.h"
#include "osal_semaphore.h"
#include "soc_osal.h"
#include <dirent.h>
#include "service_lucky_clover.h"
#include "broadcast_feature.h"
#include "service_charger.h"
#include "service_sleep.h"
#include "ble_protocol_file_download.h"
#ifdef __cplusplus
extern "C"
{
#endif
#include "TjdUiAppCameraToC.h"
// #include "TjdUiWatchFaceCtrl.h"
#include "service_gps.h"
#ifdef __cplusplus
}
#endif
#define ENABLE_STATIC_PRINT 0
#define static_print_error(...) sys_bt_log_e(__VA_ARGS__) //错误信息打印一般常开
#define static_print_warn(...) sys_bt_log_w(__VA_ARGS__) //警告信息打印一般常开
#if ENABLE_STATIC_PRINT
#define static_print_debug(...) sys_bt_log_d(__VA_ARGS__)
#define static_print_info(...) sys_bt_log_i(__VA_ARGS__)
#else
#define static_print_debug(...)
#define static_print_info(...)
#endif
#define BLE_FILE_TRANSFER_TIME_OUT (15)
#define TJD_FS_DIR_GPS_BAT TJD_FS_DIR_GPS"bat"
#define FS_VOLUME_USER "/user/"
#define FS_VOLUME_UPDATE "/update/"
#define FS_NODE_INFO_SPACE 16
FileDescriptionInfo_t g_file_description = {0};
FileTransferInfo_t g_files_transfer = {0};
DirDescriptionInfo_t g_dir_description = {0};
typedef void (*file_transfer_callback_t)(FileDescriptionInfo_t *p_description, FileTransferInfo_t *p_transfer);
typedef struct {
file_transfer_callback_t start;
file_transfer_callback_t end;
file_transfer_callback_t data;
} FileTransferCallback_t;
FileTransferCallback_t g_files_transfer_Callback[FileType_MAX];
UpgradeContext g_file_decription_context;
//文件下载中回调集中处理
extern void file_download_callback_start_type_fiemware(FileDescriptionInfo_t *p_description, FileTransferInfo_t *p_transfer);
extern void file_download_callback_end_type_fiemware(FileDescriptionInfo_t *p_description, FileTransferInfo_t *p_transfer);
extern void file_download_callback_data_type_fiemware(FileDescriptionInfo_t *p_description, FileTransferInfo_t *p_transfer);
extern void file_download_callback_start_type_dial_original(FileDescriptionInfo_t *p_description, FileTransferInfo_t *p_transfer);
extern void file_download_callback_end_type_dial_original(FileDescriptionInfo_t *p_description, FileTransferInfo_t *p_transfer);
extern void file_download_callback_start_type_dial_doc(FileDescriptionInfo_t *p_description, FileTransferInfo_t *p_transfer);
extern void file_download_callback_end_type_dial_doc(FileDescriptionInfo_t *p_description, FileTransferInfo_t *p_transfer);
extern void file_download_callback_end_type_dial_custom(FileDescriptionInfo_t *p_description, FileTransferInfo_t *p_transfer);
extern void file_download_callback_end_type_gps(FileDescriptionInfo_t *p_description, FileTransferInfo_t *p_transfer);
extern void file_download_callback_end_type_js(FileDescriptionInfo_t *p_description, FileTransferInfo_t *p_transfer);
void tjd_ble_protocol_file_download_callback_init(void)
{
static_print_debug("tjd_ble_protocol_file_download_callback_init():...........\n");
memset_s(g_files_transfer_Callback, sizeof(g_files_transfer_Callback), 0, sizeof(g_files_transfer_Callback));
g_files_transfer_Callback[TYPE_FIRMWARE].start = file_download_callback_start_type_fiemware;
g_files_transfer_Callback[TYPE_FIRMWARE].end = file_download_callback_end_type_fiemware;
g_files_transfer_Callback[TYPE_FIRMWARE].data = file_download_callback_data_type_fiemware;
g_files_transfer_Callback[TYPE_AIDIAL_ORIGINAL].start = file_download_callback_start_type_dial_original;
g_files_transfer_Callback[TYPE_AIDIAL_ORIGINAL].end = file_download_callback_end_type_dial_original;
g_files_transfer_Callback[TYPE_DIAL_DOC].start = file_download_callback_start_type_dial_doc;
g_files_transfer_Callback[TYPE_DIAL_DOC].end = file_download_callback_end_type_dial_doc;
g_files_transfer_Callback[TYPE_DIAL_DIAGRAM].end = file_download_callback_end_type_dial_custom;
g_files_transfer_Callback[TYPE_DIAL_MULTIGRAPH].end = file_download_callback_end_type_dial_custom;
g_files_transfer_Callback[TYPE_DIAL_VIDEO].end = file_download_callback_end_type_dial_custom;
g_files_transfer_Callback[TYPE_GPS].end = file_download_callback_end_type_gps;
g_files_transfer_Callback[TYPE_JS_APP].end = file_download_callback_end_type_js;
}
void tjd_file_transfer_err_operation(void)
{
switch(g_file_description.file_type){
case TYPE_E_BOOK:
static_print_error("TYPE_E_BOOK file transfer error");
tjd_fs_api_path_remove((char *)g_file_description.file_name);
break;
case TYPE_JS_APP:
static_print_error("TYPE_JS_APP file transfer error");
tjd_fs_api_path_remove((char *)g_file_description.file_name);
break;
default:
static_print_error("file transfer error");
tjd_fs_api_path_remove((char *)g_file_description.file_name);
break;
}
}
int tjd_service_timer_cnt = 0;
//文件下载通信超时检测
signed int tjd_task_service_timer_check_timeout(void *param)
{
unsigned long *p_param = (unsigned long *)param;
uint64_t temp_time = 0;
tjd_driver_rtc_get_ops()->get_timestamp(&temp_time);
static_print_debug("tjd_task_service_timer_check_timeout(): param=%ld\r\n", *p_param);
static_print_debug("tjd_task_service_timer_check_timeout(): temp_time=%ld\r\n", temp_time);
static_print_debug("tjd_task_service_timer_check_timeout(): g_files_transfer.file_status=%d\r\n", g_files_transfer.file_status);
if(temp_time - *p_param > BLE_FILE_TRANSFER_TIME_OUT) {
if(g_files_transfer.file_status != FileTransfer_NULL) {
tjd_ble_file_breakpoint_save();
g_files_transfer.file_status = FileTransfer_Timeout;
if(g_files_transfer_Callback[g_file_description.file_type].end)
{
g_files_transfer_Callback[g_file_description.file_type].end(&g_file_description, &g_files_transfer);
}
}
return 0; //自动删除超时检测
} else if(((temp_time - *p_param)%5==4) && g_files_transfer.file_status != FileTransfer_NULL) {
static_print_debug("tjd_task_service_timer_check_timeout(): repeat =%ld\r\n", *p_param);
tjd_service_timer_cnt ++;
static_print_debug("tjd_task_service_timer_check_timeout(): tjd_service_timer_cnt =%d\r\n", tjd_service_timer_cnt);
if(tjd_service_timer_cnt > 3) {
tjd_service_timer_cnt = 0;
ble_api_cmd_info_reset();
tjd_file_transfer_err_operation();
uint8_t resp_data[9] = {0};
resp_data[0] = 0x00;
resp_data[1] = g_files_transfer.operation_file_size >> 24;
resp_data[2] = (g_files_transfer.operation_file_size >> 16) & 0xFF;
resp_data[3] = (g_files_transfer.operation_file_size >> 8) & 0xFF;
resp_data[4] = g_files_transfer.operation_file_size & 0xFF;
resp_data[5] = g_files_transfer.operation_file_size >> 24;
resp_data[6] = (g_files_transfer.operation_file_size >> 16) & 0xFF;
resp_data[7] = (g_files_transfer.operation_file_size >> 8) & 0xFF;
resp_data[8] = g_files_transfer.operation_file_size & 0xFF;
tjd_ble_protocol_send_data(PROTOCOL_FRAME_RSP_HEAD_2, resp_data, sizeof(resp_data), DOWNLOAD_FILE_DATA, gatt_server_id, g_server_conn_id);
}else{
ble_api_cmd_info_reset();
uint8_t resp_data[9] = {0};
resp_data[0] = 0x01;
resp_data[1] = g_files_transfer.operation_file_size >> 24;
resp_data[2] = (g_files_transfer.operation_file_size >> 16) & 0xFF;
resp_data[3] = (g_files_transfer.operation_file_size >> 8) & 0xFF;
resp_data[4] = g_files_transfer.operation_file_size & 0xFF;
resp_data[5] = g_files_transfer.operation_file_size >> 24;
resp_data[6] = (g_files_transfer.operation_file_size >> 16) & 0xFF;
resp_data[7] = (g_files_transfer.operation_file_size >> 8) & 0xFF;
resp_data[8] = g_files_transfer.operation_file_size & 0xFF;
tjd_ble_protocol_send_data(PROTOCOL_FRAME_RSP_HEAD_2, resp_data, sizeof(resp_data), DOWNLOAD_FILE_DATA, gatt_server_id, g_server_conn_id);
}
}
return 1000; //定时执行间隔单位为ms
}
void tjd_task_service_check_timeout_start(void)
{
queue_default_info_t msg_data = { tjd_task_service_timer_check_timeout, &g_files_transfer.operation_last_time, 1000, NULL };//1000ms首次执行的等待时间。
osal_msg_queue_write_copy(tjd_task_service_timer_get_queue_id(), (void *)&msg_data, sizeof(queue_default_info_t), 0);
}
//基础接口:开始
uint32_t tjd_ble_get_file_download_current_offset(void)
{
if(g_files_transfer.file_status != FileTransfer_NULL) {
return g_files_transfer.operation_file_size;
} else {
return 0;
}
}
void tjd_ble_protocol_dir_transfer_enter_handle(uint8_t file_total_type, uint8_t file_total_number, uint32_t file_total_size)
{
static_print_debug("tjd_ble_protocol_dir_transfer_enter_handle():%d-%d-%d\n", file_total_type, file_total_number, file_total_size);
g_dir_description.file_total_type = file_total_type;
g_dir_description.file_total_number = file_total_number;
g_dir_description.file_total_size = file_total_size;
memset_s(&g_files_transfer, sizeof(g_files_transfer), 0, sizeof(g_files_transfer));
}
void tjd_ble_protocol_dir_transfer_exit_handle(void)
{
static_print_debug("tjd_ble_protocol_dir_transfer_exit_handle()\n");
g_dir_description.file_total_type = FileType_MAX;
g_dir_description.file_total_number = 0;
g_dir_description.file_total_size = 0;
memset_s(&g_files_transfer, sizeof(g_files_transfer), 0, sizeof(g_files_transfer));
}
void tjd_ble_protocol_file_download_transfer_reset(void)
{
static_print_debug("tjd_ble_protocol_file_download_transfer_reset()\n");
memset_s(&g_file_description, sizeof(g_file_description), 0, sizeof(g_file_description));
memset_s(&g_files_transfer, sizeof(g_files_transfer), 0, sizeof(g_files_transfer));
g_dir_description.file_total_type = FileType_MAX;
g_file_description.file_type = FileType_MAX;
}
//断点保存
void tjd_ble_file_breakpoint_save(void)
{
static_print_debug("tjd_ble_file_breakpoint_save()");
if(g_files_transfer.file_status != FileTransfer_NULL && g_files_transfer.operation_file_size != 0 && g_file_description.file_crc32!= 0 && g_file_description.file_name!= NULL){
if(g_files_transfer.breakpoint_en == true || g_file_description.file_size >= 1024*1000) { //使用断点功能
sql_bt_set_breakpoint_info(g_files_transfer.operation_file_size, g_file_description.file_crc32, (char *)g_file_description.file_name);
static_print_debug("sql set breakpoint info, g_files_transfer.operation_file_size : %d, g_file_description.file_crc32 : %x, g_file_description.file_name : %s",
g_files_transfer.operation_file_size, g_file_description.file_crc32, g_file_description.file_name);
}
}
}
//断点恢复
bool tjd_ble_file_breakpoint_recover(FileDescriptionInfo_t *p_description, FileTransferInfo_t *p_transfer)
{
breakpoint_info_t breakpoint_info = {0};
if(!sql_bt_get_breakpoint_info(&breakpoint_info.offset_byte, &breakpoint_info.crc_32,(char *)breakpoint_info.file_name)){
return false;
}
if(strcmp(breakpoint_info.file_name, (const char *)p_description->file_name) != 0){
return false;
}
struct stat file_stat ={0};
if(stat((char *)p_description->file_name, &file_stat) != 0)
{
return false;
}
if(file_stat.st_size != breakpoint_info.offset_byte) {
return false;
}
if(p_description->file_crc32 != breakpoint_info.crc_32) {
return false;
}
static_print_debug("breakpoint info offset_byte : %d, crc_32 : %x, file_name : %s",breakpoint_info.offset_byte, breakpoint_info.crc_32,breakpoint_info.file_name);
p_transfer->operation_file_size = breakpoint_info.offset_byte;
if(p_description->file_type != FileType_MAX && p_description->file_type == g_dir_description.file_total_type) {
p_transfer->operation_total_size += p_transfer->operation_file_size;
}
return true;
}
DirDescriptionInfo_t *tjd_ble_get_dir_description(void)
{
return &g_dir_description;
}
FileTransferInfo_t *tjd_ble_get_transfer_info(void)
{
return &g_files_transfer;
}
//protocol 相关接口 start
void tjd_file_pre_operation(void)
{
struct stat file_stat ={0};
int ret = stat((char *)g_file_description.file_name, &file_stat);
if (ret == 0) {
static_print_debug("file exist");
// 文件存在,删除文件
// ret = tjd_remove_rsvd_part((char *)base_dir, (char *)g_file_description.file_name);
ret = unlink((char *)g_file_description.file_name);
if (ret < 0) {
static_print_error("remove file fail");
}
static_print_debug("remove file success");
}
}
void tjd_ble_protocol_file_description(uint8_t server_id, uint16_t conn_id, uint8_t *write_cb_para, uint16_t len, uint8_t cmd_id)
{
// TODO: app下发文件描述:DOWNLOAD_FILE_DESCRIPTION
static_print_debug("tjd_ble_protocol_file_description():%d", g_files_transfer.file_status);
uint16_t valid_data_len = len - 9;
uint8_t data_index = 4;
uint16_t file_description_len = (write_cb_para[data_index] << 8) | write_cb_para[data_index + 1];
uint16_t rec_file_description_offset = (write_cb_para[data_index + 2] << 8) | write_cb_para[data_index + 3];
valid_data_len = (valid_data_len > file_description_len)? file_description_len : valid_data_len;
uint64_t temp_time = 0;
tjd_driver_rtc_get_ops()->get_timestamp(&temp_time);
if(temp_time - g_files_transfer.operation_last_time > BLE_FILE_TRANSFER_TIME_OUT || g_files_transfer.file_status == FileTransfer_Timeout) {
g_files_transfer.file_status = FileTransfer_NULL;
}
g_files_transfer.operation_last_time = temp_time;
if (g_files_transfer.file_status == FileTransfer_NULL) {
static_print_debug("%s , line is %d", __FUNCTION__, __LINE__);
memset_s(&g_file_decription_context, sizeof(g_file_decription_context), 0, sizeof(g_file_decription_context));
g_file_decription_context.buffer_offset = 0;
g_file_decription_context.expected_seq = file_description_len;
if(g_file_decription_context.buffer == NULL) {
g_file_decription_context.buffer = (uint8_t *)malloc(file_description_len);
}
memset_s(g_file_decription_context.buffer, file_description_len, 0, file_description_len);
g_files_transfer.file_status = FileTransfer_Description;
}
if (g_file_decription_context.buffer_offset != rec_file_description_offset) {
static_print_error("g_file_decription_context.buffer_offset != rec_file_description_offset");
uint8_t data[3] = {0};
data[0] = 0x00;
data[1] = (g_file_decription_context.buffer_offset >> 8) & 0xFF;
data[2] = g_file_decription_context.buffer_offset & 0xFF;
tjd_ble_protocol_send_data(PROTOCOL_FRAME_RSP_HEAD_2, data, sizeof(data), cmd_id, server_id, conn_id);
free(g_file_decription_context.buffer);
g_file_decription_context.buffer = NULL;
g_file_decription_context.buffer_offset = 0;
g_file_decription_context.expected_seq = 0;
return;
}
static_print_debug("file description len : %d, rec_file_description_offset : %d", file_description_len, rec_file_description_offset);
memcpy_s(g_file_decription_context.buffer + rec_file_description_offset, file_description_len - rec_file_description_offset, &write_cb_para[data_index + 4], valid_data_len);
g_file_decription_context.buffer_offset = rec_file_description_offset + valid_data_len;
if (g_files_transfer.file_status == FileTransfer_Description && g_file_decription_context.buffer_offset == file_description_len) {
//文件描述,文件传输信息重置
g_files_transfer.file_status = FileTransfer_DescriptionDone;
memset_s(&g_file_description, sizeof(g_file_description), 0, sizeof(g_file_description));
g_files_transfer.operation_file_size = 0;
// 表盘LTV文件描述如 0301040602123456780603F1F1F1F10804313233343536
// 0301040602123456780603F1F1F1F10804313233343536
for (int i = 0; i < file_description_len;) { // 遍历文件描述
uint8_t len = g_file_decription_context.buffer[i];
uint8_t type = g_file_decription_context.buffer[i + 1];
// static_print_debug("i : %u, type : %u, len : %u", i, type, len);
switch (type) {
case 0x01: { // 文件类型
memcpy_s(&g_file_description.file_type, sizeof(g_file_description.file_type), &g_file_decription_context.buffer[i + 2], len - 2);
static_print_warn("file type : %u", g_file_description.file_type);
break;
}
case 0x02: { // 文件总字节
g_file_description.file_size = (g_file_decription_context.buffer[i + 2] << 24) |
(g_file_decription_context.buffer[i + 3] << 16) |
(g_file_decription_context.buffer[i + 4] << 8) |
g_file_decription_context.buffer[i + 5];
static_print_warn("file total bytes : %u ", g_file_description.file_size);
break;
}
case 0x03: { // 文件crc32
g_file_description.file_crc32 = (g_file_decription_context.buffer[i + 2] << 24) |
(g_file_decription_context.buffer[i + 3] << 16) |
(g_file_decription_context.buffer[i + 4] << 8) |
g_file_decription_context.buffer[i + 5];
static_print_warn("file total crc32 : %08x", g_file_description.file_crc32);
break;
}
case 0x04: { // 文件名称
const char *suffix = (const char *)&g_file_decription_context.buffer[i+2];
if(len - 2 > PROTOCOL_FILE_NAME_LEN_MAX-1){
static_print_error("error:file_name len:%d, len max:%d", (len - 2), (PROTOCOL_FILE_NAME_LEN_MAX-1));
break;
}
switch (g_file_description.file_type) {
case TYPE_LOG: {
static_print_debug("log file");
// strcat(g_rec_file_path, TJD_FS_DIR_UPDATE);
break;
}
case TYPE_FIRMWARE: {
static_print_debug("firmware file");
// 如果文件后缀名是 .fwkpg 则认为是固件文件
// 需存放在“/update/”目录下,否则存放在“/user/tjd_res/”目录下
const char *extension_update = ".fwpkg";
int str_len = len - 2;
int extension_update_len = strlen(extension_update);
// int extension_res_len = strlen(extension_res);
if(str_len >= extension_update_len && strncmp(suffix + str_len - extension_update_len,extension_update,extension_update_len) == 0){
strcat((const char *)g_file_description.file_name, TJD_FS_DIR_UPDATE);
tjd_ota_set_fimrware_size(g_file_description.file_size);
}else {
strcat((const char *)g_file_description.file_name, TJD_FS_DIR_RES);
}
break;
}
case TYPE_RESOURCE_FILES: {
static_print_debug("resource files");
strcat((const char *)g_file_description.file_name, TJD_FS_DIR_RES);
break;
}
case TYPE_MULTILINGUAL_DOC: {
static_print_debug("multilingual doc file");
// strcat(g_rec_file_path, TJD_FS_DIR_DOC);
break;
}
case TYPE_DIAL_DOC: {
static_print_debug("dial doc file");
strcat((const char *)g_file_description.file_name, TJD_FS_DIR_WF);
break;
}
case TYPE_PICTURE: {
static_print_debug("picture file");
strcat((const char *)g_file_description.file_name, TJD_FS_DIR_ALBUM);
break;
}
case TYPE_VIDEO: {
static_print_debug("video file");
strcat((const char *)g_file_description.file_name, TJD_FS_DIR_ALBUM);
break;
}
case TYPE_E_BOOK: {
static_print_debug("e-book file");
strcat((const char *)g_file_description.file_name, TJD_FS_DIR_BOOK);
break;
}
case TYPE_MUSIC: {
static_print_debug("music file");
strcat((const char *)g_file_description.file_name, TJD_FS_DIR_MUSIC);
break;
}
case TYPE_AIDIAL_ORIGINAL: {
static_print_debug("aidial original file");
strcat((const char *)g_file_description.file_name, TJD_FS_DIR_WFP);
if(access(TJD_FS_DIR_WFP, 0) != 0){
mkdir(TJD_FS_DIR_WFP, 0777);
static_print_debug("mkdir /user/tjd_wfp dirent success");
}
break;
}
case TYPE_AIDIAL_THUMBNAIL: {
static_print_debug("aidial thumbnail file");
strcat((const char *)g_file_description.file_name, TJD_FS_DIR_WFP);
if(access(TJD_FS_DIR_WFP, 0) != 0){
mkdir(TJD_FS_DIR_WFP, 0777);
static_print_debug("mkdir /user/tjd_wfp dirent success");
}
break;
}
case TYPE_AIDIAL_PREVIEW: {
static_print_debug("aidial preview file");
strcat((const char *)g_file_description.file_name, TJD_FS_DIR_WFP);
if(access(TJD_FS_DIR_WFP, 0) != 0){
mkdir(TJD_FS_DIR_WFP, 0777);
static_print_debug("mkdir /user/tjd_wfp dirent success");
}
break;
}
case TYPE_GPS: {
static_print_debug("gps file");
strcat((const char *)g_file_description.file_name, TJD_FS_DIR_GPS_BAT);
//如果 ""/user/tjd_gpsbat"" 目录不存在,则创建该目录
if(access(TJD_FS_DIR_GPS_BAT, 0) != 0){
mkdir(TJD_FS_DIR_GPS_BAT, 0777);
static_print_debug("mkdir /user/tjd_gpsbat dirent success");
}
break;
}
case TYPE_DIAL_DIAGRAM: {
static_print_debug("dial diagram file");
strcat((const char *)g_file_description.file_name, TJD_FS_DIR_WFC);
//如果 ""/user/tjd_wfc"" 目录不存在,则创建该目录
if(access(TJD_FS_DIR_WFC, 0) != 0){
mkdir(TJD_FS_DIR_WFC, 0777);
static_print_debug("mkdir /user/tjd_wfc dirent success");
}
break;
}
case TYPE_DIAL_MULTIGRAPH: {
static_print_debug("dial multigraph file");
strcat((const char *)g_file_description.file_name, TJD_FS_DIR_WFC);
//如果 ""/user/tjd_wfc"" 目录不存在,则创建该目录
if(access(TJD_FS_DIR_WFC, 0) != 0){
mkdir(TJD_FS_DIR_WFC, 0777);
static_print_debug("mkdir /user/tjd_wfc dirent success");
}
break;
}
case TYPE_DIAL_VIDEO: {
static_print_debug("dial video file");
strcat((const char *)g_file_description.file_name, TJD_FS_DIR_WFC);
//如果 ""/user/tjd_wfc"" 目录不存在,则创建该目录
if(access(TJD_FS_DIR_WFC, 0) != 0){
mkdir(TJD_FS_DIR_WFC, 0777);
static_print_debug("mkdir /user/tjd_wfc dirent success");
}
break;
}
case TYPE_DIAL_PREVIEW: {
static_print_debug("dial preview file");
strcat((const char *)g_file_description.file_name, TJD_FS_DIR_WFC);
//如果 ""/user/tjd_wfc"" 目录不存在,则创建该目录
if(access(TJD_FS_DIR_WFC, 0) != 0){
mkdir(TJD_FS_DIR_WFC, 0777);
static_print_debug("mkdir /user/tjd_wfc dirent success");
}
break;
}
case TYPE_JS_APP: {
static_print_debug("js app file");
strcat((const char *)g_file_description.file_name, TJD_FS_DIR_JS);
//如果 "/system/tjd_extapp"" 目录不存在,则创建该目录
if(access(TJD_FS_DIR_JS, 0) != 0){
mkdir(TJD_FS_DIR_JS, 0777);
static_print_debug("mkdir /system/tjd_extapp dirent success");
}
break;
}
default: {
static_print_error("unknown file type");
break;
}
}
/*
1、一文件名不能包括#号。
2、如果文件名中出#号说明文件完整路径要被重定义。将"#"替换为"/"就是真实目标路径。OTA时方便全固件升级
3、例APP下发文件名为user#log#abc.txt=user/log/abc.txt
*/
if(strnstr(suffix, "#", len - 2) == NULL){
strcat((char *)g_file_description.file_name, "/");
strncat((char *)g_file_description.file_name, (char *)&g_file_decription_context.buffer[i + 2], len - 2);
} else {
g_file_description.file_name[0] = 0;
strncat((char *)g_file_description.file_name, (char *)&g_file_decription_context.buffer[i + 2], len - 2);
char * ret = strstr((char *)g_file_description.file_name, "#");
while(ret != NULL){
memset(ret, '/', 1);
ret = strstr(ret + 1, "#");
}
}
static_print_warn("file file name : %s", g_file_description.file_name);
break;
}
// case 0x05: { // 文件用途枚举
// memcpy_s(&g_file_description.file_usage, sizeof(g_file_description.file_usage),
// &g_file_decription_context.buffer[i + 2], len - 2);
// static_print_debug("file purpose : %u", g_file_description.file_usage);
// break;
// }
case 0x06: { // 图片宽度 图片高度
memcpy_s(&g_file_description.pictures_width, sizeof(g_file_description.pictures_width),
&g_file_decription_context.buffer[i + 2], 2);
memcpy_s(&g_file_description.pictures_height, sizeof(g_file_description.pictures_height),
&g_file_decription_context.buffer[i + 4], 2);
static_print_warn("image width : %u, height : %u", g_file_description.pictures_width,
g_file_description.pictures_height);
break;
}
case 0x07: { // 视频宽度 视频高度
memcpy_s(&g_file_description.video_width, sizeof(g_file_description.video_width),
&g_file_decription_context.buffer[i + 2], 2);
memcpy_s(&g_file_description.video_height, sizeof(g_file_description.video_height),
&g_file_decription_context.buffer[i + 4], 2);
static_print_warn("video width : %u, height : %u", g_file_description.video_width,
g_file_description.video_height);
break;
}
default: {
static_print_error("unknown type : %u", type);
break;
}
}
i += len;
}
uint8_t data[3] = {0};
data[0] = 0x02;
data[1] = (g_file_decription_context.buffer_offset >> 8) & 0xFF;
data[2] = g_file_decription_context.buffer_offset & 0xFF;
tjd_ble_protocol_send_data(PROTOCOL_FRAME_RSP_HEAD_2, data, sizeof(data), cmd_id, server_id, conn_id);
free(g_file_decription_context.buffer);
g_file_decription_context.buffer = NULL;
g_file_decription_context.buffer_offset = 0;
g_file_decription_context.expected_seq = 0;
return;
} else {
uint8_t data[3] = {0};
data[0] = 0x01;
data[1] = (g_file_decription_context.buffer_offset >> 8) & 0xFF;
data[2] = g_file_decription_context.buffer_offset & 0xFF;
tjd_ble_protocol_send_data(PROTOCOL_FRAME_RSP_HEAD_2, data, sizeof(data), cmd_id, server_id, conn_id);
return;
}
}
void tjd_ble_protocol_file_start(uint8_t server_id, uint16_t conn_id, uint8_t *write_cb_para, uint16_t len, uint8_t cmd_id)
{
static_print_debug("send file start:%d", g_files_transfer.file_status);
if(g_files_transfer.file_status == FileTransfer_DescriptionDone)
{
g_files_transfer.file_status = FileTransfer_Start;
}
if(g_files_transfer_Callback[g_file_description.file_type].start)
{
g_files_transfer_Callback[g_file_description.file_type].start(&g_file_description, &g_files_transfer);
}
// 电量检测 /* 待完善 */
// 存在检测
// 如果CRC与size一致则发送02直接跳过当前文件传输否则发送01等待app下发文件数据
static_print_debug("g_file_description.file_name: %s", g_file_description.file_name);
struct stat file_stat = {0};
int stat_ret = stat((char *)g_file_description.file_name,&file_stat);
static_print_debug("access ret is %d", stat_ret);
if(stat_ret == 0){
uint32_t crc32_local = calculateFileCRC32((char *)g_file_description.file_name, g_file_description.file_size);
static_print_debug("%s , line is %d", __FUNCTION__, __LINE__);
uint32_t crc32_remote = g_file_description.file_crc32;
static_print_debug("crc32_local is %08x, crc32_remote is %08x", crc32_local, crc32_remote);
if (crc32_local == crc32_remote && g_file_description.file_size == file_stat.st_size) {
static_print_debug("crc32 is same, send 02 to skip current file");
g_files_transfer.operation_file_size += g_file_description.file_size;
if(g_dir_description.file_total_type == g_file_description.file_type) {
g_files_transfer.operation_total_size += g_file_description.file_size;
g_files_transfer.operation_total_number++;
}
g_files_transfer.file_status = FileTransfer_NULL;
static_print_debug("files transfer end: total_size=%d,file_size=%d", g_files_transfer.operation_total_size, g_files_transfer.operation_file_size);
uint8_t data[] = {0x02};
tjd_ble_protocol_send_data(PROTOCOL_FRAME_RSP_HEAD_2, data, sizeof(data), DOWNLOAD_FILE_SRART, server_id, conn_id);
return;
}
}
//空间检测
struct statfs fs_stat = {0};
char fs_volume[64] = {0};
char *str_ret = NULL;
if(g_file_description.file_name[0] == '/'){
str_ret = strnstr((const char *)&g_file_description.file_name[1], "/", PROTOCOL_FILE_NAME_LEN_MAX);
if(str_ret) {
memcpy_s(fs_volume, sizeof(fs_volume), g_file_description.file_name, (size_t)((uint32_t)str_ret - (uint32_t)g_file_description.file_name));
}
} else {
str_ret = strnstr((const char *)g_file_description.file_name, "/", PROTOCOL_FILE_NAME_LEN_MAX);
if(str_ret) {
memcpy_s(fs_volume, sizeof(fs_volume), g_file_description.file_name, (size_t)((uint32_t)str_ret - (uint32_t)g_file_description.file_name));
}
}
if (statfs(fs_volume, &fs_stat) != 0) {
static_print_error("error:statfs() = null");
}
static_print_debug("fs_stat.f_bfree :[%s] %ld-%ld", fs_volume, fs_stat.f_bfree, fs_stat.f_bsize);
if (fs_stat.f_bfree >= FS_NODE_INFO_SPACE) {
fs_stat.f_bfree = fs_stat.f_bfree - FS_NODE_INFO_SPACE;
} else {
fs_stat.f_bfree = 0;
}
if(stat_ret != 0) {
static_print_debug("file stat() = null:[%s]", g_file_description.file_name);
} else {
uint32_t file_blocks = file_stat.st_size / file_stat.st_blksize ;
fs_stat.f_bfree += file_blocks;
static_print_debug("file stat() = ok:[%s] st_size=%ld", g_file_description.file_name, file_stat.st_size);
}
uint32_t free_space = fs_stat.f_bfree * fs_stat.f_bsize;
if ((free_space < g_file_description.file_size) && g_file_description.file_size != 0 ) {
static_print_error("not enough space! free space : %d , file size : %d",free_space, g_file_description.file_size);
uint8_t data[] = {0x03};
tjd_ble_protocol_send_data(PROTOCOL_FRAME_RSP_HEAD_2, data, sizeof(data), DOWNLOAD_FILE_SRART, server_id, conn_id);
return;
}
//正常开始
// gap_conn_param_update_t conn_param = { 0 };
// conn_param.conn_handle = conn_id; /* param 0: conn_handle */
// conn_param.interval_min = 6; /* param 1: interval_min */
// conn_param.interval_max = 10; /* param 2: interval_max */
// conn_param.slave_latency = 0; /* param 3: slave_latency */
// conn_param.timeout_multiplier = 300; /* param 4: timeout_multiplier */
// errcode_t update_ret = gap_ble_connect_param_update(&conn_param);
// static_print_debug("gap ble update connection parameters ret: %u", update_ret);
uint8_t data[] = {0x01};
tjd_ble_protocol_send_data(PROTOCOL_FRAME_RSP_HEAD_2, data, sizeof(data), DOWNLOAD_FILE_SRART, server_id, conn_id);
}
void tjd_ble_protocol_file_data(uint8_t server_id, uint16_t conn_id, uint8_t *write_cb_para, uint16_t len ,uint8_t cmd_id)
{
int ret = 0;
uint16_t write_len = write_cb_para[1] << 8 | write_cb_para[2];
uint32_t remaining_size = g_file_description.file_size - g_files_transfer.operation_file_size;
uint16_t data_len = write_len - 9;
uint16_t valid_data_len = len - 9;
uint32_t cmd_offset = write_cb_para[4];
cmd_offset <<= 8;
cmd_offset += write_cb_para[5];
cmd_offset <<= 8;
cmd_offset += write_cb_para[6];
cmd_offset <<= 8;
cmd_offset += write_cb_para[7];
tjd_service_timer_cnt = 0;
tjd_driver_rtc_get_ops()->get_timestamp(&g_files_transfer.operation_last_time);
if(g_files_transfer.file_status == FileTransfer_Start)
{
g_files_transfer.file_status = FileTransfer_Data;
tjd_task_service_check_timeout_start();
static_print_debug("write_len : %d, remaining_size : %d, data_len : %d, valid_data_len : %d, cmd_offset=%d\n", write_len, remaining_size, data_len, valid_data_len, cmd_offset);
if(tjd_ble_file_breakpoint_recover(&g_file_description, &g_files_transfer) == false) //无断点内容
{
tjd_file_pre_operation();
goto ACCEPTFILEDATA;
} else {
if(cmd_offset == g_files_transfer.operation_file_size) {
goto ACCEPTFILEDATA;
}
uint8_t resp_data[9] = {0};
resp_data[0] = 0x02;
resp_data[1] = g_files_transfer.operation_file_size >> 24;
resp_data[2] = (g_files_transfer.operation_file_size >> 16) & 0xFF;
resp_data[3] = (g_files_transfer.operation_file_size >> 8) & 0xFF;
resp_data[4] = g_files_transfer.operation_file_size & 0xFF;
resp_data[5] = g_files_transfer.operation_file_size >> 24;
resp_data[6] = (g_files_transfer.operation_file_size >> 16) & 0xFF;
resp_data[7] = (g_files_transfer.operation_file_size >> 8) & 0xFF;
resp_data[8] = g_files_transfer.operation_file_size & 0xFF;
// (uint32_t *)(&resp_data[1]) = g_files_transfer.operation_file_size;
// (uint32_t *)(&resp_data[5]) = download_breakpoint_resume_offset;
tjd_ble_protocol_send_data(PROTOCOL_FRAME_RSP_HEAD_2, resp_data, sizeof(resp_data), cmd_id, server_id, conn_id);
return;
}
}else if(g_files_transfer.file_status == FileTransfer_Data) {
ACCEPTFILEDATA:
if(cmd_offset != g_files_transfer.operation_file_size) {
static_print_error("error:g_files_transfer.operation_file_size:%d,cmd_offset:%d", g_files_transfer.operation_file_size, cmd_offset);
uint8_t resp_data[9] = {0};
resp_data[0] = 0x02;
resp_data[1] = g_files_transfer.operation_file_size >> 24;
resp_data[2] = (g_files_transfer.operation_file_size >> 16) & 0xFF;
resp_data[3] = (g_files_transfer.operation_file_size >> 8) & 0xFF;
resp_data[4] = g_files_transfer.operation_file_size & 0xFF;
resp_data[5] = g_files_transfer.operation_file_size >> 24;
resp_data[6] = (g_files_transfer.operation_file_size >> 16) & 0xFF;
resp_data[7] = (g_files_transfer.operation_file_size >> 8) & 0xFF;
resp_data[8] = g_files_transfer.operation_file_size & 0xFF;
tjd_ble_protocol_send_data(PROTOCOL_FRAME_RSP_HEAD_2, resp_data, sizeof(resp_data), cmd_id, server_id, conn_id);
} else {
if(data_len > 0){
if(remaining_size <= data_len){
ret = tjd_fs_api_file_append((const char *)g_file_description.file_name, write_cb_para + 8, remaining_size);
g_files_transfer.operation_file_size += remaining_size;
if(g_dir_description.file_total_type == g_file_description.file_type) {
g_files_transfer.operation_total_size += remaining_size;
}
}else{
ret = tjd_fs_api_file_append((const char *)g_file_description.file_name, write_cb_para + 8, len - 9);
g_files_transfer.operation_file_size += valid_data_len;
if(g_dir_description.file_total_type == g_file_description.file_type) {
g_files_transfer.operation_total_size += valid_data_len;
}
}
if(g_files_transfer_Callback[g_file_description.file_type].data)
{
g_files_transfer_Callback[g_file_description.file_type].data(&g_file_description, &g_files_transfer);
}
uint8_t resp_data[9] = {0};
resp_data[0] = 0x01;
resp_data[1] = g_files_transfer.operation_file_size >> 24;
resp_data[2] = (g_files_transfer.operation_file_size >> 16) & 0xFF;
resp_data[3] = (g_files_transfer.operation_file_size >> 8) & 0xFF;
resp_data[4] = g_files_transfer.operation_file_size & 0xFF;
resp_data[5] = g_files_transfer.operation_file_size >> 24;
resp_data[6] = (g_files_transfer.operation_file_size >> 16) & 0xFF;
resp_data[7] = (g_files_transfer.operation_file_size >> 8) & 0xFF;
resp_data[8] = g_files_transfer.operation_file_size & 0xFF;
tjd_ble_protocol_send_data(PROTOCOL_FRAME_RSP_HEAD_2, resp_data, sizeof(resp_data), cmd_id, server_id, conn_id);
}else{
static_print_error("error: valid_data_len is In vain");
tjd_file_transfer_err_operation();
uint8_t resp_data[9] = {0};
resp_data[0] = 0x00;
resp_data[1] = g_files_transfer.operation_file_size >> 24;
resp_data[2] = (g_files_transfer.operation_file_size >> 16) & 0xFF;
resp_data[3] = (g_files_transfer.operation_file_size >> 8) & 0xFF;
resp_data[4] = g_files_transfer.operation_file_size & 0xFF;
resp_data[5] = g_files_transfer.operation_file_size >> 24;
resp_data[6] = (g_files_transfer.operation_file_size >> 16) & 0xFF;
resp_data[7] = (g_files_transfer.operation_file_size >> 8) & 0xFF;
resp_data[8] = g_files_transfer.operation_file_size & 0xFF;
tjd_ble_protocol_send_data(PROTOCOL_FRAME_RSP_HEAD_2, resp_data, sizeof(resp_data), cmd_id, server_id, conn_id);
}
}
// static_print_debug("send resp data");
if (g_files_transfer.operation_file_size == g_file_description.file_size) {
static_print_debug("files transfer end: total_size=%d,file_size=%d", g_files_transfer.operation_total_size, g_files_transfer.operation_file_size);
static_print_debug("file_type : %d",g_file_description.file_type);
g_files_transfer.file_status = FileTransfer_NULL;
if(g_dir_description.file_total_type == g_file_description.file_type) {
g_files_transfer.operation_total_number++;
}
}
}else{
static_print_error("error:g_files_transfer.file_status:%d,file:%s", g_files_transfer.file_status, g_file_description.file_name);
}
}
void tjd_ble_protocol_file_end(uint8_t server_id, uint16_t conn_id, uint8_t *write_cb_para, uint16_t len, uint8_t cmd_id)
{
static_print_debug("tjd_ble_protocol_file_end():%d", g_files_transfer.file_status);
if(g_files_transfer_Callback[g_file_description.file_type].end)
{
g_files_transfer_Callback[g_file_description.file_type].end(&g_file_description, &g_files_transfer);
}
g_files_transfer.file_status = FileTransfer_NULL;
// g_file_transport_buf = NULL;
// memset(&g_file_description, 0, sizeof(g_file_description));
// gap_conn_param_update_t conn_param = { 0 };
// conn_param.conn_handle = conn_id; /* param 0: conn_handle */
// conn_param.interval_min = 16; /* param 1: interval_min */
// conn_param.interval_max = 32; /* param 2: interval_max */
// conn_param.slave_latency = 50; /* param 3: slave_latency */
// conn_param.timeout_multiplier = 300; /* param 4: timeout_multiplier */
// errcode_t ret = gap_ble_connect_param_update(&conn_param);
// static_print_debug("gap ble update connection parameters ret: %u", ret);
uint8_t data[] = {0x01};
tjd_ble_protocol_send_data(PROTOCOL_FRAME_RSP_HEAD_2, data, sizeof(data), DOWNLOAD_FILE_END_DATA, server_id, conn_id);
//sql_bt_set_breakpoint_info(0, 0, " ");
}