913 lines
25 KiB
C++
913 lines
25 KiB
C++
#include "valve.h"
|
|
|
|
#define HEDEBUG 0
|
|
|
|
//--- Liquid Helium
|
|
PAR_LONG heLevel = 0; // channel 6 (internal)
|
|
PAR_LONG heRaw = 0;
|
|
PAR_LONG heHigh = 9500; // stop filling
|
|
PAR_LONG heLow = 1000; // start filling
|
|
PAR_LONG heDrive = 75;
|
|
PAR_LONG heWiRes = 500;
|
|
PAR_LONG heCurrent = 0;
|
|
PAR_LONG heVolt = 0;
|
|
PAR_LONG heFastTime = 30; // 20 sec
|
|
PAR_LONG heSlowTime = 300; // 300 sec
|
|
PAR_LONG heEmpty = 200;
|
|
PAR_LONG heFull = 0;
|
|
PAR_LONG heFirst = 0;
|
|
PAR_LONG heSlope = 0;
|
|
PAR_LONG heIncreaseTolerance = 500; // [0.01%] if increase higher than this switch to fast
|
|
PAR_LONG heFastTimeout = 600; // sec, switch to slow when no increase within this time
|
|
#define he_sens_text F("ok|sensor warm|no sensor|tmo|meas soon| ")
|
|
enum {he_sens_ok, he_sens_warm, he_no_sens, he_timeout, he_not_yet, he_disabled};
|
|
PAR_BYTE heSensState = he_not_yet; // internal channel
|
|
PAR_BYTE heValve = 0;
|
|
PAR_BYTE heFast = 1; // 0: slow, 1: fast
|
|
PAR_BYTE heAuto = 1; // 0: off, 1: auto fill
|
|
PAR_BYTE heMeas = 0; // 0: idle, 1: measuring, 2:checking
|
|
PAR_LONG heExtLevel[6] = {0};
|
|
PAR_BYTE heExtState[6] = {he_not_yet, he_disabled, he_disabled, he_disabled, he_disabled, he_disabled}; // disabled
|
|
PAR_LONG heExtWiRes = 460;
|
|
PAR_LONG heExtEmpty = 565;
|
|
PAR_LONG heExtFull = 90;
|
|
PAR_LONG heExtDrive = 75;
|
|
PAR_LONG heChannel = 7;
|
|
long heCableVolt0 = 0;
|
|
long heCableVolt1 = 1;
|
|
long heMinLev[7] = {0,0,0,0,0,0,0};
|
|
long heMinLevel;
|
|
long heIntLevel = 0;
|
|
byte heIntState = he_not_yet;
|
|
|
|
//PAR_BYTE heBooster = 0; // 48 V Booster enable
|
|
PAR_BYTE heCommand = 0;
|
|
#define he_cmd_text F("stop|fill|off|watch|slow|fast|more|manual on")
|
|
enum {he_stop=0, he_fill, he_off, he_watch, he_slow, he_fast, he_more, he_manual}; // commands
|
|
|
|
const long undef_mm = 999999;
|
|
const long heMeasSpeed = 50; // mm / sec
|
|
const long heMeasTol = 20; // mm
|
|
ulong heLastIncrease = -240000;
|
|
boolean checking = false;
|
|
boolean started = false;
|
|
float res_to_len = 300;
|
|
long empty_10um = 20000;
|
|
float mm_to_percent = 0.5;
|
|
long heIntDrive = 0;
|
|
|
|
void HePars() {
|
|
byte changed;
|
|
|
|
ParFixed("h", heLevel, 2);
|
|
ParFixed("hr", heRaw, 2);
|
|
changed = (ParFixed("hd", heDrive, 0) == par_command);
|
|
ParFixed("hc", heCurrent, 1);
|
|
ParFixed("hu", heVolt, 2);
|
|
ParFixed("hh", heHigh, 2);
|
|
ParFixed("hl", heLow, 2);
|
|
changed |= (ParFixed("hwr", heWiRes, 0) == par_command);
|
|
changed |= (ParFixed("hem", heEmpty, 0) == par_command);
|
|
changed |= (ParFixed("hfu", heFull, 0) == par_command);
|
|
if (changed && heSensState != he_disabled) {
|
|
ParSet(heSensState, he_not_yet);
|
|
}
|
|
ParFixed("htf", heFastTime, 0);
|
|
ParFixed("hts", heSlowTime, 0);
|
|
ParFixed("hms", heSlope, 0);
|
|
ParFixed("hmf", heFirst, 2);
|
|
ParFixed("hit", heIncreaseTolerance, 2);
|
|
changed = (ParFixed("hft", heFastTimeout, 0) == par_command);
|
|
if (changed) {
|
|
heLastIncrease = now;
|
|
}
|
|
ParEnum("hv", heValve, valve_text);
|
|
ParEnum("hsf", heSensState, he_sens_text);
|
|
ParEnum("ha", heAuto, F("off|auto"));
|
|
ParEnum("hm", heMeas, F("idle|meas|check"));
|
|
changed = (ParEnum("hf", heFast, F("slow|fast")) == par_command);
|
|
if (changed) {
|
|
heLastIncrease = now;
|
|
}
|
|
if (ParEnum("hav", heAvailable, F("no|yes|ext")) == par_command) {
|
|
if (heAvailable == 1) {
|
|
if (heSensState == he_disabled) {
|
|
ParSet(heSensState, he_not_yet);
|
|
}
|
|
}
|
|
}
|
|
//ParEnum("hbe", heBooster, F("disable|enable"));
|
|
if (ParEnum("hcd", heCommand, he_cmd_text) == par_command) {
|
|
HeRemoteCmd(heCommand);
|
|
}
|
|
changed = (ParEnum("hea", heExtAvailable, F("0")) == par_command); // use enum 0 for pure byte
|
|
if (heExtAvailable > 6) {
|
|
ParSet(heExtAvailable, 1);
|
|
}
|
|
changed |= (ParFixed("hd0", heExtDrive, 0) == par_command);
|
|
changed |= (ParFixed("hwr0", heExtWiRes, 0) == par_command);
|
|
changed |= (ParFixed("hem0", heExtEmpty, 0) == par_command);
|
|
changed |= (ParFixed("hfu0", heExtFull, 0) == par_command);
|
|
if (changed) {
|
|
if (heExtAvailable == 1) {
|
|
if (HEDEBUG) {
|
|
Serial.println("activate channel 0");
|
|
}
|
|
ParArraySet(heExtState, 0, he_not_yet);
|
|
} else {
|
|
for (byte n = 0; n < 6; n++) {
|
|
if (ARRAY(heExtState,n) != he_disabled) {
|
|
ParArraySet(heExtState, n, he_not_yet);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ParFixed("hch", heChannel, 0);
|
|
//ParFixedArray("h", heExtLevel, 0, heExtAvailable - 1, 2);
|
|
//ParEnumArray("hs", heExtState, 0, heExtAvailable - 1, he_sens_text);
|
|
ParFixedArray("h", heExtLevel, 0, 5, 2);
|
|
ParEnumArray("hs", heExtState, 0, 5, he_sens_text);
|
|
}
|
|
|
|
void HeInit() {
|
|
byte pin;
|
|
|
|
pinMode(io_motor_current, OUTPUT);
|
|
digitalWrite(io_lev_boost, HIGH); // 48 V booster inactive
|
|
pinMode(io_lev_boost, OUTPUT);
|
|
// switch off current
|
|
digitalWrite(io_lev_enable, LOW);
|
|
pinMode(io_lev_enable, OUTPUT);
|
|
// select main channel
|
|
digitalWrite(io_he_select, LOW);
|
|
pinMode(io_he_select, OUTPUT);
|
|
|
|
if (heExtAvailable > 1) {
|
|
for (pin = 0; pin < 8; pin++) {
|
|
digitalWrite(io_ext1 + pin, HIGH);
|
|
pinMode(io_ext1 + pin, OUTPUT);
|
|
}
|
|
}
|
|
}
|
|
|
|
byte HeValueNr(byte channel) {
|
|
if (channel >= 0 && channel < 6) {
|
|
return p_heExtLevel + channel;
|
|
}
|
|
return p_heLevel;
|
|
}
|
|
|
|
byte HeStateNr(byte channel) {
|
|
if (channel >= 0 && channel < 6) {
|
|
return p_heExtState + channel;
|
|
}
|
|
return p_heSensState;
|
|
}
|
|
|
|
void HeSetLev(byte channel, long value) {
|
|
if (channel >= 0 && channel < 6) {
|
|
ParArraySet(heExtLevel, channel, value);
|
|
} else if (channel == 6) {
|
|
ParSet(heLevel, value);
|
|
}
|
|
}
|
|
|
|
void HeSetState(byte channel, byte value) {
|
|
if (channel >= 0 && channel < 6) {
|
|
ParArraySet(heExtState, channel, value);
|
|
} else if (channel == 6) {
|
|
ParSet(heSensState, value);
|
|
}
|
|
}
|
|
|
|
byte HeGetState(byte channel) {
|
|
if (channel >= 0 && channel < heExtAvailable) {
|
|
return ARRAY(heExtState,channel);
|
|
} else if (channel == 6) {
|
|
return heSensState;
|
|
}
|
|
return he_disabled;
|
|
}
|
|
|
|
long HeGetLevel(byte channel) {
|
|
if (channel >= 0 && channel < 6) {
|
|
return ARRAY(heExtLevel,channel);
|
|
} else if (channel == 6) {
|
|
return heLevel;
|
|
}
|
|
return -990; //error
|
|
}
|
|
|
|
void HeLoadChannel() {
|
|
heIntState = HeGetState(heChannel);
|
|
heIntLevel = HeGetLevel(heChannel);
|
|
if (heChannel >= 0 && heChannel <= 6) {
|
|
heMinLevel = ARRAY(heMinLev,heChannel);
|
|
}
|
|
}
|
|
|
|
boolean HeShown() {
|
|
return heAvailable; // || heValve != no_valve;
|
|
}
|
|
|
|
void HeDispExt() {
|
|
char head[4];
|
|
byte channel;
|
|
byte st;
|
|
byte h=0; // summed height
|
|
byte n=0; // number of lines
|
|
|
|
DispTouchCmd(m_menu, m_menu); // open menu on a touch anywhere
|
|
|
|
// sum up height to check if we can use large numbers
|
|
for (channel = 0; channel < 7; channel++) {
|
|
st = HeGetState(channel);
|
|
if (st != he_disabled) {
|
|
n++;
|
|
if (st == he_sens_ok) {
|
|
h += DispRowHeight(fmt_large);
|
|
} else {
|
|
h += DispRowHeight(fmt_lsmall);
|
|
}
|
|
}
|
|
}
|
|
head[1] = ')';
|
|
head[2] = 0;
|
|
|
|
for (channel = 0; channel < 7; channel++) {
|
|
st = HeGetState(channel);
|
|
if (st != he_disabled) {
|
|
head[0] = '0' + channel;
|
|
if (st == he_sens_ok) {
|
|
if (h > 128) {
|
|
DispMediumValue(head, HeValueNr(channel), HeStateNr(channel));
|
|
} else {
|
|
DispLargeValue(head, HeValueNr(channel), HeStateNr(channel));
|
|
}
|
|
} else {
|
|
DispValue(head, HeValueNr(channel), HeStateNr(channel));
|
|
if (n < 6) {
|
|
DispText(" ");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
boolean HeDispShort(boolean *big) {
|
|
boolean isbig = true;
|
|
|
|
HeStateDisp("He ");
|
|
if (heAvailable == 1 && heExtState[0] == he_sens_ok) {
|
|
isbig = true;
|
|
} else {
|
|
isbig = false;
|
|
}
|
|
if (heAvailable == 1) {
|
|
if (isbig) {
|
|
DispMediumValue("", p_heLevel, p_heSensState); // He level
|
|
} else {
|
|
DispBigValue(p_heLevel, p_heSensState); // He level
|
|
}
|
|
}
|
|
if (heExtState[0] == he_sens_ok) {
|
|
// DispValue("vessel", HeValueNr(0), HeStateNr(0));
|
|
DispMediumValue("vessel", HeValueNr(0), HeStateNr(0));
|
|
}
|
|
*big = isbig;
|
|
return heValve == valve_on;
|
|
}
|
|
|
|
void HeButtons(byte top) {
|
|
if (!heAvailable) return;
|
|
DispButton(top, m_menu, m_he, "*LHe");
|
|
if (heValve == no_valve) {
|
|
if (heFast) {
|
|
DispButton(top - 2, m_he, he_slow, "-slow");
|
|
} else {
|
|
DispButton(top - 2, m_he, he_fast, "-fast");
|
|
}
|
|
} else {
|
|
if (heValve == valve_on) {
|
|
DispButton(top - 2, m_he, he_watch, "-watch");
|
|
} else {
|
|
if (heAuto) {
|
|
DispButton(top - 2, m_he, he_off, "-off");
|
|
} else {
|
|
DispButton(top - 2, m_he, he_watch, "-watch");
|
|
}
|
|
DispButton(top - 4, m_he, he_fill, "-fill");
|
|
}
|
|
}
|
|
}
|
|
|
|
void HeDisp() {
|
|
boolean showAuto;
|
|
byte codebase = m_he * 16;
|
|
|
|
//DispFullScreenTouch(m_he, he_more);
|
|
//DispCheckbox(he_fast, he_slow, p_heFast, "fast");
|
|
//DispState(0, p_heValve);
|
|
if (DispPage()) {
|
|
DispValue("%:", p_heLevel, p_heSensState);
|
|
DispValue("high: ", p_heHigh, 0);
|
|
DispValue("low: ", p_heLow, 0);
|
|
HeStateDisp(" ");
|
|
DispValue("mm:", p_heRaw, 0);
|
|
DispValue("empty:", p_heEmpty, 0);
|
|
DispValue("full:", p_heFull, 0);
|
|
DispButton(2, m_he, he_more, "back");
|
|
} else {
|
|
//DispState(0, p_heMeas);
|
|
if (heAvailable == 1) {
|
|
DispText("He level/%");
|
|
DispBigValue(p_heLevel, p_heSensState); // He level
|
|
if (heExtAvailable == 1 && heExtState[0] != he_disabled) {
|
|
DispLargeValue("v", HeValueNr(0), HeStateNr(0));
|
|
}
|
|
DispButton(3, m_he, he_more, "more");
|
|
if (heFast) {
|
|
DispButton(2, m_he, he_slow, "slow");
|
|
} else {
|
|
DispButton(2, m_he, he_fast, "fast");
|
|
}
|
|
}
|
|
HeStateDisp("");
|
|
if (heValve == valve_on) {
|
|
DispButton(5, m_he, he_watch, "watch");
|
|
} else if (heValve != no_valve) {
|
|
if (heAuto) {
|
|
DispButton(5, m_he, he_off, "off");
|
|
} else {
|
|
DispButton(5, m_he, he_watch, "watch");
|
|
}
|
|
DispButton(4, m_he, he_fill, "fill");
|
|
}
|
|
}
|
|
DispButton(0, m_menu, m_menu, "menu");
|
|
DispButton(1, m_menu, m_home, "home");
|
|
}
|
|
|
|
void HeEndMeas() {
|
|
if (HEDEBUG) {Serial.print(heChannel); if (heMeas == 2) Serial.println(" HeEndChk"); else Serial.println(" HeEndMeas"); }
|
|
// switch off current
|
|
digitalWrite(io_lev_enable, LOW);
|
|
pinMode(io_lev_enable, OUTPUT);
|
|
analogWrite(io_lev_current, 0);
|
|
digitalWrite(io_lev_boost, HIGH); // 48 V booster inactive
|
|
if (HeGetState(heChannel) != he_disabled) {
|
|
if (HEDEBUG) {
|
|
Serial.print(heChannel); Serial.print(" state "); Serial.println(heIntState);
|
|
}
|
|
// saving result
|
|
HeSetState(heChannel, heIntState);
|
|
if (heChannel >= 0 && heChannel <= 6) {
|
|
ARRAY(heMinLev,heChannel) = heMinLevel;
|
|
}
|
|
if (heIntState == he_sens_ok) {
|
|
if (heMeas == 1) HeSetLev(heChannel, heIntLevel);
|
|
} else if (heIntState == he_no_sens) {
|
|
HeSetLev(heChannel, 0);
|
|
}
|
|
}
|
|
ParSet(heMeas, 0); // off
|
|
|
|
if (heValve == valve_on) {
|
|
if (heLevel > heHigh && heCommand != he_manual) {
|
|
HeCmd(he_stop);
|
|
}
|
|
} else {
|
|
if (heLevel < heLow && heAuto && heSensState == he_sens_ok) {
|
|
HeCmd(he_fill);
|
|
}
|
|
}
|
|
}
|
|
|
|
void HeSelect() {
|
|
byte pin;
|
|
|
|
if (heChannel == 6) {
|
|
heIntDrive = heDrive;
|
|
res_to_len = 1e7 / heWiRes; // result is in 1e-5 m (+5), input in 1e-2 V (-2), heWiRes in Ohm/m, heCurrent in 1e-4 A (+4)
|
|
mm_to_percent = 100.0 / (heEmpty - heFull);
|
|
empty_10um = 100 * heEmpty;
|
|
digitalWrite(io_he_select, LOW);
|
|
} else {
|
|
heIntDrive = heExtDrive;
|
|
res_to_len = 1e7 / heExtWiRes;
|
|
mm_to_percent = 100.0 / (heExtEmpty - heExtFull);
|
|
empty_10um = 100 * heExtEmpty;
|
|
digitalWrite(io_he_select, HIGH);
|
|
}
|
|
if (heExtAvailable > 1) {
|
|
for (pin = 0; pin < 6; pin++) {
|
|
digitalWrite(io_ext1 + pin, pin != heChannel);
|
|
}
|
|
}
|
|
}
|
|
|
|
void HeHandler() {
|
|
static ulong last = 0;
|
|
static ulong lastChk = -3600000;
|
|
static long sumc = 0;
|
|
static long sump = 0;
|
|
static long summ = 0;
|
|
static int cnt = 0;
|
|
static long lastLevels[4];
|
|
long lev; // level in 0.01 mm
|
|
byte i, n;
|
|
long heVplus;
|
|
long expTime;
|
|
static int8_t stab = 0;
|
|
static byte pos;
|
|
static ulong start = 0;
|
|
static byte heNoSensCnt = 0;
|
|
static long hiLev = 0;
|
|
static ulong hiTim = 0;
|
|
static long lev0 = 0;
|
|
static ulong tim0 = 0;
|
|
static long slope;
|
|
static long heDriveCurrent = 0;
|
|
static boolean heWarmCheck = false;
|
|
ulong tim;
|
|
const float sum_to_current = 1235. / 1024 / 100 / 5 / 0.1; // 1235 mV / 1024 adcsteps / 100 sum_counts / 5 Ohm / 0.1 mA
|
|
const float sum_to_volt = 1235. / 1024 / 200 * 105.62 / 5.62 / 10; // 1235 mV / 1024 adcsteps / 200 sum_counts * (105.62 kOhm / 5.62 kOhm) / 10 mV;
|
|
|
|
if (heAvailable != 1 && heExtAvailable == 0) {
|
|
return;
|
|
}
|
|
if (heMeas == 0) { // not measuring/checking
|
|
if (checking) {
|
|
if (heIntState == he_not_yet) {
|
|
ParSet(heMeas, 1);
|
|
started = true;
|
|
return;
|
|
}
|
|
ParSet(heChannel, heChannel + 1);
|
|
if (heChannel > 6) { // this was the last channel
|
|
checking = false;
|
|
return;
|
|
}
|
|
HeLoadChannel();
|
|
if (heIntState == he_disabled) return;
|
|
ParSet(heMeas, 2); // check
|
|
started = true;
|
|
} else if (heChannel <= 6) { // we are finished with measuring a channel
|
|
ParSet(heChannel, heChannel + 1);
|
|
if (heChannel > 6) { // this was the last channel
|
|
return;
|
|
}
|
|
HeLoadChannel();
|
|
if (heIntState == he_disabled) return;
|
|
ParSet(heMeas, 1);
|
|
started = true;
|
|
} else {
|
|
if (heFast) {
|
|
expTime = heFastTime;
|
|
} else {
|
|
expTime = heSlowTime;
|
|
}
|
|
if (expired(&last, 1000 * expTime)) {
|
|
ParSet(heChannel, 0);
|
|
HeLoadChannel();
|
|
if (heIntState == he_disabled) return;
|
|
ParSet(heMeas, 1);
|
|
started = true;
|
|
} else if (expired(&lastChk, 1000 * 2)) { // check period
|
|
checking = true;
|
|
ParSet(heChannel, 0);
|
|
HeLoadChannel();
|
|
if (heIntState == he_disabled) return;
|
|
ParSet(heMeas, 2); // check
|
|
started = true;
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if (heMeas == 2) { // check
|
|
if (started) {
|
|
HeSelect();
|
|
started = false;
|
|
if (HEDEBUG) { Serial.print(heChannel); Serial.print (" start chk, "); };
|
|
sumc = 0;
|
|
summ = 0;
|
|
cnt = 0;
|
|
start = now;
|
|
analogWrite(io_lev_current, 1); // drive current 1 mA
|
|
// switch on current
|
|
pinMode(io_lev_enable, INPUT);
|
|
digitalWrite(io_lev_enable, HIGH); // input pullup
|
|
}
|
|
for (i = 0 ; i < 20; i++) {
|
|
summ += aRead(a_levb_vminus);
|
|
sumc += aRead(a_lev_current);
|
|
}
|
|
cnt += 20;
|
|
if (cnt < 100) return;
|
|
|
|
// cnt == 100
|
|
long cur = sumc * sum_to_current;
|
|
if (heChannel < 6) { // external channels only (vessels)
|
|
summ = summ * ((47.5 + 5.62) / 105.62); // 47.5 + 5.62 instead of 105.62 kOhm
|
|
heCableVolt0 = (summ - sumc) * sum_to_volt * 2; // voltage between vminus and iminus (* 2 because voltages are NOT summed twice)
|
|
}
|
|
if (HEDEBUG) { Serial.print(cur); Serial.print(",");}
|
|
if (cur > 3) { // there is a current
|
|
if (HEDEBUG) Serial.print("sens yes ");
|
|
if (heIntState == he_no_sens) {
|
|
if (HEDEBUG) Serial.print("was no ");
|
|
heIntState = he_not_yet;
|
|
}
|
|
HeEndMeas();
|
|
} else if (time_ge(now, start + 100)) { // no current after 0.1 sec
|
|
if (HEDEBUG) Serial.print("no sens ");
|
|
heIntState = he_no_sens;
|
|
HeEndMeas();
|
|
}
|
|
return;
|
|
}
|
|
if (started) {
|
|
HeSelect();
|
|
started = false;
|
|
if (HEDEBUG) { Serial.print(heChannel); Serial.print (" start he, "); };
|
|
sumc = 0;
|
|
sump = 0;
|
|
summ = 0;
|
|
cnt = 0;
|
|
stab = 0;
|
|
start = now;
|
|
hiLev = 0;
|
|
slope = 0;
|
|
if (heIntState == he_sens_warm) {
|
|
heDriveCurrent = heIntDrive / 3;
|
|
heWarmCheck = true;
|
|
} else {
|
|
heDriveCurrent = heIntDrive;
|
|
heWarmCheck = false;
|
|
}
|
|
analogWrite(io_lev_current, heDriveCurrent);
|
|
// switch on current
|
|
pinMode(io_lev_enable, INPUT);
|
|
digitalWrite(io_lev_enable, HIGH); // input pullup
|
|
for (i = 0; i < 4; i++) {
|
|
ARRAY(lastLevels,i) = undef_mm;
|
|
}
|
|
}
|
|
tim = now;
|
|
if (heChannel < 6) {
|
|
for (i = 0 ; i < 20; i++) {
|
|
sump += aRead(a_levb_vplus);
|
|
summ += aRead(a_levb_vminus);
|
|
sumc += aRead(a_lev_current);
|
|
summ += aRead(a_levb_vminus);
|
|
sump += aRead(a_levb_vplus);
|
|
}
|
|
} else {
|
|
if (heAvailable != 1) { // ext only
|
|
// should not happen, but may be ...
|
|
ParSet(heMeas, 2); // check
|
|
return;
|
|
}
|
|
for (i = 0 ; i < 20; i++) {
|
|
sump += aRead(a_lev_vplus);
|
|
summ += aRead(a_lev_vminus);
|
|
sumc += aRead(a_lev_current);
|
|
summ += aRead(a_lev_vminus);
|
|
sump += aRead(a_lev_vplus);
|
|
}
|
|
}
|
|
tim += (now - tim) / 2;
|
|
cnt += 20;
|
|
if (cnt < 100) return;
|
|
|
|
// cnt == 100
|
|
ParSet(heCurrent, sumc * sum_to_current);
|
|
|
|
if (time_ge(now, start + 500)) { // after 0.5 sec
|
|
if (heCurrent < heDriveCurrent * 5) { // measured current less than 50 % of drive current
|
|
heIntState = he_no_sens;
|
|
heIntLevel = 0;
|
|
HeEndMeas();
|
|
return;
|
|
}
|
|
}
|
|
if (heChannel < 6) {
|
|
if (HEDEBUG && 0) {
|
|
Serial.print("he ");
|
|
Serial.println(heChannel);
|
|
Serial.println(sump);
|
|
Serial.println(summ);
|
|
}
|
|
sump = sump * ((221 + 5.62) / 105.62); // 221 + 5.62 kOhm instead of 100 + 5.62 kOhm
|
|
summ = summ * ((47.5 + 5.62) / 105.62); // 47.5 + 5.62 instead of 105.62 kOhm
|
|
heCableVolt1 = (summ - sumc * 2) * sum_to_volt; // voltage between vminus and iminus (* 2 because sumc is NOT summed twice)
|
|
}
|
|
ParSet(heVolt, (sump - summ) * sum_to_volt);
|
|
heVplus = sump * sum_to_volt;
|
|
if (HEDEBUG && 0) {
|
|
Serial.print("(");
|
|
Serial.print(sump * sum_to_volt);
|
|
Serial.print("-");
|
|
Serial.print(summ * sum_to_volt);
|
|
Serial.print("/");
|
|
Serial.print(heCurrent);
|
|
Serial.print(")");
|
|
}
|
|
/*
|
|
if (heVplus > 2000 && heBooster) { // 20.00 V
|
|
digitalWrite(io_lev_boost, LOW); // 48 V booster active
|
|
} else {
|
|
digitalWrite(io_lev_boost, HIGH); // 48 V booster inactive
|
|
}
|
|
*/
|
|
sumc = 0;
|
|
sump = 0;
|
|
summ = 0;
|
|
cnt = 0;
|
|
lev = heVolt * (res_to_len / heCurrent);
|
|
if (HEDEBUG) {
|
|
//Serial.print("("); Serial.print(heVolt); Serial.print(" "); Serial.print(heWiRes); Serial.print(" "); Serial.print(heCurrent); Serial.print(")");
|
|
//Serial.print(lev, DEC); Serial.print(" ");
|
|
}
|
|
if (lev > hiLev) {
|
|
if (hiLev == 0) {
|
|
lev0 = lev;
|
|
tim0 = tim;
|
|
} else {
|
|
slope = (lev - lev0) * 10 / (tim - tim0);
|
|
}
|
|
hiLev = lev;
|
|
hiTim = tim;
|
|
stab = 0;
|
|
} else if (lev < hiLev + heMeasSpeed * (tim - hiTim) / 10) {// 1/10 = mm / sec * msec / 0.01 mm
|
|
stab++;
|
|
} else if (stab > 0) {
|
|
stab--;
|
|
}
|
|
pos = (pos + 1) % 4;
|
|
ARRAY(lastLevels,pos) = lev;
|
|
if (HEDEBUG && 0) {Serial.print(lev); Serial.print("\n"); }
|
|
if (lev > empty_10um + empty_10um / 33) { // value more than 3% more than empty length:
|
|
heIntState = he_sens_warm;
|
|
if (HEDEBUG) Serial.print("warm");
|
|
HeEndMeas();
|
|
return;
|
|
}
|
|
if (time_ge(now, start + 30000)) { // timeout
|
|
heIntState = he_timeout;
|
|
if (HEDEBUG) Serial.print("tmo");
|
|
HeEndMeas();
|
|
return;
|
|
}
|
|
if (heWarmCheck) {
|
|
heIntState = he_not_yet;
|
|
if (HEDEBUG) Serial.print("not warm");
|
|
HeEndMeas();
|
|
return;
|
|
}
|
|
if (HEDEBUG) { if (stab) {Serial.print(" stab"); Serial.print(stab, DEC);} else {Serial.print("~");} }
|
|
if (stab < 8) return; // not yet finished
|
|
heIntState = he_sens_ok;
|
|
|
|
ParSet(heSlope, slope);
|
|
ParSet(heFirst, lev0 - slope * (tim0 - start) / 10);
|
|
|
|
// finished measuring
|
|
n = 1;
|
|
for (i = 0; i < 4; i++) {
|
|
if (ARRAY(lastLevels,i) != undef_mm) {
|
|
lev += ARRAY(lastLevels,i);
|
|
n++;
|
|
}
|
|
}
|
|
lev /= n; // calculate the mean of up to 5 values
|
|
heIntLevel = (empty_10um - lev) * mm_to_percent; // lev is in 10 um = 0.01 mm, result is in 0.01 %
|
|
ParSet(heRaw, -lev); // negative raw value: while filling, value increases
|
|
if (HEDEBUG) {
|
|
Serial.print("r="); Serial.print(heRaw, DEC); Serial.print(" lev="); Serial.print(heIntLevel, DEC); Serial.print(' '); Serial.println(heMinLevel, DEC);
|
|
}
|
|
|
|
if (heIntLevel < heMinLevel) { // level decrease
|
|
heMinLevel = heIntLevel;
|
|
if (HEDEBUG) {
|
|
Serial.print(now - heLastIncrease, DEC); Serial.print(" ");
|
|
Serial.print(heMinLevel);
|
|
Serial.println(" minlevel\n");
|
|
}
|
|
if ((heFast || heValve == valve_on) && time_ge(now, heLastIncrease + heFastTimeout * 1000)) {
|
|
if (heFast) ParSet(heFast, false);
|
|
if (heCommand != he_manual) {
|
|
if (heValve == valve_on) {
|
|
ParSet(heValve, valve_timeout);
|
|
}
|
|
HeCmd(he_stop); // stop when no substantial increase with heFastTimeout
|
|
}
|
|
}
|
|
} else if (heIntLevel > heMinLevel + heIncreaseTolerance) { // significant level increase
|
|
if (!heFast && heExtAvailable <= 1) {
|
|
ParSet(heFast, true);
|
|
}
|
|
heMinLevel = heIntLevel;
|
|
if (HEDEBUG) Serial.println("last increase now 3");
|
|
heLastIncrease = now;
|
|
if (HEDEBUG) {
|
|
Serial.print(heMinLevel);
|
|
Serial.println(" he increase\n");
|
|
}
|
|
}
|
|
HeEndMeas();
|
|
}
|
|
|
|
void HeSetStart() {
|
|
// n2start = now;
|
|
// n2StartThreshold = n2lower - 500;
|
|
// if (n2StartThreshold < n2threshold) {
|
|
// n2StartThreshold = n2threshold;
|
|
// }
|
|
}
|
|
|
|
void HeRemoteCmd(byte cmd) {
|
|
if (heAvailable == 1 && heSensState > he_sens_warm) {
|
|
if (cmd == he_fill || cmd == he_watch) return;
|
|
}
|
|
if (heValve >= valve_timeout) {
|
|
ParSet(heValve, valve_off);
|
|
}
|
|
HeCmd(cmd);
|
|
}
|
|
|
|
void HeStopFill() {
|
|
ValveSet(io_he_valve, LOW);
|
|
if (heValve == valve_on) {
|
|
ParSet(heValve, valve_off);
|
|
}
|
|
}
|
|
|
|
void HeCmd(byte cmd) {
|
|
switch (cmd) {
|
|
case he_stop:
|
|
HeStopFill();
|
|
ParSet(heFast, false);
|
|
break;
|
|
case he_fill:
|
|
heLastIncrease = now;
|
|
ParSet(heFast, true);
|
|
ParSet(heAuto, true);
|
|
if (heValve != no_valve && (heAvailable != 1 || heLevel < heHigh)) {
|
|
if (heValve != valve_on) {
|
|
ValveSet(io_he_valve, HIGH);
|
|
}
|
|
ParSet(heValve, valve_on);
|
|
if (HEDEBUG) Serial.println("valve on");
|
|
HeSetStart();
|
|
} else if (HEDEBUG) {
|
|
Serial.println(heValve);
|
|
Serial.println(heLevel);
|
|
}
|
|
break;
|
|
case he_watch:
|
|
HeStopFill();
|
|
ParSet(heFast, false);
|
|
ParSet(heAuto, true);
|
|
break;
|
|
case he_off:
|
|
HeStopFill();
|
|
ParSet(heFast, false);
|
|
ParSet(heAuto, false);
|
|
break;
|
|
case he_fast:
|
|
ParSet(heFast, true);
|
|
if (HEDEBUG) Serial.println("last increase now 4");
|
|
heLastIncrease = now;
|
|
break;
|
|
case he_slow:
|
|
ParSet(heFast, false);
|
|
break;
|
|
case he_more:
|
|
DispNextPage(2);
|
|
break;
|
|
case he_manual:
|
|
if (heValve != no_valve) {
|
|
if (heValve != valve_on) {
|
|
ValveSet(io_he_valve, HIGH);
|
|
}
|
|
ParSet(heValve, valve_on);
|
|
if (HEDEBUG) Serial.println("valve on");
|
|
};
|
|
break;
|
|
}
|
|
}
|
|
|
|
void HeSetFast() {
|
|
HeCmd(he_fast);
|
|
}
|
|
|
|
void HeValveState(boolean ok) {
|
|
if (ok) {
|
|
if (heValve == no_valve) {
|
|
ParSet(heValve, valve_off);
|
|
}
|
|
} else {
|
|
ParSet(heValve, no_valve);
|
|
}
|
|
}
|
|
|
|
boolean HeStateDisp(const char *title) {
|
|
const char *text;
|
|
static char old[32];
|
|
if (heValve == valve_on) {
|
|
if (heMeas && heChannel == 6) {
|
|
text = "~fill meas";
|
|
} else if (heCommand == he_manual) {
|
|
text = "manual on";
|
|
} else {
|
|
text = "~filling";
|
|
}
|
|
} else if (heAuto && heValve == valve_off) {
|
|
if (heMeas == 1 && heChannel == 6) {
|
|
text = "watc.meas";
|
|
} else {
|
|
text = "watching";
|
|
}
|
|
} else if (heAvailable == 2) {
|
|
text = "fill off";
|
|
} else if (heFast) {
|
|
if (heMeas == 1 && heChannel == 6) {
|
|
text = "fast meas";
|
|
} else {
|
|
text = "fast";
|
|
}
|
|
} else if (heMeas == 1 && heChannel == 6) {
|
|
text = "meas";
|
|
} else {
|
|
text = " ";
|
|
}
|
|
/*
|
|
if (!textequal(old, text)) {
|
|
textcopy(old, sizeof old, text);
|
|
Serial.print(text); Serial.println("<HETEXT");
|
|
}
|
|
*/
|
|
DispTextRow(fmt_lsmall, title, text);
|
|
}
|
|
|
|
void HeStore(EeMode mode) {
|
|
// store parameters for external device
|
|
byte channel, usedMask;
|
|
if (mode == ee_write) {
|
|
usedMask = 0;
|
|
for (channel = 0; channel <= 6; channel++) {
|
|
if (HeGetState(channel) != he_disabled) bitSet(usedMask, channel);
|
|
}
|
|
}
|
|
eeStore((void *)&heExtWiRes, sizeof heExtWiRes, mode);
|
|
eeStore((void *)&heExtDrive, sizeof heExtDrive, mode);
|
|
eeStore((void *)&heExtEmpty, sizeof heExtEmpty, mode);
|
|
eeStore((void *)&heExtFull, sizeof heExtFull, mode);
|
|
eeStore((void *)&usedMask, sizeof usedMask, mode);
|
|
if (mode == ee_read) {
|
|
Serial.print("enabled he channels:");
|
|
for (channel = 0; channel <= 6; channel++) {
|
|
if (bitRead(usedMask, channel)) {
|
|
HeSetState(channel, he_not_yet);
|
|
Serial.print(" ");Serial.print(channel, DEC);
|
|
} else {
|
|
HeSetState(channel, he_disabled);
|
|
}
|
|
}
|
|
Serial.print("\nwire res."); Serial.print(heExtWiRes);
|
|
Serial.print(" Ohm/m\ndrive current "); Serial.print(heExtDrive);
|
|
Serial.print(" mA\nempty at "); Serial.print(heExtEmpty);
|
|
Serial.print(" mm from top\nfull at "); Serial.print(heExtFull);
|
|
Serial.print(" mm from top\n");
|
|
dispEco = 35;
|
|
// default for vessels
|
|
ParSet(heFast, 0);
|
|
ParSet(heLow, 0);
|
|
ParSet(heSlowTime, 1800);
|
|
//ParSet(heIncreaseTolerance, 99999);
|
|
}
|
|
}
|
|
|
|
void HeConfig(byte avail, byte cur, int wires, int empty, int full) {
|
|
if (HEDEBUG) Serial.println("HeConfig");
|
|
ParSet(heAvailable, avail);
|
|
if (avail) {
|
|
ParSet(heDrive, cur);
|
|
ParSet(heWiRes, wires);
|
|
ParSet(heEmpty, empty);
|
|
ParSet(heFull, full);
|
|
if (heExtAvailable == 1) {
|
|
HeSetState(0, he_not_yet);
|
|
}
|
|
/*
|
|
if ((long)wires * empty * cur > 22000000) {
|
|
ParSet(heBooster, 1);
|
|
} else {
|
|
ParSet(heBooster, 0);
|
|
}
|
|
*/
|
|
}
|
|
}
|