/**************************************************************************** * 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 /* ------------------------------------------------------------------------------------------------ * 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, AQHREACT_PORT *port, const AQHREACT_DATAOBJECT *dataObject); static AQHREACT_PARAM *_cbGetParamByName(const AQHREACT_UNIT *unit, const char *paramName); static int _cbProcess(AQHREACT_UNIT *unit); static void _cbDump(const AQHREACT_UNIT *unit, GWEN_BUFFER *buf, int indent); static void _readProxyFromXml(GWEN_XMLNODE *xmlNode, MODULE_PROXY_DESCR_LIST *proxyDescrList, const char *mainGroupName, const char *groupName, const char *nameProperty, const char *targetObjectProperty, const char *targetNameProperty); static int _readInputPortsFromXml(AQHREACT_UNIT *unit, GWEN_XMLNODE *xmlNode); static int _readOutputPortsFromXml(AQHREACT_UNIT *unit, GWEN_XMLNODE *xmlNode); 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, 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); static int _linkFromThisModulesInput(AQHOME_REACT *aqh, AQHREACT_UNIT *unit, const char *emittingPortName, const char *receivingUnitName, const char *receivingPortName); static int _linkToThisModulesOutput(AQHOME_REACT *aqh, AQHREACT_UNIT *unit, const char *emittingUnitName, const char *emittingPortName, const char *receivingPortName); static int _linkBetweenUnits(AQHOME_REACT *aqh, AQHREACT_UNIT *unit, const char *emittingUnitName, const char *emittingPortName, const char *receivingUnitName, const char *receivingPortName); /* ------------------------------------------------------------------------------------------------ * 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->unitList=AQHREACT_Unit_List_new(); AQHREACT_Unit_SetInputDataFn(unit, _cbInputData); AQHREACT_Unit_SetGetParamByNameFn(unit, _cbGetParamByName); AQHREACT_Unit_SetProcessFn(unit, _cbProcess); AQHREACT_Unit_SetDumpFn(unit, _cbDump); return unit; } void _freeData(GWEN_UNUSED void *bp, void *p) { AQHREACT_UNIT_MODULE *xunit; xunit=(AQHREACT_UNIT_MODULE*) p; AQHREACT_Unit_List_free(xunit->unitList); ModuleProxyDescr_List_free(xunit->paramProxyList); GWEN_FREE_OBJECT(xunit); } AQHREACT_UNIT *AqHomeReact_UnitModule_fromXml(AQHOME_REACT *aqh, GWEN_XMLNODE *xmlNode) { 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_SetTypeName(unit, GWEN_XMLNode_GetProperty(xmlNode, "type", NULL)); AQHREACT_Unit_SetId(unit, GWEN_XMLNode_GetProperty(xmlNode, "id", NULL)); _readProxyFromXml(xmlNode, xunit->paramProxyList, "paramdefs", "param", "name", "targetModule", "targetParam"); rv=_readInputPortsFromXml(unit, xmlNode); if (rv<0) { DBG_INFO(NULL, "here (%d)", rv); AQHREACT_Unit_free(unit); return NULL; } rv=_readOutputPortsFromXml(unit, xmlNode); if (rv<0) { DBG_INFO(NULL, "here (%d)", rv); AQHREACT_Unit_free(unit); return NULL; } _readUnitsFromXml(aqh, unit, xmlNode); 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; } void _cbInputData(GWEN_UNUSED AQHREACT_UNIT *unit, AQHREACT_PORT *port, const AQHREACT_DATAOBJECT *dataObject) { if (port) AQHREACT_Port_SendData(port, dataObject); } AQHREACT_PARAM *_cbGetParamByName(const AQHREACT_UNIT *unit, const char *paramName) { AQHREACT_UNIT_MODULE *xunit; DBG_INFO(NULL, "Looking for param \"%s\" in proxy descr of module \"%s\"", paramName, AQHREACT_Unit_GetTypeName(unit)); 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) { DBG_INFO(NULL, "Found proxydescr for param (-> %s:%s)", (pd->targetObjectPtr)?AQHREACT_Unit_GetTypeName(pd->targetObjectPtr):"", (pd->targetName)?(pd->targetName):""); return 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 _cbDump(const AQHREACT_UNIT *unit, GWEN_BUFFER *buf, int indent) { AQHREACT_UNIT_MODULE *xunit; xunit=(AQHREACT_UNIT_MODULE*)GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_MODULE, unit); if (xunit) AQHREACT_Unit_List_Dump(xunit->unitList, buf, indent, "Sub Units:"); } void _readProxyFromXml(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); } } } int _readInputPortsFromXml(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, "inputPorts", NULL, NULL); if (nGroup) { GWEN_XMLNODE *n; n=GWEN_XMLNode_FindFirstTag(nGroup, "inputPort", NULL, NULL); while(n) { const char *name; int dataType; AQHREACT_PORT *port; name=GWEN_XMLNode_GetProperty(n, "name", NULL); dataType=AQHREACT_DataObjectType_fromString(GWEN_XMLNode_GetProperty(n, "dataType", "double")); if (dataType==AQHREACT_DATAOBJECTTYPE_UNKNOWN) { DBG_ERROR(NULL, "Unknown dataType: %s", GWEN_XMLNode_GetProperty(n, "dataType", "double")); return GWEN_ERROR_BAD_DATA; } if (name==NULL) { DBG_ERROR(NULL, "Missing name in input port"); return GWEN_ERROR_BAD_DATA; } /* create input port */ port=AQHREACT_Port_new(); AQHREACT_Port_SetName(port, name); AQHREACT_Port_SetIdForUnit(port, ++(xunit->lastPortId)); AQHREACT_Port_SetDataType(port, dataType); AQHREACT_Unit_AddInputPort(unit, port); n=GWEN_XMLNode_FindNextTag(n, "inputPort", NULL, NULL); } /* while */ } return 0; } int _readOutputPortsFromXml(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, "outputPorts", NULL, NULL); if (nGroup) { GWEN_XMLNODE *n; n=GWEN_XMLNode_FindFirstTag(nGroup, "outputPort", NULL, NULL); while(n) { const char *name; int dataType; AQHREACT_PORT *port; name=GWEN_XMLNode_GetProperty(n, "name", NULL); dataType=AQHREACT_DataObjectType_fromString(GWEN_XMLNode_GetProperty(n, "dataType", "double")); if (dataType==AQHREACT_DATAOBJECTTYPE_UNKNOWN) { DBG_ERROR(NULL, "Unknown dataType: %s", GWEN_XMLNode_GetProperty(n, "dataType", "double")); return GWEN_ERROR_BAD_DATA; } if (name==NULL) { DBG_ERROR(NULL, "Missing name in output port"); return GWEN_ERROR_BAD_DATA; } /* create input port */ port=AQHREACT_Port_new(); AQHREACT_Port_SetName(port, name); AQHREACT_Port_SetIdForUnit(port, ++(xunit->lastPortId)); AQHREACT_Port_SetDataType(port, dataType); AQHREACT_Unit_AddOutputPort(unit, port); n=GWEN_XMLNode_FindNextTag(n, "outputPort", NULL, NULL); } } 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_GetTypeName(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, 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, GWEN_XMLNODE *xmlNode) { const char *id; const char *t; const char *s; id=GWEN_XMLNode_GetProperty(xmlNode, "id", NULL); t=GWEN_XMLNode_GetProperty(xmlNode, "type", NULL); s=GWEN_XMLNode_GetProperty(xmlNode, "invert", NULL); if (id && t) { AQHREACT_UNIT *subUnit; int rv; subUnit=AqHomeReact_CreateUnitByName(aqh, t); if (subUnit==NULL) { DBG_INFO(NULL, "Could not create unit of type \"%s\"", t); return NULL; } AQHREACT_Unit_SetId(subUnit, id); if (s && strcasecmp(s, "TRUE")==0) AQHREACT_Unit_AddFlags(subUnit, AQHREACT_UNIT_FLAGS_INVERT); 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 \"%s\"", paramName, AQHREACT_Unit_GetTypeName(unit)); 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_GetTypeName(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) { const char *emittingUnitName; const char *emittingPortName; const char *receivingUnitName; const char *receivingPortName; int rv; emittingUnitName=GWEN_XMLNode_GetProperty(linkNode, "sourceUnit", "."); emittingPortName=GWEN_XMLNode_GetProperty(linkNode, "sourcePort", NULL); receivingUnitName=GWEN_XMLNode_GetProperty(linkNode, "targetUnit", "."); receivingPortName=GWEN_XMLNode_GetProperty(linkNode, "targetPort", NULL); if (!(emittingUnitName && *emittingUnitName && emittingPortName && *emittingPortName && receivingUnitName && *receivingUnitName && receivingPortName && *receivingPortName)) { DBG_ERROR(NULL, "Link in net \"%s\" needs properties sourceUnit, sourcePort, targetUnit and targetPort", AQHREACT_Unit_GetTypeName(unit)); return GWEN_ERROR_BAD_DATA; } if (strcasecmp(emittingUnitName, ".")==0) rv=_linkFromThisModulesInput(aqh, unit, emittingPortName, receivingUnitName, receivingPortName); else if (strcasecmp(receivingUnitName, ".")==0) rv=_linkToThisModulesOutput(aqh, unit, emittingUnitName, emittingPortName, receivingPortName); else rv=_linkBetweenUnits(aqh, unit, emittingUnitName, emittingPortName, receivingUnitName, receivingPortName); if (rv<0) { DBG_INFO(NULL, "Error creating link: %s:%s -> %s:%s (%d)", emittingUnitName, emittingPortName, receivingUnitName, receivingPortName, rv); return rv; } return 0; } int _linkFromThisModulesInput(AQHOME_REACT *aqh, AQHREACT_UNIT *unit, const char *emittingPortName, const char *receivingUnitName, const char *receivingPortName) { AQHREACT_UNIT_MODULE *xunit; AQHREACT_UNIT *receivingUnit; AQHREACT_PORT *receivingPort; AQHREACT_PORT *emittingPort; AQHREACT_LINK *link; xunit=(AQHREACT_UNIT_MODULE*)GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_MODULE, unit); receivingUnit=AQHREACT_Unit_List_GetById(xunit->unitList, receivingUnitName); if (receivingUnit==NULL) receivingUnit=AqHomeReact_FindUnitByUnitId(aqh, receivingUnitName); if (receivingUnit==NULL) { DBG_ERROR(NULL, "Target unit \"%s\" not found", receivingUnitName); return GWEN_ERROR_NOT_FOUND; } emittingPort=AQHREACT_Unit_GetInputPortByName(unit, emittingPortName); /* find in modules input port list! */ if (emittingPort==NULL) { DBG_ERROR(NULL, "Target port \"%s\" not found for source unit \"%s\"", emittingPortName, AQHREACT_Unit_GetTypeName(unit)); return GWEN_ERROR_NOT_FOUND; } receivingPort=AQHREACT_Unit_GetOrCreateUnusedInputPortByName(receivingUnit, receivingPortName); /*receivingPort=AQHREACT_Unit_GetInputPortByName(receivingUnit, receivingPortName);*/ if (receivingPort==NULL) { DBG_ERROR(NULL, "Input port \"%s\" not found for target unit \"%s\"", receivingPortName, receivingUnitName); return GWEN_ERROR_NOT_FOUND; } AQHREACT_Port_AddFlags(receivingPort, AQHREACT_UNIT_FLAGS_INUSE); link=AQHREACT_Link_new(); AQHREACT_Link_SetTargetUnit(link, receivingUnit); AQHREACT_Link_SetTargetPort(link, receivingPort); AQHREACT_Port_AddLink(emittingPort, link); return 0; } int _linkToThisModulesOutput(AQHOME_REACT *aqh, AQHREACT_UNIT *unit, const char *emittingUnitName, const char *emittingPortName, const char *receivingPortName) { AQHREACT_UNIT_MODULE *xunit; AQHREACT_UNIT *receivingUnit; AQHREACT_PORT *receivingPort; AQHREACT_UNIT *emittingUnit; AQHREACT_PORT *emittingPort; AQHREACT_LINK *link; xunit=(AQHREACT_UNIT_MODULE*)GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_MODULE, unit); emittingUnit=AQHREACT_Unit_List_GetById(xunit->unitList, emittingUnitName); if (emittingUnit==NULL) emittingUnit=AqHomeReact_FindUnitByUnitId(aqh, emittingUnitName); if (emittingUnit==NULL) { DBG_ERROR(NULL, "Source unit \"%s\" not found", emittingUnitName); return GWEN_ERROR_NOT_FOUND; } receivingUnit=unit; emittingPort=AQHREACT_Unit_GetOutputPortByName(emittingUnit, emittingPortName); if (emittingPort==NULL) { DBG_ERROR(NULL, "Output port \"%s\" not found", emittingPortName); return GWEN_ERROR_NOT_FOUND; } receivingPort=AQHREACT_Unit_GetOutputPortByName(unit, receivingPortName); /* find in modules output port list! */ if (receivingPort==NULL) { DBG_ERROR(NULL, "Target port \"%s\" not found", receivingPortName); return GWEN_ERROR_NOT_FOUND; } link=AQHREACT_Link_new(); AQHREACT_Link_SetTargetUnit(link, receivingUnit); AQHREACT_Link_SetTargetPort(link, receivingPort); AQHREACT_Port_AddLink(emittingPort, link); return 0; } int _linkBetweenUnits(AQHOME_REACT *aqh, AQHREACT_UNIT *unit, const char *emittingUnitName, const char *emittingPortName, const char *receivingUnitName, const char *receivingPortName) { AQHREACT_UNIT_MODULE *xunit; AQHREACT_UNIT *receivingUnit; AQHREACT_PORT *receivingPort; AQHREACT_UNIT *emittingUnit; AQHREACT_PORT *emittingPort; AQHREACT_LINK *link; xunit=(AQHREACT_UNIT_MODULE*)GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_MODULE, unit); emittingUnit=AQHREACT_Unit_List_GetById(xunit->unitList, emittingUnitName); if (emittingUnit==NULL) emittingUnit=AqHomeReact_FindUnitByUnitId(aqh, emittingUnitName); if (emittingUnit==NULL) { DBG_ERROR(NULL, "Source unit \"%s\" not found", emittingUnitName); return GWEN_ERROR_NOT_FOUND; } receivingUnit=AQHREACT_Unit_List_GetById(xunit->unitList, receivingUnitName); if (receivingUnit==NULL) receivingUnit=AqHomeReact_FindUnitByUnitId(aqh, receivingUnitName); if (receivingUnit==NULL) { DBG_ERROR(NULL, "Target unit \"%s\" not found", receivingUnitName); return GWEN_ERROR_NOT_FOUND; } emittingPort=AQHREACT_Unit_GetOutputPortByName(emittingUnit, emittingPortName); if (emittingPort==NULL) { DBG_ERROR(NULL, "Output port \"%s\" not found for source unit \"%s\"", emittingPortName, emittingUnitName); return GWEN_ERROR_NOT_FOUND; } receivingPort=AQHREACT_Unit_GetOrCreateUnusedInputPortByName(receivingUnit, receivingPortName); if (receivingPort==NULL) { DBG_ERROR(NULL, "Input port \"%s\" not found for target unit \"%s\"", receivingPortName, receivingUnitName); return GWEN_ERROR_NOT_FOUND; } AQHREACT_Port_AddFlags(receivingPort, AQHREACT_UNIT_FLAGS_INUSE); link=AQHREACT_Link_new(); AQHREACT_Link_SetTargetUnit(link, receivingUnit); AQHREACT_Link_SetTargetPort(link, receivingPort); AQHREACT_Port_AddLink(emittingPort, link); return 0; }