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.

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