Browse Source

添加加液和排液逻辑

storage-in-realtime
zhaohe 12 months ago
parent
commit
22824e363a
  1. 12
      app_protocols/apperrorcode/apperrorcode.hpp
  2. 2
      appsrc/appsetting/project_port/project_port.hpp
  3. 18
      appsrc/baseservice/devicestate/device_state_service.hpp
  4. 26
      appsrc/service/app/add_liquid_service.cpp
  5. 14
      appsrc/service/app/add_liquid_service.hpp
  6. 62
      appsrc/service/app/drain_liquid_service.cpp
  7. 16
      appsrc/service/app/drain_liquid_service.hpp
  8. 167
      appsrc/service/hardware/device_ctrl_service.cpp

12
app_protocols/apperrorcode/apperrorcode.hpp

@ -62,7 +62,17 @@ typedef enum {
kappe_missing_param = 10016,
kappe_param_num_err = 10017,
kappe_is_busy = 10018,
// 液体已加到位
kappe_adding_liquid_is_already_in_place = 10100,
// 加液大于设备最大容量
kappe_adding_liquid_is_greater_than_the_maximum_capacity_of_the_device = 10101,
kappe_state_is_busy = 10020,
kappe_is_adding_liquid = 10021, // 加液中
kappe_is_draining_liquid = 10022, // 排液中
kappe_is_disinfecting = 10023, // 消毒中
kappe_is_air_leak_detect_testing = 10024, // 气密性测试中
} apperror_t;
}

2
appsrc/appsetting/project_port/project_port.hpp

