#include "electrocardiograph_tester.hpp" #include #include #include "logger.hpp" #include "zexception.hpp" using namespace iflytop; #define TAG "ElectrocardiographTester" /******************************************************************************* * UTILS_BEGIN * *******************************************************************************/ static bool isHeader(uint8_t *data, uint8_t *headerType) { if (data[0] == 0x5A && data[1] == 0xA5) { *headerType = 1; return true; } if (data[0] == 0x4A && data[1] == 0xA4) { *headerType = 2; return true; } return false; } static bool isTail(uint8_t headerType, uint8_t *data) { if (headerType == 1 && data[0] == 0x5B && data[1] == 0xB5) { return true; } if (headerType == 2 && data[0] == 0x4B && data[1] == 0xB4) { return true; } return false; } /******************************************************************************* * UTILS_END * *******************************************************************************/ ElectrocardiographTester *ElectrocardiographTester::ins() { static ElectrocardiographTester *ins = nullptr; if (ins == nullptr) { ins = new ElectrocardiographTester(); } return ins; } void ElectrocardiographTester::initialize(IDataChannel *channel) { // m_channel = channel; m_channel->regRxListener([this](uint8_t *data, size_t len) { { // ZLOGI(TAG, "rx: %s", zhex2str(data, len).c_str()); lock_guard lock(lock_); if (len + m_rxlen > sizeof(m_rxcache)) { m_rxlen = 0; } memcpy(m_rxcache + m_rxlen, data, len); m_rxlen += len; } }); m_thread.reset(new thread([this]() { while (true) { this_thread::sleep_for(chrono::milliseconds(2)); { lock_guard lock(lock_); // 1.找头部 int32_t headerpos = -1; uint8_t headerType = 0; for (int32_t i = 0; i < m_rxlen - 1; i++) { if (isHeader(m_rxcache + i, &headerType)) { headerpos = i; break; } } if (headerpos == -1) { continue; } // 2.找尾 int32_t tailpos = -1; for (int32_t i = headerpos + 2; i < m_rxlen - 1; i++) { if (isTail(headerType, m_rxcache + i)) { tailpos = i; break; } } if (tailpos == -1) { continue; } // 3.处理数据 int32_t datalen = tailpos - headerpos + 2; uint8_t *packet = &m_rxcache[headerpos]; if (packet[0] == 0x5A && packet[1] == 0xA5) { processCh3RxData(packet, datalen); } else if (packet[0] == 0x4B && packet[1] == 0xB4) { processCh4RxData(packet, datalen); } else { ZLOGI(TAG, "unknow packet: %s", zhex2str(packet, datalen).c_str()); } // 4. 移除已经处理的数据 int32_t leftlen = m_rxlen - tailpos - 2; if (leftlen > 0) { memmove(m_rxcache, m_rxcache + tailpos + 2, leftlen); } m_rxlen = leftlen; } } })); } // m_on_raw_data_cb void ElectrocardiographTester::regReportCB(on_report_t cb) { m_on_report = cb; } void ElectrocardiographTester::regCh4CheckSumPacketReport(on_ch4_check_sum_packet_report_t cb) { m_on_ch4_check_sum_packet_report = cb; } void ElectrocardiographTester::regRawDataCB(on_raw_data_t cb) { m_on_raw_data_cb = cb; } typedef struct { uint32_t rxcnt; uint32_t m_rx_sum_cnt; } block_data_rx_state_t; void ElectrocardiographTester::processCh4RxData(uint8_t *rx, int32_t rxlen) { block_data_rx_state_t *block_data_rx_state = (block_data_rx_state_t *)&rx[2]; if (m_on_ch4_check_sum_packet_report) m_on_ch4_check_sum_packet_report(block_data_rx_state->rxcnt, block_data_rx_state->m_rx_sum_cnt); return; } void ElectrocardiographTester::processCh3RxData(uint8_t *rx, int32_t rxlen) { ify_hrs_packet_t *rxcmd = (ify_hrs_packet_t *)&rx[2]; if (rxcmd->frame_type == kifyhrs_pt_cmd_receipt || rxcmd->frame_type == kifyhrs_pt_error_receipt) { if (rxcmd->frame_index == m_rxReceiptContext.waittingIndex) { lock_guard lock(m_rxReceiptContext_lock); m_rxReceiptContext.receiptIsReady = true; m_rxReceiptContext.receiptLen = rxlen; memcpy(m_rxReceiptContext.receipt, &rx[2], rxlen - 2); } else { ZLOGE(TAG, "Rx index not match, %s", zhex2str(rx, rxlen).c_str()); return; } } else if (rxcmd->frame_type == kifyhrs_pt_report) { processRxReportPacket(rxcmd, rxlen); } } void ElectrocardiographTester::processRxReportPacket(ify_hrs_packet_t *rx, int32_t rxlen) { if (m_on_report == nullptr) { return; } if (m_on_raw_data_cb) m_on_raw_data_cb(kcmd_report, (uint8_t *)rx, rxlen); m_on_report(rx, rxlen); } void ElectrocardiographTester::sendCmd(ify_hrs_packet_t *tx, int32_t txlen, ify_hrs_packet_t *rx, int32_t *rxlen, int32_t overtime) { if (m_channel == nullptr || m_channel->isOpen() == false) { throw zexception(kifyhrs_ecode_channle_is_close, "channel is not open"); } uint8_t txindex = m_txindex++; ify_hrs_packet_t *txcmd = (ify_hrs_packet_t *)tx; txcmd->frame_index = txindex; txcmd->frame_type = kifyhrs_pt_cmd; { lock_guard lock(m_rxReceiptContext_lock); m_rxReceiptContext.waittingIndex = txindex; m_rxReceiptContext.waittingForReceipt = true; m_rxReceiptContext.receiptIsReady = false; m_rxReceiptContext.receiptLen = 0; } if (m_on_raw_data_cb) m_on_raw_data_cb(kcmd_cmd, (uint8_t *)tx, txlen); m_channel->send((uint8_t *)tx, txlen); bool rxreceipt = false; for (int32_t i = 0; i < overtime; i++) { { lock_guard lock(m_rxReceiptContext_lock); /** * @brief 接收到回执 */ if (m_rxReceiptContext.receiptIsReady) { memcpy(rx, m_rxReceiptContext.receipt, m_rxReceiptContext.receiptLen); *rxlen = m_rxReceiptContext.receiptLen; rxreceipt = true; if (m_on_raw_data_cb) m_on_raw_data_cb(kcmd_receipt, (uint8_t *)rx, *rxlen); break; } } this_thread::sleep_for(chrono::milliseconds(1)); } if (!rxreceipt) { throw zexception(kifyhrs_ecode_overtime, "overtime"); } ify_hrs_packet_t *rxcmd = (ify_hrs_packet_t *)rx; if (rxcmd->frame_type == kifyhrs_pt_error_receipt) { error_receipt_t *receipt = (error_receipt_t *)rxcmd->data; throw zexception(receipt->errorcode, "ecode"); } return; } void ElectrocardiographTester::readDeviceVersion(device_version_info_receipt_t *version) { lock_guard lock(m_tx_lock); m_txcmd->cmd = ify_hrs_cmd_read_device_version; sendCmd(m_txcmd, sizeof(ify_hrs_packet_t), m_rxcmd, &m_rxsize, 100); device_version_info_receipt_t *receipt = (device_version_info_receipt_t *)m_rxcmd->data; memcpy(version, receipt, sizeof(device_version_info_receipt_t)); return; } void ElectrocardiographTester::readSensorInfo(sensor_info_receipt_t *sensor) { lock_guard lock(m_tx_lock); m_txcmd->cmd = ify_hrs_cmd_read_sensor_info; sendCmd(m_txcmd, sizeof(ify_hrs_packet_t), m_rxcmd, &m_rxsize, 100); sensor_info_receipt_t *receipt = (sensor_info_receipt_t *)m_rxcmd->data; memcpy(sensor, receipt, sizeof(sensor_info_receipt_t)); return; } void ElectrocardiographTester::readDeviceState(device_state_receipt_t *state) { lock_guard lock(m_tx_lock); m_txcmd->cmd = ify_hrs_cmd_read_device_state; sendCmd(m_txcmd, sizeof(ify_hrs_packet_t), m_rxcmd, &m_rxsize, 100); device_state_receipt_t *receipt = (device_state_receipt_t *)m_rxcmd->data; memcpy(state, receipt, sizeof(device_state_receipt_t)); return; } void ElectrocardiographTester::readTime(read_time_receipt_t *time) { lock_guard lock(m_tx_lock); m_txcmd->cmd = ify_hrs_cmd_read_time; sendCmd(m_txcmd, sizeof(ify_hrs_packet_t), m_rxcmd, &m_rxsize, 100); read_time_receipt_t *receipt = (read_time_receipt_t *)m_rxcmd->data; memcpy(time, receipt, sizeof(read_time_receipt_t)); return; } void ElectrocardiographTester::syncTime(uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { lock_guard lock(m_tx_lock); sync_time_cmd_t *cmd = (sync_time_cmd_t *)m_txcmd->data; cmd->year = year; cmd->month = month; cmd->day = day; cmd->hour = hour; cmd->minute = minute; cmd->second = second; m_txcmd->cmd = ify_hrs_cmd_sync_time; sendCmd(m_txcmd, sizeof(ify_hrs_packet_t) + sizeof(sync_time_cmd_t), m_rxcmd, &m_rxsize, 100); return; } void ElectrocardiographTester::startCapture() { lock_guard lock(m_tx_lock); m_txcmd->cmd = ify_hrs_cmd_start_capture; sendCmd(m_txcmd, sizeof(ify_hrs_packet_t), m_rxcmd, &m_rxsize, 100); return; } void ElectrocardiographTester::stopCapture() { lock_guard lock(m_tx_lock); m_txcmd->cmd = ify_hrs_cmd_stop_capture; sendCmd(m_txcmd, sizeof(ify_hrs_packet_t), m_rxcmd, &m_rxsize, 100); return; } void ElectrocardiographTester::startRealtimeReport() { lock_guard lock(m_tx_lock); m_txcmd->cmd = ify_hrs_cmd_start_realtime_report; sendCmd(m_txcmd, sizeof(ify_hrs_packet_t), m_rxcmd, &m_rxsize, 100); return; } void ElectrocardiographTester::stopRealtimeReport() { lock_guard lock(m_tx_lock); m_txcmd->cmd = ify_hrs_cmd_stop_realtime_report; sendCmd(m_txcmd, sizeof(ify_hrs_packet_t), m_rxcmd, &m_rxsize, 100); return; } void ElectrocardiographTester::readRecordsInfo(int32_t recordoff, read_record_info_receipt_t *recordinfo) { lock_guard lock(m_tx_lock); m_txcmd->cmd = ify_hrs_cmd_read_records_info; read_record_info_cmd_t *cmd = (read_record_info_cmd_t *)m_txcmd->data; cmd->record_index = recordoff; sendCmd(m_txcmd, sizeof(ify_hrs_packet_t) + sizeof(read_record_info_cmd_t), m_rxcmd, &m_rxsize, 100); read_record_info_receipt_t *receipt = (read_record_info_receipt_t *)m_rxcmd->data; memcpy(recordinfo, receipt, sizeof(read_record_info_receipt_t)); return; } void ElectrocardiographTester::delRecord(uint8_t *recordId) { lock_guard lock(m_tx_lock); del_record_cmd_t *cmd = (del_record_cmd_t *)m_txcmd->data; memcpy(cmd->record_id, recordId, 6); m_txcmd->cmd = ify_hrs_cmd_del_record; sendCmd(m_txcmd, sizeof(ify_hrs_packet_t) + sizeof(del_record_cmd_t), m_rxcmd, &m_rxsize, 100); return; } void ElectrocardiographTester::startUploadRecord(uint8_t *recordId) { lock_guard lock(m_tx_lock); start_upload_record_cmd_t *cmd = (start_upload_record_cmd_t *)m_txcmd->data; memcpy(cmd->record_id, recordId, 6); m_txcmd->cmd = ify_hrs_cmd_start_upload_record; sendCmd(m_txcmd, sizeof(ify_hrs_packet_t) + sizeof(start_upload_record_cmd_t), m_rxcmd, &m_rxsize, 100); return; } void ElectrocardiographTester::stopUploadRecord() { lock_guard lock(m_tx_lock); m_txcmd->cmd = ify_hrs_cmd_stop_upload_record; sendCmd(m_txcmd, sizeof(ify_hrs_packet_t), m_rxcmd, &m_rxsize, 100); return; } void ElectrocardiographTester::readSn(string &sn) { lock_guard lock(m_tx_lock); m_txcmd->cmd = ify_hrs_cmd_read_sn; sendCmd(m_txcmd, sizeof(ify_hrs_packet_t), m_rxcmd, &m_rxsize, 100); read_sn_receipt_t *receipt = (read_sn_receipt_t *)m_rxcmd->data; sn = string((char *)receipt->sn, 14); return; } void ElectrocardiographTester::reset() { lock_guard lock(m_tx_lock); m_txcmd->cmd = ify_hrs_cmd_reset; sendCmd(m_txcmd, sizeof(ify_hrs_packet_t), m_rxcmd, &m_rxsize, 100); return; }