/**************************************************************************** * 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 "./devicesread.h" #include "./server_p.h" #include "aqhome/aqhome.h" #include #include #include /* ------------------------------------------------------------------------------------------------ * defines * ------------------------------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------------------------------ * forward declarations * ------------------------------------------------------------------------------------------------ */ static int _readDeviceFileToList(const char *sFilename, AQHNODE_DEVICE_LIST *deviceList); static AQHNODE_DEVICE_LIST *_readDeviceFiles(const GWEN_STRINGLIST *sl); static int _readXmlDevices(GWEN_XMLNODE *deviceListNode, AQHNODE_DEVICE_LIST *deviceList); static AQHNODE_DEVICE *_readXmlDevice(GWEN_XMLNODE *deviceNode); static AQHNODE_VALUE_LIST *_readXmlValueList(GWEN_XMLNODE *valuesNode); static AQHNODE_VALUE *_readXmlValue(GWEN_XMLNODE *valueNode); static int _readManufacturer(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode); static int _readDeviceType(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode); static int _readDeviceVersion(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode); /* ------------------------------------------------------------------------------------------------ * implementations * ------------------------------------------------------------------------------------------------ */ AQHNODE_DEVICE_LIST *AQH_NodeServer_ReadDeviceFile(const char *sFilename) { int rv; rv=GWEN_Directory_GetPath(sFilename, GWEN_PATH_FLAGS_CHECKROOT | GWEN_PATH_FLAGS_PATHMUSTEXIST | GWEN_PATH_FLAGS_VARIABLE); if (rv<0) { DBG_ERROR(NULL, "File \"%s\" does not exists, writing later", sFilename); return NULL; } else { AQHNODE_DEVICE_LIST *deviceList; deviceList=AQHNODE_Device_List_new(); rv=_readDeviceFileToList(sFilename, deviceList); if (rv<0) { DBG_ERROR(NULL, "File \"%s\" not found", sFilename); AQHNODE_Device_List_free(deviceList); return NULL; } if (AQHNODE_Device_List_GetCount(deviceList)<1) { AQHNODE_Device_List_free(deviceList); return NULL; } return deviceList; } } AQHNODE_DEVICE_LIST *AQH_NodeServer_ReadDataDeviceFiles() { GWEN_STRINGLIST *sl; sl=AQH_GetListOfMatchingDataFiles("aqhome/devices/nodes", "*.xml"); if (sl) { AQHNODE_DEVICE_LIST *deviceList; deviceList=_readDeviceFiles(sl); GWEN_StringList_free(sl); if (deviceList==NULL) { DBG_INFO(NULL, "Error reading data device files"); return NULL; } return deviceList; } else { DBG_ERROR(NULL, "No data device files"); return NULL; } } AQHNODE_DEVICE_LIST *_readDeviceFiles(const GWEN_STRINGLIST *sl) { GWEN_STRINGLISTENTRY *se; AQHNODE_DEVICE_LIST *deviceList; deviceList=AQHNODE_Device_List_new(); se=GWEN_StringList_FirstEntry(sl); while(se) { const char *s; s=GWEN_StringListEntry_Data(se); if (s && *s) { int rv; DBG_INFO(NULL, "Reading device file \"%s\"", s); rv=_readDeviceFileToList(s, deviceList); if (rv<0 && rv!=GWEN_ERROR_NO_DATA) { DBG_WARN(NULL, "Error reading device file \"%s\" (%d), ignoring", s, rv); } } se=GWEN_StringListEntry_Next(se); } if (AQHNODE_Device_List_GetCount(deviceList)<1) { AQHNODE_Device_List_free(deviceList); return NULL; } return deviceList; } int _readDeviceFileToList(const char *sFilename, AQHNODE_DEVICE_LIST *deviceList) { GWEN_XMLNODE *rootNode; GWEN_XMLNODE *deviceListNode; int rv; rootNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, NULL); rv=GWEN_XML_ReadFile(rootNode, sFilename, GWEN_XML_FLAGS_DEFAULT); if (rv<0) { DBG_ERROR(NULL, "Error reading XML file \"%s\": %d", sFilename, rv); GWEN_XMLNode_free(rootNode); return rv; } deviceListNode=GWEN_XMLNode_FindFirstTag(rootNode, "devices", NULL, NULL); if (deviceListNode==NULL) deviceListNode=rootNode; rv=_readXmlDevices(deviceListNode, deviceList); if (rv<0 && rv!=GWEN_ERROR_NO_DATA) { DBG_ERROR(AQH_LOGDOMAIN, "Error reading devices from file \"%s\" (%d)", sFilename, rv); GWEN_XMLNode_free(rootNode); return rv; } GWEN_XMLNode_free(rootNode); return 0; } int _readXmlDevices(GWEN_XMLNODE *deviceListNode, AQHNODE_DEVICE_LIST *deviceList) { GWEN_XMLNODE *deviceNode; deviceNode=GWEN_XMLNode_FindFirstTag(deviceListNode, "device", NULL, NULL); if (deviceNode) { while(deviceNode) { const char *driverName; driverName=GWEN_XMLNode_GetProperty(deviceNode, "driver", NULL); if (driverName && *driverName && strcasecmp(driverName, "nodes")==0) { AQHNODE_DEVICE *device; device=_readXmlDevice(deviceNode); if (device==NULL) { DBG_INFO(NULL, "Error reading device from XML"); return GWEN_ERROR_BAD_DATA; } else { const char *sDeviceName; sDeviceName=AQHNODE_Device_GetName(device); if (sDeviceName && *sDeviceName) { DBG_ERROR(NULL, "Adding device type \"%s\" to list", sDeviceName?sDeviceName:""); AQHNODE_Device_List_Add(device, deviceList); } else { DBG_ERROR(NULL, "Device with no name, not adding"); AQHNODE_Device_free(device); } } } else { DBG_INFO(NULL, "Device is not an NODES device, ignoring"); } deviceNode=GWEN_XMLNode_FindNextTag(deviceNode, "device", NULL, NULL); } /* while */ return 0; } else { DBG_INFO(NULL, "No element found"); return GWEN_ERROR_NO_DATA; } } AQHNODE_DEVICE *_readXmlDevice(GWEN_XMLNODE *deviceNode) { AQHNODE_DEVICE *device; GWEN_XMLNODE *valuesNode; int rv; device=AQHNODE_Device_new(); AQHNODE_Device_SetName(device, GWEN_XMLNode_GetProperty(deviceNode, "name", NULL)); AQHNODE_Device_SetDriver(device, GWEN_XMLNode_GetProperty(deviceNode, "driver", NULL)); rv=_readManufacturer(device, deviceNode); if (rv<0) { DBG_INFO(NULL, "here (%d)", rv); AQHNODE_Device_free(device); return NULL; } rv=_readDeviceType(device, deviceNode); if (rv<0) { DBG_INFO(NULL, "here (%d)", rv); AQHNODE_Device_free(device); return NULL; } rv=_readDeviceVersion(device, deviceNode); if (rv<0) { DBG_INFO(NULL, "here (%d)", rv); AQHNODE_Device_free(device); return NULL; } /* read values */ valuesNode=GWEN_XMLNode_FindFirstTag(deviceNode, "values", NULL, NULL); if (valuesNode) { AQHNODE_VALUE_LIST *valueList; valueList=_readXmlValueList(valuesNode); if (valueList==NULL) { DBG_INFO(NULL, "here"); AQHNODE_Device_free(device); return NULL; } AQHNODE_Device_SetValueList(device, valueList); } else { DBG_INFO(NULL, "No element"); AQHNODE_Device_free(device); return NULL; } return device; } AQHNODE_VALUE_LIST *_readXmlValueList(GWEN_XMLNODE *valuesNode) { AQHNODE_VALUE_LIST *valueList; GWEN_XMLNODE *node; valueList=AQHNODE_Value_List_new(); node=GWEN_XMLNode_FindFirstTag(valuesNode, "value", NULL, NULL); while(node) { AQHNODE_VALUE *value; value=_readXmlValue(node); if (value) AQHNODE_Value_List_Add(value, valueList); else { DBG_INFO(NULL, "Error reading element"); AQHNODE_Value_List_free(valueList); return NULL; } node=GWEN_XMLNode_FindNextTag(node, "value", NULL, NULL); } if (AQHNODE_Value_List_GetCount(valueList)<1) { DBG_INFO(NULL, "No element in element"); AQHNODE_Value_List_free(valueList); return NULL; } return valueList; } AQHNODE_VALUE *_readXmlValue(GWEN_XMLNODE *valueNode) { AQHNODE_VALUE *value; value=AQHNODE_Value_new(); AQHNODE_Value_SetName(value, GWEN_XMLNode_GetProperty(valueNode, "name", NULL)); AQHNODE_Value_SetId(value, GWEN_XMLNode_GetIntProperty(valueNode, "id", 0)); AQHNODE_Value_SetValueUnits(value, GWEN_XMLNode_GetProperty(valueNode, "units", NULL)); AQHNODE_Value_SetValueType(value, AQH_ValueType_fromString(GWEN_XMLNode_GetProperty(valueNode, "type", NULL))); AQHNODE_Value_SetDataType(value, AQH_ValueDataType_fromString(GWEN_XMLNode_GetProperty(valueNode, "dataType", NULL))); AQHNODE_Value_SetModality(value, AQH_ValueModality_fromString(GWEN_XMLNode_GetProperty(valueNode, "modality", NULL))); AQHNODE_Value_SetDenom(value, GWEN_XMLNode_GetIntProperty(valueNode, "denom", 1)); return value; } int _readManufacturer(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode) { const char *s; uint32_t v; s=GWEN_XMLNode_GetCharValue(deviceNode, "manufacturer", NULL); if (!(s && *s)) { DBG_ERROR(NULL, "Missing manufacturer"); return GWEN_ERROR_BAD_DATA; } if (strlen(s)>4) { DBG_ERROR(NULL, "Bad manufacturer string (too long): \"%s\"", s); return GWEN_ERROR_BAD_DATA; } v=0; while(*s) { v<<=8; v|=*s & 0xff; s++; } v=((v>>24) & 0x000000ffL) | ((v>>8) & 0x0000ff00L) | ((v<<8) & 0x00ff0000L) | ((v<<24) & 0xff000000L); AQHNODE_Device_SetManufacturer(device, v); return 0; } int _readDeviceType(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode) { const char *s; uint16_t v; s=GWEN_XMLNode_GetCharValue(deviceNode, "devicetype", NULL); if (!(s && *s)) { DBG_ERROR(NULL, "Missing device type"); return GWEN_ERROR_BAD_DATA; } if (strlen(s)>2) { DBG_ERROR(NULL, "Bad devicetype string (too long): \"%s\"", s); return GWEN_ERROR_BAD_DATA; } v=0; while(*s) { v<<=8; v|=*s & 0xff; s++; } AQHNODE_Device_SetDeviceType(device, v); return 0; } int _readDeviceVersion(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode) { int v; v=GWEN_XMLNode_GetIntValue(deviceNode, "deviceversion", -1); if (v<0) { DBG_ERROR(NULL, "Missing device version"); return GWEN_ERROR_BAD_DATA; } AQHNODE_Device_SetDeviceVersion(device, v<<8); return 0; }