You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

525 lines
19 KiB

2 years ago
2 years ago
1 year ago
2 years ago
1 year ago
2 years ago
2 years ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
1 year ago
2 years ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. #include "mainwindow.h"
  2. #include <QDateTime>
  3. #include <QMessageBox>
  4. #include <QtConcurrent>
  5. #include <QtSerialPort/QSerialPort>
  6. #include <QtSerialPort/QSerialPortInfo>
  7. #include "./ui_mainwindow.h"
  8. #include "electrocardiograph_tester.hpp"
  9. #include "logger.hpp"
  10. #include "qt_serial_datachannel.hpp"
  11. #include "widgetplot2d.h"
  12. #include "zexception.hpp"
  13. WidgetPlot2D *wp2d;
  14. using namespace std;
  15. using namespace iflytop;
  16. typedef enum {
  17. kone_lead_ecg,
  18. kthree_lead_ecg,
  19. } device_type_t;
  20. static MainWindow *m_mainWindow;
  21. static QTDataChannel G_QTDataChannel;
  22. static device_type_t m_devicetype;
  23. #define TAG "MainWindow"
  24. static const char *fmt(const char *fmt, ...) {
  25. va_list args;
  26. va_start(args, fmt);
  27. static char buf[1024] = {0};
  28. vsnprintf(buf, sizeof(buf), fmt, args);
  29. va_end(args);
  30. return buf;
  31. }
  32. void MainWindow::log_output(QtMsgType type, const QMessageLogContext &context, const QString &msg) {}
  33. void MainWindow::doinui_slot(QFunction func) {
  34. if (func.get()) func.get()();
  35. }
  36. void MainWindow::instructionPreviewShow(const char *fmt, ...) {
  37. va_list args;
  38. va_start(args, fmt);
  39. char buf[1024] = {0};
  40. vsnprintf(buf, sizeof(buf), fmt, args);
  41. va_end(args);
  42. QString text(buf);
  43. QString info;
  44. info.append(QDateTime::currentDateTime().toString("hh:mm:ss.zzz "));
  45. info.append(" |");
  46. info.append(text);
  47. emit doinui_signal(QFunction([this, info]() { ui->instructionPreview->append(info); }));
  48. }
  49. void MainWindow::instructionPreviewClear() { ui->instructionPreview->document()->clear(); }
  50. void MainWindow::reportPreviewShow(const char *fmt, ...) {
  51. va_list args;
  52. va_start(args, fmt);
  53. char buf[1024] = {0};
  54. vsnprintf(buf, sizeof(buf), fmt, args);
  55. va_end(args);
  56. QString text(buf);
  57. QString info;
  58. info.append(QDateTime::currentDateTime().toString("hh:mm:ss.zzz "));
  59. info.append(text);
  60. emit doinui_signal(QFunction([this, info]() {
  61. if (ui->reportPreview->document()->lineCount() > 1000) {
  62. ui->reportPreview->document()->clear();
  63. }
  64. ui->reportPreview->append(info);
  65. }));
  66. }
  67. void MainWindow::blockDataUploadPreviewShow(const char *fmt, ...) {
  68. va_list args;
  69. va_start(args, fmt);
  70. char buf[1024] = {0};
  71. vsnprintf(buf, sizeof(buf), fmt, args);
  72. va_end(args);
  73. QString text(buf);
  74. QString info;
  75. info.append(QDateTime::currentDateTime().toString("hh:mm:ss.zzz "));
  76. info.append(text);
  77. emit doinui_signal(QFunction([this, info]() {
  78. if (ui->uploadDataPreview->document()->lineCount() > 1000) {
  79. ui->uploadDataPreview->document()->clear();
  80. }
  81. ui->uploadDataPreview->append(info);
  82. }));
  83. }
  84. void MainWindow::rawDataPreviewShow(const char *fmt, ...) {
  85. va_list args;
  86. va_start(args, fmt);
  87. char buf[1024] = {0};
  88. vsnprintf(buf, sizeof(buf), fmt, args);
  89. va_end(args);
  90. QString text(buf);
  91. QString info;
  92. info.append(QDateTime::currentDateTime().toString("hh:mm:ss.zzz"));
  93. info.append(text);
  94. emit doinui_signal(QFunction([this, info]() {
  95. if (ui->rawDataPreview->document()->lineCount() > 1000) {
  96. ui->rawDataPreview->document()->clear();
  97. }
  98. ui->rawDataPreview->append(info);
  99. }));
  100. }
  101. // uploadDataPreview
  102. #pragma pack(push, 1)
  103. typedef struct {
  104. uint16_t header;
  105. int16_t wave1;
  106. int16_t wave2;
  107. int16_t wave3;
  108. int16_t wave4;
  109. int16_t wave5;
  110. uint8_t check;
  111. uint16_t tail;
  112. } Wave_t;
  113. #pragma pack(pop)
  114. void MainWindow::displayInfo(bool suc, QString info) {}
  115. MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
  116. /*******************************************************************************
  117. * QT初始化 *
  118. *******************************************************************************/
  119. ui->setupUi(this);
  120. m_mainWindow = this;
  121. qRegisterMetaType<int32_t>("int32_t");
  122. qRegisterMetaType<uint32_t>("uint32_t");
  123. qRegisterMetaType<float>("float");
  124. qRegisterMetaType<function<void()>>("function<void()>");
  125. qRegisterMetaType<QFunction>("QFunction");
  126. connect(this, SIGNAL(doinui_signal(QFunction)), this, SLOT(doinui_slot(QFunction)));
  127. // qInstallMessageHandler(log_output);
  128. wp2d = new WidgetPlot2D();
  129. wp2d->initGraphName(QStringList() << "心电");
  130. /*******************************************************************************
  131. * *
  132. *******************************************************************************/
  133. constructUI();
  134. /*******************************************************************************
  135. * *
  136. *******************************************************************************/
  137. G_QTDataChannel.init();
  138. ElectrocardiographTester::ins()->initialize(&G_QTDataChannel);
  139. }
  140. MainWindow::~MainWindow() { delete ui; }
  141. /*******************************************************************************
  142. * UI相关构造 *
  143. *******************************************************************************/
  144. void MainWindow::constructUI() {
  145. /*******************************************************************************
  146. * UI *
  147. *******************************************************************************/
  148. {
  149. const auto infos = QSerialPortInfo::availablePorts();
  150. for (const QSerialPortInfo &info : infos) {
  151. ui->serialPortCB->addItem(info.portName());
  152. }
  153. }
  154. ui->serialBaudrateCB->addItem("9600");
  155. ui->serialBaudrateCB->addItem("14400");
  156. ui->serialBaudrateCB->addItem("19200");
  157. ui->serialBaudrateCB->addItem("38400");
  158. ui->serialBaudrateCB->addItem("57600");
  159. ui->serialBaudrateCB->addItem("115200");
  160. ui->serialBaudrateCB->addItem("460800");
  161. ui->serialBaudrateCB->addItem("500000");
  162. ui->serialBaudrateCB->setCurrentIndex(6);
  163. connect(ui->serialPortRefreshKey, &QPushButton::clicked, this, [this](bool check) {
  164. ui->serialPortCB->clear();
  165. const auto infos = QSerialPortInfo::availablePorts();
  166. for (const QSerialPortInfo &info : infos) {
  167. ui->serialPortCB->addItem(info.portName());
  168. }
  169. });
  170. connect(ui->serialOpenKey, &QPushButton::clicked, this, [=](bool check) {
  171. // 打开串口
  172. if (ui->serialOpenKey->text() == "打开") {
  173. G_QTDataChannel.setPortName(ui->serialPortCB->currentText().toStdString());
  174. G_QTDataChannel.setBaudRate(ui->serialBaudrateCB->currentText().toInt());
  175. G_QTDataChannel.setDataBits(QSerialPort::Data8);
  176. G_QTDataChannel.setParity(QSerialPort::NoParity);
  177. G_QTDataChannel.setFlowControl(QSerialPort::NoFlowControl);
  178. G_QTDataChannel.setStopBits(QSerialPort::OneStop);
  179. if (!G_QTDataChannel.open()) {
  180. QMessageBox::about(NULL, "提示", "串口无法打开,串口不存在或已被占??");
  181. return;
  182. }
  183. ui->serialOpenKey->setText("关闭");
  184. // 下拉菜单控件使能
  185. ui->serialBaudrateCB->setEnabled(false);
  186. ui->serialPortCB->setEnabled(false);
  187. ui->serialPortRefreshKey->setEnabled(false);
  188. } else {
  189. G_QTDataChannel.close();
  190. ui->serialOpenKey->setText("打开");
  191. ui->serialBaudrateCB->setEnabled(true);
  192. ui->serialPortCB->setEnabled(true);
  193. ui->serialPortRefreshKey->setEnabled(true);
  194. }
  195. });
  196. /*******************************************************************************
  197. * UI *
  198. *******************************************************************************/
  199. {
  200. ui->deviceType->addItem("单导联一代(M1001)");
  201. ui->deviceType->addItem("三导联一代(M1002)");
  202. ui->deviceType->setCurrentIndex(0);
  203. connect(ui->deviceType, &QComboBox::currentTextChanged, this, [this](const QString &text) {
  204. if (text == "单导联一代(M1001)") {
  205. m_devicetype = kone_lead_ecg;
  206. } else if (text == "三导联一代(M1002)") {
  207. m_devicetype = kthree_lead_ecg;
  208. }
  209. });
  210. }
  211. // 事件填充
  212. ElectrocardiographTester::ins()->regReportCB([this](bool checkok, ify_hrs_packet_t *report_packet, size_t len) {
  213. int reportType = report_packet->cmd;
  214. switch (reportType) {
  215. case ify_hrs_report_heartrate_data: {
  216. heartrate_report_packet_t *heartrate_report = (heartrate_report_packet_t *)report_packet;
  217. if (m_devicetype == kone_lead_ecg) {
  218. if (checkok) {
  219. uint16_t data0 = (uint16_t)(heartrate_report->data[0]) + ((uint16_t)heartrate_report->data[1] << 8);
  220. uint16_t data1 = (uint16_t)(heartrate_report->data[2]) + ((uint16_t)heartrate_report->data[3] << 8);
  221. uint16_t data2 = (uint16_t)(heartrate_report->data[4]) + ((uint16_t)heartrate_report->data[5] << 8);
  222. uint16_t data3 = (uint16_t)(heartrate_report->data[6]) + ((uint16_t)heartrate_report->data[7] << 8);
  223. uint16_t data4 = (uint16_t)(heartrate_report->data[8]) + ((uint16_t)heartrate_report->data[9] << 8);
  224. emit doinui_signal(QFunction([this, data0, data1, data2, data3, data4]() { //
  225. reportPreviewShow("[preview data ] index %llu %d", data0);
  226. wp2d->addData("心电", data0, 0);
  227. wp2d->addData("心电", data1, 2);
  228. wp2d->addData("心电", data2, 4);
  229. wp2d->addData("心电", data3, 6);
  230. wp2d->addData("心电", data4, 8);
  231. // wp2d->addData("心电", data2);
  232. // wp2d->addData("心电", data3);
  233. // wp2d->addData("心电", data4);
  234. }));
  235. }
  236. } else if (m_devicetype == kthree_lead_ecg) {
  237. }
  238. // heartrate_report->data[]
  239. // uin
  240. // uint16_t header = 0xA55A;
  241. // uint16_t tail = 0xB55B;
  242. // G_WaveDataChannel.send((uint8_t *)&header, sizeof(header));
  243. // G_WaveDataChannel.send((uint8_t *)report_packet, len);
  244. // G_WaveDataChannel.send((uint8_t *)&tail, sizeof(tail));
  245. // if (m_devicetype == kone_lead_ecg) {
  246. // reportPreviewShow("[preview data ] checksum_ok:%d index %llu", checkok, heartrate_report->sample_data_index);
  247. // } else if (m_devicetype == kthree_lead_ecg) {
  248. // displayWave(heartrate_report->data[0], heartrate_report->data[1], heartrate_report->data[2]);
  249. // }
  250. // break;
  251. }
  252. case ify_hrs_report_battery_level: {
  253. reportPreviewShow("[battery_level ]");
  254. break;
  255. }
  256. case ify_hrs_report_low_battey_level: {
  257. reportPreviewShow("[low_battey ]");
  258. break;
  259. }
  260. case ify_hrs_report_sample_finish_end: {
  261. reportPreviewShow("[sample_finish ]");
  262. break;
  263. }
  264. case ify_hrs_report_sensor_drop_detect: {
  265. sensor_drop_event_report_packet_t *sensor_drop_report = (sensor_drop_event_report_packet_t *)report_packet->data;
  266. reportPreviewShow("[sensor_drop ] %s %s", zhex2binary(sensor_drop_report->drop_state0).c_str(), zhex2binary(sensor_drop_report->drop_state1).c_str());
  267. break;
  268. }
  269. case ify_hrs_report_record_upload_end: {
  270. uint32_t checksum = *(uint32_t *)report_packet->data;
  271. reportPreviewShow("[upload end ] checksum: 0x%08x", checksum);
  272. break;
  273. }
  274. default:
  275. break;
  276. }
  277. });
  278. ElectrocardiographTester::ins()->regCh4CheckSumPacketReport([this](uint32_t rxcnt, uint32_t report_packet_checksum) { //
  279. blockDataUploadPreviewShow("RXCNT %d CHECKSUM 0x%08x", rxcnt, report_packet_checksum);
  280. });
  281. ElectrocardiographTester::ins()->regRawDataCB([this](raw_data_type_t type, uint8_t *hex, uint32_t hexlen) {
  282. if (type == kcmd_cmd) {
  283. rawDataPreviewShow("[CMD ] %s", zhex2str(hex, hexlen).c_str());
  284. } else if (type == kcmd_receipt) {
  285. rawDataPreviewShow("[RECEIPT] %s", zhex2str(hex, hexlen).c_str());
  286. } else if (type == kcmd_report) {
  287. rawDataPreviewShow("[REPORT ] %s", zhex2str(hex, hexlen).c_str());
  288. } else if (type == kcmd_ch4_data) {
  289. // rawDataPreviewShow("[CH4 ] %s", zhex2str(hex, hexlen).c_str());
  290. }
  291. });
  292. }
  293. void MainWindow::processException(zexception &e) { instructionPreviewShow("%s:%s", e.what(), hrs_ecode2str((ify_hrs_error_code_t)e.ecode())); }
  294. void MainWindow::on_readDeviceVersion_clicked() {
  295. instructionPreviewClear();
  296. try {
  297. device_version_info_receipt_t version;
  298. ElectrocardiographTester::ins()->readDeviceVersion(&version);
  299. instructionPreviewShow("-------------- version ----------------");
  300. instructionPreviewShow(" blestack_version: %d", version.blestack_version);
  301. instructionPreviewShow(" bootloader_version: %d", version.bootloader_version);
  302. instructionPreviewShow(" firmware_version: %d", version.firmware_version);
  303. instructionPreviewShow(" hardware_version: %d", version.hardware_version);
  304. } catch (zexception &exception) {
  305. processException(exception);
  306. }
  307. }
  308. void MainWindow::on_readDeviceState_clicked() {
  309. instructionPreviewClear();
  310. try {
  311. device_state_receipt_t state;
  312. ElectrocardiographTester::ins()->readDeviceState(&state);
  313. instructionPreviewShow("-------------- state ----------------");
  314. instructionPreviewShow(" drop_state0: %s", zhex2binary(state.drop_state0).c_str());
  315. instructionPreviewShow(" drop_state1: %s", zhex2binary(state.drop_state1).c_str());
  316. instructionPreviewShow(" sampling_state: %d", state.device_state0.sampling_state);
  317. instructionPreviewShow(" report_state: %d", state.device_state0.report_state);
  318. instructionPreviewShow(" low_battery: %d", state.device_state0.low_battery);
  319. instructionPreviewShow(" full_storge: %d", state.device_state0.full_storge);
  320. instructionPreviewShow(" holder: %d", state.device_state0.holder);
  321. instructionPreviewShow(" powerlevel: %d", state.powerlevel);
  322. instructionPreviewShow(" storage_item_num: %d", state.storage_item_num);
  323. } catch (zexception &exception) {
  324. processException(exception);
  325. }
  326. }
  327. void MainWindow::on_readTime_clicked() {
  328. instructionPreviewClear();
  329. try {
  330. read_time_receipt_t time;
  331. ElectrocardiographTester::ins()->readTime(&time);
  332. instructionPreviewShow("-------------- time ----------------");
  333. instructionPreviewShow(" %d/%d/%d %d:%d:%d", time.year + 2000, time.month, time.day, time.hour, time.minute, time.second);
  334. } catch (zexception &exception) {
  335. processException(exception);
  336. }
  337. }
  338. void MainWindow::on_syncTime_clicked() {
  339. instructionPreviewClear();
  340. try {
  341. // 获取系统时间
  342. QDateTime now = QDateTime::currentDateTime();
  343. ElectrocardiographTester::ins()->syncTime(now.date().year() - 2000, now.date().month(), now.date().day(), now.time().hour(), now.time().minute(), now.time().second());
  344. instructionPreviewShow("sync time success!");
  345. } catch (zexception &exception) {
  346. processException(exception);
  347. }
  348. }
  349. std::string zhex2time(const uint8_t *hex, size_t len) {
  350. std::string str;
  351. if (len < 6) return str;
  352. str.append(fmt("%d/%d/%d %2d:%2d:%2d", hex[0] + 2000, hex[1], hex[2], hex[3], hex[4], hex[5]));
  353. return str;
  354. }
  355. void MainWindow::on_readAllRecords_clicked() {
  356. // 读取当前有多少条记录
  357. instructionPreviewClear();
  358. try {
  359. device_state_receipt_t state;
  360. ElectrocardiographTester::ins()->readDeviceState(&state);
  361. instructionPreviewShow("index recordid frameNum dataSize sensorNum captRate captPrec compAlgo checksum");
  362. for (int32_t i = 0; i < state.storage_item_num; i++) {
  363. read_record_info_receipt_t record;
  364. ElectrocardiographTester::ins()->readRecordsInfo(i, &record);
  365. instructionPreviewShow("%d %s %8d %8d %8d %8d %8d %8d 0x%08x", i, zhex2time(record.record_id, 6).c_str(), record.frameNum, record.dataSize, record.sensorNum, record.captureRate, record.capturePrecision, record.compressAlgorithm, record.checksum);
  366. }
  367. } catch (zexception &exception) {
  368. processException(exception);
  369. }
  370. }
  371. void MainWindow::on_startUploadRecord_clicked() {
  372. instructionPreviewClear();
  373. int reportIndex = ui->startUploadRecord_p0->toPlainText().toInt();
  374. try {
  375. read_record_info_receipt_t record;
  376. ElectrocardiographTester::ins()->readRecordsInfo(reportIndex, &record);
  377. ElectrocardiographTester::ins()->startUploadRecord(record.record_id);
  378. instructionPreviewShow("start upload record [%s] success", zhex2time(record.record_id, 6).c_str());
  379. } catch (zexception &exception) {
  380. processException(exception);
  381. }
  382. }
  383. void MainWindow::on_readSensorInfo_clicked() {
  384. instructionPreviewClear();
  385. try {
  386. sensor_info_receipt_t sensor;
  387. ElectrocardiographTester::ins()->readSensorInfo(&sensor);
  388. instructionPreviewShow("-------------- sensor ----------------");
  389. instructionPreviewShow(" sensor_num: %d", sensor.sensor_num);
  390. instructionPreviewShow(" sensor_precision: %d", sensor.sensor_precision);
  391. instructionPreviewShow(" sensor_sample_rate:%d", sensor.sensor_sample_rate);
  392. instructionPreviewShow(" sensor0_pos: %d", sensor.sensor0_pos);
  393. instructionPreviewShow(" sensor1_pos: %d", sensor.sensor1_pos);
  394. instructionPreviewShow(" sensor2_pos: %d", sensor.sensor2_pos);
  395. } catch (zexception &exception) {
  396. processException(exception);
  397. }
  398. }
  399. void MainWindow::on_readSN_clicked() {
  400. instructionPreviewClear();
  401. try {
  402. string sn;
  403. ElectrocardiographTester::ins()->readSn(sn);
  404. instructionPreviewShow("-------------- sn ----------------");
  405. instructionPreviewShow(" sn: %s", sn.c_str());
  406. } catch (zexception &exception) {
  407. processException(exception);
  408. }
  409. }
  410. void MainWindow::on_stopUploadRecord_clicked() {
  411. instructionPreviewClear();
  412. try {
  413. ElectrocardiographTester::ins()->stopUploadRecord();
  414. instructionPreviewShow("stop upload record success");
  415. } catch (zexception &exception) {
  416. processException(exception);
  417. }
  418. }
  419. void MainWindow::on_delRecord_clicked() {
  420. instructionPreviewClear();
  421. int reportIndex = ui->delRecord_p0->toPlainText().toInt();
  422. try {
  423. read_record_info_receipt_t record;
  424. ElectrocardiographTester::ins()->readRecordsInfo(reportIndex, &record);
  425. ElectrocardiographTester::ins()->delRecord(record.record_id);
  426. instructionPreviewShow("delete record [%s] success", zhex2time(record.record_id, 6).c_str());
  427. } catch (zexception &exception) {
  428. processException(exception);
  429. }
  430. }
  431. void MainWindow::on_startCapture_clicked() {
  432. instructionPreviewClear();
  433. try {
  434. ElectrocardiographTester::ins()->startCapture();
  435. instructionPreviewShow("start capture success");
  436. } catch (zexception &exception) {
  437. processException(exception);
  438. }
  439. }
  440. void MainWindow::on_stopCapture_clicked() {
  441. instructionPreviewClear();
  442. try {
  443. ElectrocardiographTester::ins()->stopCapture();
  444. instructionPreviewShow("stop capture success");
  445. } catch (zexception &exception) {
  446. processException(exception);
  447. }
  448. }
  449. void MainWindow::on_startRealtimeReport_clicked() {
  450. instructionPreviewClear();
  451. try {
  452. ElectrocardiographTester::ins()->startRealtimeReport();
  453. instructionPreviewShow("start realtime report success");
  454. wp2d->show();
  455. } catch (zexception &exception) {
  456. processException(exception);
  457. }
  458. }
  459. void MainWindow::on_stopRealtimeReport_clicked() {
  460. instructionPreviewClear();
  461. try {
  462. ElectrocardiographTester::ins()->stopRealtimeReport();
  463. instructionPreviewShow("stop realtime report success");
  464. wp2d->hide();
  465. } catch (zexception &exception) {
  466. processException(exception);
  467. }
  468. }
  469. void MainWindow::on_clearPreview_clicked() {
  470. ui->reportPreview->document()->clear();
  471. ui->uploadDataPreview->document()->clear();
  472. ui->rawDataPreview->document()->clear();
  473. ui->instructionPreview->document()->clear();
  474. }