593 lines
13 KiB
Arduino
593 lines
13 KiB
Arduino
#define ARRAY_CHECK 1
|
|
#include "utils.h"
|
|
#include "DispSerial.h"
|
|
#include "SerialWrapper.h"
|
|
#include "dipdisplay.h"
|
|
#include "motor.h"
|
|
#include "parser.h"
|
|
#include "par.h"
|
|
|
|
#define RAMTEST 0
|
|
// define SERIALCOMMON 1 for testing the serial connection over usb
|
|
#define SERIALCOMMON 0
|
|
|
|
PAR_TEXT configSoft[16] = "8.3";
|
|
|
|
long now; // global variable, updated by FastHandler
|
|
byte inside;
|
|
boolean displayAvailable;
|
|
boolean online = 0;
|
|
byte dispEco = 5; // default eco brightness: 5 %
|
|
|
|
// parameter list
|
|
enum {
|
|
p_none, p_flow, p_flowAvailable, p_flowSensState, p_motorState, p_motorAutoState,
|
|
p_motorAvailable, p_motorPulse, p_motorOpenTime, p_motorCurrent, p_motorFreeCurrent,
|
|
p_motorTorqueConst, p_motorTorque, p_motorTorqueLimit, p_motorFlowTarget,
|
|
p_motorMeasuredPulse, p_motorSpeed, p_motorRead, p_motorWiggle,
|
|
p_heLevel, p_heRaw, p_heAvailable, p_heDrive, p_heCurrent, p_heVolt, p_heHigh, p_heLow,
|
|
p_heWiRes, p_heEmpty, p_heFull, p_heFastTime, p_heSlowTime, p_heSlope, p_heFirst,
|
|
p_heValve, p_heSensState, p_heAuto, p_heMeas, p_heFast, p_heCommand, /* p_heBooster, */
|
|
p_heIncreaseTolerance, p_heFastTimeout, p_heExtAvailable, p_heChannel, p_heExtDrive,
|
|
p_heExtWiRes, p_heExtEmpty, p_heExtFull,
|
|
p_n2Available, p_n2upper, p_n2lower, p_n2threshold, p_n2tubecooldelay,
|
|
p_n2filltimeout, p_n2fault, p_n2auto, p_n2valve, p_n2command, p_boostdelay,
|
|
p_codeA, p_codeB, p_codeAbad, p_codeBbad, p_freeRam,
|
|
p_timC, p_timN, p_timH, p_timF, p_timM, p_timV, p_timQ,
|
|
p_configDevice, p_configDeviceState, p_configSoft, p_configIdn, p_configSpecial,
|
|
p_configSave, p_configVersion, p_configItem,
|
|
p_instr, p_instrConnected, p_instrRack,
|
|
p_auxAvailable, p_aux, p_auxScale, p_auxDigits, p_auxLabel,
|
|
p_heFeedback, p_n2Feedback, p_vuAvailable,
|
|
p_heExtLevel, p_heExtState = p_heExtLevel + 6,
|
|
p_nBase = p_heExtState + 6
|
|
};
|
|
|
|
enum {p_vu = p_nBase - 1, p_vuCmd = p_vu + 12}; // valve unit base (+ 24 parameters)
|
|
|
|
enum {p_nPar = p_nBase + 24}; // max. parameter of all extensions
|
|
|
|
enum {no_extension, valve_extension, he_extension};
|
|
byte extension;
|
|
|
|
/*
|
|
char *menu_text = "menu|home|configuration";
|
|
char *menu_text1_flow = "needle valve";
|
|
char *menu_text2_n2 = "LN2";
|
|
char *menu_text3_he = "LHe level";
|
|
*/
|
|
//enum {m_none, m_home, m_menu, m_device, m_instr, m_loading, m_commands, m_config, m_nv, m_n2, m_he, m_ext};
|
|
enum {m_none, m_home, m_menu, m_device, m_instr, m_loading, m_config, m_nv, m_n2, m_he, m_ext};
|
|
enum {cmd_stop, cmd_area, cmd_wake, cmd_sleep};
|
|
enum {N_hdl = 8};
|
|
|
|
byte screen = m_instr; // screen shown on start
|
|
|
|
PAR_TEXT configIdn[16] = "CCU4";
|
|
PAR_BYTE n2Available = 0;
|
|
PAR_BYTE heAvailable = 0;
|
|
PAR_BYTE flowAvailable = 0;
|
|
PAR_BYTE motorAvailable = 0; // was 1, why?
|
|
PAR_BYTE vuAvailable = 0;
|
|
PAR_BYTE heExtAvailable = 0; // 0: no addition He Level channel, 1: 2nd He Channel, 6: 6 additional channels with He Extension
|
|
PAR_BYTE auxAvailable = 0;
|
|
PAR_LONG timC = 0;
|
|
PAR_LONG timN = 0;
|
|
PAR_LONG timH = 0;
|
|
PAR_LONG timF = 0;
|
|
PAR_LONG timM = 0;
|
|
PAR_LONG timV = 0;
|
|
PAR_LONG timQ = 0;
|
|
byte motorEndSwitch = 0;
|
|
|
|
// parameters for Summary command:
|
|
int sumidx = 0; // actual position in parameter list
|
|
int sumsup = 0; // index of next supplementary parameters to write
|
|
|
|
enum {
|
|
io_lev_enable = 2,
|
|
io_lev_current = 3,
|
|
io_motor_enable = 4,
|
|
io_motor_current = 5,
|
|
io_motor_open = 6,
|
|
io_motor_close = 7,
|
|
io_n2_valve = 8,
|
|
io_he_valve = 9,
|
|
io_motor2_open = 10,
|
|
io_motor2_close = 11,
|
|
io_lev_boost = 12,
|
|
io_valve_boost = 13,
|
|
io_disp_input = 20,
|
|
io_he_select = 21,
|
|
io_ext1 = 22,
|
|
io_ext2 = 30,
|
|
io_ext3 = 38,
|
|
io_ext4 = 46
|
|
};
|
|
|
|
enum {
|
|
a_lev_current = 0,
|
|
a_lev_vplus = 1,
|
|
a_levb_vplus = 2,
|
|
a_lev_vminus = 3,
|
|
a_codea = 4,
|
|
a_codeb = 5,
|
|
a_n2_lower = 6,
|
|
a_n2_upper = 7,
|
|
a_flow_prec = 8,
|
|
a_flow_raw = 9,
|
|
a_motor_volt = 10,
|
|
a_motor_current = 11,
|
|
a_lhe_feedback = 12,
|
|
a_ln2_feedback = 13,
|
|
a_aux_current = 14,
|
|
a_levb_vminus = 15
|
|
};
|
|
|
|
|
|
#if (SERIALCOMMON)
|
|
#define Serial2 Serial
|
|
#endif
|
|
|
|
DispSerial SerialD(&Serial3);
|
|
SerialWrapper SerialC(&Serial2);
|
|
|
|
void setup() {
|
|
analogReference(EXTERNAL);
|
|
#if (RAMTEST)
|
|
RamFill();
|
|
#endif
|
|
Serial.begin(9600);
|
|
Serial.print("\n---------\n");
|
|
Serial3.begin(9600);
|
|
#if (!SERIALCOMMON)
|
|
Serial2.begin(9600);
|
|
#endif
|
|
SerialC.handler = HardHandler;
|
|
SerialD.handler = HardHandler;
|
|
ParSetAllChanged();
|
|
ConfigInit();
|
|
ValveInit();
|
|
HeInit();
|
|
FlowInit();
|
|
switch (extension) {
|
|
case valve_extension: VuInit(); break;
|
|
case he_extension: break;
|
|
}
|
|
displayAvailable = DispInit(ParHandler, screen); // initialize Display and tell that it should call ParHandler between every line written on the display
|
|
WriteDisplay();
|
|
}
|
|
|
|
void Pars() {
|
|
FlowPars();
|
|
HePars();
|
|
N2Pars();
|
|
ValvePars();
|
|
ConfigPars();
|
|
InstrPars();
|
|
if (auxAvailable) AuxPars();
|
|
ParFixed("tc", timC, 1);
|
|
ParFixed("tn", timN, 1);
|
|
ParFixed("th", timH, 1);
|
|
ParFixed("tf", timF, 1);
|
|
ParFixed("tm", timM, 1);
|
|
ParFixed("tv", timV, 1);
|
|
ParFixed("tq", timQ, 0);
|
|
switch (extension) {
|
|
case valve_extension: VuPars(); break;
|
|
}
|
|
}
|
|
|
|
void HomeDisp() {
|
|
boolean run = false;
|
|
boolean big = false;
|
|
|
|
ConfigDispShort(configSoft);
|
|
DispTouchCmd(m_menu, m_menu); // touch outside buttons opens menu
|
|
if (HeShown()) {
|
|
run |= HeDispShort(&big);
|
|
DispLine();
|
|
}
|
|
if (flowAvailable || motorAvailable) {
|
|
run |= FlowDispShort(!big);
|
|
DispLine();
|
|
}
|
|
if (auxAvailable) {
|
|
AuxDisp();
|
|
DispLine();
|
|
}
|
|
if (N2Shown()) {
|
|
run |= N2DispShort();
|
|
DispLine();
|
|
}
|
|
switch (extension) {
|
|
case valve_extension: VuDispShort(); DispLine(); break;
|
|
}
|
|
if (run) {
|
|
DispButton(1, m_home, cmd_stop, "stop");
|
|
} else {
|
|
InstrButton();
|
|
}
|
|
DispButton(0, m_menu, m_menu, "menu");
|
|
}
|
|
|
|
void CmdDisp() {
|
|
N2Buttons(7);
|
|
MotorButtons(12);
|
|
HeButtons(13);
|
|
switch (extension) {
|
|
case valve_extension: VuButtons(6); break;
|
|
}
|
|
DispButton(4, m_menu, m_instr, "instr");
|
|
DispButton(2, m_menu, m_config, "config");
|
|
DispButton(1, m_menu, m_home, "home");
|
|
}
|
|
|
|
void WriteDisplay() {
|
|
DispBegin(screen);
|
|
/*
|
|
DispMenu(0, 1, menu_text);
|
|
if (flowAvailable || motorAvailable) {
|
|
DispAppendToMenu(menu_text1_flow);
|
|
}
|
|
if (N2Shown()) {
|
|
DispAppendToMenu(menu_text2_n2);
|
|
}
|
|
if (HeShown()) {
|
|
DispAppendToMenu(menu_text3_he);
|
|
}
|
|
DispEndMenu();
|
|
*/
|
|
switch (screen) {
|
|
case m_home:
|
|
if (extension == he_extension) {
|
|
HeDispExt();
|
|
DispEnd();
|
|
return;
|
|
}
|
|
HomeDisp();
|
|
break;
|
|
case m_loading:
|
|
ConfigLoadingDisp();
|
|
break;
|
|
case m_menu:
|
|
CmdDisp();
|
|
break;
|
|
case m_config:
|
|
ConfigDispShort("cfg");
|
|
ConfigDisp();
|
|
break;
|
|
case m_device:
|
|
ConfigDeviceDisp();
|
|
break;
|
|
case m_instr:
|
|
InstrDisp();
|
|
break;
|
|
case m_he:
|
|
ConfigDispShort("LHe");
|
|
HeDisp();
|
|
break;
|
|
case m_n2:
|
|
ConfigDispShort("LN2");
|
|
N2Disp();
|
|
break;
|
|
case m_nv:
|
|
if (flowAvailable) {
|
|
ConfigDispShort("n.v.");
|
|
} else {
|
|
ConfigDispShort("m.v.");
|
|
}
|
|
FlowDisp();
|
|
break;
|
|
case m_ext:
|
|
switch (extension) {
|
|
case valve_extension:
|
|
ConfigDispShort("valves");
|
|
VuDisp();
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
// DispButton(0, m_menu * 16 + m_commands, "menu");
|
|
// DispButton(1, m_menu * 16 + m_home, "home");
|
|
DispEnd();
|
|
}
|
|
|
|
void DisplayHandler() {
|
|
int button;
|
|
byte menu, cmd;
|
|
static ulong last=0;
|
|
static ulong lastW=0;
|
|
|
|
//if (!expired(&last, 30)) return;
|
|
DispGet(menu, cmd);
|
|
switch (menu) {
|
|
case m_menu:
|
|
screen = cmd;
|
|
DispGotoPage(0);
|
|
break;
|
|
case m_home:
|
|
switch (cmd) {
|
|
case cmd_wake: // wake up
|
|
screen = m_home;
|
|
if (heExtAvailable <= 1) HeSetFast();
|
|
break;
|
|
case cmd_sleep: // sleep
|
|
screen = m_home;
|
|
break;
|
|
case cmd_stop:
|
|
HeCmd(cmd_stop);
|
|
N2Cmd(cmd_stop);
|
|
MotorCmd(cmd_stop);
|
|
break;
|
|
}
|
|
break;
|
|
case m_config:
|
|
ConfigCmd(cmd);
|
|
break;
|
|
case m_device:
|
|
ConfigDeviceCmd(cmd);
|
|
break;
|
|
case m_instr:
|
|
InstrCmd(cmd);
|
|
break;
|
|
case m_nv:
|
|
MotorCmd(cmd);
|
|
break;
|
|
case m_n2:
|
|
N2Cmd(cmd);
|
|
break;
|
|
case m_he:
|
|
HeCmd(cmd);
|
|
break;
|
|
case m_ext:
|
|
if (extension == valve_extension) VuCmd(cmd);
|
|
break;
|
|
}
|
|
|
|
ParHandler();
|
|
if (!expired(&lastW, 100)) return;
|
|
WriteDisplay();
|
|
}
|
|
|
|
boolean spc;
|
|
name_t name;
|
|
|
|
void OutResult(boolean ok) {
|
|
const char *value;
|
|
boolean containsBlanks;
|
|
//long s;
|
|
|
|
if (name != 0) {
|
|
if (spc) {
|
|
SerialC.write(' ');
|
|
} else {
|
|
spc = true;
|
|
}
|
|
//s = micros();
|
|
value = ParFmtByName(name);
|
|
containsBlanks = textContainsBlanks(value);
|
|
if (containsBlanks) SerialC.print('{');
|
|
SerialC.print(c40(name));
|
|
if (value == 0 || !ok) {
|
|
SerialC.write('?');
|
|
} else {
|
|
SerialC.write('=');
|
|
SerialC.print(value);
|
|
}
|
|
if (containsBlanks) SerialC.print('}');
|
|
name = 0;
|
|
}
|
|
}
|
|
|
|
byte List(byte nr, name_t name, const char *formatted, const char *astext, byte unchanged) {
|
|
SerialC.print(c40(name));
|
|
SerialC.print('\t');
|
|
if (formatted) {
|
|
SerialC.print(formatted);
|
|
}
|
|
if (astext) {
|
|
SerialC.print('\t');
|
|
if (astext[0] == '~') { // remove blink control character
|
|
astext++;
|
|
}
|
|
SerialC.print(astext);
|
|
}
|
|
SerialC.print('\n');
|
|
return 0;
|
|
}
|
|
|
|
byte Summary(byte nr, name_t name, const char *formatted, const char *astext, byte unchanged) {
|
|
char str[8];
|
|
boolean containsBlanks;
|
|
|
|
if (!formatted) return 0;
|
|
sumidx++;
|
|
if (unchanged && sumsup / 4 != sumidx / 4) return 0; // write unchanged only if within sumsup ... sumsup + 3
|
|
c40toString(name, str, sizeof str);
|
|
containsBlanks = textContainsBlanks(formatted);
|
|
if (containsBlanks) SerialC.print('{');
|
|
SerialC.print(str);
|
|
SerialC.print('=');
|
|
SerialC.print(formatted);
|
|
if (containsBlanks) SerialC.print('}');
|
|
SerialC.print(' ');
|
|
return 1;
|
|
}
|
|
|
|
void ShowSummary() {
|
|
sumidx = 0;
|
|
ParScan(Summary); // show changed values plus the parameters within sumsup ... sumsup + 3
|
|
sumsup += 4;
|
|
if (sumsup > sumidx) {
|
|
sumsup = 0;
|
|
}
|
|
}
|
|
|
|
void ParHandler() {
|
|
char *txt;
|
|
ParserType type;
|
|
char sym;
|
|
static ulong lastQuery = 0;
|
|
|
|
if (bitRead(inside, 0)) {
|
|
Serial.print("already inside ParHandler\n");
|
|
return;
|
|
}
|
|
bitSet(inside,0);
|
|
HardHandler();
|
|
type = Parser();
|
|
if (type == parser_none) {
|
|
if (online && time_ge(now, lastQuery + 5000)) {
|
|
online = false;
|
|
}
|
|
} else {
|
|
lastQuery = now;
|
|
online = true;
|
|
|
|
switch (type) {
|
|
case parser_value:
|
|
//Serial.println("number");
|
|
if (name == 0) {
|
|
SerialC.print('?');
|
|
}
|
|
OutResult(ParCommand(name));
|
|
break;
|
|
// case parser_colon:
|
|
// name = ParserIdent();
|
|
// ParSetHidden(name);
|
|
// name = 0;
|
|
// break;
|
|
case parser_ident:
|
|
OutResult(true);
|
|
name = ParserIdent();
|
|
break;
|
|
case parser_symbol:
|
|
sym = ParserSymbol();
|
|
if (sym == ':') {
|
|
ParHide(name);
|
|
name = 0;
|
|
break;
|
|
}
|
|
OutResult(true);
|
|
if (sym == '*') {
|
|
ParScan(List);
|
|
} else if (sym == '?') {
|
|
ShowSummary();
|
|
} else if (sym == '!') {
|
|
DispDebug(true);
|
|
} else if (sym == '$') {
|
|
#if (RAMTEST)
|
|
RamTest();
|
|
#else
|
|
SerialC.print(F("ramtest disabled\n"));
|
|
#endif
|
|
} else {
|
|
SerialC.print(sym);
|
|
}
|
|
spc = false;
|
|
break;
|
|
case parser_error:
|
|
SerialC.print('?');
|
|
break;
|
|
}
|
|
}
|
|
bitClear(inside,0);
|
|
}
|
|
|
|
int aRead(byte pin) {
|
|
int result;
|
|
|
|
result = analogRead(pin);
|
|
FastHandler();
|
|
return result;
|
|
}
|
|
|
|
void FastHandler() {
|
|
static long old = 0;
|
|
|
|
now = millis();
|
|
if (now == old) return;
|
|
|
|
if (now - old > timQ && old != 0) {
|
|
//Serial.println(old);
|
|
//Serial.println(now);
|
|
ParSet(timQ, now - old);
|
|
}
|
|
/*
|
|
if ((ulong) now / 1000 != (ulong) old / 1000) {
|
|
//Serial.print(now, DEC); Serial.println("tick");
|
|
}
|
|
*/
|
|
old = now;
|
|
MotorFastHandler();
|
|
ValveFastHandler();
|
|
}
|
|
|
|
void HardHandler() {
|
|
static byte hdl=0;
|
|
static ulong callcnt = 0;
|
|
static long times[N_hdl] = {0};
|
|
static long cnt[N_hdl] = {0};
|
|
static long last = 0;
|
|
byte i;
|
|
long t;
|
|
long m;
|
|
|
|
if (bitRead(inside, 1)) {
|
|
Serial.print("already inside HardHandler\n");
|
|
return;
|
|
}
|
|
bitSet(inside, 1);
|
|
FastHandler();
|
|
callcnt++;
|
|
if (time_ge(now, callcnt)) {
|
|
bitClear(inside, 1);
|
|
return; // make sure that this function does not consume more than 1 ms IN AVERAGE (for serial connections)
|
|
}
|
|
if (time_ge(now, callcnt + 1000)) {
|
|
Serial.println(now);
|
|
Serial.println(callcnt);
|
|
Serial.print("HardHandler is not called often enough\n");
|
|
callcnt = now - 1000;
|
|
}
|
|
|
|
t = micros();
|
|
switch (hdl) {
|
|
case 0: ConfigHandler(); break;
|
|
case 1: N2Handler(); break;
|
|
case 2: HeHandler(); break;
|
|
case 3: FlowHandler(); break;
|
|
case 4: MotorHandler(); break;
|
|
case 5: ValveHandler(); break;
|
|
case 6: AuxHandler(); break;
|
|
case 7: if (extension == valve_extension) VuHandler(); break;
|
|
}
|
|
t = micros() - t;
|
|
ARRAY(times, hdl) += t;
|
|
ARRAY(cnt, hdl) ++;
|
|
if (cnt[hdl] >= 10) {
|
|
m = ARRAY(times, hdl) * 0.001;
|
|
switch (hdl) {
|
|
case 0: ParSet(timC, m); break;
|
|
case 1: ParSet(timN, m); break;
|
|
case 2: ParSet(timH, m); break;
|
|
case 3: ParSet(timF, m); break;
|
|
case 4: ParSet(timM, m); break;
|
|
case 5: ParSet(timV, m); break;
|
|
}
|
|
ARRAY(cnt, hdl) = 0;
|
|
ARRAY(times, hdl) = 0;
|
|
}
|
|
hdl++;
|
|
if (hdl >= N_hdl) {
|
|
hdl = 0;
|
|
}
|
|
bitClear(inside, 1);
|
|
}
|
|
|
|
void loop() {
|
|
ParHandler();
|
|
if (displayAvailable) DisplayHandler();
|
|
}
|