281 lines
7.2 KiB
C++
281 lines
7.2 KiB
C++
#include "valve.h"
|
|
|
|
#define N2DEBUG 0
|
|
|
|
//--- Liquid Nitrogen
|
|
PAR_LONG n2upper = 0;
|
|
PAR_LONG n2lower = 0;
|
|
PAR_LONG n2threshold = 9000;
|
|
PAR_LONG n2tubecooldelay = 300;
|
|
PAR_LONG n2filltimeout = 1800;
|
|
PAR_BYTE n2fault = 0;
|
|
#define n2_sens_text F(" |no sensor|sns.short|sns.upside dn|sns. warm|empty")
|
|
enum {n2_sens_ok, n2_no_sensor, n2_sensor_short, n2_upside_down, n2_sensor_warm, n2_empty};
|
|
|
|
PAR_BYTE n2valve = 0;
|
|
PAR_BYTE n2auto = 1; // 0: off, 1: auto fill
|
|
PAR_BYTE n2command = 0;
|
|
#define n2_cmd_text F("stop|fill|off|watch")
|
|
enum {n2_stop=0, n2_fill, n2_off, n2_watch}; // commands
|
|
|
|
long n2start;
|
|
long n2StartThreshold = 0; // threshold to be reached within n2tubecooldelay after start
|
|
|
|
void N2Pars() {
|
|
ParEnum("nav", n2Available, F("no|yes|ext"));
|
|
ParFixed("nu", n2upper, 2);
|
|
ParFixed("nl", n2lower, 2);
|
|
ParFixed("nth", n2threshold, 2);
|
|
ParFixed("ntc", n2tubecooldelay, 0);
|
|
ParFixed("ntm", n2filltimeout, 0);
|
|
ParEnum("ns", n2fault, n2_sens_text);
|
|
ParEnum("na", n2auto, F("off|auto"));
|
|
ParEnum("nv", n2valve, valve_text);
|
|
if (ParEnum("nc", n2command, n2_cmd_text) == par_command) {
|
|
N2RemoteCmd(n2command);
|
|
}
|
|
}
|
|
|
|
boolean N2Shown() {
|
|
return n2Available; // || n2valve != no_valve;
|
|
}
|
|
|
|
boolean N2DispShort() {
|
|
N2StateDisp("LN2 ");
|
|
return n2valve == valve_on;
|
|
}
|
|
|
|
void N2Buttons(byte top) {
|
|
byte codebase = m_n2 * 16;
|
|
|
|
if (!n2Available) return;
|
|
DispButton(top, m_menu, m_n2, "*LN2");
|
|
if (n2valve == valve_on) {
|
|
DispButton(top - 2, m_n2, n2_watch, "-watch");
|
|
} else if (n2valve != no_valve) {
|
|
if (n2auto) {
|
|
DispButton(top - 2, m_n2, n2_off, "-off");
|
|
} else {
|
|
DispButton(top - 2, m_n2, n2_watch, "-watch");
|
|
}
|
|
DispButton(top - 4, m_n2, n2_fill, "-fill");
|
|
}
|
|
}
|
|
|
|
void N2Disp() {
|
|
byte codebase = m_n2 * 16;
|
|
|
|
if (n2Available == 1) {
|
|
DispText("N2 upper/K");
|
|
DispValue(0, p_n2upper, 0); // upper n2 sensor
|
|
DispText("N2 lower/K");
|
|
DispValue(0, p_n2lower, 0); // lower n2 sensor
|
|
}
|
|
N2StateDisp("");
|
|
//DispState(0, p_n2fault); // sensor state
|
|
//DispState(0, p_n2valve); // valve state
|
|
if (n2valve == valve_on) {
|
|
DispButton(3, m_n2, n2_stop, "watch");
|
|
} else if (n2valve != no_valve) {
|
|
if (n2auto) {
|
|
DispButton(3, m_n2, n2_off, "off");
|
|
} else {
|
|
DispButton(3, m_n2, n2_watch, "watch");
|
|
}
|
|
DispButton(2, m_n2, n2_fill, "fill");
|
|
}
|
|
DispButton(0, m_menu, m_menu, "menu");
|
|
DispButton(1, m_menu, m_home, "home");
|
|
}
|
|
|
|
const long n2_fact = 1024L * 5000 / 1235; // 5 V (excit. voltage), 1.235 V (analog reference)
|
|
const long n2_res = 6200; // 62 Ohm
|
|
|
|
void N2Handler() {
|
|
static long sumu = 0, suml = 0;
|
|
static int cnt = 0;
|
|
static ulong last;
|
|
const int8_t cond_off = -3; // -number of n2upper values below threshold
|
|
const int8_t cond_on = 20; // number of n2lower values above threshold
|
|
static int8_t cond = 0;
|
|
long t;
|
|
byte state;
|
|
|
|
if (n2Available != 1) return;
|
|
sumu += aRead(a_n2_upper);
|
|
suml += aRead(a_n2_lower);
|
|
cnt++;
|
|
if (expired(&last, 500) || cnt >= 400) {
|
|
state = n2_sens_ok;
|
|
if (sumu >= 1023L * cnt) {
|
|
state = n2_sensor_short;
|
|
ParSet(n2upper, 0);
|
|
} else {
|
|
if (sumu == 0) {
|
|
sumu = 1;
|
|
}
|
|
t = (n2_res * n2_fact * 25L / (sumu * 100 / cnt) - n2_res / 4) + 2680; // rough formula for pt1000: R / Ohm * 0.25 K + 26.8 K
|
|
if (t > 99990) {
|
|
t = 99990;
|
|
}
|
|
ParSet(n2upper, t);
|
|
}
|
|
if (suml >= 1023L * cnt) {
|
|
state = n2_sensor_short;
|
|
ParSet(n2lower, 0);
|
|
} else {
|
|
if (suml == 0) {
|
|
suml = 1;
|
|
}
|
|
t = (n2_res * n2_fact * 25L / (suml * 100 / cnt) - n2_res / 4) + 2680; // rough formula for pt1000: R / Ohm * 0.25 K + 26.8 K
|
|
if (t > 99990) {
|
|
t = 99990;
|
|
}
|
|
ParSet(n2lower, t);
|
|
}
|
|
cnt = 0;
|
|
sumu = 0;
|
|
suml = 0;
|
|
if (state == n2_sens_ok) {
|
|
if (n2lower == 99990 || n2upper == 99990) {
|
|
state = n2_no_sensor;
|
|
} else if (n2lower > n2upper + n2upper / 10) {
|
|
state = n2_upside_down;
|
|
} else if (n2lower > 20000) {
|
|
state = n2_sensor_warm;
|
|
// ParSet(n2auto, false);
|
|
}
|
|
}
|
|
ParSet(n2fault, state);
|
|
if (n2upper < n2threshold) { // condition for stopping
|
|
if (cond > cond_off) cond--;
|
|
} else if (n2lower > n2threshold) { // condition for fill start
|
|
if (cond < cond_on) cond++;
|
|
} else {
|
|
cond = 0;
|
|
}
|
|
if (n2valve == valve_on) {
|
|
if (cond <= cond_off) { // n2upper was a couple of times below threshold
|
|
N2StopFill();
|
|
cond = 0;
|
|
}
|
|
if (time_ge(now, n2start + n2filltimeout * 1000)) {
|
|
Serial.print("filltmo");
|
|
N2Cmd(n2_stop);
|
|
ParSet(n2valve, valve_timeout);
|
|
Serial.println(n2valve);
|
|
} else if (time_ge(now, n2start + n2tubecooldelay * 1000)) {
|
|
if (n2lower > n2StartThreshold) {
|
|
Serial.print("startmo");
|
|
N2Cmd(n2_stop);
|
|
ParSet(n2valve, valve_timeout1);
|
|
Serial.println(n2valve);
|
|
} else if (n2StartThreshold > n2threshold) { // still cooling lower sensor
|
|
N2SetStart();
|
|
}
|
|
}
|
|
} else if (cond >= cond_on) { // n2lower was a couple of times above threshold
|
|
if (n2valve == valve_off && n2auto && (n2fault == n2_sens_ok || n2fault == n2_empty)) {
|
|
N2Cmd(n2_fill);
|
|
cond = 0;
|
|
} else if (n2fault == n2_sens_ok) {
|
|
ParSet(n2fault, n2_empty);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void N2SetStart() {
|
|
n2start = now;
|
|
n2StartThreshold = n2lower - 500;
|
|
if (n2StartThreshold < n2threshold) {
|
|
n2StartThreshold = n2threshold;
|
|
}
|
|
}
|
|
|
|
void N2RemoteCmd(byte cmd) {
|
|
if (n2Available == 1 && n2fault >= n2_no_sensor && n2fault <= n2_upside_down) {
|
|
if (cmd == n2_fill || cmd == n2_watch) return;
|
|
}
|
|
N2Cmd(cmd);
|
|
}
|
|
|
|
void N2StopFill() {
|
|
ValveSet(io_n2_valve, LOW);
|
|
if (n2valve == valve_on) {
|
|
ParSet(n2valve, valve_off);
|
|
}
|
|
}
|
|
|
|
void N2Cmd(byte cmd) {
|
|
if (n2valve >= valve_timeout) {
|
|
N2StopFill();
|
|
}
|
|
switch (cmd) {
|
|
case n2_stop:
|
|
N2StopFill();
|
|
break;
|
|
case n2_watch:
|
|
N2StopFill();
|
|
ParSet(n2auto, true);
|
|
break;
|
|
case n2_fill:
|
|
ParSet(n2auto, true);
|
|
if (N2DEBUG) Serial.println("fill");
|
|
if (n2valve != no_valve && (n2Available != 1 || n2upper > n2threshold)) {
|
|
if (n2valve != valve_on) {
|
|
ValveSet(io_n2_valve, HIGH);
|
|
}
|
|
ParSet(n2valve, valve_on);
|
|
if (N2DEBUG) Serial.println("valve on");
|
|
N2SetStart();
|
|
} else if (N2DEBUG) {
|
|
Serial.println(n2valve);
|
|
Serial.println(n2upper);
|
|
Serial.println(n2threshold);
|
|
}
|
|
break;
|
|
case n2_off:
|
|
N2StopFill();
|
|
ParSet(n2auto, false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void N2ValveState(boolean ok) {
|
|
if (ok) {
|
|
if (n2valve == no_valve) {
|
|
ParSet(n2valve, valve_off);
|
|
N2StopFill();
|
|
}
|
|
} else {
|
|
N2StopFill();
|
|
ParSet(n2valve, no_valve);
|
|
}
|
|
}
|
|
|
|
void N2StateDisp(const char *title) {
|
|
const char *text;
|
|
|
|
if (n2valve == valve_on) {
|
|
if (n2fault == n2_no_sensor) {
|
|
text = "~fill no s.";
|
|
} else {
|
|
text = "~filling";
|
|
}
|
|
} else if (n2valve == valve_timeout) {
|
|
text = "timeout";
|
|
} else if (n2valve == valve_timeout1) {
|
|
text = "tmoStart";
|
|
} else if (n2fault) {
|
|
text = ParFmt(p_n2fault);
|
|
} else if (n2auto && n2valve == valve_off) {
|
|
text = "watching";
|
|
} else if (n2valve == no_valve) {
|
|
text = "no valve";
|
|
} else {
|
|
text = "off";
|
|
}
|
|
DispTextRow(fmt_lsmall, title, text);
|
|
}
|