Heavy work on IPC.

We will now have a broker (aqhome-data) which stores data and distributes
value change messages among connected clients.
aqhomed will connect to that broker and send its values there.
aqhome-mqtt will also connect to the broker and send its values there.
Other clients can later connect to check for changes and react according
to rules.
This commit is contained in:
Martin Preuss
2023-09-10 23:13:03 +02:00
parent 2b733a52ca
commit 518a3a53f9
43 changed files with 1412 additions and 707 deletions

View File

@@ -40,6 +40,11 @@
fini.h
init.h
loop.h
c_connect.h
c_updatedata.h
c_getvalues.h
c_getdatapoints.h
c_getlastdatapoint.h
</headers>
<sources>
@@ -49,6 +54,11 @@
fini.c
init.c
loop.c
c_connect.c
c_updatedata.c
c_getvalues.c
c_getdatapoints.c
c_getlastdatapoint.c
main.c
</sources>

View File

@@ -12,6 +12,7 @@
#include "./aqhome_data_p.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include <gwenhywfar/misc.h>
#include <gwenhywfar/debug.h>
@@ -111,6 +112,23 @@ int AqHomeData_UnlockStorage(AQHOME_DATA *aqh)
GWEN_MSG_ENDPOINT *AqHomeData_GetIpcEndpointByServiceName(const AQHOME_DATA *aqh, const char *serviceName)
{
GWEN_MSG_ENDPOINT *ep;
ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->ipcdEndpoint);
while(ep) {
const char *s;
s=AQH_IpcEndpoint_GetServiceName(ep);
if (s && *s && strcasecmp(s, serviceName)==0)
return ep;
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
}
return NULL;
}

View File

@@ -24,6 +24,8 @@ void AqHomeData_free(AQHOME_DATA *aqh);
GWEN_MSG_ENDPOINT *AqHomeData_GetIpcdEndpoint(const AQHOME_DATA *aqh);
GWEN_MSG_ENDPOINT *AqHomeData_GetIpcEndpointByServiceName(const AQHOME_DATA *aqh, const char *serviceName);
GWEN_DB_NODE *AqHomeData_GetDbArgs(const AQHOME_DATA *aqh);
AQH_STORAGE *AqHomeData_GetStorage(const AQHOME_DATA *aqh);

View File

@@ -0,0 +1,93 @@
/****************************************************************************
* 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 "./c_connect.h"
#include "./aqhome_data_p.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include "aqhome/ipc/data/msg_data_connect.h"
#include "aqhome/ipc/msg_ipc_tag16.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeData_HandleConnect(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
{
GWEN_MSG *outMsg;
int resultCode=AQH_MSG_IPC_SUCCESS;
GWEN_TAG16_LIST *tagList;
char *clientId=NULL;
char *userId=NULL;
char *passw=NULL;
tagList=AQH_Tag16IpcMsg_ParseTags(msg, 0);
if (tagList) {
const GWEN_TAG16 *tag;
tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_CONNECT_TAGS_CLIENTID);
clientId=tag?GWEN_Tag16_GetTagDataAsNewString(tag, NULL):NULL;
tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_CONNECT_TAGS_USERID);
userId=tag?GWEN_Tag16_GetTagDataAsNewString(tag, NULL):NULL;
tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_CONNECT_TAGS_PASSWORD);
passw=tag?GWEN_Tag16_GetTagDataAsNewString(tag, NULL):NULL;
}
if (clientId)
AQH_IpcEndpoint_SetServiceName(ep, clientId);
if (userId)
AQH_IpcEndpoint_SetUserName(ep, userId);
/* TODO: add user management, for now we allow all */
AQH_IpcEndpoint_SetPermissions(ep,
AQH_IPCENDPOINT_PERMS_LISTVALUES |
AQH_IPCENDPOINT_PERMS_READVALUE |
AQH_IPCENDPOINT_PERMS_ADDVALUE |
AQH_IPCENDPOINT_PERMS_LISTDATA |
AQH_IPCENDPOINT_PERMS_READDATA |
AQH_IPCENDPOINT_PERMS_ADDDATA);
free(passw);
free(userId);
free(clientId);
GWEN_Tag16_List_free(tagList);
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT, resultCode);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
}

View File