@ -44,6 +44,8 @@ class ProjectPort {
bool isInited = false;
int disinfectantBucketCapacity = 0;
int emptyPipeSprayPumpRPM = 700;
public:
static ProjectPort &ins() {
static ProjectPort instance;

18
appsrc/baseservice/devicestate/device_state_service.hpp

@ -62,4 +62,22 @@ class DeviceStateService : public enable_shared_from_this<DeviceStateService> {
void initialize() {};
};
static inline int32_t getDeviceBusyReason(DeviceState nowState) {
switch (nowState.id) {
case DeviceState::kIdle:
return 0;
case DeviceState::kDisinfection:
return err::kappe_is_disinfecting;
case DeviceState::kAddingLiquid:
return err::kappe_is_adding_liquid;
case DeviceState::kDrainingLiquid:
return err::kappe_is_draining_liquid;
case DeviceState::kAirLeakDetectTesting:
return err::kappe_is_air_leak_detect_testing;
default:
return 6;
}
}
} // namespace iflytop

26
appsrc/service/app/add_liquid_service.cpp

@ -1,5 +1,6 @@
#include "add_liquid_service.hpp"
using namespace iflytop;
void AddLiquidService::initialize() {
logger->info("AddLiquidService initialize");
REGFNV2(AddLiquidService, start);
@ -10,34 +11,31 @@ void AddLiquidService::initialize() {
void AddLiquidService::start(int stopatg) {
lock_guard<recursive_mutex> lock(lock_);
if (m_ds->getDeviceState() != DeviceState::Idle) {
auto nowstate = m_ds->getDeviceState();
if (nowstate != DeviceState::Idle) {
logger->warn("start add liquid fail, device state is not idle");
THROW_APP_EXCEPTION(err::kappe_is_busy, "device state is not idle");
THROW_APP_EXCEPTION(getDeviceBusyReason(nowstate), "");
}
if (m_thread) {
m_thread->join();
m_thread = nullptr;
m_workstate = kidle;
m_thread = nullptr;
}
int32_t nowvolume = m_dwus->getWeight();
int maxg = PORT.disinfectantBucketCapacity;
stopatg += 0; // 由于加液过程中,测量到的液体要比真实的小,所以这里要比预设值大100
if (nowvolume > stopatg) {
logger->warn("start add liquid fail, nowvolume {} > stopatg {}", nowvolume, stopatg);
THROW_APP_EXCEPTION(err::kappe_adding_liquid_is_already_in_place, "");
}
if (stopatg > maxg) {
logger->warn("start add liquid fail, stopatg {} > maxg {}", stopatg, maxg);
stopatg = maxg;
}
if (nowvolume > stopatg) {
logger->warn("start add liquid fail, nowvolume {} > stopatg {}", nowvolume, stopatg);
return;
}
m_workstate = kaddingLiquid;
m_thread.reset(new Thread("addLiquid", [this, stopatg]() { addLiquidWork(stopatg); }));
//
logger->info("start add liquid success");
@ -64,7 +62,7 @@ void AddLiquidService::addLiquidWork(int stopatg) {
*/
m_workstate = kemptyLineLiquid;
logger->info("start drain the liquid from the line");
m_dcs->SprayPump_startInRPM(-800); // 40gpm 约等于450RPM
m_dcs->SprayPump_startInRPM(-PORT.emptyPipeSprayPumpRPM);
thisThread.sleepForMs(1000);
m_dcs->AddLiquidPump_run(-23); // @TODO:提取常数到系统配置中
#define EMTPTY_LINE_WHEN_ADDING_DISINFECTANT_TIMES 1000
@ -105,11 +103,11 @@ void AddLiquidService::fn_stop(shared_ptr<MsgProcessContext> cxt) { stop(); }
void AddLiquidService::fn_getState(shared_ptr<MsgProcessContext> cxt) { //
cxt->content["workState"] = state2str(getWorkstate());
cxt->content["workStateDisplay"] = state2chstr(getWorkstate());
cxt->content["nowLiquid"] = 1000;
cxt->content["nowLiquid"] = m_dwus->getWeight();
}
void AddLiquidService::fn_getServiceConfig(shared_ptr<MsgProcessContext> cxt) {
json cfg;
cfg["maxLiquid"] = 4950;
cfg["maxLiquid"] = PORT.disinfectantBucketCapacity;
cfg["show"] = true;
cfg["updatePeriod"] = 300;
cxt->content = cfg;

14
appsrc/service/app/add_liquid_service.hpp

@ -53,18 +53,15 @@ class AddLiquidService : public enable_shared_from_this<AddLiquidService> {
}
private:
shared_ptr<DBService> m_db;
shared_ptr<DeviceStateService> m_ds;
shared_ptr<GConfig> m_gConfig;
shared_ptr<DBService> m_db;
shared_ptr<DeviceStateService> m_ds;
shared_ptr<GConfig> m_gConfig;
shared_ptr<DeviceIoControlService> m_dcs;
shared_ptr<DisinfectantWeightUpdateService> m_dwus;
state_t m_workstate = kidle;
unique_ptr<Thread> m_thread;
state_t m_workstate = kidle;
recursive_mutex lock_;
recursive_mutex lock_;
public:
void initialize();
@ -80,7 +77,6 @@ class AddLiquidService : public enable_shared_from_this<AddLiquidService> {
private:
void addLiquidWork(int stopatg);
};
} // namespace iflytop

62
appsrc/service/app/drain_liquid_service.cpp

@ -1,5 +1,7 @@
#include "drain_liquid_service.hpp"
using namespace iflytop;
#define DRAINLIQUID_EXT_TIME_S 8
void DrainLiquidService::initialize() {
logger->info("DrainLiquidService initialize");
REGFNV2(DrainLiquidService, start);
@ -8,10 +10,26 @@ void DrainLiquidService::initialize() {
REGFNV2(DrainLiquidService, getServiceConfig);
}
void DrainLiquidService::start() { m_workstate = kwork; }
void DrainLiquidService::stop() { m_workstate = kidle; }
void DrainLiquidService::start() {
lock_guard<recursive_mutex> lock(lock_);
auto nowstate = m_ds->getDeviceState();
if (nowstate != DeviceState::Idle) {
logger->warn("start add liquid fail, device state is not idle");
THROW_APP_EXCEPTION(getDeviceBusyReason(nowstate), "");
}
if (m_thread) {
m_thread->join();
m_thread = nullptr;
}
m_workstate = kwork;
m_thread.reset(new Thread("addLiquid", [this]() { workThread(); }));
}
DrainLiquidService::state_t DrainLiquidService::getWorkstate() { return m_workstate; }
void DrainLiquidService::stop() { m_workstate = kidle; }
void DrainLiquidService::fn_start(shared_ptr<MsgProcessContext> cxt) { //
start();
}
@ -19,14 +37,48 @@ void DrainLiquidService::fn_stop(shared_ptr<MsgProcessContext> cxt) { stop(); }
void DrainLiquidService::fn_getState(shared_ptr<MsgProcessContext> cxt) { //
cxt->content["workState"] = state2str(getWorkstate());
cxt->content["workStateDisplay"] = state2chstr(getWorkstate());
cxt->content["nowLiquid"] = 1000;
cxt->content["nowLiquid"] = m_dwus->getWeight();
}
void DrainLiquidService::fn_getServiceConfig(shared_ptr<MsgProcessContext> cxt) {
json cfg;
cfg["maxLiquid"] = 4950;
cfg["maxLiquid"] = PORT.disinfectantBucketCapacity;
cfg["show"] = true;
cfg["updatePeriod"] = 300;
cxt->content = cfg;
}
void DrainLiquidService::workThread() {
ThisThread thisThread;
m_dcs->AddLiquidPump_drainLiquid();
m_dcs->SprayPump_startInRPM(-PORT.emptyPipeSprayPumpRPM);
logger->info("startDraining ");
auto startdrainingtime = zsteady_clock().now();
zsteady_tp volumeReachZeroTime;
bool volumeReachZeroFlag = false;
while (!thisThread.getExitFlag()) {
int32_t nowvolume = m_dwus->getWeight();
logger->info("draining remain {} g", nowvolume);
if (!volumeReachZeroFlag && nowvolume <= 0) {
volumeReachZeroTime = zsteady_clock().now();
volumeReachZeroFlag = true;
}
if (volumeReachZeroFlag) {
logger->info("stopDraining after {} s", DRAINLIQUID_EXT_TIME_S - zsteady_clock().elapsedTimeS(volumeReachZeroTime));
if (zsteady_clock().elapsedTimeS(volumeReachZeroTime) > DRAINLIQUID_EXT_TIME_S) {
break;
}
}
cxt->content = cfg;
thisThread.sleepForMs(500);
}
logger->info("stopDraining");
m_dcs->AddLiquidPump_stop();
m_dcs->SprayPump_stop();
m_workstate = kidle;
}

16
appsrc/service/app/drain_liquid_service.hpp

@ -10,6 +10,9 @@
#include <vector>
//
#include "baseservice/baseservice.hpp"
#include "service/hardware/device_ctrl_service.hpp"
#include "service/hardware/disinfectant_weight_update_service.hpp"
//
namespace iflytop {
class DrainLiquidService : public enable_shared_from_this<DrainLiquidService> {
THISCLASS(AddLiquidService);
@ -43,11 +46,15 @@ class DrainLiquidService : public enable_shared_from_this<DrainLiquidService> {
}
private:
shared_ptr<DBService> m_db;
shared_ptr<DeviceStateService> m_ds;
shared_ptr<GConfig> m_gConfig;
shared_ptr<DBService> m_db;
shared_ptr<DeviceStateService> m_ds;
shared_ptr<GConfig> m_gConfig;
shared_ptr<DeviceIoControlService> m_dcs;
shared_ptr<DisinfectantWeightUpdateService> m_dwus;
state_t m_workstate = kidle;
state_t m_workstate = kidle;
unique_ptr<Thread> m_thread;
recursive_mutex lock_;
public:
void initialize();
@ -62,6 +69,7 @@ class DrainLiquidService : public enable_shared_from_this<DrainLiquidService> {
void fn_getServiceConfig(shared_ptr<MsgProcessContext> cxt);
private:
void workThread();
};
} // namespace iflytop

167
appsrc/service/hardware/device_ctrl_service.cpp

@ -60,53 +60,123 @@ void DeviceIoControlService::processReportMsg(uint8_t from, uint8_t *hex, uint32
// 加液泵控制
#define COMPONENT HardwareComponent::AddLiquidPump
void DeviceIoControlService::AddLiquidPump_addLiquid() {
if (isInPc()) return;
int pumpspeed = GET_SETTING(int, SettingId::drainage_pump_speed);
CAN_MASTER->pumpRotate(GET_BOARDID(), GET_SUBID(), pumpspeed);
}
void DeviceIoControlService::AddLiquidPump_drainLiquid() {
if (isInPc()) return;
int pumpspeed = GET_SETTING(int, SettingId::drainage_pump_speed);
CAN_MASTER->pumpRotate(GET_BOARDID(), GET_SUBID(), -pumpspeed);
}
void DeviceIoControlService::AddLiquidPump_run(int rpm) { CAN_MASTER->pumpRotate(GET_BOARDID(), GET_SUBID(), rpm); }
void DeviceIoControlService::AddLiquidPump_run(int rpm) {
if (isInPc()) return;
CAN_MASTER->pumpRotate(GET_BOARDID(), GET_SUBID(), rpm);
}
void DeviceIoControlService::AddLiquidPump_stop() { CAN_MASTER->pumpStop(GET_BOARDID(), GET_SUBID()); }
void DeviceIoControlService::AddLiquidPump_stop() {
if (isInPc()) return;
CAN_MASTER->pumpStop(GET_BOARDID(), GET_SUBID());
}
#undef COMPONENT
// 喷雾泵控制
#define COMPONENT HardwareComponent::SprayPump
void DeviceIoControlService::SprayPump_start(int32_t gpm) {
if (isInPc()) return;
int pumpspeed_rpm = ProjectPort::ins().gpm2speed(gpm);
CAN_MASTER->pumpRotate(GET_BOARDID(), GET_SUBID(), pumpspeed_rpm);
}
void DeviceIoControlService::SprayPump_stop() { CAN_MASTER->pumpStop(GET_BOARDID(), GET_SUBID()); }
void DeviceIoControlService::SprayPump_startInRPM(int32_t rpm) { CAN_MASTER->pumpRotate(GET_BOARDID(), GET_SUBID(), rpm); }
void DeviceIoControlService::SprayPump_stop() {
if (isInPc()) return;
CAN_MASTER->pumpStop(GET_BOARDID(), GET_SUBID());
}
void DeviceIoControlService::SprayPump_startInRPM(int32_t rpm) {
if (isInPc()) return;
CAN_MASTER->pumpRotate(GET_BOARDID(), GET_SUBID(), rpm);
}
#undef COMPONENT
// 鼓风机控制
#define COMPONENT HardwareComponent::Blower
void DeviceIoControlService::Blower_ctrl(int power) { CAN_MASTER->blowerCtrl(GET_BOARDID(), power); }
void DeviceIoControlService::Blower_close() { CAN_MASTER->blowerCtrl(GET_BOARDID(), 0); }
float DeviceIoControlService::Blower_readEI() { return CAN_MASTER->blowerReadEI(GET_BOARDID()) / 1000.0; }
void DeviceIoControlService::Blower_ctrl(int power) {
if (isInPc()) return;
CAN_MASTER->blowerCtrl(GET_BOARDID(), power);
}
void DeviceIoControlService::Blower_close() {
if (isInPc()) return;
CAN_MASTER->blowerCtrl(GET_BOARDID(), 0);
}
float DeviceIoControlService::Blower_readEI() {
if (isInPc()) return;
return CAN_MASTER->blowerReadEI(GET_BOARDID()) / 1000.0;
}
#undef COMPONENT
// 空压机控制
#define COMPONENT HardwareComponent::AirCompressor
void DeviceIoControlService::AC_ctrl(int power) { CAN_MASTER->airCompressorCtrl(GET_BOARDID(), power); }
void DeviceIoControlService::AC_close() { CAN_MASTER->airCompressorCtrl(GET_BOARDID(), 0); }
float DeviceIoControlService::AC_readEI() { return CAN_MASTER->airCompressorReadEI(GET_BOARDID()) / 1000.0; }
void DeviceIoControlService::AC_ctrl(int power) {
if (isInPc()) return;
CAN_MASTER->airCompressorCtrl(GET_BOARDID(), power);
}
void DeviceIoControlService::AC_close() {
if (isInPc()) {
return;
}
CAN_MASTER->airCompressorCtrl(GET_BOARDID(), 0);
}
float DeviceIoControlService::AC_readEI() {
if (isInPc()) {
return 0;
}
return CAN_MASTER->airCompressorReadEI(GET_BOARDID()) / 1000.0;
}
#undef COMPONENT
// 加热器控制
#define COMPONENT HardwareComponent::Heater
void DeviceIoControlService::Heater_ctrl(int power) { CAN_MASTER->heaterCtrl(GET_BOARDID(), power); }
void DeviceIoControlService::Heater_close() { CAN_MASTER->heaterCtrl(GET_BOARDID(), 0); }
float DeviceIoControlService::Heater_readEI() { return CAN_MASTER->heaterReadEI(GET_BOARDID()) / 1000.0; }
float DeviceIoControlService::Heater_readTemperature() { return CAN_MASTER->heaterReadTemperature(GET_BOARDID()) / 10.0; }
void DeviceIoControlService::Heater_ctrl(int power) {
if (isInPc()) {
return;
}
CAN_MASTER->heaterCtrl(GET_BOARDID(), power);
}
void DeviceIoControlService::Heater_close() {
if (isInPc()) {
return;
}
CAN_MASTER->heaterCtrl(GET_BOARDID(), 0);
}
float DeviceIoControlService::Heater_readEI() {
if (isInPc()) {
return 0;
}
return CAN_MASTER->heaterReadEI(GET_BOARDID()) / 1000.0;
}
float DeviceIoControlService::Heater_readTemperature() {
if (isInPc()) {
return 0;
}
return CAN_MASTER->heaterReadTemperature(GET_BOARDID()) / 10.0;
}
#undef COMPONENT
// 三色指示灯控制
#define COMPONENT HardwareComponent::WarningLight
void DeviceIoControlService::WarningLight_setState(int r, int g, int b, int warning) { //
if (isInPc()) return;
CAN_MASTER->warningLightSetState(GET_BOARDID(), r, g, b, warning);
}
#undef COMPONENT
@ -118,46 +188,75 @@ void DeviceIoControlService::WarningLight_setState(int r, int g, int b, int warn
#define COMPONENT HardwareComponent::PositivePressureProportional
void DeviceIoControlService::PosiPressureProp_setValve(int valveValue) { //
if (isInPc()) return;
CAN_MASTER->proportionalSetValve(GET_BOARDID(), GET_SUBID(), valveValue);
}
int DeviceIoControlService::PosiPressureProp_readPos() { return CAN_MASTER->proportionalReadPos(GET_BOARDID(), GET_SUBID()); }
bool DeviceIoControlService::PosiPressureProp_isBusy() { return CAN_MASTER->proportionalIsBusy(GET_BOARDID(), GET_SUBID()); }
int DeviceIoControlService::PosiPressureProp_readPos() {
if (isInPc()) return 0;
return CAN_MASTER->proportionalReadPos(GET_BOARDID(), GET_SUBID());
}
bool DeviceIoControlService::PosiPressureProp_isBusy() {
if (isInPc()) return false;
return CAN_MASTER->proportionalIsBusy(GET_BOARDID(), GET_SUBID());
}
#undef COMPONENT
#define COMPONENT HardwareComponent::NegativePressureProportional
void DeviceIoControlService::NegaPressureProp_setValve(int valveValue) { CAN_MASTER->proportionalSetValve(GET_BOARDID(), GET_SUBID(), valveValue); }
int DeviceIoControlService::NegaPressureProp_readPos() { return CAN_MASTER->proportionalReadPos(GET_BOARDID(), GET_SUBID()); }
bool DeviceIoControlService::NegaPressureProp_isBusy() { return CAN_MASTER->proportionalIsBusy(GET_BOARDID(), GET_SUBID()); }
void DeviceIoControlService::NegaPressureProp_setValve(int valveValue) {
if (isInPc()) return;
CAN_MASTER->proportionalSetValve(GET_BOARDID(), GET_SUBID(), valveValue);
}
int DeviceIoControlService::NegaPressureProp_readPos() {
if (isInPc()) return 0;
return CAN_MASTER->proportionalReadPos(GET_BOARDID(), GET_SUBID());
}
bool DeviceIoControlService::NegaPressureProp_isBusy() {
if (isInPc()) return false;
return CAN_MASTER->proportionalIsBusy(GET_BOARDID(), GET_SUBID());
}
#undef COMPONENT
#define COMPONENT HardwareComponent::AirLeakDetectTestChannelCtrl
void DeviceIoControlService::AirLeakDetectTestChannelCtrl_cutoffCh() { CAN_MASTER->airLeakDetectTestCloseOffCh(GET_BOARDID()); }
void DeviceIoControlService::AirLeakDetectTestChannelCtrl_releaseCh() { CAN_MASTER->airLeakDetectTestReleaseCh(GET_BOARDID()); }
void DeviceIoControlService::AirLeakDetectTestChannelCtrl_cutoffCh() {
if (isInPc()) return;
CAN_MASTER->airLeakDetectTestCloseOffCh(GET_BOARDID());
}
void DeviceIoControlService::AirLeakDetectTestChannelCtrl_releaseCh() {
if (isInPc()) return;
CAN_MASTER->airLeakDetectTestReleaseCh(GET_BOARDID());
}
#undef COMPONENT
// ExtChSelector
#define COMPONENT HardwareComponent::ExtChSelector
void DeviceIoControlService::ExtChSelector_selectCh(int ch) { CAN_MASTER->extChSelectorSetCh(GET_BOARDID(), ch); }
void DeviceIoControlService::ExtChSelector_selectCh(int ch) {
if (isInPc()) return;
CAN_MASTER->extChSelectorSetCh(GET_BOARDID(), ch);
}
#undef COMPONENT
// 水浸传感器
// 蒸发仓水浸
#define COMPONENT HardwareComponent::EvaporationBinWS
bool DeviceIoControlService::WaterSensor_readEvaporationBin() { return CAN_MASTER->evaporationTankWSReadState(GET_BOARDID()); }
bool DeviceIoControlService::WaterSensor_readEvaporationBin() {
if (isInPc()) return false;
return CAN_MASTER->evaporationTankWSReadState(GET_BOARDID());
}
#undef COMPONENT
#define COMPONENT HardwareComponent::DeviceBottomWS
bool DeviceIoControlService::WaterSensor_readDeviceBottom() { return CAN_MASTER->bottomWSReadState(GET_BOARDID()); } // 设备底部水浸
bool DeviceIoControlService::WaterSensor_readDeviceBottom() {
if (isInPc()) return false;
return CAN_MASTER->bottomWSReadState(GET_BOARDID());
} // 设备底部水浸
#undef COMPONENT
// ACPostPS_To_Pa
// AirLeakDetectPS_To_Pa
// LiquidWeightPS_To_Pa
// SprayPumpPostPS_To_Pa
// AddLiquidPumpPostPS_To_Pa
#define COMPONENT HardwareComponent::ACPostPS
int DeviceIoControlService::ACPostPS_readPa() { //
if (isInPc()) return 0;
int32_t val = CAN_MASTER->psBusReadData(GET_BOARDID(), GET_SUBID());
return ProjectPort::ins().ACPostPS_To_Pa(val);
}
@ -165,6 +264,8 @@ int DeviceIoControlService::ACPostPS_readPa() { //
#define COMPONENT HardwareComponent::AirLeakDetectPS
int DeviceIoControlService::AirLeakDetectPS_readPa() { //
if (isInPc()) return 0;
int32_t val = CAN_MASTER->psBusReadData(GET_BOARDID(), GET_SUBID());
return ProjectPort::ins().AirLeakDetectPS_To_Pa(val);
}
@ -172,6 +273,8 @@ int DeviceIoControlService::AirLeakDetectPS_readPa() { //
#define COMPONENT HardwareComponent::LiquidWeightPS
int DeviceIoControlService::LiquidWeightPS_readPa() { //
if (isInPc()) return 0;
int32_t val = CAN_MASTER->psBusReadData(GET_BOARDID(), GET_SUBID());
return ProjectPort::ins().LiquidWeightPS_To_Pa(val);
}
@ -179,6 +282,8 @@ int DeviceIoControlService::LiquidWeightPS_readPa() { //
#define COMPONENT HardwareComponent::SprayPumpPostPS
int DeviceIoControlService::SprayPumpPostPS_readPa() { //
if (isInPc()) return 0;
int32_t val = CAN_MASTER->psBusReadData(GET_BOARDID(), GET_SUBID());
return ProjectPort::ins().SprayPumpPostPS_To_Pa(val);
}
@ -186,12 +291,16 @@ int DeviceIoControlService::SprayPumpPostPS_readPa() { //
#define COMPONENT HardwareComponent::AddLiquidPumpPostPS
int DeviceIoControlService::AddLiquidPumpPostPS_readPa() { //
if (isInPc()) return 0;
int32_t val = CAN_MASTER->psBusReadData(GET_BOARDID(), GET_SUBID());
return ProjectPort::ins().AddLiquidPumpPostPS_To_Pa(val);
}
#undef COMPONENT
int DeviceIoControlService::DisinfectantVolume_readVal() {
if (isInPc()) return 0;
int pa = LiquidWeightPS_readPa();
return ProjectPort::ins().pressurePa2VolumeG(pa);

Loading…
Cancel
Save