Files
2023-09-11 18:04:36 +02:00

380 lines
9.7 KiB
Arduino

// ParGet, ParFmt, ParCommand, ParScan are access functions. The Functions are not reentrant,
// but it is allowed to call any function within another
// ParFixed_, ParEnum_, ParText_ are functions to define parameters
#define PARDEBUG 0
// the text fields of the following struct might be accessed after a Par* function, and must therefore be static
// all fields are used by only one action, and can therefore be static
struct {
boolean readonly; // par_command: parameter is readonly
ScanFunc scan; // par_scan: scan function
char text[24]; // par_fmtdisp: output (numbers, enum and texts)
char scantext[24]; // par_scan: output as text (fix and enum)
char scanform[16]; // par_scan: formatted output (numbers)
char *formatted; // par_fmt: output
char formattedbuf[16]; // only for numbers
} ctx;
ParAction *action = 0;
//byte unchangedSerial[p_nPar / 8 + 1] = {0}; // for serial connection
//byte unchangedDisplay[p_nPar / 8 + 1] = {0}; // for display
byte flags[p_nPar+1] = {0};
void ParClrAll(byte flag) {
byte i;
for (i = 0; i <= p_nPar; i++) {
bitClear(ARRAY(flags,i), flag);
}
}
void ParSetAllChanged() {
ParClrAll(par_serial_unchanged);
}
void ParSetAllChangedDisp() {
ParClrAll(par_display_unchanged);
}
boolean ParChanged(byte nr) {
if (bitRead(ARRAY(flags,nr), par_display_unchanged)) return false;
bitSet(ARRAY(flags,nr), par_display_unchanged);
return true;
}
/*
boolean ParHasChanged(byte nr) {
return !bitRead(ARRAY(flags,nr), par_serial_unchanged);
}
*/
void ParSetChanged(byte nr) {
bitClear(ARRAY(flags,nr), par_serial_unchanged);
}
void ParSet_(byte nr, void *ptr, byte siz, long value) {
long old;
if (siz == 4) {
old = *(long *)ptr;
if (value == old) return;
*(long *)ptr = value;
} else if (siz == 1) {
old = *(byte *)ptr;
if (value == old) return;
*(byte *)ptr = value;
} else {
DispError(c40(nr % 10 + 1 + 40 * (nr / 10 + 1)), "bad siz");
}
bitClear(ARRAY(flags,nr), par_serial_unchanged);
if (PARDEBUG) {
if (bitRead(ARRAY(flags,nr), par_display_unchanged)) {
Serial.print(nr); Serial.print("/"); Serial.print(siz); Serial.println(" changed");
}
}
if (siz == 4 && (value + 5) / 10 == (old + 5) / 10) return;
bitClear(ARRAY(flags,nr), par_display_unchanged);
}
void ParSetText_(byte nr, char *ptr, byte siz, const char *value) {
textcopy(ptr, siz, value);
bitClear(ARRAY(flags,nr), par_serial_unchanged);
bitClear(ARRAY(flags,nr), par_display_unchanged);
}
long ParGet(byte nr) {
ParAction *oldact = action;
ParAction act;
char number[4];
action = &act;
act.action = par_get;
act.nr = nr;
act.value = 0;
Pars();
action = oldact;
if (act.action != par_done) {
number[0] = (nr / 100) % 10 + '0';
number[1] = (nr / 10) % 10 + '0';
number[2] = nr % 10 + '0';
number[3] = 0;
DispError(number, " undefined");
}
return act.value;
}
boolean ParCommand(name_t name) {
ParAction *oldact = action;
ParAction act;
action = &act;
act.action = par_command;
act.name = name;
Pars();
action = oldact;
return act.action == par_done;
}
void ParHide(name_t name) {
ParAction *oldact = action;
ParAction act;
action = &act;
act.action = par_hide;
act.name = name;
Pars();
action = oldact;
}
const char *ParFmtByName(name_t name) {
ParAction *oldact = action;
ParAction act;
action = &act;
act.action = par_fmt;
act.name = name;
ctx.formatted = 0;
Pars();
action = oldact;
if (act.action != par_done) return "undef";
return ctx.formatted;
}
// format for display
const char *ParFmt(byte nr, byte maxlen) {
ParAction *oldact = action;
ParAction act;
action = &act;
act.action = par_fmtdisp;
act.nr = nr;
Pars();
action = oldact;
if (act.action != par_done) return "undef";
if (maxlen > 1 && maxlen < sizeof ctx.text) {
ctx.text[maxlen] = 0;
if (ctx.text[maxlen - 1] == '.') {
ctx.text[maxlen - 1] = 0;
}
}
return ctx.text;
}
const char *ParFmt(byte nr) {
return ParFmt(nr, 0);
}
void ParScan(ScanFunc scan) {
ParAction *oldact = action;
ParAction act;
action = &act;
act.action = par_scan;
ctx.scan = scan;
Pars();
action = oldact;
return;
}
void ParReadonly(boolean value) {
ctx.readonly = value;
}
byte ParFixed_(byte nr, name_t name, long *ptr, byte dig) {
long value;
byte result = action->action;
byte len;
FastHandler();
switch (action->action) {
case par_done: return par_none;
case par_hide:
if (name != action->name) return par_none;
//Serial.print("hide "); Serial.println(c40(name));
bitSet(ARRAY(flags,nr), par_hidden);
action->action = par_done;
break;
case par_scan:
if (bitRead(ARRAY(flags,nr), par_hidden)) return par_none;
fix2str(*ptr, dig, ctx.scanform, sizeof ctx.scanform);
if (ctx.scan(nr, name, ctx.scanform, 0, bitRead(ARRAY(flags,nr), par_serial_unchanged))) {
bitSet(ARRAY(flags,nr), par_serial_unchanged);
}
break;
case par_command:
if (name != action->name) return par_none;
if (ctx.readonly) {
action->action = par_none;
return par_readonly;
}
value = ParserFixed(dig, &len);
if (len > 0) {
ParSet_(nr, (void *)ptr, sizeof (*ptr), value);
} else {
Serial.print(F("can not convert "));
Serial.print(ParserText());
Serial.print(F(" to number"));
}
action->action = par_done;
break;
case par_get:
if (nr != action->nr) return par_none;
action->value = *ptr;
if (dig > 0) {
action->value = (action->value + 5) / 10;
}
action->action = par_done;
break;
case par_fmt:
if (name != action->name) return par_none;
//Serial.print("show "); Serial.println(c40(name));
bitClear(ARRAY(flags,nr), par_hidden);
value = *ptr;
fix2str(value, dig, ctx.formattedbuf, sizeof ctx.formattedbuf);
ctx.formatted = ctx.formattedbuf;
action->action = par_done;
break;
case par_fmtdisp:
if (nr != action->nr) return par_none;
value = *ptr;
if (dig > 0) {
dig--;
value = (value + 5) / 10;
}
fix2str(value, dig, ctx.text, sizeof ctx.text);
action->action = par_done;
break;
default:
return par_none;
}
return result;
}
byte ParEnum_(byte nr, name_t name, byte *ptr, flash_str list) {
byte result = action->action;
long value;
byte len;
FastHandler();
switch (action->action) {
case par_done: return par_none;
case par_hide:
if (name != action->name) return par_none;
bitSet(ARRAY(flags,nr), par_hidden);
action->action = par_done;
break;
case par_scan:
if (bitRead(ARRAY(flags,nr), par_hidden)) return par_none;
enum2str(*ptr, list, ctx.scantext, sizeof ctx.scantext);
fix2str(*ptr, 0, ctx.scanform, sizeof ctx.scanform);
if (ctx.scan(nr, name, ctx.scanform, ctx.scantext, bitRead(ARRAY(flags,nr), par_serial_unchanged))) {
bitSet(ARRAY(flags,nr), par_serial_unchanged);
//if(PARDEBUG) { Serial.print('('); Serial.print(c40(name)); Serial.print(":"); Serial.print(nr); Serial.print(')'); };
}
break;
case par_command:
if (name != action->name) return par_none;
if (ctx.readonly) {
action->action = par_none;
return par_readonly;
}
value = ParserFixed(0, &len);
if (len > 0) {
ParSet_(nr, (void *)ptr, sizeof (*ptr), value);
} else {
Serial.print(F("can not convert "));
Serial.print(ParserText());
Serial.print(F(" to number"));
}
action->action = par_done;
break;
case par_get:
if (nr != action->nr) return par_none;
action->value = *ptr;
action->action = par_done;
break;
case par_fmt:
if (name != action->name) return par_none;
bitClear(ARRAY(flags,nr), par_hidden);
fix2str(*ptr, 0, ctx.formattedbuf, sizeof ctx.formattedbuf);
ctx.formatted = ctx.formattedbuf;
action->action = par_done;
break;
case par_fmtdisp:
if (nr != action->nr) return par_none;
enum2str(*ptr, list, ctx.text, sizeof ctx.text);
action->action = par_done;
break;
default:
return par_none;
}
return result;
}
byte ParText_(byte nr, name_t name, char *ptr, byte siz, boolean update) {
// update=false: does not appear in summary
byte result = action->action;
byte l;
char ch, *p;
FastHandler();
switch (action->action) {
case par_done: return par_none;
case par_hide:
if (name != action->name) return par_none;
bitSet(ARRAY(flags,nr), par_hidden);
action->action = par_done;
break;
case par_scan:
if (bitRead(ARRAY(flags,nr), par_hidden)) return par_none;
if (update) {
p = ptr;
} else {
p = 0;
}
if (ctx.scan(nr, name, p, ptr, bitRead(ARRAY(flags,nr), par_serial_unchanged))) {
bitSet(ARRAY(flags,nr), par_serial_unchanged);
}
return true;
case par_command:
if (name != action->name) return par_none;
if (ctx.readonly) {
action->action = par_none;
return par_readonly;
}
ParSetText_(nr, ptr, siz, ParserText());
action->action = par_done;
break;
case par_get:
if (nr != action->nr) return par_none;
action->value = 0; // par_get currently not used for text
// textcopy(ctx.text, sizeof(ctx.text), ptr);
action->action = par_done;
break;
case par_fmt:
if (name != action->name) return par_none;
bitClear(ARRAY(flags,nr), par_hidden);
//textcopy(ctx.formatted, sizeof(ctx.formatted), ptr);
ctx.formatted = ptr;
/*
for (l = 0; l < sizeof(ctx.formatted); l++) {
if (ctx.formatted[l] == 0) break;
if (ctx.formatted[l] <= ' ') {
ctx.formatted[l] = '_';
}
}
*/
action->action = par_done;
break;
case par_fmtdisp:
if (nr != action->nr) return par_none;
textcopy(ctx.text, sizeof(ctx.text), ptr);
action->action = par_done;
break;
default:
return par_none;
}
return result;
}