@@ -0,0 +1,25 @@
/****************************************************************************
* 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.
****************************************************************************/
#ifndef AQHOME_DATA_C_CONNECT_H
#define AQHOME_DATA_C_CONNECT_H
#include "./aqhome_data.h"
void AqHomeData_HandleConnect(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
#endif

View File

@@ -0,0 +1,117 @@
/****************************************************************************
* 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 "./c_getdatapoints.h"
#include "./aqhome_data_p.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/data/msg_data_datapoints.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES 2048
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeData_HandleGetDataPoints(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *recvdMsg)
{
GWEN_MSG *outMsg;
int resultCode=0;
if (AQH_DataPointsDataIpcMsg_IsValid(recvdMsg)) {
const char *valueName;
valueName=AQH_DataPointsDataIpcMsg_GetValueName(recvdMsg);
if (valueName) {
const AQH_VALUE *value;
value=AQH_Storage_GetValueByNameForSystem(aqh->storage, valueName);
if (value) {
uint64_t valueId;
uint32_t numValues;
uint64_t tsBegin=0;
uint64_t tsEnd=0;
uint64_t *tablePtr;
valueId=AQH_Value_GetId(value);
numValues=AQH_DataPointsDataIpcMsg_GetNumValues(recvdMsg);
if (numValues==1) {
const uint64_t *dataPoints;
dataPoints=AQH_DataPointsDataIpcMsg_GetDataPoints(recvdMsg);
tsBegin=dataPoints[0];
tsEnd=dataPoints[1];
}
tablePtr=AQH_Storage_GetDataPoints(aqh->storage, valueId, tsBegin, tsEnd, AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES);
if (tablePtr) {
int numTableEntries;
int numDataPoints;
numTableEntries=(int)(tablePtr[0]);
numDataPoints=numTableEntries/2;
outMsg=AQH_DataPointsDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETDATA_RSP, AQH_MSGDATA_DATAPOINTS_FLAGS_LASTMSG,
valueId,
AQH_Value_GetNameForSystem(value),
AQH_Value_GetValueUnits(value),
&(tablePtr[1]), numDataPoints);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
free(tablePtr);
return;
}
else {
DBG_INFO(NULL, "No matching datapoints for value \"%s\"", valueName);
resultCode=AQH_MSG_IPC_ERROR_NODATA;
}
}
else {
DBG_INFO(NULL, "Value \"%s\" not found", valueName);
resultCode=AQH_MSG_IPC_ERROR_NOTFOUND;
}
}
else {
DBG_INFO(NULL, "No value name in request");
resultCode=AQH_MSG_IPC_ERROR_INVALID;
}
}
else {
DBG_INFO(NULL, "Invalid request message");
resultCode=AQH_MSG_IPC_ERROR_INVALID;
}
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT, resultCode);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
}

View File

@@ -0,0 +1,25 @@
/****************************************************************************
* 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.
****************************************************************************/
#ifndef AQHOME_DATA_C_GETDATAPOINTS_H
#define AQHOME_DATA_C_GETDATAPOINTS_H
#include "./aqhome_data.h"
void AqHomeData_HandleGetDataPoints(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
#endif

View File

@@ -0,0 +1,48 @@
/****************************************************************************
* 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 "./c_getlastdatapoint.h"
#include "./aqhome_data_p.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/data/msg_data_values.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeData_HandleGetLastDataPoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
{
}

View File

@@ -0,0 +1,25 @@
/****************************************************************************
* 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.
****************************************************************************/
#ifndef AQHOME_DATA_C_GETLASTDATAPOINT_H
#define AQHOME_DATA_C_GETLASTDATAPOINT_H
#include "./aqhome_data.h"
void AqHomeData_HandleGetLastDataPoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
#endif

View File

@@ -0,0 +1,96 @@
/****************************************************************************
* 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 "./c_getvalues.h"
#include "./aqhome_data_p.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/data/msg_data_values.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define AQHOMEDATA_VALUESPERMSG 10
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _sendValueList(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE_LIST *vl, uint32_t flags);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeData_HandleGetValues(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
{
const AQH_VALUE_LIST *origValueList;
origValueList=AQH_Storage_GetValueList(aqh->storage);
if (origValueList) {
if (AQH_Value_List_GetCount(origValueList)<AQHOMEDATA_VALUESPERMSG)
_sendValueList(aqh, ep, origValueList, AQH_MSGDATA_VALUES_FLAGS_LASTMSG);
else {
AQH_VALUE_LIST *tmpValueList;
const AQH_VALUE *v;
tmpValueList=AQH_Value_List_new();
v=AQH_Value_List_First(origValueList);
while(v) {
const AQH_VALUE *next;
AQH_VALUE *copyOfValue;
next=AQH_Value_List_Next(v);
copyOfValue=AQH_Value_dup(v);
AQH_Value_List_Add(copyOfValue, tmpValueList);
if (AQH_Value_List_GetCount(tmpValueList)>=AQHOMEDATA_VALUESPERMSG) {
_sendValueList(aqh, ep, tmpValueList, next?0:AQH_MSGDATA_VALUES_FLAGS_LASTMSG);
AQH_Value_List_Clear(tmpValueList);
}
v=next;
}
if (AQH_Value_List_GetCount(tmpValueList))
_sendValueList(aqh, ep, tmpValueList, AQH_MSGDATA_VALUES_FLAGS_LASTMSG); /* send remaining */
AQH_Value_List_free(tmpValueList);
}
}
else {
/* empty list */
_sendValueList(aqh, ep, NULL, AQH_MSGDATA_VALUES_FLAGS_LASTMSG);
}
}
void _sendValueList(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE_LIST *vl, uint32_t flags)
{
GWEN_MSG *msg;
msg=AQH_ValuesDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETVALUES_RSP, flags, vl, 1);
GWEN_MsgEndpoint_AddSendMessage(ep, msg);
}

