600 lines
17 KiB
Arduino
600 lines
17 KiB
Arduino
#define MOTDEBUG 0
|
|
#define MOTCHKDEBUG 0
|
|
|
|
//--- needle valve flow control
|
|
PAR_LONG flow = 0;
|
|
PAR_BYTE flowSensState = 0;
|
|
PAR_BYTE motorState = 0;
|
|
PAR_LONG motorPulse = 0;
|
|
PAR_LONG motorOpenTime = 60;
|
|
PAR_LONG motorCurrent = 50;
|
|
PAR_LONG motorFreeCurrent = 120;
|
|
//PAR_LONG motorOverrunConst = 25000; // obsolete
|
|
PAR_LONG motorTorqueConst = 1100;
|
|
PAR_LONG motorTorqueLimit = 200;
|
|
PAR_LONG motorTorque = 0;
|
|
//PAR_LONG motorOverrun = 0; // obsolete
|
|
PAR_LONG motorMeasuredPulse = 0;
|
|
PAR_LONG motorRead = 0;
|
|
PAR_LONG motorFlowTarget = 0;
|
|
PAR_LONG motorWiggle = 0;
|
|
PAR_LONG motorSpeed = 0;
|
|
|
|
#define motor_text F("idle|~opening|~closing|opened|closed|no motor")
|
|
enum {motor_idle, motor_opening, motor_closing, motor_opened, motor_closed, motor_unplugged};
|
|
|
|
PAR_BYTE motorAutoState = 0;
|
|
#define motor_auto_text F("fixed|contrl.|autom.|offline")
|
|
enum {motor_fixed, motor_ctrl, motor_auto, motor_offline};
|
|
// commands
|
|
enum {motor_stop=0, motor_open, motor_close, motor_setfixed, motor_setctrl, motor_setauto}; // commands
|
|
|
|
ulong phaseStart = 0;
|
|
long mvolt = 0;
|
|
int8_t motorDir = 0;
|
|
byte motorCheckCurrent = 0;
|
|
MotorState pstate = pulse_off;
|
|
long flowUnfiltered = 0;
|
|
long pulseLength = 0;
|
|
byte lastAuto = motor_auto;
|
|
long motorPulseSum = 0;
|
|
ulong motorSpeedCalcTime = 0;
|
|
|
|
void FlowInit() {
|
|
pinMode(io_motor_current, OUTPUT);
|
|
analogWrite(io_motor_current, 0);
|
|
pinMode(io_motor_open, OUTPUT);
|
|
pinMode(io_motor_close, OUTPUT);
|
|
// switch on current: input pullup high
|
|
digitalWrite(io_motor_enable, HIGH);
|
|
pinMode(io_motor_enable, INPUT);
|
|
}
|
|
|
|
void FlowPars() {
|
|
ParFixed("f", flow, 2);
|
|
ParEnum("fav", flowAvailable, F("no|yes"));
|
|
ParEnum("fs", flowSensState, F("ok|no sensor"));
|
|
ParEnum("fm", motorState, motor_text);
|
|
ParEnum("fa", motorAutoState, motor_auto_text);
|
|
ParEnum("mav", motorAvailable, F("no|yes"));
|
|
if (ParFixed("mp", motorPulse, 3) == par_command) {
|
|
MotorSync();
|
|
MotorStart();
|
|
}
|
|
ParFixed("mot", motorOpenTime, 0);
|
|
ParFixed("mc", motorCurrent, 0);
|
|
//ParFixed("mfc", motorFreeCurrent, 0); // obsolete
|
|
ParFixed("mtc", motorTorqueConst, 0);
|
|
ParFixed("mtl", motorTorqueLimit, 3);
|
|
ParFixed("mt", motorTorque, 3);
|
|
ParFixed("mft", motorFlowTarget, 2);
|
|
//ParFixed("moc", motorOverrunConst, 0); // obsolete
|
|
//ParFixed("mo", motorOverrun, 3); // obsolete
|
|
ParFixed("mcr", motorRead, 1);
|
|
ParFixed("mw", motorWiggle, 3);
|
|
ParFixed("mmp", motorMeasuredPulse, 3); // measured pulse length until target reached
|
|
ParFixed("msp", motorSpeed, 3);
|
|
}
|
|
|
|
boolean FlowDispShort(boolean big) {
|
|
if (flowAvailable) {
|
|
if (big) {
|
|
DispText("flow/mbar");
|
|
DispBigValue(p_flow, p_flowSensState); // flow value
|
|
} else {
|
|
DispMediumValue("flow", p_flow, p_flowSensState); // flow value
|
|
//DispValue("flow", p_flow, p_flowSensState);
|
|
}
|
|
FlowStateDisp();
|
|
} else {
|
|
DispState("m.v. ", p_motorState);
|
|
}
|
|
return motorState == motor_opening || motorState == motor_closing;
|
|
}
|
|
|
|
boolean MotorDispShort() {
|
|
DispTextRow(fmt_lsmall, "m.v. ", ParFmt(p_motorState));
|
|
}
|
|
|
|
void MotorButtons(byte top) {
|
|
byte codebase = m_nv * 16;
|
|
|
|
if (!flowAvailable && !motorAvailable) return;
|
|
if (flowAvailable) {
|
|
DispButton(top, m_menu, m_nv, "*n.v.");
|
|
} else {
|
|
DispButton(top, m_menu, m_nv, "*m.v.");
|
|
}
|
|
if (motorState != motor_unplugged) {
|
|
if (motorAutoState == motor_ctrl) {
|
|
DispButton(top - 2, m_nv, motor_setfixed, "-fixed");
|
|
DispButton(top - 4, m_nv, motor_setauto, "-auto");
|
|
} else if (motorAutoState == motor_auto) {
|
|
DispButton(top - 2, m_nv, motor_setfixed, "-fixed");
|
|
DispButton(top - 4, m_nv, motor_setctrl, "-contrl");
|
|
} else {
|
|
if (abs(motorPulse) > 300 && (motorState == motor_opening || motorState == motor_closing)) {
|
|
DispButton(top - 2, m_nv, motor_stop, "-stop");
|
|
} else {
|
|
DispButton(top - 2, m_nv, motor_open, "-open");
|
|
DispButton(top - 4, m_nv, motor_close, "-close");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FlowDisp() {
|
|
byte codebase = m_nv * 16;
|
|
|
|
if (flowAvailable) {
|
|
DispText("flow/mbar");
|
|
DispBigValue(p_flow, p_flowSensState); // flow value
|
|
DispState("n.v. ", p_motorState);
|
|
DispState("mode: ", p_motorAutoState);
|
|
} else {
|
|
DispState("m.v. ", p_motorState);
|
|
}
|
|
if (motorState != motor_unplugged) {
|
|
DispButton(2, m_nv, motor_open, "open");
|
|
DispButton(3, m_nv, motor_close, "close");
|
|
if (motorAutoState == motor_auto || motorAutoState == motor_ctrl) {
|
|
DispButton(4, m_nv, motor_setfixed, "fixed");
|
|
} else if (abs(motorPulse) > 300 && (motorState == motor_opening || motorState == motor_closing)) {
|
|
DispButton(4, m_nv, motor_stop, "stop");
|
|
}
|
|
if (motorAutoState == motor_offline) {
|
|
// no button here
|
|
} else if (motorAutoState == motor_auto || (motorAutoState != motor_ctrl && lastAuto == motor_ctrl)) {
|
|
DispButton(5, m_nv, motor_setctrl, "contrl");
|
|
} else {
|
|
DispButton(5, m_nv, motor_setauto, "auto");
|
|
}
|
|
}
|
|
DispButton(0, m_menu, m_menu, "menu");
|
|
DispButton(1, m_menu, m_home, "home");
|
|
}
|
|
|
|
void FlowHandler() {
|
|
static ulong last;
|
|
long raw;
|
|
long rsum = 0;
|
|
long psum = 0;
|
|
int rcnt = 0;
|
|
int pcnt = 0;
|
|
int pmax = 0;
|
|
long dif;
|
|
long maxdif, md2;
|
|
static long sum=0;
|
|
static long cnt=0;
|
|
static const long fact = 10;
|
|
static ulong lastUpdate = 0;
|
|
|
|
if (!flowAvailable) return;
|
|
rsum = 0;
|
|
psum = 0;
|
|
rcnt = 0;
|
|
pcnt = 0;
|
|
pmax = 0;
|
|
while (pcnt + rcnt < 50) {
|
|
if (pcnt < pmax / 2) {
|
|
psum += aRead(a_flow_prec) * 19L; // 19 = 47.5 Ohm / 2.5 Ohm (2.5 Ohm = reference R)
|
|
pcnt++;
|
|
} else {
|
|
rsum += aRead(a_flow_raw) * 99L; // 99 = 247.5 Ohm / 2.5 Ohm
|
|
rcnt++;
|
|
}
|
|
// calculate the weight for the precise range meas. (0...100)
|
|
if (pcnt > rcnt) {
|
|
pmax = 1000 - psum / pcnt / 19;
|
|
} else {
|
|
pmax = 1000 - rsum / rcnt / 19;
|
|
}
|
|
if (pmax < 0) {
|
|
pmax = 0;
|
|
} else if (pmax > 100) {
|
|
pmax = 100;
|
|
}
|
|
}
|
|
if (rcnt == 0) {
|
|
pmax = 100;
|
|
}
|
|
if (pcnt == 0) {
|
|
pmax = 0;
|
|
flowUnfiltered = 0;
|
|
} else {
|
|
flowUnfiltered = psum * pmax / pcnt;
|
|
}
|
|
if (rcnt > 0) {
|
|
flowUnfiltered += rsum * (100 - pmax) / rcnt;
|
|
}
|
|
// flowUnfiltered is in 0.01 mbar
|
|
// 250 = 100 (weight) / 1235 mV * 1024 / 2.5 Ohm * 47.5 Ohm * 247.5 Ohm / 250 mbar * 16 mA * (0.01 mbar)
|
|
// 6150 = 4 mA / 16 mA * 250 mbar / (0.01 mbar) - 1.0 mbar (margin)
|
|
flowUnfiltered = flowUnfiltered / 250 - 6150;
|
|
sum += flowUnfiltered;
|
|
cnt++;
|
|
if (cnt > 1000 || expired(&lastUpdate, 250)) {
|
|
//if (cnt > 1000 || expired(&lastUpdate, 500)) {
|
|
ParSet(flow, sum / cnt);
|
|
if (flow < -5000) {
|
|
ParSet(flowSensState, 1);
|
|
} else if (flow > -4000) {
|
|
ParSet(flowSensState, 0);
|
|
}
|
|
sum = 0;
|
|
cnt = 0;
|
|
}
|
|
}
|
|
|
|
void MotorSetCurrent(int8_t sign, MotorCurrentType ct) {
|
|
long c = 0;
|
|
|
|
/*
|
|
long cf;
|
|
if (ct == zero_current) {
|
|
c = 0;
|
|
} else {
|
|
cf = motorFreeCurrent + motorFreeCurrent / 14;
|
|
if (ct == freeClose_current) {
|
|
c = cf;
|
|
} else {
|
|
c = motorCurrent + motorCurrent / 14;
|
|
if (c > cf * 2 / 3) {
|
|
c = cf * 2 / 3;
|
|
}
|
|
if (ct == freeOpen_current) {
|
|
c = (c + cf) / 2;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
if (ct != zero_current) {
|
|
if (motorCurrent > 100) {
|
|
ParSet(motorCurrent, 100); // this is the permanent limit of the switch MAX314
|
|
}
|
|
c = motorCurrent + motorCurrent / 14;
|
|
}
|
|
analogWrite(io_motor_current, c);
|
|
if (sign) {
|
|
// enable current
|
|
pinMode(io_motor_enable, INPUT);
|
|
digitalWrite(io_motor_enable, HIGH);
|
|
if (sign < 0) {
|
|
if (MOTDEBUG) {
|
|
Serial.print(c, DEC);
|
|
Serial.print(" motor-\n");
|
|
}
|
|
digitalWrite(io_motor_open, HIGH);
|
|
digitalWrite(io_motor_close, LOW);
|
|
motorDir = -1;
|
|
} else {
|
|
if (MOTDEBUG) {
|
|
Serial.print(c, DEC);
|
|
Serial.print(" motor+\n");
|
|
}
|
|
digitalWrite(io_motor_open, LOW);
|
|
digitalWrite(io_motor_close, HIGH);
|
|
motorDir = 1;
|
|
}
|
|
} else {
|
|
if (MOTDEBUG) {
|
|
Serial.print(c, DEC);
|
|
Serial.print(" motor0\n");
|
|
}
|
|
// disable current
|
|
digitalWrite(io_motor_enable, LOW);
|
|
pinMode(io_motor_enable, OUTPUT);
|
|
motorDir = 0;
|
|
}
|
|
}
|
|
|
|
void MotorSetState(MotorState p) {
|
|
if (MOTCHKDEBUG) {
|
|
Serial.print(pstate); Serial.print(" -> "); Serial.println(p);
|
|
}
|
|
pstate = p;
|
|
phaseStart = now;
|
|
}
|
|
|
|
void MotorStart() {
|
|
FastHandler();
|
|
if (motorPulse == 0) {
|
|
pulseLength = 0;
|
|
return;
|
|
}
|
|
pulseLength = abs(motorPulse);
|
|
if (pstate == pulse_running) {
|
|
motorPulseSum += (now - phaseStart) * motorDir;
|
|
if ((motorDir > 0) == (motorPulse > 0)) {
|
|
// do not interrupt a running pulse, but count new pulse from now
|
|
phaseStart = now;
|
|
return;
|
|
}
|
|
}
|
|
if (pstate != pulse_before) {
|
|
MotorSetState(pulse_before);
|
|
MotorSetCurrent(0, std_current); // set current output, but with disabled output (for stabilizing pwm filter)
|
|
}
|
|
}
|
|
|
|
void MotorFastHandler() {
|
|
if (pstate == pulse_running) {
|
|
if (time_ge(now, phaseStart + pulseLength)) {
|
|
motorPulseSum += pulseLength * motorDir;
|
|
if (MOTDEBUG) {
|
|
Serial.print(pulseLength);
|
|
Serial.print(" pulseEND\n");
|
|
}
|
|
//MotorSetCurrent(motorDir, zero_current); // stop motor
|
|
MotorSetCurrent(0, zero_current); // stop motor (0: short circuit)
|
|
MotorSetState(pulse_after);
|
|
ParSet(motorState, motor_idle);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MotorSync() {
|
|
// synchronize motorSpeed sum interval
|
|
if (time_ge(now, motorSpeedCalcTime + 1500)) return;
|
|
motorSpeedCalcTime = now - 750;
|
|
}
|
|
|
|
void MotorHandler() {
|
|
long current, volt;
|
|
long drive;
|
|
byte i;
|
|
static byte off_cnt = 0;
|
|
long p;
|
|
|
|
if (!motorAvailable) return;
|
|
if (motorAutoState == motor_ctrl || motorAutoState == motor_auto) {
|
|
lastAuto = motorAutoState;
|
|
}
|
|
if (!online) {
|
|
if (motorAutoState != motor_offline) {
|
|
ParSet(motorAutoState, motor_offline);
|
|
}
|
|
}
|
|
current = aRead(a_motor_current) + aRead(a_motor_current);
|
|
volt = 0;
|
|
for (i = 0; i < 4; i++) {
|
|
volt += aRead(a_motor_volt);
|
|
}
|
|
current += aRead(a_motor_current) + aRead(a_motor_current);
|
|
if (volt > 3000 && current <= 4) {
|
|
if (motorState != motor_unplugged) {
|
|
if (off_cnt > 20) {
|
|
// switch off
|
|
ParSet(motorPulse, 0);
|
|
ParSet(motorState, motor_unplugged);
|
|
ParSet(motorAutoState, motor_fixed);
|
|
if (MOTCHKDEBUG) {
|
|
Serial.print("NO MOT\n");
|
|
}
|
|
} else {
|
|
off_cnt++;
|
|
}
|
|
}
|
|
} else if (off_cnt > 0) {
|
|
off_cnt--;
|
|
}
|
|
switch (pstate) {
|
|
case pulse_before:
|
|
if (motorFlowTarget > 0 && motorDir > 0 && flowUnfiltered > motorFlowTarget) {
|
|
ParSet(motorState, motor_idle);
|
|
ParSet(motorFlowTarget, 0);
|
|
//ParSet(motorOverrun, 0);
|
|
MotorSetState(pulse_off);
|
|
break;
|
|
}
|
|
if (time_ge(now, phaseStart + 200)) {
|
|
if (motorPulse > 0) {
|
|
MotorSetCurrent(1, std_current);
|
|
ParSet(motorState, motor_opening);
|
|
} else {
|
|
MotorSetCurrent(-1, std_current);
|
|
ParSet(motorState, motor_closing);
|
|
}
|
|
mvolt = 0;
|
|
MotorSetState(pulse_running);
|
|
ParSet(motorMeasuredPulse, 0); // reset measured open pulse
|
|
if (MOTDEBUG) {
|
|
Serial.println("CLOSING PULSE");
|
|
}
|
|
}
|
|
break;
|
|
case pulse_running:
|
|
if (motorFlowTarget > 0 && motorDir > 0 && flowUnfiltered > motorFlowTarget) {
|
|
ParSet(motorMeasuredPulse, motorDir * (now - phaseStart));
|
|
motorPulseSum += motorMeasuredPulse;
|
|
MotorSetCurrent(0, zero_current); // stop motor (0: short circuit)
|
|
ParSet(motorState, motor_idle);
|
|
// this feature has to be choosen before every pulse
|
|
ParSet(motorFlowTarget, 0);
|
|
MotorSetState(pulse_after);
|
|
break;
|
|
}
|
|
if (time_ge(now, phaseStart + 250)) { // check torque
|
|
if (mvolt == 0) {
|
|
ParSet(motorTorque, current * motorTorqueConst / volt);
|
|
} else { // averaged torque
|
|
ParSet(motorTorque, (motorTorque * 4 + current * motorTorqueConst / volt) / 5);
|
|
}
|
|
mvolt = volt / 4;
|
|
if (MOTDEBUG) {
|
|
Serial.print(now - phaseStart);
|
|
Serial.print("ms ");
|
|
Serial.print(volt * 19 / 3); // 1235 mV * (20 kOhm / 1kOhm + 1) / 4 / 1024
|
|
Serial.print("mV ");
|
|
Serial.print(current * 7 / 130); // 1235 mV / 5.6 Ohm / 4 times / 1024
|
|
Serial.print("mA ");
|
|
Serial.print(motorTorque);
|
|
Serial.println("tq");
|
|
}
|
|
if (motorEndSwitch && motorState != motor_closing) {
|
|
if (aRead(a_aux_current) > 10) {
|
|
ParSet(motorState, motor_opened);
|
|
}
|
|
}
|
|
if (motorTorque > motorTorqueLimit) {
|
|
if (motorDir > 0) {
|
|
if (MOTDEBUG) {
|
|
Serial.println("OPENED");
|
|
}
|
|
ParSet(motorState, motor_opened);
|
|
} else {
|
|
if (MOTDEBUG) {
|
|
Serial.println("CLOSED");
|
|
}
|
|
ParSet(motorState, motor_closed);
|
|
}
|
|
}
|
|
}
|
|
if (motorState != motor_opening && motorState != motor_closing) {
|
|
if (MOTDEBUG) {
|
|
Serial.print(motorState);
|
|
Serial.print(" dir");
|
|
Serial.print(motorDir);
|
|
Serial.println(" Stop");
|
|
}
|
|
MotorSetCurrent(motorDir, zero_current); // stop motor
|
|
motorPulseSum += motorDir * (now - phaseStart);
|
|
MotorSetState(pulse_after);
|
|
}
|
|
break;
|
|
case pulse_after:
|
|
if (motorWiggle != 0) {
|
|
MotorSetState(pulse_running);
|
|
pulseLength = abs(motorWiggle);
|
|
if (motorPulse > 0) {
|
|
MotorSetCurrent(-1, std_current);
|
|
ParSet(motorState, motor_closing);
|
|
ParSet(motorPulse, -pulseLength);
|
|
} else {
|
|
MotorSetCurrent(1, std_current);
|
|
ParSet(motorState, motor_opening);
|
|
ParSet(motorPulse, pulseLength);
|
|
}
|
|
ParSet(motorWiggle, 0);
|
|
break;
|
|
}
|
|
MotorSetCurrent(-1, zero_current);
|
|
MotorSetState(pulse_off);
|
|
mvolt = 0;
|
|
/*
|
|
if (time_ge(now, phaseStart + 1000)) { // stop anyway after 1000 msec
|
|
MotorSetState(pulse_off);
|
|
mvolt = 0;
|
|
} else if (volt < 100) {
|
|
if (mvolt > volt + 50) {
|
|
ParSet(motorOverrun, (motorOverrunConst - volt * motorOverrunConst / mvolt) / (now - phaseStart));
|
|
}
|
|
MotorSetState(pulse_off);
|
|
mvolt = 0;
|
|
}
|
|
*/
|
|
break;
|
|
case pulse_off:
|
|
if (time_ge(now, phaseStart + 3000)) {
|
|
MotorSetState(pulse_check0);
|
|
MotorSetCurrent(0, zero_current);
|
|
}
|
|
if (motorState == motor_opening || motorState == motor_closing) {
|
|
ParSet(motorState, motor_idle);
|
|
}
|
|
break;
|
|
case pulse_check0:
|
|
if (time_ge(now, phaseStart + 250)) {
|
|
MotorSetState(pulse_check);
|
|
MotorSetCurrent(1, zero_current);
|
|
motorCheckCurrent = 0;
|
|
}
|
|
break;
|
|
case pulse_check:
|
|
if (MOTCHKDEBUG) {
|
|
Serial.print("volt "); Serial.print(volt); Serial.print(" current "); Serial.print(current); Serial.print(" drive "); Serial.println(motorCheckCurrent);
|
|
}
|
|
if (volt > 500) { // voltage high - current low: no motor
|
|
if (current <= 4) {
|
|
if (motorState != motor_unplugged) {
|
|
ParSet(motorState, motor_unplugged);
|
|
ParSet(motorAutoState, motor_fixed);
|
|
ParSet(motorPulse, 0);
|
|
if (MOTCHKDEBUG) {
|
|
Serial.print("NO MOT\n");
|
|
}
|
|
}
|
|
analogWrite(io_motor_current, 0);
|
|
}
|
|
} else if (current > 4) {
|
|
if (MOTCHKDEBUG) {
|
|
Serial.print("MOT is there\n");
|
|
}
|
|
if (motorState == motor_unplugged) {
|
|
ParSet(motorState, motor_idle);
|
|
}
|
|
} else if (motorCheckCurrent < 20) {
|
|
motorCheckCurrent++;
|
|
analogWrite(io_motor_current, motorCheckCurrent);
|
|
break;
|
|
}
|
|
MotorSetCurrent(0, zero_current);
|
|
MotorSetState(pulse_off);
|
|
}
|
|
if (time_ge(now, motorSpeedCalcTime + 5000)) {
|
|
motorSpeedCalcTime = now;
|
|
if (pstate == pulse_running) {
|
|
p = motorDir * (now - phaseStart);
|
|
} else {
|
|
p = 0;
|
|
}
|
|
ParSet(motorSpeed, motorPulseSum + p);
|
|
motorPulseSum = - p;
|
|
}
|
|
}
|
|
|
|
void MotorCmd(byte cmd) {
|
|
switch (cmd) {
|
|
case motor_setfixed:
|
|
case motor_stop:
|
|
ParSet(motorAutoState, motor_fixed);
|
|
if (motorState == motor_opening || motorState == motor_closing) {
|
|
ParSet(motorState, motor_idle);
|
|
if (MOTDEBUG) {
|
|
Serial.print("stopped\n");
|
|
}
|
|
ParSet(motorPulse, 0);
|
|
}
|
|
break;
|
|
case motor_open:
|
|
if (motorState != motor_unplugged) {
|
|
ParSet(motorPulse, 1000 * motorOpenTime);
|
|
MotorStart();
|
|
}
|
|
break;
|
|
case motor_close:
|
|
if (motorState != motor_unplugged) {
|
|
ParSet(motorPulse, -1000 * motorOpenTime);
|
|
MotorStart();
|
|
}
|
|
break;
|
|
case motor_setctrl:
|
|
ParSet(motorAutoState, motor_ctrl);
|
|
break;
|
|
case motor_setauto:
|
|
ParSet(motorAutoState, motor_auto);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void FlowStateDisp() {
|
|
const char *text;
|
|
|
|
if (motorState == motor_idle && motorAutoState != motor_offline) {
|
|
text = ParFmt(p_motorAutoState);
|
|
} else {
|
|
text = ParFmt(p_motorState);
|
|
}
|
|
DispTextRow(fmt_lsmall, "n.v. ", text);
|
|
}
|