/**************************************************************************** * This file is part of the project AqHome. * AqHome (c) by 2025 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 "./s_getdatapoints.h" #include "./server_p.h" #include "aqhome/aqhome.h" #include "aqhome/ipc2/endpoint.h" #include "aqhome/msg/ipc/m_ipc.h" #include "aqhome/msg/ipc/m_ipc_result.h" #include "aqhome/msg/ipc/data/m_ipcd.h" #include "aqhome/msg/ipc/data/m_ipcd_getdata.h" #include "aqhome/msg/ipc/data/m_ipcd_multidata.h" #include "aqhome/msg/ipc/m_ipc_result.h" #include "aqhome/msg/ipc/m_ipc_tag16.h" #include /* ------------------------------------------------------------------------------------------------ * defines * ------------------------------------------------------------------------------------------------ */ #define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES 1024 #define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS 512 /* ------------------------------------------------------------------------------------------------ * forward declarations * ------------------------------------------------------------------------------------------------ */ static int _getAndSendDataPoints(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, int mode, uint64_t tsBegin, uint64_t tsEnd, uint64_t num, uint32_t refMsgId); static int _getAndSendDataPointsPeriod(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd, uint64_t num, uint32_t refMsgId); static int _getAndSendDataPointsFirst(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint64_t num, uint32_t refMsgId); static int _getAndSendDataPointsLast(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint64_t num, uint32_t refMsgId); static void _sendDataPointsResponse(AQH_OBJECT *ep, const AQH_VALUE *value, const uint64_t *tablePtr, uint32_t refMsgId); /* ------------------------------------------------------------------------------------------------ * implementations * ------------------------------------------------------------------------------------------------ */ void AqHomeDataServer_HandleGetDataPoints(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *recvdMsg, const GWEN_TAG16_LIST *tagList) { if (tagList) { AQHOME_SERVER *xo; xo=AqHomeDataServer_GetServerData(o); if (xo) { uint32_t refMsgId; refMsgId=AQH_IpcMessage_GetMsgId(recvdMsg); if (AQH_Endpoint_GetPermissions(ep) & AQH_ENDPOINT_PERMS_READDATA) { char *valueName; valueName=AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSGDATA_GETDATA_TAGS_NAME, NULL); if (valueName && *valueName) { AQH_VALUE *value; uint64_t tsBegin; uint64_t tsEnd; uint64_t numRequested; int mode; tsBegin=AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_BEGIN, 0); tsEnd=AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_END, 0); numRequested=AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_NUM, 0); mode=AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_MODE, AQH_MSGDATA_GETDATA_MODE_FIRST); value=AQH_Storage_GetValueByNameForSystem(xo->storage, valueName); if (value) { int resultCode; resultCode=_getAndSendDataPoints(xo->storage, ep, value, mode, tsBegin, tsEnd, numRequested, refMsgId); AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, resultCode); } else { DBG_INFO(NULL, "Value \"%s\" does not exist", valueName); AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, AQH_MSGDATA_RESULT_ERROR_NOTFOUND); } free(valueName); } else { DBG_INFO(NULL, "Missing value name"); AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, AQH_MSGDATA_RESULT_ERROR_BADDATA); } } else { DBG_ERROR(AQH_LOGDOMAIN, "No permissions to read data"); AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, AQH_MSGDATA_RESULT_ERROR_PERMS); } } } } int _getAndSendDataPoints(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, int mode, uint64_t tsBegin, uint64_t tsEnd, uint64_t num, uint32_t refMsgId) { switch(mode) { case AQH_MSGDATA_GETDATA_MODE_FIRST: return _getAndSendDataPointsFirst(storage, ep, value, num, refMsgId); case AQH_MSGDATA_GETDATA_MODE_PERIOD: return _getAndSendDataPointsPeriod(storage, ep, value, tsBegin, tsEnd, num, refMsgId); default: case AQH_MSGDATA_GETDATA_MODE_LAST: return _getAndSendDataPointsLast(storage, ep, value, num, refMsgId); } } int _getAndSendDataPointsPeriod(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd, uint64_t num, uint32_t refMsgId) { uint64_t valueId; uint64_t *tablePtr; valueId=AQH_Value_GetId(value); if (num==0 || num>AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES) num=AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES; tablePtr=AQH_Storage_GetDataPoints(storage, valueId, tsBegin, tsEnd, num); if (tablePtr) { _sendDataPointsResponse(ep, value, tablePtr, refMsgId); free(tablePtr); return AQH_MSGDATA_RESULT_SUCCESS; } else { DBG_INFO(NULL, "No matching datapoints for value \"%s\"", AQH_Value_GetNameForSystem(value)); return AQH_MSGDATA_RESULT_ERROR_NODATA; } } int _getAndSendDataPointsLast(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint64_t num, uint32_t refMsgId) { uint64_t valueId; uint64_t *tablePtr; if (num>AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS) num=AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS; valueId=AQH_Value_GetId(value); tablePtr=AQH_Storage_GetLastNDataPoints(storage, valueId, num); if (tablePtr) { _sendDataPointsResponse(ep, value, tablePtr, refMsgId); free(tablePtr); return AQH_MSGDATA_RESULT_SUCCESS; } else { DBG_INFO(NULL, "No matching datapoints for value \"%s\"", AQH_Value_GetNameForSystem(value)); return AQH_MSGDATA_RESULT_ERROR_NODATA; } } int _getAndSendDataPointsFirst(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint64_t num, uint32_t refMsgId) { uint64_t valueId; uint64_t *tablePtr; if (num>AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS) num=AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS; valueId=AQH_Value_GetId(value); tablePtr=AQH_Storage_GetFirstNDataPoints(storage, valueId, num); if (tablePtr) { _sendDataPointsResponse(ep, value, tablePtr, refMsgId); free(tablePtr); return AQH_MSGDATA_RESULT_SUCCESS; } else { DBG_INFO(NULL, "No matching datapoints for value \"%s\"", AQH_Value_GetNameForSystem(value)); return AQH_MSGDATA_RESULT_ERROR_NODATA; } } void _sendDataPointsResponse(AQH_OBJECT *ep, const AQH_VALUE *value, const uint64_t *tablePtr, uint32_t refMsgId) { int numTableEntries; int numDataPoints; AQH_MESSAGE *outMsg; numTableEntries=(int)(tablePtr[0]); numDataPoints=numTableEntries/2; outMsg=AQH_IpcdMessageMultiData_new(AQH_MSGTYPE_IPC_DATA_GETDATA_RSP, AQH_Endpoint_GetNextMessageId(ep), refMsgId, value, &(tablePtr[1]), numDataPoints); AQH_Endpoint_AddMsgOut(ep, outMsg); }