View File

@@ -0,0 +1,25 @@
/****************************************************************************
* 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.
****************************************************************************/
#ifndef AQHOME_DATA_C_GETVALUES_H
#define AQHOME_DATA_C_GETVALUES_H
#include "./aqhome_data.h"
void AqHomeData_HandleGetValues(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
#endif

View File

@@ -0,0 +1,210 @@
/****************************************************************************
* 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 "./c_updatedata.h"
#include "./aqhome_data_p.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/data/msg_data_datapoints.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _readDataPoints(AQHOME_DATA *aqh, const AQH_VALUE *v, const uint64_t *dataPoints, uint32_t numValues);
static void _sendDataChangedMsgToAllClients(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epSrc, const AQH_VALUE *v,
const uint64_t *dataPoints, uint32_t numValues);
static AQH_VALUE *_getOrCreateValue(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const char *nameForDriver, const char *units);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeData_HandleUpdateData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *recvdMsg)
{
GWEN_MSG *outMsg;
int resultCode=AQH_MSG_IPC_SUCCESS;
if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_ADDDATA) {
if (AQH_DataPointsDataIpcMsg_IsValid(recvdMsg)) {
uint32_t numValues;
numValues=AQH_DataPointsDataIpcMsg_GetNumValues(recvdMsg);
if (numValues) {
const char *s;
s=AQH_DataPointsDataIpcMsg_GetValueName(recvdMsg);
if (s && *s) {
AQH_VALUE *v;
v=_getOrCreateValue(aqh, ep, s, AQH_DataPointsDataIpcMsg_GetUnits(recvdMsg));
if (v==NULL) {
resultCode=AQH_MSG_IPC_ERROR_PERMS;
}
else {
const uint64_t *dataPoints;
dataPoints=AQH_DataPointsDataIpcMsg_GetDataPoints(recvdMsg);
if (dataPoints)
resultCode=_readDataPoints(aqh, v, dataPoints, numValues);
else {
DBG_INFO(NULL, "No datapoints");
resultCode=AQH_MSG_IPC_ERROR_BADDATA;
}
if (resultCode==AQH_MSG_IPC_SUCCESS)
_sendDataChangedMsgToAllClients(aqh, ep, v, dataPoints, numValues);
}
}
else {
DBG_INFO(NULL, "Value without name ");
resultCode=AQH_MSG_IPC_ERROR_INVALID;
}
}
else {
DBG_INFO(NULL, "No datapoints");
resultCode=AQH_MSG_IPC_ERROR_BADDATA;
}
}
else {
DBG_INFO(NULL, "Invalid message received");
resultCode=AQH_MSG_IPC_ERROR_BADDATA;
}
}
else {
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to add data");
resultCode=AQH_MSG_IPC_ERROR_PERMS;
}
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT, resultCode);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
}
int _readDataPoints(AQHOME_DATA *aqh, const AQH_VALUE *v, const uint64_t *dataPoints, uint32_t numValues)
{
uint32_t i;
for(i=0; i<numValues; i++) {
uint64_t timestamp;
union {double f; uint64_t i;} u;
int rv;
timestamp=*(dataPoints++);
u.i=*(dataPoints++);
rv=AQH_Storage_AddDatapoint(aqh->storage, AQH_Value_GetId(v), timestamp, u.f);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return AQH_MSG_IPC_ERROR_GENERIC;
}
else {
DBG_INFO(NULL, "Datapoint added for value \"%s\"", AQH_Value_GetNameForSystem(v));
}
} /* for */
return AQH_MSG_IPC_SUCCESS;
}
void _sendDataChangedMsgToAllClients(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epSrc, const AQH_VALUE *v,
const uint64_t *dataPoints, uint32_t numValues)
{
GWEN_MSG_ENDPOINT *ep;
ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->ipcdEndpoint);
while(ep) {
if (ep!=epSrc) {
if (GWEN_MsgEndpoint_GetFlags(ep) & AQH_IPCENDPOINT_FLAGS_WANTUPDATES) {
GWEN_MSG *msg;
DBG_INFO(AQH_LOGDOMAIN, "Sending update msg to endpoint %s", GWEN_MsgEndpoint_GetName(ep));
msg=AQH_DataPointsDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_DATACHANGED,
0, /* flags */
AQH_Value_GetId(v),
AQH_Value_GetNameForSystem(v),
AQH_Value_GetValueUnits(v),
dataPoints, numValues);
GWEN_MsgEndpoint_AddSendMessage(ep, msg);
}
else {
DBG_INFO(AQH_LOGDOMAIN, "Endpoint %s doesn't want updates", GWEN_MsgEndpoint_GetName(ep));
}
}
else {
DBG_INFO(AQH_LOGDOMAIN, "Not sending update msg to source of updates");
}
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
}
}
AQH_VALUE *_getOrCreateValue(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const char *nameForDriver, const char *units)
{
const char *serviceName;
AQH_VALUE *v;
GWEN_BUFFER *buf;
serviceName=AQH_IpcEndpoint_GetServiceName(ep);
buf=GWEN_Buffer_new(0, 256, 0, 1);
if (serviceName && *serviceName) {
GWEN_Buffer_AppendString(buf, serviceName);
GWEN_Buffer_AppendString(buf, "/");
}
else {
GWEN_Buffer_AppendString(buf, "unknown/");
}
GWEN_Buffer_AppendString(buf, nameForDriver);
v=AQH_Storage_GetValueByNameForSystem(aqh->storage, GWEN_Buffer_GetStart(buf));
if (v==NULL) {
if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_ADDVALUE) {
DBG_INFO(AQH_LOGDOMAIN, "Creating value \"%s\"", GWEN_Buffer_GetStart(buf));
v=AQH_Value_new();
AQH_Value_SetDriver(v, serviceName);
AQH_Value_SetNameForDriver(v, nameForDriver);
AQH_Value_SetNameForSystem(v, GWEN_Buffer_GetStart(buf));
AQH_Value_SetValueUnits(v, units);
AQH_Storage_AddValue(aqh->storage, v);
}
else {
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to create value \"%s\"", GWEN_Buffer_GetStart(buf));
GWEN_Buffer_free(buf);
return NULL;
}
}
GWEN_Buffer_free(buf);
return v;
}

