Skip to content

Commit

Permalink
initVar and initValue to Model and Variable
Browse files Browse the repository at this point in the history
SysModModel
- move initVar and initValue to Model and Variable
- setValue returns void
- walkThroughModel using  Variable
  • Loading branch information
ewowi committed Nov 9, 2024
1 parent b2ee171 commit 0b96d0e
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 178 deletions.
8 changes: 4 additions & 4 deletions src/Sys/SysModInstances.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ class SysModInstances:public SysModule {
print->fFormat(columnVarID, sizeof(columnVarID), "ins%s_%s", variable.pid(), variable.id());

//create a var of the same type. InitVar is not calling onChange which is good in this situation! // = ui->cloneVar(var, columnVarID, [this, var](JsonObject insVar){});
Variable insVariable = ui->initVar(tableVar, columnVarID, variable.var["type"], false, [this](Variable insVariable, uint8_t rowNr, uint8_t eventType) {
Variable insVariable = mdl->initVar(tableVar, columnVarID, variable.var["type"], false, [this](Variable insVariable, uint8_t rowNr, uint8_t eventType) {
//extract the variable from insVariable.id()
char pid[32]; strlcpy(pid, insVariable.id() + 3, sizeof(pid)); //+3 : remove ins
char * id = strtok(pid, "_"); if (id != NULL ) {strlcpy(pid, id, sizeof(pid)); id = strtok(NULL, "_");} //split pid and id
Expand All @@ -244,7 +244,7 @@ class SysModInstances:public SysModule {

web->addResponse(insVariable.var, "value", instances[rowNrL].jsonData[variable.id()], rowNrL); // error: passing 'const Variable' as 'this' argument discards qualifiers

// mdl->setValue(insVariable.var, instances[rowNrL].jsonData[Variable(var).id()], rowNr);
// mdl->setValue(insVariable.var, instances[rowNrL].jsonData[variable.id()], rowNr);
//send to ws?
}
return true;
Expand Down Expand Up @@ -615,10 +615,10 @@ class SysModInstances:public SysModule {
mdl->findVars("dash", true, [&instance](Variable variable) { //varEvent
instance.jsonData[variable.id()] = variable.value();
// // print->printJson("setVar", var);
// JsonArray valArray = Variable(var).valArray();
// JsonArray valArray = variable.valArray();
// if (valArray.isNull())
// else if (valArray.size())
// instance.jsonData[Variable(var).id()] = valArray;
// instance.jsonData[variable.id()] = valArray;
});

serializeJson(instance.jsonData, starMessage.jsonString);
Expand Down
162 changes: 149 additions & 13 deletions src/Sys/SysModModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,26 +385,24 @@
return false;
}

JsonObject Variable::setValueJV(JsonVariant value, uint8_t rowNr) {
void Variable::setValueJV(JsonVariant value, uint8_t rowNr) {
if (value.is<JsonArray>()) {
uint8_t rowNr = 0;
// ppf(" %s is Array\n", value.as<String>().c_str);
JsonObject var;
for (JsonVariant el: value.as<JsonArray>()) {
var = setValueJV(el, rowNr++);
setValueJV(el, rowNr++);
}
return var;
}
else if (value.is<const char *>())
return setValue(JsonString(value, JsonString::Copied), rowNr);
setValue(JsonString(value, JsonString::Copied), rowNr);
else if (value.is<Coord3D>()) //otherwise it will be treated as JsonObject and toJson / fromJson will not be triggered!!!
return setValue(value.as<Coord3D>(), rowNr);
setValue(value.as<Coord3D>(), rowNr);
else
return setValue(value, rowNr);
setValue(value, rowNr);
}

//Set value with argument list
JsonObject Variable::setValueF(const char * format, ...) {
void Variable::setValueF(const char * format, ...) {
va_list args;
va_start(args, format);

Expand All @@ -413,7 +411,7 @@

va_end(args);

return setValue(JsonString(value, JsonString::Copied));
setValue(JsonString(value, JsonString::Copied));
}

JsonVariant Variable::getValue(uint8_t rowNr) {
Expand All @@ -433,6 +431,67 @@
return var["value"];
}

bool Variable::initValue(int min, int max, int pointer) {

if (pointer != 0) {
if (mdl->setValueRowNr == UINT8_MAX)
var["p"] = pointer; //store pointer!
else
var["p"][mdl->setValueRowNr] = pointer; //store pointer in array!
// ppf("initValue pointer stored %s: %s\n", id(), (void *)(var["p"].as<String>().c_str()));
}

if (min) var["min"] = min;
if (max && max != UINT16_MAX) var["max"] = max;

//value needs update if varVal not set yet or varVal is array and setValueRowNr is not in it
bool doSetValue = false;
if (var["type"] != "button") { //button never gets a value
if (var["value"].isNull()) {
doSetValue = true;
// print->printJson("initValue varEvent value is null", var);
} else if (var["value"].is<JsonArray>()) {
JsonArray valueArray = valArray();
if (mdl->setValueRowNr != UINT8_MAX) { // if var in table
if (mdl->setValueRowNr >= valueArray.size())
doSetValue = true;
else if (valueArray[mdl->setValueRowNr].isNull())
doSetValue = true;
}
}
}

//sets the default values, by varEvent if exists, otherwise manually (by returning true)
if (doSetValue) {
bool onSetValueExists = false;
if (!var["fun"].isNull()) {
onSetValueExists = triggerEvent(onSetValue, mdl->setValueRowNr);
}
if (!onSetValueExists) { //setValue provided (if not null)
return true;
}
}
else { //do onChange on existing value
//no call of onChange for buttons otherwise all buttons will be fired which is highly undesirable
if (var["type"] != "button") { // && !var["fun"].isNull(): also if no varEvent to update pointers !isPointer because 0 is also a value then && (!isPointer || value)
bool onChangeExists = false;
if (var["value"].is<JsonArray>()) {
//refill the vector
for (uint8_t rowNr = 0; rowNr < valArray().size(); rowNr++) {
onChangeExists |= triggerEvent(onChange, rowNr, true); //init, also set var["p"]
}
}
else {
onChangeExists = triggerEvent(onChange, mdl->setValueRowNr, true); //init, also set var["p"]
}

if (onChangeExists)
ppf("initValue onChange %s.%s <- %s\n", pid(), id(), valueString().c_str());
}
}
return false;
}

SysModModel::SysModModel() :SysModule("Model") {
model = new JsonDocument(&allocator);

Expand Down Expand Up @@ -517,8 +576,8 @@ void SysModModel::loop20ms() {
}

void SysModModel::loop1s() {
mdl->walkThroughModel([](JsonObject var) {
Variable(var).triggerEvent(onLoop1s);
mdl->walkThroughModel([](Variable variable) {
variable.triggerEvent(onLoop1s);
return false; //don't stop
});
}
Expand Down Expand Up @@ -571,7 +630,84 @@ void SysModModel::cleanUpModel(Variable parent, bool oPos, bool ro) {
}
}

bool SysModModel::walkThroughModel(std::function<bool(JsonObject)> fun, JsonObject parent) {
Variable SysModModel::initVar(Variable parent, const char * id, const char * type, bool readOnly, VarEvent varEvent) {
const char * parentId = parent.var["id"];
if (!parentId) parentId = "m"; //m=module
JsonObject var = mdl->findVar(parentId, id);
Variable variable = Variable(var);

//create new var
if (var.isNull()) {
// ppf("initVar new %s: %s.%s\n", type, parentId, id); //parentId not null otherwise crash
if (parent.var.isNull()) {
JsonArray vars = mdl->model->as<JsonArray>();
var = vars.add<JsonObject>();
} else {
if (parent.var["n"].isNull()) parent.var["n"].to<JsonArray>(); //TO!!! if parent exist and no "n" array, create it
var = parent.var["n"].add<JsonObject>();
// serializeJson(model, Serial);Serial.println();
}
var["id"] = JsonString(id, JsonString::Copied);
}
// else {
// ppf("initVar Var %s->%s already defined\n", modelParentId, id);
// }

if (!var.isNull()) {
if (var["type"].isNull() || var["type"] != type) {
var["type"] = JsonString(type, JsonString::Copied);
// print->printJson("initVar set type", var);
}

variable = Variable(var);

var["pid"] = parentId;

if (var["ro"].isNull() || variable.readOnly() != readOnly) variable.readOnly(readOnly);

//set order. make order negative to check if not obsolete, see cleanUpModel
if (variable.order() >= 1000) //predefined! (modules) - positive as saved in model.json
variable.order( -variable.order()); //leave the order as is
else {
if (!parent.var.isNull() && Variable(parent).order() >= 0) // if checks on the parent already done so vars added later, e.g. controls, will be autochecked
variable.order( mdl->varCounter++); //redefine order
else
variable.order( -mdl->varCounter++); //redefine order
}

//if varEvent, add it to the list
if (varEvent) {
//if fun already in ucFunctions then reuse, otherwise add new fun in ucFunctions
//lambda update: when replacing typedef void(*UCFun)(JsonObject); with typedef std::function<void(JsonObject)> UCFun; this gives error:
// mismatched types 'T*' and 'std::function<void(ArduinoJson::V6213PB2::JsonObject)>' { return *__it == _M_value; }
// it also looks like functions are not added more then once anyway
// std::vector<UCFun>::iterator itr = find(ucFunctions.begin(), ucFunctions.end(), varEvent);
// if (itr!=ucFunctions.end()) //found
// var["varEvent"] = distance(ucFunctions.begin(), itr); //assign found function
// else { //not found
mdl->varEvents.push_back(varEvent); //add new function
var["fun"] = mdl->varEvents.size()-1;
// }

if (varEvent(var, UINT8_MAX, onLoop)) { //test run if it supports loop
//no need to check if already in...
VarLoop loop;
loop.loopFun = varEvent;
loop.var = var;

ui->loopFunctions.push_back(loop);
var["loopFun"] = ui->loopFunctions.size()-1;
// ppf("iObject loopFun %s %u %u %d %d\n", variable.id());
}
}
}
else
ppf("initVar could not find or create var %s with %s\n", id, type);

return variable;
}

bool SysModModel::walkThroughModel(std::function<bool(Variable)> fun, JsonObject parent) {
JsonArray root;
if (parent.isNull())
root = model->as<JsonArray>();
Expand All @@ -580,7 +716,7 @@ bool SysModModel::walkThroughModel(std::function<bool(JsonObject)> fun, JsonObje

for (JsonObject var : root) {
// ppf(" %s", var["id"].as<String>());
if (fun(var)) return true;
if (fun(Variable(var))) return true;

if (!var["n"].isNull()) {
if (walkThroughModel(fun, var)) return true;
Expand Down
23 changes: 13 additions & 10 deletions src/Sys/SysModModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,10 @@ class Variable {
bool findOptionsTextRec(JsonVariant options, uint8_t * startValue, uint8_t value, JsonString *groupName, JsonString *optionName, JsonString parentGroup = JsonString());

//setValue for JsonVariants (extract the StarMod supported types)
JsonObject setValueJV(JsonVariant value, uint8_t rowNr = UINT8_MAX);
void setValueJV(JsonVariant value, uint8_t rowNr = UINT8_MAX);

template <typename Type>
JsonObject setValue(Type value, uint8_t rowNr = UINT8_MAX) {
void setValue(Type value, uint8_t rowNr = UINT8_MAX) {
bool changed = false;

if (rowNr == UINT8_MAX) { //normal situation
Expand Down Expand Up @@ -319,15 +319,16 @@ class Variable {
}

if (changed) triggerEvent(onChange, rowNr);

return var;
}

//Set value with argument list
JsonObject setValueF(const char * format = nullptr, ...);
void setValueF(const char * format = nullptr, ...);

JsonVariant getValue(uint8_t rowNr = UINT8_MAX);

//gives a variable an initital value returns true if setValue must be called
bool initValue(int min = 0, int max = 255, int pointer = 0);

}; //class Variable

typedef std::function<void(Variable)> FindFun;
Expand Down Expand Up @@ -356,20 +357,22 @@ class SysModModel: public SysModule {
void setup();
void loop20ms();
void loop1s();


//adds a variable to the model
Variable initVar(Variable parent, const char * id, const char * type, bool readOnly = true, VarEvent varEvent = nullptr);

//scan all vars in the model and remove vars where var["o"] is negative or positive, if ro then remove ro values
void cleanUpModel(Variable parent = Variable(), bool oPos = true, bool ro = false);

//sets the value of var with id
template <typename Type>
JsonObject setValue(const char * pid, const char * id, Type value, uint8_t rowNr = UINT8_MAX) {
void setValue(const char * pid, const char * id, Type value, uint8_t rowNr = UINT8_MAX) {
JsonObject var = findVar(pid, id);
if (!var.isNull()) {
return Variable(var).setValue(value, rowNr);
Variable(var).setValue(value, rowNr);
}
else {
ppf("setValue var %s.%s not found\n", pid, id);
return JsonObject();
}
}

Expand All @@ -385,7 +388,7 @@ class SysModModel: public SysModule {
}

//returns the var defined by id (parent to recursively call findVar)
bool walkThroughModel(std::function<bool(JsonObject)> fun, JsonObject parent = JsonObject());
bool walkThroughModel(std::function<bool(Variable)> fun, JsonObject parent = JsonObject());
JsonObject findVar(const char * pid, const char * id, JsonObject parent = JsonObject());
void findVars(const char * id, bool value, FindFun fun, JsonArray parent = JsonArray());

Expand Down
77 changes: 0 additions & 77 deletions src/Sys/SysModUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,83 +65,6 @@ void SysModUI::loop20ms() { //never more then 50 times a second!
}
}

Variable SysModUI::initVar(Variable parent, const char * id, const char * type, bool readOnly, VarEvent varEvent) {
const char * parentId = parent.var["id"];
if (!parentId) parentId = "m"; //m=module
JsonObject var = mdl->findVar(parentId, id);
Variable variable = Variable(var);

//create new var
if (var.isNull()) {
// ppf("initVar new %s: %s.%s\n", type, parentId, id); //parentId not null otherwise crash
if (parent.var.isNull()) {
JsonArray vars = mdl->model->as<JsonArray>();
var = vars.add<JsonObject>();
} else {
if (parent.var["n"].isNull()) parent.var["n"].to<JsonArray>(); //TO!!! if parent exist and no "n" array, create it
var = parent.var["n"].add<JsonObject>();
// serializeJson(model, Serial);Serial.println();
}
var["id"] = JsonString(id, JsonString::Copied);
}
// else {
// ppf("initVar Var %s->%s already defined\n", modelParentId, id);
// }

if (!var.isNull()) {
if (var["type"].isNull() || var["type"] != type) {
var["type"] = JsonString(type, JsonString::Copied);
// print->printJson("initVar set type", var);
}

variable = Variable(var);

var["pid"] = parentId;

if (var["ro"].isNull() || variable.readOnly() != readOnly) variable.readOnly(readOnly);

//set order. make order negative to check if not obsolete, see cleanUpModel
if (variable.order() >= 1000) //predefined! (modules) - positive as saved in model.json
variable.order( -variable.order()); //leave the order as is
else {
if (!parent.var.isNull() && Variable(parent).order() >= 0) // if checks on the parent already done so vars added later, e.g. controls, will be autochecked
variable.order( mdl->varCounter++); //redefine order
else
variable.order( -mdl->varCounter++); //redefine order
}

//if varEvent, add it to the list
if (varEvent) {
//if fun already in ucFunctions then reuse, otherwise add new fun in ucFunctions
//lambda update: when replacing typedef void(*UCFun)(JsonObject); with typedef std::function<void(JsonObject)> UCFun; this gives error:
// mismatched types 'T*' and 'std::function<void(ArduinoJson::V6213PB2::JsonObject)>' { return *__it == _M_value; }
// it also looks like functions are not added more then once anyway
// std::vector<UCFun>::iterator itr = find(ucFunctions.begin(), ucFunctions.end(), varEvent);
// if (itr!=ucFunctions.end()) //found
// var["varEvent"] = distance(ucFunctions.begin(), itr); //assign found function
// else { //not found
mdl->varEvents.push_back(varEvent); //add new function
var["fun"] = mdl->varEvents.size()-1;
// }

if (varEvent(var, UINT8_MAX, onLoop)) { //test run if it supports loop
//no need to check if already in...
VarLoop loop;
loop.loopFun = varEvent;
loop.var = var;

loopFunctions.push_back(loop);
var["loopFun"] = loopFunctions.size()-1;
// ppf("iObject loopFun %s %u %u %d %d\n", Variable(var).id());
}
}
}
else
ppf("initVar could not find or create var %s with %s\n", id, type);

return variable;
}

void SysModUI::processJson(JsonVariant json) {
if (json.is<JsonObject>()) //should be
{
Expand Down
Loading

0 comments on commit 0b96d0e

Please sign in to comment.