#include "mainwindow.h" #include #include #include #include #include #include "./ui_mainwindow.h" #include "electrocardiograph_tester.hpp" #include "logger.hpp" #include "qt_serial_datachannel.hpp" #include "zexception.hpp" using namespace std; using namespace iflytop; static MainWindow *m_mainWindow; static QTDataChannel G_QTDataChannel; #define TAG "MainWindow" static const char *fmt(const char *fmt, ...) { va_list args; va_start(args, fmt); static char buf[1024] = {0}; vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); return buf; } void MainWindow::log_output(QtMsgType type, const QMessageLogContext &context, const QString &msg) {} void MainWindow::doinui_slot(QFunction func) { if (func.get()) func.get()(); } void MainWindow::instructionPreviewShow(const char *fmt, ...) { va_list args; va_start(args, fmt); char buf[1024] = {0}; vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); QString text(buf); QString info; info.append(QDateTime::currentDateTime().toString("hh:mm:ss.zzz")); info.append(" |"); info.append(text); emit doinui_signal(QFunction([this, info]() { ui->instructionPreview->append(info); })); } void MainWindow::instructionPreviewClear() { ui->instructionPreview->document()->clear(); } void MainWindow::reportPreviewShow(const char *fmt, ...) { va_list args; va_start(args, fmt); char buf[1024] = {0}; vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); QString text(buf); QString info; info.append(QDateTime::currentDateTime().toString("hh:mm:ss.zzz")); info.append(text); emit doinui_signal(QFunction([this, info]() { if (ui->reportPreview->document()->lineCount() > 100) { ui->reportPreview->document()->clear(); } ui->reportPreview->append(info); })); } void MainWindow::blockDataUploadPreviewShow(const char *fmt, ...) { va_list args; va_start(args, fmt); char buf[1024] = {0}; vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); QString text(buf); QString info; info.append(QDateTime::currentDateTime().toString("hh:mm:ss.zzz")); info.append(text); emit doinui_signal(QFunction([this, info]() { if (ui->uploadDataPreview->document()->lineCount() > 100) { ui->uploadDataPreview->document()->clear(); } ui->uploadDataPreview->append(info); })); } void MainWindow::rawDataPreviewShow(const char *fmt, ...) { va_list args; va_start(args, fmt); char buf[1024] = {0}; vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); QString text(buf); QString info; info.append(QDateTime::currentDateTime().toString("hh:mm:ss.zzz")); info.append(text); emit doinui_signal(QFunction([this, info]() { if (ui->rawDataPreview->document()->lineCount() > 100) { ui->rawDataPreview->document()->clear(); } ui->rawDataPreview->append(info); })); } // uploadDataPreview void MainWindow::displayInfo(bool suc, QString info) {} MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { /******************************************************************************* * QT初始化 * *******************************************************************************/ ui->setupUi(this); m_mainWindow = this; qRegisterMetaType("int32_t"); qRegisterMetaType("uint32_t"); qRegisterMetaType("float"); qRegisterMetaType>("function"); qRegisterMetaType("QFunction"); connect(this, SIGNAL(doinui_signal(QFunction)), this, SLOT(doinui_slot(QFunction))); // qInstallMessageHandler(log_output); /******************************************************************************* * 页面逻辑初始化 * *******************************************************************************/ constructUI(); /******************************************************************************* * 业务逻辑构造 * *******************************************************************************/ G_QTDataChannel.init(); ElectrocardiographTester::ins()->initialize(&G_QTDataChannel); } MainWindow::~MainWindow() { delete ui; } /******************************************************************************* * UI相关构造 * *******************************************************************************/ void MainWindow::constructUI() { /******************************************************************************* * serialPortCB * *******************************************************************************/ const auto infos = QSerialPortInfo::availablePorts(); for (const QSerialPortInfo &info : infos) { ui->serialPortCB->addItem(info.portName()); } /******************************************************************************* * 波特率填?? * *******************************************************************************/ ui->serialBaudrateCB->addItem("9600"); ui->serialBaudrateCB->addItem("14400"); ui->serialBaudrateCB->addItem("19200"); ui->serialBaudrateCB->addItem("38400"); ui->serialBaudrateCB->addItem("57600"); ui->serialBaudrateCB->addItem("115200"); ui->serialBaudrateCB->addItem("460800"); ui->serialBaudrateCB->addItem("500000"); ui->serialBaudrateCB->setCurrentIndex(6); /******************************************************************************* * 刷新串口 * *******************************************************************************/ connect(ui->serialPortRefreshKey, &QPushButton::clicked, this, [this](bool check) { ui->serialPortCB->clear(); const auto infos = QSerialPortInfo::availablePorts(); for (const QSerialPortInfo &info : infos) { ui->serialPortCB->addItem(info.portName()); } }); /******************************************************************************* * 打开串口 * *******************************************************************************/ connect(ui->serialOpenKey, &QPushButton::clicked, this, [=](bool check) { // 打开串口 if (ui->serialOpenKey->text() == "打开") { G_QTDataChannel.setPortName(ui->serialPortCB->currentText().toStdString()); G_QTDataChannel.setBaudRate(ui->serialBaudrateCB->currentText().toInt()); G_QTDataChannel.setDataBits(QSerialPort::Data8); G_QTDataChannel.setParity(QSerialPort::NoParity); G_QTDataChannel.setFlowControl(QSerialPort::NoFlowControl); G_QTDataChannel.setStopBits(QSerialPort::OneStop); if (!G_QTDataChannel.open()) { QMessageBox::about(NULL, "提示", "串口无法打开,串口不存在或已被占??"); return; } ui->serialOpenKey->setText("关闭"); // 下拉菜单控件使能 ui->serialBaudrateCB->setEnabled(false); ui->serialPortCB->setEnabled(false); ui->serialPortRefreshKey->setEnabled(false); } else { G_QTDataChannel.close(); ui->serialOpenKey->setText("打开"); ui->serialBaudrateCB->setEnabled(true); ui->serialPortCB->setEnabled(true); ui->serialPortRefreshKey->setEnabled(true); } }); // 事件填充 ElectrocardiographTester::ins()->regReportCB([this](ify_hrs_packet_t *report_packet, size_t len) { int reportType = report_packet->cmd; switch (reportType) { case ify_hrs_report_heartrate_data: { heartrate_report_packet_t *heartrate_report = (heartrate_report_packet_t *)report_packet; reportPreviewShow("[preview data ] index %llu", heartrate_report->sample_data_index); break; } case ify_hrs_report_battery_level: { reportPreviewShow("[battery_level ]"); break; } case ify_hrs_report_low_battey_level: { reportPreviewShow("[low_battey ]"); break; } case ify_hrs_report_sample_finish_end: { reportPreviewShow("[sample_finish ]"); break; } case ify_hrs_report_sensor_drop_detect: { sensor_drop_event_report_packet_t *sensor_drop_report = (sensor_drop_event_report_packet_t *)report_packet->data; reportPreviewShow("[sensor_drop ] %s %s", zhex2binary(sensor_drop_report->drop_state0).c_str(), zhex2binary(sensor_drop_report->drop_state1).c_str()); break; } case ify_hrs_report_record_upload_end: { uint32_t checksum = *(uint32_t *)report_packet->data; reportPreviewShow("[record_upload ] 0x%08x", checksum); break; } default: break; } }); ElectrocardiographTester::ins()->regCh4CheckSumPacketReport([this](uint32_t rxcnt, uint32_t report_packet_checksum) { blockDataUploadPreviewShow("RXCNT %d CHECKSUM %d", rxcnt, report_packet_checksum); }); ElectrocardiographTester::ins()->regRawDataCB([this](raw_data_type_t type, uint8_t *hex, uint32_t hexlen) { if (type == kcmd_cmd) { blockDataUploadPreviewShow("[CMD ] %s", zhex2str(hex, hexlen).c_str()); } else if (type == kcmd_receipt) { blockDataUploadPreviewShow("[RECEIPT] %s", zhex2str(hex, hexlen).c_str()); } else if (type == kcmd_report) { blockDataUploadPreviewShow("[REPORT ] %s", zhex2str(hex, hexlen).c_str()); } else if (type == kcmd_ch4_data) { // blockDataUploadPreviewShow("[CH4 ] %s", zhex2str(hex, hexlen).c_str()); } }); } void MainWindow::processException(zexception &e) { instructionPreviewShow("%s:%s", e.what(), hrs_ecode2str((ify_hrs_error_code_t)e.ecode())); } void MainWindow::on_readDeviceVersion_clicked() { instructionPreviewClear(); try { device_version_info_receipt_t version; ElectrocardiographTester::ins()->readDeviceVersion(&version); instructionPreviewShow("-------------- version ----------------"); instructionPreviewShow(" blestack_version: %d", version.blestack_version); instructionPreviewShow(" bootloader_version: %d", version.bootloader_version); instructionPreviewShow(" firmware_version: %d", version.firmware_version); instructionPreviewShow(" hardware_version: %d", version.hardware_version); } catch (zexception &exception) { processException(exception); } } void MainWindow::on_readDeviceState_clicked() { instructionPreviewClear(); try { device_state_receipt_t state; ElectrocardiographTester::ins()->readDeviceState(&state); instructionPreviewShow("-------------- state ----------------"); instructionPreviewShow(" drop_state0: %s", zhex2binary(state.drop_state0).c_str()); instructionPreviewShow(" drop_state1: %s", zhex2binary(state.drop_state1).c_str()); instructionPreviewShow(" sampling_state: %d", state.device_state0.sampling_state); instructionPreviewShow(" report_state: %d", state.device_state0.report_state); instructionPreviewShow(" low_battery: %d", state.device_state0.low_battery); instructionPreviewShow(" full_storge: %d", state.device_state0.full_storge); instructionPreviewShow(" holder: %d", state.device_state0.holder); instructionPreviewShow(" powerlevel: %d", state.powerlevel); instructionPreviewShow(" storage_item_num: %d", state.storage_item_num); } catch (zexception &exception) { processException(exception); } } void MainWindow::on_readTime_clicked() { instructionPreviewClear(); try { read_time_receipt_t time; ElectrocardiographTester::ins()->readTime(&time); instructionPreviewShow("-------------- time ----------------"); instructionPreviewShow(" %d/%d/%d %d:%d:%d", time.year + 2000, time.month, time.day, time.hour, time.minute, time.second); } catch (zexception &exception) { processException(exception); } } void MainWindow::on_syncTime_clicked() { instructionPreviewClear(); try { // 获取系统时间 QDateTime now = QDateTime::currentDateTime(); ElectrocardiographTester::ins()->syncTime(now.date().year() - 2000, now.date().month(), now.date().day(), now.time().hour(), now.time().minute(), now.time().second()); instructionPreviewShow("sync time success!"); } catch (zexception &exception) { processException(exception); } } std::string zhex2time(const uint8_t *hex, size_t len) { std::string str; if (len < 6) return str; str.append(fmt("%d/%d/%d %2d:%2d:%2d", hex[0] + 2000, hex[1], hex[2], hex[3], hex[4], hex[5])); return str; } void MainWindow::on_readAllRecords_clicked() { // 读取当前有多少条记录 instructionPreviewClear(); try { device_state_receipt_t state; ElectrocardiographTester::ins()->readDeviceState(&state); instructionPreviewShow("index recordid frameNum dataSize sensorNum captRate captPrec compAlgo"); for (int32_t i = 0; i < state.storage_item_num; i++) { read_record_info_receipt_t record; ElectrocardiographTester::ins()->readRecordsInfo(i, &record); instructionPreviewShow("%d %s %8d %8d %8d %8d %8d %8d", i, zhex2time(record.record_id, 6).c_str(), record.frameNum, record.dataSize, record.sensorNum, record.captureRate, record.capturePrecision, record.compressAlgorithm); } } catch (zexception &exception) { processException(exception); } } void MainWindow::on_startUploadRecord_clicked() { instructionPreviewClear(); int reportIndex = ui->startUploadRecord_p0->toPlainText().toInt(); try { read_record_info_receipt_t record; ElectrocardiographTester::ins()->readRecordsInfo(reportIndex, &record); ElectrocardiographTester::ins()->startUploadRecord(record.record_id); instructionPreviewShow("start upload record [%s] success", zhex2time(record.record_id, 6).c_str()); } catch (zexception &exception) { processException(exception); } } void MainWindow::on_readSensorInfo_clicked() { instructionPreviewClear(); try { sensor_info_receipt_t sensor; ElectrocardiographTester::ins()->readSensorInfo(&sensor); instructionPreviewShow("-------------- sensor ----------------"); instructionPreviewShow(" sensor_num: %d", sensor.sensor_num); instructionPreviewShow(" sensor_precision: %d", sensor.sensor_precision); instructionPreviewShow(" sensor_sample_rate:%d", sensor.sensor_sample_rate); instructionPreviewShow(" sensor0_pos: %d", sensor.sensor0_pos); instructionPreviewShow(" sensor1_pos: %d", sensor.sensor1_pos); instructionPreviewShow(" sensor2_pos: %d", sensor.sensor2_pos); } catch (zexception &exception) { processException(exception); } } void MainWindow::on_readSN_clicked() { instructionPreviewClear(); try { string sn; ElectrocardiographTester::ins()->readSn(sn); instructionPreviewShow("-------------- sn ----------------"); instructionPreviewShow(" sn: %s", sn.c_str()); } catch (zexception &exception) { processException(exception); } } void MainWindow::on_stopUploadRecord_clicked() { instructionPreviewClear(); try { ElectrocardiographTester::ins()->stopUploadRecord(); instructionPreviewShow("stop upload record success"); } catch (zexception &exception) { processException(exception); } } void MainWindow::on_delRecord_clicked() { instructionPreviewClear(); int reportIndex = ui->delRecord_p0->toPlainText().toInt(); try { read_record_info_receipt_t record; ElectrocardiographTester::ins()->readRecordsInfo(reportIndex, &record); ElectrocardiographTester::ins()->delRecord(record.record_id); instructionPreviewShow("delete record [%s] success", zhex2time(record.record_id, 6).c_str()); } catch (zexception &exception) { processException(exception); } } void MainWindow::on_startCapture_clicked() { instructionPreviewClear(); try { ElectrocardiographTester::ins()->startCapture(); instructionPreviewShow("start capture success"); } catch (zexception &exception) { processException(exception); } } void MainWindow::on_stopCapture_clicked() { instructionPreviewClear(); try { ElectrocardiographTester::ins()->stopCapture(); instructionPreviewShow("stop capture success"); } catch (zexception &exception) { processException(exception); } } void MainWindow::on_startRealtimeReport_clicked() { instructionPreviewClear(); try { ElectrocardiographTester::ins()->startRealtimeReport(); instructionPreviewShow("start realtime report success"); } catch (zexception &exception) { processException(exception); } } void MainWindow::on_stopRealtimeReport_clicked() { instructionPreviewClear(); try { ElectrocardiographTester::ins()->stopRealtimeReport(); instructionPreviewShow("stop realtime report success"); } catch (zexception &exception) { processException(exception); } } void MainWindow::on_clearPreview_clicked() { ui->reportPreview->document()->clear(); ui->uploadDataPreview->document()->clear(); ui->rawDataPreview->document()->clear(); ui->instructionPreview->document()->clear(); }