From 7297dc490502c2ed675558f76e8c24b98f0c091f Mon Sep 17 00:00:00 2001 From: zhaohe Date: Tue, 30 Jan 2024 14:17:44 +0800 Subject: [PATCH] update --- README.md | 19 +- app/src/basic/heart_rate_sensor_protocol.h | 48 ++++- app/src/basic/zble_module.c | 31 ++- app/src/basic/zble_module.h | 2 +- app/src/basic/zdatachannel_service.c | 1 + app/src/basic/zdatachannel_service.h | 1 - app/src/one_conduction/ble_cmd_process_service.c | 231 +++++++++++++++++++-- app/src/one_conduction/ble_cmd_process_service.h | 10 +- app/src/one_conduction/device_state.h | 9 +- app/src/one_conduction/heart_wave_sample_service.c | 49 +++-- app/src/one_conduction/one_conduction_main.c | 12 +- app/src/one_conduction/sample_data_manager.c | 2 +- app/src/one_conduction/sample_data_manager.h | 3 +- libznordic | 2 +- 14 files changed, 355 insertions(+), 65 deletions(-) diff --git a/README.md b/README.md index 9ca4b6d..ddf5fbb 100644 --- a/README.md +++ b/README.md @@ -251,23 +251,24 @@ TODO: 任务: 16. 解决断开连接,再次唤醒,屏幕无显示的BUG OK 1. 提取休眠时间到宏配置中 OK - 9. 支持数据上报 - 12. 支持数据上传 + 9. 支持数据实时上报 OK + 12. 支持数据上传 OK + 15. 检查设备状态 OK + 14. 支持掉落事件 OK + 6. 支持电池电量采集 8. 采集完30秒,蜂鸣器滴一声,采集完成,蜂鸣器滴一声 - 13. 支持低电量事件 - 14. 支持掉落事件 - 15. 检查设备状态 - + 16. 调整UI位置 +-------------------------------------------------------------- 2. UI添加蓝牙状态 3. UI添加上传状态 4. UI添加心率计算 5. UI添加心脏跳动效果 7. 校准电池电量采集 + 7. 添加心率 10. 添加OTA支持 11. 数据掉电不丢失 - - - + 12. 优化定时器周期 + 13. 支持低电量事件 ``` \ 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 6921002..27ffe69 100644 --- a/app/src/basic/heart_rate_sensor_protocol.h +++ b/app/src/basic/heart_rate_sensor_protocol.h @@ -58,7 +58,7 @@ typedef enum { 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_sample_finish_end = 104, ify_hrs_report_sensor_drop_detect = 105, ify_hrs_report_record_upload_end = 106, @@ -85,9 +85,24 @@ typedef struct { } sensor_info_receipt_t; typedef struct { - uint8_t drop_state0; + struct { + uint8_t sensor0_pos : 1; // 位置 + uint8_t sensor1_pos : 1; // 位置 + uint8_t sensor2_pos : 1; // 位置 + uint8_t sensor3_pos : 1; // 位置 + uint8_t sensor4_pos : 1; // 位置 + uint8_t sensor5_pos : 1; // 位置 + uint8_t sensor6_pos : 1; // 位置 + uint8_t sensor7_pos : 1; // 位置 + } drop_state0; uint8_t drop_state1; - uint8_t device_state0; + struct { + uint8_t sampling_state : 1; // 位置 + uint8_t report_state : 1; // 位置 + uint8_t low_battery : 1; // 位置 + uint8_t full_storge : 1; // 位置 + uint8_t holder : 4; // 位置 + } device_state0; uint8_t device_state1; // 预留 uint8_t powerlevel; // 电量 uint8_t storage_item_num; // 记录存储条数 @@ -143,6 +158,11 @@ typedef struct { } start_upload_record_cmd_t; typedef struct { + uin +} start_upload_record_receipt_t; + + +typedef struct { uint8_t sn[14]; } read_sn_receipt_t; @@ -150,4 +170,26 @@ typedef struct { uint8_t errorcode; } error_receipt_t; +/******************************************************************************* + * 上报相关结构体 * + *******************************************************************************/ + +typedef struct { + uint8_t frame_type; + uint8_t frame_index; + uint8_t cmd; + + uint32_t sample_data_index; + uint8_t data[]; // 上报的数据 +} heartrate_report_packet_t; + +typedef struct { + uint8_t frame_type; + uint8_t frame_index; + uint8_t cmd; + + uint8_t drop_state0; + uint8_t drop_state1; +} sensor_drop_event_report_packet_t; + #pragma pack(pop) diff --git a/app/src/basic/zble_module.c b/app/src/basic/zble_module.c index 6439140..b89e6c8 100644 --- a/app/src/basic/zble_module.c +++ b/app/src/basic/zble_module.c @@ -7,7 +7,7 @@ #include "znordic.h" /******************************************************************************* - * 骞挎挱鍖呴厤缃? * + * 广播包配?? * *******************************************************************************/ #define MIN_CONN_INTERVAL MSEC_TO_UNITS(20, UNIT_1_25_MS) /**< Minimum acceptable connection interval (20 ms), Connection interval uses 1.25 ms units. */ #define MAX_CONN_INTERVAL MSEC_TO_UNITS(75, UNIT_1_25_MS) /**< Maximum acceptable connection interval (75 ms), Connection interval uses 1.25 ms units. */ @@ -21,12 +21,12 @@ static ble_uuid_t m_adv_uuids[] = /**< Universally u BLE_ADVERTISING_DEF(m_advertising); /**< Advertising module instance. */ /******************************************************************************* - * GATT閰嶇疆 * + * GATT配置 * *******************************************************************************/ NRF_BLE_GATT_DEF(m_gatt); /**< GATT module instance. */ /******************************************************************************* - * 杩炴帴鍙傛暟閰嶇疆 * + * 连接参数配置 * *******************************************************************************/ #define FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(5000) /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (5 seconds). */ #define NEXT_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(30000) /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */ @@ -36,11 +36,9 @@ NRF_BLE_GATT_DEF(m_gatt); /**< GATT module instance. */ * CODE * *******************************************************************************/ -static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; /**< 褰撳墠杩炴帴鍙ユ焺 */ +static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; /**< 当前连接句柄 */ static uint16_t m_mtu_size = BLE_GATT_ATT_MTU_DEFAULT - 3; - - static void ble_evt_handler(ble_evt_t const* p_ble_evt, void* p_context) { uint32_t err_code; switch (p_ble_evt->header.evt_id) { @@ -93,7 +91,7 @@ static void ble_evt_handler(ble_evt_t const* p_ble_evt, void* p_context) { } static void gatt_evt_handler(nrf_ble_gatt_t* p_gatt, nrf_ble_gatt_evt_t const* p_evt) { /******************************************************************************* - * MTU SIZE 鏇存柊 * + * MTU SIZE 更新 * *******************************************************************************/ if ((m_conn_handle == p_evt->conn_handle) && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED)) { m_mtu_size = p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH; @@ -109,7 +107,6 @@ static void on_conn_params_evt(ble_conn_params_evt_t* p_evt) { } static void conn_params_error_handler(uint32_t nrf_error) { APP_ERROR_HANDLER(nrf_error); } static void on_adv_evt(ble_adv_evt_t ble_adv_evt) { - switch (ble_adv_evt) { case BLE_ADV_EVT_FAST: // err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING); @@ -138,11 +135,11 @@ void zble_module_stop_adv() { void zble_module_init(zble_module_cfg_t* cfg) { /** * @brief - * 鍒濆鍖栬摑鐗欏崗璁爤锛屽苟娉ㄥ唽钃濈墮浜嬩欢澶勭悊鍑芥暟锛屽浐瀹氫唬鐮侊紝鍕夸慨鏀? + * 初始化蓝牙协议栈,并注册蓝牙事件处理函数,固定代码,勿修?? */ { NRF_SDH_BLE_OBSERVER(m_ble_observer, 3, ble_evt_handler, NULL); } /******************************************************************************* - * GAP鍒濆鍖? * + * GAP初始?? * *******************************************************************************/ { uint32_t err_code; @@ -166,7 +163,7 @@ void zble_module_init(zble_module_cfg_t* cfg) { } /******************************************************************************* - * GATT 鍒濆鍖? * + * GATT 初始?? * *******************************************************************************/ { ret_code_t err_code; @@ -179,14 +176,14 @@ void zble_module_init(zble_module_cfg_t* cfg) { } /******************************************************************************* - * 钃濈墮鏈嶅姟鍒濆鍖? * + * 蓝牙服务初始?? * *******************************************************************************/ { if (cfg->on_service_init) cfg->on_service_init(); } /******************************************************************************* - * 骞挎挱鍒濆鍖? * + * 广播初始?? * *******************************************************************************/ { uint32_t err_code; @@ -197,7 +194,7 @@ void zble_module_init(zble_module_cfg_t* cfg) { init.advdata.name_type = BLE_ADVDATA_FULL_NAME; init.advdata.include_appearance = false; // init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE; - init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; + init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; init.srdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]); init.srdata.uuids_complete.p_uuids = m_adv_uuids; @@ -213,7 +210,7 @@ void zble_module_init(zble_module_cfg_t* cfg) { ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG); } /******************************************************************************* - * 杩炴帴鍙傛暟鍒濆鍖? * + * 连接参数初始?? * *******************************************************************************/ { uint32_t err_code; @@ -235,4 +232,6 @@ void zble_module_init(zble_module_cfg_t* cfg) { } // zble_module_start_adv(); -} \ No newline at end of file +} + +int32_t zble_module_get_mtu_size() { return m_mtu_size; } \ No newline at end of file diff --git a/app/src/basic/zble_module.h b/app/src/basic/zble_module.h index a630a0a..3c42aa1 100644 --- a/app/src/basic/zble_module.h +++ b/app/src/basic/zble_module.h @@ -17,4 +17,4 @@ void zble_module_init(zble_module_cfg_t* cfg); void zble_module_start_adv(); void zble_module_stop_adv(); -void zble_module_is_connected(); +int32_t zble_module_get_mtu_size(); \ No newline at end of file diff --git a/app/src/basic/zdatachannel_service.c b/app/src/basic/zdatachannel_service.c index 0ab6a38..a11367d 100644 --- a/app/src/basic/zdatachannel_service.c +++ b/app/src/basic/zdatachannel_service.c @@ -21,6 +21,7 @@ } /**< Used vendor specific UUID. */ static zdatachannel_t *p_datachannel; +static uint32_t m_mtusize; static bool notification_enable(uint16_t conn_handle, uint16_t cccd_handle) { ret_code_t err_code; diff --git a/app/src/basic/zdatachannel_service.h b/app/src/basic/zdatachannel_service.h index 094f9e5..7015f3a 100644 --- a/app/src/basic/zdatachannel_service.h +++ b/app/src/basic/zdatachannel_service.h @@ -78,7 +78,6 @@ uint32_t zdatachannel_init(zdatachannel_t* p_nus, zdatachannel_init_t const* p_n void zdatachannel_on_ble_evt(ble_evt_t const* p_ble_evt, void* p_context); bool zdatachannel_is_connected(); - uint32_t zdatachannel_data_send(uint8_t* p_data, uint16_t* p_length); static inline uint32_t zdatachannel_data_send2(uint8_t* p_data, uint16_t p_length){ return zdatachannel_data_send(p_data, &p_length); diff --git a/app/src/one_conduction/ble_cmd_process_service.c b/app/src/one_conduction/ble_cmd_process_service.c index 186c031..9acd4fe 100644 --- a/app/src/one_conduction/ble_cmd_process_service.c +++ b/app/src/one_conduction/ble_cmd_process_service.c @@ -8,16 +8,195 @@ #include "one_conduction_board.h" #include "sample_data_manager.h" -static uint8_t txbuf[128]; +APP_TIMER_DEF(m_record_upload_tmr); // 数据上报定时器 +static uint8_t txbuf[128]; +static uint8_t reportbuf[128]; +static bool m_realtime_report_state = false; +static bool m_isupload_data_state = false; +static bool m_ble_cmder_is_inited = false; +static uint32_t m_report_data_sumcheckcode = 0; + +static void record_upload_tmr_cb(void* p_context); +int ble_stop_upload_record(); +/******************************************************************************* + * 广播控制 * + *******************************************************************************/ +void ble_cmder_start_adv() { + m_realtime_report_state = false; + zble_module_start_adv(); +} +void ble_cmder_stop_adv() { + zble_module_stop_adv(); + m_realtime_report_state = false; +} + +/******************************************************************************* + * 模块初始化 * + *******************************************************************************/ +void ble_cmder_init() { + if (!m_ble_cmder_is_inited) { + ZERROR_CHECK(app_timer_create(&m_record_upload_tmr, APP_TIMER_MODE_REPEATED, record_upload_tmr_cb)); + } + m_ble_cmder_is_inited = true; +} +void ble_cmder_uninit() {} + +/******************************************************************************* + * 实时上报控制 * + *******************************************************************************/ +int ble_start_realtime_report() { + m_realtime_report_state = true; + return 0; +} +int ble_stop_realtime_report() { + m_realtime_report_state = false; + return 0; +} +void ble_cmder_try_report_one_sample_data(uint32_t frameIndex, uint16_t data) { + if (!m_realtime_report_state) { + return; + } + + heartrate_report_packet_t* reportpacket = (heartrate_report_packet_t*)reportbuf; + reportpacket->cmd = ify_hrs_report_heartrate_data; + reportpacket->frame_index = 0; + reportpacket->frame_type = kifyhrs_pt_report; + reportpacket->sample_data_index = frameIndex; + + /** + * @brief 第一导联数据 + */ + reportpacket->data[0] = (data >> 0) & 0xFF; + reportpacket->data[1] = (data >> 8) & 0xFF; + reportpacket->data[2] = 0; + + uint16_t sendlen = sizeof(heartrate_report_packet_t) + 3; + zdatachannel_data_send2(reportbuf, sendlen); + return; +} + +void ble_cmder_try_report_sensor_drop_event(uint8_t dropstate0, uint8_t dropstate1) { + sensor_drop_event_report_packet_t* reportpacket = (sensor_drop_event_report_packet_t*)reportbuf; + reportpacket->cmd = ify_hrs_report_sensor_drop_detect; + reportpacket->frame_index = 0; + reportpacket->frame_type = kifyhrs_pt_report; + reportpacket->drop_state0 = dropstate0; + reportpacket->drop_state1 = dropstate1; + + uint16_t sendlen = sizeof(sensor_drop_event_report_packet_t); + zdatachannel_data_send2(reportbuf, sendlen); + return; +} +void ble_cmder_report_upload_finish_event(uint32_t sumcheckcode) { + ify_hrs_packet_t* txheader = (ify_hrs_packet_t*)txbuf; + uint16_t sendlen = sizeof(ify_hrs_packet_t) + 4; + + txheader->cmd = ify_hrs_report_record_upload_end; + txheader->frame_index = 0; + txheader->frame_type = kifyhrs_pt_report; + + // txheader->data[0] = errorcode; + *(uint32_t*)txheader->data = sumcheckcode; + + zdatachannel_data_send2(txbuf, sendlen); + return; +} + +void ble_cmder_report_sample_finish_event() { + ify_hrs_packet_t* txheader = (ify_hrs_packet_t*)txbuf; + uint16_t sendlen = sizeof(ify_hrs_packet_t); -void ble_cmder_start_adv() { zble_module_start_adv(); } -void ble_cmder_stop_adv() { zble_module_stop_adv(); } + txheader->cmd = ify_hrs_report_sample_finish_end; + txheader->frame_index = 0; + txheader->frame_type = kifyhrs_pt_report; -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; } + zdatachannel_data_send2(txbuf, sendlen); + return; +} + +/******************************************************************************* + * 上传数据控制 * + *******************************************************************************/ +static int m_upload_fd; +static uint8_t datacache[256]; +static uint8_t m_remaindatalen = 0; +static void record_upload_tmr_cb(void* p_context) { // + + // sample_data_mgr_read + if (m_remaindatalen == 0) { + memset(datacache, 0, sizeof(datacache)); + int32_t rdsize = sample_data_mgr_read(m_upload_fd, datacache, sizeof(datacache)); + if (rdsize <= 0) { + ZLOGI("read file end,stop upload"); + ble_cmder_report_upload_finish_event(m_report_data_sumcheckcode); + ble_stop_upload_record(); + return; + } + m_remaindatalen = rdsize; + } + int32_t mtusize = zble_module_get_mtu_size(); + + uint8_t* data = datacache + (sizeof(datacache) - m_remaindatalen); + uint8_t len = m_remaindatalen > mtusize ? mtusize : m_remaindatalen; + + if (!zdatachannel_is_connected()) { + ZLOGI("ble is disconnected,stop upload"); + ble_stop_upload_record(); + return; + } + + uint32_t suc = zdatachannel_block_data_send2(data, len); + if (suc != NRF_SUCCESS) { + if (suc == NRF_ERROR_INVALID_STATE) { + // 未使能notify + ZLOGI("ble unenable notify,stop upload"); + ble_stop_upload_record(); + return; + } else if (suc == NRF_ERROR_BUSY) { + // 等待下次发送 + return; + } else { + ZLOGI("ble send error,stop upload %x", suc); + ble_stop_upload_record(); + return; + } + } + for (uint32_t i = 0; i < len; i++) { + m_report_data_sumcheckcode += data[i]; + } + m_remaindatalen -= len; +} + +int ble_start_upload_record(sample_data_filename_t* recordid) { + // + // 启动 + // + if (ds_now_state() != kdevice_state_home) { + return kifyhrs_ecode_device_busy; + } + + m_upload_fd = sample_data_mgr_open(recordid, kwrflag_read_only); + if (m_upload_fd <= 0) { + return kifyhrs_ecode_no_record_find; + } + + ZERROR_CHECK(app_timer_start(m_record_upload_tmr, APP_TIMER_TICKS(2), NULL)); + m_isupload_data_state = true; + m_remaindatalen = 0; + m_report_data_sumcheckcode = 0; + return 0; +} +int ble_stop_upload_record() { + m_isupload_data_state = false; + app_timer_stop(m_record_upload_tmr); + return 0; +} +bool ble_is_upload_record() { return m_isupload_data_state; } + +/******************************************************************************* + * UTILS * + *******************************************************************************/ 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; @@ -88,12 +267,13 @@ void ble_cmder_process_rx(uint8_t* rx, int len) { 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->drop_state0 |= 0x01; - receipt->drop_state1 = 0x00; - receipt->device_state0 = (0x01 << 0 /*设备采集*/) | // - (0x01 << 1 /*设备上报*/) | // - (0x00 << 2 /*低电量*/) | // - (0x01 << 3 /*存储满*/); + receipt->drop_state0.sensor0_pos = (!SingleLeadECG_ecg_plod_get_connected_state()); + receipt->drop_state1 = 0x00; + receipt->device_state0.sampling_state = (ds_now_state() == kdevice_state_sampling); + receipt->device_state0.report_state = m_realtime_report_state; + receipt->device_state0.low_battery = (SingleLeadECG_battery_val() < 20); + receipt->device_state0.full_storge = (sample_data_mgr_storage_is_full()); + receipt->device_state1 = 0; receipt->powerlevel = SingleLeadECG_battery_val(); receipt->storage_item_num = sample_data_mgr_get_file_num(); @@ -152,12 +332,19 @@ void ble_cmder_process_rx(uint8_t* rx, int len) { } else if (cmd == ify_hrs_cmd_read_records_info) { - // send_error_receipt(rxheader, kifyhrs_ecode_cmd_not_support); + // 指令 10-读取采样记录头部信息 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; + uint8_t recordoff = cmd->record_index; + + // 采样时不支持 + if (ds_now_state() != kdevice_state_home) { + send_error_receipt(rxheader, kifyhrs_ecode_device_busy); + return; + } + sample_data_fileinfo_list_t* recordlist = sample_data_mgr_get_fileinfo_list(); if (recordoff >= recordlist->count) { send_error_receipt(rxheader, kifyhrs_ecode_no_record_find); @@ -178,12 +365,19 @@ void ble_cmder_process_rx(uint8_t* rx, int len) { } else if (cmd == ify_hrs_cmd_del_record) { + // 指令 11-删除采样记录 del_record_cmd_t* cmd = (del_record_cmd_t*)rxheader->data; static sample_data_filename_t filename; memset(&filename, 0, sizeof(filename)); memcpy(&filename, cmd->record_id, sizeof(cmd->record_id)); + // 采样时不支持 + if (ds_now_state() != kdevice_state_home) { + send_error_receipt(rxheader, kifyhrs_ecode_device_busy); + return; + } + int ecode = sample_data_mgr_delete_file(&filename); if (ecode == 0) { send_success_receipt(rxheader); @@ -193,12 +387,19 @@ void ble_cmder_process_rx(uint8_t* rx, int len) { } else if (cmd == ify_hrs_cmd_start_upload_record) { + // 指令 12-上传采集记录 start_upload_record_cmd_t* cmd = (start_upload_record_cmd_t*)rxheader->data; static sample_data_filename_t filename; memset(&filename, 0, sizeof(filename)); memcpy(&filename, cmd->record_id, sizeof(cmd->record_id)); + // 采样时不支持 + if (ds_now_state() != kdevice_state_home) { + send_error_receipt(rxheader, kifyhrs_ecode_device_busy); + return; + } + int ecode = ble_start_upload_record(&filename); if (ecode == 0) { send_success_receipt(rxheader); diff --git a/app/src/one_conduction/ble_cmd_process_service.h b/app/src/one_conduction/ble_cmd_process_service.h index a14c427..d6e039d 100644 --- a/app/src/one_conduction/ble_cmd_process_service.h +++ b/app/src/one_conduction/ble_cmd_process_service.h @@ -3,6 +3,14 @@ #include "basic/heart_rate_sensor_protocol.h" #include "device_state.h" +void ble_cmder_init(); +void ble_cmder_uninit(); + void ble_cmder_process_rx(uint8_t* rx, int len); void ble_cmder_start_adv(); -void ble_cmder_stop_adv(); \ No newline at end of file +void ble_cmder_stop_adv(); + +void ble_cmder_try_report_one_sample_data(uint32_t frameIndex, uint16_t data); +void ble_cmder_try_report_sensor_drop_event(uint8_t dropstate0, uint8_t dropstate1); +void ble_cmder_report_upload_finish_event(uint32_t sumcheckcode); +void ble_cmder_report_sample_finish_event(); diff --git a/app/src/one_conduction/device_state.h b/app/src/one_conduction/device_state.h index 4f5d0c8..f9c90b3 100644 --- a/app/src/one_conduction/device_state.h +++ b/app/src/one_conduction/device_state.h @@ -11,7 +11,9 @@ typedef enum { kplod_end_charge_event, // 充电结束事件 kevent_tmr_scheduler_event, // 定时器调度事件 - kevent_capture_data_event, // 采样数据回调 + + kevent_capture_256data_event, // 采样数据回调 + kevent_capture_1data_event, // 单次采样数据回调 } app_event_type_t; typedef struct { @@ -19,6 +21,11 @@ typedef struct { union { uint32_t plod_connected_accumulation_time; // 导联连接累计时间 uint8_t* capture_data_cache; // 实时采样数据,数据长度为256字节 + struct { + uint32_t frameIndex; + uint16_t data; + } + frame_data; } val; } app_event_t; diff --git a/app/src/one_conduction/heart_wave_sample_service.c b/app/src/one_conduction/heart_wave_sample_service.c index 816ba51..49ff56c 100644 --- a/app/src/one_conduction/heart_wave_sample_service.c +++ b/app/src/one_conduction/heart_wave_sample_service.c @@ -13,8 +13,9 @@ static uint16_t m_capture_buffer_b[128]; static uint16_t* m_capture_buffer; static uint16_t m_capture_buffer_index = 0; -volatile static float m_real_time_data = 0; // 0->100 +volatile static float m_sensor_display_data = 0; // 0->100 static uint32_t m_start_capture_tp; +static uint32_t m_frameindex = 0; static void swap_buffer() { if (m_capture_buffer == NULL) { @@ -58,16 +59,22 @@ static float Filter(filter_t* filter, float newInput) { filter->value = newv; return newv; } -void nrfx_timer_event_handler(nrf_timer_event_t event_type, void* p_context) { // - uint16_t val = SingleLeadECG_ecg_plod_get_ecg_val(); // 12bit - - float val_af100 = (float)val / 4096.0f * 100; - - val_af100 = amp_val(val_af100, 50, 1.8f); - val_af100 = Filter(&m_filter, val_af100); - m_real_time_data = val_af100; - // ZLOGI("%d", val); +void nrfx_timer_event_handler(nrf_timer_event_t event_type, void* p_context) { // + uint16_t val = SingleLeadECG_ecg_plod_get_ecg_val(); // 12bit + m_frameindex++; + + /******************************************************************************* + * 显示数据计算并赋值 * + *******************************************************************************/ + float val_af100 = (float)val / 4096.0f * 100; + val_af100 = amp_val(val_af100, 50, 1.8f); + val_af100 = Filter(&m_filter, val_af100); + m_sensor_display_data = val_af100; + + /******************************************************************************* + * 采样数据缓存 * + *******************************************************************************/ if (m_capture_buffer == NULL) { swap_buffer(); } @@ -78,11 +85,23 @@ void nrfx_timer_event_handler(nrf_timer_event_t event_type, void* p_context) { if (m_capture_buffer_index == 128) { app_event_t evt; - evt.eventType = kevent_capture_data_event; + evt.eventType = kevent_capture_256data_event; evt.val.capture_data_cache = (uint8_t*)m_capture_buffer; swap_buffer(); app_sched_event_put(&evt, sizeof(evt), app_event_process_cb); } + + /******************************************************************************* + * 实时采样数据事件上报 * + *******************************************************************************/ + { + app_event_t evt; + evt.eventType = kevent_capture_1data_event; + evt.val.frame_data.frameIndex = m_frameindex; + evt.val.frame_data.data = val; + swap_buffer(); + app_sched_event_put(&evt, sizeof(evt), app_event_process_cb); + } } void hwss_init(void) { @@ -114,13 +133,17 @@ void hwss_uninit(void) { nrfx_timer_disable(&m_timer); } void hwss_start_capture(void) { m_start_capture_tp = znordic_getpower_on_s(); swap_buffer(); + m_frameindex = 0; nrfx_timer_enable(&m_timer); } -void hwss_stop_capture(void) { nrfx_timer_disable(&m_timer); } +void hwss_stop_capture(void) { + nrfx_timer_disable(&m_timer); + m_frameindex = 0; +} float hwss_read_val(void) { __disable_irq(); - float val = m_real_time_data; + float val = m_sensor_display_data; __enable_irq(); return val; } diff --git a/app/src/one_conduction/one_conduction_main.c b/app/src/one_conduction/one_conduction_main.c index eca1066..5f591c7 100644 --- a/app/src/one_conduction/one_conduction_main.c +++ b/app/src/one_conduction/one_conduction_main.c @@ -119,6 +119,7 @@ static void power_on() { hwss_init(); sample_data_mgr_init(); dsp_mgr_init(); + ble_cmder_init(); ble_cmder_start_adv(); m_poweronflag = true; @@ -135,6 +136,7 @@ static void power_off() { SingleLeadECG_beep_deinit(); SingleLeadECG_adc_module_deinit(); ble_cmder_stop_adv(); + ble_cmder_uninit(); ZERROR_CHECK(app_timer_stop(m_state_machine_driver_tmr)); m_poweronflag = false; } @@ -302,7 +304,7 @@ void app_event_process_cb(void* p_event_data, uint16_t event_size) { */ bool always_capture = false; - if (p_event->eventType == kevent_capture_data_event) { + if (p_event->eventType == kevent_capture_256data_event) { if (hwss_has_captured_time_ms() <= (MAX_STORAGE_TIMEOUT_S * 1000)) { // ZLOGI("storage data 256 [%d]ms", hwss_has_captured_time_ms()); sample_data_mgr_write(m_cur_fd, p_event->val.capture_data_cache, 256); @@ -317,9 +319,13 @@ void app_event_process_cb(void* p_event_data, uint16_t event_size) { hwss_stop_capture(); } } - } else if (!m_plod_state_connected_state || p_event->eventType == kplod_disconnected_event) { + } else if (p_event->eventType == kevent_capture_1data_event) { + // 单帧实时上报 + ble_cmder_try_report_one_sample_data(p_event->val.frame_data.frameIndex, p_event->val.frame_data.data); + } else if (p_event->eventType == kplod_disconnected_event || !m_plod_state_connected_state) { if (hwss_has_captured_time_ms() < 30000) { // 采集不足30秒 + ble_cmder_try_report_sensor_drop_event(0x01, 0); /******************************************************************************* * 切换到采集出错页面 * *******************************************************************************/ @@ -347,11 +353,13 @@ void app_event_process_cb(void* p_event_data, uint16_t event_size) { if (ds_cur_state_haspassed_ms() >= 2000) { ZLOGI("ds_cur_state_haspassed_ms() %d> 2000", ds_cur_state_haspassed_ms()); state_machine__change_to_home_state(); + ble_cmder_report_sample_finish_event(); } } else if (ds_now_state() == kdevice_state_sampling_error) { if ((ds_cur_state_haspassed_ms() >= 2000) || (ds_cur_state_haspassed_ms() >= 1000 && m_plod_state_connected_state)) { ZLOGI("ds_cur_state_haspassed_ms() %d> 2000", ds_cur_state_haspassed_ms()); state_machine__change_to_home_state(); + ble_cmder_report_sample_finish_event(); } } } diff --git a/app/src/one_conduction/sample_data_manager.c b/app/src/one_conduction/sample_data_manager.c index e78c296..fdc822b 100644 --- a/app/src/one_conduction/sample_data_manager.c +++ b/app/src/one_conduction/sample_data_manager.c @@ -44,7 +44,7 @@ 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; } +bool 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 diff --git a/app/src/one_conduction/sample_data_manager.h b/app/src/one_conduction/sample_data_manager.h index 48910e7..07cd4af 100644 --- a/app/src/one_conduction/sample_data_manager.h +++ b/app/src/one_conduction/sample_data_manager.h @@ -1,4 +1,5 @@ #pragma once +#include #include #include "config.h" @@ -33,7 +34,7 @@ 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(); +bool 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); diff --git a/libznordic b/libznordic index 2117d96..9fccfb3 160000 --- a/libznordic +++ b/libznordic @@ -1 +1 @@ -Subproject commit 2117d966a451e4b5be5f4d0e822cabe625d39316 +Subproject commit 9fccfb3e530ffd0289bc36ba3b13509f90bb4323