diff --git a/.vscode/settings.json b/.vscode/settings.json index 0c5d5e7..96ba328 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -87,7 +87,8 @@ "zeeprom_fs.h": "c", "config.h": "c", "stdarg.h": "c", - "nrf_uarte.h": "c" + "nrf_uarte.h": "c", + "heart_rate_sensor_protocol.h": "c" }, "files.encoding": "gbk" } \ No newline at end of file diff --git a/app/src/basic/device_info_mgr.c b/app/src/basic/device_info_mgr.c new file mode 100644 index 0000000..c037669 --- /dev/null +++ b/app/src/basic/device_info_mgr.c @@ -0,0 +1,10 @@ +#include "device_info_mgr.h" + +void device_info_read_sn(sn_t* sn) { + const char* sn_str = "M1001000000001"; + memcpy(sn->sn, sn_str, sizeof(sn->sn)); +} +uint16_t device_info_read_blestack_version(void) { return 1; } +uint16_t device_info_read_bootloader_version(void) { return 1; } +uint16_t device_info_read_firmware_version(void) { return 1; } +uint16_t device_info_read_hardware_version(void) { return 1; } \ No newline at end of file diff --git a/app/src/basic/device_info_mgr.h b/app/src/basic/device_info_mgr.h new file mode 100644 index 0000000..89895ff --- /dev/null +++ b/app/src/basic/device_info_mgr.h @@ -0,0 +1,13 @@ +#pragma once +#include "znordic.h" + +typedef struct { + uint8_t sn[14]; +} sn_t; + + +void device_info_read_sn(sn_t *sn); +uint16_t device_info_read_blestack_version(void); +uint16_t device_info_read_bootloader_version(void); +uint16_t device_info_read_firmware_version(void); +uint16_t device_info_read_hardware_version(void); \ No newline at end of file diff --git a/app/src/basic/heart_rate_sensor_protocol.h b/app/src/basic/heart_rate_sensor_protocol.h index c20aee5..6213278 100644 --- a/app/src/basic/heart_rate_sensor_protocol.h +++ b/app/src/basic/heart_rate_sensor_protocol.h @@ -19,6 +19,7 @@ typedef enum { kifyhrs_ecode_device_busy = 4, kifyhrs_ecode_hardware_error = 5, kifyhrs_ecode_sensor_drop = 6, + kifyhrs_ecode_no_record_find = 7, } ify_hrs_error_code_t; typedef enum { @@ -49,7 +50,130 @@ typedef enum { ify_hrs_cmd_stop_realtime_report = 9, ify_hrs_cmd_read_records_info = 10, ify_hrs_cmd_del_record = 11, + ify_hrs_cmd_start_upload_record = 12, + ify_hrs_cmd_enter_ota = 13, + ify_hrs_cmd_read_sn = 14, + ify_hrs_cmd_reset = 15, + ify_hrs_report_heartrate_data = 101, + ify_hrs_report_battery_level = 102, + ify_hrs_report_low_battey_level = 103, + ify_hrs_report_upload_report_end = 104, + ify_hrs_report_sensor_drop_detect = 105, + ify_hrs_report_record_upload_end = 106, } ify_hrs_cmd_t; + +/******************************************************************************* + * packet_struct * + *******************************************************************************/ +typedef struct { + uint16_t placeholder; + uint16_t blestack_version; + uint16_t bootloader_version; + uint16_t firmware_version; + uint16_t hardware_version; +} device_version_info_receipt_t; + +typedef struct { + uint8_t sensor_num; // 数量 + uint8_t sensor_precision; // 精度 + uint8_t sensor_sample_rate; // 采样率 + uint8_t sensor0_pos; // 位置 + uint8_t sensor1_pos; // 位置 + uint8_t sensor2_pos; // 位置 +} sensor_info_receipt_t; + +typedef struct { + struct { + uint8_t drop0 : 1; // 传感器0脱落 + uint8_t drop1 : 1; // 传感器1脱落 + uint8_t drop2 : 1; // 传感器2脱落 + uint8_t drop3 : 1; // 传感器3脱落 + uint8_t drop4 : 1; // 传感器4脱落 + uint8_t drop5 : 1; // 传感器5脱落 + uint8_t drop6 : 1; // 传感器6脱落 + uint8_t drop7 : 1; // 传感器7脱落 + } drop0_state; + + struct { + uint8_t drop0 : 1; + uint8_t drop1 : 1; + uint8_t drop2 : 1; + uint8_t drop3 : 1; + uint8_t drop4 : 1; + uint8_t drop5 : 1; + uint8_t drop6 : 1; + uint8_t drop7 : 1; + } drop1_state; + + struct { + uint8_t sample_state : 1; + uint8_t report_state : 1; + uint8_t lowbattery_state : 1; + uint8_t full_storage : 1; + uint8_t placeholder : 4; + } device_state0; + uint8_t device_state1; // 预留 + uint8_t powerlevel; // 电量 + uint8_t storage_item_num; // 记录存储条数 +} device_state_receipt_t; + +typedef struct { + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; +} read_time_receipt_t; + +typedef struct { + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; +} sync_time_cmd_t; + +typedef struct { + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; +} start_capture_cmd_t; + +typedef struct { + uint8_t record_index; // 最近第几条记录 +} read_record_info_cmd_t; + +typedef struct { + uint8_t record_id[6]; + uint32_t frameNum; + uint32_t dataSize; + uint8_t sensorNum; + uint8_t captureRate; // N*10HZ + uint8_t capturePrecision; + uint8_t compressAlgorithm; // 压缩算法 +} read_record_info_receipt_t; + +typedef struct { + uint8_t record_id[6]; +} del_record_cmd_t; + +typedef struct { + uint8_t record_id[6]; +} start_upload_record_cmd_t; + +typedef struct { + uint8_t sn[14]; +} read_sn_receipt_t; + +typedef struct { + uint8_t errorcode; +} error_receipt_t; + #pragma pack(pop) diff --git a/app/src/basic/zdatachannel_service.h b/app/src/basic/zdatachannel_service.h index 7941ed7..9d3f8a3 100644 --- a/app/src/basic/zdatachannel_service.h +++ b/app/src/basic/zdatachannel_service.h @@ -63,12 +63,12 @@ typedef struct { struct zdatachannel_s { uint8_t uuid_type; /**< UUID type for Nordic UART Service Base UUID. */ uint16_t service_handle; /**< Handle of Nordic UART Service (as provided by the SoftDevice). */ - ble_gatts_char_handles_t cmd_tx_handles; /**< 鎸囦护鍙戦佸彞鏌 */ - ble_gatts_char_handles_t cmd_rx_handles; /**< 鎸囦护鎺ユ敹鍙ユ焺 */ - ble_gatts_char_handles_t datablock_tx_handles; /**< 鏁版嵁鍧楀彂閫佸彞鏌 */ + ble_gatts_char_handles_t cmd_tx_handles; /**< 指令发送句柄 */ + ble_gatts_char_handles_t cmd_rx_handles; /**< 指令接收句柄 */ + ble_gatts_char_handles_t datablock_tx_handles; /**< 数据块发送句柄 */ zdatachannel_data_handler_t data_handler; /**< Event handler to be called for handling received data. */ - // 鐘舵 + // 状态 int16_t conn_handle; bool cmd_tx_channel_is_notification_enabled; bool datablock_tx_channel_is_notification_enabled; diff --git a/app/src/one_conduction/ble_cmd_process_service.c b/app/src/one_conduction/ble_cmd_process_service.c index e69de29..71388d0 100644 --- a/app/src/one_conduction/ble_cmd_process_service.c +++ b/app/src/one_conduction/ble_cmd_process_service.c @@ -0,0 +1,225 @@ +#include "ble_cmd_process_service.h" + +#include "basic/device_info_mgr.h" +#include "basic/heart_rate_sensor_protocol.h" +#include "basic/zdatachannel_service.h" +#include "config.h" +#include "one_conduction_board.h" +#include "sample_data_manager.h" +static uint8_t txbuf[128]; + +void ble_cmder_try_start_adv() {} + +int ble_start_realtime_report() { return 0; } +int ble_stop_realtime_report() { return 0; } +int ble_start_upload_record(sample_data_filename_t* recordid) { return 0; } +int ble_stop_upload_record() { return 0; } + +static void send_error_receipt(ify_hrs_packet_t* rxpacket, int32_t errorcode) { + ify_hrs_packet_t* txheader = (ify_hrs_packet_t*)txbuf; + error_receipt_t* receipt = (error_receipt_t*)txheader->data; + uint16_t sendlen = sizeof(ify_hrs_packet_t) + sizeof(error_receipt_t); + + txheader->cmd = rxpacket->cmd; + txheader->frame_index = rxpacket->frame_index; + txheader->frame_type = kifyhrs_pt_error_receipt; + + txheader->frame_type = kifyhrs_pt_error_receipt; + receipt->errorcode = kifyhrs_ecode_cmd_not_support; + zdatachannel_data_send(txbuf, sendlen); +} + +static void send_success_receipt(ify_hrs_packet_t* rxpacket) { + ify_hrs_packet_t* txheader = (ify_hrs_packet_t*)txbuf; + uint16_t sendlen = sizeof(ify_hrs_packet_t); + + txheader->cmd = rxpacket->cmd; + txheader->frame_index = rxpacket->frame_index; + txheader->frame_type = kifyhrs_pt_cmd_receipt; + + zdatachannel_data_send(txbuf, sendlen); +} + +/******************************************************************************* + * 下发消息处理 * + *******************************************************************************/ +void ble_cmder_process_rx(uint8_t* rx, int len) { + ify_hrs_packet_t* rxheader = (ify_hrs_packet_t*)rx; + ify_hrs_packet_t* txheader = (ify_hrs_packet_t*)txbuf; + + int packetdata_len = len - sizeof(ify_hrs_packet_t); + ify_hrs_cmd_t cmd = rxheader->cmd; + + txheader->cmd = rxheader->cmd; + txheader->frame_index = rxheader->frame_index; + txheader->frame_type = kifyhrs_pt_cmd_receipt; + + memset(txbuf, 0, sizeof(txbuf)); + + if (cmd == ify_hrs_cmd_read_device_version) { + device_version_info_receipt_t* receipt = (device_version_info_receipt_t*)txheader->data; + uint16_t sendlen = sizeof(ify_hrs_packet_t) + sizeof(device_version_info_receipt_t); + + receipt->blestack_version = device_info_read_blestack_version(); + receipt->bootloader_version = device_info_read_bootloader_version(); + receipt->firmware_version = device_info_read_firmware_version(); + receipt->hardware_version = device_info_read_hardware_version(); + zdatachannel_data_send(txbuf, sendlen); + } + + else if (ify_hrs_cmd_read_sensor_info) { + sensor_info_receipt_t* receipt = (sensor_info_receipt_t*)txheader->data; + uint16_t sendlen = sizeof(ify_hrs_packet_t) + sizeof(sensor_info_receipt_t); + + receipt->sensor_num = 1; + receipt->sensor_precision = SAMPLE_PRECISION; + receipt->sensor_sample_rate = SAMPLE_RATE / 10; + receipt->sensor0_pos = kifyhrs_sensor_pos_none; + receipt->sensor1_pos = kifyhrs_sensor_pos_none; + receipt->sensor2_pos = kifyhrs_sensor_pos_none; + + zdatachannel_data_send(txbuf, sendlen); + } + + else if (ify_hrs_cmd_read_device_state) { + device_state_receipt_t* receipt = (device_state_receipt_t*)txheader->data; + uint16_t sendlen = sizeof(ify_hrs_packet_t) + sizeof(device_state_receipt_t); + + receipt->drop0_state.drop0 = 0; + receipt->device_state0.sample_state = 1; + receipt->device_state0.report_state = 1; + receipt->device_state0.lowbattery_state = 0; + receipt->device_state0.full_storage = sample_data_mgr_storage_is_full(); + receipt->powerlevel = SingleLeadECG_battery_val(); + receipt->storage_item_num = sample_data_mgr_get_file_num(); + + zdatachannel_data_send(txbuf, sendlen); + } + + else if (ify_hrs_cmd_read_time) { + read_time_receipt_t* receipt = (read_time_receipt_t*)txheader->data; + uint16_t sendlen = sizeof(ify_hrs_packet_t) + sizeof(read_time_receipt_t); + static ztm_t ztm; + znordic_rtc_gettime(&ztm); + + receipt->year = (ztm.tm_year + 1900 - 2000); + receipt->month = ztm.tm_mon + 1; + receipt->day = ztm.tm_mday; + receipt->hour = ztm.tm_hour; + receipt->minute = ztm.tm_min; + receipt->second = ztm.tm_sec; + zdatachannel_data_send(txbuf, sendlen); + } + + else if (ify_hrs_cmd_sync_time) { + sync_time_cmd_t* cmd = (sync_time_cmd_t*)rxheader->data; + uint16_t sendlen = sizeof(ify_hrs_packet_t); + + znordic_rtc_settime(cmd->year + 2000, cmd->month, cmd->day, cmd->hour, cmd->minute, cmd->second); + zdatachannel_data_send(txbuf, sendlen); + } + + else if (ify_hrs_cmd_start_capture) { + send_error_receipt(rxheader, kifyhrs_ecode_cmd_not_support); + } + + else if (ify_hrs_cmd_stop_capture) { + send_error_receipt(rxheader, kifyhrs_ecode_cmd_not_support); + } + + else if (ify_hrs_cmd_start_realtime_report) { + // unsupport cmd + int ecode = ble_start_realtime_report(); + if (ecode == 0) { + send_success_receipt(rxheader); + } else { + send_error_receipt(rxheader, ecode); + } + } + + else if (ify_hrs_cmd_stop_realtime_report) { + int ecode = ble_stop_realtime_report(); + if (ecode == 0) { + send_success_receipt(rxheader); + } else { + send_error_receipt(rxheader, ecode); + } + } + + else if (ify_hrs_cmd_read_records_info) { + // send_error_receipt(rxheader, kifyhrs_ecode_cmd_not_support); + read_record_info_cmd_t* cmd = (read_record_info_cmd_t*)rxheader->data; + read_record_info_receipt_t* receipt = (read_record_info_receipt_t*)txheader->data; + uint16_t sendlen = sizeof(ify_hrs_packet_t) + sizeof(read_record_info_receipt_t); + + uint8_t recordoff = cmd->record_index; + sample_data_fileinfo_list_t* recordlist = sample_data_mgr_get_fileinfo_list(); + if (recordoff >= recordlist->count) { + send_error_receipt(rxheader, kifyhrs_ecode_cmd_not_support); + return; + } + + sample_data_fileinfo_t* fileinfo = recordlist->fileinfo[recordoff]; + memcpy(receipt->record_id, fileinfo->filename, 6); + receipt->frameNum = fileinfo->size / 16; // 16 bytes per frame + receipt->dataSize = fileinfo->size; + receipt->sensorNum = 1; + receipt->captureRate = SAMPLE_RATE / 10; + receipt->capturePrecision = SAMPLE_PRECISION; + receipt->compressAlgorithm = 0; + + zdatachannel_data_send(txbuf, sendlen); + + } + + else if (ify_hrs_cmd_del_record) { + del_record_cmd_t* cmd = (del_record_cmd_t*)rxheader->data; + uint16_t sendlen = sizeof(ify_hrs_packet_t); + + static sample_data_filename_t filename; + memset(&filename, 0, sizeof(filename)); + memcpy(&filename, cmd->record_id, sizeof(cmd->record_id)); + + int ecode = sample_data_mgr_delete_file(&filename); + if (ecode == 0) { + send_success_receipt(rxheader); + } else { + send_error_receipt(rxheader, kifyhrs_ecode_unkown_error); + } + } + + else if (ify_hrs_cmd_start_upload_record) { + start_upload_record_cmd_t* cmd = (start_upload_record_cmd_t*)rxheader->data; + uint16_t sendlen = sizeof(ify_hrs_packet_t); + + static sample_data_filename_t filename; + memset(&filename, 0, sizeof(filename)); + memcpy(&filename, cmd->record_id, sizeof(cmd->record_id)); + + int ecode = ble_start_upload_record(&filename); + if (ecode == 0) { + send_success_receipt(rxheader); + } else { + send_error_receipt(rxheader, ecode); + } + } + + else if (ify_hrs_cmd_enter_ota) { + send_error_receipt(rxheader, kifyhrs_ecode_cmd_not_support); + } + + else if (ify_hrs_cmd_read_sn) { + read_sn_receipt_t* receipt = (read_sn_receipt_t*)txheader->data; + uint16_t sendlen = sizeof(ify_hrs_packet_t) + sizeof(read_sn_receipt_t); + device_info_read_sn((sn_t*)&receipt->sn); + zdatachannel_data_send(txbuf, sendlen); + } + + else if (ify_hrs_cmd_reset) { + NVIC_SystemReset(); + } + // + else { + send_error_receipt(rxheader, kifyhrs_ecode_cmd_not_support); + } +} diff --git a/app/src/one_conduction/ble_cmd_process_service.h b/app/src/one_conduction/ble_cmd_process_service.h index d1b3bf6..5fb269b 100644 --- a/app/src/one_conduction/ble_cmd_process_service.h +++ b/app/src/one_conduction/ble_cmd_process_service.h @@ -3,3 +3,5 @@ #include "basic/heart_rate_sensor_protocol.h" #include "device_state.h" +void ble_cmder_process_rx(uint8_t* rx, int len); +void ble_cmder_try_start_adv(); \ No newline at end of file diff --git a/app/src/one_conduction/config.h b/app/src/one_conduction/config.h index f350db9..d809ee6 100644 --- a/app/src/one_conduction/config.h +++ b/app/src/one_conduction/config.h @@ -13,4 +13,7 @@ #define MAX_STORAGE_TIMEOUT_S (60 * 10) #define MAX_STORAGE_SIZE (MAX_STORAGE_TIMEOUT_S * 400) // 存储最大限制为 (256-8)kbyte -#define MAX_FILE_NUM 10 \ No newline at end of file +#define MAX_FILE_NUM 10 + +#define SAMPLE_RATE 200 +#define SAMPLE_PRECISION 12 \ No newline at end of file diff --git a/app/src/one_conduction/one_conduction_main.c b/app/src/one_conduction/one_conduction_main.c index 5658f92..26cc174 100644 --- a/app/src/one_conduction/one_conduction_main.c +++ b/app/src/one_conduction/one_conduction_main.c @@ -253,7 +253,7 @@ void app_event_process_cb(void* p_event_data, uint16_t event_size) { memset(&sampledata_file_name, 0, sizeof(sampledata_file_name)); znordic_rtc_gettime(&tm); - sampledata_file_name.year = tm.tm_year; + sampledata_file_name.year = tm.tm_year + 1900 - 2000; sampledata_file_name.month = tm.tm_mon; sampledata_file_name.day = tm.tm_mday; sampledata_file_name.hour = tm.tm_hour; diff --git a/app/src/one_conduction/sample_data_manager.c b/app/src/one_conduction/sample_data_manager.c index 2bc3937..e78c296 100644 --- a/app/src/one_conduction/sample_data_manager.c +++ b/app/src/one_conduction/sample_data_manager.c @@ -43,6 +43,10 @@ sample_data_fileinfo_list_t* sample_data_mgr_get_fileinfo_list() { // } return &fileinfo_list; } + +int32_t sample_data_mgr_storage_is_full() { return zeeprom_fs_get_file_num() >= FILE_MAX_COUNT; } +int32_t sample_data_mgr_get_file_num() { return zeeprom_fs_get_file_num(); } + #if 1 static const char* filename2str(uint8_t* filename) { static char filename_str[32]; diff --git a/app/src/one_conduction/sample_data_manager.h b/app/src/one_conduction/sample_data_manager.h index 0f30b19..48910e7 100644 --- a/app/src/one_conduction/sample_data_manager.h +++ b/app/src/one_conduction/sample_data_manager.h @@ -1,21 +1,21 @@ #pragma once #include -#include "zeeprom_fs.h" #include "config.h" +#include "zeeprom_fs.h" void sample_data_mgr_init(); #define FILE_MAX_COUNT MAX_FILE_NUM typedef struct { - uint16_t year; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t min; - uint8_t sec; - uint8_t placeholder[2]; + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t min; + uint8_t sec; + uint8_t placeholder[2]; } sample_data_filename_t; typedef struct { @@ -33,6 +33,8 @@ void sample_data_mgr_init(); void sample_data_mgr_uninit(); sample_data_fileinfo_list_t* sample_data_mgr_get_fileinfo_list(); +int32_t sample_data_mgr_storage_is_full(); +int32_t sample_data_mgr_get_file_num(); int32_t sample_data_mgr_open(sample_data_filename_t* filename, wrflag_t flag); int32_t sample_data_mgr_close(int32_t fd); diff --git a/libznordic b/libznordic index 1eb8d83..195d289 160000 --- a/libznordic +++ b/libznordic @@ -1 +1 @@ -Subproject commit 1eb8d83d8d82aecd5a0da03be2a9399e061f91a8 +Subproject commit 195d28909c8ed31853420141b4902fb8d61e6975