View File

@@ -0,0 +1,25 @@
/****************************************************************************
* 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.
****************************************************************************/
#ifndef AQHOME_DATA_C_UPDATEDATA_H
#define AQHOME_DATA_C_UPDATEDATA_H
#include "./aqhome_data.h"
void AqHomeData_HandleUpdateData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *recvdMsg);
#endif

View File

@@ -12,6 +12,11 @@
#include "./loop.h"
#include "./c_connect.h"
#include "./c_updatedata.h"
#include "./c_getdatapoints.h"
#include "./c_getlastdatapoint.h"
#include "./c_getvalues.h"
#include "./aqhome_data_p.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/data/msg_data_values.h"
@@ -31,8 +36,6 @@
* ------------------------------------------------------------------------------------------------
*/
#define AQHOMEDATA_VALUESPERMSG 10
/* ------------------------------------------------------------------------------------------------
@@ -44,14 +47,6 @@ static void _readAndHandleIpcMessages(AQHOME_DATA *aqh);
static void _handleIpcEndpoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep);
static void _handleIpcMsg(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
static void _handleGetValues(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
static void _sendValueList(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE_LIST *vl, uint32_t flags);
static void _handleAddValue(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
static void _handleEditValues(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
static void _handleAddDataPoints(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
static void _handleGetDataPoints(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
static void _handleGetLastDataPoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
/* ------------------------------------------------------------------------------------------------
@@ -134,260 +129,14 @@ void _handleIpcMsg(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
code=GWEN_IpcMsg_GetCode(msg);
DBG_ERROR(AQH_LOGDOMAIN, "Received IPC packet %d", (int) code);
switch(code) {
case AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ: _handleGetValues(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_ADDVALUES_REQ: _handleAddValue(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_EDITVALUE_REQ: _handleEditValues(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_ADDDATAPOINTS_REQ: _handleAddDataPoints(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_GETDATAPOINTS_REQ: _handleGetDataPoints(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_GETLASTDATAPOINT_REQ: _handleGetLastDataPoint(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_CONNECT_REQ: AqHomeData_HandleConnect(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_UPDATEDATA: AqHomeData_HandleUpdateData(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ: AqHomeData_HandleGetValues(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_GETDATA_REQ: AqHomeData_HandleGetDataPoints(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_GETLASTDATAPOINT_REQ: AqHomeData_HandleGetLastDataPoint(aqh, ep, msg); break;
default: break;
}
}
void _handleGetValues(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
{
const AQH_VALUE_LIST *origValueList;
origValueList=AQH_Storage_GetValueList(aqh->storage);
if (origValueList) {
if (AQH_Value_List_GetCount(origValueList)<AQHOMEDATA_VALUESPERMSG)
_sendValueList(aqh, ep, origValueList, AQH_MSGDATA_VALUES_FLAGS_LASTMSG);
else {
AQH_VALUE_LIST *tmpValueList;
const AQH_VALUE *v;
tmpValueList=AQH_Value_List_new();
v=AQH_Value_List_First(origValueList);
while(v) {
const AQH_VALUE *next;
AQH_VALUE *copyOfValue;
next=AQH_Value_List_Next(v);
copyOfValue=AQH_Value_dup(v);
AQH_Value_List_Add(copyOfValue, tmpValueList);
if (AQH_Value_List_GetCount(tmpValueList)>=AQHOMEDATA_VALUESPERMSG) {
_sendValueList(aqh, ep, tmpValueList, next?0:AQH_MSGDATA_VALUES_FLAGS_LASTMSG);
AQH_Value_List_Clear(tmpValueList);
}
v=next;
}
if (AQH_Value_List_GetCount(tmpValueList))
_sendValueList(aqh, ep, tmpValueList, AQH_MSGDATA_VALUES_FLAGS_LASTMSG); /* send remaining */
AQH_Value_List_free(tmpValueList);
}
}
else {
/* empty list */
_sendValueList(aqh, ep, NULL, AQH_MSGDATA_VALUES_FLAGS_LASTMSG);
}
}
void _sendValueList(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE_LIST *vl, uint32_t flags)
{
GWEN_MSG *msg;
msg=AQH_ValuesDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETVALUES_RSP, flags, vl);
GWEN_MsgEndpoint_AddSendMessage(ep, msg);
}
void _handleAddValue(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *recvdMsg)
{
GWEN_MSG *outMsg;
int resultCode=0;
if (AQH_ValuesDataIpcMsg_IsValid(recvdMsg)) {
uint32_t numValues;
numValues=AQH_ValuesDataIpcMsg_GetNumValues(recvdMsg);
if (numValues==1) {
const char *s;
s=AQH_ValuesDataIpcMsg_GetValueName(recvdMsg, 0);
if (s && *s) {
if (AQH_Storage_GetValueByName(aqh->storage, s)==NULL) {
AQH_VALUE *v;
v=AQH_Value_new();
AQH_Value_SetName(v, s);
s=AQH_ValuesDataIpcMsg_GetValueUnits(recvdMsg, 0);
if (s && *s)
AQH_Value_SetValueUnits(v, s);
DBG_INFO(NULL, "Adding value \"%s\" (%s)", AQH_Value_GetName(v), AQH_Value_GetValueUnits(v));
AQH_Storage_AddValue(aqh->storage, v);
AQH_Storage_AddRuntimeFlags(aqh->storage, AQH_STORAGE_RTFLAGS_MODIFIED);
resultCode=AQH_MSG_IPC_SUCCESS;
}
else {
DBG_INFO(NULL, "Value \"%s\" already exists", s);
resultCode=AQH_MSG_IPC_ERROR_EXISTS;
}
}
else {
DBG_INFO(NULL, "Value without name ");
resultCode=AQH_MSG_IPC_ERROR_INVALID;
}
}
else {
DBG_INFO(NULL, "Invalid number of values in message (%d)", numValues);
resultCode=AQH_MSG_IPC_ERROR_INVALID;
}
}
else {
DBG_INFO(NULL, "Invalid message received");
resultCode=AQH_MSG_IPC_ERROR_BADDATA;
}
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT, resultCode);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
}
void _handleEditValues(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *recvdMsg)
{
GWEN_MSG *outMsg;
int resultCode=0;
if (AQH_ValuesDataIpcMsg_IsValid(recvdMsg)) {
uint32_t numValues;
numValues=AQH_ValuesDataIpcMsg_GetNumValues(recvdMsg);
if (numValues==1) {
const char *s;
s=AQH_ValuesDataIpcMsg_GetValueName(recvdMsg, 0);
if (s && *s) {
AQH_VALUE *v;
v=AQH_Storage_GetValueByName(aqh->storage, s);
if (v==NULL) {
DBG_INFO(NULL, "Value \"%s\" doesn't not exist", s);
resultCode=AQH_MSG_IPC_ERROR_EXISTS;
}
else {
DBG_INFO(NULL, "Updating value \"%s\" (%s)", AQH_Value_GetName(v), AQH_Value_GetValueUnits(v));
s=AQH_ValuesDataIpcMsg_GetValueUnits(recvdMsg, 0);
if (s && *s)
AQH_Value_SetValueUnits(v, s);
AQH_Storage_AddRuntimeFlags(aqh->storage, AQH_STORAGE_RTFLAGS_MODIFIED);
resultCode=AQH_MSG_IPC_SUCCESS;
}
}
else {
DBG_INFO(NULL, "Value without name ");
resultCode=AQH_MSG_IPC_ERROR_INVALID;
}
}
else {
DBG_INFO(NULL, "Invalid number of values in message (%d)", numValues);
resultCode=AQH_MSG_IPC_ERROR_INVALID;
}
}
else {
DBG_INFO(NULL, "Invalid message received");
resultCode=AQH_MSG_IPC_ERROR_BADDATA;
}
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT, resultCode);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
}
void _handleAddDataPoints(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *recvdMsg)
{
GWEN_MSG *outMsg;
int resultCode=0;
if (AQH_DataPointsDataIpcMsg_IsValid(recvdMsg)) {
uint32_t numValues;
numValues=AQH_DataPointsDataIpcMsg_GetNumValues(recvdMsg);
if (numValues) {
const char *s;
s=AQH_DataPointsDataIpcMsg_GetValueName(recvdMsg);
if (s && *s) {
AQH_VALUE *v;
v=AQH_Storage_GetValueByName(aqh->storage, s);
if (v==NULL) {
// TODO: maybe create the value on the fly
DBG_INFO(NULL, "Value \"%s\" doesn't not exist", s);
resultCode=AQH_MSG_IPC_ERROR_EXISTS;
}
else {
const uint64_t *dataPoints;
dataPoints=AQH_DataPointsDataIpcMsg_GetDataPoints(recvdMsg);
if (dataPoints) {
uint32_t i;
for(i=0; i<numValues; i++) {
uint64_t timestamp;
union {double f; uint64_t i;} u;
int rv;
timestamp=*(dataPoints++);
u.i=*(dataPoints++);
rv=AQH_Storage_AddDatapoint(aqh->storage, AQH_Value_GetId(v), timestamp, u.f);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
resultCode=AQH_MSG_IPC_ERROR_GENERIC;
}
else {
DBG_INFO(NULL, "Datapoint added for value \"%s\"", s);
resultCode=0;
}
} /* for */
} /* if datapoints */
else {
DBG_INFO(NULL, "No datapoints");
resultCode=AQH_MSG_IPC_ERROR_BADDATA;
}
}
}
else {
DBG_INFO(NULL, "Value without name ");
resultCode=AQH_MSG_IPC_ERROR_INVALID;
}
}
else {
DBG_INFO(NULL, "No datapoints");
resultCode=AQH_MSG_IPC_ERROR_BADDATA;
}
}
else {
DBG_INFO(NULL, "Invalid message received");
resultCode=AQH_MSG_IPC_ERROR_BADDATA;
}
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT, resultCode);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
}
void _handleGetDataPoints(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
{
}
void _handleGetLastDataPoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
{
}