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;
-}
-
-
-
-
-
-
-