834 lines
22 KiB
C++
834 lines
22 KiB
C++
#include <avr/eeprom.h>
|
|
//#include "utils.h"
|
|
#include "EEPROM.h"
|
|
|
|
enum {standard_cfg, argon_cfg, multihe_cfg, jtext_cfg};
|
|
#define config_cfg_text "std|argon|multiHe|jtext"
|
|
|
|
PAR_LONG codeA = 0;
|
|
PAR_LONG codeB = 0;
|
|
PAR_BYTE codeAbad = 1;
|
|
PAR_BYTE codeBbad = 1;
|
|
PAR_TEXT configDevice[16] = "none";
|
|
PAR_LONG configVersion = 1;
|
|
PAR_BYTE configSpecial = 0;
|
|
PAR_BYTE configDeviceState = 0;
|
|
enum {config_local, config_remote, config_loading, config_by_code, config_by_touch};
|
|
#define config_state_text "local|remote|loading|by_code|by_touch"
|
|
char configItem[64] = "";
|
|
char configTitle[16] = "init";
|
|
ulong loadingUntil = 0; // show loading screen until ...
|
|
|
|
#if (RAMTEST)
|
|
PAR_LONG freeRam = 0;
|
|
#endif
|
|
word caladr = 0; // address for storing level calibration
|
|
|
|
enum {config_noflow, config_flow, config_non2, config_n2, config_nohe, config_select};
|
|
// coding resistor values.
|
|
// the values are choosen in a manner to distinguish between different values
|
|
// with a tolerance dependent on the measurement precision
|
|
// the effectively used values are between 220 and 47k, because these values are
|
|
// sold in an assortment (distrelec 728001)
|
|
enum {R_MIN, R_100, R_220, R_330, R_470, R_680, R_820,
|
|
R_1k, R_1k2, R_1k5, R_1k8, R_2k2, R_2k7, R_3k3, R_3k9, R_4k7, R_5k6, R_6k8, R_8k2,
|
|
R_10k, R_12k, R_15k, R_18k, R_22k, R_27k, R_33k, R_39k, R_47k, R_56k, R_68k, R_82k,
|
|
/* R_100k, R_120k, R_150k, */ R_MAX, R_INSTABLE};
|
|
|
|
static const long res_list[] PROGMEM = {0, 100, 220, 330, 470, 680, 820,
|
|
1000, 1200, 1500, 1800, 2200, 2700, 3300, 3900, 4700, 5600, 6800, 8200,
|
|
10000, 12000, 15000, 18000, 22000, 27000, 33000, 39000, 47000, 56000, 68000, 82000,
|
|
/* 100000,120000, 150000, */ 999999, 888888};
|
|
|
|
enum {HE = 1, N2 = 2, NV = 4, N2V = 8, HEV = 16, VALVEUNIT = 32};
|
|
enum {AMI20= 1, AMI38, AMI52, OXF38, OXF40, OXF52};
|
|
enum {AMI_heCur = 75, AMI_heWiRes = 460, OXF_heCur = 130, OXF_heWiRes = 166};
|
|
enum {EEPROM_version = 8, configMaxDev = 64};
|
|
|
|
static struct deviceTable_s {
|
|
char name[8];
|
|
byte rescode[2];
|
|
byte opt;
|
|
byte heCur; // current in mA
|
|
int heWiRes; // wire resistivity Ohm/m
|
|
int heEmpty; // warm length at 0 %
|
|
int heFull; // warm length at 100 %
|
|
} deviceTable[configMaxDev];
|
|
|
|
const long code_max = 10 * 1024L; // 10 times max. adc
|
|
const long code_res = 20000; // reference resistor
|
|
|
|
byte configNdevices = 0;
|
|
byte configItemIndex = 0;
|
|
byte configDevIdx = 0;
|
|
byte devno0 = 255;
|
|
|
|
enum {device_other = 250};
|
|
|
|
struct config_stat_s {
|
|
byte stableCode;
|
|
byte code;
|
|
word v0;
|
|
word v1;
|
|
word v2;
|
|
word ltcnt;
|
|
word eqcnt;
|
|
word gtcnt;
|
|
word cnt;
|
|
int8_t pos; // -1: decrease code, 1: increase code
|
|
};
|
|
|
|
void ConfigPars() {
|
|
ParFixed("cvs", configVersion, 0);
|
|
ParText("csf", configSoft, false);
|
|
ParText("cid", configIdn, false);
|
|
ParFixed("cda", codeA, 0);
|
|
ParFixed("cdb", codeB, 0);
|
|
ParEnum("cba", codeAbad, F("stable|instable"));
|
|
ParEnum("cbb", codeBbad, F("stable|instable"));
|
|
#if (RAMTEST)
|
|
ParFixed("cfr", freeRam, 0);
|
|
#endif
|
|
if (ParEnum("csp", configSpecial, F(config_cfg_text)) == par_command) {
|
|
ConfigSave();
|
|
setup();
|
|
return;
|
|
}
|
|
if (ParText("cdv", configDevice, true) == par_command) {
|
|
if (configSpecial == 0) {
|
|
if (configDevice[0] == '*' && configDevice[1] == 0) {
|
|
devno0 = 255; // force code detection
|
|
} else {
|
|
textcopy(configTitle, sizeof configTitle, configDevice);
|
|
if (screen != m_instr) {
|
|
screen = m_loading;
|
|
loadingUntil = now + 5000;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (ParEnum("cds", configDeviceState, F(config_state_text)) == par_command) {
|
|
if (configDeviceState == config_remote) {
|
|
if (screen != m_instr) screen = m_home;
|
|
textcopy(configTitle, sizeof configTitle, configDevice);
|
|
}
|
|
}
|
|
if (ParText("c", configItem, false) == par_command) {
|
|
ConfigItem();
|
|
}
|
|
}
|
|
|
|
void ConfigDispShort(const char *text) {
|
|
DispText2(configTitle, text);
|
|
DispLine();
|
|
}
|
|
|
|
void ConfigDisp() {
|
|
if (configSpecial == standard_cfg) {
|
|
DispValue("A: ", p_codeA, p_codeAbad);
|
|
DispValue("B: ", p_codeB, p_codeBbad);
|
|
DispValue("n.v.:", p_flowAvailable, 0);
|
|
DispValue("LHe: ", p_heAvailable, 0);
|
|
DispValue("LN2:", p_n2Available, 0);
|
|
#if (RAMTEST)
|
|
DispValue("mem", p_freeRam, 0);
|
|
#endif
|
|
DispButton(2, m_menu, m_device, "device");
|
|
} else if (extension == valve_extension) {
|
|
DispText2("valve_ext", configSoft);
|
|
} else if (extension == he_extension) {
|
|
DispText2("he_ext", configSoft);
|
|
}
|
|
DispButton(0, m_menu, m_menu, "menu");
|
|
DispButton(1, m_menu, m_home, "home");
|
|
}
|
|
|
|
void ConfigLoadingDisp() {
|
|
ConfigDispShort("load");
|
|
if (time_ge(now, loadingUntil)) {
|
|
screen = m_home;
|
|
}
|
|
}
|
|
|
|
void ConfigInit() {
|
|
long value;
|
|
byte l;
|
|
|
|
byte eeversion = EEPROM.read(0);
|
|
eeSetAdr(1);
|
|
if (eeversion > EEPROM_version || eeversion < 5) {
|
|
configNdevices = 1;
|
|
textcopy(deviceTable[0].name, sizeof (deviceTable[0].name), "none");
|
|
deviceTable[0].opt = 0;
|
|
deviceTable[0].rescode[0] = R_MAX;
|
|
deviceTable[0].rescode[1] = R_MAX;
|
|
Serial.print("new EEPROM version:");
|
|
Serial.println(EEPROM_version);
|
|
ConfigSave();
|
|
}
|
|
EESTORE(value, ee_read);
|
|
ParSet(configVersion, value);
|
|
extension = no_extension;
|
|
if (eeversion == 5) {
|
|
ParSet(configSpecial, standard_cfg);
|
|
} else {
|
|
EESTORE(configSpecial, ee_read);
|
|
l = textcopyuntil((char *)configIdn, sizeof configIdn, configIdn, '.'); // find dot
|
|
if (l < sizeof configIdn - 2) {
|
|
#if PARCHECK == 0
|
|
ARRAY(configIdn,l) = '.'; // exception of PARCHECK, no complain about usage outside ParSet
|
|
#endif
|
|
l++;
|
|
l = textcopy((char *)configIdn + l, sizeof configIdn - l, ParFmt(p_configSpecial));
|
|
}
|
|
}
|
|
if (configSpecial != 0) {
|
|
configNdevices = 0;
|
|
ConfigSpecial(ee_read);
|
|
textcopy(configTitle, sizeof configTitle, configDevice);
|
|
Serial.print("load ");
|
|
Serial.print(EEPROM_version, DEC);
|
|
Serial.print(" ");
|
|
Serial.println(configTitle);
|
|
return;
|
|
}
|
|
EESTORE(configNdevices, ee_read);
|
|
Serial.print("load ");
|
|
Serial.print(EEPROM_version, DEC);
|
|
Serial.print(".");
|
|
Serial.println(configVersion);
|
|
eeStore((void *)&deviceTable, (sizeof deviceTable[0]) * configNdevices, ee_read);
|
|
EESTORE(heExtAvailable, ee_read);
|
|
if (heExtAvailable != 1 || EEPROM_version < 7) {
|
|
ParSet(heExtAvailable, 0);
|
|
}
|
|
if (EEPROM_version > 7) {
|
|
InstrStore(ee_read);
|
|
}
|
|
}
|
|
|
|
boolean ConfigCrit(word good, word total) {
|
|
// statistics: assume that more than 50 % of the samples are good in average
|
|
// the probability of a false positive should be less than 1e-10
|
|
// formula: m > n * (1 - p) + sqrt(- 2 * n * ln(1e-10) * p * (1-p)), m = good, n = total, p = 0.5
|
|
// or (2 * m - n)^2 > 2 * n * 23.026
|
|
ulong i;
|
|
|
|
if (good <= total / 2) return false; // avoid underflow
|
|
i = 2 * good - total; // 2 * (m - n * (1 - p))
|
|
if (i * i > 46L * total) { // 46 ~= 2^2 * 2 * -ln(1e-10) * 0.5 * 0.5
|
|
//Serial.print("C"); Serial.print(good); Serial.print("/"); Serial.println(total);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void ConfigStat(struct config_stat_s *s, int8_t pos, byte weight) {
|
|
byte j;
|
|
|
|
s->pos = 0;
|
|
if (s->cnt > 10000) {
|
|
/*
|
|
Serial.print("lt "); Serial.print(s->ltcnt);
|
|
Serial.print(" eq "); Serial.print(s->eqcnt);
|
|
Serial.print(" gt "); Serial.print(s->gtcnt);
|
|
Serial.print(" CODE "); Serial.println(s->code);
|
|
*/
|
|
s->cnt = 0;
|
|
s->ltcnt = 0;
|
|
s->eqcnt = 0;
|
|
s->gtcnt = 0;
|
|
s->stableCode = R_INSTABLE;
|
|
}
|
|
s->cnt += weight;
|
|
if (pos < 0) {
|
|
s->ltcnt += weight;
|
|
if (ConfigCrit(s->ltcnt / 10, s->cnt / 10)) {
|
|
/*
|
|
Serial.print("LT "); Serial.print(s->ltcnt);
|
|
Serial.print(" eq "); Serial.print(s->eqcnt);
|
|
Serial.print(" gt "); Serial.print(s->gtcnt);
|
|
Serial.print(" code "); Serial.println(s->code);
|
|
*/
|
|
s->ltcnt = 0;
|
|
s->eqcnt = weight;
|
|
s->gtcnt = 0;
|
|
s->cnt = weight;
|
|
if (s->code == 1) {
|
|
s->stableCode = 0;
|
|
} else {
|
|
s->stableCode = R_INSTABLE;
|
|
s->pos = -1;
|
|
}
|
|
}
|
|
} else if (pos > 0) {
|
|
s->gtcnt += weight;
|
|
if (ConfigCrit(s->gtcnt / 10, s->cnt / 10)) {
|
|
/*
|
|
Serial.print("lt "); Serial.print(s->ltcnt);
|
|
Serial.print(" eq "); Serial.print(s->eqcnt);
|
|
Serial.print(" GT "); Serial.print(s->gtcnt);
|
|
Serial.print(" code "); Serial.println(s->code);
|
|
*/
|
|
s->ltcnt = 0;
|
|
s->eqcnt = weight;
|
|
s->gtcnt = 0;
|
|
s->cnt = weight;
|
|
if (s->code == R_MAX - 1) {
|
|
s->stableCode = R_MAX;
|
|
} else {
|
|
s->stableCode = R_INSTABLE;
|
|
s->pos = 1;
|
|
}
|
|
}
|
|
} else {
|
|
s->eqcnt += weight;
|
|
if (ConfigCrit(s->eqcnt / 10, s->cnt / 10)) {
|
|
if (s->code != s->stableCode) {
|
|
s->stableCode = s->code;
|
|
/*
|
|
Serial.print("lt "); Serial.print(s->ltcnt);
|
|
Serial.print(" EQ "); Serial.print(s->eqcnt);
|
|
Serial.print(" gt "); Serial.print(s->gtcnt);
|
|
Serial.print(" code "); Serial.println(s->code);
|
|
*/
|
|
}
|
|
s->ltcnt = 0;
|
|
s->eqcnt = weight;
|
|
s->gtcnt = 0;
|
|
s->cnt = weight;
|
|
}
|
|
}
|
|
}
|
|
|
|
long ConfigResFromCode(byte code) {
|
|
const long *rp = res_list;
|
|
return pgm_read_dword(&rp[code]);
|
|
}
|
|
|
|
word ConfigAdcFromCode(byte code) {
|
|
long r = ConfigResFromCode(code);
|
|
if (r < 2000000000 / code_max) { // avoid overflow
|
|
return code_max * r / (r + code_res);
|
|
} else { // might not be needed
|
|
return r / ((r + code_res) / code_max);
|
|
}
|
|
}
|
|
|
|
long ConfigResFromAdc(word adc) {
|
|
if (adc == 0) return 0;
|
|
return code_res * (long)adc / (1024L - adc);
|
|
}
|
|
|
|
byte ConfigGetCode(byte chan, word adc) {
|
|
byte frac;
|
|
byte w;
|
|
static struct config_stat_s config_stat[2] = {{R_INSTABLE,1,0,1,2},{R_INSTABLE,1,0,1,2}};
|
|
int code;
|
|
int8_t pos;
|
|
struct config_stat_s *s;
|
|
|
|
s = &ARRAY(config_stat, chan);
|
|
adc *= 10;
|
|
|
|
if (adc < s->v1) {
|
|
pos = -1;
|
|
if (adc <= s->v0) {
|
|
frac = 0;
|
|
} else {
|
|
frac = 10 * (adc - s->v1) / (s->v1 - s->v0);
|
|
}
|
|
} else {
|
|
pos = 0;
|
|
if (adc >= s->v2) {
|
|
frac = 10;
|
|
} else {
|
|
frac = 10 * (adc - s->v2) / (s->v2 - s->v1);
|
|
}
|
|
}
|
|
if (frac < 3) {
|
|
ConfigStat(s, pos, 10);
|
|
} else if (frac > 7) {
|
|
ConfigStat(s, pos + 1, 10);
|
|
} else {
|
|
w = frac * 2 - 5;
|
|
ConfigStat(s, pos, 10 - w);
|
|
ConfigStat(s, pos + 1, w);
|
|
}
|
|
if (s->pos == 0) return s->stableCode;
|
|
code = s->code;
|
|
if (s->pos > 0) { // code is certainly higher
|
|
while (code < R_MAX - 1 && adc > ConfigAdcFromCode(code)) {
|
|
code ++;
|
|
FastHandler();
|
|
}
|
|
} else {
|
|
while (code > 1 && adc < ConfigAdcFromCode(code)) {
|
|
code --;
|
|
FastHandler();
|
|
}
|
|
}
|
|
s->v0 = ConfigAdcFromCode(code - 1);
|
|
s->v1 = ConfigAdcFromCode(code);
|
|
s->v2 = ConfigAdcFromCode(code + 1);
|
|
s->code = code;
|
|
return s->stableCode;
|
|
}
|
|
|
|
void ConfigDevice(byte devno, byte state) {
|
|
struct deviceTable_s *d;
|
|
byte av;
|
|
|
|
if (devno >= configMaxDev) {
|
|
devno = 0;
|
|
}
|
|
d = &ARRAY(deviceTable, devno);
|
|
if (d->name[0] == 0) {
|
|
ParSetText(configDevice, "unknown");
|
|
} else {
|
|
ParSetText(configDevice, d->name);
|
|
}
|
|
if (online) {
|
|
ParSet(configDeviceState, state);
|
|
if (configDeviceState == config_by_touch) {
|
|
screen = m_loading;
|
|
loadingUntil = now + 5000;
|
|
}
|
|
return;
|
|
}
|
|
textcopy(configTitle, sizeof configTitle, configDevice);
|
|
ParSet(configDeviceState, config_local);
|
|
ParSet(flowAvailable, (d->opt & NV) != 0);
|
|
ParSet(vuAvailable, (d->opt & VALVEUNIT) != 0);
|
|
ParSet(motorAvailable, flowAvailable);
|
|
if (d->opt & N2) {
|
|
av = 1;
|
|
} else if (d->opt & N2V) {
|
|
av = 2;
|
|
} else {
|
|
av = 0;
|
|
}
|
|
ParSet(n2Available, av);
|
|
if (d->opt & HE) {
|
|
av = 1;
|
|
} else if (d->opt & HEV) {
|
|
av = 2;
|
|
} else {
|
|
av = 0;
|
|
}
|
|
HeConfig(av, d->heCur, d->heWiRes, d->heEmpty, d->heFull);
|
|
if (screen == m_loading) {
|
|
screen = m_home;
|
|
}
|
|
}
|
|
|
|
void ConfigHandler() {
|
|
byte ca, cb;
|
|
byte devno1;
|
|
byte i, m;
|
|
struct deviceTable_s *d;
|
|
char name[16];
|
|
boolean changed;
|
|
|
|
#if (RAMTEST)
|
|
if (freeRam == 1) return;
|
|
ParSet(freeRam, RamFreeSize());
|
|
if (freeRam < 16) {
|
|
freeRam = 1;
|
|
DispError("stack", "overflow");
|
|
}
|
|
#endif
|
|
if (devno0 == 255 && devno0 == 0) { // make config faster when nothing else is running
|
|
m = 100;
|
|
} else {
|
|
m = 10;
|
|
}
|
|
for (i = 0; i < m; i++) {
|
|
ca = ConfigGetCode(0, aRead(a_codea));
|
|
if (ca == R_INSTABLE) {
|
|
ParSet(codeAbad, 1);
|
|
} else {
|
|
ParSet(codeAbad, 0);
|
|
ParSet(codeA, ConfigResFromCode(ca));
|
|
}
|
|
cb = ConfigGetCode(1, aRead(a_codeb));
|
|
if (cb == R_INSTABLE) {
|
|
ParSet(codeBbad, 1);
|
|
} else {
|
|
ParSet(codeBbad, 0);
|
|
ParSet(codeB, ConfigResFromCode(cb));
|
|
}
|
|
}
|
|
|
|
d = 0;
|
|
for (devno1 = 0; devno1 < configNdevices; devno1++) {
|
|
FastHandler();
|
|
d = &ARRAY(deviceTable,devno1);
|
|
if (d->rescode[0] == ca && d->rescode[1] == cb) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (devno1 != devno0 && devno1 < configNdevices) {
|
|
devno0 = devno1;
|
|
if (d) {
|
|
ConfigDevice(devno0, config_by_code);
|
|
} else {
|
|
ParSetText(configDevice, "other");
|
|
screen = m_home;
|
|
}
|
|
//DispTriggerRewrite();
|
|
}
|
|
}
|
|
|
|
int8_t ConfigItemText(char *text, byte maxlen) {
|
|
int8_t len;
|
|
if (configItemIndex != 0) {
|
|
if (ARRAY(configItem,configItemIndex) != ',') return -1; // bad syntax
|
|
configItemIndex++;
|
|
}
|
|
len = textcopyuntil(text, maxlen, &ARRAY(configItem,configItemIndex), ',');
|
|
if (len == maxlen) return -1; // too long
|
|
configItemIndex += len;
|
|
return len;
|
|
}
|
|
|
|
int8_t ConfigItemNum(long *result, byte dig) {
|
|
byte len;
|
|
|
|
if (configItemIndex != 0) {
|
|
if (ARRAY(configItem,configItemIndex) != ',') return -1; // bad syntax
|
|
configItemIndex++;
|
|
}
|
|
*result = text2fix(&ARRAY(configItem,configItemIndex), dig, &len);
|
|
configItemIndex += len;
|
|
return len;
|
|
}
|
|
|
|
byte ConfigFindItem(char *name) {
|
|
byte devno;
|
|
|
|
for (devno = 0; devno < configNdevices; devno++) {
|
|
if (strcmp(ARRAY(deviceTable,devno).name, name) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
return devno;
|
|
}
|
|
|
|
void ConfigTrimNum(char *buffer) {
|
|
// trims away training zeros and decimal points
|
|
char *p = 0;
|
|
while (*buffer != 0) {
|
|
if (p) { // we have already passed decimal point
|
|
if (*buffer != '0') { // we need this digit
|
|
p = buffer + 1;
|
|
}
|
|
} else if (*buffer == '.') {
|
|
p = buffer;
|
|
}
|
|
buffer++;
|
|
}
|
|
if (p) {
|
|
*p = 0;
|
|
}
|
|
}
|
|
|
|
void ConfigItem() {
|
|
struct deviceTable_s *d;
|
|
long value, r;
|
|
byte len, c, i, j, devno;
|
|
char buffer[8];
|
|
boolean addhecur;
|
|
|
|
if (configNdevices >= configMaxDev) {
|
|
SerialC.write('?');
|
|
Serial.print(F("config table full"));
|
|
return;
|
|
}
|
|
if (configItem[0] == '-') { // it's an instrument name list
|
|
// ignore obsolete item
|
|
return;
|
|
}
|
|
configItemIndex = 0;
|
|
d = &ARRAY(deviceTable,configNdevices);
|
|
if (ConfigItemText(d->name, sizeof d->name) < 0) {
|
|
SerialC.write('?');
|
|
Serial.print(F("device name too long\n"));
|
|
return;
|
|
}
|
|
if (ARRAY(configItem,configItemIndex) == 0) { // end of data
|
|
switch (d->name[0]) {
|
|
case 'c': configNdevices = 0; return;
|
|
case 's': ConfigSave(); return;
|
|
case 'b': configDevIdx = 0; return;
|
|
}
|
|
if (configDevIdx >= configNdevices) {
|
|
configItem[0] = 0;
|
|
configDevIdx = 0;
|
|
return;
|
|
}
|
|
d = &ARRAY(deviceTable,configDevIdx);
|
|
configDevIdx++;
|
|
// configItem is reconstructed in a standardized way
|
|
textcopy(configItem, sizeof configItem, d->name);
|
|
textappend(configItem, sizeof configItem, ",");
|
|
if (d->rescode[0] != R_MAX) {
|
|
fix2str(ConfigResFromCode(d->rescode[0]), 3, buffer, sizeof buffer);
|
|
ConfigTrimNum(buffer);
|
|
textappend(configItem, sizeof configItem, buffer);
|
|
}
|
|
textappend(configItem, sizeof configItem, ",");
|
|
if (d->rescode[1] != R_MAX) {
|
|
fix2str(ConfigResFromCode(d->rescode[1]), 3, buffer, sizeof buffer);
|
|
ConfigTrimNum(buffer);
|
|
textappend(configItem, sizeof configItem, buffer);
|
|
}
|
|
textappend(configItem, sizeof configItem, ",");
|
|
if (d->opt & N2) {
|
|
textappend(configItem, sizeof configItem, "n");
|
|
} else if (d->opt & N2V) {
|
|
textappend(configItem, sizeof configItem, "N");
|
|
}
|
|
if (d->opt & NV) textappend(configItem, sizeof configItem, "f");
|
|
if (d->opt & VALVEUNIT) textappend(configItem, sizeof configItem, "v");
|
|
if (d->opt & HE) {
|
|
if (d->heCur == AMI_heCur && d->heWiRes == AMI_heWiRes) {
|
|
textappend(configItem, sizeof configItem, "a");
|
|
addhecur = false;
|
|
} else if (d->heCur == OXF_heCur && d->heWiRes == OXF_heWiRes) {
|
|
textappend(configItem, sizeof configItem, "o");
|
|
addhecur = false;
|
|
} else {
|
|
textappend(configItem, sizeof configItem, "h");
|
|
addhecur = true;
|
|
}
|
|
textappend(configItem, sizeof configItem, ",");
|
|
fix2str(d->heEmpty, 0, buffer, sizeof buffer);
|
|
ConfigTrimNum(buffer);
|
|
textappend(configItem, sizeof configItem, buffer);
|
|
if (d->heFull != 0 || addhecur) {
|
|
textappend(configItem, sizeof configItem, ",");
|
|
fix2str(d->heFull, 0, buffer, sizeof buffer);
|
|
ConfigTrimNum(buffer);
|
|
textappend(configItem, sizeof configItem, buffer);
|
|
if (addhecur) {
|
|
textappend(configItem, sizeof configItem, ",");
|
|
fix2str(d->heCur, 0, buffer, sizeof buffer);
|
|
textappend(configItem, sizeof configItem, buffer);
|
|
fix2str(d->heWiRes, 0, buffer, sizeof buffer);
|
|
textappend(configItem, sizeof configItem, buffer);
|
|
}
|
|
}
|
|
} else if (d->opt & HEV) {
|
|
textappend(configItem, sizeof configItem, "H");
|
|
}
|
|
return;
|
|
}
|
|
|
|
for (j =0; j < 2; j++) {
|
|
len = ConfigItemNum(&r, 3);
|
|
if (len < 0) {
|
|
SerialC.write('?');
|
|
Serial.print(F("missing codes\n"));
|
|
return;
|
|
}
|
|
if (len == 0) {
|
|
d->rescode[j] = R_MAX;
|
|
} else {
|
|
for (c = 0; c < R_INSTABLE; c++) {
|
|
if (ConfigResFromCode(c) == r) {
|
|
d->rescode[j] = c;
|
|
break;
|
|
}
|
|
}
|
|
if (c == R_INSTABLE) {
|
|
SerialC.write('?');
|
|
Serial.print(F("unknown resistor code "));
|
|
Serial.println(r);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if (ConfigItemText(buffer, sizeof buffer) < 0) {
|
|
SerialC.write('?');
|
|
Serial.print(F("missing flags\n"));
|
|
return;
|
|
}
|
|
d->heCur = 0;
|
|
d->opt = 0;
|
|
for (i = 0; i < sizeof buffer && buffer[i] != 0; i++) {
|
|
switch (buffer[i]) {
|
|
case 'n': d->opt |= N2; break;
|
|
case 'N': d->opt |= N2V; break;
|
|
case 'H': d->opt |= HEV; break;
|
|
case 'f': d->opt |= NV; break;
|
|
case 'h': d->opt |= HE; d->heCur = 1; d->heWiRes = 1; break;
|
|
case 'a': d->opt |= HE; d->heCur = AMI_heCur; d->heWiRes = AMI_heWiRes; break;
|
|
case 'o': d->opt |= HE; d->heCur = OXF_heCur; d->heWiRes = OXF_heWiRes; break;
|
|
case 'v': d->opt |= VALVEUNIT; break;
|
|
default: Serial.print(F("bad flags\n")); return;
|
|
}
|
|
}
|
|
if (d->heCur != 0) {
|
|
d->heFull = 0;
|
|
if (ConfigItemNum(&value, 0) < 0) {
|
|
SerialC.write('?');
|
|
Serial.print(F("missing He level res.\n"));
|
|
return;
|
|
}
|
|
d->heEmpty = value;
|
|
if (ConfigItemNum(&value, 0) >= 0) {
|
|
d->heFull = value;
|
|
if (ConfigItemNum(&value, 0) > 0) {
|
|
d->heCur = value;
|
|
if (ConfigItemNum(&value, 0) > 0) {
|
|
d->heWiRes = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (d->heCur == 1) {
|
|
SerialC.write('?');
|
|
Serial.print(F("missing He level current\n"));
|
|
return;
|
|
}
|
|
if (d->heWiRes == 1) {
|
|
SerialC.write('?');
|
|
Serial.print(F("missing He wire resistivity\n"));
|
|
return;
|
|
}
|
|
devno = ConfigFindItem(d->name);
|
|
if (devno == configNdevices) {
|
|
configNdevices++;
|
|
// Serial.println("added");
|
|
} else {
|
|
ARRAY(deviceTable,devno) = *d;
|
|
// Serial.println("replaced");
|
|
}
|
|
return;
|
|
}
|
|
|
|
void ConfigSave() {
|
|
long value = configVersion;
|
|
|
|
EEPROM.write(0, EEPROM_version);
|
|
eeSetAdr(1);
|
|
EESTORE(value, ee_write);
|
|
EESTORE(configSpecial, ee_write);
|
|
if (configSpecial != 0) {
|
|
Serial.print("savespecial ");
|
|
Serial.print(EEPROM_version, DEC);
|
|
Serial.print(".");
|
|
Serial.println(configSpecial, DEC);
|
|
ConfigSpecial(ee_write);
|
|
} else {
|
|
EESTORE(configNdevices, ee_write);
|
|
Serial.print("save ");
|
|
Serial.print(EEPROM_version, DEC);
|
|
Serial.print(".");
|
|
Serial.println(configVersion);
|
|
eeStore((void *)&deviceTable, (sizeof deviceTable[0]) * configNdevices, ee_write);
|
|
EESTORE(heExtAvailable, ee_write);
|
|
if (EEPROM_version > 7) {
|
|
InstrStore(ee_write);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void ConfigCmd(byte cmd) {
|
|
|
|
switch (cmd) {
|
|
case config_noflow:
|
|
case config_flow:
|
|
ParSet(flowAvailable, cmd - config_noflow);
|
|
ParSet(motorAvailable, flowAvailable);
|
|
WriteDisplay();
|
|
//DispRedrawMenu(0);
|
|
break;
|
|
case config_non2:
|
|
case config_n2:
|
|
ParSet(n2Available, cmd - config_non2);
|
|
WriteDisplay();
|
|
// DispRedrawMenu(0);
|
|
break;
|
|
case config_nohe:
|
|
ParSet(heAvailable, false);
|
|
//DispTriggerRewrite();
|
|
WriteDisplay();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ConfigDeviceDisp() {
|
|
byte pos, devno, base;
|
|
|
|
base = DispPage() * 12;
|
|
if (base >= configNdevices) {
|
|
DispGotoPage(0);
|
|
DispClrAll();
|
|
base = 0;
|
|
}
|
|
for (pos = 13, devno = base; pos > 0 && devno < configNdevices; pos -= 2, devno++) {
|
|
if (pos == 1) pos = 12; // next column
|
|
DispButton(pos, m_device, devno, ARRAY(deviceTable,devno).name);
|
|
}
|
|
DispButton(0, m_device, device_other, "other");
|
|
DispButton(1, m_menu, m_home, "home");
|
|
}
|
|
|
|
void ConfigDeviceCmd(byte cmd) {
|
|
if (cmd < configNdevices && cmd != device_other) {
|
|
ConfigDevice(cmd, config_by_touch);
|
|
screen = m_home;
|
|
return;
|
|
}
|
|
DispClrAll();
|
|
DispNextPage(99);
|
|
}
|
|
|
|
void ConfigSpecial(EeMode mode) {
|
|
switch (configSpecial) {
|
|
case argon_cfg:
|
|
if (mode == ee_read) {
|
|
extension = valve_extension;
|
|
ParSet(auxAvailable, 1);
|
|
ParSetText(configDevice, "argon");
|
|
Serial.print("load");
|
|
} else {
|
|
Serial.print("save");
|
|
}
|
|
Serial.println(" argon");
|
|
EESTORE(auxDigits, mode);
|
|
EESTORE(auxScale, mode);
|
|
EESTORE(auxLabel, mode);
|
|
EESTORE(n2Available, mode);
|
|
Serial.print("nav="); Serial.print(n2Available);
|
|
break;
|
|
case multihe_cfg:
|
|
if (mode == ee_read) {
|
|
extension = he_extension;
|
|
ParSet(heAvailable, 1);
|
|
ParSet(heExtAvailable, 6);
|
|
ParSetText(configDevice, "LHe vess");
|
|
}
|
|
HeStore(mode);
|
|
break;
|
|
case jtext_cfg:
|
|
if (mode == ee_read) {
|
|
extension = valve_extension;
|
|
ParSetText(configDevice, "jtext");
|
|
Serial.print("load");
|
|
ParSet(n2Available, 1);
|
|
ParSet(motorAvailable, 1);
|
|
motorEndSwitch = 1;
|
|
} else {
|
|
Serial.print("save");
|
|
}
|
|
Serial.println(" jtext");
|
|
break;
|
|
|
|
}
|
|
}
|