15 changed files with 1498 additions and 4254 deletions
-
2.vscode/c_cpp_properties.json
-
3.vscode/settings.json
-
3CMakeLists.txt
-
491CMakeLists.txt.user
-
16libzqt/logger.cpp
-
7libzqt/logger.hpp
-
22libzqt/zexception.hpp
-
165mainwindow.cpp
-
12mainwindow.h
-
4219mainwindow.ui
-
206src/electrocardiograph_tester.cpp
-
95src/electrocardiograph_tester.hpp
-
202src/heart_rate_sensor_protocol.h
-
156src/qt_serial_datachannel.cpp
-
77src/qt_serial_datachannel.hpp
@ -0,0 +1,22 @@ |
|||
#pragma once
|
|||
|
|||
#include <exception>
|
|||
#include <string>
|
|||
|
|||
namespace std _GLIBCXX_VISIBILITY(default) { |
|||
|
|||
class zexception : public exception { |
|||
string m_ecodeinfo = ""; |
|||
int32_t m_ecode = 0; |
|||
|
|||
public: |
|||
/** Takes a character string describing the error. */ |
|||
explicit zexception(int32_t ecode, const string& __arg) { |
|||
m_ecodeinfo = __arg; |
|||
m_ecode = ecode; |
|||
} |
|||
|
|||
const char* what() const noexcept override { return m_ecodeinfo.c_str(); } |
|||
int32_t ecode() const noexcept { return m_ecode; } |
|||
}; |
|||
} // namespace std _GLIBCXX_VISIBILITY(default)
|
4219
mainwindow.ui
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,206 @@ |
|||
#include "electrocardiograph_tester.hpp"
|
|||
|
|||
#include <stdlib.h>
|
|||
#include <string.h>
|
|||
|
|||
#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) { |
|||
{ |
|||
lock_guard<mutex> 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<mutex> 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 { |
|||
processCh4RxData(packet, datalen); |
|||
} |
|||
|
|||
// 4. 移除已经处理的数据
|
|||
int32_t leftlen = m_rxlen - tailpos - 2; |
|||
if (leftlen > 0) { |
|||
memmove(m_rxcache, m_rxcache + tailpos + 2, leftlen); |
|||
} |
|||
m_rxlen = leftlen; |
|||
} |
|||
} |
|||
})); |
|||
} |
|||
|
|||
void ElectrocardiographTester::regReportCB(on_report_t cb) { m_on_report = cb; } |
|||
void ElectrocardiographTester::processCh4RxData(uint8_t *rx, int32_t rxlen) { |
|||
ZLOGI(TAG, "rx ch4: %s", zhex2str(rx, rxlen).c_str()); |
|||
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<mutex> 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; |
|||
} |
|||
m_on_report(rx, rxlen); |
|||
} |
|||
|
|||
void ElectrocardiographTester::readDeviceVersion(device_version_info_receipt_t *version) { |
|||
lock_guard<mutex> 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::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<mutex> lock(m_rxReceiptContext_lock); |
|||
m_rxReceiptContext.waittingIndex = txindex; |
|||
m_rxReceiptContext.waittingForReceipt = true; |
|||
m_rxReceiptContext.receiptIsReady = false; |
|||
m_rxReceiptContext.receiptLen = 0; |
|||
} |
|||
|
|||
m_channel->send((uint8_t *)tx, txlen); |
|||
bool rxreceipt = false; |
|||
|
|||
for (int32_t i = 0; i < overtime; i++) { |
|||
{ |
|||
lock_guard<mutex> lock(m_rxReceiptContext_lock); |
|||
/**
|
|||
* @brief 接收到回执 |
|||
*/ |
|||
if (m_rxReceiptContext.receiptIsReady) { |
|||
memcpy(rx, m_rxReceiptContext.receipt, m_rxReceiptContext.receiptLen); |
|||
*rxlen = m_rxReceiptContext.receiptLen; |
|||
rxreceipt = true; |
|||
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; |
|||
} |
@ -0,0 +1,95 @@ |
|||
#pragma once
|
|||
#include <fstream>
|
|||
#include <functional>
|
|||
#include <iostream>
|
|||
#include <list>
|
|||
#include <map>
|
|||
#include <memory>
|
|||
#include <mutex>
|
|||
#include <set>
|
|||
#include <sstream>
|
|||
#include <string>
|
|||
#include <thread>
|
|||
#include <vector>
|
|||
|
|||
#include "electrocardiograph_tester.hpp"
|
|||
#include "heart_rate_sensor_protocol.h"
|
|||
|
|||
#define SDK_VERSION 1
|
|||
|
|||
namespace iflytop { |
|||
using namespace std; |
|||
|
|||
typedef enum { |
|||
kuart_raw_tx, |
|||
kuart_raw_rx, |
|||
} uart_message_type_t; |
|||
|
|||
typedef function<void(ify_hrs_packet_t *report_packet, size_t len)> on_report_t; |
|||
|
|||
class IDataChannel { |
|||
public: |
|||
virtual ~IDataChannel(){}; |
|||
virtual bool isOpen() = 0; |
|||
virtual bool send(const uint8_t *data, size_t len) = 0; |
|||
virtual void regRxListener(function<void(uint8_t *data, size_t len)> cb) = 0; |
|||
}; |
|||
|
|||
class RxReceiptContext { |
|||
public: |
|||
bool waittingForReceipt; |
|||
bool receiptIsReady; |
|||
uint16_t waittingIndex; |
|||
uint8_t receipt[1024]; |
|||
size_t receiptLen; |
|||
}; |
|||
|
|||
class ElectrocardiographTester { |
|||
ElectrocardiographTester() {} |
|||
|
|||
IDataChannel *m_channel = nullptr; |
|||
|
|||
uint8_t m_rxcache[1024]; |
|||
int32_t m_rxlen = 0; |
|||
bool m_rxcache_is_full = false; |
|||
|
|||
mutex lock_; |
|||
|
|||
unique_ptr<thread> m_thread; |
|||
|
|||
RxReceiptContext m_rxReceiptContext; |
|||
mutex m_rxReceiptContext_lock; |
|||
|
|||
/*******************************************************************************
|
|||
* TX CONTEXT * |
|||
*******************************************************************************/ |
|||
mutex m_tx_lock; |
|||
uint8_t m_txbuf[1024]; |
|||
uint8_t m_rxbuf[1024]; |
|||
ify_hrs_packet_t *m_txcmd = (ify_hrs_packet_t *)m_txbuf; |
|||
ify_hrs_packet_t *m_rxcmd = (ify_hrs_packet_t *)m_rxbuf; |
|||
int32_t m_rxsize; |
|||
uint8_t m_txindex = 0; |
|||
|
|||
/*******************************************************************************
|
|||
* ReportCB * |
|||
*******************************************************************************/ |
|||
on_report_t m_on_report; |
|||
|
|||
public: |
|||
static ElectrocardiographTester *ins(); |
|||
|
|||
void initialize(IDataChannel *channel); |
|||
void regReportCB(on_report_t cb); |
|||
|
|||
public: |
|||
void readDeviceVersion(device_version_info_receipt_t *version); |
|||
|
|||
private: |
|||
void sendCmd(ify_hrs_packet_t *tx, int32_t txlen, ify_hrs_packet_t *rx, int32_t *rxlen, int32_t overtime); |
|||
void processCh3RxData(uint8_t *rx, int32_t rxlen); // 指令通道
|
|||
void processCh4RxData(uint8_t *rx, int32_t rxlen); // 心电原始数据通道
|
|||
void processRxReportPacket(ify_hrs_packet_t *rx, int32_t rxlen); |
|||
}; |
|||
|
|||
} // namespace iflytop
|
@ -0,0 +1,202 @@ |
|||
#include <stdint.h> |
|||
|
|||
#ifndef HEART_RATE_SENSOR_PROTOCOL_H |
|||
#define HEART_RATE_SENSOR_PROTOCOL_H |
|||
#ifdef __cplusplus |
|||
extern "C" { |
|||
#endif |
|||
|
|||
#pragma pack(push, 1) |
|||
|
|||
typedef struct { |
|||
uint8_t frame_type; |
|||
uint8_t frame_index; |
|||
uint8_t cmd; |
|||
uint8_t data[]; |
|||
} ify_hrs_packet_t; |
|||
|
|||
typedef enum { |
|||
kifyhrs_ecode_success = 0, |
|||
kifyhrs_ecode_unkown_error = 1, |
|||
kifyhrs_ecode_cmd_not_support = 2, |
|||
kifyhrs_ecode_illegal_parameter = 3, |
|||
kifyhrs_ecode_device_busy = 4, |
|||
kifyhrs_ecode_hardware_error = 5, |
|||
kifyhrs_ecode_sensor_drop = 6, |
|||
kifyhrs_ecode_no_record_find = 7, |
|||
|
|||
kifyhrs_ecode_channle_is_close = 100, |
|||
kifyhrs_ecode_overtime = 101, |
|||
kifyhrs_ecode_logic_error = 102, |
|||
|
|||
} ify_hrs_error_code_t; |
|||
|
|||
typedef enum { |
|||
kifyhrs_pt_cmd = 1, |
|||
kifyhrs_pt_cmd_receipt = 2, |
|||
kifyhrs_pt_report = 3, |
|||
kifyhrs_pt_error_receipt = 4, |
|||
} ify_hrs_packet_type_t; |
|||
|
|||
typedef enum { |
|||
kifyhrs_sensor_pos_none = 0, // 无指定位置 |
|||
kifyhrs_sensor_pos_I = 1, // I |
|||
kifyhrs_sensor_pos_II = 2, // II |
|||
kifyhrs_sensor_pos_III = 3, // III |
|||
kifyhrs_sensor_pos_V1 = 4, // V1 |
|||
kifyhrs_sensor_pos_V2 = 5, // V2 |
|||
kifyhrs_sensor_pos_V3 = 6, // V3 |
|||
kifyhrs_sensor_pos_V4 = 7, // V4 |
|||
kifyhrs_sensor_pos_V5 = 8, // V5 |
|||
kifyhrs_sensor_pos_V6 = 9, // V6 |
|||
kifyhrs_sensor_pos_aVR = 10, // |
|||
kifyhrs_sensor_pos_aVL = 11, // |
|||
kifyhrs_sensor_pos_aVF = 12, // |
|||
} ify_hrs_sensor_pos_t; |
|||
|
|||
typedef enum { |
|||
ify_hrs_cmd_read_device_version = 1, |
|||
ify_hrs_cmd_read_sensor_info = 2, |
|||
ify_hrs_cmd_read_device_state = 3, |
|||
ify_hrs_cmd_read_time = 4, |
|||
ify_hrs_cmd_sync_time = 5, |
|||
ify_hrs_cmd_start_capture = 6, |
|||
ify_hrs_cmd_stop_capture = 7, |
|||
ify_hrs_cmd_start_realtime_report = 8, |
|||
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_cmd_stop_upload_record = 16, |
|||
ify_hrs_report_heartrate_data = 101, |
|||
ify_hrs_report_battery_level = 102, |
|||
ify_hrs_report_low_battey_level = 103, |
|||
ify_hrs_report_sample_finish_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 { |
|||
uint8_t drop_state0; |
|||
uint8_t drop_state1; |
|||
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; // 记录存储条数 |
|||
} 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; |
|||
|
|||
/******************************************************************************* |
|||
* 上报相关结构体 * |
|||
*******************************************************************************/ |
|||
|
|||
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) |
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
#endif |
@ -0,0 +1,156 @@ |
|||
#include "qt_serial_datachannel.hpp"
|
|||
|
|||
//
|
|||
|
|||
#include <QtSerialPort/QSerialPort>
|
|||
#include <QtSerialPort/QSerialPortInfo>
|
|||
|
|||
#pragma comment(lib, "ws2_32.lib")
|
|||
|
|||
#include "logger.hpp"
|
|||
|
|||
using namespace iflytop; |
|||
using namespace std; |
|||
|
|||
#define TAG "QTDataChannel"
|
|||
|
|||
void QTDataChannel::init() { |
|||
m_thread.reset(new thread([this]() { |
|||
while (true) { |
|||
if (m_isOpen) { |
|||
uint8_t rx[1024] = {0}; |
|||
int rx_cnt = com_receive(rx, 1024); |
|||
if (rx_cnt != 0) { |
|||
// ZLOGI(TAG, "rx %s ", zhex2str(rx, rx_cnt).c_str());
|
|||
if (m_rxcb) m_rxcb(rx, rx_cnt); |
|||
} |
|||
this_thread::sleep_for(chrono::microseconds(100)); |
|||
} else { |
|||
this_thread::sleep_for(chrono::microseconds(10000)); |
|||
} |
|||
} |
|||
})); |
|||
} |
|||
bool QTDataChannel::open() { |
|||
char portnamebuf[256] = {0}; |
|||
sprintf(portnamebuf, "\\\\.\\%s", m_name.c_str()); |
|||
m_CommHandler = CreateFileA(portnamebuf, // port name
|
|||
GENERIC_READ | GENERIC_WRITE, // Read/Write
|
|||
0, // No Sharing
|
|||
NULL, // No Security
|
|||
OPEN_EXISTING, // Open existing port only
|
|||
0, // Non Overlapped I/O
|
|||
NULL); // Null for Comm Devices
|
|||
if (m_CommHandler == INVALID_HANDLE_VALUE) { |
|||
ZLOGI(TAG, "Error in opening serial port"); |
|||
return false; |
|||
} |
|||
DCB p; |
|||
memset(&p, 0, sizeof(p)); |
|||
p.DCBlength = sizeof(p); |
|||
p.BaudRate = m_baudRate; // 波特率
|
|||
|
|||
switch (m_dataBits) { |
|||
case QSerialPort::Data5: |
|||
p.ByteSize = 5; |
|||
break; |
|||
case QSerialPort::Data6: |
|||
p.ByteSize = 6; |
|||
break; |
|||
case QSerialPort::Data7: |
|||
p.ByteSize = 7; |
|||
break; |
|||
case QSerialPort::Data8: |
|||
p.ByteSize = 8; |
|||
break; |
|||
default: |
|||
p.ByteSize = 8; |
|||
break; |
|||
} |
|||
|
|||
// QSerialPort::NoParity = 0,
|
|||
// QSerialPort::EvenParity = 2,
|
|||
// QSerialPort::OddParity = 3,
|
|||
// QSerialPort::SpaceParity = 4,
|
|||
// QSerialPort::MarkParity = 5,
|
|||
// QSerialPort::UnknownParity = -1
|
|||
|
|||
switch (m_parity) // 校验位
|
|||
{ |
|||
case QSerialPort::NoParity: |
|||
p.Parity = NOPARITY; // 无校验
|
|||
break; |
|||
case QSerialPort::EvenParity: |
|||
p.Parity = EVENPARITY; // 奇校验
|
|||
break; |
|||
case QSerialPort::OddParity: |
|||
p.Parity = ODDPARITY; // 偶校验
|
|||
break; |
|||
case QSerialPort::MarkParity: |
|||
p.Parity = MARKPARITY; // 标记校验
|
|||
break; |
|||
default: |
|||
p.Parity = NOPARITY; // 无校验
|
|||
} |
|||
|
|||
switch (m_stopBits) // 停止位
|
|||
{ |
|||
case QSerialPort::OneStop: |
|||
p.StopBits = ONESTOPBIT; // 1位停止位
|
|||
break; |
|||
case QSerialPort::OneAndHalfStop: |
|||
p.StopBits = TWOSTOPBITS; // 2位停止位
|
|||
break; |
|||
case QSerialPort::TwoStop: |
|||
p.StopBits = ONE5STOPBITS; // 1.5位停止位
|
|||
break; |
|||
default: |
|||
p.StopBits = ONESTOPBIT; // 无校验
|
|||
} |
|||
|
|||
if (!SetCommState(m_CommHandler, &p)) { |
|||
// 设置参数失败
|
|||
CloseHandle(m_CommHandler); |
|||
return false; |
|||
} |
|||
m_isOpen = true; |
|||
return true; |
|||
} |
|||
|
|||
void QTDataChannel::close() { |
|||
CloseHandle(m_CommHandler); |
|||
m_isOpen = false; |
|||
} |
|||
|
|||
bool QTDataChannel::isOpen() { return m_isOpen; } |
|||
bool QTDataChannel::send(const uint8_t *data, size_t len) { |
|||
ZLOGI(TAG, "send %s", zhex2str(data, len).c_str()); |
|||
|
|||
DWORD dwBytesWrite = len; |
|||
BOOL bWriteStat = WriteFile(m_CommHandler, // 串口句柄
|
|||
(char *)data, // 数据首地址
|
|||
dwBytesWrite, // 要发送的数据字节数
|
|||
&dwBytesWrite, // DWORD*,用来接收返回成功发送的数据字节数
|
|||
NULL); // NULL为同步发送,OVERLAPPED*为异步发送
|
|||
return dwBytesWrite; |
|||
} |
|||
void QTDataChannel::regRxListener(function<void(uint8_t *data, size_t len)> cb) { m_rxcb = cb; } |
|||
|
|||
int QTDataChannel::com_receive(uint8_t *rxbuf, int rxbufsize) { |
|||
COMMTIMEOUTS TimeOuts; |
|||
GetCommTimeouts(m_CommHandler, &TimeOuts); |
|||
TimeOuts.ReadIntervalTimeout = 0; // 读间隔超时
|
|||
TimeOuts.ReadTotalTimeoutMultiplier = 0; // 读时间系数
|
|||
TimeOuts.ReadTotalTimeoutConstant = 1; // 读时间常量
|
|||
SetCommTimeouts(m_CommHandler, &TimeOuts); |
|||
|
|||
// PurgeComm(m_CommHandler, PURGE_RXCLEAR);
|
|||
|
|||
DWORD wCount = rxbufsize; // 成功读取的数据字节数
|
|||
BOOL bReadStat = ReadFile(m_CommHandler, // 串口句柄
|
|||
rxbuf, // 数据首地址
|
|||
wCount, // 要读取的数据最大字节数
|
|||
&wCount, // DWORD*,用来接收返回成功读取的数据字节数
|
|||
NULL); |
|||
return wCount; |
|||
} |
@ -0,0 +1,77 @@ |
|||
#pragma once
|
|||
|
|||
#include <fstream>
|
|||
#include <functional>
|
|||
#include <iostream>
|
|||
#include <list>
|
|||
#include <map>
|
|||
#include <memory>
|
|||
#include <mutex>
|
|||
#include <set>
|
|||
#include <sstream>
|
|||
#include <string>
|
|||
#include <vector>
|
|||
//
|
|||
|
|||
#include <winsock2.h>
|
|||
//
|
|||
#include <Windows.h>
|
|||
//
|
|||
#include <QtSerialPort/QSerialPort>
|
|||
#include <QtSerialPort/QSerialPortInfo>
|
|||
//
|
|||
#include "zqthread.hpp"
|
|||
#include "electrocardiograph_tester.hpp"
|
|||
|
|||
#define SDK_VERSION 1
|
|||
|
|||
namespace iflytop { |
|||
using namespace std; |
|||
// QT_CHARTS_USE_NAMESPACE
|
|||
|
|||
typedef function<void(bool connect)> device_state_cb_t; |
|||
|
|||
class QTDataChannel : public IDataChannel { |
|||
function<void(uint8_t *data, size_t len)> m_rxcb; |
|||
|
|||
QSerialPort::DataBits m_dataBits; |
|||
QSerialPort::Parity m_parity; |
|||
QSerialPort::StopBits m_stopBits; |
|||
QSerialPort::FlowControl m_flowControl; |
|||
string m_name; |
|||
|
|||
unique_ptr<thread> m_thread; |
|||
|
|||
uint32_t m_baudRate; |
|||
HANDLE m_CommHandler; |
|||
|
|||
bool m_isOpen = false; |
|||
|
|||
public: |
|||
void init(); |
|||
|
|||
virtual bool isOpen() override; |
|||
virtual bool send(const uint8_t *data, size_t len) override; |
|||
virtual void regRxListener(function<void(uint8_t *data, size_t len)> cb) override; |
|||
|
|||
bool open(); |
|||
void close(); |
|||
|
|||
void setBaudRate(qint32 baudRate) { m_baudRate = baudRate; } |
|||
qint32 baudRate() const { return m_baudRate; } |
|||
|
|||
void setPortName(string name) { m_name = name; } |
|||
void setDataBits(QSerialPort::DataBits dataBits) { m_dataBits = dataBits; } |
|||
void setParity(QSerialPort::Parity parity) { m_parity = parity; } |
|||
void setStopBits(QSerialPort::StopBits stopBits) { m_stopBits = stopBits; } |
|||
void setFlowControl(QSerialPort::FlowControl flowControl) { m_flowControl = flowControl; } |
|||
|
|||
QSerialPort::DataBits dataBits() const { return m_dataBits; } |
|||
QSerialPort::Parity parity() const { return m_parity; } |
|||
QSerialPort::StopBits stopBits() const { return m_stopBits; } |
|||
QSerialPort::FlowControl flowControl() const { return m_flowControl; } |
|||
|
|||
private: |
|||
int com_receive(uint8_t *rxbuf, int rxbufsize); |
|||
}; |
|||
} // namespace iflytop
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue