/** * @file ui_event_homePage.c * @brief 此文件中实现了主页的UI事件处理函数 * * 核心逻辑:1.处理标准变更事件;2.处理测试指令下发事件 * * @author wang xiang en * @date 2025-04-19 * @version 版本号 * @copyright 版权声明((C)2025, YUWELL MEDTECH Co.ltd) */ #include "ui.h" #include "FluxProtocol.h" /* 使用定时器 */ #include #include "FluxSD.h" /* 创建用于表征当前是否进行BS测试的全局变量 */ extern bool is_bs_test_ing; extern bool is_nom_test_ing; /* 任务控制句柄 */ extern TaskHandle_t bs_test_task_handle; extern TaskHandle_t nom_test_task_handle; /* 声明需要调用的静态函数 */ void comulate_time_set(void); /* 更新当前标准体积数据 */ static void standard_volume_refresh(void); /* 定时器执行函数声明 */ static void comulate_result_read(lv_timer_t * timer); /************************************ 呼吸频率更改响应函数 start ******************************************* */ /** * @brief 呼吸频率减操作 * * 只对Spinbox进行-5,协议发送在Spinbox的值更改响应事件中。 * * @param[in] e not used */ void on_buttonRateMinus_clicked(lv_event_t * e) { uint16_t value = lv_spinbox_get_value(ui_pageHome_spinboxRate); lv_spinbox_set_value(ui_pageHome_spinboxRate,value-5); #if LOG_RECORD_ENABLE WRITE_LOG_TO_SD("常规频率减事件"); #endif } /** * @brief 呼吸频率加操作 * * 只对Spinbox进行+5,协议发送在Spinbox的值更改响应事件中。 * * @param[in] e not used */ void on_buttonRatePlus_clicked(lv_event_t * e) { uint16_t value = lv_spinbox_get_value(ui_pageHome_spinboxRate); lv_spinbox_set_value(ui_pageHome_spinboxRate,value+5); #if LOG_RECORD_ENABLE WRITE_LOG_TO_SD("常规频率加事件"); #endif } /** * @brief 呼吸频率值改变响应事件,向流量计下发累时。 * * 通过485协议下发命令,实现流量计的累时。 * 使用0x06指令,只修改单个16bit寄存器 * * @note 协议格式: * 例如:01 06 00 02 41 F0 18 1E * * 意思是: * 01:设备地址 * 06:功能码,修改单个寄存器 * 00 02:寄存器地址,0x00 02 * 41 F0:需要发送的数据 41 F0 00 00 对应浮点数 30 * * @param[in] e not used */ void on_spinboxRate_valueChanged(lv_event_t * e) { /* 更改下方测试结果部分的频率信息 */ FluxMachineData.breathRate = lv_spinbox_get_value(e->target); lv_label_set_text_fmt(ui_pageHome_labelResultRate,"%ld",FluxMachineData.breathRate); /* 刷新标准体积数据,频率不同标准体积也不同。 */ standard_volume_refresh(); /* 根据设定的出气次数设定积分时间 */ comulate_time_set(); /* 下发计算好的积分时间*/ uint8_t bytes[4]; float time = (float)lv_spinbox_get_value(ui_pageFluxRead_spinboxTime); memcpy(bytes, &time, 4); /* 下发命令 */ flux_frame.ADDR = FLUX_ADDR; /* 0x06指令 */ flux_frame.FUNC = FLUX_FUNC_SET_SINGLE; /* 寄存器地址 0x00 02 */ flux_frame.DATA[0] = 0x00; flux_frame.DATA[1] = 0x02; /* 只修改时间寄存器(32bit)的前两个字节数据(16bit) */ flux_frame.DATA[2] = bytes[3]; flux_frame.DATA[3] = bytes[2]; ESP_ERROR_CHECK(ModbusRTU_Send_0306(ECHO_UART_PORT_NUM1,&flux_frame)); /* 更新SD卡中需要存储的频率数据 */ sdData.flux_test_result.current_rate = FluxMachineData.breathRate; #if LOG_RECORD_ENABLE WRITE_LOG_TO_SD("正常情况下呼吸频率更改切换"); #endif } /** * @brief 根据spinbox中的值修改 pageFluxRead 页中的显示积分时间 * * @attention 不能在spinboxTime_valueChanged中调用!! * 否则容易造成 死循环。 * */ void comulate_time_set(void) { /* 获取当前呼吸频率 */ FluxMachineData.breathRate = lv_spinbox_get_value(ui_pageHome_spinboxRate); uint16_t currntTimes = lv_dropdown_get_selected(ui_pageFluxRead_dropdownPulseTimes); ESP_LOGI("comulateTimeSend","currentTimes:%d",currntTimes); if (currntTimes == 0)//进行十次积分 { /* 10次脉冲计量 */ switch (FluxMachineData.breathRate) { case 15: /*呼吸频率为15BPM时,积分时间设定为40秒*/ lv_spinbox_set_value(ui_pageFluxRead_spinboxTime,40); break; case 20: /*呼吸频率为20BPM时,积分时间设定为30秒*/ lv_spinbox_set_value(ui_pageFluxRead_spinboxTime,30); break; case 25: /*呼吸频率为25BPM时,积分时间设定为24秒*/ lv_spinbox_set_value(ui_pageFluxRead_spinboxTime,24); break; case 30: /*呼吸频率为30BPM时,积分时间设定为20秒*/ lv_spinbox_set_value(ui_pageFluxRead_spinboxTime,20); break; case 35: /*呼吸频率为35BPM时,积分时间设定为16秒*/ lv_spinbox_set_value(ui_pageFluxRead_spinboxTime,18); break; case 40: /*呼吸频率为40BPM时,积分时间设定为15秒*/ lv_spinbox_set_value(ui_pageFluxRead_spinboxTime,15); break; default: break; } }else if (currntTimes == 1) { /* 20次脉冲 */ switch (FluxMachineData.breathRate) { case 15: /*呼吸频率为15BPM时,积分时间设定为40秒*/ lv_spinbox_set_value(ui_pageFluxRead_spinboxTime,80); break; case 20: /*呼吸频率为20BPM时,积分时间设定为30秒*/ lv_spinbox_set_value(ui_pageFluxRead_spinboxTime,60); break; case 25: /*呼吸频率为25BPM时,积分时间设定为24秒*/ lv_spinbox_set_value(ui_pageFluxRead_spinboxTime,48); break; case 30: /*呼吸频率为30BPM时,积分时间设定为20秒*/ lv_spinbox_set_value(ui_pageFluxRead_spinboxTime,40); break; case 35: /*呼吸频率为35BPM时,积分时间设定为16秒*/ lv_spinbox_set_value(ui_pageFluxRead_spinboxTime,36); break; case 40: /*呼吸频率为40BPM时,积分时间设定为15秒*/ lv_spinbox_set_value(ui_pageFluxRead_spinboxTime,30); break; default: break; } }else if (currntTimes == 2) { /* 30次脉冲 */ switch (FluxMachineData.breathRate) { case 15: /*呼吸频率为15BPM时,积分时间设定为40秒*/ lv_spinbox_set_value(ui_pageFluxRead_spinboxTime,120); break; case 20: /*呼吸频率为20BPM时,积分时间设定为30秒*/ lv_spinbox_set_value(ui_pageFluxRead_spinboxTime,90); break; case 25: /*呼吸频率为25BPM时,积分时间设定为24秒*/ lv_spinbox_set_value(ui_pageFluxRead_spinboxTime,72); break; case 30: /*呼吸频率为30BPM时,积分时间设定为20秒*/ lv_spinbox_set_value(ui_pageFluxRead_spinboxTime,60); break; case 35: /*呼吸频率为35BPM时,积分时间设定为16秒*/ lv_spinbox_set_value(ui_pageFluxRead_spinboxTime,54); break; case 40: /*呼吸频率为40BPM时,积分时间设定为15秒*/ lv_spinbox_set_value(ui_pageFluxRead_spinboxTime,45); break; default: break; } } #if LOG_RECORD_ENABLE WRITE_LOG_TO_SD("脉冲次数重置时间"); #endif } /** * @brief 更新测试时间 * * 修改单次测试脉冲总数10 20 30 次后,更新测试时间, * 向流量计下发测试时间。 * * @param[in] e not used */ void on_dropdownPulseTimes_valueChanged(lv_event_t * e) { /* 根据脉冲次数设置测试时间 */ comulate_time_set(); /* 下发测试时间 */ uint8_t bytes[4]; float time = (float)lv_spinbox_get_value(ui_pageFluxRead_spinboxTime); memcpy(bytes, &time, 4); flux_frame.ADDR = FLUX_ADDR; flux_frame.FUNC = FLUX_FUNC_SET_SINGLE; flux_frame.DATA[0] = 0x00; flux_frame.DATA[1] = 0x02; flux_frame.DATA[2] = bytes[3]; flux_frame.DATA[3] = bytes[2]; ESP_ERROR_CHECK(ModbusRTU_Send_0306(ECHO_UART_PORT_NUM1,&flux_frame)); } /************************************ 呼吸频率更改响应函数 end ******************************************* */ /************************************ 挡位更改响应函数 start ******************************************* */ /** * @brief 挡位切换后的响应事件 * * 只更新标准,不通过485下发数据。 * * @note 加减操作已在SquareLine工程内部实现,无需手动调用。 * @param[in] e not used */ void on_spinboxStage_valueChanged(lv_event_t * e) { /*获取当前挡位并更新标准体积数据*/ int32_t value = lv_spinbox_get_value(e->target); lv_label_set_text_fmt(ui_pageHome_labelResultStage,"%ld",value); standard_volume_refresh(); /* 更新当前挡位数据 */ sdData.flux_test_result.current_stage = value; #if LOG_RECORD_ENABLE WRITE_LOG_TO_SD("正常情况下的挡位切换"); #endif } /** * @brief 标准体积数据刷新 * * 修改标准体积数据,设置最大最小值。 * 最后根据标准判定当前读取到的体积流量是否合格 * */ static void standard_volume_refresh(void) { /*获取当前的呼吸频率及挡位*/ fluxProtocol.currentBPM = lv_spinbox_get_value(ui_pageHome_spinboxRate); fluxProtocol.currentStage = lv_spinbox_get_value(ui_pageHome_spinboxStage); /*获取当前测试设备类型*/ fluxProtocol.currentDevice = lv_dropdown_get_selected(ui_pageSetting_dropdownDeviceType); if (fluxProtocol.currentDevice == Spirit3) { /*判定当前测试设备为Spirit-3*/ /*获取标准体积数据*/ fluxProtocol.nominalVolumeStage = Spirit3_Volume[fluxProtocol.currentStage-1]; }else if (fluxProtocol.currentDevice == Spirit6) { /*判定当前测试设备为Spirit-6*/ fluxProtocol.nominalVolumeStage = Spirit6_Volume[fluxProtocol.currentStage-1]; }else if(fluxProtocol.currentDevice == YU_Lite8) { /*判定当前测试设备为YU-Lite-8*/ fluxProtocol.nominalVolumeStage = YULite8_Volume[fluxProtocol.currentStage-1]; } float Volume_nominal = fluxProtocol.nominalVolumeStage /fluxProtocol.currentBPM*1.0; float VolumeMax = Volume_nominal*1.15; float VolumeMin = Volume_nominal*0.85; lv_label_set_text_fmt(ui_pageHome_labelNominalVolume,"%.2f",Volume_nominal); lv_label_set_text_fmt(ui_pageHome_labelNominalVolumeMax,"%.2f",VolumeMax); lv_label_set_text_fmt(ui_pageHome_labelNominalVolumeMin,"%.2f",VolumeMin); /* 更新BS界面中各频率值 */ /*根据标准值判定当前检测结果是否合格*/ RefreshResult(); #if LOG_RECORD_ENABLE WRITE_LOG_TO_SD("常规测试刷新标准体积"); #endif } /************************************ 挡位更改响应函数 end ******************************************* */ /************************************ 开始测试按键按下 start ******************************************* */ /** * @brief 开始测试按键按下后响应事件 * * @details 执行流程: * 1. 下发测试时间,确保测试时间正确 * 2. 创建定时器,配置定时器计时时间 * 3. 下发启动测试指令 * * @param[in] e not used */ void on_buttonStartTest_clicked(lv_event_t * e) { /* 设定当前工作模式为nom */ is_test_mode_nom = true; /* 判断是否正在测试 */ if(is_nom_test_ing) { /* 如果正在测试,按下后取消测试 */ vTaskDelete(nom_test_task_handle); /* 挂起LED闪烁 */ NOM_STATE_LED_TASK_SUSPEND; /* 等待开始测试 */ is_nom_test_ing = false; /* 清空已完成的测试结果 */ NOM_ALL_RESULT_CLEAR; /* 清空进度条 */ lv_bar_set_value(ui_pageHome_barNomTest,0,LV_ANIM_ON); lv_label_set_text(ui_pageHome_labelStartTest,"Start Test NOM"); }else{ /* 如果没有测试,按下后开始测试 */ /* 创建NOM测试任务 */ xTaskCreate(nom_test_task, "nom_test_task", 1024*4, NULL, 5, &nom_test_task_handle); is_nom_test_ing = true; lv_label_set_text(ui_pageHome_labelStartTest,"Cancel Test NOM"); } #if 0 uint8_t bytes[4]; float time = (float)lv_spinbox_get_value(ui_pageFluxRead_spinboxTime); memcpy(bytes, &time, 4); /*下发命令*/ flux_frame.ADDR = FLUX_ADDR; flux_frame.FUNC = FLUX_FUNC_SET_SINGLE; flux_frame.DATA[0] = 0x00; flux_frame.DATA[1] = 0x02; flux_frame.DATA[2] = bytes[3]; flux_frame.DATA[3] = bytes[2]; ESP_ERROR_CHECK(ModbusRTU_Send_0306(ECHO_UART_PORT_NUM1,&flux_frame)); /*创建定时器*/ lv_timer_t * comulateResultReadTimer; /* 基于定时器进行任务调用 */ comulateResultReadTimer = lv_timer_create(comulate_result_read, 500, NULL); /* 只重复一次 */ lv_timer_set_repeat_count(comulateResultReadTimer, 1); /* 根据测试时间确定定时器延时 */ int32_t timeS = lv_spinbox_get_value(ui_pageFluxRead_spinboxTime); lv_timer_set_period(comulateResultReadTimer, timeS*1000+2000); /*下发启动测试指令*/ flux_frame_start.ADDR = FLUX_ADDR; flux_frame_start.FUNC = FLUX_FUNC_SET_SINGLE; flux_frame_start.DATA[0] = 0x00; flux_frame_start.DATA[1] = 0x01; flux_frame_start.DATA[2] = 0x00; flux_frame_start.DATA[3] = 0x01; ESP_ERROR_CHECK(ModbusRTU_Send_0306(ECHO_UART_PORT_NUM1,&flux_frame_start)); /* 修改Label 开始测试 */ lv_label_set_text(ui_pageHome_labelStartTest,"Testing..."); /* 开始计时 */ lv_timer_enable(comulateResultReadTimer); #endif } /** * @brief 定时器响应函数 * * 时间到达后执行 * 定时器响应函数,用于定时获取测试结果,并更新界面。 * * @param[in] timer not used */ static void comulate_result_read(lv_timer_t * timer) { /*下发数据获取指令*/ /* 起始地址为 0x00 */ flux_frame.DATA[0] = 0; flux_frame.DATA[1] = 0; /* 数据长度为 120 */ flux_frame.DATA[2] = 0; flux_frame.DATA[3] = 120; flux_frame.FUNC = FLUX_FUNC_READ; /*下发问询120个参数*/ ESP_ERROR_CHECK(ModbusRTU_Send_0306(ECHO_UART_PORT_NUM1,&flux_frame)); lv_label_set_text(ui_pageHome_labelStartTest,"Test Complete!"); } /** * @brief BS界面 带BS测试 按键按下事件 * * 按键按下后执行以下操作 * 1.设置15BPM测试时间 * 2.开始测试 * 3.等待结果 * 4.重复测试 * * @param[in] e not used */ void on_buttonStartTestBS_clicked(lv_event_t * e) { /* 设定当前工作模式为bs */ is_test_mode_nom = false; /* 判断是否正在测试 */ if(is_bs_test_ing) { /* 如果正在测试,按下后取消测试 */ vTaskDelete(bs_test_task_handle); /* 挂起LED闪烁 */ BS_STATE_LED_TASK_SUSPEND; /* 等待开始测试 */ is_bs_test_ing = false; /* 清空已完成的测试结果 */ BS_ALL_RESULT_CLEAR; /* 清空进度条 */ lv_bar_set_value(ui_pageHome_BarTestProgBS, 0, LV_ANIM_ON); lv_label_set_text(ui_pageHome_labelstr21,"--BPM"); lv_label_set_text(ui_pageHome_labelStartTest1,"Start Test BS"); lv_label_set_text(ui_pageHome_labelBSInfo,"wait for test"); }else{ /* 如果没有测试,按下后开始测试 */ /* 创建BS测试任务 */ xTaskCreate(bs_test_task, "bs_test_task", 1024*4, NULL, 5, &bs_test_task_handle); is_bs_test_ing = true; lv_label_set_text(ui_pageHome_labelStartTest1,"Cancel Test BS"); /* 清空已完成的测试结果 */ BS_ALL_RESULT_CLEAR; } #if 0 /* 屏幕中显示下发成功 */ lv_label_set_text(ui_pageHome_labelBSInfo,test_info[0]); /* 屏幕中显示下发成功 */ lv_label_set_text(ui_pageHome_labelBSInfo,test_info[1]); /* 创建定时器 */ lv_timer_t * bsTestTimer; /* 创建定时器调用函数 */ bsTestTimer = lv_timer_create(bs_test_timer_func, 4*1000, NULL); lv_timer_set_period(bsTestTimer, 4*1000); lv_timer_set_repeat_count(bsTestTimer, 1); /* 开启定时器 */ lv_timer_enable(bsTestTimer); /* 显示正在测试中 */ lv_label_set_text(ui_pageHome_labelBSInfo,test_info[2]); #endif } /** * @brief BS界面设备类型选择响应函数 * * 值改变后执行以下操作 * 1.更新Home界面显示设备类型 * 2.更新测试标准值 * 3.根据测试标准刷新判断结果 * * @param[in] e not used */ void on_dropdown_deviceTypeBS_valueChanged(lv_event_t * e) { char buf[32]={}; uint16_t index = lv_dropdown_get_selected(e->target); /* 更新SD卡中的数据存储 */ sdData.flux_test_result.current_device_type = index; /* 更新Home界面显示设备类型 */ lv_dropdown_get_selected_str(e->target,buf,32); lv_label_set_text(ui_pageHome_labelTitle, buf); /* 更新挡位显示范围 */ if (index == Spirit3) { //lv_spinbox_set_range(ui_pageHome_spinboxStage,1,4); lv_spinbox_set_range(ui_pageHome_spinboxStageBS,1,4); }else{ //lv_spinbox_set_range(ui_pageHome_spinboxStage,1,6); lv_spinbox_set_range(ui_pageHome_spinboxStageBS,1,6); } /* 刷新标准值 */ on_spinboxStageBS_valueChanged(e); #if LOG_RECORD_ENABLE WRITE_LOG_TO_SD("BS测试设备类型修改成功"); #endif } /** * @brief BS界面 当前挡位发生修改事件 * * 按键按下后执行以下操作 * 1.更新屏幕显示标准数据 * 2.根据标准判断是否合格 * * @param[in] e not used */ void on_spinboxStageBS_valueChanged(lv_event_t * e) { /* 获取当前挡位 */ int32_t currentStage = lv_spinbox_get_value(ui_pageHome_spinboxStageBS); /* 获取当前测试设备类型 */ uint16_t currentDevice = lv_dropdown_get_selected(ui_pageHome_DropdownTestTypeBS); /* 获取该挡位下的体积数据 */ float nominalVolumeStage = 0; if (currentDevice == Spirit3) { /*判定当前测试设备为Spirit-3*/ nominalVolumeStage = Spirit3_Volume[currentStage-1]; }else if (currentDevice == Spirit6) { /*判定当前测试设备为Spirit-6*/ nominalVolumeStage = Spirit6_Volume[currentStage-1]; }else if(currentDevice == YU_Lite8) { /*判定当前测试设备为YU-Lite-8*/ nominalVolumeStage = YULite8_Volume[currentStage-1]; } /* 设置15 - 40 BPM对应标准体积值及其上下限 */ { float tmp_nml = 0; float tmp_max = 0; float tmp_min = 0; /* 计算15BPM标准体积值 */ tmp_nml = nominalVolumeStage/15.0; tmp_max = tmp_nml*1.15; tmp_min = tmp_nml*0.85; lv_label_set_text_fmt(ui_pageHome_LabelRate15STD, "%.1f",tmp_nml); lv_label_set_text_fmt(ui_pageHome_LabelRate15UP, "%.1f",tmp_max); lv_label_set_text_fmt(ui_pageHome_LabelRate15DOWN, "%.1f",tmp_min); /* 计算20BPM标准体积值 */ tmp_nml = nominalVolumeStage/20.0; tmp_max = tmp_nml*1.15; tmp_min = tmp_nml*0.85; lv_label_set_text_fmt(ui_pageHome_LabelRate20STD, "%.1f",tmp_nml); lv_label_set_text_fmt(ui_pageHome_LabelRate20UP, "%.1f",tmp_max); lv_label_set_text_fmt(ui_pageHome_LabelRate20DOWN, "%.1f",tmp_min); /* 计算25BPM标准体积值 */ tmp_nml = nominalVolumeStage/25.0; tmp_max = tmp_nml*1.15; tmp_min = tmp_nml*0.85; lv_label_set_text_fmt(ui_pageHome_LabelRate25STD, "%.1f",tmp_nml); lv_label_set_text_fmt(ui_pageHome_LabelRate25UP, "%.1f",tmp_max); lv_label_set_text_fmt(ui_pageHome_LabelRate25DOWN, "%.1f",tmp_min); /* 计算30BPM标准体积值 */ tmp_nml = nominalVolumeStage/30.0; tmp_max = tmp_nml*1.15; tmp_min = tmp_nml*0.85; lv_label_set_text_fmt(ui_pageHome_LabelRate30STD, "%.1f",tmp_nml); lv_label_set_text_fmt(ui_pageHome_LabelRate30UP, "%.1f",tmp_max); lv_label_set_text_fmt(ui_pageHome_LabelRate30DOWN, "%.1f",tmp_min); /* 计算35BPM标准体积值 */ tmp_nml = nominalVolumeStage/35.0; tmp_max = tmp_nml*1.15; tmp_min = tmp_nml*0.85; lv_label_set_text_fmt(ui_pageHome_LabelRate35STD, "%.1f",tmp_nml); lv_label_set_text_fmt(ui_pageHome_LabelRate35UP, "%.1f",tmp_max); lv_label_set_text_fmt(ui_pageHome_LabelRate35DOWN, "%.1f",tmp_min); /* 计算40BPM标准体积值 */ tmp_nml = nominalVolumeStage/40.0; tmp_max = tmp_nml*1.15; tmp_min = tmp_nml*0.85; lv_label_set_text_fmt(ui_pageHome_LabelRate40STD, "%.1f",tmp_nml); lv_label_set_text_fmt(ui_pageHome_LabelRate40UP, "%.1f",tmp_max); lv_label_set_text_fmt(ui_pageHome_LabelRate40DOWN, "%.1f",tmp_min); } /* 更新BS界面中各频率值 */ /*根据标准值判定当前检测结果是否合格*/ //RefreshResult(); #if LOG_RECORD_ENABLE WRITE_LOG_TO_SD("BS测试刷新标准体积"); #endif }