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

490 lines
23 KiB
C
Raw Permalink 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-12
*--------------------------------------------------------------------------*/
#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 "broadcast_feature.h"
#include "ble_protocol_file_upload.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 UPLOAD_FILE_TASK_SIZE 0x1200
#define UPLOAD_FILE_TASK_PRIO 20
#define UPLOAD_FILE_TIMEOUT_MS 3000
FileDescriptionInfo_t g_files_upload_description = {0};
FileTransferInfo_t g_files_upload_transfer = {0};
FileUploadEndEnum g_state_temp = UPLOAD_END_SUCCEED;
typedef void (*file_transfer_end_callback_t)(FileUploadEndEnum value);
typedef void (*file_transfer_start_callback_t)(uint8_t cmd_ret);
typedef struct {
file_transfer_start_callback_t start;
file_transfer_end_callback_t end;
} FileTransferCallback_t;
FileTransferCallback_t g_files_upload_transfer_Callback[FileType_MAX] = {0};
osal_task *g_tjd_ble_upload_file_task_handle = NULL;
static osal_semaphore g_tjd_ble_upload_file_mutex = {0};
extern void file_upload_callback_start_type_recode(uint8_t cmd_ret);
extern void file_upload_callback_end_type_recode(FileUploadEndEnum value);
extern void file_upload_callback_start_type_sport_record(uint8_t cmd_ret);
extern void file_upload_callback_end_type_sport_record(FileUploadEndEnum value);
extern void file_upload_callback_start_type_js_app_list(uint8_t cmd_ret);
extern void file_upload_callback_end_type_js_app_list(FileUploadEndEnum value);
void tjd_ble_protocol_file_upload_callback_init(void)
{
static_print_debug("tjd_ble_protocol_file_upload_callback_init():...........\n");
memset_s(g_files_upload_transfer_Callback, sizeof(g_files_upload_transfer_Callback), 0, sizeof(g_files_upload_transfer_Callback));
g_files_upload_transfer_Callback[TYPE_SPORT_RECORD].start = file_upload_callback_start_type_sport_record;
g_files_upload_transfer_Callback[TYPE_SPORT_RECORD].end = file_upload_callback_end_type_sport_record;
g_files_upload_transfer_Callback[TYPE_RECODE].start = file_upload_callback_start_type_recode;
g_files_upload_transfer_Callback[TYPE_RECODE].end = file_upload_callback_end_type_recode;
// g_files_upload_transfer_Callback[TYPE_JS_APP_LIST].start = file_upload_callback_start_type_js_app_list; //处理掩码
// g_files_upload_transfer_Callback[TYPE_JS_APP_LIST].end = file_upload_callback_end_type_js_app_list; //处理掩码
}
//基础接口
static void upload_file_decription(FileDescriptionInfo_t *file_description_packet)
{
static_print_debug("upload file description");
uint16_t file_description_len = 17;
static_print_debug("file_description_len: %d", file_description_len);
// file_description_len -= sizeof(file_description_packet->file_name);
// static_print_debug("file_description_len: %d", file_description_len);
uint8_t lt_len = 2 * 4; // 2 : type + len 6: FileDescriptionPacket的字段个数
switch (file_description_packet->file_type) {
case TYPE_PICTURE:
file_description_len -= sizeof(uint16_t) * 2;
// lt_len -= 2; // 2 : type + len
break;
case TYPE_VIDEO:
file_description_len -= sizeof(uint16_t) * 2;
// lt_len -= 2; // 2 : type + len
break;
default:
file_description_len -= sizeof(uint16_t) * 4;
// lt_len -= 4; // 4 : 2 个 type + len
break;
}
// file_description_packet->file_name = "/user/tjd_res/2000-8-4.mp3"
// 从file_description_packet->file_name 提取到 2000-8-4.mp3
// 怎么计算 file_name 的长度
static_print_debug("file_description_packet->file_name: %s", file_description_packet->file_name);
char *file_name = strrchr((const char *)(file_description_packet->file_name), '/') + 1;
static_print_debug("file_name: %s", file_name);
static_print_debug("strlen(file_name) : %d", strlen(file_name));
// file_name++; // 跳过'/'
file_description_len += strlen(file_name);
static_print_debug("file_description_len: %d", file_description_len);
// if (file_description_packet->file_usage) {
// file_description_len -= sizeof(uint16_t);
// }
file_description_len += lt_len;
static_print_debug("file_description_len: %d", file_description_len);
uint8_t *file_description_data = malloc(file_description_len);
memset_s(file_description_data, file_description_len, 0, file_description_len);
int data_index = 0;
file_description_data[data_index++] = sizeof(file_description_packet->file_type) + 2;
file_description_data[data_index++] = 0x01;
file_description_data[data_index++] = file_description_packet->file_type;
file_description_data[data_index++] = sizeof(file_description_packet->file_size) + 2;
file_description_data[data_index++] = 0x02;
file_description_data[data_index++] = file_description_packet->file_size >> 24;
file_description_data[data_index++] = file_description_packet->file_size >> 16;
file_description_data[data_index++] = file_description_packet->file_size >> 8;
file_description_data[data_index++] = file_description_packet->file_size & 0xff;
file_description_data[data_index++] = sizeof(file_description_packet->file_crc32) + 2;
file_description_data[data_index++] = 0x03;
file_description_data[data_index++] = file_description_packet->file_crc32 >> 24;
file_description_data[data_index++] = file_description_packet->file_crc32 >> 16;
file_description_data[data_index++] = file_description_packet->file_crc32 >> 8;
file_description_data[data_index++] = file_description_packet->file_crc32 & 0xff;
file_description_data[data_index++] = strlen(file_name) + 2;
file_description_data[data_index++] = 0x04;
memcpy_s(&file_description_data[data_index], strlen(file_name), file_name, strlen(file_name));
data_index += strlen(file_name);
uint32_t mtu_size = tjd_ble_get_mtu_size() - 3 > 509 ? 509 : tjd_ble_get_mtu_size() - 3;
// if (mtu_size < file_description_len) {
// // 长包分包
uint16_t sub_package_size = mtu_size - 9; // 9是包头长度包括末尾crc8
uint16_t sub_package_count = file_description_len / sub_package_size;
if (file_description_len % sub_package_size) {
sub_package_count++; // 如果有余数,则多一包
}
uint16_t sub_package_index = 0;
uint16_t sub_package_offset = 0;
uint8_t *sub_package_data = malloc(sub_package_size + 9); // 9是包头长度包括末尾crc8
// memset_s(sub_package_data, sub_package_size + 9, 0, sub_package_size + 9);
while (sub_package_index < sub_package_count) {
memset_s(sub_package_data, sub_package_size + 9, 0, sub_package_size + 9);
uint16_t sub_package_length = mtu_size;
if (sub_package_index == sub_package_count - 1) { // 最后一包
sub_package_length = file_description_len - sub_package_offset + 9; // 9是包头长度包括末尾crc8
}
int index = 0;
sub_package_data[index++] = PROTOCOL_RES_FRAME_HEAD_2;
// *(uint16_t *)(&sub_package_data[index]) = sub_package_length >> 8 | (sub_package_length & 0xff);
// index += sizeof(uint16_t);
sub_package_data[index++] = sub_package_length >> 8;
sub_package_data[index++] = sub_package_length & 0xff;
sub_package_data[index++] = UPLOAD_FILE_DESCRIPTION;
// *(uint16_t *)(&sub_package_data[index]) = file_description_len >> 8 | (file_description_len & 0xff);
sub_package_data[index++] = file_description_len >> 8;
sub_package_data[index++] = file_description_len & 0xff;
// file_description_data[4] = file_description_len & 0xFF;
// index += sizeof(uint16_t);
// *(uint16_t *)(&sub_package_data[index]) = sub_package_offset >> 8 | (sub_package_offset & 0xff);
sub_package_data[index++] = sub_package_offset >> 8;
sub_package_data[index++] = sub_package_offset & 0xff;
// memcpy_s(&file_description_data[7], sizeof(data), file_description_packet, file_description_len);
// index += sizeof(uint16_t);
memcpy_s(&sub_package_data[index], sub_package_length - 9, &file_description_data[sub_package_offset],
sub_package_length - 9);
index += sub_package_length - 9;
sub_package_data[index] = do_crc(sub_package_data, sub_package_length - 1);
for(int i = 0 ; i < sub_package_length; i++){
static_print_info("%02x ",sub_package_data[i]);
if(i % 10 == 0){
static_print_info("\r\n");
}
}
static_print_info("\r\n");
gatt_send_response(sub_package_data, sub_package_length,gatt_server_id,g_server_conn_id);
sub_package_index++;
sub_package_offset += sub_package_length - 9;
//等待信号量
/* wait for trans */
if (osal_sem_down_timeout(&g_tjd_ble_upload_file_mutex, UPLOAD_FILE_TIMEOUT_MS) != OSAL_SUCCESS) {
//摧毁上传文件描述信号量
// osal_kthread_destroy(g_tjd_ble_upload_file_task_handle,1);
osal_sem_destroy(&g_tjd_ble_upload_file_mutex);
if(g_files_upload_transfer_Callback[g_files_upload_description.file_type].start)
{
g_files_upload_transfer_Callback[g_files_upload_description.file_type].start(0);//通知发送失败
}
break;
}
}
free(sub_package_data);
sub_package_data = NULL;
free(file_description_data);
file_description_data = NULL;
}
void tjd_ble_protocol_upload_file_description(const char *file_name, uint8_t file_type)
{
//主动发起
static_print_debug("upload file:[%s]file_type=%d", file_name, file_type);
if(file_name == NULL){
static_print_error("file name is null");
return;
}
//初始化信号量
(void)memset_s((osal_semaphore *)&(g_tjd_ble_upload_file_mutex), sizeof(g_tjd_ble_upload_file_mutex), 0, sizeof(g_tjd_ble_upload_file_mutex));
(void)osal_sem_init(&g_tjd_ble_upload_file_mutex,0);
memset(&g_files_upload_description, 0, sizeof(g_files_upload_description));
memset(&g_files_upload_transfer, 0, sizeof(g_files_upload_transfer));
g_files_upload_description.file_type = file_type;
g_files_upload_transfer.operation_file_size = 0;
g_files_upload_transfer.file_status = FileTransfer_NULL;
//读取文件 获取文件大小 文件crc32 发送文件描述信息
memcpy(g_files_upload_description.file_name, file_name, strlen(file_name));
g_files_upload_description.file_size = tjd_ble_get_file_size((const char *)file_name);
g_files_upload_description.file_crc32 = calculateFileCRC32(file_name, &g_files_upload_description.file_size);
upload_file_decription(&g_files_upload_description);
}
void tjd_ble_protocol_file_upload_description_recover_handle(uint8_t server_id, uint16_t conn_id, uint8_t *write_cb_para, uint16_t len, uint8_t cmd_id)
{
//APP回复处理
static_print_debug("tjd_ble_protocol_upload_file_description_recover_handle()");
osal_sem_up(&g_tjd_ble_upload_file_mutex);
if (write_cb_para[4] == 0x02) {
tjd_ble_protocol_file_upload_start(server_id, conn_id);
} else {
static_print_debug("upload file description faile");
if(g_files_upload_transfer_Callback[g_files_upload_description.file_type].start)
{
g_files_upload_transfer_Callback[g_files_upload_description.file_type].start(0);//通知发送失败
}
}
}
void tjd_ble_protocol_file_upload_start(uint8_t server_id, uint16_t conn_id)
{
static_print_debug("tjd_ble_protocol_file_upload_start()");
uint8_t data[5] = {0};
data[0] = 0x5B;
data[1] = 0x00;
data[2] = 0x05;
data[3] = UPLOAD_FILE_SRART;
data[4] = do_crc(data, 4);
gatt_send_response(data, sizeof(data), server_id, conn_id);
}
void tjd_ble_protocol_file_upload_start_recover_handle(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");
if (write_cb_para[4] == 0x01) {
//开线程传输文件
g_tjd_ble_upload_file_task_handle = osal_kthread_create((osal_kthread_handler)tjd_ble_protocol_file_upload_data, NULL,
"upload_file", UPLOAD_FILE_TASK_SIZE);
if (g_tjd_ble_upload_file_task_handle == NULL) {
// osal_msg_queue_is_full(g_app_queue);
static_print_error("create upload file thread fail!");
}
osal_kthread_set_priority(g_tjd_ble_upload_file_task_handle, UPLOAD_FILE_TASK_PRIO);
}
if(g_files_upload_transfer_Callback[g_files_upload_description.file_type].start)
{
g_files_upload_transfer_Callback[g_files_upload_description.file_type].start(write_cb_para[4]);
}
}
int tjd_ble_protocol_file_upload_data(void * arg)
{
static_print_debug("tjd_ble_protocol_file_upload_data");
g_state_temp = UPLOAD_END_SUCCEED;
// 分块读取文件数据传输文件
const size_t bufferSize = 4105; // 缓冲区大小,可根据实际情况调整
uint8_t *buffer = malloc(bufferSize);
if (buffer == NULL) {
static_print_error("malloc failed");
g_state_temp = UPLOAD_END_SYS;
}
g_files_upload_transfer.operation_file_size = 0;
uint32_t mtu_size = tjd_ble_get_mtu_size() - 3 > 509 ? 509 : tjd_ble_get_mtu_size() - 3;;
size_t read_size = bufferSize - 9;
uint8_t * tmp_buffer = malloc(mtu_size);
if(tmp_buffer == NULL){
static_print_error("malloc failed");
g_state_temp = UPLOAD_END_SYS;
}
osal_sem_up(&g_tjd_ble_upload_file_mutex);//首次手动释放信号信量后续收到APP回复时释放信号信量
// 长包分包传输
while(g_files_upload_transfer.operation_file_size < g_files_upload_description.file_size) {
if(g_state_temp == UPLOAD_END_USER || g_state_temp == UPLOAD_END_SYS )
{
break;
}
if(g_files_upload_transfer.operation_file_size == g_files_upload_description.file_size){
g_state_temp = UPLOAD_END_SUCCEED;
break;
}
//等待信号量
static_print_debug("wait for semaphore ...");
if (osal_sem_down_timeout(&g_tjd_ble_upload_file_mutex, UPLOAD_FILE_TIMEOUT_MS) != OSAL_SUCCESS) {
//上超时退出
static_print_warn("osal_sem_down_timeout!");
g_state_temp = UPLOAD_END_TIMEOUT;
break;
}
uint16_t sub_package_offset = 0;
uint16_t sub_package_index = 0;
uint16_t sub_package_size = mtu_size; // 509是包体大小可根据实际情况调整
uint16_t sub_package_count = bufferSize / mtu_size;
memset_s(buffer, bufferSize, 0, bufferSize);
int index = 0;
buffer[index++] = PROTOCOL_RES_FRAME_HEAD_2;
buffer[index++] = (bufferSize >> 8) & 0xFF;
buffer[index++] = (bufferSize & 0xFF);
buffer[index++] = UPLOAD_FILE_DATA;
buffer[index++] = ((g_files_upload_transfer.operation_file_size + sub_package_offset) >> 24) & 0xFF;
buffer[index++] = ((g_files_upload_transfer.operation_file_size + sub_package_offset) >> 16) & 0xFF;
buffer[index++] = ((g_files_upload_transfer.operation_file_size + sub_package_offset) >> 8) & 0xFF;
buffer[index++] = (g_files_upload_transfer.operation_file_size + sub_package_offset) & 0xFF;
// tjd_fs_api_file_load((const char *)(g_file_description_packet.file_name), g_files_upload_transfer.operation_file_size, buffer, read_size);
if (g_files_upload_transfer.operation_file_size + bufferSize > g_files_upload_description.file_size) {
read_size = g_files_upload_description.file_size - g_files_upload_transfer.operation_file_size;
sub_package_count = read_size / mtu_size;
buffer[1] = ((read_size + 9) >> 8) & 0xFF;
buffer[2] = (read_size + 9) & 0xFF;
}
tjd_ble_load_file_data((const char *)(g_files_upload_description.file_name), g_files_upload_transfer.operation_file_size, buffer + index, read_size);
index += read_size;
buffer[index] = do_crc(buffer, index);
static_print_debug("read_size : %d, g_files_upload_transfer.operation_file_size: %d, file_size: %d, index: %d", read_size, g_files_upload_transfer.operation_file_size, index, g_files_upload_description.file_size);
while (sub_package_index <= sub_package_count) {
static_print_debug("sub_package_index %d , sub_package_count %d " , sub_package_index , sub_package_count);
static_print_debug("sub_package_offset %d , sub_package_size %d " , sub_package_offset , sub_package_size);
if (sub_package_index == sub_package_count && sub_package_index != 0) { // 最后一包
sub_package_size = read_size - sub_package_offset + 1 + 8 + 1; // 9是包头长度包括末尾crc8
static_print_debug("last package read_size : %d , sub_package_offset : %d , sub_package_size %d " , read_size , sub_package_offset , sub_package_size);
} else if(sub_package_index == sub_package_count && sub_package_index == 0){ //只发一包
sub_package_size = read_size - sub_package_offset + 1 + 8 ; // 9是包头长度包括末尾crc8
static_print_debug("last package read_size : %d , sub_package_offset : %d , sub_package_size %d " , read_size , sub_package_offset , sub_package_size);
}
if(sub_package_index == 0){
gatt_send_response(buffer + sub_package_offset, sub_package_size,gatt_server_id,g_server_conn_id);
sub_package_offset += sub_package_size;
g_files_upload_transfer.operation_file_size += sub_package_size - 8;
}else{
// uint8_t tmp_buffer[509] = {0};
tmp_buffer[0] = sub_package_index - 1;
memcpy_s(tmp_buffer + 1, mtu_size - 1, buffer + sub_package_offset, sub_package_size - 1);
gatt_send_response(tmp_buffer, sub_package_size,gatt_server_id,g_server_conn_id);
sub_package_offset += sub_package_size - 1;
if(sub_package_index == sub_package_count){
g_files_upload_transfer.operation_file_size += sub_package_size - 1 - 1;
}else{
g_files_upload_transfer.operation_file_size += sub_package_size - 1;
}
}
// gatt_send_response(sub_package_data, sub_package_size,gatt_server_id,g_server_conn_id);
sub_package_index++;
// sub_package_offset += sub_package_size;
static_print_debug("sub_package_offset: %d , sub_package_size : %d g_files_upload_transfer.operation_file_size : %d ",sub_package_offset , sub_package_size , g_files_upload_transfer.operation_file_size);
}
}
free(buffer);
buffer = NULL;
free(tmp_buffer);
tmp_buffer = NULL;
g_files_upload_transfer.file_status = FileTransfer_End;
tjd_ble_protocol_file_upload_end(g_state_temp);
return 0;
}
void tjd_ble_protocol_file_upload_data_recover_handle(uint8_t server_id, uint16_t conn_id, uint8_t *write_cb_para, uint16_t len ,uint8_t cmd_id)
{
if (write_cb_para[4] == 0x01) {
static_print_debug("upload file data success");
osal_sem_up(&g_tjd_ble_upload_file_mutex);
if(g_files_upload_transfer.file_status == FileTransfer_End)
{
//tjd_ble_protocol_file_upload_end(g_state_temp);
}
} else if (write_cb_para[4] == 0x00) {
static_print_debug("upload file data faile");
}
}
void tjd_ble_protocol_file_upload_end(FileUploadEndEnum status)
{
static_print_debug("tjd_ble_protocol_file_upload_end(status=%d) file_type:%d-end(%p)", status, g_files_upload_description.file_type, g_files_upload_transfer_Callback[g_files_upload_description.file_type].end);
uint8_t pack_head = PROTOCOL_RES_FRAME_HEAD_2;
tjd_ble_protocol_send_lefun_data(&pack_head, NULL, 0, UPLOAD_FILE_END_DATA);
if(g_state_temp != status) {
g_state_temp = status;
}
osal_sem_destroy(&g_tjd_ble_upload_file_mutex);
//osal_kthread_destroy(g_tjd_ble_upload_file_task_handle,1);
osThreadDetach(g_tjd_ble_upload_file_task_handle); //osThreadDetach() 空闲删除
g_tjd_ble_upload_file_task_handle = NULL;
if(g_files_upload_transfer_Callback[g_files_upload_description.file_type].end)
{
static_print_debug("g_files_upload_transfer_Callback[g_files_upload_description.file_type].end()");
g_files_upload_transfer_Callback[g_files_upload_description.file_type].end(status);
}
}
void tjd_ble_protocol_file_upload_end_recover_handle(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_upload_end_recover_handle");
#if 0
int ret = osal_event_write(&g_sport_record_event, FILE_SEND_FAILE);
if(ret != OSAL_SUCCESS){
static_print_error("write event FILE_SEND_SUCCESS failed!");
}
osal_sem_destroy(&g_tjd_ble_upload_file_mutex);
osal_kthread_destroy(g_tjd_ble_upload_file_task_handle,1);
g_tjd_ble_upload_file_task_handle = NULL;
if (write_cb_para[4]) {
static_print_debug("upload file end data success");
if(get_upload_file_end_callback() != NULL){
get_upload_file_end_callback()(UPLOAD_SUCESS);
}
} else {
static_print_debug("upload file end data faile");
if(get_upload_file_end_callback() != NULL){
get_upload_file_end_callback()(UPLOAD_FAILE);
}
}
#endif
}