380 lines
9.7 KiB
Arduino
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;
|
|
}
|