229 lines
7.8 KiB
C
229 lines
7.8 KiB
C
/****************************************************************************
|
|
* This file is part of the project AqHome.
|
|
* AqHome (c) by 2023 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 <config.h>
|
|
#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 <gwenhywfar/debug.h>
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* defines
|
|
* ------------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES 2048
|
|
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS 1024
|
|
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* forward declarations
|
|
* ------------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
static int _getAndSendDataPoints(AQH_STORAGE *storage, AQH_OBJECT *ep,
|
|
const AQH_VALUE *value,
|
|
uint64_t tsBegin, uint64_t tsEnd, uint64_t num, uint32_t refMsgId);
|
|
static int _getAndSendDataPointsNoNum(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd,
|
|
uint32_t refMsgId);
|
|
static int _getAndSendDataPointsWithNum(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);
|
|
static void _getAndSendLastDatapoint(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, 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;
|
|
|
|
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);
|
|
|
|
value=AQH_Storage_GetValueByNameForSystem(xo->storage, valueName);
|
|
if (value) {
|
|
int resultCode;
|
|
|
|
resultCode=_getAndSendDataPoints(xo->storage, ep, value, 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,
|
|
uint64_t tsBegin, uint64_t tsEnd, uint64_t num,
|
|
uint32_t refMsgId)
|
|
{
|
|
if (num==0)
|
|
return _getAndSendDataPointsNoNum(storage, ep, value, tsBegin, tsEnd, refMsgId);
|
|
else if (num==1) {
|
|
_getAndSendLastDatapoint(storage, ep, value, refMsgId);
|
|
return AQH_MSGDATA_RESULT_SUCCESS;
|
|
}
|
|
else
|
|
return _getAndSendDataPointsWithNum(storage, ep, value, num, refMsgId);
|
|
}
|
|
|
|
|
|
|
|
int _getAndSendDataPointsNoNum(AQH_STORAGE *storage, AQH_OBJECT *ep,
|
|
const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd,
|
|
uint32_t refMsgId)
|
|
{
|
|
uint64_t valueId;
|
|
uint64_t *tablePtr;
|
|
|
|
valueId=AQH_Value_GetId(value);
|
|
tablePtr=AQH_Storage_GetDataPoints(storage, valueId, tsBegin, tsEnd, AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES);
|
|
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 _getAndSendDataPointsWithNum(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;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
|
|
void _getAndSendLastDatapoint(AQH_STORAGE *storage, AQH_OBJECT *ep,
|
|
const AQH_VALUE *value, uint32_t refMsgId)
|
|
{
|
|
int rv;
|
|
uint64_t timestamp=0;
|
|
double data=0.0;
|
|
|
|
rv=AQH_Storage_GetLastDataPoint(storage, AQH_Value_GetId(value), ×tamp, &data);
|
|
if (rv<0) {
|
|
int resultCode;
|
|
|
|
switch(rv) {
|
|
case GWEN_ERROR_INVALID: resultCode=AQH_MSGDATA_RESULT_ERROR_INVALID; break;
|
|
case GWEN_ERROR_NO_DATA: resultCode=AQH_MSGDATA_RESULT_ERROR_NODATA; break;
|
|
default: resultCode=AQH_MSGDATA_RESULT_ERROR_GENERIC; break;
|
|
}
|
|
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, resultCode);
|
|
}
|
|
else {
|
|
AQH_MESSAGE *outMsg;
|
|
|
|
outMsg=AQH_IpcdMessageMultiData_newForOne(AQH_MSGTYPE_IPC_DATA_GETDATA_RSP,
|
|
AQH_Endpoint_GetNextMessageId(ep), refMsgId,
|
|
value, timestamp, data);
|
|
AQH_Endpoint_AddMsgOut(ep, outMsg);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|