#include "app_ble_service.h" #include "../../ify_hrs_protocol/heart_rate_sensor_protocol.h" #include "app_event.h" #include "app_event_distribute.h" #include "app_scheduler.h" #include "board/board.h" #include "board/board_battery_state.h" #include "device_ctrl_service.h" #include "heart_wave_sample_service.h" #include "sample_data_manager_service.h" #include "zble_module.h" #include "zdatachannel_service.h" #include "znordic.h" #include "znordic_device_info_mgr.h" static uint8_t rxbufcache[256]; static bool is_rxbufcache_used = false; // 接收到的消息是否正在被处理中 static bool m_realtime_report_state = false; // 实时上报状态 static uint8_t m_txbuf[128]; static uint8_t m_reportbuf[128]; static void prvf_process_ble_rx_data(void* p_event_data, uint16_t event_size); static void process_ble_rx_data(void* p_event_data, uint16_t event_size); /******************************************************************************* * 蓝牙服务注册 * *******************************************************************************/ ZDATACHANNEL_DEF(m_zhrs, 2 /*优先级*/, 1 /*client num*/); /** * @brief 蓝牙消息回调 */ static void zdatachannel_data_handler(zdatachannel_evt_t* p_evt) { if (p_evt->type != ZDATACHANNEL_EVT_RX_DATA) { return; } // 消息正在被处理中,丢弃新来的消息 if (is_rxbufcache_used) return; if (p_evt->params.rx_data.length > sizeof(rxbufcache)) return; memcpy(rxbufcache, p_evt->params.rx_data.p_data, p_evt->params.rx_data.length); uint32_t suc = app_sched_event_put(rxbufcache, p_evt->params.rx_data.length, process_ble_rx_data); if (suc == 0) { is_rxbufcache_used = true; } } /******************************************************************************* * UTILS * *******************************************************************************/ int ble_start_realtime_report() { m_realtime_report_state = true; return 0; } int ble_stop_realtime_report() { m_realtime_report_state = false; return 0; } static void send_error_receipt(ify_hrs_packet_t* rxpacket, int32_t errorcode) { ify_hrs_packet_t* txheader = (ify_hrs_packet_t*)m_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_send2(m_txbuf, sendlen); } static void send_success_receipt(ify_hrs_packet_t* rxpacket, int32_t emptydatasize) { ify_hrs_packet_t* txheader = (ify_hrs_packet_t*)m_txbuf; uint16_t sendlen = sizeof(ify_hrs_packet_t) + emptydatasize; txheader->cmd = rxpacket->cmd; txheader->frame_index = rxpacket->frame_index; txheader->frame_type = kifyhrs_pt_cmd_receipt; zdatachannel_data_send2(m_txbuf, sendlen); } static void prvf_try_report_sensor_drop_event(uint8_t dropstate0, uint8_t dropstate1) { sensor_drop_event_report_packet_t* reportpacket = (sensor_drop_event_report_packet_t*)m_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(m_reportbuf, sendlen); return; } static void prvf_try_report_sample_end_event() { ify_hrs_packet_t* reportpacket = (ify_hrs_packet_t*)m_reportbuf; reportpacket->cmd = ify_hrs_report_sample_finish_end; reportpacket->frame_index = 0; reportpacket->frame_type = kifyhrs_pt_report; uint16_t sendlen = sizeof(ify_hrs_packet_t); zdatachannel_data_send2(m_reportbuf, sendlen); return; } void prvf_report_sample_data(uint32_t frameIndex, uint32_t data, uint32_t data2, uint32_t data3) { if (!m_realtime_report_state) { return; } heartrate_report_packet_t* reportpacket = (heartrate_report_packet_t*)m_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] = (data >> 16) & 0xFF; reportpacket->data[3] = 0; /** * @brief 第二导联数据 */ reportpacket->data[4] = (data2 >> 0) & 0xFF; reportpacket->data[5] = (data2 >> 8) & 0xFF; reportpacket->data[6] = (data2 >> 16) & 0xFF; reportpacket->data[7] = 0; /** * @brief 第三导联数据 */ reportpacket->data[8] = (data3 >> 0) & 0xFF; reportpacket->data[9] = (data3 >> 8) & 0xFF; reportpacket->data[10] = (data3 >> 16) & 0xFF; reportpacket->data[11] = 0; uint16_t sendlen = sizeof(heartrate_report_packet_t) + 4 * 3; zdatachannel_data_send2(m_reportbuf, sendlen); return; } /******************************************************************************* * 消息处理 * *******************************************************************************/ static void process_ble_rx_data(void* p_event_data, uint16_t event_size) { // prvf_process_ble_rx_data(p_event_data, event_size); is_rxbufcache_used = false; } static void prvf_process_ble_rx_data(void* p_event_data, uint16_t len) { ify_hrs_packet_t* rxheader = (ify_hrs_packet_t*)p_event_data; ify_hrs_packet_t* txheader = (ify_hrs_packet_t*)m_txbuf; ify_hrs_cmd_t cmd = (ify_hrs_cmd_t)rxheader->cmd; memset(m_txbuf, 0, sizeof(m_txbuf)); ZLOGI("rx:"); NRF_LOG_HEXDUMP_INFO(p_event_data, len); ZLOGI("rx cmd:%d index:%d datalen:%d", cmd, rxheader->frame_index, len - sizeof(ify_hrs_packet_t)); txheader->cmd = rxheader->cmd; txheader->frame_index = rxheader->frame_index; txheader->frame_type = kifyhrs_pt_cmd_receipt; NRF_LOG_HEXDUMP_INFO(rxheader->data, len - sizeof(ify_hrs_packet_t)); 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_send2(m_txbuf, sendlen); } else if (cmd == 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_II; receipt->sensor1_pos = kifyhrs_sensor_pos_V1; receipt->sensor2_pos = kifyhrs_sensor_pos_V5; zdatachannel_data_send2(m_txbuf, sendlen); } else if (cmd == 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->drop_state0 = hwss_get_drop_state0(); receipt->drop_state1 = hwss_get_drop_state1(); receipt->drop_state1 = 0x00; receipt->device_state0.sampling_state = (DeviceCtrl_now_state() == kdevice_state_sampling); receipt->device_state0.report_state = m_realtime_report_state; receipt->device_state0.low_battery = (BoardBattery_get_battery_level() < 20); receipt->device_state0.full_storge = (SampleDataMgr_storageIsFull()); receipt->device_state1 = 0; receipt->powerlevel = BoardBattery_get_battery_level(); receipt->storage_item_num = SampleDataMgr_getFileNum(); zdatachannel_data_send2(m_txbuf, sendlen); } else if (cmd == 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_send2(m_txbuf, sendlen); } else if (cmd == 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_send2(m_txbuf, sendlen); } else if (cmd == ify_hrs_cmd_start_capture) { hwss_start_capture(); send_success_receipt(rxheader, 0); } else if (cmd == ify_hrs_cmd_stop_capture) { hwss_stop_capture(); send_success_receipt(rxheader, 0); } else if (cmd == ify_hrs_cmd_start_realtime_report) { // unsupport cmd int ecode = ble_start_realtime_report(); if (ecode == 0) { send_success_receipt(rxheader, 8); // 凑8个字节,使这个回执的字节长度同上报包长度一致,方便调试 } else { send_error_receipt(rxheader, ecode); } } else if (cmd == ify_hrs_cmd_stop_realtime_report) { int ecode = ble_stop_realtime_report(); if (ecode == 0) { send_success_receipt(rxheader, 0); } else { send_error_receipt(rxheader, ecode); } } else if (cmd == ify_hrs_cmd_read_records_info) { // 指令 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; // 采样时不支持 if (hwss_is_capturing()) { send_error_receipt(rxheader, kifyhrs_ecode_device_busy); return; } sample_data_fileinfo_list_t* recordlist = SampleDataMgr_getFileinfoList(); if (recordoff >= recordlist->count) { send_error_receipt(rxheader, kifyhrs_ecode_no_record_find); return; } sample_data_fileinfo_t* fileinfo = recordlist->fileinfo[recordoff]; memcpy(receipt->record_id, fileinfo->filename, 6); receipt->frameNum = fileinfo->size / 2; // 2byte per frame receipt->dataSize = fileinfo->size; receipt->sensorNum = 1; receipt->captureRate = SAMPLE_RATE / 10; receipt->capturePrecision = SAMPLE_PRECISION; receipt->compressAlgorithm = 0; zdatachannel_data_send2(m_txbuf, sendlen); } 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)); send_error_receipt(rxheader, kifyhrs_ecode_cmd_not_support); } else if (cmd == ify_hrs_cmd_start_upload_record) { // 指令 12-上传采集记录 send_error_receipt(rxheader, kifyhrs_ecode_cmd_not_support); } else if (cmd == ify_hrs_cmd_enter_ota) { send_error_receipt(rxheader, kifyhrs_ecode_cmd_not_support); } else if (cmd == 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_send2(m_txbuf, sendlen); } else if (cmd == ify_hrs_cmd_reset) { NVIC_SystemReset(); } // else { send_error_receipt(rxheader, kifyhrs_ecode_cmd_not_support); } } void AppBleService_onServiceInitCB() { ZLOGI("init zdatachannel service"); static zdatachannel_init_t zdatachannle_init; memset(&zdatachannle_init, 0, sizeof(zdatachannle_init)); zdatachannle_init.data_handler = zdatachannel_data_handler; ZERROR_CHECK(zdatachannel_init(&m_zhrs, &zdatachannle_init)); } static void app_event_listener(void* p_event_data, uint16_t event_size) { // app_event_t* event = (app_event_t*)p_event_data; if (event->eventType == kevent_sensor_drop) { prvf_try_report_sensor_drop_event(event->val.sensor_drop.drop0, event->val.sensor_drop.drop1); } else if (event->eventType == kevent_sample_stop_event) { prvf_try_report_sample_end_event(); } else if (event->eventType == kevent_capture_little_data_block_event) { // 上报采样数据 if (m_realtime_report_state) { // 上报采样数据 prvf_report_sample_data(event->val.little_data_block.frameIndex, // event->val.little_data_block.data[0].data0, // event->val.little_data_block.data[0].data1, // event->val.little_data_block.data[0].data2); } } } void AppBleService_init() { AppEvent_regListener(app_event_listener); }