diff --git a/apps/aqhome-react/units/0BUILD b/apps/aqhome-react/units/0BUILD index 5c9148c..fde3420 100644 --- a/apps/aqhome-react/units/0BUILD +++ b/apps/aqhome-react/units/0BUILD @@ -37,7 +37,7 @@ - u_or.h + u_logical.c u_passthrough.h u_varchanges.h u_valuefilter.h @@ -47,11 +47,13 @@ u_stabilize.h u_valueset.h u_zeroposnegstring.h + u_module.h + u_module_p.h $(local/typefiles) - u_or.c + u_logical.c u_passthrough.c u_varchanges.c u_valuefilter.c @@ -61,6 +63,7 @@ u_stabilize.c u_valueset.c u_zeroposnegstring.c + u_module.c diff --git a/apps/aqhome-react/units/u_logical.c b/apps/aqhome-react/units/u_logical.c new file mode 100644 index 0000000..2f32e7a --- /dev/null +++ b/apps/aqhome-react/units/u_logical.c @@ -0,0 +1,256 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2024 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "./u_logical.h" + +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define AQHOMEREACT_UNIT_LOGICAL_INSLOT_INPUT 0 +#define AQHOMEREACT_UNIT_LOGICAL_INSLOT_AUTOINPUT 100 + +#define AQHOMEREACT_UNIT_LOGICAL_OUTSLOT_RESULT 0 + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static AQHREACT_UNIT *_unitLogical_new(AQHOME_REACT *aqh); +static int _cbProcessOr(AQHREACT_UNIT *unit); +static int _cbProcessAnd(AQHREACT_UNIT *unit); +static int _cbProcessXor(AQHREACT_UNIT *unit); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + + +AQHREACT_UNIT *AqHomeReact_UnitOr_new(AQHOME_REACT *aqh) +{ + AQHREACT_UNIT *unit; + + unit=_unitLogical_new(aqh); + AQHREACT_Unit_SetName(unit, "or"); + AQHREACT_Unit_SetDescription(unit, "Logical OR inputs"); + AQHREACT_Unit_SetProcessFn(unit, _cbProcessOr); + return unit; +} + + + +AQHREACT_UNIT *AqHomeReact_UnitAnd_new(AQHOME_REACT *aqh) +{ + AQHREACT_UNIT *unit; + + unit=_unitLogical_new(aqh); + AQHREACT_Unit_SetName(unit, "and"); + AQHREACT_Unit_SetDescription(unit, "Logical AND inputs"); + AQHREACT_Unit_SetProcessFn(unit, _cbProcessAnd); + return unit; +} + + + +AQHREACT_UNIT *AqHomeReact_UnitXor_new(AQHOME_REACT *aqh) +{ + AQHREACT_UNIT *unit; + + unit=_unitLogical_new(aqh); + AQHREACT_Unit_SetName(unit, "xor"); + AQHREACT_Unit_SetDescription(unit, "Logical XOR inputs"); + AQHREACT_Unit_SetProcessFn(unit, _cbProcessXor); + return unit; +} + + + + +AQHREACT_UNIT *_unitLogical_new(AQHOME_REACT *aqh) +{ + AQHREACT_UNIT *unit; + AQHREACT_OUTPUT_SLOT *outputSlot; + AQHREACT_INPUT_SLOT *inputSlot; + + unit=AQHREACT_Unit_new(aqh); + AQHREACT_Unit_SetName(unit, "or"); + AQHREACT_Unit_SetDescription(unit, "Logical OR inputs"); + + AQHREACT_Unit_SetNextInputSlotId(unit, AQHOMEREACT_UNIT_LOGICAL_INSLOT_AUTOINPUT); /* for auto-gen multi-slots */ + + outputSlot=AQHREACT_OutputSlot_new(); + AQHREACT_OutputSlot_SetName(outputSlot, "output"); + AQHREACT_OutputSlot_SetIdForUnit(outputSlot, AQHOMEREACT_UNIT_LOGICAL_OUTSLOT_RESULT); + AQHREACT_OutputSlot_SetEmittedDataType(outputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE); + AQHREACT_Unit_AddOutputSlot(unit, outputSlot); + + inputSlot=AQHREACT_InputSlot_new(); + AQHREACT_InputSlot_SetName(inputSlot, "input"); + AQHREACT_InputSlot_SetIdForUnit(inputSlot, AQHOMEREACT_UNIT_LOGICAL_INSLOT_INPUT); + AQHREACT_InputSlot_SetAcceptedDataType(inputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE); + AQHREACT_InputSlot_AddFlags(inputSlot, AQHREACT_UNIT_FLAGS_MULTI); + AQHREACT_Unit_AddInputSlot(unit, inputSlot); + + return unit; +} + + + +int _cbProcessOr(AQHREACT_UNIT *unit) +{ + if (unit && AQHREACT_Unit_InputHasChanged(unit)) { + AQHREACT_INPUT_SLOT_LIST *inputSlotList; + + inputSlotList=AQHREACT_Unit_GetInputSlots(unit); + if (inputSlotList) { + const AQHREACT_INPUT_SLOT *inputSlot; + int result=0; + + inputSlot=AQHREACT_InputSlot_List_First(inputSlotList); + while(inputSlot) { + const char *slotName; + const AQHREACT_DATAOBJECT *dataObject; + + slotName=AQHREACT_InputSlot_GetName(inputSlot); + dataObject=AQHREACT_InputSlot_GetCurrentDataObject(inputSlot); + if (dataObject) { + if (AQHREACT_DataObject_GetDataType(dataObject)==AQHREACT_DATAOBJECTTYPE_DOUBLE) { + double d; + + d=AQHREACT_DataObject_GetDoubleData(dataObject); + if (d>0.0) + result|=1; + } + else { + DBG_ERROR(NULL, "Data at input slot \"%s\" isn't DOUBLE, ignoring", slotName?slotName:""); + } + } + else { + DBG_ERROR(NULL, "Data at input slot \"%s\" has not current data, ignoring", slotName?slotName:""); + } + inputSlot=AQHREACT_InputSlot_List_Next(inputSlot); + } + + AQHREACT_Unit_ClearChangeFlagsInUnitAndInputSlots(unit); + AQHREACT_Unit_OutputDoubleData(unit, AQHOMEREACT_UNIT_LOGICAL_OUTSLOT_RESULT, result?1.0:0.0); + return 1; + } + } + + return 0; +} + + + +int _cbProcessAnd(AQHREACT_UNIT *unit) +{ + if (unit && AQHREACT_Unit_InputHasChanged(unit)) { + AQHREACT_INPUT_SLOT_LIST *inputSlotList; + + inputSlotList=AQHREACT_Unit_GetInputSlots(unit); + if (inputSlotList) { + const AQHREACT_INPUT_SLOT *inputSlot; + int result=1; + + inputSlot=AQHREACT_InputSlot_List_First(inputSlotList); + while(inputSlot) { + const char *slotName; + const AQHREACT_DATAOBJECT *dataObject; + + slotName=AQHREACT_InputSlot_GetName(inputSlot); + dataObject=AQHREACT_InputSlot_GetCurrentDataObject(inputSlot); + if (dataObject) { + if (AQHREACT_DataObject_GetDataType(dataObject)==AQHREACT_DATAOBJECTTYPE_DOUBLE) { + double d; + + d=AQHREACT_DataObject_GetDoubleData(dataObject); + if (!(d>0.0)) + result=0; + } + else { + DBG_ERROR(NULL, "Data at input slot \"%s\" isn't DOUBLE, ignoring", slotName?slotName:""); + } + } + else { + DBG_ERROR(NULL, "Data at input slot \"%s\" has not current data, ignoring", slotName?slotName:""); + } + inputSlot=AQHREACT_InputSlot_List_Next(inputSlot); + } + + AQHREACT_Unit_ClearChangeFlagsInUnitAndInputSlots(unit); + AQHREACT_Unit_OutputDoubleData(unit, AQHOMEREACT_UNIT_LOGICAL_OUTSLOT_RESULT, result?1.0:0.0); + return 1; + } + } + + return 0; +} + + + +int _cbProcessXor(AQHREACT_UNIT *unit) +{ + if (unit && AQHREACT_Unit_InputHasChanged(unit)) { + AQHREACT_INPUT_SLOT_LIST *inputSlotList; + + inputSlotList=AQHREACT_Unit_GetInputSlots(unit); + if (inputSlotList) { + const AQHREACT_INPUT_SLOT *inputSlot; + int result=0; + + inputSlot=AQHREACT_InputSlot_List_First(inputSlotList); + while(inputSlot) { + const char *slotName; + const AQHREACT_DATAOBJECT *dataObject; + + slotName=AQHREACT_InputSlot_GetName(inputSlot); + dataObject=AQHREACT_InputSlot_GetCurrentDataObject(inputSlot); + if (dataObject) { + if (AQHREACT_DataObject_GetDataType(dataObject)==AQHREACT_DATAOBJECTTYPE_DOUBLE) { + double d; + + d=AQHREACT_DataObject_GetDoubleData(dataObject); + if (d>0.0) + result^=1; /*only xor when >0.0, otherwise no change (x XOR 0 is still x) */ + } + else { + DBG_ERROR(NULL, "Data at input slot \"%s\" isn't DOUBLE, ignoring", slotName?slotName:""); + } + } + else { + DBG_ERROR(NULL, "Data at input slot \"%s\" has not current data, ignoring", slotName?slotName:""); + } + inputSlot=AQHREACT_InputSlot_List_Next(inputSlot); + } + + AQHREACT_Unit_ClearChangeFlagsInUnitAndInputSlots(unit); + AQHREACT_Unit_OutputDoubleData(unit, AQHOMEREACT_UNIT_LOGICAL_OUTSLOT_RESULT, result?1.0:0.0); + return 1; + } + } + + return 0; +} + + + diff --git a/apps/aqhome-react/units/u_or.h b/apps/aqhome-react/units/u_logical.h similarity index 74% rename from apps/aqhome-react/units/u_or.h rename to apps/aqhome-react/units/u_logical.h index bd7b1aa..7f44ef8 100644 --- a/apps/aqhome-react/units/u_or.h +++ b/apps/aqhome-react/units/u_logical.h @@ -6,8 +6,8 @@ * should have received along with this file. ****************************************************************************/ -#ifndef AQHOMEREACT_U_OR_H -#define AQHOMEREACT_U_OR_H +#ifndef AQHOMEREACT_U_LOGICAL_H +#define AQHOMEREACT_U_LOGICAL_H #include "aqhome-react/aqhome_react.h" @@ -15,6 +15,8 @@ AQHREACT_UNIT *AqHomeReact_UnitOr_new(AQHOME_REACT *aqh); +AQHREACT_UNIT *AqHomeReact_UnitAnd_new(AQHOME_REACT *aqh); +AQHREACT_UNIT *AqHomeReact_UnitXor_new(AQHOME_REACT *aqh); diff --git a/apps/aqhome-react/units/u_module.c b/apps/aqhome-react/units/u_module.c new file mode 100644 index 0000000..64478e6 --- /dev/null +++ b/apps/aqhome-react/units/u_module.c @@ -0,0 +1,817 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2024 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "./u_module_p.h" + +#include +#include +#include + +//TODO: set params + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +GWEN_INHERIT(AQHREACT_UNIT, AQHREACT_UNIT_MODULE); + +GWEN_LIST_FUNCTIONS(MODULE_PROXY_DESCR, ModuleProxyDescr); + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void GWENHYWFAR_CB _freeData(void *bp, void *p); +static void _cbInputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject); +static void _cbOutputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject); +static AQHREACT_PARAM *_cbGetParamByName(const AQHREACT_UNIT *unit, const char *paramName); +static int _cbProcess(AQHREACT_UNIT *unit); + +static void _readProxyFromXml(AQHREACT_UNIT *unit, + GWEN_XMLNODE *xmlNode, + MODULE_PROXY_DESCR_LIST *proxyDescrList, + const char *mainGroupName, + const char *groupName, + const char *nameProperty, + const char *targetObjectProperty, + const char *targetNameProperty); +static void _readInputSlotsFromXml(AQHOME_REACT *aqh, AQHREACT_UNIT *unit, GWEN_XMLNODE *xmlNode); +static void _readOutputSlotsFromXml(AQHOME_REACT *aqh, AQHREACT_UNIT *unit, GWEN_XMLNODE *xmlNode); +static int _finishInSlots(AQHREACT_UNIT *unit); +static int _finishOutSlots(AQHREACT_UNIT *unit); +static int _finishParams(AQHREACT_UNIT *unit); +static void _readUnitsFromXml(AQHOME_REACT *aqh, AQHREACT_UNIT *unit, GWEN_XMLNODE *xmlNode); +static AQHREACT_UNIT *_readOneUnitFromXml(AQHOME_REACT *aqh, AQHREACT_UNIT *parentUnit, GWEN_XMLNODE *xmlNode); +static int _readParamsFromXml(AQHREACT_UNIT *unit, GWEN_XMLNODE *xmlNodeUnit, const char *mainGroupName); +static int _readParamFromXml(AQHREACT_UNIT *unit, GWEN_XMLNODE *paramNode); +static int _setParamDataFromString(AQHREACT_PARAM *param, const char *value); +static int _readLinksFromXml(AQHOME_REACT *aqh, AQHREACT_UNIT *unit, GWEN_XMLNODE *xmlNode); +static int _readLinkFromXml(AQHOME_REACT *aqh, AQHREACT_UNIT *unit, GWEN_XMLNODE *linkNode); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + + +/* ------------------------------------------------------------------------------------------------ + * ModuleProxyDescr + * ------------------------------------------------------------------------------------------------ + */ + +MODULE_PROXY_DESCR *ModuleProxyDescr_new(const char *name, const char *targetObject, const char *targetName) +{ + MODULE_PROXY_DESCR *pd; + + GWEN_NEW_OBJECT(MODULE_PROXY_DESCR, pd); + GWEN_LIST_INIT(MODULE_PROXY_DESCR, pd); + pd->name=name?strdup(name):NULL; + pd->targetObject=targetObject?strdup(targetObject):NULL; + pd->targetName=targetName?strdup(targetName):NULL; + + return pd; +} + + + +void ModuleProxyDescr_free(MODULE_PROXY_DESCR *pd) +{ + if (pd) { + GWEN_LIST_FINI(MODULE_PROXY_DESCR, pd); + free(pd->targetName); + free(pd->targetObject); + free(pd->name); + GWEN_FREE_OBJECT(pd); + } +} + + + +MODULE_PROXY_DESCR *ModuleProxyDescr_List_FindByName(const MODULE_PROXY_DESCR_LIST *pdList, const char *s) +{ + if (pdList && s && *s) { + MODULE_PROXY_DESCR *pd; + + pd=ModuleProxyDescr_List_First(pdList); + while(pd) { + if (pd->name && strcasecmp(pd->name, s)==0) + return pd; + pd=ModuleProxyDescr_List_Next(pd); + } + } + + return NULL; +} + + + + + +/* ------------------------------------------------------------------------------------------------ + * AqHomeReact_UnitModule + * ------------------------------------------------------------------------------------------------ + */ + +AQHREACT_UNIT *AqHomeReact_UnitModule_new(AQHOME_REACT *aqh) +{ + AQHREACT_UNIT *unit; + AQHREACT_UNIT_MODULE *xunit; + + unit=AQHREACT_Unit_new(aqh); + GWEN_NEW_OBJECT(AQHREACT_UNIT_MODULE, xunit); + GWEN_INHERIT_SETDATA(AQHREACT_UNIT, AQHREACT_UNIT_MODULE, unit, xunit, _freeData); + + xunit->paramProxyList=ModuleProxyDescr_List_new(); + xunit->inSlotProxyList=ModuleProxyDescr_List_new(); + xunit->outSlotProxyList=ModuleProxyDescr_List_new(); + xunit->unitList=AQHREACT_Unit_List_new(); + + AQHREACT_Unit_SetInputDataFn(unit, _cbInputData); + AQHREACT_Unit_SetOutputDataFn(unit, _cbOutputData); + AQHREACT_Unit_SetGetParamByNameFn(unit, _cbGetParamByName); + AQHREACT_Unit_SetProcessFn(unit, _cbProcess); + + return unit; +} + + + +void _freeData(void *bp, void *p) +{ + AQHREACT_UNIT_MODULE *xunit; + + xunit=(AQHREACT_UNIT_MODULE*) p; + + AQHREACT_Unit_List_free(xunit->unitList); + ModuleProxyDescr_List_free(xunit->outSlotProxyList); + ModuleProxyDescr_List_free(xunit->inSlotProxyList); + ModuleProxyDescr_List_free(xunit->paramProxyList); + + GWEN_FREE_OBJECT(xunit); +} + + + +AQHREACT_UNIT *AqHomeReact_UnitModule_fromXml(AQHOME_REACT *aqh, GWEN_XMLNODE *xmlNode) +{ + const char *t; + + t=GWEN_XMLNode_GetProperty(xmlNode, "type", NULL); + if (t && *t) { + AQHREACT_UNIT *unit; + AQHREACT_UNIT_MODULE *xunit; + int rv; + + unit=AqHomeReact_UnitModule_new(aqh); + xunit=(AQHREACT_UNIT_MODULE*)GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_MODULE, unit); + AQHREACT_Unit_SetName(unit, t); + + _readProxyFromXml(unit, xmlNode, xunit->paramProxyList, "paramdefs", "param", "name", "targetModule", "targetParam"); + + _readInputSlotsFromXml(aqh, unit, xmlNode); + _readOutputSlotsFromXml(aqh, unit, xmlNode); + + _readUnitsFromXml(aqh, unit, xmlNode); + + rv=_finishInSlots(unit); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + AQHREACT_Unit_free(unit); + return NULL; + } + rv=_finishOutSlots(unit); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + AQHREACT_Unit_free(unit); + return NULL; + } + + rv=_finishParams(unit); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + AQHREACT_Unit_free(unit); + return NULL; + } + + rv=_readParamsFromXml(unit, xmlNode, "paramDefs"); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + AQHREACT_Unit_free(unit); + return NULL; + } + + rv=_readLinksFromXml(aqh, unit, xmlNode); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + AQHREACT_Unit_free(unit); + return NULL; + } + + return unit; + } + else { + DBG_ERROR(NULL, "No \"type\" property in xml node for module"); + return NULL; + } +} + + + +void _cbInputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject) +{ + AQHREACT_UNIT_MODULE *xunit; + + xunit=(AQHREACT_UNIT_MODULE*)GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_MODULE, unit); + if (xunit) { + AQHREACT_INPUT_SLOT *slot; + + slot=AQHREACT_Unit_GetInputSlotByIdForUnit(unit, slotIdForUnit); + if (slot) { + const char *slotName; + const MODULE_PROXY_DESCR *pd; + + slotName=AQHREACT_InputSlot_GetName(slot); + pd=ModuleProxyDescr_List_FindByName(xunit->inSlotProxyList, slotName); + if (pd) + AQHREACT_Unit_InputData(pd->targetObjectPtr, pd->targetIdForModule, dataObject); + } + } +} + + + +void _cbOutputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject) +{ + AQHREACT_UNIT_MODULE *xunit; + + xunit=(AQHREACT_UNIT_MODULE*)GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_MODULE, unit); + if (xunit) { + AQHREACT_OUTPUT_SLOT *slot; + + slot=AQHREACT_Unit_GetOutputSlotByIdForUnit(unit, slotIdForUnit); + if (slot) { + const char *slotName; + const MODULE_PROXY_DESCR *pd; + + slotName=AQHREACT_OutputSlot_GetName(slot); + pd=ModuleProxyDescr_List_FindByName(xunit->outSlotProxyList, slotName); + if (pd) + AQHREACT_Unit_OutputData(pd->targetObjectPtr, pd->targetIdForModule, dataObject); + } + } +} + + + +AQHREACT_PARAM *_cbGetParamByName(const AQHREACT_UNIT *unit, const char *paramName) +{ + AQHREACT_UNIT_MODULE *xunit; + + xunit=(AQHREACT_UNIT_MODULE*)GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_MODULE, unit); + if (xunit) { + const MODULE_PROXY_DESCR *pd; + + pd=ModuleProxyDescr_List_FindByName(xunit->paramProxyList, paramName); + if (pd) + AQHREACT_Unit_GetParamByName(pd->targetObjectPtr, pd->targetName); + } + return NULL; +} + + + +int _cbProcess(AQHREACT_UNIT *unit) +{ + AQHREACT_UNIT_MODULE *xunit; + int result=0; + + xunit=(AQHREACT_UNIT_MODULE*)GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_MODULE, unit); + if (xunit) { + AQHREACT_UNIT *subUnit; + + subUnit=AQHREACT_Unit_List_First(xunit->unitList); + while(subUnit) { + int rv; + + rv=AQHREACT_Unit_Process(subUnit); + if (rv<0) + result=rv; + else if (result>=0) + result=rv; + subUnit=AQHREACT_Unit_List_Next(subUnit); + } + } + return result; +} + + + +void _readProxyFromXml(AQHREACT_UNIT *unit, + GWEN_XMLNODE *xmlNode, + MODULE_PROXY_DESCR_LIST *proxyDescrList, + const char *mainGroupName, + const char *groupName, + const char *nameProperty, + const char *targetObjectProperty, + const char *targetNameProperty) +{ + GWEN_XMLNODE *nGroup; + + nGroup=GWEN_XMLNode_FindFirstTag(xmlNode, mainGroupName, NULL, NULL); + if (nGroup) { + GWEN_XMLNODE *n; + + n=GWEN_XMLNode_FindFirstTag(nGroup, groupName, NULL, NULL); + while(n) { + const char *name; + const char *targetObject; + const char *targetName; + + name=GWEN_XMLNode_GetProperty(n, nameProperty, NULL); + targetObject=GWEN_XMLNode_GetProperty(n, targetObjectProperty, NULL); + targetName=GWEN_XMLNode_GetProperty(n, targetNameProperty, NULL); + + if (name && targetObject && targetName) { + MODULE_PROXY_DESCR *pd; + + pd=ModuleProxyDescr_new(name, targetObject, targetName); + ModuleProxyDescr_List_Add(pd, proxyDescrList); + } + else { + DBG_ERROR(NULL, "Incomplete entry in list \"%s\", ignoring", mainGroupName); + } + n=GWEN_XMLNode_FindNextTag(n, groupName, NULL, NULL); + } + } +} + + + +void _readInputSlotsFromXml(AQHOME_REACT *aqh, AQHREACT_UNIT *unit, GWEN_XMLNODE *xmlNode) +{ + AQHREACT_UNIT_MODULE *xunit; + GWEN_XMLNODE *nGroup; + + xunit=(AQHREACT_UNIT_MODULE*)GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_MODULE, unit); + + nGroup=GWEN_XMLNode_FindFirstTag(xmlNode, "inputSlots", NULL, NULL); + if (nGroup) { + GWEN_XMLNODE *n; + + n=GWEN_XMLNode_FindFirstTag(nGroup, "inputSlot", NULL, NULL); + while(n) { + const char *name; + const char *targetUnit; + const char *targetSlot; + int slotIdForUnit; + + name=GWEN_XMLNode_GetProperty(n, "name", NULL); + targetUnit=GWEN_XMLNode_GetProperty(n, "targetUnit", NULL); + targetSlot=GWEN_XMLNode_GetProperty(n, "targetSlot", NULL); + slotIdForUnit=GWEN_XMLNode_GetIntProperty(n, "idForUnit", 0); + + if (name && targetUnit && targetSlot) { + MODULE_PROXY_DESCR *pd; + AQHREACT_INPUT_SLOT *slot; + + pd=ModuleProxyDescr_new(name, targetUnit, targetSlot); /* set pd->targetObjectPtr later */ + ModuleProxyDescr_List_Add(pd, xunit->inSlotProxyList); + + slot=AQHREACT_InputSlot_new(); + AQHREACT_InputSlot_SetName(slot, name); + AQHREACT_InputSlot_SetIdForUnit(slot, slotIdForUnit); + AQHREACT_Unit_AddInputSlot(unit, slot); + } + else { + DBG_ERROR(NULL, "Incomplete input slot, ignoring"); + } + n=GWEN_XMLNode_FindNextTag(n, "inputSlot", NULL, NULL); + } + } +} + + + +void _readOutputSlotsFromXml(AQHOME_REACT *aqh, AQHREACT_UNIT *unit, GWEN_XMLNODE *xmlNode) +{ + AQHREACT_UNIT_MODULE *xunit; + GWEN_XMLNODE *nGroup; + + xunit=(AQHREACT_UNIT_MODULE*)GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_MODULE, unit); + + nGroup=GWEN_XMLNode_FindFirstTag(xmlNode, "outputSlots", NULL, NULL); + if (nGroup) { + GWEN_XMLNODE *n; + + n=GWEN_XMLNode_FindFirstTag(nGroup, "outputSlot", NULL, NULL); + while(n) { + const char *name; + const char *targetUnit; + const char *targetSlot; + int slotIdForUnit; + + name=GWEN_XMLNode_GetProperty(n, "name", NULL); + targetUnit=GWEN_XMLNode_GetProperty(n, "targetUnit", NULL); + targetSlot=GWEN_XMLNode_GetProperty(n, "targetSlot", NULL); + slotIdForUnit=GWEN_XMLNode_GetIntProperty(n, "idForUnit", 0); + + if (name && targetUnit && targetSlot) { + MODULE_PROXY_DESCR *pd; + AQHREACT_OUTPUT_SLOT *slot; + + pd=ModuleProxyDescr_new(name, targetUnit, targetSlot); /* set pd->targetObjectPtr later */ + ModuleProxyDescr_List_Add(pd, xunit->outSlotProxyList); + + slot=AQHREACT_OutputSlot_new(); + AQHREACT_OutputSlot_SetName(slot, name); + AQHREACT_OutputSlot_SetIdForUnit(slot, slotIdForUnit); + AQHREACT_Unit_AddOutputSlot(unit, slot); + } + else { + DBG_ERROR(NULL, "Incomplete output slot, ignoring"); + } + n=GWEN_XMLNode_FindNextTag(n, "outputSlot", NULL, NULL); + } + } +} + + + +int _finishInSlots(AQHREACT_UNIT *unit) +{ + AQHREACT_UNIT_MODULE *xunit; + MODULE_PROXY_DESCR *pd; + const char *unitName; + + xunit=(AQHREACT_UNIT_MODULE*)GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_MODULE, unit); + unitName=AQHREACT_Unit_GetName(unit); + pd=ModuleProxyDescr_List_First(xunit->inSlotProxyList); + while(pd) { + AQHREACT_UNIT *subUnit; + const AQHREACT_INPUT_SLOT *subUnitSlot; + AQHREACT_INPUT_SLOT *moduleSlot; + + subUnit=AQHREACT_Unit_List_GetById(xunit->unitList, pd->targetObject); + if (subUnit==NULL) { + DBG_ERROR(NULL, "Subunit \"%s\" not found for input slot", pd->targetObject); + return GWEN_ERROR_BAD_DATA; + } + pd->targetObjectPtr=subUnit; + + moduleSlot=AQHREACT_Unit_GetInputSlotByName(subUnit, pd->name); + if (moduleSlot==NULL) { + DBG_ERROR(NULL, "Unit %s: Input slot \"%s\" not defined", unitName, pd->targetName); + return GWEN_ERROR_BAD_DATA; + } + + subUnitSlot=AQHREACT_Unit_GetInputSlotByName(subUnit, pd->targetName); + if (subUnitSlot==NULL) { + DBG_ERROR(NULL, "Unit %s: Input slot \"%s\" not found for subunit \"%s\"", unitName, pd->targetName, pd->targetObject); + return GWEN_ERROR_BAD_DATA; + } + + AQHREACT_InputSlot_SetDescription(moduleSlot, AQHREACT_InputSlot_GetDescription(subUnitSlot)); + AQHREACT_InputSlot_SetFlags(moduleSlot, AQHREACT_InputSlot_GetFlags(subUnitSlot)); + AQHREACT_InputSlot_SetAcceptedDataType(moduleSlot, AQHREACT_InputSlot_GetAcceptedDataType(subUnitSlot)); + + pd->targetIdForModule=AQHREACT_InputSlot_GetIdForUnit(subUnitSlot); + + pd=ModuleProxyDescr_List_Next(pd); + } + + return 0; +} + + + +int _finishOutSlots(AQHREACT_UNIT *unit) +{ + AQHREACT_UNIT_MODULE *xunit; + MODULE_PROXY_DESCR *pd; + const char *unitName; + + xunit=(AQHREACT_UNIT_MODULE*)GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_MODULE, unit); + unitName=AQHREACT_Unit_GetName(unit); + pd=ModuleProxyDescr_List_First(xunit->outSlotProxyList); + while(pd) { + AQHREACT_UNIT *subUnit; + const AQHREACT_OUTPUT_SLOT *subUnitSlot; + AQHREACT_OUTPUT_SLOT *moduleSlot; + + subUnit=AQHREACT_Unit_List_GetById(xunit->unitList, pd->targetObject); + if (subUnit==NULL) { + DBG_ERROR(NULL, "Subunit \"%s\" not found for output slot", pd->targetObject); + return GWEN_ERROR_BAD_DATA; + } + pd->targetObjectPtr=subUnit; + + moduleSlot=AQHREACT_Unit_GetOutputSlotByName(subUnit, pd->name); + if (moduleSlot==NULL) { + DBG_ERROR(NULL, "Unit %s: Output slot \"%s\" not defined", unitName, pd->targetName); + return GWEN_ERROR_BAD_DATA; + } + + subUnitSlot=AQHREACT_Unit_GetOutputSlotByName(subUnit, pd->targetName); + if (subUnitSlot==NULL) { + DBG_ERROR(NULL, "Unit %s: Output slot \"%s\" not found for subunit \"%s\"", unitName, pd->targetName, pd->targetObject); + return GWEN_ERROR_BAD_DATA; + } + + AQHREACT_OutputSlot_SetDescription(moduleSlot, AQHREACT_OutputSlot_GetDescription(subUnitSlot)); + AQHREACT_OutputSlot_SetFlags(moduleSlot, AQHREACT_OutputSlot_GetFlags(subUnitSlot)); + AQHREACT_OutputSlot_SetEmittedDataType(moduleSlot, AQHREACT_OutputSlot_GetEmittedDataType(subUnitSlot)); + + pd->targetIdForModule=AQHREACT_OutputSlot_GetIdForUnit(subUnitSlot); + + pd=ModuleProxyDescr_List_Next(pd); + } + + return 0; +} + + + +int _finishParams(AQHREACT_UNIT *unit) +{ + AQHREACT_UNIT_MODULE *xunit; + MODULE_PROXY_DESCR *pd; + const char *unitName; + + xunit=(AQHREACT_UNIT_MODULE*)GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_MODULE, unit); + unitName=AQHREACT_Unit_GetName(unit); + pd=ModuleProxyDescr_List_First(xunit->paramProxyList); + while(pd) { + AQHREACT_UNIT *subUnit; + + subUnit=AQHREACT_Unit_List_GetById(xunit->unitList, pd->targetObject); + if (subUnit==NULL) { + DBG_ERROR(NULL, "Unit %s: Subunit \"%s\" not found for param \"%s\"", unitName, pd->targetObject, pd->name); + return GWEN_ERROR_BAD_DATA; + } + pd->targetObjectPtr=subUnit; + + pd=ModuleProxyDescr_List_Next(pd); + } + + return 0; +} + + + +void _readUnitsFromXml(AQHOME_REACT *aqh, AQHREACT_UNIT *unit, GWEN_XMLNODE *xmlNode) +{ + GWEN_XMLNODE *nGroup; + AQHREACT_UNIT_MODULE *xunit; + + xunit=(AQHREACT_UNIT_MODULE*)GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_MODULE, unit); + + nGroup=GWEN_XMLNode_FindFirstTag(xmlNode, "units", NULL, NULL); + if (nGroup) { + GWEN_XMLNODE *n; + + n=GWEN_XMLNode_FindFirstTag(nGroup, "unit", NULL, NULL); + while(n) { + AQHREACT_UNIT *subUnit; + + subUnit=_readOneUnitFromXml(aqh, unit, n); + if (subUnit) + AQHREACT_Unit_List_Add(subUnit, xunit->unitList); + else { + DBG_INFO(NULL, "Error reading unit from XML node"); + } + + n=GWEN_XMLNode_FindNextTag(n, "unit", NULL, NULL); + } + } +} + + + +AQHREACT_UNIT *_readOneUnitFromXml(AQHOME_REACT *aqh, AQHREACT_UNIT *parentUnit, GWEN_XMLNODE *xmlNode) +{ + const char *id; + const char *t; + + id=GWEN_XMLNode_GetProperty(xmlNode, "id", NULL); + t=GWEN_XMLNode_GetProperty(xmlNode, "type", NULL); + + if (id && t) { + AQHREACT_UNIT *subUnit; + int rv; + + subUnit=AqHomeReact_CreateUnitByName(aqh, t); + AQHREACT_Unit_SetId(subUnit, id); + rv=_readParamsFromXml(subUnit, xmlNode, "params"); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + AQHREACT_Unit_free(subUnit); + return NULL; + } + return subUnit; + } + else { + DBG_ERROR(NULL, "Incomplete unit, ignoring"); + return NULL; + } +} + + + +int _readParamsFromXml(AQHREACT_UNIT *unit, GWEN_XMLNODE *xmlNodeUnit, const char *mainGroupName) +{ + GWEN_XMLNODE *nGroup; + + nGroup=GWEN_XMLNode_FindFirstTag(xmlNodeUnit, mainGroupName, NULL, NULL); + if (nGroup) { + GWEN_XMLNODE *n; + + n=GWEN_XMLNode_FindFirstTag(nGroup, "param", NULL, NULL); + while(n) { + int rv; + + rv=_readParamFromXml(unit, n); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return rv; + } + n=GWEN_XMLNode_FindNextTag(n, "param", NULL, NULL); + } + } + return 0; +} + + + +int _readParamFromXml(AQHREACT_UNIT *unit, GWEN_XMLNODE *paramNode) +{ + const char *paramName; + + paramName=GWEN_XMLNode_GetProperty(paramNode, "name", NULL); + if (paramName && *paramName) { + AQHREACT_PARAM *param; + + param=AQHREACT_Unit_GetParamByName(unit, paramName); + if (param) { + const char *value; + + value=GWEN_XMLNode_GetCharValue(paramNode, NULL, NULL); + if (value && *value) { + int rv; + + rv=_setParamDataFromString(param, value); + if (rv<0) { + DBG_ERROR(NULL, "Error setting param data for param \"%s\" (%d)", paramName, rv); + return rv; + } + } /* if value */ + } + else { + DBG_ERROR(NULL, "No param name \"%s\" in unit", paramName); + return GWEN_ERROR_BAD_DATA; + } + } + + return 0; +} + + + +int _setParamDataFromString(AQHREACT_PARAM *param, const char *value) +{ + if (value && *value) { + int dataType; + + dataType=AQHREACT_Param_GetDataType(param); + switch(dataType) { + case AQHREACT_DATAOBJECTTYPE_DOUBLE: + { + int rv; + double valueAsDouble; + + rv=GWEN_Text_StringToDouble(value, &valueAsDouble); + if (rv<0) { + DBG_ERROR(NULL, "Not a DOUBLE value for param \"%s\" [%s]", AQHREACT_Param_GetName(param), value); + return rv; + } + AQHREACT_Param_SetDoubleValue(param, valueAsDouble); + break; + } + case AQHREACT_DATAOBJECTTYPE_STRING: + default: + AQHREACT_Param_SetStringValue(param, value); + break; + } + } + return 0; +} + + + +int _readLinksFromXml(AQHOME_REACT *aqh, AQHREACT_UNIT *unit, GWEN_XMLNODE *xmlNode) +{ + GWEN_XMLNODE *nGroup; + + nGroup=GWEN_XMLNode_FindFirstTag(xmlNode, "links", NULL, NULL); + if (nGroup) { + GWEN_XMLNODE *n; + + n=GWEN_XMLNode_FindFirstTag(nGroup, "link", NULL, NULL); + while(n) { + int rv; + + rv=_readLinkFromXml(aqh, unit, n); + if (rv<0) { + DBG_ERROR(NULL, "Error reading link in net \"%s\" (%d)", AQHREACT_Unit_GetName(unit), rv); + return GWEN_ERROR_BAD_DATA; + } + n=GWEN_XMLNode_FindNextTag(n, "link", NULL, NULL); + } + } + return 0; +} + + + +int _readLinkFromXml(AQHOME_REACT *aqh, AQHREACT_UNIT *unit, GWEN_XMLNODE *linkNode) +{ + AQHREACT_UNIT_MODULE *xunit; + const char *sourceUnitName; + const char *sourceSlotName; + const char *targetUnitName; + const char *targetSlotName; + AQHREACT_UNIT *sourceUnit; + AQHREACT_UNIT *targetUnit; + AQHREACT_INPUT_SLOT *inputSlot; + AQHREACT_OUTPUT_SLOT *outputSlot; + AQHREACT_LINK *link; + + xunit=(AQHREACT_UNIT_MODULE*)GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_MODULE, unit); + + sourceUnitName=GWEN_XMLNode_GetProperty(linkNode, "sourceUnit", NULL); + sourceSlotName=GWEN_XMLNode_GetProperty(linkNode, "sourceSlot", NULL); + targetUnitName=GWEN_XMLNode_GetProperty(linkNode, "targetUnit", NULL); + targetSlotName=GWEN_XMLNode_GetProperty(linkNode, "targetSlot", NULL); + + if (!(sourceUnitName && *sourceUnitName && sourceSlotName && *sourceSlotName && + targetUnitName && *targetUnitName && targetSlotName && *targetSlotName)) { + DBG_ERROR(NULL, + "Link in net \"%s\" needs properties sourceUnit, sourceSlot, targetUnit and targetSlot", + AQHREACT_Unit_GetName(unit)); + return GWEN_ERROR_BAD_DATA; + } + + sourceUnit=AQHREACT_Unit_List_GetById(xunit->unitList, sourceUnitName); + if (sourceUnit==NULL) + sourceUnit=AqHomeReact_FindUnitByNetNameAndUnitId(aqh, NULL, sourceUnitName); + if (sourceUnit==NULL) { + DBG_ERROR(NULL, "Source unit \"%s\" not found", sourceUnitName); + return GWEN_ERROR_NOT_FOUND; + } + outputSlot=AQHREACT_Unit_GetOutputSlotByName(sourceUnit, sourceSlotName); + if (outputSlot==NULL) { + DBG_ERROR(NULL, "Output slot \"%s\" not found for source unit \"%s\"", sourceSlotName, sourceUnitName); + return GWEN_ERROR_NOT_FOUND; + } + + targetUnit=AQHREACT_Unit_List_GetById(xunit->unitList, targetUnitName); + if (targetUnit==NULL) + targetUnit=AqHomeReact_FindUnitByNetNameAndUnitId(aqh, NULL, targetUnitName); + if (targetUnit==NULL) { + DBG_ERROR(NULL, "Target unit \"%s\" not found", targetUnitName); + return GWEN_ERROR_NOT_FOUND; + } + inputSlot=AQHREACT_Unit_GetOrCreateUnusedInputSlotByName(targetUnit, targetSlotName); + if (inputSlot==NULL) { + DBG_ERROR(NULL, "Input slot \"%s\" not found for target unit \"%s\"", targetSlotName, targetUnitName); + return GWEN_ERROR_NOT_FOUND; + } + + link=AQHREACT_Link_new(); + AQHREACT_Link_SetTargetUnitId(link, targetUnitName); + AQHREACT_Link_SetTargetUnit(link, targetUnit); + AQHREACT_Link_SetTargetInputSlotIdForUnit(link, AQHREACT_InputSlot_GetIdForUnit(inputSlot)); + AQHREACT_OutputSlot_AddLink(outputSlot, link); + return 0; +} + + + + + + diff --git a/apps/aqhome-react/units/u_module.h b/apps/aqhome-react/units/u_module.h new file mode 100644 index 0000000..d74479a --- /dev/null +++ b/apps/aqhome-react/units/u_module.h @@ -0,0 +1,29 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2024 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQHOMEREACT_U_MODULE_H +#define AQHOMEREACT_U_MODULE_H + + +#include "aqhome-react/aqhome_react.h" +#include "aqhome-react/types/unit.h" + +#include + + +AQHREACT_UNIT *AqHomeReact_UnitModule_new(AQHOME_REACT *aqh); + +AQHREACT_UNIT *AqHomeReact_UnitModule_fromXml(AQHOME_REACT *aqh, GWEN_XMLNODE *xmlNode); + + +#endif + + + + + diff --git a/apps/aqhome-react/units/u_module_p.h b/apps/aqhome-react/units/u_module_p.h new file mode 100644 index 0000000..ad0a477 --- /dev/null +++ b/apps/aqhome-react/units/u_module_p.h @@ -0,0 +1,58 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2024 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQHOMEREACT_U_MODULE_P_H +#define AQHOMEREACT_U_MODULE_P_H + + +#include "./u_module.h" + +#include "aqhome-react/aqhome_react.h" +#include "aqhome-react/types/unit.h" + +#include + + +typedef struct MODULE_PROXY_DESCR MODULE_PROXY_DESCR; +typedef struct AQHREACT_UNIT_MODULE AQHREACT_UNIT_MODULE; + +GWEN_LIST_FUNCTION_DEFS(MODULE_PROXY_DESCR, ModuleProxyDescr); + + + +struct MODULE_PROXY_DESCR { + GWEN_LIST_ELEMENT(MODULE_PROXY_DESCR); + char *name; + char *targetObject; + char *targetName; + int targetIdForModule; + AQHREACT_UNIT *targetObjectPtr; +}; + + +static MODULE_PROXY_DESCR *ModuleProxyDescr_new(const char *name, const char *targetObject, const char *targetName); +static void ModuleProxyDescr_free(MODULE_PROXY_DESCR *pd); +static MODULE_PROXY_DESCR *ModuleProxyDescr_List_FindByName(const MODULE_PROXY_DESCR_LIST *pdList, const char *s); + + + +struct AQHREACT_UNIT_MODULE { + MODULE_PROXY_DESCR_LIST *paramProxyList; + MODULE_PROXY_DESCR_LIST *inSlotProxyList; + MODULE_PROXY_DESCR_LIST *outSlotProxyList; + + AQHREACT_UNIT_LIST *unitList; +}; + + +#endif + + + + + diff --git a/apps/aqhome-react/units/u_or.c b/apps/aqhome-react/units/u_or.c deleted file mode 100644 index c492983..0000000 --- a/apps/aqhome-react/units/u_or.c +++ /dev/null @@ -1,137 +0,0 @@ -/**************************************************************************** - * This file is part of the project AqHome. - * AqHome (c) by 2024 Martin Preuss, all rights reserved. - * - * The license for this file can be found in the file COPYING which you - * should have received along with this file. - ****************************************************************************/ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "./u_or.h" - -#include - - - -/* ------------------------------------------------------------------------------------------------ - * defines - * ------------------------------------------------------------------------------------------------ - */ - -#define AQHOMEREACT_UNIT_OR_INSLOT_INPUT 0 -#define AQHOMEREACT_UNIT_OR_INSLOT_AUTOINPUT 100 - -#define AQHOMEREACT_UNIT_OR_OUTSLOT_RESULT 0 - - - -/* ------------------------------------------------------------------------------------------------ - * forward declarations - * ------------------------------------------------------------------------------------------------ - */ - -static int _cbProcessFn(AQHREACT_UNIT *unit); -static int _sampleInputSlots(const AQHREACT_INPUT_SLOT_LIST *inputSlotList); - - - -/* ------------------------------------------------------------------------------------------------ - * implementations - * ------------------------------------------------------------------------------------------------ - */ - -AQHREACT_UNIT *AqHomeReact_UnitOr_new(AQHOME_REACT *aqh) -{ - AQHREACT_UNIT *unit; - AQHREACT_OUTPUT_SLOT *outputSlot; - AQHREACT_INPUT_SLOT *inputSlot; - - unit=AQHREACT_Unit_new(aqh); - AQHREACT_Unit_SetName(unit, "or"); - AQHREACT_Unit_SetDescription(unit, "Logical OR inputs"); - AQHREACT_Unit_SetProcessFn(unit, _cbProcessFn); - - AQHREACT_Unit_SetNextInputSlotId(unit, AQHOMEREACT_UNIT_OR_INSLOT_AUTOINPUT); /* for auto-gen multi-slots */ - - outputSlot=AQHREACT_OutputSlot_new(); - AQHREACT_OutputSlot_SetName(outputSlot, "output"); - AQHREACT_OutputSlot_SetIdForUnit(outputSlot, AQHOMEREACT_UNIT_OR_OUTSLOT_RESULT); - AQHREACT_OutputSlot_SetEmittedDataType(outputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE); - AQHREACT_Unit_AddOutputSlot(unit, outputSlot); - - inputSlot=AQHREACT_InputSlot_new(); - AQHREACT_InputSlot_SetName(inputSlot, "input"); - AQHREACT_InputSlot_SetIdForUnit(inputSlot, AQHOMEREACT_UNIT_OR_INSLOT_INPUT); - AQHREACT_InputSlot_SetAcceptedDataType(inputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE); - AQHREACT_InputSlot_AddFlags(inputSlot, AQHREACT_UNIT_FLAGS_MULTI); - AQHREACT_Unit_AddInputSlot(unit, inputSlot); - - return unit; -} - - - -int _cbProcessFn(AQHREACT_UNIT *unit) -{ - if (unit && AQHREACT_Unit_InputHasChanged(unit)) { - AQHREACT_INPUT_SLOT_LIST *inputSlotList; - - inputSlotList=AQHREACT_Unit_GetInputSlots(unit); - if (inputSlotList) { - int result; - - result=_sampleInputSlots(inputSlotList); - AQHREACT_Unit_ClearChangeFlagsInUnitAndInputSlots(unit); - AQHREACT_Unit_OutputDoubleData(unit, AQHOMEREACT_UNIT_OR_OUTSLOT_RESULT, result?1.0:0.0); - return 1; - } - } - - return 0; -} - - - -int _sampleInputSlots(const AQHREACT_INPUT_SLOT_LIST *inputSlotList) -{ - const AQHREACT_INPUT_SLOT *inputSlot; - int result=0; - - inputSlot=AQHREACT_InputSlot_List_First(inputSlotList); - while(inputSlot) { - const char *slotName; - const AQHREACT_DATAOBJECT *dataObject; - - slotName=AQHREACT_InputSlot_GetName(inputSlot); - dataObject=AQHREACT_InputSlot_GetCurrentDataObject(inputSlot); - if (dataObject) { - if (AQHREACT_DataObject_GetDataType(dataObject)==AQHREACT_DATAOBJECTTYPE_DOUBLE) { - double d; - - d=AQHREACT_DataObject_GetDoubleData(dataObject); - if (d>0.0) - result|=1; - } - else { - DBG_ERROR(NULL, "Data at input slot \"%s\" isn't DOUBLE, ignoring", slotName?slotName:""); - } - } - else { - DBG_ERROR(NULL, "Data at input slot \"%s\" has not current data, ignoring", slotName?slotName:""); - } - - inputSlot=AQHREACT_InputSlot_List_Next(inputSlot); - } - - return result; -} - - - - - - -