From cf8edbbd5fd26768b1969b90e338dfdf39a855b1 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Tue, 25 Feb 2025 01:13:07 +0100 Subject: [PATCH] aqhome: started rewriting message code, start using new event2 lib. --- aqhome/events2/eventloop.c | 2 +- aqhome/events2/eventloop.h | 2 +- aqhome/events2/fdobject.c | 154 ++++++- aqhome/events2/fdobject.h | 12 + aqhome/events2/fdobject_p.h | 3 + aqhome/events2/object.c | 8 +- aqhome/ipc2/0BUILD | 15 + aqhome/ipc2/ipcmsgreader.c | 149 +++++++ aqhome/ipc2/ipcmsgreader.h | 20 + aqhome/ipc2/message.c | 355 +++++++++++++++ aqhome/ipc2/message.h | 72 +++ aqhome/ipc2/message_p.h | 37 ++ aqhome/ipc2/msgreader.c | 400 ++++++++++------- aqhome/ipc2/msgreader.h | 5 +- aqhome/ipc2/msgreader_p.h | 38 +- aqhome/ipc2/msgwriter.c | 240 ++++++++++ aqhome/ipc2/msgwriter.h | 38 ++ aqhome/ipc2/msgwriter_p.h | 34 ++ aqhome/ipc2/nodeendpoint.c | 236 ++++++++++ aqhome/ipc2/nodeendpoint.h | 37 ++ aqhome/ipc2/nodeendpoint_p.h | 27 ++ aqhome/ipc2/nodemsgreader.c | 185 ++++++++ aqhome/ipc2/nodemsgreader.h | 20 + aqhome/ipc2/ttyobject.c | 230 ++++++++++ aqhome/ipc2/ttyobject.h | 38 ++ aqhome/libtest.c | 57 ++- aqhome/msg/0BUILD | 4 + aqhome/msg/ipc/0BUILD | 84 ++++ aqhome/msg/ipc/data/0BUILD | 90 ++++ aqhome/msg/ipc/data/m_ipcd.c | 56 +++ aqhome/msg/ipc/data/m_ipcd.h | 57 +++ aqhome/msg/ipc/data/m_ipcd_connect.c | 90 ++++ aqhome/msg/ipc/data/m_ipcd_connect.h | 40 ++ aqhome/msg/ipc/data/m_ipcd_devices.c | 119 +++++ aqhome/msg/ipc/data/m_ipcd_devices.h | 41 ++ aqhome/msg/ipc/data/m_ipcd_getdata.c | 87 ++++ aqhome/msg/ipc/data/m_ipcd_getdata.h | 38 ++ aqhome/msg/ipc/data/m_ipcd_multidata.c | 158 +++++++ aqhome/msg/ipc/data/m_ipcd_multidata.h | 44 ++ aqhome/msg/ipc/data/m_ipcd_setdata.c | 120 +++++ aqhome/msg/ipc/data/m_ipcd_setdata.h | 43 ++ aqhome/msg/ipc/data/m_ipcd_values.c | 119 +++++ aqhome/msg/ipc/data/m_ipcd_values.h | 41 ++ aqhome/msg/ipc/m_ipc.c | 159 +++++++ aqhome/msg/ipc/m_ipc.h | 85 ++++ aqhome/msg/ipc/m_ipc_result.c | 81 ++++ aqhome/msg/ipc/m_ipc_result.h | 33 ++ aqhome/msg/ipc/m_ipc_tag16.c | 582 +++++++++++++++++++++++++ aqhome/msg/ipc/m_ipc_tag16.h | 43 ++ aqhome/msg/node/0BUILD | 84 ++++ aqhome/msg/node/m_device.c | 186 ++++++++ aqhome/msg/node/m_device.h | 42 ++ aqhome/msg/node/m_node.c | 262 +++++++++++ aqhome/msg/node/m_node.h | 121 +++++ aqhome/msg/node/m_recvstats.c | 97 +++++ aqhome/msg/node/m_recvstats.h | 32 ++ aqhome/msg/node/m_sendstats.c | 70 +++ aqhome/msg/node/m_sendstats.h | 34 ++ 58 files changed, 5393 insertions(+), 163 deletions(-) create mode 100644 aqhome/ipc2/ipcmsgreader.c create mode 100644 aqhome/ipc2/ipcmsgreader.h create mode 100644 aqhome/ipc2/message.c create mode 100644 aqhome/ipc2/message.h create mode 100644 aqhome/ipc2/message_p.h create mode 100644 aqhome/ipc2/msgwriter.c create mode 100644 aqhome/ipc2/msgwriter.h create mode 100644 aqhome/ipc2/msgwriter_p.h create mode 100644 aqhome/ipc2/nodeendpoint.c create mode 100644 aqhome/ipc2/nodeendpoint.h create mode 100644 aqhome/ipc2/nodeendpoint_p.h create mode 100644 aqhome/ipc2/nodemsgreader.c create mode 100644 aqhome/ipc2/nodemsgreader.h create mode 100644 aqhome/ipc2/ttyobject.c create mode 100644 aqhome/ipc2/ttyobject.h create mode 100644 aqhome/msg/ipc/0BUILD create mode 100644 aqhome/msg/ipc/data/0BUILD create mode 100644 aqhome/msg/ipc/data/m_ipcd.c create mode 100644 aqhome/msg/ipc/data/m_ipcd.h create mode 100644 aqhome/msg/ipc/data/m_ipcd_connect.c create mode 100644 aqhome/msg/ipc/data/m_ipcd_connect.h create mode 100644 aqhome/msg/ipc/data/m_ipcd_devices.c create mode 100644 aqhome/msg/ipc/data/m_ipcd_devices.h create mode 100644 aqhome/msg/ipc/data/m_ipcd_getdata.c create mode 100644 aqhome/msg/ipc/data/m_ipcd_getdata.h create mode 100644 aqhome/msg/ipc/data/m_ipcd_multidata.c create mode 100644 aqhome/msg/ipc/data/m_ipcd_multidata.h create mode 100644 aqhome/msg/ipc/data/m_ipcd_setdata.c create mode 100644 aqhome/msg/ipc/data/m_ipcd_setdata.h create mode 100644 aqhome/msg/ipc/data/m_ipcd_values.c create mode 100644 aqhome/msg/ipc/data/m_ipcd_values.h create mode 100644 aqhome/msg/ipc/m_ipc.c create mode 100644 aqhome/msg/ipc/m_ipc.h create mode 100644 aqhome/msg/ipc/m_ipc_result.c create mode 100644 aqhome/msg/ipc/m_ipc_result.h create mode 100644 aqhome/msg/ipc/m_ipc_tag16.c create mode 100644 aqhome/msg/ipc/m_ipc_tag16.h create mode 100644 aqhome/msg/node/0BUILD create mode 100644 aqhome/msg/node/m_device.c create mode 100644 aqhome/msg/node/m_device.h create mode 100644 aqhome/msg/node/m_node.c create mode 100644 aqhome/msg/node/m_node.h create mode 100644 aqhome/msg/node/m_recvstats.c create mode 100644 aqhome/msg/node/m_recvstats.h create mode 100644 aqhome/msg/node/m_sendstats.c create mode 100644 aqhome/msg/node/m_sendstats.h diff --git a/aqhome/events2/eventloop.c b/aqhome/events2/eventloop.c index a37bc0d..406511b 100644 --- a/aqhome/events2/eventloop.c +++ b/aqhome/events2/eventloop.c @@ -17,7 +17,7 @@ -AQH_EVENT_LOOP *AQH_EventLoop_new() +AQH_EVENT_LOOP *AQH_EventLoop_new(void) { AQH_EVENT_LOOP *eventLoop; diff --git a/aqhome/events2/eventloop.h b/aqhome/events2/eventloop.h index 9d95bcd..a73570d 100644 --- a/aqhome/events2/eventloop.h +++ b/aqhome/events2/eventloop.h @@ -16,7 +16,7 @@ typedef struct AQH_EVENT_LOOP AQH_EVENT_LOOP; -AQHOME_API AQH_EVENT_LOOP *AQH_EventLoop_new(); +AQHOME_API AQH_EVENT_LOOP *AQH_EventLoop_new(void); AQHOME_API void AQH_EventLoop_free(AQH_EVENT_LOOP *eventLoop); AQHOME_API void AQH_EventLoop_Run(AQH_EVENT_LOOP *eventLoop); diff --git a/aqhome/events2/fdobject.c b/aqhome/events2/fdobject.c index e33bcd1..252b0c4 100644 --- a/aqhome/events2/fdobject.c +++ b/aqhome/events2/fdobject.c @@ -1,6 +1,6 @@ /**************************************************************************** * This file is part of the project Gwenhywfar. - * Gwenhywfar (c) by 2023 Martin Preuss, all rights reserved. + * Gwenhywfar (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. @@ -15,10 +15,10 @@ #include #include -#include +//#include #include #include - +#include GWEN_INHERIT(AQH_OBJECT, AQH_FDOBJECT) @@ -71,6 +71,40 @@ void GWENHYWFAR_CB _freeData(GWEN_UNUSED void *bp, void *p) +AQH_FDOBJECT_STARTMSG_FN AQH_FdObject_SetStartMsgFn(AQH_OBJECT *o, AQH_FDOBJECT_STARTMSG_FN f) +{ + AQH_FDOBJECT *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_FDOBJECT, o); + if (xo) { + AQH_FDOBJECT_STARTMSG_FN oldFn; + + oldFn=xo->startMsgFn; + xo->startMsgFn=f; + return oldFn; + } + return NULL; +} + + + +AQH_FDOBJECT_ENDMSG_FN AQH_FdObject_SetEndMsgFn(AQH_OBJECT *o, AQH_FDOBJECT_ENDMSG_FN f) +{ + AQH_FDOBJECT *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_FDOBJECT, o); + if (xo) { + AQH_FDOBJECT_ENDMSG_FN oldFn; + + oldFn=xo->endMsgFn; + xo->endMsgFn=f; + return oldFn; + } + return NULL; +} + + + int AQH_FdObject_GetFdMode(const AQH_OBJECT *o) { if (o) { @@ -124,17 +158,18 @@ int AQH_FdObject_Read(AQH_OBJECT *o, uint8_t *ptrBuffer, uint32_t lenBuffer) if (xo->fd!=-1) { ssize_t rv; - rv=recv(xo->fd, ptrBuffer, lenBuffer, MSG_DONTWAIT); + rv=read(xo->fd, ptrBuffer, lenBuffer); if (rv==0) { DBG_INFO(AQH_LOGDOMAIN, "EOF met"); return 0; } else if (rv>0) { /* data received */ + DBG_ERROR(AQH_LOGDOMAIN, "Received %d bytes", (int) rv); return (int) rv; } else { - if (rv==EINTR || errno==EWOULDBLOCK || errno==EAGAIN) { + if (errno==EINTR || errno==EWOULDBLOCK || errno==EAGAIN) { /* temporarily no data, try again */ return GWEN_ERROR_TRY_AGAIN; } @@ -157,6 +192,115 @@ int AQH_FdObject_Read(AQH_OBJECT *o, uint8_t *ptrBuffer, uint32_t lenBuffer) +int AQH_FdObject_FlushInput(AQH_OBJECT *o) +{ + if (o) { + AQH_FDOBJECT *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_FDOBJECT, o); + if (xo) { + if (xo->fd!=-1) { + ssize_t rv; + ssize_t bytesRead=0; + uint8_t tbuf[16]; + + do { + rv=read(xo->fd, tbuf, sizeof(tbuf)); + if (rv>0) + bytesRead+=rv; + } while(rv>=0); + + if (rv==0) { + DBG_INFO(AQH_LOGDOMAIN, "EOF met"); + return GWEN_ERROR_EOF; + } + else if (rv<0) { + if (errno!=EINTR && errno!=EWOULDBLOCK && errno!=EAGAIN) { + DBG_ERROR(AQH_LOGDOMAIN, "Error on read: %s (%d)", strerror(errno), errno); + xo->fd=-1; + return GWEN_ERROR_IO; + } + } + return (bytesRead>0)?1:0; + } + else { + DBG_ERROR(AQH_LOGDOMAIN, "Previous error, not reading."); + return GWEN_ERROR_IO; + } + } + } + + return GWEN_ERROR_INVALID; +} + + + +int AQH_FdObject_Write(AQH_OBJECT *o, const uint8_t *ptrBuffer, uint32_t lenBuffer) +{ + if (o && ptrBuffer && lenBuffer) { + AQH_FDOBJECT *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_FDOBJECT, o); + if (xo) { + if (xo->fd!=-1) { + ssize_t rv; + + rv=write(xo->fd, ptrBuffer, lenBuffer); + if (rv<0) { + if (errno==EINTR || errno==EWOULDBLOCK || errno==EAGAIN) { + /* temporarily no data, try again */ + return GWEN_ERROR_TRY_AGAIN; + } + else { + DBG_ERROR(AQH_LOGDOMAIN, "Error on write: %s (%d)", strerror(errno), errno); + xo->fd=-1; + return GWEN_ERROR_IO; + } + } + else { + /* data received */ + return (int) rv; + } + } + else { + DBG_ERROR(AQH_LOGDOMAIN, "Previous error, not writing."); + return GWEN_ERROR_IO; + } + } + } + + return GWEN_ERROR_INVALID; +} + + + +int AQH_FdObject_StartMsg(AQH_OBJECT *o) +{ + if (o) { + AQH_FDOBJECT *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_FDOBJECT, o); + if (xo && xo->startMsgFn) + return xo->startMsgFn(o); + } + return 0; +} + + + +void AQH_FdObject_EndMsg(AQH_OBJECT *o) +{ + if (o) { + AQH_FDOBJECT *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_FDOBJECT, o); + if (xo && xo->endMsgFn) + xo->endMsgFn(o); + } +} + + + void _cbEnable(AQH_OBJECT *o) { if (o && !(AQH_Object_GetFlags(o) & AQH_OBJECT_FLAGS_ENABLED)) { diff --git a/aqhome/events2/fdobject.h b/aqhome/events2/fdobject.h index 9289d81..4d4779b 100644 --- a/aqhome/events2/fdobject.h +++ b/aqhome/events2/fdobject.h @@ -24,6 +24,10 @@ enum { }; +typedef int (*AQH_FDOBJECT_STARTMSG_FN)(AQH_OBJECT *o); +typedef void (*AQH_FDOBJECT_ENDMSG_FN)(AQH_OBJECT *o); + + AQHOME_API AQH_OBJECT *AQH_FdObject_new(AQH_EVENT_LOOP *eventLoop, int fd, int mode); @@ -33,6 +37,14 @@ AQHOME_API void AQH_FdObject_SetFdMode(AQH_OBJECT *o, int i); AQHOME_API int AQH_FdObject_GetFd(const AQH_OBJECT *o); AQHOME_API int AQH_FdObject_Read(AQH_OBJECT *o, uint8_t *ptrBuffer, uint32_t lenBuffer); +AQHOME_API int AQH_FdObject_Write(AQH_OBJECT *o, const uint8_t *ptrBuffer, uint32_t lenBuffer); +AQHOME_API int AQH_FdObject_FlushInput(AQH_OBJECT *o); + +AQHOME_API int AQH_FdObject_StartMsg(AQH_OBJECT *o); +AQHOME_API void AQH_FdObject_EndMsg(AQH_OBJECT *o); + +AQHOME_API AQH_FDOBJECT_STARTMSG_FN AQH_FdObject_SetStartMsgFn(AQH_OBJECT *o, AQH_FDOBJECT_STARTMSG_FN f); +AQHOME_API AQH_FDOBJECT_ENDMSG_FN AQH_FdObject_SetEndMsgFn(AQH_OBJECT *o, AQH_FDOBJECT_ENDMSG_FN f); #endif diff --git a/aqhome/events2/fdobject_p.h b/aqhome/events2/fdobject_p.h index c3793b3..5d1a4b1 100644 --- a/aqhome/events2/fdobject_p.h +++ b/aqhome/events2/fdobject_p.h @@ -17,6 +17,9 @@ typedef struct AQH_FDOBJECT AQH_FDOBJECT; struct AQH_FDOBJECT { int fdMode; int fd; + + AQH_FDOBJECT_STARTMSG_FN startMsgFn; + AQH_FDOBJECT_ENDMSG_FN endMsgFn; }; diff --git a/aqhome/events2/object.c b/aqhome/events2/object.c index 61a3a24..d50118c 100644 --- a/aqhome/events2/object.c +++ b/aqhome/events2/object.c @@ -19,10 +19,10 @@ * ------------------------------------------------------------------------------------------------ */ -AQH_LINK *AQH_Link_new(); -void AQH_Link_free(AQH_LINK *ln); +static AQH_LINK *AQH_Link_new(); +static void AQH_Link_free(AQH_LINK *ln); -AQH_LINK *_findLink(AQH_OBJECT *o, uint32_t signalId, uint32_t slotId, AQH_OBJECT *targetObject); +static AQH_LINK *_findLink(AQH_OBJECT *o, uint32_t signalId, uint32_t slotId, AQH_OBJECT *targetObject); @@ -54,7 +54,7 @@ AQH_OBJECT *AQH_Object_new(AQH_EVENT_LOOP *eventLoop) o->eventLoop=eventLoop; o->linkList=AQH_Link_List_new(); - return 0; + return o; } diff --git a/aqhome/ipc2/0BUILD b/aqhome/ipc2/0BUILD index e4dabe8..a9c2dd7 100644 --- a/aqhome/ipc2/0BUILD +++ b/aqhome/ipc2/0BUILD @@ -46,13 +46,22 @@ msgreader.h + msgwriter.h + ipcmsgreader.h + nodemsgreader.h + ttyobject.h tcpd_object.h + nodeendpoint.h + message.h msgreader_p.h + msgwriter_p.h tcpd_object_p.h + nodeendpoint_p.h + message_p.h @@ -60,7 +69,13 @@ $(local/typefiles) msgreader.c + msgwriter.c + ipcmsgreader.c + nodemsgreader.c + ttyobject.c tcpd_object.c + nodeendpoint.c + message.c diff --git a/aqhome/ipc2/ipcmsgreader.c b/aqhome/ipc2/ipcmsgreader.c new file mode 100644 index 0000000..4f6f5c5 --- /dev/null +++ b/aqhome/ipc2/ipcmsgreader.c @@ -0,0 +1,149 @@ +/**************************************************************************** + * 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 "./ipcmsgreader.h" +#include "./msgreader_p.h" +#include + +#include +#include +#include + +#include + + +#define AQH_MSG_READER_HEADER_SIZE 4 +#define AQH_MSG_READER_MINMSGSIZE 12 +#define AQH_MSG_READER_MAXMSGSIZE 10240 + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static int _readMsg(AQH_OBJECT *o); +static int _readHeaderFromRingbuffer(AQH_MSG_READER *xo); + + + +/* ------------------------------------------------------------------------------------------------ + * implementation + * ------------------------------------------------------------------------------------------------ + */ + +AQH_OBJECT *AQH_IpcMsgReader_new(AQH_EVENT_LOOP *eventLoop, AQH_OBJECT *fdObject) +{ + AQH_OBJECT *o; + + o=AQH_MsgReader_new(eventLoop, fdObject); + AQH_MsgReader_SetReadMsgFn(o, _readMsg); + + return o; +} + + + +int _readMsg(AQH_OBJECT *o) +{ + AQH_MSG_READER *xo; + + xo=AQH_MsgReader_GetData(o); + if (xo) { + int rv; + + if (xo->bytesReceivedbytesReceived>=AQH_MSG_READER_HEADER_SIZE) { + /* reading remainder of msg directly into allocated buffer */ + rv=AQH_MsgReader_ReadRemainderFromRingbuffer(o); + if (rv<0) { + DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); + return rv; + } + else if (rv==1) { + int msgLen; + uint8_t *msgPtr; + + msgLen=xo->bytesReceived; + msgPtr=xo->currentMsgBuf; + + xo->bytesReceived=0; + xo->bytesLeft=0; + xo->currentMsgBuf=NULL; + + rv=AQH_Object_EmitSignal(o, AQH_MSG_READER_SIGNAL_MSGRECVD, msgLen, (void*) msgPtr); + if (rv==0) { + DBG_INFO(AQH_LOGDOMAIN, "Received message ignored"); + } + free(msgPtr); + return 1; + } + } + return 0; + } + return GWEN_ERROR_GENERIC; +} + + + +int _readHeaderFromRingbuffer(AQH_MSG_READER *xo) +{ + uint32_t remaining; + int rv; + uint32_t xferSize; + uint32_t bytesInBuffer; + + bytesInBuffer=GWEN_RingBuffer_GetUsedBytes(xo->ringBuffer); + + /* still reading header */ + remaining=AQH_MSG_READER_HEADER_SIZE-xo->bytesReceived; + if (bytesInBufferringBuffer, (char*) (xo->headerBuffer+xo->bytesReceived), &xferSize); + if (rv<0) { + DBG_INFO(AQH_LOGDOMAIN, "Ringbuffer empty"); + return 0; + } + if (xferSizebytesReceived+=xferSize; + if (xo->bytesReceived==AQH_MSG_READER_HEADER_SIZE) { + uint32_t msgLen; + + /* full size received, parse msg size, allocate buffer */ + msgLen=GWEN_ENDIAN_LE32TOH(*((const uint32_t*)(xo->headerBuffer))); + if (msgLenAQH_MSG_READER_MAXMSGSIZE) { + DBG_ERROR(AQH_LOGDOMAIN, "Bad message size(%lu)", (unsigned long int) msgLen); + return GWEN_ERROR_GENERIC; + } + xo->currentMsgBuf=(uint8_t*) malloc(msgLen+4); /* +4 because of msg len (4 bytes) */ + memmove(xo->currentMsgBuf, xo->headerBuffer, xo->bytesReceived); + xo->bytesLeft=(msgLen+4)-xo->bytesReceived; + } + + return 0; +} + + + + diff --git a/aqhome/ipc2/ipcmsgreader.h b/aqhome/ipc2/ipcmsgreader.h new file mode 100644 index 0000000..43bc996 --- /dev/null +++ b/aqhome/ipc2/ipcmsgreader.h @@ -0,0 +1,20 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_IPCMSGREADER_H +#define AQH_IPCMSGREADER_H + +#include + + +AQH_OBJECT *AQH_IpcMsgReader_new(AQH_EVENT_LOOP *eventLoop, AQH_OBJECT *fdObject); + + + +#endif + diff --git a/aqhome/ipc2/message.c b/aqhome/ipc2/message.c new file mode 100644 index 0000000..27439f9 --- /dev/null +++ b/aqhome/ipc2/message.c @@ -0,0 +1,355 @@ +/**************************************************************************** + * 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 "./message_p.h" + +#include +#include +#include + + + +GWEN_LIST_FUNCTIONS(AQH_MESSAGE, AQH_Message) +GWEN_INHERIT_FUNCTIONS(AQH_MESSAGE) + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _ensureSize(AQH_MESSAGE *msg, uint32_t neededSize); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +AQH_MESSAGE *AQH_Message_new(void) +{ + AQH_MESSAGE *msg; + + GWEN_NEW_OBJECT(AQH_MESSAGE, msg); + GWEN_INHERIT_INIT(AQH_MESSAGE, msg); + GWEN_LIST_INIT(AQH_MESSAGE, msg); + msg->refCount=1; + + return msg; +} + + + +void AQH_Message_IncRef(AQH_MESSAGE *msg) +{ + if (msg && msg->refCount) + msg->refCount++; +} + + + +void AQH_Message_free(AQH_MESSAGE *msg) +{ + if (msg && msg->refCount>0) { + if (msg->refCount==1) { + msg->refCount=0; + GWEN_LIST_FINI(AQH_MESSAGE, msg); + GWEN_INHERIT_FINI(AQH_MESSAGE, msg); + free(msg->msgPointer); + GWEN_FREE_OBJECT(msg); + } + else + msg->refCount--; + } +} + + + +uint8_t *AQH_Message_GetMsgPointer(const AQH_MESSAGE *msg) +{ + return (msg && msg->refCount)?msg->msgPointer:NULL; +} + + + +uint32_t AQH_Message_GetMsgSize(const AQH_MESSAGE *msg) +{ + return (msg && msg->refCount)?msg->msgSize:0; +} + + + +void AQH_Message_SetData(AQH_MESSAGE *msg, const uint8_t *msgPtr, uint32_t msgSize) +{ + if (msg && msg->refCount) { + free(msg->msgPointer); + msg->msgPointer=NULL; + msg->msgSize=0; + if (msgSize) { + msg->msgPointer=(uint8_t*) malloc(msgSize); + if (msg->msgPointer) { + if (msgPtr) + memmove(msg->msgPointer, msgPtr, msgSize); + else + memset(msg->msgPointer, 0, msgSize); + msg->msgSize=msgSize; + } + } + } +} + + + +uint32_t AQH_Message_GetUsedSize(const AQH_MESSAGE *msg) +{ + return msg?msg->usedSize:0; +} + + + +void AQH_Message_SetUsedSize(AQH_MESSAGE *msg, uint32_t i) +{ + if (msg) { + _ensureSize(msg, i); + msg->usedSize=i; + } +} + + + +void AQH_Message_IncUsedSize(AQH_MESSAGE *msg, uint32_t i) +{ + if (msg) { + _ensureSize(msg, msg->usedSize+i); + msg->usedSize+=i; + } +} + + + +int AQH_Message_GetMsgType(const AQH_MESSAGE *msg) +{ + return (msg && msg->refCount)?msg->msgType:0; +} + + + +void AQH_Message_SetMsgType(AQH_MESSAGE *msg, int i) +{ + if (msg && msg->refCount) + msg->msgType=i; +} + + +int AQH_Message_GetMsgProtoId(const AQH_MESSAGE *msg) +{ + return (msg && msg->refCount)?msg->msgProtoId:0; +} + + + +void AQH_Message_SetMsgProtoId(AQH_MESSAGE *msg, int i) +{ + if (msg && msg->refCount) + msg->msgProtoId=i; +} + + + +int AQH_Message_GetMsgProtoVer(const AQH_MESSAGE *msg) +{ + return (msg && msg->refCount)?msg->msgProtoVer:0; +} + + + +void AQH_Message_SetMsgProtoVer(AQH_MESSAGE *msg, int i) +{ + if (msg && msg->refCount) + msg->msgProtoVer=i; +} + + + +int AQH_Message_GetMsgCommand(const AQH_MESSAGE *msg) +{ + return (msg && msg->refCount)?msg->msgCommand:0; +} + + + +void AQH_Message_SetMsgCommand(AQH_MESSAGE *msg, int i) +{ + if (msg && msg->refCount) + msg->msgCommand=i; +} + + + +void AQH_Message_WriteUint8At(AQH_MESSAGE *msg, uint32_t pos, uint8_t d) +{ + if (msg) { + _ensureSize(msg, pos+1); + msg->msgPointer[pos]=d; + } +} + + + +uint8_t AQH_Message_ReadUint8At(const AQH_MESSAGE *msg, uint32_t pos, uint8_t defaultValue) +{ + if (msg && msg->msgPointer && msg->msgSize>=pos+1) + return msg->msgPointer[pos]; + return defaultValue; +} + + + +void AQH_Message_WriteUint16At(AQH_MESSAGE *msg, uint32_t pos, uint16_t d) +{ + if (msg) { + _ensureSize(msg, pos+2); + *( (uint16_t*) (msg->msgPointer+pos) )=GWEN_ENDIAN_HTOLE16(d); + } +} + + + +uint16_t AQH_Message_ReadUint16At(const AQH_MESSAGE *msg, uint32_t pos, uint16_t defaultValue) +{ + if (msg && msg->msgPointer && msg->msgSize>=pos+2) + return GWEN_ENDIAN_LE16TOH(*( (uint16_t*) (msg->msgPointer+pos) )); + return defaultValue; +} + + + +void AQH_Message_WriteUint32At(AQH_MESSAGE *msg, uint32_t pos, uint32_t d) +{ + if (msg) { + _ensureSize(msg, pos+4); + *( (uint32_t*) (msg->msgPointer+pos) )=GWEN_ENDIAN_HTOLE32(d); + } +} + + + +uint32_t AQH_Message_ReadUint32At(const AQH_MESSAGE *msg, uint32_t pos, uint32_t defaultValue) +{ + if (msg && msg->msgPointer && msg->msgSize>=pos+4) + return GWEN_ENDIAN_LE32TOH(*( (uint32_t*) (msg->msgPointer+pos) )); + return defaultValue; +} + + + +void AQH_Message_WriteUint64At(AQH_MESSAGE *msg, uint32_t pos, uint64_t d) +{ + if (msg) { + _ensureSize(msg, pos+8); + *( (uint64_t*) (msg->msgPointer+pos) )=GWEN_ENDIAN_HTOLE64(d); + } +} + + + +uint64_t AQH_Message_ReadUint64At(const AQH_MESSAGE *msg, uint32_t pos, uint64_t defaultValue) +{ + if (msg && msg->msgPointer && msg->msgSize>=pos+8) + return GWEN_ENDIAN_LE64TOH(*( (uint64_t*) (msg->msgPointer+pos) )); + return defaultValue; +} + + + +void AQH_Message_WriteBytesAt(AQH_MESSAGE *msg, uint32_t pos, const uint8_t *bufferPtr, uint32_t bufferLen) +{ + if (msg && bufferPtr && bufferLen) { + _ensureSize(msg, pos+bufferLen); + memmove(msg->msgPointer+pos, bufferPtr, bufferLen); + } +} + + + +int AQH_Message_WriteStringAt(AQH_MESSAGE *msg, uint32_t pos, uint32_t maxSize, int filler, const char *s) +{ + if (msg && maxSize) { + uint32_t slen=0; + + if (s) { + slen=strlen(s); + if (slen>maxSize) { + DBG_ERROR(AQH_LOGDOMAIN, "String too long (%d > %d)", slen, maxSize); + return GWEN_ERROR_INVALID; + } + } + _ensureSize(msg, pos+maxSize); + if (s) + memmove(msg->msgPointer+pos, s, slen); + if (slenmsgPointer+pos+slen, filler, maxSize-slen); + } + return 0; +} + + + +int AQH_Message_WriteStringWithTrailingNullAt(AQH_MESSAGE *msg, uint32_t pos, uint32_t maxSize, int filler, const char *s) +{ + if (msg && maxSize) { + uint32_t slen=1; + + if (s) { + slen=strlen(s)+1; + if (slen>maxSize) { + DBG_ERROR(AQH_LOGDOMAIN, "String too long (%d > %d)", slen, maxSize); + return GWEN_ERROR_INVALID; + } + } + _ensureSize(msg, pos+maxSize); + if (s) + memmove(msg->msgPointer+pos, s, slen); + if (slenmsgPointer+pos+slen, filler, maxSize-slen); + } + return 0; +} + + + +void _ensureSize(AQH_MESSAGE *msg, uint32_t neededSize) +{ + if (msg && neededSize) { + if (msg->msgPointer==0 || msg->msgSize==0) { + msg->msgPointer=(uint8_t*) malloc(neededSize); + assert(msg->msgPointer); + } + else { + if (neededSize>msg->msgSize) { + uint8_t *ptr; + + ptr=realloc(msg->msgPointer, neededSize); + assert(ptr); + if (ptr) { + msg->msgPointer=ptr; + msg->msgSize=neededSize; + } + } + } + } +} + + + diff --git a/aqhome/ipc2/message.h b/aqhome/ipc2/message.h new file mode 100644 index 0000000..6d0b8e7 --- /dev/null +++ b/aqhome/ipc2/message.h @@ -0,0 +1,72 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_MESSAGE_H +#define AQH_MESSAGE_H + + +#include + +#include +#include + + + +typedef struct AQH_MESSAGE AQH_MESSAGE; +GWEN_LIST_FUNCTION_LIB_DEFS(AQH_MESSAGE, AQH_Message, AQHOME_API) +GWEN_INHERIT_FUNCTION_LIB_DEFS(AQH_MESSAGE, AQHOME_API) + + + +AQHOME_API AQH_MESSAGE *AQH_Message_new(void); +AQHOME_API void AQH_Message_IncRef(AQH_MESSAGE *msg); +AQHOME_API void AQH_Message_free(AQH_MESSAGE *msg); + + +/* unparsed data */ +AQHOME_API uint8_t *AQH_Message_GetMsgPointer(const AQH_MESSAGE *msg); +AQHOME_API uint32_t AQH_Message_GetMsgSize(const AQH_MESSAGE *msg); +AQHOME_API void AQH_Message_SetData(AQH_MESSAGE *msg, const uint8_t *msgPtr, uint32_t msgSize); + +AQHOME_API uint32_t AQH_Message_GetUsedSize(const AQH_MESSAGE *msg); +AQHOME_API void AQH_Message_SetUsedSize(AQH_MESSAGE *msg, uint32_t i); +AQHOME_API void AQH_Message_IncUsedSize(AQH_MESSAGE *msg, uint32_t i); + +/* parsed header data */ +AQHOME_API int AQH_Message_GetMsgType(const AQH_MESSAGE *msg); +AQHOME_API void AQH_Message_SetMsgType(AQH_MESSAGE *msg, int i); + +AQHOME_API int AQH_Message_GetMsgProtoId(const AQH_MESSAGE *msg); +AQHOME_API void AQH_Message_SetMsgProtoId(AQH_MESSAGE *msg, int i); + +AQHOME_API int AQH_Message_GetMsgProtoVer(const AQH_MESSAGE *msg); +AQHOME_API void AQH_Message_SetMsgProtoVer(AQH_MESSAGE *msg, int i); + +AQHOME_API int AQH_Message_GetMsgCommand(const AQH_MESSAGE *msg); +AQHOME_API void AQH_Message_SetMsgCommand(AQH_MESSAGE *msg, int i); + +/* helper functions for parsing */ +AQHOME_API void AQH_Message_WriteUint8At(AQH_MESSAGE *msg, uint32_t pos, uint8_t d); +AQHOME_API uint8_t AQH_Message_ReadUint8At(const AQH_MESSAGE *msg, uint32_t pos, uint8_t defaultValue); + +AQHOME_API void AQH_Message_WriteUint16At(AQH_MESSAGE *msg, uint32_t pos, uint16_t d); +AQHOME_API uint16_t AQH_Message_ReadUint16At(const AQH_MESSAGE *msg, uint32_t pos, uint16_t defaultValue); + +AQHOME_API void AQH_Message_WriteUint32At(AQH_MESSAGE *msg, uint32_t pos, uint32_t d); +AQHOME_API uint32_t AQH_Message_ReadUint32At(const AQH_MESSAGE *msg, uint32_t pos, uint32_t defaultValue); + +AQHOME_API void AQH_Message_WriteUint64At(AQH_MESSAGE *msg, uint32_t pos, uint64_t d); +AQHOME_API uint64_t AQH_Message_ReadUint64At(const AQH_MESSAGE *msg, uint32_t pos, uint64_t defaultValue); + +AQHOME_API void AQH_Message_WriteBytesAt(AQH_MESSAGE *msg, uint32_t pos, const uint8_t *bufferPtr, uint32_t bufferLen); +AQHOME_API int AQH_Message_WriteStringAt(AQH_MESSAGE *msg, uint32_t pos, uint32_t maxSize, int filler, const char *s); +AQHOME_API int AQH_Message_WriteStringWithTrailingNullAt(AQH_MESSAGE *msg, uint32_t pos, uint32_t maxSize, int filler, const char *s); + + +#endif + diff --git a/aqhome/ipc2/message_p.h b/aqhome/ipc2/message_p.h new file mode 100644 index 0000000..235af32 --- /dev/null +++ b/aqhome/ipc2/message_p.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_MESSAGE_P_H +#define AQH_MESSAGE_P_H + +#include "./message.h" + + + +struct AQH_MESSAGE { + GWEN_INHERIT_ELEMENT(AQH_MESSAGE) + GWEN_LIST_ELEMENT(AQH_MESSAGE) + + int refCount; + + /* unparsed data */ + uint8_t *msgPointer; + uint32_t msgSize; + uint32_t usedSize; + + /* parsed header data */ + int msgType; + int msgProtoId; + int msgProtoVer; + int msgCommand; +}; + + + +#endif + diff --git a/aqhome/ipc2/msgreader.c b/aqhome/ipc2/msgreader.c index 6ac8efc..8776c05 100644 --- a/aqhome/ipc2/msgreader.c +++ b/aqhome/ipc2/msgreader.c @@ -18,14 +18,12 @@ #include #include +#include -#define AQH_MSG_READER_MINMSGSIZE 12 -#define AQH_MSG_READER_MAXMSGSIZE 10240 +#define AQH_MSGREADER_SKIPTIME_IN_MS 20 -enum { - AQH_MSGREADER_SLOT_SOCKETREADY=1 -}; +#define AQH_MSGREADER_FLAGS_SKIP 0x0001 @@ -39,13 +37,15 @@ GWEN_INHERIT(AQH_OBJECT, AQH_MSG_READER) */ static void GWENHYWFAR_CB _freeData(void *bp, void *p); - static int _handleSignal(AQH_OBJECT *o, uint32_t slotId, AQH_OBJECT *senderObject, int param1, void *param2); -static int _handleSocketReady(AQH_OBJECT *o); -static int _fillRingbuffer(AQH_OBJECT *o); -static int _readMsgFromRingbuffer(AQH_OBJECT *o, AQH_MSG_READER *xo); -static int _readHeaderFromRingbuffer(AQH_MSG_READER *xo); -static int _readRemainderFromRingbuffer(AQH_MSG_READER *xo); +static int _handleSocketReady(AQH_OBJECT *o, AQH_OBJECT *fdObject); +static int _fillRingbuffer(AQH_OBJECT *o, AQH_MSG_READER *xo, AQH_OBJECT *fdObject); +static void _handleSkipping(AQH_OBJECT *o, AQH_OBJECT *fdObject); +static int _isStillSkipTime(AQH_MSG_READER *xo); +static uint64_t _getTimeInMilliSeconds(void); +static void _resetBuffers(AQH_MSG_READER *xo); +static void _cbEnable(AQH_OBJECT *o); +static void _cbDisable(AQH_OBJECT *o); @@ -54,7 +54,7 @@ static int _readRemainderFromRingbuffer(AQH_MSG_READER *xo); * ------------------------------------------------------------------------------------------------ */ -AQH_OBJECT *AQH_MsgReader_new(AQH_EVENT_LOOP *eventLoop, int fd) +AQH_OBJECT *AQH_MsgReader_new(AQH_EVENT_LOOP *eventLoop, AQH_OBJECT *fdObject) { AQH_OBJECT *o; AQH_MSG_READER *xo; @@ -62,15 +62,16 @@ AQH_OBJECT *AQH_MsgReader_new(AQH_EVENT_LOOP *eventLoop, int fd) o=AQH_Object_new(eventLoop); GWEN_NEW_OBJECT(AQH_MSG_READER, xo); GWEN_INHERIT_SETDATA(AQH_OBJECT, AQH_MSG_READER, o, xo, _freeData); - xo->fdSocket=fd; xo->ringBuffer=GWEN_RingBuffer_new(AQH_MSG_READER_RINGBUFFER_SIZE); AQH_Object_SetSignalHandlerFn(o, _handleSignal); + AQH_Object_SetEnableFn(o, _cbEnable); + AQH_Object_SetDisableFn(o, _cbDisable); - /* create object for readable socket, connect to THIS, enable */ - xo->fdObject=AQH_FdObject_new(AQH_Object_GetEventLoop(o), fd, AQH_FDOBJECT_FDMODE_READ); - AQH_Object_AddLink(xo->fdObject, AQH_FDOBJECT_SIGNAL_ISREADY, AQH_MSGREADER_SLOT_SOCKETREADY, o); - AQH_Object_Enable(xo->fdObject); + if (fdObject) { + xo->fdObject=fdObject; + AQH_Object_AddLink(xo->fdObject, AQH_FDOBJECT_SIGNAL_ISREADY, AQH_MSGREADER_SLOT_SOCKETREADY, o); + } return o; } @@ -82,23 +83,77 @@ void GWENHYWFAR_CB _freeData(GWEN_UNUSED void *bp, void *p) AQH_MSG_READER *xo; xo=(AQH_MSG_READER*) p; - if (xo->fdObject) { - AQH_Object_Disable(xo->fdObject); - AQH_Object_free(xo->fdObject); - } + free(xo->currentMsgBuf); GWEN_FREE_OBJECT(xo); } +uint32_t AQH_MsgReader_GetFlags(const AQH_OBJECT *o) +{ + AQH_MSG_READER *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_MSG_READER, o); + return xo?xo->flags:0; +} + + + +void AQH_MsgReader_SetFlags(AQH_OBJECT *o, uint32_t f) +{ + AQH_MSG_READER *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_MSG_READER, o); + if (xo) + xo->flags=f; +} + + + +void AQH_MsgReader_AddFlags(AQH_OBJECT *o, uint32_t f) +{ + AQH_MSG_READER *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_MSG_READER, o); + if (xo) + xo->flags|=f; +} + + + +void AQH_MsgReader_SubFlags(AQH_OBJECT *o, uint32_t f) +{ + AQH_MSG_READER *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_MSG_READER, o); + if (xo) + xo->flags&=~f; +} + + + +AQH_MSG_READER *AQH_MsgReader_GetData(const AQH_OBJECT *o) +{ + if (o) { + AQH_MSG_READER *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_MSG_READER, o); + return xo; + } + return NULL; +} + + + + int _handleSignal(AQH_OBJECT *o, uint32_t slotId, - GWEN_UNUSED AQH_OBJECT *senderObject, + AQH_OBJECT *senderObject, GWEN_UNUSED int param1, GWEN_UNUSED void *param2) { switch(slotId) { - case AQH_MSGREADER_SLOT_SOCKETREADY: return _handleSocketReady(o); + case AQH_MSGREADER_SLOT_SOCKETREADY: return _handleSocketReady(o, senderObject); default: break; } @@ -108,7 +163,36 @@ int _handleSignal(AQH_OBJECT *o, -int _handleSocketReady(AQH_OBJECT *o) +int AQH_MsgReader_ReadMsg(AQH_OBJECT *o) +{ + AQH_MSG_READER *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_MSG_READER, o); + if (xo) + return xo->readMsgFn(o); + return GWEN_ERROR_NOT_IMPLEMENTED; +} + + + +AQH_MSG_READER_READMSG_FN AQH_MsgReader_SetReadMsgFn(AQH_OBJECT *o, AQH_MSG_READER_READMSG_FN f) +{ + AQH_MSG_READER *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_MSG_READER, o); + if (xo) { + AQH_MSG_READER_READMSG_FN oldFn; + + oldFn=xo->readMsgFn; + xo->readMsgFn=f; + return oldFn; + } + return NULL; +} + + + +int _handleSocketReady(AQH_OBJECT *o, AQH_OBJECT *fdObject) { AQH_MSG_READER *xo; @@ -116,22 +200,28 @@ int _handleSocketReady(AQH_OBJECT *o) if (xo) { int rv; + if (xo->flags & AQH_MSGREADER_FLAGS_SKIP) { + if (_isStillSkipTime(xo)) { + _handleSkipping(o, fdObject); + return 1; + } + } + /* read available data into ringbuffer */ - rv=_fillRingbuffer(o); + rv=_fillRingbuffer(o, xo, fdObject); if (rv<0) { - DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); - AQH_Object_EmitSignal(o, AQH_MSG_READER_SIGNAL_ERROR, rv, NULL); - xo->fdSocket=-1; - return 1; + if (rv!=GWEN_ERROR_TRY_AGAIN) { + DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); + AQH_Object_EmitSignal(o, AQH_MSG_READER_SIGNAL_ERROR, rv, NULL); + } } /* read messages from ring buffer until buffer empty */ do { - rv=_readMsgFromRingbuffer(o, xo); + rv=AQH_MsgReader_ReadMsg(o); } while (rv==1); if (rv<0) { AQH_Object_EmitSignal(o, AQH_MSG_READER_SIGNAL_ERROR, rv, NULL); - xo->fdSocket=-1; } return 1; @@ -142,12 +232,66 @@ int _handleSocketReady(AQH_OBJECT *o) -int _fillRingbuffer(AQH_OBJECT *o) +void AQH_MsgReader_StartSkipping(AQH_OBJECT *o) { AQH_MSG_READER *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_MSG_READER, o); - if (xo && xo->fdSocket!=-1) { + if (xo) { + DBG_ERROR(AQH_LOGDOMAIN, "Enter skip mode"); + GWEN_RingBuffer_Reset(xo->ringBuffer); + _resetBuffers(xo); + xo->flags|=AQH_MSGREADER_FLAGS_SKIP; + xo->timestamp=_getTimeInMilliSeconds(); + } +} + + + +void _handleSkipping(AQH_OBJECT *o, AQH_OBJECT *fdObject) +{ + AQH_MSG_READER *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_MSG_READER, o); + if (xo) { + int rv; + + rv=AQH_FdObject_FlushInput(fdObject); + if (rv<0) { + AQH_Object_EmitSignal(o, AQH_MSG_READER_SIGNAL_ERROR, rv, NULL); + } + else if (rv>0) + xo->timestamp=_getTimeInMilliSeconds(); + } +} + + + +int _isStillSkipTime(AQH_MSG_READER *xo) +{ + uint64_t currentTime; + uint64_t diffTime; + + currentTime=_getTimeInMilliSeconds(); + diffTime=currentTime-xo->timestamp; + if (diffTime>=AQH_MSGREADER_SKIPTIME_IN_MS) { + xo->flags&=~AQH_MSGREADER_FLAGS_SKIP; + GWEN_RingBuffer_Reset(xo->ringBuffer); + _resetBuffers(xo); + DBG_ERROR(AQH_LOGDOMAIN, "Leaving skip mode"); + return 0; + } + else { + xo->timestamp=currentTime; + return 1; + } +} + + + +int _fillRingbuffer(AQH_OBJECT *o, AQH_MSG_READER *xo, AQH_OBJECT *fdObject) +{ + while (1) { uint32_t len; /* read data into ringbuffer */ @@ -155,160 +299,124 @@ int _fillRingbuffer(AQH_OBJECT *o) if (len>0) { int rv; - rv=AQH_FdObject_Read(xo->fdObject, (uint8_t*) GWEN_RingBuffer_GetWritePointer(xo->ringBuffer), len); + rv=AQH_FdObject_Read(fdObject, (uint8_t*) GWEN_RingBuffer_GetWritePointer(xo->ringBuffer), len); if (rv<0) { - DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); - xo->fdSocket=-1; + if (rv!=GWEN_ERROR_TRY_AGAIN) { + DBG_ERROR(AQH_LOGDOMAIN, "here (%d)", rv); + } return rv; } else if (rv==0) { DBG_INFO(AQH_LOGDOMAIN, "EOF met"); - xo->fdSocket=-1; + AQH_Object_EmitSignal(o, AQH_MSG_READER_SIGNAL_CLOSED, 0, NULL); return 0; } else { /* bytes received */ GWEN_RingBuffer_SkipBytesWrite(xo->ringBuffer, rv); - return rv; + //return rv; } } else { DBG_INFO(AQH_LOGDOMAIN, "Ringbuffer full"); - return GWEN_ERROR_BUFFER_OVERFLOW; + /*return GWEN_ERROR_BUFFER_OVERFLOW;*/ + return 0; } } +} + + + +int AQH_MsgReader_ReadRemainderFromRingbuffer(AQH_OBJECT *o) +{ + AQH_MSG_READER *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_MSG_READER, o); + if (xo) { + uint32_t bytesInRingBuffer; + uint32_t bytesToRead; + int rv; + + bytesInRingBuffer=GWEN_RingBuffer_GetUsedBytes(xo->ringBuffer); + + /* still reading header */ + bytesToRead=xo->bytesLeft; + if (bytesInRingBufferringBuffer, (char*) (xo->currentMsgBuf+xo->bytesReceived), &xferSize); + if (rv<0) { + DBG_INFO(AQH_LOGDOMAIN, "Ringbuffer empty"); + return 0; + } + if (xferSizebytesReceived+=xferSize; + xo->bytesLeft-=xferSize; + if (xo->bytesLeft==0) { + /* msg finished */ + DBG_INFO(AQH_LOGDOMAIN, "Message complete"); + return 1; + } + } + return 0; + } else { - DBG_INFO(AQH_LOGDOMAIN, "fd inactive (previous error or EOF?)"); + DBG_ERROR(AQH_LOGDOMAIN, "Not a MSGREADER object"); return GWEN_ERROR_INVALID; } } -int _readMsgFromRingbuffer(AQH_OBJECT *o, AQH_MSG_READER *xo) +uint64_t _getTimeInMilliSeconds(void) { - int rv; + struct timespec t ; - if (xo->bytesReceivedbytesReceived>=AQH_MSG_READER_HEADERBUFFER_SIZE) { - /* reading remainder of msg directly into allocated buffer */ - rv=_readRemainderFromRingbuffer(xo); - if (rv<0) { - DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); - return rv; - } - else if (rv==1) { - int msgLen; - uint8_t *msgPtr; - - msgLen=xo->bytesReceived; - msgPtr=xo->currentMsgBuf; - - xo->bytesReceived=0; - xo->bytesLeft=0; - xo->currentMsgBuf=NULL; - - rv=AQH_Object_EmitSignal(o, AQH_MSG_READER_SIGNAL_MSGRECVD, msgLen, (void*) msgPtr); - if (rv==0) { - DBG_INFO(AQH_LOGDOMAIN, "Received message ignored"); - free(msgPtr); - } - return 1; - } - } - return 0; + clock_gettime(CLOCK_REALTIME, &t); + return t.tv_sec*1000+(t.tv_nsec+500000)/1000000 ; } -int _readHeaderFromRingbuffer(AQH_MSG_READER *xo) +void _resetBuffers(AQH_MSG_READER *xo) { - uint32_t remaining; - int rv; - uint32_t xferSize; - uint32_t bytesInBuffer; - - bytesInBuffer=GWEN_RingBuffer_GetUsedBytes(xo->ringBuffer); - - /* still reading header */ - remaining=AQH_MSG_READER_HEADERBUFFER_SIZE-xo->bytesReceived; - if (bytesInBufferringBuffer, (char*) (xo->headerBuffer+xo->bytesReceived), &xferSize); - if (rv<0) { - DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); - return rv; - } - if (xferSizebytesReceived+=xferSize; - if (xo->bytesReceived==AQH_MSG_READER_HEADERBUFFER_SIZE) { - uint32_t msgLen; - - /* full size received, parse msg size, allocate buffer */ - msgLen=GWEN_ENDIAN_LE32TOH(*((const uint32_t*)(xo->headerBuffer))); - if (msgLenAQH_MSG_READER_MAXMSGSIZE) { - DBG_ERROR(AQH_LOGDOMAIN, "Bad message size(%lu)", (unsigned long int) msgLen); - return GWEN_ERROR_GENERIC; - } - xo->currentMsgBuf=(uint8_t*) malloc(msgLen+4); - memmove(xo->currentMsgBuf, xo->headerBuffer, xo->bytesReceived); - xo->bytesLeft=(msgLen+4)-xo->bytesReceived; - } - - return 0; + free(xo->currentMsgBuf); + xo->currentMsgBuf=NULL; + xo->bytesReceived=0; + xo->bytesLeft=0; } -int _readRemainderFromRingbuffer(AQH_MSG_READER *xo) +void _cbEnable(AQH_OBJECT *o) { - uint32_t bytesInBuffer; - uint32_t bytesToRead; - int rv; + if (o && !(AQH_Object_GetFlags(o) & AQH_OBJECT_FLAGS_ENABLED)) { + AQH_MSG_READER *xo; - bytesInBuffer=GWEN_RingBuffer_GetUsedBytes(xo->ringBuffer); - - /* still reading header */ - bytesToRead=xo->bytesLeft; - if (bytesInBufferringBuffer, (char*) (xo->currentMsgBuf+xo->bytesReceived), &xferSize); - if (rv<0) { - DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); - return rv; - } - if (xferSizebytesReceived+=xferSize; - xo->bytesLeft-=xferSize; - if (xo->bytesLeft==0) { - /* msg finished */ - DBG_INFO(AQH_LOGDOMAIN, "Message complete"); - return 1; - } + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_MSG_READER, o); + if (xo && xo->fdObject) + AQH_Object_Enable(xo->fdObject); } - return 0; } +void _cbDisable(AQH_OBJECT *o) +{ + if (o && (AQH_Object_GetFlags(o) & AQH_OBJECT_FLAGS_ENABLED)) { + AQH_MSG_READER *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_MSG_READER, o); + if (xo && xo->fdObject) + AQH_Object_Disable(xo->fdObject); + } +} diff --git a/aqhome/ipc2/msgreader.h b/aqhome/ipc2/msgreader.h index 199c390..b6f39b4 100644 --- a/aqhome/ipc2/msgreader.h +++ b/aqhome/ipc2/msgreader.h @@ -12,7 +12,6 @@ #include - enum { /** param1=msgSize, param2=msgPointer */ AQH_MSG_READER_SIGNAL_MSGRECVD=AQH_OBJECT_SIGNAL_LAST, @@ -23,8 +22,10 @@ enum { +enum { + AQH_MSGREADER_SLOT_SOCKETREADY=1 +}; -AQH_OBJECT *AQH_MsgReader_new(AQH_EVENT_LOOP *eventLoop, int fd); diff --git a/aqhome/ipc2/msgreader_p.h b/aqhome/ipc2/msgreader_p.h index b62c44c..6f4b0bf 100644 --- a/aqhome/ipc2/msgreader_p.h +++ b/aqhome/ipc2/msgreader_p.h @@ -15,22 +15,54 @@ #include #define AQH_MSG_READER_RINGBUFFER_SIZE 1024 -#define AQH_MSG_READER_HEADERBUFFER_SIZE 4 +#define AQH_MSG_READER_HEADERBUFFER_SIZE 32 typedef struct AQH_MSG_READER AQH_MSG_READER; + +/** + * Read data for a message from the internal ring buffer. + * + * @return 1 if something has been done, 0 if not, negative on error + * @param o object (THIS) + */ +typedef int (*AQH_MSG_READER_READMSG_FN)(AQH_OBJECT *o); + + + struct AQH_MSG_READER { - int fdSocket; - AQH_OBJECT *fdObject; GWEN_RINGBUFFER *ringBuffer; int bytesReceived; int bytesLeft; uint8_t headerBuffer[AQH_MSG_READER_HEADERBUFFER_SIZE]; uint8_t *currentMsgBuf; + + uint32_t flags; + uint64_t timestamp; + + AQH_OBJECT *fdObject; + + AQH_MSG_READER_READMSG_FN readMsgFn; }; +AQH_OBJECT *AQH_MsgReader_new(AQH_EVENT_LOOP *eventLoop, AQH_OBJECT *fdObject); + +AQH_MSG_READER *AQH_MsgReader_GetData(const AQH_OBJECT *o); +int AQH_MsgReader_ReadRemainderFromRingbuffer(AQH_OBJECT *o); + +int AQH_MsgReader_ReadMsg(AQH_OBJECT *o); +AQH_MSG_READER_READMSG_FN AQH_MsgReader_SetReadMsgFn(AQH_OBJECT *o, AQH_MSG_READER_READMSG_FN f); + + +uint32_t AQH_MsgReader_GetFlags(const AQH_OBJECT *o); +void AQH_MsgReader_SetFlags(AQH_OBJECT *o, uint32_t f); +void AQH_MsgReader_AddFlags(AQH_OBJECT *o, uint32_t f); +void AQH_MsgReader_SubFlags(AQH_OBJECT *o, uint32_t f); + +void AQH_MsgReader_StartSkipping(AQH_OBJECT *o); + diff --git a/aqhome/ipc2/msgwriter.c b/aqhome/ipc2/msgwriter.c new file mode 100644 index 0000000..55bc4f4 --- /dev/null +++ b/aqhome/ipc2/msgwriter.c @@ -0,0 +1,240 @@ +/**************************************************************************** + * 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 "./msgwriter_p.h" +#include + +#include +#include +#include + +#include + + +#define AQH_MSGWRITER_FLAGS_MSGSTARTED 0x0001 + + + +GWEN_INHERIT(AQH_OBJECT, AQH_MSG_WRITER) + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void GWENHYWFAR_CB _freeData(void *bp, void *p); +static int _handleSignal(AQH_OBJECT *o, uint32_t slotId, AQH_OBJECT *senderObject, int param1, void *param2); +static int _handleSocketReady(AQH_OBJECT *o, AQH_OBJECT *fdObject); +static int _startMsg(AQH_MSG_WRITER *xo, AQH_OBJECT *fdObject); +static void _endMsg(AQH_MSG_WRITER *xo, AQH_OBJECT *fdObject); +static void _resetBuffer(AQH_OBJECT *o); +static void _cbEnable(AQH_OBJECT *o); +static void _cbDisable(AQH_OBJECT *o); + + + +/* ------------------------------------------------------------------------------------------------ + * implementation + * ------------------------------------------------------------------------------------------------ + */ + +AQH_OBJECT *AQH_MsgWriter_new(AQH_EVENT_LOOP *eventLoop, AQH_OBJECT *fdObject) +{ + AQH_OBJECT *o; + AQH_MSG_WRITER *xo; + + o=AQH_Object_new(eventLoop); + GWEN_NEW_OBJECT(AQH_MSG_WRITER, xo); + GWEN_INHERIT_SETDATA(AQH_OBJECT, AQH_MSG_WRITER, o, xo, _freeData); + + AQH_Object_SetSignalHandlerFn(o, _handleSignal); + AQH_Object_SetEnableFn(o, _cbEnable); + AQH_Object_SetDisableFn(o, _cbDisable); + + if (fdObject) { + xo->fdObject=fdObject; + AQH_Object_AddLink(xo->fdObject, AQH_FDOBJECT_SIGNAL_ISREADY, AQH_MSGWRITER_SLOT_SOCKETREADY, o); + } + + return o; +} + + + +void GWENHYWFAR_CB _freeData(GWEN_UNUSED void *bp, void *p) +{ + AQH_MSG_WRITER *xo; + + xo=(AQH_MSG_WRITER*) p; + GWEN_FREE_OBJECT(xo); +} + + + +void AQH_MsgWriter_SendMsg(AQH_OBJECT *o, const uint8_t *ptr, int len) +{ + if (o) { + AQH_MSG_WRITER *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_MSG_WRITER, o); + if (xo) { + _resetBuffer(o); + if (ptr && len) { + xo->msgBufPtr=ptr; + xo->msgBufLen=len; + } + xo->bytesLeft=xo->msgBufLen; + xo->currentPtr=xo->msgBufPtr; + xo->flags&=~AQH_MSGWRITER_FLAGS_MSGSTARTED; + } + } +} + + + +int _handleSignal(AQH_OBJECT *o, + uint32_t slotId, + GWEN_UNUSED AQH_OBJECT *senderObject, + GWEN_UNUSED int param1, + GWEN_UNUSED void *param2) +{ + switch(slotId) { + case AQH_MSGWRITER_SLOT_SOCKETREADY: return _handleSocketReady(o, senderObject); + default: + break; + } + + return 0; /* not handled */ +} + + + +int _handleSocketReady(AQH_OBJECT *o, AQH_OBJECT *fdObject) +{ + AQH_MSG_WRITER *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_MSG_WRITER, o); + if (xo) { + if (xo->bytesLeft) { + int rv; + + if (!(xo->flags & AQH_MSGWRITER_FLAGS_MSGSTARTED)) { + rv=_startMsg(xo, fdObject); + if (rv<0) { + if (rv==GWEN_ERROR_TRY_AGAIN) { + /* line is busy */ + } + else { + _endMsg(xo, fdObject); + AQH_Object_EmitSignal(o, AQH_MSG_WRITER_SIGNAL_ERROR, rv, NULL); + } + return 1; + } + } + + do { + rv=AQH_FdObject_Write(fdObject, xo->currentPtr, xo->bytesLeft); + if (rv>0) { + xo->currentPtr+=rv; + xo->bytesLeft-=rv; + } + } while (rv>0 && xo->bytesLeft>0); + if (rv<0 && rv!=GWEN_ERROR_TRY_AGAIN) { + _endMsg(xo, fdObject); + AQH_Object_EmitSignal(o, AQH_MSG_WRITER_SIGNAL_ERROR, rv, NULL); + } + else { + if (xo->bytesLeft==0) { + _endMsg(xo, fdObject); + rv=AQH_Object_EmitSignal(o, AQH_MSG_WRITER_SIGNAL_MSGSENT, xo->msgBufLen, (void*) (xo->msgBufPtr)); + if (rv==0) { + DBG_INFO(AQH_LOGDOMAIN, "Sent message ignored"); + } + _resetBuffer(o); + } + } + } + return 1; + } + return 0; +} + + + +int _startMsg(AQH_MSG_WRITER *xo, AQH_OBJECT *fdObject) +{ + int rv; + + rv=AQH_FdObject_StartMsg(fdObject); + if (rv<0) { + /* line is busy */ + return rv; + } + xo->flags|=AQH_MSGWRITER_FLAGS_MSGSTARTED; + return 0; +} + + + +void _endMsg(AQH_MSG_WRITER *xo, AQH_OBJECT *fdObject) +{ + xo->flags&=~AQH_MSGWRITER_FLAGS_MSGSTARTED; + AQH_FdObject_EndMsg(fdObject); +} + + + +void _resetBuffer(AQH_OBJECT *o) +{ + AQH_MSG_WRITER *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_MSG_WRITER, o); + if (xo) { + xo->msgBufPtr=NULL; + xo->msgBufLen=0; + xo->currentPtr=NULL; + xo->bytesLeft=0; + } +} + + + +void _cbEnable(AQH_OBJECT *o) +{ + if (o && !(AQH_Object_GetFlags(o) & AQH_OBJECT_FLAGS_ENABLED)) { + AQH_MSG_WRITER *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_MSG_WRITER, o); + if (xo && xo->fdObject) + AQH_Object_Enable(xo->fdObject); + } +} + + + +void _cbDisable(AQH_OBJECT *o) +{ + if (o && (AQH_Object_GetFlags(o) & AQH_OBJECT_FLAGS_ENABLED)) { + AQH_MSG_WRITER *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_MSG_WRITER, o); + if (xo && xo->fdObject) + AQH_Object_Disable(xo->fdObject); + } +} + + + + + diff --git a/aqhome/ipc2/msgwriter.h b/aqhome/ipc2/msgwriter.h new file mode 100644 index 0000000..1909197 --- /dev/null +++ b/aqhome/ipc2/msgwriter.h @@ -0,0 +1,38 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_MSGWRITER_H +#define AQH_MSGWRITER_H + +#include + + +enum { + /** param1=msgSize, param2=msgPointer */ + AQH_MSG_WRITER_SIGNAL_MSGSENT=AQH_OBJECT_SIGNAL_LAST, + /** param1: error code */ + AQH_MSG_WRITER_SIGNAL_ERROR, + AQH_MSG_WRITER_SIGNAL_CLOSED +}; + + +enum { + AQH_MSGWRITER_SLOT_SOCKETREADY=1 +}; + + + + +AQH_OBJECT *AQH_MsgWriter_new(AQH_EVENT_LOOP *eventLoop, AQH_OBJECT *fdObject); + + +void AQH_MsgWriter_SendMsg(AQH_OBJECT *o, const uint8_t *ptr, int len); + + +#endif + diff --git a/aqhome/ipc2/msgwriter_p.h b/aqhome/ipc2/msgwriter_p.h new file mode 100644 index 0000000..2a1c9f9 --- /dev/null +++ b/aqhome/ipc2/msgwriter_p.h @@ -0,0 +1,34 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_MSGWRITER_P_H +#define AQH_MSGWRITER_P_H + + +#include "./msgwriter.h" + + + +typedef struct AQH_MSG_WRITER AQH_MSG_WRITER; +struct AQH_MSG_WRITER { + int msgBufLen; + const uint8_t *msgBufPtr; + + int bytesLeft; + const uint8_t *currentPtr; + + uint32_t flags; + + AQH_OBJECT *fdObject; +}; + + + + +#endif + diff --git a/aqhome/ipc2/nodeendpoint.c b/aqhome/ipc2/nodeendpoint.c new file mode 100644 index 0000000..9adc10a --- /dev/null +++ b/aqhome/ipc2/nodeendpoint.c @@ -0,0 +1,236 @@ +/**************************************************************************** + * 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 "./nodeendpoint_p.h" +#include "aqhome/ipc2/msgreader.h" +#include "aqhome/ipc2/msgwriter.h" +#include "aqhome/msg/node/m_node.h" + +#include "aqhome/msg/node/m_device.h" +#include "aqhome/msg/node/m_recvstats.h" +#include "aqhome/msg/node/m_sendstats.h" + + +#include +#include + + + +GWEN_INHERIT(AQH_OBJECT, AQH_NODE_ENDPOINT) + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void GWENHYWFAR_CB _freeData(void *bp, void *p); +static int _handleSignal(AQH_OBJECT *o, uint32_t slotId, AQH_OBJECT *senderObject, int param1, void *param2); +static int _handleMsgRecvd(AQH_OBJECT *o, AQH_OBJECT *senderObject, int msgLen, const uint8_t *msgPtr); +static int _handleMsgSent(AQH_OBJECT *o, AQH_OBJECT *senderObject, int msgLen, const uint8_t *msgPtr); +static void _dumpMsg(const AQH_MESSAGE *msg, const char *sText); + + + +/* ------------------------------------------------------------------------------------------------ + * implementation + * ------------------------------------------------------------------------------------------------ + */ + +AQH_OBJECT *AQH_NodeEndpoint_new(AQH_EVENT_LOOP *eventLoop, AQH_OBJECT *msgReader, AQH_OBJECT *msgWriter) +{ + AQH_OBJECT *o; + AQH_NODE_ENDPOINT *xo; + + o=AQH_Object_new(eventLoop); + GWEN_NEW_OBJECT(AQH_NODE_ENDPOINT, xo); + GWEN_INHERIT_SETDATA(AQH_OBJECT, AQH_NODE_ENDPOINT, o, xo, _freeData); + + xo->msgOutList=AQH_Message_List_new(); + xo->msgInList=AQH_Message_List_new(); + + AQH_Object_SetSignalHandlerFn(o, _handleSignal); + + if (msgReader) { + xo->msgReader=msgReader; + AQH_Object_AddLink(msgReader, AQH_MSG_READER_SIGNAL_MSGRECVD, AQH_NODE_ENDPOINT_SLOT_MSG_RECVD, o); + } + + if (msgWriter) { + xo->msgWriter=msgWriter; + AQH_Object_AddLink(msgWriter, AQH_MSG_WRITER_SIGNAL_MSGSENT, AQH_NODE_ENDPOINT_SLOT_MSG_SENT, o); + } + + return o; +} + + + +void GWENHYWFAR_CB _freeData(GWEN_UNUSED void *bp, void *p) +{ + AQH_NODE_ENDPOINT *xo; + + xo=(AQH_NODE_ENDPOINT*) p; + AQH_Message_List_free(xo->msgOutList); + AQH_Message_List_free(xo->msgInList); + AQH_Object_free(xo->msgWriter); + AQH_Object_free(xo->msgReader); + GWEN_FREE_OBJECT(xo); +} + + + +AQH_MESSAGE_LIST *AQH_NodeEndpoint_GetMsgOutList(const AQH_OBJECT *o) +{ + if (o) { + AQH_NODE_ENDPOINT *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_NODE_ENDPOINT, o); + if (xo) + return xo->msgOutList; + } + return NULL; +} + + + +AQH_MESSAGE *AQH_NodeEndpoint_GetNextMsgOut(AQH_OBJECT *o) +{ + if (o) { + AQH_NODE_ENDPOINT *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_NODE_ENDPOINT, o); + if (xo) + return AQH_Message_List_First(xo->msgOutList); + } + return NULL; +} + + + +void AQH_NodeEndpoint_AddMsgOut(AQH_OBJECT *o, AQH_MESSAGE *msg) +{ + if (o && msg) { + AQH_NODE_ENDPOINT *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_NODE_ENDPOINT, o); + if (xo) { + AQH_Message_List_Add(msg, xo->msgOutList); + if (xo->msgWriter && AQH_Message_List_GetCount(xo->msgOutList)==1) { + AQH_MsgWriter_SendMsg(xo->msgWriter, AQH_Message_GetMsgPointer(msg), AQH_Message_GetUsedSize(msg)); + AQH_Object_Enable(xo->msgWriter); + } + } + } +} + + + +AQH_MESSAGE_LIST *AQH_NodeEndpoint_GetMsgInList(const AQH_OBJECT *o) +{ + if (o) { + AQH_NODE_ENDPOINT *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_NODE_ENDPOINT, o); + if (xo) + return xo->msgInList; + } + return NULL; +} + + + +AQH_MESSAGE *AQH_NodeEndpoint_GetNextMsgIn(AQH_OBJECT *o) +{ + if (o) { + AQH_NODE_ENDPOINT *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_NODE_ENDPOINT, o); + if (xo) + return AQH_Message_List_First(xo->msgInList); + } + return NULL; +} + + + +void AQH_NodeEndpoint_AddMsgIn(AQH_OBJECT *o, AQH_MESSAGE *msg) +{ + if (o && msg) { + AQH_NODE_ENDPOINT *xo; + + xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_NODE_ENDPOINT, o); + if (xo) { + AQH_Message_List_Add(msg, xo->msgInList); + DBG_ERROR(AQH_LOGDOMAIN, "now %d msgs in list", AQH_Message_List_GetCount(xo->msgInList)); + } + } +} + + + +int _handleSignal(AQH_OBJECT *o, uint32_t slotId, AQH_OBJECT *senderObject, int param1, void *param2) +{ + switch(slotId) { + case AQH_NODE_ENDPOINT_SLOT_MSG_RECVD: return _handleMsgRecvd(o, senderObject, param1, param2); + case AQH_NODE_ENDPOINT_SLOT_MSG_SENT: return _handleMsgSent(o, senderObject, param1, param2); + default: + break; + } + + return 0; /* not handled */ +} + + + +int _handleMsgRecvd(AQH_OBJECT *o, AQH_OBJECT *senderObject, int msgLen, const uint8_t *msgPtr) +{ + AQH_MESSAGE *msg; + + DBG_ERROR(AQH_LOGDOMAIN, "Msg received:"); + msg=AQH_NodeMessage_fromBuffer(msgPtr, msgLen); + _dumpMsg(msg, "Received"); + AQH_NodeEndpoint_AddMsgIn(o, msg); + + return 1; +} + + + +int _handleMsgSent(AQH_OBJECT *o, AQH_OBJECT *senderObject, int msgLen, const uint8_t *msgPtr) +{ + DBG_ERROR(AQH_LOGDOMAIN, "Msg sent:"); + GWEN_Text_LogString((const char*) msgPtr, msgLen, AQH_LOGDOMAIN, GWEN_LoggerLevel_Error); + return 1; +} + + + +void _dumpMsg(const AQH_MESSAGE *msg, const char *sText) +{ + if (msg) { + GWEN_BUFFER *mbuf; + + mbuf=GWEN_Buffer_new(0, 256, 0, 1); + switch(AQH_NodeMessage_GetMsgType(msg)) { + case AQH_MSG_TYPE_DEVICE: AQH_DeviceMessage_DumpToBuffer(msg, mbuf, sText); break; + case AQH_MSG_TYPE_COMRECVSTATS: AQH_RecvStatsMessage_DumpToBuffer(msg, mbuf, sText); break; + case AQH_MSG_TYPE_COMSENDSTATS: AQH_SendStatsMessage_DumpToBuffer(msg, mbuf, sText); break; + default: AQH_NodeMessage_DumpToBuffer(msg, mbuf, sText); break; + } + DBG_ERROR(AQH_LOGDOMAIN, "%s", GWEN_Buffer_GetStart(mbuf)); + GWEN_Buffer_free(mbuf); + } +} + + diff --git a/aqhome/ipc2/nodeendpoint.h b/aqhome/ipc2/nodeendpoint.h new file mode 100644 index 0000000..6541a9f --- /dev/null +++ b/aqhome/ipc2/nodeendpoint.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_NODEENDPOINT_H +#define AQH_NODEENDPOINT_H + +#include +#include + + + +enum { + AQH_NODE_ENDPOINT_SLOT_MSG_RECVD=1, + AQH_NODE_ENDPOINT_SLOT_MSG_SENT +}; + + +AQHOME_API AQH_OBJECT *AQH_NodeEndpoint_new(AQH_EVENT_LOOP *eventLoop, AQH_OBJECT *msgReader, AQH_OBJECT *msgWriter); + +AQHOME_API AQH_MESSAGE_LIST *AQH_NodeEndpoint_GetMsgOutList(const AQH_OBJECT *o); +AQHOME_API AQH_MESSAGE *AQH_NodeEndpoint_GetNextMsgOut(AQH_OBJECT *o); +AQHOME_API void AQH_NodeEndpoint_AddMsgOut(AQH_OBJECT *o, AQH_MESSAGE *msg); + +AQHOME_API AQH_MESSAGE_LIST *AQH_NodeEndpoint_GetMsgInList(const AQH_OBJECT *o); +AQHOME_API AQH_MESSAGE *AQH_NodeEndpoint_GetNextMsgIn(AQH_OBJECT *o); +AQHOME_API void AQH_NodeEndpoint_AddMsgIn(AQH_OBJECT *o, AQH_MESSAGE *msg); + + + + +#endif + diff --git a/aqhome/ipc2/nodeendpoint_p.h b/aqhome/ipc2/nodeendpoint_p.h new file mode 100644 index 0000000..6f60d5d --- /dev/null +++ b/aqhome/ipc2/nodeendpoint_p.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_NODEENDPOINT_P_H +#define AQH_NODEENDPOINT_P_H + + +#include "./nodeendpoint.h" + +typedef struct AQH_NODE_ENDPOINT AQH_NODE_ENDPOINT; + +struct AQH_NODE_ENDPOINT { + AQH_MESSAGE_LIST *msgOutList; + AQH_MESSAGE_LIST *msgInList; + AQH_OBJECT *msgWriter; + AQH_OBJECT *msgReader; +}; + + + +#endif + diff --git a/aqhome/ipc2/nodemsgreader.c b/aqhome/ipc2/nodemsgreader.c new file mode 100644 index 0000000..f83957a --- /dev/null +++ b/aqhome/ipc2/nodemsgreader.c @@ -0,0 +1,185 @@ +/**************************************************************************** + * 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 "./nodemsgreader.h" +#include "./msgreader_p.h" +#include + +#include +#include +#include + +#include + + + +/* ------------------------------------------------------------------------------------------------ + * definitions + * ------------------------------------------------------------------------------------------------ + */ + +#define AQH_MSG_READER_HEADER_SIZE 2 +#define AQH_MSG_READER_MAXMSGSIZE 32 + +#define AQH_MSG_READER_FLAG_SKIPPING 0x0001 + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static int _readMsg(AQH_OBJECT *o); +static int _readHeaderFromRingbuffer(AQH_OBJECT *o, AQH_MSG_READER *xo); +static uint8_t _calcCrc8Checksum(const uint8_t *ptr, uint8_t len); + + + +/* ------------------------------------------------------------------------------------------------ + * implementation + * ------------------------------------------------------------------------------------------------ + */ + +AQH_OBJECT *AQH_NodeMsgReader_new(AQH_EVENT_LOOP *eventLoop, AQH_OBJECT *fdObject) +{ + AQH_OBJECT *o; + + o=AQH_MsgReader_new(eventLoop, fdObject); + AQH_MsgReader_SetReadMsgFn(o, _readMsg); + + return o; +} + + + +int _readMsg(AQH_OBJECT *o) +{ + AQH_MSG_READER *xo; + + xo=AQH_MsgReader_GetData(o); + if (xo) { + int rv; + + if (xo->bytesReceivedbytesReceived>=AQH_MSG_READER_HEADER_SIZE) { + /* reading remainder of msg directly into allocated buffer */ + rv=AQH_MsgReader_ReadRemainderFromRingbuffer(o); + if (rv<0) { + DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); + return rv; + } + else if (rv==1) { + int msgLen; + uint8_t *msgPtr; + + msgLen=xo->bytesReceived; + msgPtr=xo->currentMsgBuf; + + xo->bytesReceived=0; + xo->bytesLeft=0; + xo->currentMsgBuf=NULL; + + if (_calcCrc8Checksum(msgPtr, msgLen)==0) { + rv=AQH_Object_EmitSignal(o, AQH_MSG_READER_SIGNAL_MSGRECVD, msgLen, (void*) msgPtr); + if (rv==0) { + DBG_INFO(AQH_LOGDOMAIN, "Received message ignored"); + } + } + else { + DBG_INFO(AQH_LOGDOMAIN, "Bad CRC"); + AQH_MsgReader_StartSkipping(o); + } + free(msgPtr); + return 1; + } + } + return 0; + } + return GWEN_ERROR_GENERIC; +} + + + +int _readHeaderFromRingbuffer(AQH_OBJECT *o, AQH_MSG_READER *xo) +{ + uint32_t remaining; + int rv; + uint32_t xferSize; + uint32_t bytesInBuffer; + + bytesInBuffer=GWEN_RingBuffer_GetUsedBytes(xo->ringBuffer); + + /* still reading header */ + remaining=AQH_MSG_READER_HEADER_SIZE-xo->bytesReceived; + if (bytesInBufferringBuffer, (char*) (xo->headerBuffer+xo->bytesReceived), &xferSize); + if (rv<0) { + DBG_INFO(AQH_LOGDOMAIN, "Ringbuffer empty"); + return 0; + } + if (xferSizebytesReceived+=xferSize; + if (xo->bytesReceived==AQH_MSG_READER_HEADER_SIZE) { + uint32_t msgLen; + + /* full size received, parse msg size, allocate buffer */ + msgLen=xo->headerBuffer[1]; + if (msgLen>AQH_MSG_READER_MAXMSGSIZE) { + DBG_ERROR(AQH_LOGDOMAIN, "Bad message size(%lu)", (unsigned long int) msgLen); + AQH_MsgReader_StartSkipping(o); + return GWEN_ERROR_GENERIC; + } + xo->currentMsgBuf=(uint8_t*) malloc(msgLen+3); /* +3 (dest addr, msg len, crc) */ + memmove(xo->currentMsgBuf, xo->headerBuffer, xo->bytesReceived); + xo->bytesLeft=(msgLen+3)-xo->bytesReceived; + } + + return 0; +} + + + +uint8_t _calcCrc8Checksum(const uint8_t *ptr, uint8_t len) +{ + int i; + uint8_t x=0xff; + + for (i=0; i + + +AQHOME_API AQH_OBJECT *AQH_NodeMsgReader_new(AQH_EVENT_LOOP *eventLoop, AQH_OBJECT *fdObject); + + + +#endif + diff --git a/aqhome/ipc2/ttyobject.c b/aqhome/ipc2/ttyobject.c new file mode 100644 index 0000000..066620b --- /dev/null +++ b/aqhome/ipc2/ttyobject.c @@ -0,0 +1,230 @@ +/**************************************************************************** + * 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 "./ttyobject.h" +#include + +#include + +#include +#include +#include +#include + + +#define AQH_TTYOBJECT_BAUDRATE B19200 + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static int _startMsg(AQH_OBJECT *o); +static void _endMsg(AQH_OBJECT *o); +static int _getAttn(int fd); +static int _setAttn(int fd, int val); +static int _fdSetBlocking(int sk, int fl); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +AQH_OBJECT *AQH_TtyObject_new(AQH_EVENT_LOOP *eventLoop, int fd, int fdMode) +{ + AQH_OBJECT *o; + + o=AQH_FdObject_new(eventLoop, fd, fdMode); + AQH_FdObject_SetStartMsgFn(o, _startMsg); + AQH_FdObject_SetEndMsgFn(o, _endMsg); + return o; +} + + + +int _startMsg(AQH_OBJECT *o) +{ + if (o) { + int fd; + int rv; + + fd=AQH_FdObject_GetFd(o); + if (fd==-1) + return GWEN_ERROR_IO; + rv=_getAttn(fd); + if (rv<0) { + DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); + return rv; + } + else if (rv==0) { + return GWEN_ERROR_TRY_AGAIN; /* line busy */ + } + else { + _setAttn(fd, 0); /* set ATTN low */ + return 0; + } + } + else + return GWEN_ERROR_INVALID; +} + + + +void _endMsg(AQH_OBJECT *o) +{ + if (o) { + int fd; + + fd=AQH_FdObject_GetFd(o); + if (fd>=0) + _setAttn(fd, 1); /* set ATTN high */ + } +} + + + +int _getAttn(int fd) +{ + int rv; + int status; + + rv=ioctl(fd, TIOCMGET, &status); + if (rv<0) { + DBG_ERROR(AQH_LOGDOMAIN, "Error on ioctl: %s (%d)", strerror(errno), errno); + return GWEN_ERROR_IO; + } + return (status & TIOCM_CTS)?0:1; +} + + + +int _setAttn(int fd, int val) +{ + int rv; + int status; + + rv=ioctl(fd, TIOCMGET, &status); + if (rv<0) { + DBG_ERROR(AQH_LOGDOMAIN, "Error on ioctl: %s (%d)", strerror(errno), errno); + return GWEN_ERROR_IO; + } + + if (val) + status &= ~ (TIOCM_DTR | TIOCM_RTS); /* attn high, clear the DTR pin (cave: signals inverted!) */ + else + status |= TIOCM_DTR | TIOCM_RTS; /* attn low, set the DTR pin (cave: signals inverted!) */ + + rv=ioctl(fd, TIOCMSET, &status); + if (rv<0) { + DBG_ERROR(AQH_LOGDOMAIN, "Error on ioctl: %s (%d)", strerror(errno), errno); + return GWEN_ERROR_IO; + } + return 0; +} + + + +int AQH_TtyObject_OpenAndInitDevice(const char *device, struct termios *initialTermiosState) +{ + int fd; + struct termios options; + int rv; + + fd=open(device, O_NOCTTY | O_NDELAY | O_RDWR); + if (fd<0) { + DBG_ERROR(AQH_LOGDOMAIN, "Error on open(%s): %s (%d)", device, strerror(errno), errno); + return GWEN_ERROR_IO; + } + DBG_INFO(AQH_LOGDOMAIN, "Device %s open (socket %d)", device, fd); + + _fdSetBlocking(fd, 0); + + rv=tcgetattr(fd, &options); + if (initialTermiosState) + *initialTermiosState=options; + + options.c_cflag=CLOCAL | CREAD | CS8; + options.c_iflag=IGNPAR | IGNBRK; + options.c_oflag=0; + options.c_lflag&= ~(ICANON | ECHO | ECHOE | ISIG); + options.c_cc[VTIME]=0; /* read timeout in deciseconds */ + options.c_cc[VMIN]=0; /* no minimum number of receive bytes */ + cfmakeraw(&options); + + rv=cfsetispeed(&options, AQH_TTYOBJECT_BAUDRATE); + if (rv<0) { + DBG_ERROR(AQH_LOGDOMAIN, "Error on cfsetispeed(%s): %s (%d)", device, strerror(errno), errno); + return GWEN_ERROR_IO; + } + rv=cfsetospeed(&options, AQH_TTYOBJECT_BAUDRATE); + if (rv<0) { + DBG_ERROR(AQH_LOGDOMAIN, "Error on cfsetospeed(%s): %s (%d)", device, strerror(errno), errno); + return GWEN_ERROR_IO; + } + + rv=tcflush(fd, TCIOFLUSH); + if (rv<0) { + DBG_ERROR(AQH_LOGDOMAIN, "Error on tcflush(%s): %s (%d)", device, strerror(errno), errno); + return GWEN_ERROR_IO; + } + + rv=tcsetattr(fd, TCSANOW, &options); + if (rv<0) { + DBG_ERROR(AQH_LOGDOMAIN, "Error on tcsetattr(%s): %s (%d)", device, strerror(errno), errno); + return GWEN_ERROR_IO; + } + + return fd; +} + + + +int _fdSetBlocking(int fd, int fl) +{ + int prevFlags; + int newFlags; + + /* get current socket flags */ + prevFlags=fcntl(fd, F_GETFL); + if (prevFlags==-1) { + DBG_INFO(AQH_LOGDOMAIN, "fcntl(): %s", strerror(errno)); + return GWEN_ERROR_IO; + } + + /* set nonblocking/blocking */ + if (fl) + newFlags=prevFlags&(~O_NONBLOCK); + else + newFlags=prevFlags|O_NONBLOCK; + + if (-1==fcntl(fd, F_SETFL, newFlags)) { + DBG_INFO(AQH_LOGDOMAIN, "fcntl(): %s", strerror(errno)); + return GWEN_ERROR_IO; + } + prevFlags=fcntl(fd, F_GETFL); + if (prevFlags!=newFlags) { + DBG_ERROR(AQH_LOGDOMAIN, "fcntl() did not set flags correctly (%08x!=%08x)", prevFlags, newFlags); + return GWEN_ERROR_IO; + } + + return 0; +} + + + + + + diff --git a/aqhome/ipc2/ttyobject.h b/aqhome/ipc2/ttyobject.h new file mode 100644 index 0000000..6b5eabc --- /dev/null +++ b/aqhome/ipc2/ttyobject.h @@ -0,0 +1,38 @@ +/**************************************************************************** + * This file is part of the project Gwenhywfar. + * Gwenhywfar (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 AQH_TTYOBJECT_H +#define AQH_TTYOBJECT_H + + +#include + +#include + + +/** + * Create Tty object for given filedescriptor and in given mode (read or write) + * + * @return object created + * @param eventLoop event loop to assign the new object to + * @param fd filedescriptor (e.g. created by calls to open or socket) + * @param fdMode AQH_FDOBJECT_FDMODE_READ or AQH_FDOBJECT_FDMODE_WRITE + */ +AQHOME_API AQH_OBJECT *AQH_TtyObject_new(AQH_EVENT_LOOP *eventLoop, int fd, int fdMode); + +/** + * Open given device and setup TTY parameters for it. + * + * @return filedescriptor for the openened and initialized device + * @param device path to device to open (e.g. "/dev/ttyUSB0") + * @param initialTermiosState var to store initial state of the device (if given) + */ +AQHOME_API int AQH_TtyObject_OpenAndInitDevice(const char *device, struct termios *initialTermiosState); + + +#endif diff --git a/aqhome/libtest.c b/aqhome/libtest.c index 3675b45..4b1da83 100644 --- a/aqhome/libtest.c +++ b/aqhome/libtest.c @@ -17,6 +17,15 @@ #include "aqhome/hexfile/hexfile.h" #include "aqhome/hexfile/flashrecord.h" +#include "aqhome/events2/eventloop.h" +#include "aqhome/events2/fdobject.h" +#include "aqhome/ipc2/ttyobject.h" +#include "aqhome/ipc2/nodemsgreader.h" +#include "aqhome/ipc2/msgreader.h" +#include "aqhome/ipc2/msgwriter.h" +#include "aqhome/ipc2/nodeendpoint.h" + + #include "aqhome/aqhome.h" #include @@ -463,6 +472,51 @@ int testFlashRecords(int argc, char **argv) +int testTty(int argc, char **argv) +{ + const char *deviceName; + AQH_EVENT_LOOP *eventLoop; + struct termios initialTermiosState; + int fd; + AQH_OBJECT *ttyReadObject; + AQH_OBJECT *msgReaderObject; + AQH_OBJECT *nodeEndpointObject; + int rv; + + if (argc<2) { + fprintf(stderr, "Missing device name\n"); + return 1; + } + + rv=AQH_Init(); + if (rv<0) { + } + + deviceName=argv[1]; + + eventLoop=AQH_EventLoop_new(); + fd=AQH_TtyObject_OpenAndInitDevice(deviceName, &initialTermiosState); + if (fd<0) { + fprintf(stderr, "Error opening device \"%s\"\n", deviceName); + return 2; + } + + ttyReadObject=AQH_TtyObject_new(eventLoop, fd, AQH_FDOBJECT_FDMODE_READ); + AQH_FdObject_FlushInput(ttyReadObject); + msgReaderObject=AQH_NodeMsgReader_new(eventLoop, ttyReadObject); + nodeEndpointObject=AQH_NodeEndpoint_new(eventLoop, msgReaderObject, NULL); + + AQH_Object_Enable(msgReaderObject); + + for (;;) { + AQH_EventLoop_Run(eventLoop); + } + + return 0; +} + + + int main(int argc, char **argv) { @@ -471,7 +525,8 @@ int main(int argc, char **argv) //return testMqttConnection2(); //return testMqttSubscribe2(argc, argv); //return testHttpDaemon(); - return testMqttSubscribe3(argc, argv); + //return testMqttSubscribe3(argc, argv); + return testTty(argc, argv); return 0; } diff --git a/aqhome/msg/0BUILD b/aqhome/msg/0BUILD index 7a8d80e..9f09863 100644 --- a/aqhome/msg/0BUILD +++ b/aqhome/msg/0BUILD @@ -108,9 +108,13 @@ + aqhmsg_node + aqhmsg_ipc + node + ipc diff --git a/aqhome/msg/ipc/0BUILD b/aqhome/msg/ipc/0BUILD new file mode 100644 index 0000000..765cd13 --- /dev/null +++ b/aqhome/msg/ipc/0BUILD @@ -0,0 +1,84 @@ + + + + + + + + $(gwenhywfar_cflags) + -I$(topsrcdir) + -I$(topbuilddir) + + + + --include=$(builddir) + --include=$(srcdir) + + + + + + $(visibility_cflags) + + + + --api=AQHOME_API + + + + + + + + + + + + + + + + + + $(local/built_headers_pub) + + + + + m_ipc.h + m_ipc_tag16.h + m_ipc_result.h + + + + + + + + + $(local/typefiles) + + m_ipc.c + m_ipc_tag16.c + m_ipc_result.c + + + + + + + + + aqhmsg_ipcd + + + + data + + + + + + + + diff --git a/aqhome/msg/ipc/data/0BUILD b/aqhome/msg/ipc/data/0BUILD new file mode 100644 index 0000000..f86f805 --- /dev/null +++ b/aqhome/msg/ipc/data/0BUILD @@ -0,0 +1,90 @@ + + + + + + + + $(gwenhywfar_cflags) + -I$(topsrcdir) + -I$(topbuilddir) + + + + --include=$(builddir) + --include=$(srcdir) + + + + + + $(visibility_cflags) + + + + --api=AQHOME_API + + + + + + + + + + + + + + + + + + $(local/built_headers_pub) + + + + + m_ipcd.h + m_ipcd_connect.h + m_ipcd_multidata.h + m_ipcd_devices.h + m_ipcd_values.h + m_ipcd_getdata.h + m_ipcd_setdata.h + + + + + + + + + $(local/typefiles) + + m_ipcd.c + m_ipcd_connect.c + m_ipcd_multidata.c + m_ipcd_devices.c + m_ipcd_values.c + m_ipcd_getdata.c + m_ipcd_setdata.c + + + + + + + + + + + + + + + + + + + diff --git a/aqhome/msg/ipc/data/m_ipcd.c b/aqhome/msg/ipc/data/m_ipcd.c new file mode 100644 index 0000000..effdc30 --- /dev/null +++ b/aqhome/msg/ipc/data/m_ipcd.c @@ -0,0 +1,56 @@ +/**************************************************************************** + * 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 "aqhome/msg/ipc/data/m_ipcd.h" +#include "aqhome/msg/ipc/m_ipc.h" + +#include + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + + + +/* ------------------------------------------------------------------------------------------------ + * implementation + * ------------------------------------------------------------------------------------------------ + */ + +const char *AQH_IpcdMessage_MsgTypeToChar(uint16_t i) +{ + switch(i) { + case AQH_MSGTYPE_IPC_DATA_RESULT: return "Result"; + case AQH_MSGTYPE_IPC_DATA_CONNECT_REQ: return "Connect(Req)"; + case AQH_MSGTYPE_IPC_DATA_UPDATEDATA: return "UpdateData"; + case AQH_MSGTYPE_IPC_DATA_DATACHANGED: return "DataChanged"; + case AQH_MSGTYPE_IPC_DATA_SETDATA: return "SetData"; + case AQH_MSGTYPE_IPC_DATA_ADDVALUE: return "AddValue"; + case AQH_MSGTYPE_IPC_DATA_GETDATA_REQ: return "GetData(Req)"; + case AQH_MSGTYPE_IPC_DATA_GETDATA_RSP: return "GetData(Rsp)"; + case AQH_MSGTYPE_IPC_DATA_GETLASTDATA_REQ: return "GetLastData(Req)"; + case AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP: return "GetLastData(Rsp)"; + case AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ: return "GetValues(Req)"; + case AQH_MSGTYPE_IPC_DATA_GETVALUES_RSP: return "GetValues(Rsp)"; + case AQH_MSGTYPE_IPC_DATA_GETDEVICES_REQ: return "GetDevices(Req)"; + case AQH_MSGTYPE_IPC_DATA_GETDEVICES_RSP: return "GetDevices(Rsp)"; + case AQH_MSGTYPE_IPC_DATA_MODDEVICE_REQ: return "ModDevice(Req)"; + case AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE: return "AnnounceValue"; + default: return "(unknown)"; + } +} + + + diff --git a/aqhome/msg/ipc/data/m_ipcd.h b/aqhome/msg/ipc/data/m_ipcd.h new file mode 100644 index 0000000..aea5535 --- /dev/null +++ b/aqhome/msg/ipc/data/m_ipcd.h @@ -0,0 +1,57 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_M_IPCD_H +#define AQH_M_IPCD_H + + +#include +#include + + +#define AQH_IPC_PROTOCOL_DATA_ID 2 +#define AQH_IPC_PROTOCOL_DATA_VERSION 1 + + + +#define AQH_MSGTYPE_IPC_DATA_RESULT 0x0001 /* AQH_ResultIpcMsg */ + +#define AQH_MSGTYPE_IPC_DATA_CONNECT_REQ 0x0010 /* serviceName, userName, password */ + +#define AQH_MSGTYPE_IPC_DATA_UPDATEDATA 0x0100 /* AQH_MultiDataDataIpcMsg */ +#define AQH_MSGTYPE_IPC_DATA_DATACHANGED 0x0200 /* AQH_MultiDataDataIpcMsg */ + +#define AQH_MSGTYPE_IPC_DATA_SETDATA 0x0300 /* AQH_SetDataIpcMsg */ + +#define AQH_MSGTYPE_IPC_DATA_ADDVALUE 0x0400 /* AQH_AddValueDataIpcMsg */ + +#define AQH_MSGTYPE_IPC_DATA_GETDATA_REQ 0x0500 /* AQH_GetDataDataIpcMsg */ +#define AQH_MSGTYPE_IPC_DATA_GETDATA_RSP 0x0600 /* AQH_MultiDataDataIpcMsg */ + +#define AQH_MSGTYPE_IPC_DATA_GETLASTDATA_REQ 0x0700 /* AQH_GetDataDataIpcMsg */ +#define AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP 0x0800 /* AQH_MultiDataDataIpcMsg */ + +#define AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ 0x0900 /* GWEN_IpcMsg */ +#define AQH_MSGTYPE_IPC_DATA_GETVALUES_RSP 0x0a00 /* AQH_ValuesDataIpcMsg */ + +#define AQH_MSGTYPE_IPC_DATA_GETDEVICES_REQ 0x0b00 /* GWEN_IpcMsg */ +#define AQH_MSGTYPE_IPC_DATA_GETDEVICES_RSP 0x0c00 /* AQH_DevicesDataIpcMsg */ + +#define AQH_MSGTYPE_IPC_DATA_MODDEVICE_REQ 0x0d00 /* AQH_DevicesDataIpcMsg */ + +#define AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE 0x0e00 /* AQH_ValuesDataIpcMsg */ + + + +AQHOME_API const char *AQH_IpcdMessage_MsgTypeToChar(uint16_t i); + + + + + +#endif diff --git a/aqhome/msg/ipc/data/m_ipcd_connect.c b/aqhome/msg/ipc/data/m_ipcd_connect.c new file mode 100644 index 0000000..d3de792 --- /dev/null +++ b/aqhome/msg/ipc/data/m_ipcd_connect.c @@ -0,0 +1,90 @@ +/**************************************************************************** + * 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 "aqhome/msg/ipc/data/m_ipcd_connect.h" +#include "aqhome/msg/ipc/m_ipc_tag16.h" +#include "aqhome/msg/ipc/data/m_ipcd.h" +#include "aqhome/msg/ipc/m_ipc.h" + +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + + + +/* ------------------------------------------------------------------------------------------------ + * implementation + * ------------------------------------------------------------------------------------------------ + */ + +AQH_MESSAGE *AQH_IpcdMessageConnect_new(uint16_t code, uint32_t msgId, uint32_t refMsgId, + const char *clientId, const char *userId, const char *password, uint32_t flags) +{ + AQH_MESSAGE *msg; + GWEN_BUFFER *buf; + + buf=GWEN_Buffer_new(0, 256, 0, 1); + if (clientId && *clientId) + GWEN_Tag16_WriteStringTagToBuffer(AQH_MSGDATA_CONNECT_TAGS_CLIENTID, clientId, buf); + if (userId && *userId) + GWEN_Tag16_WriteStringTagToBuffer(AQH_MSGDATA_CONNECT_TAGS_USERID, userId, buf); + if (password && *password) + GWEN_Tag16_WriteStringTagToBuffer(AQH_MSGDATA_CONNECT_TAGS_PASSWORD, password, buf); + GWEN_Tag16_WriteUint32TagToBuffer(AQH_MSGDATA_CONNECT_TAGS_FLAGS, flags, buf); + + msg=AQH_IpcMessage_new(AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION, code, msgId, refMsgId, + GWEN_Buffer_GetUsedBytes(buf), (const uint8_t*) GWEN_Buffer_GetStart(buf)); + + GWEN_Buffer_free(buf); + return msg; +} + + + +void AQH_IpcdMessageConnect_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, GWEN_BUFFER *dbuf, const char *sText) +{ + char *clientId=NULL; + char *userId=NULL; + uint32_t flags=0; + + if (tagList) { + clientId=AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSGDATA_CONNECT_TAGS_CLIENTID, NULL); + userId=AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSGDATA_CONNECT_TAGS_USERID, NULL); + flags=AQH_Tag16_GetTagDataAsUint32(tagList, AQH_MSGDATA_CONNECT_TAGS_FLAGS, 0); + } + + GWEN_Buffer_AppendArgs(dbuf, + "CONNECT(%s) %s (code=%d, proto=%d, proto version=%d, clientId=%s, userId=%s, flags=%08x)\n", + AQH_IpcdMessage_MsgTypeToChar(AQH_IpcMessage_GetCode(msg)), + sText?sText:"", + AQH_IpcMessage_GetCode(msg), + AQH_IpcMessage_GetProtoId(msg), + AQH_IpcMessage_GetProtoVersion(msg), + clientId?clientId:"", + userId?userId:"", + flags); + free(userId); + free(clientId); +} + + + + + diff --git a/aqhome/msg/ipc/data/m_ipcd_connect.h b/aqhome/msg/ipc/data/m_ipcd_connect.h new file mode 100644 index 0000000..f2006f0 --- /dev/null +++ b/aqhome/msg/ipc/data/m_ipcd_connect.h @@ -0,0 +1,40 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_M_IPCD_CONNECT_H +#define AQH_M_IPCD_CONNECT_H + + + +#include +#include + +#include + + +#define AQH_MSGDATA_CONNECT_TAGS_CLIENTID 0x0001 +#define AQH_MSGDATA_CONNECT_TAGS_USERID 0x0002 +#define AQH_MSGDATA_CONNECT_TAGS_PASSWORD 0x0003 +#define AQH_MSGDATA_CONNECT_TAGS_FLAGS 0x0004 + +#define AQH_MSGDATA_CONNECT_FLAGS_WANTUPDATES 0x0001 + + + +AQHOME_API AQH_MESSAGE *AQH_IpcdMessageConnect_new(uint16_t code, + uint32_t msgId, uint32_t refMsgId, + const char *clientId, const char *userId, const char *password, + uint32_t flags); + +AQHOME_API void AQH_IpcdMessageConnect_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, + GWEN_BUFFER *dbuf, const char *sText); + + + + +#endif diff --git a/aqhome/msg/ipc/data/m_ipcd_devices.c b/aqhome/msg/ipc/data/m_ipcd_devices.c new file mode 100644 index 0000000..3634503 --- /dev/null +++ b/aqhome/msg/ipc/data/m_ipcd_devices.c @@ -0,0 +1,119 @@ +/**************************************************************************** + * 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 "aqhome/msg/ipc/data/m_ipcd_devices.h" +#include "aqhome/msg/ipc/m_ipc_tag16.h" +#include "aqhome/msg/ipc/data/m_ipcd.h" +#include "aqhome/msg/ipc/m_ipc.h" + +#include +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + + + +/* ------------------------------------------------------------------------------------------------ + * implementation + * ------------------------------------------------------------------------------------------------ + */ + +AQH_MESSAGE *AQH_IpcdMessageDevices_new(uint16_t code, uint32_t msgId, uint32_t refMsgId, + uint32_t flags, const AQH_DEVICE_LIST *deviceList) +{ + AQH_MESSAGE *msg; + GWEN_BUFFER *buf; + int rv; + + buf=GWEN_Buffer_new(0, 256, 0, 1); + GWEN_Tag16_WriteUint32TagToBuffer(AQH_MSGDATA_DEVICES_TAGS_FLAGS, flags, buf); + rv=AQH_Tag16_WriteDeviceListAsTagsToBuffer(AQH_MSGDATA_DEVICES_TAGS_DEVICE, deviceList, buf); + if (rv<0) { + DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); + GWEN_Buffer_free(buf); + return NULL; + } + + msg=AQH_IpcMessage_new(AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION, code, msgId, refMsgId, + GWEN_Buffer_GetUsedBytes(buf), (const uint8_t*) GWEN_Buffer_GetStart(buf)); + GWEN_Buffer_free(buf); + return msg; +} + + + +AQH_DEVICE_LIST *AQH_IpcdMessageDevices_ReadDeviceList(const GWEN_TAG16_LIST *tagList) +{ + if (tagList) { + AQH_DEVICE_LIST *deviceList; + + deviceList=AQH_Tag16_ReadDevicesFromTagList(tagList, AQH_MSGDATA_DEVICES_TAGS_DEVICE); + if (deviceList==NULL) { + DBG_INFO(AQH_LOGDOMAIN, "No device list received"); + } + return deviceList; + } + return NULL; +} + + + +AQH_DEVICE *AQH_IpcdMessageDevices_ReadFirstDevice(const GWEN_TAG16_LIST *tagList) +{ + if (tagList) { + AQH_DEVICE *device; + + device=AQH_Tag16_ReadDeviceFromTagList(tagList, AQH_MSGDATA_DEVICES_TAGS_DEVICE); + if (device==NULL) { + DBG_INFO(AQH_LOGDOMAIN, "No device received"); + } + return device; + } + return NULL; +} + + + +uint32_t AQH_IpcdMessageDevices_GetFlags(const GWEN_TAG16_LIST *tagList) +{ + return tagList?AQH_Tag16_GetTagDataAsUint32(tagList, AQH_MSGDATA_DEVICES_TAGS_FLAGS, 0):0; +} + + + +void AQH_IpcdMessageDevices_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, + GWEN_BUFFER *dbuf, const char *sText) +{ + uint32_t flags; + + flags=AQH_IpcdMessageDevices_GetFlags(tagList); + GWEN_Buffer_AppendArgs(dbuf, + "DEVICES(%s) %s (code=%d, proto=%d, proto version=%d, flags=0x%08x)\n", + AQH_IpcdMessage_MsgTypeToChar(AQH_IpcMessage_GetCode(msg)), + sText?sText:"", + AQH_IpcMessage_GetCode(msg), + AQH_IpcMessage_GetProtoId(msg), + AQH_IpcMessage_GetProtoVersion(msg), + (unsigned int) flags); +} + + + + diff --git a/aqhome/msg/ipc/data/m_ipcd_devices.h b/aqhome/msg/ipc/data/m_ipcd_devices.h new file mode 100644 index 0000000..81d59c1 --- /dev/null +++ b/aqhome/msg/ipc/data/m_ipcd_devices.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_M_IPCD_DEVICES_H +#define AQH_M_IPCD_DEVICES_H + + + +#include +#include +#include + +#include +#include + + + +#define AQH_MSGDATA_DEVICES_FLAGS_LASTMSG 0x0001 + +#define AQH_MSGDATA_DEVICES_TAGS_FLAGS 0x01 +#define AQH_MSGDATA_DEVICES_TAGS_DEVICE 0xc2 + + + +AQHOME_API AQH_MESSAGE *AQH_IpcdMessageDevices_new(uint16_t code, uint32_t msgId, uint32_t refMsgId, + uint32_t flags, const AQH_DEVICE_LIST *deviceList); +AQHOME_API AQH_DEVICE_LIST *AQH_IpcdMessageDevices_ReadDeviceList(const GWEN_TAG16_LIST *tagList); +AQHOME_API AQH_DEVICE *AQH_IpcdMessageDevices_ReadFirstDevice(const GWEN_TAG16_LIST *tagList); +AQHOME_API uint32_t AQH_IpcdMessageDevices_GetFlags(const GWEN_TAG16_LIST *tagList); + +AQHOME_API void AQH_IpcdMessageDevices_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, + GWEN_BUFFER *dbuf, const char *sText); + + + +#endif diff --git a/aqhome/msg/ipc/data/m_ipcd_getdata.c b/aqhome/msg/ipc/data/m_ipcd_getdata.c new file mode 100644 index 0000000..47b85cb --- /dev/null +++ b/aqhome/msg/ipc/data/m_ipcd_getdata.c @@ -0,0 +1,87 @@ +/**************************************************************************** + * 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 "aqhome/msg/ipc/data/m_ipcd_getdata.h" +#include "aqhome/msg/ipc/m_ipc_tag16.h" +#include "aqhome/msg/ipc/data/m_ipcd.h" +#include "aqhome/msg/ipc/m_ipc.h" + +#include +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + + + +/* ------------------------------------------------------------------------------------------------ + * implementation + * ------------------------------------------------------------------------------------------------ + */ + +AQH_MESSAGE *AQH_IpcdMessageGetData_new(uint16_t code, + uint32_t msgId, uint32_t refMsgId, + const char *valueName, uint64_t tsBegin, uint64_t tsEnd, uint64_t num) +{ + AQH_MESSAGE *msg; + GWEN_BUFFER *buf; + + buf=GWEN_Buffer_new(0, 256, 0, 1); + + if (valueName && *valueName) + GWEN_Tag16_WriteStringTagToBuffer(AQH_MSGDATA_GETDATA_TAGS_NAME, valueName, buf); + GWEN_Tag16_WriteUint64TagToBuffer(AQH_MSGDATA_GETDATA_TAGS_BEGIN, tsBegin, buf); + GWEN_Tag16_WriteUint64TagToBuffer(AQH_MSGDATA_GETDATA_TAGS_END, tsEnd, buf); + GWEN_Tag16_WriteUint64TagToBuffer(AQH_MSGDATA_GETDATA_TAGS_NUM, num, buf); + + msg=AQH_IpcMessage_new(AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION, code, msgId, refMsgId, + GWEN_Buffer_GetUsedBytes(buf), (const uint8_t*) GWEN_Buffer_GetStart(buf)); + GWEN_Buffer_free(buf); + return msg; +} + + + +void AQH_IpcdMessageGetData_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, + GWEN_BUFFER *dbuf, const char *sText) +{ + char *valueName; + uint64_t tsBegin; + uint64_t tsEnd; + + valueName=tagList?AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSGDATA_GETDATA_TAGS_NAME, NULL):NULL; + tsBegin=tagList?AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_BEGIN, 0):0; + tsEnd=tagList?AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_END, 0):0; + + GWEN_Buffer_AppendArgs(dbuf, + "GETDATA(%s) %s (code=%d, proto=%d, proto version=%d, name=%s, tsBegin=%lu, tsEnd=%lu)\n", + AQH_IpcdMessage_MsgTypeToChar(AQH_IpcMessage_GetCode(msg)), + sText?sText:"", + AQH_IpcMessage_GetCode(msg), + AQH_IpcMessage_GetProtoId(msg), + AQH_IpcMessage_GetProtoVersion(msg), + valueName?valueName:"", + (unsigned long int) tsBegin, + (unsigned long int) tsEnd); + free(valueName); +} + + + + diff --git a/aqhome/msg/ipc/data/m_ipcd_getdata.h b/aqhome/msg/ipc/data/m_ipcd_getdata.h new file mode 100644 index 0000000..46ea85d --- /dev/null +++ b/aqhome/msg/ipc/data/m_ipcd_getdata.h @@ -0,0 +1,38 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_M_IPCD_GETDATA_H +#define AQH_M_IPCD_GETDATA_H + + + +#include +#include +#include + +#include +#include + + + +#define AQH_MSGDATA_GETDATA_TAGS_NAME 0x0001 +#define AQH_MSGDATA_GETDATA_TAGS_BEGIN 0x0020 +#define AQH_MSGDATA_GETDATA_TAGS_END 0x0021 +#define AQH_MSGDATA_GETDATA_TAGS_NUM 0x0022 + + +AQHOME_API AQH_MESSAGE *AQH_IpcdMessageGetData_new(uint16_t code, + uint32_t msgId, uint32_t refMsgId, + const char *valueName, uint64_t tsBegin, uint64_t tsEnd, uint64_t num); + +AQHOME_API void AQH_IpcdMessageGetData_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, + GWEN_BUFFER *dbuf, const char *sText); + + + +#endif diff --git a/aqhome/msg/ipc/data/m_ipcd_multidata.c b/aqhome/msg/ipc/data/m_ipcd_multidata.c new file mode 100644 index 0000000..9886775 --- /dev/null +++ b/aqhome/msg/ipc/data/m_ipcd_multidata.c @@ -0,0 +1,158 @@ +/**************************************************************************** + * 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 "aqhome/msg/ipc/data/m_ipcd_multidata.h" +#include "aqhome/msg/ipc/m_ipc_tag16.h" +#include "aqhome/msg/ipc/data/m_ipcd.h" +#include "aqhome/msg/ipc/m_ipc.h" + +#include +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + + + +/* ------------------------------------------------------------------------------------------------ + * implementation + * ------------------------------------------------------------------------------------------------ + */ + +AQH_MESSAGE *AQH_IpcdMessageMultiData_new(uint16_t code, + uint32_t msgId, uint32_t refMsgId, + const AQH_VALUE *value, const uint64_t *i64Ptr, int numOfDataPoints) +{ + AQH_MESSAGE *msg; + GWEN_BUFFER *buf; + int rv; + + buf=GWEN_Buffer_new(0, 256, 0, 1); + + rv=AQH_Tag16_WriteValueAsTagToBuffer(AQH_MSGDATA_MULTIDATA_TAGS_VALUE, value, buf); + if (rv<0) { + DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); + GWEN_Buffer_free(buf); + return NULL; + } + + if (i64Ptr && numOfDataPoints) + GWEN_Tag16_WriteTagToBuffer(AQH_MSGDATA_MULTIDATA_TAGS_DATA, (const uint8_t*)i64Ptr, numOfDataPoints*2*sizeof(uint64_t), buf); + + msg=AQH_IpcMessage_new(AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION, code, msgId, refMsgId, + GWEN_Buffer_GetUsedBytes(buf), (const uint8_t*) GWEN_Buffer_GetStart(buf)); + GWEN_Buffer_free(buf); + return msg; +} + + + +AQH_MESSAGE *AQH_IpcdMessageMultiData_newForOne(uint16_t code, + uint32_t msgId, uint32_t refMsgId, + const AQH_VALUE *value, uint64_t timeStamp, double dataPoint) +{ + AQH_MESSAGE *msg; + GWEN_BUFFER *buf; + int rv; + union {double f; uint64_t i;} u; + uint64_t arrayToSend[2]; + + buf=GWEN_Buffer_new(0, 256, 0, 1); + + rv=AQH_Tag16_WriteValueAsTagToBuffer(AQH_MSGDATA_MULTIDATA_TAGS_VALUE, value, buf); + if (rv<0) { + DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); + GWEN_Buffer_free(buf); + return NULL; + } + + arrayToSend[0]=timeStamp; + u.f=dataPoint; + arrayToSend[1]=u.i; + GWEN_Tag16_WriteTagToBuffer(AQH_MSGDATA_MULTIDATA_TAGS_DATA, (const uint8_t*) arrayToSend, 2*sizeof(uint64_t), buf); + + msg=AQH_IpcMessage_new(AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION, code, msgId, refMsgId, + GWEN_Buffer_GetUsedBytes(buf), (const uint8_t*) GWEN_Buffer_GetStart(buf)); + GWEN_Buffer_free(buf); + return msg; +} + + + +AQH_VALUE *AQH_IpcdMessageMultiData_ReadValue(const GWEN_TAG16_LIST *tagList) +{ + return tagList?AQH_Tag16_ReadValueFromTagList(tagList, AQH_MSGDATA_MULTIDATA_TAGS_VALUE):NULL; +} + + + +void AQH_IpcdMessageMultiData_ReadDatapoints(const GWEN_TAG16_LIST *tagList, const uint64_t **pDataPtr, uint64_t *pNumberOfPoints) +{ + if (tagList) { + const GWEN_TAG16 *tag; + unsigned int numberOfPoints; + const uint64_t *dataPoints; + + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_MULTIDATA_TAGS_DATA); + numberOfPoints=(tag?GWEN_Tag16_GetTagLength(tag):0)/(2*sizeof(uint64_t)); + dataPoints=tag?((const uint64_t*) GWEN_Tag16_GetTagData(tag)):NULL; + if (numberOfPoints>0 && dataPoints) { + *pDataPtr=dataPoints; + *pNumberOfPoints=numberOfPoints; + } + } +} + + + +void AQH_IpcdMessageMultiData_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, GWEN_BUFFER *dbuf, const char *sText) +{ + AQH_VALUE *value; + const GWEN_TAG16 *tag; + const char *valueName; + const char *valueUnits; + int valueType; + unsigned int numberOfPoints=0; + + value=tagList?AQH_IpcdMessageMultiData_ReadValue(tagList):NULL; + valueName=value?AQH_Value_GetNameForSystem(value):NULL; + valueUnits=value?AQH_Value_GetValueUnits(value):NULL; + valueType=value?AQH_Value_GetValueType(value):0; + + tag=tagList?GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGDATA_MULTIDATA_TAGS_DATA):NULL; + numberOfPoints=(tag?GWEN_Tag16_GetTagLength(tag):0)/(2*sizeof(uint64_t)); + + GWEN_Buffer_AppendArgs(dbuf, + "MULTIDATA(%s) %s (code=%d, proto=%d, proto version=%d, name=%s, units=%s, type=%d, datapoints=%u)\n", + AQH_IpcdMessage_MsgTypeToChar(AQH_IpcMessage_GetCode(msg)), + sText?sText:"", + AQH_IpcMessage_GetCode(msg), + AQH_IpcMessage_GetProtoId(msg), + AQH_IpcMessage_GetProtoVersion(msg), + valueName?valueName:"", + valueUnits?valueUnits:"", + valueType, + numberOfPoints); + AQH_Value_free(value); +} + + + + + diff --git a/aqhome/msg/ipc/data/m_ipcd_multidata.h b/aqhome/msg/ipc/data/m_ipcd_multidata.h new file mode 100644 index 0000000..68edd91 --- /dev/null +++ b/aqhome/msg/ipc/data/m_ipcd_multidata.h @@ -0,0 +1,44 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_M_IPCD_MULTIDATA_H +#define AQH_M_IPCD_MULTIDATA_H + + + +#include +#include +#include + +#include +#include + + + +#define AQH_MSGDATA_MULTIDATA_TAGS_VALUE 0xc1 +#define AQH_MSGDATA_MULTIDATA_TAGS_DATA 0xc2 + + + +AQHOME_API AQH_MESSAGE *AQH_IpcdMessageMultiData_new(uint16_t code, + uint32_t msgId, uint32_t refMsgId, + const AQH_VALUE *value, const uint64_t *i64Ptr, int numOfDataPoints); +AQHOME_API AQH_MESSAGE *AQH_IpcdMessageMultiData_newForOne(uint16_t code, + uint32_t msgId, uint32_t refMsgId, + const AQH_VALUE *value, uint64_t timeStamp, double dataPoint); + +AQHOME_API AQH_VALUE *AQH_IpcdMessageMultiData_ReadValue(const GWEN_TAG16_LIST *tagList); +AQHOME_API void AQH_IpcdMessageMultiData_ReadDatapoints(const GWEN_TAG16_LIST *tagList, + const uint64_t **pDataPtr, uint64_t *pNumberOfPoints); + +AQHOME_API void AQH_IpcdMessageMultiData_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, + GWEN_BUFFER *dbuf, const char *sText); + + + +#endif diff --git a/aqhome/msg/ipc/data/m_ipcd_setdata.c b/aqhome/msg/ipc/data/m_ipcd_setdata.c new file mode 100644 index 0000000..63b71a5 --- /dev/null +++ b/aqhome/msg/ipc/data/m_ipcd_setdata.c @@ -0,0 +1,120 @@ +/**************************************************************************** + * 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 "aqhome/msg/ipc/data/m_ipcd_setdata.h" +#include "aqhome/msg/ipc/m_ipc_tag16.h" +#include "aqhome/msg/ipc/data/m_ipcd.h" +#include "aqhome/msg/ipc/m_ipc.h" + +#include +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + + + +/* ------------------------------------------------------------------------------------------------ + * implementation + * ------------------------------------------------------------------------------------------------ + */ + +AQH_MESSAGE *AQH_IpcdMessageSetData_new(uint16_t code, + uint32_t msgId, uint32_t refMsgId, + const AQH_VALUE *value, const char *data) +{ + AQH_MESSAGE *msg; + GWEN_BUFFER *buf; + int rv; + + buf=GWEN_Buffer_new(0, 256, 0, 1); + + rv=AQH_Tag16_WriteValueAsTagToBuffer(AQH_MSGDATA_SET_TAGS_VALUE, value, buf); + if (rv<0) { + DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); + GWEN_Buffer_free(buf); + return NULL; + } + if (data && *data) + GWEN_Tag16_WriteStringTagToBuffer(AQH_MSGDATA_SET_TAGS_DATA, data, buf); + + msg=AQH_IpcMessage_new(AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION, code, msgId, refMsgId, + GWEN_Buffer_GetUsedBytes(buf), (const uint8_t*) GWEN_Buffer_GetStart(buf)); + GWEN_Buffer_free(buf); + return msg; +} + + + +AQH_VALUE *AQH_IpcdMessageSetData_ReadValue(const GWEN_TAG16_LIST *tagList) +{ + if (tagList) { + AQH_VALUE *value; + + value=AQH_Tag16_ReadValueFromTagList(tagList, AQH_MSGDATA_SET_TAGS_VALUE); + if (value==NULL) { + DBG_INFO(AQH_LOGDOMAIN, "No value received"); + } + return value; + } + return NULL; +} + + + +char *AQH_IpcdMessageSetData_ReadData(const GWEN_TAG16_LIST *tagList) +{ + return AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSGDATA_SET_TAGS_DATA, NULL); +} + + + +void AQH_IpcdMessageSetData_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, + GWEN_BUFFER *dbuf, const char *sText) +{ + AQH_VALUE *value; + const char *valueName; + const char *valueUnits; + int valueType; + char *data; + + value=tagList?AQH_IpcdMessageSetData_ReadValue(tagList):NULL; + valueName=value?AQH_Value_GetNameForSystem(value):NULL; + valueUnits=value?AQH_Value_GetValueUnits(value):NULL; + valueType=value?AQH_Value_GetValueType(value):0; + data=tagList?AQH_IpcdMessageSetData_ReadData(tagList):NULL; + + GWEN_Buffer_AppendArgs(dbuf, + "SETDATA(%s) %s (code=%d, proto=%d, proto version=%d, name=%s, units=%s, type=%d, value=%s)\n", + AQH_IpcdMessage_MsgTypeToChar(AQH_IpcMessage_GetCode(msg)), + sText?sText:"", + AQH_IpcMessage_GetCode(msg), + AQH_IpcMessage_GetProtoId(msg), + AQH_IpcMessage_GetProtoVersion(msg), + valueName?valueName:"", + valueUnits?valueUnits:"", + valueType, + data?data:""); + free(data); + AQH_Value_free(value); +} + + + + diff --git a/aqhome/msg/ipc/data/m_ipcd_setdata.h b/aqhome/msg/ipc/data/m_ipcd_setdata.h new file mode 100644 index 0000000..3aee4ba --- /dev/null +++ b/aqhome/msg/ipc/data/m_ipcd_setdata.h @@ -0,0 +1,43 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_M_IPCD_SETDATA_H +#define AQH_M_IPCD_SETDATA_H + + + +#include +#include +#include + +#include +#include + + + +#define AQH_MSGDATA_SET_TAGS_VALUE 0xc1 +#define AQH_MSGDATA_SET_TAGS_DATA 0x02 + + + +AQHOME_API AQH_MESSAGE *AQH_IpcdMessageSetData_new(uint16_t code, + uint32_t msgId, uint32_t refMsgId, + const AQH_VALUE *value, const char *data); + +AQHOME_API AQH_VALUE *AQH_IpcdMessageSetData_ReadValue(const GWEN_TAG16_LIST *tagList); +AQHOME_API char *AQH_IpcdMessageSetData_ReadData(const GWEN_TAG16_LIST *tagList); + +AQHOME_API void AQH_IpcdMessageSetData_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, + GWEN_BUFFER *dbuf, const char *sText); + + + + + + +#endif diff --git a/aqhome/msg/ipc/data/m_ipcd_values.c b/aqhome/msg/ipc/data/m_ipcd_values.c new file mode 100644 index 0000000..d11024d --- /dev/null +++ b/aqhome/msg/ipc/data/m_ipcd_values.c @@ -0,0 +1,119 @@ +/**************************************************************************** + * 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 "aqhome/msg/ipc/data/m_ipcd_values.h" +#include "aqhome/msg/ipc/m_ipc_tag16.h" +#include "aqhome/msg/ipc/data/m_ipcd.h" +#include "aqhome/msg/ipc/m_ipc.h" + +#include +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + + + +/* ------------------------------------------------------------------------------------------------ + * implementation + * ------------------------------------------------------------------------------------------------ + */ + +AQH_MESSAGE *AQH_IpcdMessageValues_new(uint16_t code, uint32_t msgId, uint32_t refMsgId, + uint32_t flags, const AQH_VALUE_LIST *valueList) +{ + AQH_MESSAGE *msg; + GWEN_BUFFER *buf; + int rv; + + buf=GWEN_Buffer_new(0, 256, 0, 1); + GWEN_Tag16_WriteUint32TagToBuffer(AQH_MSGDATA_VALUES_TAGS_FLAGS, flags, buf); + rv=AQH_Tag16_WriteValueListAsTagsToBuffer(AQH_MSGDATA_VALUES_TAGS_VALUE, valueList, buf); + if (rv<0) { + DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); + GWEN_Buffer_free(buf); + return NULL; + } + + msg=AQH_IpcMessage_new(AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION, code, msgId, refMsgId, + GWEN_Buffer_GetUsedBytes(buf), (const uint8_t*) GWEN_Buffer_GetStart(buf)); + GWEN_Buffer_free(buf); + return msg; +} + + + +AQH_VALUE_LIST *AQH_IpcdMessageDevices_ReadValueList(const GWEN_TAG16_LIST *tagList) +{ + if (tagList) { + AQH_VALUE_LIST *valueList; + + valueList=AQH_Tag16_ReadValuesFromTagList(tagList, AQH_MSGDATA_VALUES_TAGS_VALUE); + if (valueList==NULL) { + DBG_INFO(AQH_LOGDOMAIN, "No value list received"); + } + return valueList; + } + return NULL; +} + + + +AQH_VALUE *AQH_IpcdMessageValues_ReadFirstValue(const GWEN_TAG16_LIST *tagList) +{ + if (tagList) { + AQH_VALUE *value; + + value=AQH_Tag16_ReadValueFromTagList(tagList, AQH_MSGDATA_VALUES_TAGS_VALUE); + if (value==NULL) { + DBG_INFO(AQH_LOGDOMAIN, "No value received"); + } + return value; + } + return NULL; +} + + + +uint32_t AQH_IpcdMessageValues_GetFlags(const GWEN_TAG16_LIST *tagList) +{ + return tagList?AQH_Tag16_GetTagDataAsUint32(tagList, AQH_MSGDATA_VALUES_TAGS_FLAGS, 0):0; +} + + + +void AQH_IpcdMessageValues_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, + GWEN_BUFFER *dbuf, const char *sText) +{ + uint32_t flags; + + flags=AQH_IpcdMessageValues_GetFlags(tagList); + GWEN_Buffer_AppendArgs(dbuf, + "VALUES(%s) %s (code=%d, proto=%d, proto version=%d, flags=0x%08x)\n", + AQH_IpcdMessage_MsgTypeToChar(AQH_IpcMessage_GetCode(msg)), + sText?sText:"", + AQH_IpcMessage_GetCode(msg), + AQH_IpcMessage_GetProtoId(msg), + AQH_IpcMessage_GetProtoVersion(msg), + (unsigned int) flags); +} + + + + diff --git a/aqhome/msg/ipc/data/m_ipcd_values.h b/aqhome/msg/ipc/data/m_ipcd_values.h new file mode 100644 index 0000000..f083ca2 --- /dev/null +++ b/aqhome/msg/ipc/data/m_ipcd_values.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_M_IPCD_VALUES_H +#define AQH_M_IPCD_VALUES_H + + + +#include +#include +#include + +#include +#include + + + +#define AQH_MSGDATA_VALUES_FLAGS_LASTMSG 0x0001 + +#define AQH_MSGDATA_VALUES_TAGS_FLAGS 0x01 +#define AQH_MSGDATA_VALUES_TAGS_VALUE 0xc2 + + + +AQHOME_API AQH_MESSAGE *AQH_IpcdMessageValues_new(uint16_t code, uint32_t msgId, uint32_t refMsgId, + uint32_t flags, const AQH_VALUE_LIST *valueList); +AQHOME_API AQH_VALUE_LIST *AQH_IpcdMessageDevices_ReadValueList(const GWEN_TAG16_LIST *tagList); +AQHOME_API AQH_VALUE *AQH_IpcdMessageValues_ReadFirstValue(const GWEN_TAG16_LIST *tagList); +AQHOME_API uint32_t AQH_IpcdMessageValues_GetFlags(const GWEN_TAG16_LIST *tagList); + +AQHOME_API void AQH_IpcdMessageValues_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, + GWEN_BUFFER *dbuf, const char *sText); + + + +#endif diff --git a/aqhome/msg/ipc/m_ipc.c b/aqhome/msg/ipc/m_ipc.c new file mode 100644 index 0000000..70f2586 --- /dev/null +++ b/aqhome/msg/ipc/m_ipc.c @@ -0,0 +1,159 @@ +/**************************************************************************** + * 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 "aqhome/msg/ipc/m_ipc.h" + +#include + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + + + +/* ------------------------------------------------------------------------------------------------ + * implementation + * ------------------------------------------------------------------------------------------------ + */ + +AQH_MESSAGE *AQH_IpcMessage_new(uint8_t protoId, uint8_t protoVer, uint16_t code, + uint32_t msgId, uint32_t refMsgId, + uint32_t payloadLen, const uint8_t *payload) +{ + AQH_MESSAGE *msg; + uint32_t len; + + len=AQH_IPCMSG_OFFS_PAYLOAD+payloadLen; + msg=AQH_Message_new(); + AQH_Message_SetData(msg, NULL, len); /* auto-malloc len bytes */ + + AQH_Message_WriteUint32At(msg, AQH_IPCMSG_OFFS_SIZE, len); + AQH_Message_WriteUint8At(msg, AQH_IPCMSG_OFFS_PROTOID, protoId); + AQH_Message_WriteUint8At(msg, AQH_IPCMSG_OFFS_PROTOVER, protoVer); + AQH_Message_WriteUint16At(msg, AQH_IPCMSG_OFFS_CODE, code); + AQH_Message_WriteUint32At(msg, AQH_IPCMSG_OFFS_ID, msgId); + AQH_Message_WriteUint32At(msg, AQH_IPCMSG_OFFS_REFID, refMsgId); + if (payloadLen && payload) + AQH_Message_WriteBytesAt(msg, AQH_IPCMSG_OFFS_PAYLOAD, payload, payloadLen); + AQH_Message_SetUsedSize(msg, len); + return msg; +} + + + +AQH_MESSAGE *AQH_IpcMessage_fromBuffer(const uint8_t *ptr, uint32_t len) +{ + if (ptr && len) { + AQH_MESSAGE *msg; + + msg=AQH_Message_new(); + AQH_Message_SetData(msg, ptr, len); + AQH_Message_SetUsedSize(msg, len); + return msg; + } + return NULL; +} + + + +void AQH_IpcMessage_AdjustMsgSize(AQH_MESSAGE *msg) +{ + if (msg) + AQH_Message_WriteUint32At(msg, AQH_IPCMSG_OFFS_SIZE, AQH_Message_GetUsedSize(msg)); +} + + + +uint32_t AQH_IpcMessage_GetMsgSize(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint32At(msg, AQH_IPCMSG_OFFS_SIZE, 0); +} + + + +uint8_t AQH_IpcMessage_GetProtoId(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint8At(msg, AQH_IPCMSG_OFFS_PROTOID, 0); +} + + + +uint8_t AQH_IpcMessage_GetProtoVersion(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint8At(msg, AQH_IPCMSG_OFFS_PROTOVER, 0); +} + + + +uint16_t AQH_IpcMessage_GetCode(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint16At(msg, AQH_IPCMSG_OFFS_CODE, 0); +} + + + +uint32_t AQH_IpcMessage_GetMsgId(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint32At(msg, AQH_IPCMSG_OFFS_ID, 0); +} + + + +uint32_t AQH_IpcMessage_GetRefMsgId(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint32At(msg, AQH_IPCMSG_OFFS_REFID, 0); +} + + + +uint32_t AQH_IpcMessage_GetPayloadLength(const AQH_MESSAGE *msg) +{ + return msg?(AQH_IpcMessage_GetMsgSize(msg)-AQH_IPCMSG_OFFS_PAYLOAD):0; +} + + + +uint8_t *AQH_IpcMessage_GetPayloadPointer(const AQH_MESSAGE *msg) +{ + return msg?(AQH_Message_GetMsgPointer(msg)+AQH_IPCMSG_OFFS_PAYLOAD):NULL; +} + + + +const char *AQH_IpcMessage_MsgTypeToChar(uint16_t i) +{ + switch(i) { + case AQH_MSGTYPE_IPC_DATA_RESULT: return "Result"; + case AQH_MSGTYPE_IPC_DATA_CONNECT_REQ: return "Connect(Req)"; + case AQH_MSGTYPE_IPC_DATA_UPDATEDATA: return "UpdateData"; + case AQH_MSGTYPE_IPC_DATA_DATACHANGED: return "DataChanged"; + case AQH_MSGTYPE_IPC_DATA_SETDATA: return "SetData"; + case AQH_MSGTYPE_IPC_DATA_ADDVALUE: return "AddValue"; + case AQH_MSGTYPE_IPC_DATA_GETDATA_REQ: return "GetData(Req)"; + case AQH_MSGTYPE_IPC_DATA_GETDATA_RSP: return "GetData(Rsp)"; + case AQH_MSGTYPE_IPC_DATA_GETLASTDATA_REQ: return "GetLastData(Req)"; + case AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP: return "GetLastData(Rsp)"; + case AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ: return "GetValues(Req)"; + case AQH_MSGTYPE_IPC_DATA_GETVALUES_RSP: return "GetValues(Rsp)"; + case AQH_MSGTYPE_IPC_DATA_GETDEVICES_REQ: return "GetDevices(Req)"; + case AQH_MSGTYPE_IPC_DATA_GETDEVICES_RSP: return "GetDevices(Rsp)"; + case AQH_MSGTYPE_IPC_DATA_MODDEVICE_REQ: return "ModDevice(Req)"; + case AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE: return "AnnounceValue"; + default: return "(unknown)"; + } +} + + + diff --git a/aqhome/msg/ipc/m_ipc.h b/aqhome/msg/ipc/m_ipc.h new file mode 100644 index 0000000..739256b --- /dev/null +++ b/aqhome/msg/ipc/m_ipc.h @@ -0,0 +1,85 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_M_IPC_H +#define AQH_M_IPC_H + + +#include +#include + + +#define AQH_IPCMSG_OFFS_SIZE 0 /* 4 bytes: number of all bytes including size, protoid, protover and code */ +#define AQH_IPCMSG_OFFS_PROTOID 4 /* 1 byte: protocol id (free to use) */ +#define AQH_IPCMSG_OFFS_PROTOVER 5 /* 1 byte: protocol version (free to use) */ +#define AQH_IPCMSG_OFFS_CODE 6 /* 2 bytes msg code (meaning depends on protocol) */ +#define AQH_IPCMSG_OFFS_ID 8 /* 4 bytes msg id */ +#define AQH_IPCMSG_OFFS_REFID 12 /* 4 bytes reference msg id */ +#define AQH_IPCMSG_OFFS_PAYLOAD 16 /* begin of payload for a given message */ + + + +#define AQH_IPC_PROTOCOL_DATA_ID 2 +#define AQH_IPC_PROTOCOL_DATA_VERSION 1 + + + +#define AQH_MSGTYPE_IPC_DATA_RESULT 0x0001 /* AQH_ResultIpcMsg */ + +#define AQH_MSGTYPE_IPC_DATA_CONNECT_REQ 0x0010 /* serviceName, userName, password */ + +#define AQH_MSGTYPE_IPC_DATA_UPDATEDATA 0x0100 /* AQH_MultiDataDataIpcMsg */ +#define AQH_MSGTYPE_IPC_DATA_DATACHANGED 0x0200 /* AQH_MultiDataDataIpcMsg */ + +#define AQH_MSGTYPE_IPC_DATA_SETDATA 0x0300 /* AQH_SetDataIpcMsg */ + +#define AQH_MSGTYPE_IPC_DATA_ADDVALUE 0x0400 /* AQH_AddValueDataIpcMsg */ + +#define AQH_MSGTYPE_IPC_DATA_GETDATA_REQ 0x0500 /* AQH_GetDataDataIpcMsg */ +#define AQH_MSGTYPE_IPC_DATA_GETDATA_RSP 0x0600 /* AQH_MultiDataDataIpcMsg */ + +#define AQH_MSGTYPE_IPC_DATA_GETLASTDATA_REQ 0x0700 /* AQH_GetDataDataIpcMsg */ +#define AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP 0x0800 /* AQH_MultiDataDataIpcMsg */ + +#define AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ 0x0900 /* GWEN_IpcMsg */ +#define AQH_MSGTYPE_IPC_DATA_GETVALUES_RSP 0x0a00 /* AQH_ValuesDataIpcMsg */ + +#define AQH_MSGTYPE_IPC_DATA_GETDEVICES_REQ 0x0b00 /* GWEN_IpcMsg */ +#define AQH_MSGTYPE_IPC_DATA_GETDEVICES_RSP 0x0c00 /* AQH_DevicesDataIpcMsg */ + +#define AQH_MSGTYPE_IPC_DATA_MODDEVICE_REQ 0x0d00 /* AQH_DevicesDataIpcMsg */ + +#define AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE 0x0e00 /* AQH_ValuesDataIpcMsg */ + + + +AQHOME_API AQH_MESSAGE *AQH_IpcMessage_new(uint8_t protoId, uint8_t protoVer, uint16_t code, + uint32_t msgId, uint32_t refMsgId, + uint32_t payloadLen, const uint8_t *payload); +AQHOME_API AQH_MESSAGE *AQH_IpcMessage_fromBuffer(const uint8_t *ptr, uint32_t len); + +AQHOME_API void AQH_IpcMessage_AdjustMsgSize(AQH_MESSAGE *msg); + +AQHOME_API uint32_t AQH_IpcMessage_GetMsgSize(const AQH_MESSAGE *msg); +AQHOME_API uint8_t AQH_IpcMessage_GetProtoId(const AQH_MESSAGE *msg); +AQHOME_API uint8_t AQH_IpcMessage_GetProtoVersion(const AQH_MESSAGE *msg); +AQHOME_API uint16_t AQH_IpcMessage_GetCode(const AQH_MESSAGE *msg); +AQHOME_API uint32_t AQH_IpcMessage_GetMsgId(const AQH_MESSAGE *msg); +AQHOME_API uint32_t AQH_IpcMessage_GetRefMsgId(const AQH_MESSAGE *msg); + +AQHOME_API uint32_t AQH_IpcMessage_GetPayloadLength(const AQH_MESSAGE *msg); +AQHOME_API uint8_t *AQH_IpcMessage_GetPayloadPointer(const AQH_MESSAGE *msg); + + +AQHOME_API const char *AQH_IpcMessage_MsgTypeToChar(uint16_t i); + + + + + +#endif diff --git a/aqhome/msg/ipc/m_ipc_result.c b/aqhome/msg/ipc/m_ipc_result.c new file mode 100644 index 0000000..01cb7b8 --- /dev/null +++ b/aqhome/msg/ipc/m_ipc_result.c @@ -0,0 +1,81 @@ +/**************************************************************************** + * 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 "aqhome/msg/ipc/m_ipc_result.h" +#include "aqhome/msg/ipc/m_ipc_tag16.h" +#include "aqhome/msg/ipc/m_ipc.h" + +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + + + +/* ------------------------------------------------------------------------------------------------ + * implementation + * ------------------------------------------------------------------------------------------------ + */ + +AQH_MESSAGE *AQH_IpcMessageResult_new(uint8_t protoId, uint8_t protoVer, uint16_t code, + uint32_t msgId, uint32_t refMsgId, + int result, const char *text) +{ + AQH_MESSAGE *msg; + GWEN_BUFFER *buf; + + buf=GWEN_Buffer_new(0, 256, 0, 1); + GWEN_Tag16_WriteUint32TagToBuffer(AQH_MSGDATA_RESULT_TAGS_RESULT, result, buf); + if (text && *text) + GWEN_Tag16_WriteStringTagToBuffer(AQH_MSGDATA_RESULT_TAGS_TEXT, text, buf); + + msg=AQH_IpcMessage_new(protoId, protoVer, code, msgId, refMsgId, + GWEN_Buffer_GetUsedBytes(buf), (const uint8_t*) GWEN_Buffer_GetStart(buf)); + GWEN_Buffer_free(buf); + return msg; +} + + + +void AQH_IpcMessageResult_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, GWEN_BUFFER *dbuf, const char *sText) +{ + int result=0; + char *text=NULL; + + if (tagList) { + result=AQH_Tag16_GetTagDataAsUint32(tagList, AQH_MSGDATA_RESULT_TAGS_RESULT, 0); + text=AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSGDATA_RESULT_TAGS_TEXT, NULL); + } + + GWEN_Buffer_AppendArgs(dbuf, + "RESULT(%s) %s (code=%d, proto=%d, proto version=%d, result=%d, text=\"%s\")\n", + AQH_IpcMessage_MsgTypeToChar(AQH_IpcMessage_GetCode(msg)), + sText?sText:"", + AQH_IpcMessage_GetCode(msg), + AQH_IpcMessage_GetProtoId(msg), + AQH_IpcMessage_GetProtoVersion(msg), + result, + text?text:""); + free(text); +} + + + + + diff --git a/aqhome/msg/ipc/m_ipc_result.h b/aqhome/msg/ipc/m_ipc_result.h new file mode 100644 index 0000000..0aab871 --- /dev/null +++ b/aqhome/msg/ipc/m_ipc_result.h @@ -0,0 +1,33 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_M_IPC_RESULT_H +#define AQH_M_IPC_RESULT_H + + + +#include +#include + +#include + + + +#define AQH_MSGDATA_RESULT_TAGS_RESULT 0x0001 +#define AQH_MSGDATA_RESULT_TAGS_TEXT 0x0002 + + + +AQHOME_API AQH_MESSAGE *AQH_IpcMessageResult_new(uint8_t protoId, uint8_t protoVer, uint16_t code, + uint32_t msgId, uint32_t refMsgId, + int result, const char *text); +AQHOME_API void AQH_IpcMessageResult_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, + GWEN_BUFFER *dbuf, const char *sText); + + +#endif diff --git a/aqhome/msg/ipc/m_ipc_tag16.c b/aqhome/msg/ipc/m_ipc_tag16.c new file mode 100644 index 0000000..b8f1010 --- /dev/null +++ b/aqhome/msg/ipc/m_ipc_tag16.c @@ -0,0 +1,582 @@ +/**************************************************************************** + * 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 "aqhome/msg/ipc/m_ipc_tag16.h" +#include "aqhome/msg/ipc/m_ipc.h" + +#include +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define AQH_IPCDATA_VALUE_TAGS_ID 0x01 +#define AQH_IPCDATA_VALUE_TAGS_DRIVER 0x02 +#define AQH_IPCDATA_VALUE_TAGS_NAMEFORDRIVER 0x03 +#define AQH_IPCDATA_VALUE_TAGS_NAMEFORSYSTEM 0x04 +#define AQH_IPCDATA_VALUE_TAGS_TYPE 0x05 +#define AQH_IPCDATA_VALUE_TAGS_UNITS 0x06 +#define AQH_IPCDATA_VALUE_TAGS_TIMEOFCREATION 0x07 +#define AQH_IPCDATA_VALUE_TAGS_DEVFORDRIVER 0x08 +#define AQH_IPCDATA_VALUE_TAGS_DEVFORSYSTEM 0x09 +#define AQH_IPCDATA_VALUE_TAGS_MODALITY 0x0a + +#define AQH_IPCDATA_DEVICE_TAGS_ID 0x01 +#define AQH_IPCDATA_DEVICE_TAGS_DRIVER 0x02 +#define AQH_IPCDATA_DEVICE_TAGS_ROOMNAME 0x03 +#define AQH_IPCDATA_DEVICE_TAGS_NAMEFORDRIVER 0x04 +#define AQH_IPCDATA_DEVICE_TAGS_NAMEFORSYSTEM 0x05 +#define AQH_IPCDATA_DEVICE_TAGS_NAMEFORGUI 0x06 +#define AQH_IPCDATA_DEVICE_TAGS_LOCATION 0x07 +#define AQH_IPCDATA_DEVICE_TAGS_DESCRIPTION 0x08 +#define AQH_IPCDATA_DEVICE_TAGS_DEVTYPE 0x09 +#define AQH_IPCDATA_DEVICE_TAGS_MANUFACTURER 0x0a +#define AQH_IPCDATA_DEVICE_TAGS_TIMEOFCREATION 0x0b + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _writeValueFieldsAsTagsToBuffer(const AQH_VALUE *value, GWEN_BUFFER *buf); +static AQH_VALUE *_readValueFromTag(const uint8_t *ptr, uint32_t len); +static void _writeDeviceFieldsAsTagsToBuffer(const AQH_DEVICE *device, GWEN_BUFFER *buf); +static AQH_DEVICE *_readDeviceFromTag(const uint8_t *ptr, uint32_t len); + + + +/* ------------------------------------------------------------------------------------------------ + * implementation + * ------------------------------------------------------------------------------------------------ + */ + + + +GWEN_TAG16_LIST *AQH_IpcMessageTag16_ParsePayload(const AQH_MESSAGE *msg, int doCopy) +{ + if (msg) { + const uint8_t *payloadPtr; + uint32_t payloadSize; + + payloadPtr=AQH_IpcMessage_GetPayloadPointer(msg); + payloadSize=AQH_IpcMessage_GetPayloadLength(msg); + return AQH_Tag16_ParseTags(payloadPtr, payloadSize, doCopy); + } + + return NULL; +} + + + +GWEN_TAG16_LIST *AQH_Tag16_ParseTags(const uint8_t *payloadPtr, uint32_t payloadSize, int doCopy) +{ + if (payloadPtr && payloadSize) { + GWEN_TAG16_LIST *tagList; + + tagList=GWEN_Tag16_List_fromBuffer(payloadPtr, payloadSize, doCopy); + if (tagList==NULL) { + DBG_INFO(AQH_LOGDOMAIN, "Error reading tags from message"); + return NULL; + } + return tagList; + } + + return NULL; +} + + + + +char *AQH_Tag16_GetTagDataAsNewString(const GWEN_TAG16_LIST *tagList, unsigned int tagType, const char *defaultValue) +{ + if (tagList) { + const GWEN_TAG16 *tag; + + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, tagType); + if (tag) + return GWEN_Tag16_GetTagDataAsNewString(tag, defaultValue); + } + return defaultValue?strdup(defaultValue):NULL; +} + + + +uint32_t AQH_Tag16_GetTagDataAsUint32(const GWEN_TAG16_LIST *tagList, unsigned int tagType, uint32_t defaultValue) +{ + if (tagList) { + const GWEN_TAG16 *tag; + + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, tagType); + return tag?GWEN_Tag16_GetTagDataAsUint32(tag, defaultValue):defaultValue; + } + return defaultValue; +} + + + +uint64_t AQH_Tag16_GetTagDataAsUint64(const GWEN_TAG16_LIST *tagList, unsigned int tagType, uint64_t defaultValue) +{ + if (tagList) { + const GWEN_TAG16 *tag; + + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, tagType); + return tag?GWEN_Tag16_GetTagDataAsUint64(tag, defaultValue):defaultValue; + } + return defaultValue; +} + + + +int AQH_Tag16_WriteValueListAsTagsToBuffer(unsigned int tagType, const AQH_VALUE_LIST *valueList, GWEN_BUFFER *buf) +{ + if (valueList) { + const AQH_VALUE *value; + + value=AQH_Value_List_First(valueList); + while(value) { + int rv; + + rv=AQH_Tag16_WriteValueAsTagToBuffer(tagType, value, buf); + if (rv<0) { + DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); + GWEN_Buffer_free(buf); + return rv; + } + + value=AQH_Value_List_Next(value); + } + } + return 0; +} + + + +int AQH_Tag16_WriteValueAsTagToBuffer(unsigned int tagType, const AQH_VALUE *value, GWEN_BUFFER *buf) +{ + int startPos; + int rv; + + startPos=GWEN_Tag16_StartTagInBuffer(tagType, buf); + if (startPos<0) { + DBG_INFO(AQH_LOGDOMAIN, "here (%d)", startPos); + return startPos; + } + + _writeValueFieldsAsTagsToBuffer(value, buf); + + rv=GWEN_Tag16_EndTagInBuffer(startPos, buf); + if (rv<0) { + DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); + return rv; + } + + return 0; +} + + + +int AQH_Tag16_WriteDeviceListAsTagsToBuffer(unsigned int tagType, const AQH_DEVICE_LIST *deviceList, GWEN_BUFFER *buf) +{ + if (deviceList) { + const AQH_DEVICE *device; + + device=AQH_Device_List_First(deviceList); + while(device) { + int rv; + + rv=AQH_Tag16_WriteDeviceAsTagToBuffer(tagType, device, buf); + if (rv<0) { + DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); + GWEN_Buffer_free(buf); + return rv; + } + + device=AQH_Device_List_Next(device); + } + } + return 0; +} + + + +int AQH_Tag16_WriteDeviceAsTagToBuffer(unsigned int tagType, const AQH_DEVICE *device, GWEN_BUFFER *buf) +{ + int startPos; + int rv; + + startPos=GWEN_Tag16_StartTagInBuffer(tagType, buf); + if (startPos<0) { + DBG_INFO(AQH_LOGDOMAIN, "here (%d)", startPos); + return startPos; + } + + _writeDeviceFieldsAsTagsToBuffer(device, buf); + + rv=GWEN_Tag16_EndTagInBuffer(startPos, buf); + if (rv<0) { + DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); + return rv; + } + + return 0; +} + + + +void _writeValueFieldsAsTagsToBuffer(const AQH_VALUE *value, GWEN_BUFFER *buf) +{ + const char *s; + + GWEN_Tag16_WriteUint64TagToBuffer(AQH_IPCDATA_VALUE_TAGS_ID, AQH_Value_GetId(value), buf); + + s=AQH_Value_GetDriver(value); + if (s && *s) + GWEN_Tag16_WriteStringTagToBuffer(AQH_IPCDATA_VALUE_TAGS_DRIVER, s, buf); + + s=AQH_Value_GetName(value); + if (s && *s) + GWEN_Tag16_WriteStringTagToBuffer(AQH_IPCDATA_VALUE_TAGS_NAMEFORDRIVER, s, buf); + + s=AQH_Value_GetNameForSystem(value); + if (s && *s) + GWEN_Tag16_WriteStringTagToBuffer(AQH_IPCDATA_VALUE_TAGS_NAMEFORSYSTEM, s, buf); + + GWEN_Tag16_WriteUint32TagToBuffer(AQH_IPCDATA_VALUE_TAGS_TYPE, AQH_Value_GetValueType(value), buf); + + s=AQH_Value_GetValueUnits(value); + if (s && *s) + GWEN_Tag16_WriteStringTagToBuffer(AQH_IPCDATA_VALUE_TAGS_UNITS, s, buf); + + GWEN_Tag16_WriteUint64TagToBuffer(AQH_IPCDATA_VALUE_TAGS_TIMEOFCREATION, AQH_Value_GetTimestampCreation(value), buf); + + s=AQH_Value_GetDeviceName(value); + if (s && *s) + GWEN_Tag16_WriteStringTagToBuffer(AQH_IPCDATA_VALUE_TAGS_DEVFORDRIVER, s, buf); + + s=AQH_Value_GetDeviceNameForSystem(value); + if (s && *s) + GWEN_Tag16_WriteStringTagToBuffer(AQH_IPCDATA_VALUE_TAGS_DEVFORSYSTEM, s, buf); + + GWEN_Tag16_WriteUint32TagToBuffer(AQH_IPCDATA_VALUE_TAGS_MODALITY, AQH_Value_GetModality(value), buf); + +} + + + + + + +AQH_VALUE_LIST *AQH_Tag16_ReadValuesFromTagList(const GWEN_TAG16_LIST *tagList, unsigned int wantedTagType) +{ + AQH_VALUE_LIST *valueList; + const GWEN_TAG16 *tag; + + valueList=AQH_Value_List_new(); + tag=GWEN_Tag16_List_First(tagList); + while(tag) { + unsigned int tagType; + AQH_VALUE *value; + + tagType=GWEN_Tag16_GetTagType(tag); + if (tagType==wantedTagType) { + value=_readValueFromTag((const uint8_t*) GWEN_Tag16_GetTagData(tag), (uint32_t) GWEN_Tag16_GetTagLength(tag)); + if (value) + AQH_Value_List_Add(value, valueList); + } + + tag=GWEN_Tag16_List_Next(tag); + } + + if (AQH_Value_List_GetCount(valueList)<1) { + AQH_Value_List_free(valueList); + return NULL; + } + + return valueList; +} + + + +AQH_VALUE *AQH_Tag16_ReadValueFromTagList(const GWEN_TAG16_LIST *tagList, unsigned int wantedTagType) +{ + if (tagList) { + const GWEN_TAG16 *tag; + + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, wantedTagType); + return tag?_readValueFromTag((const uint8_t*) GWEN_Tag16_GetTagData(tag), (uint32_t) GWEN_Tag16_GetTagLength(tag)):NULL; + } + return NULL; +} + + + +AQH_DEVICE_LIST *AQH_Tag16_ReadDevicesFromTagList(const GWEN_TAG16_LIST *tagList, unsigned int wantedTagType) +{ + AQH_DEVICE_LIST *deviceList; + const GWEN_TAG16 *tag; + + deviceList=AQH_Device_List_new(); + tag=GWEN_Tag16_List_First(tagList); + while(tag) { + unsigned int tagType; + AQH_DEVICE *device; + + tagType=GWEN_Tag16_GetTagType(tag); + if (tagType==wantedTagType) { + device=_readDeviceFromTag((const uint8_t*) GWEN_Tag16_GetTagData(tag), (uint32_t) GWEN_Tag16_GetTagLength(tag)); + if (device) + AQH_Device_List_Add(device, deviceList); + } + + tag=GWEN_Tag16_List_Next(tag); + } + + if (AQH_Device_List_GetCount(deviceList)<1) { + AQH_Device_List_free(deviceList); + return NULL; + } + + return deviceList; +} + + + +AQH_DEVICE *AQH_Tag16_ReadDeviceFromTagList(const GWEN_TAG16_LIST *tagList, unsigned int wantedTagType) +{ + if (tagList) { + const GWEN_TAG16 *tag; + + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, wantedTagType); + return tag?_readDeviceFromTag((const uint8_t*) GWEN_Tag16_GetTagData(tag), (uint32_t) GWEN_Tag16_GetTagLength(tag)):NULL; + } + return NULL; +} + + + +AQH_VALUE *_readValueFromTag(const uint8_t *ptr, uint32_t len) +{ + GWEN_TAG16_LIST *tagList; + + tagList=GWEN_Tag16_List_fromBuffer(ptr, len, 0); + if (tagList) { + GWEN_TAG16 *tag; + AQH_VALUE *value; + + value=AQH_Value_new(); + tag=GWEN_Tag16_List_First(tagList); + while(tag) { + unsigned int tagType; + char *s; + + tagType=GWEN_Tag16_GetTagType(tag); + switch(tagType) { + case AQH_IPCDATA_VALUE_TAGS_ID: + AQH_Value_SetId(value, GWEN_Tag16_GetTagDataAsUint64(tag, 0)); + break; + case AQH_IPCDATA_VALUE_TAGS_DRIVER: + s=GWEN_Tag16_GetTagDataAsNewString(tag, NULL); + AQH_Value_SetDriver(value, s); + free(s); + break; + case AQH_IPCDATA_VALUE_TAGS_NAMEFORDRIVER: + s=GWEN_Tag16_GetTagDataAsNewString(tag, NULL); + AQH_Value_SetName(value, s); + free(s); + break; + case AQH_IPCDATA_VALUE_TAGS_NAMEFORSYSTEM: + s=GWEN_Tag16_GetTagDataAsNewString(tag, NULL); + AQH_Value_SetNameForSystem(value, s); + free(s); + break; + case AQH_IPCDATA_VALUE_TAGS_TYPE: + AQH_Value_SetValueType(value, GWEN_Tag16_GetTagDataAsUint32(tag, 0)); + break; + case AQH_IPCDATA_VALUE_TAGS_UNITS: + s=GWEN_Tag16_GetTagDataAsNewString(tag, NULL); + AQH_Value_SetValueUnits(value, s); + free(s); + break; + case AQH_IPCDATA_VALUE_TAGS_TIMEOFCREATION: + AQH_Value_SetTimestampCreation(value, GWEN_Tag16_GetTagDataAsUint64(tag, 0)); + break; + case AQH_IPCDATA_VALUE_TAGS_DEVFORDRIVER: + s=GWEN_Tag16_GetTagDataAsNewString(tag, NULL); + AQH_Value_SetDeviceName(value, s); + free(s); + break; + case AQH_IPCDATA_VALUE_TAGS_DEVFORSYSTEM: + s=GWEN_Tag16_GetTagDataAsNewString(tag, NULL); + AQH_Value_SetDeviceNameForSystem(value, s); + free(s); + break; + case AQH_IPCDATA_VALUE_TAGS_MODALITY: + AQH_Value_SetModality(value, GWEN_Tag16_GetTagDataAsUint32(tag, 0)); + break; + default: + DBG_INFO(AQH_LOGDOMAIN, "Unhandled tag typ %d (%02x)", tagType, tagType); + break; + } + tag=GWEN_Tag16_List_Next(tag); + } + GWEN_Tag16_List_free(tagList); + return value; + } + + return NULL; +} + + + +void _writeDeviceFieldsAsTagsToBuffer(const AQH_DEVICE *device, GWEN_BUFFER *buf) +{ + const char *s; + + GWEN_Tag16_WriteUint64TagToBuffer(AQH_IPCDATA_DEVICE_TAGS_ID, AQH_Device_GetId(device), buf); + + s=AQH_Device_GetDriver(device); + if (s && *s) + GWEN_Tag16_WriteStringTagToBuffer(AQH_IPCDATA_DEVICE_TAGS_DRIVER, s, buf); + + s=AQH_Device_GetRoomName(device); + if (s && *s) + GWEN_Tag16_WriteStringTagToBuffer(AQH_IPCDATA_DEVICE_TAGS_ROOMNAME, s, buf); + + s=AQH_Device_GetName(device); + if (s && *s) + GWEN_Tag16_WriteStringTagToBuffer(AQH_IPCDATA_DEVICE_TAGS_NAMEFORDRIVER, s, buf); + + s=AQH_Device_GetNameForSystem(device); + if (s && *s) + GWEN_Tag16_WriteStringTagToBuffer(AQH_IPCDATA_DEVICE_TAGS_NAMEFORSYSTEM, s, buf); + + s=AQH_Device_GetNameForGui(device); + if (s && *s) + GWEN_Tag16_WriteStringTagToBuffer(AQH_IPCDATA_DEVICE_TAGS_NAMEFORGUI, s, buf); + + s=AQH_Device_GetLocation(device); + if (s && *s) + GWEN_Tag16_WriteStringTagToBuffer(AQH_IPCDATA_DEVICE_TAGS_LOCATION, s, buf); + + s=AQH_Device_GetDescription(device); + if (s && *s) + GWEN_Tag16_WriteStringTagToBuffer(AQH_IPCDATA_DEVICE_TAGS_DESCRIPTION, s, buf); + + s=AQH_Device_GetDeviceType(device); + if (s && *s) + GWEN_Tag16_WriteStringTagToBuffer(AQH_IPCDATA_DEVICE_TAGS_DEVTYPE, s, buf); + + s=AQH_Device_GetManufacturer(device); + if (s && *s) + GWEN_Tag16_WriteStringTagToBuffer(AQH_IPCDATA_DEVICE_TAGS_MANUFACTURER, s, buf); + + GWEN_Tag16_WriteUint64TagToBuffer(AQH_IPCDATA_DEVICE_TAGS_TIMEOFCREATION, AQH_Device_GetTimestampCreation(device), buf); +} + + + +AQH_DEVICE *_readDeviceFromTag(const uint8_t *ptr, uint32_t len) +{ + GWEN_TAG16_LIST *tagList; + + tagList=GWEN_Tag16_List_fromBuffer(ptr, len, 0); + if (tagList) { + GWEN_TAG16 *tag; + AQH_DEVICE *device; + + device=AQH_Device_new(); + tag=GWEN_Tag16_List_First(tagList); + while(tag) { + unsigned int tagType; + char *s; + + tagType=GWEN_Tag16_GetTagType(tag); + switch(tagType) { + case AQH_IPCDATA_DEVICE_TAGS_ID: + AQH_Device_SetId(device, GWEN_Tag16_GetTagDataAsUint64(tag, 0)); + break; + case AQH_IPCDATA_DEVICE_TAGS_DRIVER: + s=GWEN_Tag16_GetTagDataAsNewString(tag, NULL); + AQH_Device_SetDriver(device, s); + free(s); + break; + case AQH_IPCDATA_DEVICE_TAGS_ROOMNAME: + s=GWEN_Tag16_GetTagDataAsNewString(tag, NULL); + AQH_Device_SetRoomName(device, s); + free(s); + break; + case AQH_IPCDATA_DEVICE_TAGS_NAMEFORDRIVER: + s=GWEN_Tag16_GetTagDataAsNewString(tag, NULL); + AQH_Device_SetName(device, s); + free(s); + break; + case AQH_IPCDATA_DEVICE_TAGS_NAMEFORSYSTEM: + s=GWEN_Tag16_GetTagDataAsNewString(tag, NULL); + AQH_Device_SetNameForSystem(device, s); + free(s); + break; + case AQH_IPCDATA_DEVICE_TAGS_NAMEFORGUI: + s=GWEN_Tag16_GetTagDataAsNewString(tag, NULL); + AQH_Device_SetNameForGui(device, s); + free(s); + break; + case AQH_IPCDATA_DEVICE_TAGS_LOCATION: + s=GWEN_Tag16_GetTagDataAsNewString(tag, NULL); + AQH_Device_SetLocation(device, s); + free(s); + break; + case AQH_IPCDATA_DEVICE_TAGS_DESCRIPTION: + s=GWEN_Tag16_GetTagDataAsNewString(tag, NULL); + AQH_Device_SetDescription(device, s); + free(s); + break; + case AQH_IPCDATA_DEVICE_TAGS_DEVTYPE: + s=GWEN_Tag16_GetTagDataAsNewString(tag, NULL); + AQH_Device_SetDeviceType(device, s); + free(s); + break; + case AQH_IPCDATA_DEVICE_TAGS_MANUFACTURER: + s=GWEN_Tag16_GetTagDataAsNewString(tag, NULL); + AQH_Device_SetManufacturer(device, s); + free(s); + break; + case AQH_IPCDATA_DEVICE_TAGS_TIMEOFCREATION: + AQH_Device_SetTimestampCreation(device, GWEN_Tag16_GetTagDataAsUint64(tag, 0)); + break; + default: + DBG_INFO(AQH_LOGDOMAIN, "Unhandled tag typ %d (%02x)", tagType, tagType); + break; + } + tag=GWEN_Tag16_List_Next(tag); + } + GWEN_Tag16_List_free(tagList); + return device; + } + + return NULL; +} + + + + + + + diff --git a/aqhome/msg/ipc/m_ipc_tag16.h b/aqhome/msg/ipc/m_ipc_tag16.h new file mode 100644 index 0000000..7c74c50 --- /dev/null +++ b/aqhome/msg/ipc/m_ipc_tag16.h @@ -0,0 +1,43 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_M_IPC_TAG16_H +#define AQH_M_IPC_TAG16_H + + + +#include +#include +#include +#include + +#include + + + +AQHOME_API GWEN_TAG16_LIST *AQH_IpcMessageTag16_ParsePayload(const AQH_MESSAGE *msg, int doCopy); + +AQHOME_API GWEN_TAG16_LIST *AQH_Tag16_ParseTags(const uint8_t *payloadPtr, uint32_t payloadSize, int doCopy); +AQHOME_API char *AQH_Tag16_GetTagDataAsNewString(const GWEN_TAG16_LIST *tagList, unsigned int tagType, const char *defaultValue); +AQHOME_API uint32_t AQH_Tag16_GetTagDataAsUint32(const GWEN_TAG16_LIST *tagList, unsigned int tagType, uint32_t defaultValue); +AQHOME_API uint64_t AQH_Tag16_GetTagDataAsUint64(const GWEN_TAG16_LIST *tagList, unsigned int tagType, uint64_t defaultValue); + +/* utils */ +AQHOME_API int AQH_Tag16_WriteValueListAsTagsToBuffer(unsigned int tagType, const AQH_VALUE_LIST *valueList, GWEN_BUFFER *buf); +AQHOME_API int AQH_Tag16_WriteValueAsTagToBuffer(unsigned int tagType, const AQH_VALUE *value, GWEN_BUFFER *buf); +AQHOME_API AQH_VALUE_LIST *AQH_Tag16_ReadValuesFromTagList(const GWEN_TAG16_LIST *tagList, unsigned int wantedTagType); +AQHOME_API AQH_VALUE *AQH_Tag16_ReadValueFromTagList(const GWEN_TAG16_LIST *tagList, unsigned int wantedTagType); + +AQHOME_API int AQH_Tag16_WriteDeviceListAsTagsToBuffer(unsigned int tagType, const AQH_DEVICE_LIST *deviceList, GWEN_BUFFER *buf); +AQHOME_API int AQH_Tag16_WriteDeviceAsTagToBuffer(unsigned int tagType, const AQH_DEVICE *device, GWEN_BUFFER *buf); +AQHOME_API AQH_DEVICE_LIST *AQH_Tag16_ReadDevicesFromTagList(const GWEN_TAG16_LIST *tagList, unsigned int wantedTagType); +AQHOME_API AQH_DEVICE *AQH_Tag16_ReadDeviceFromTagList(const GWEN_TAG16_LIST *tagList, unsigned int wantedTagType); + + + +#endif diff --git a/aqhome/msg/node/0BUILD b/aqhome/msg/node/0BUILD new file mode 100644 index 0000000..26497d0 --- /dev/null +++ b/aqhome/msg/node/0BUILD @@ -0,0 +1,84 @@ + + + + + + + + $(gwenhywfar_cflags) + -I$(topsrcdir) + -I$(topbuilddir) + + + + --include=$(builddir) + --include=$(srcdir) + + + + + + $(visibility_cflags) + + + + --api=AQHOME_API + + + + + + + + + + + + + + + + + + $(local/built_headers_pub) + + + + + m_node.h + m_device.h + m_recvstats.h + m_sendstats.h + + + + + + + + + $(local/typefiles) + + m_node.c + m_device.c + m_recvstats.c + m_sendstats.c + + + + + + + + + + + + + + + + + + + diff --git a/aqhome/msg/node/m_device.c b/aqhome/msg/node/m_device.c new file mode 100644 index 0000000..5d46573 --- /dev/null +++ b/aqhome/msg/node/m_device.c @@ -0,0 +1,186 @@ +/**************************************************************************** + * 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 +#endif + + +#include "aqhome/msg/node/m_device.h" +#include "aqhome/msg/node/m_node.h" + +#include + +#include + + + +#define AQH_MSG_OFFS_DEVICE_UID 0 /* 4 bytes */ +#define AQH_MSG_OFFS_DEVICE_MANUF 4 /* 4 bytes */ +#define AQH_MSG_OFFS_DEVICE_DEVTYPE 8 /* 2 bytes */ +#define AQH_MSG_OFFS_DEVICE_DEVVERSION 10 /* 1 byte */ +#define AQH_MSG_OFFS_DEVICE_DEVREVISION 11 /* 1 byte */ +#define AQH_MSG_OFFS_DEVICE_FWVARIANT 12 /* 1 byte */ +#define AQH_MSG_OFFS_DEVICE_FWVMAJOR 13 /* 1 byte */ +#define AQH_MSG_OFFS_DEVICE_FWVMINOR 14 /* 1 byte */ +#define AQH_MSG_OFFS_DEVICE_FWVPATCH 15 /* 1 byte */ + + + +static void _addDeviceId(const AQH_MESSAGE *msg, GWEN_BUFFER *dbuf); +static int _isAllGraphic(uint32_t value, int len); +static void _printChars(uint32_t value, int len, GWEN_BUFFER *dbuf); + + + + +uint32_t AQH_DeviceMessage_GetUid(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint32At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_DEVICE_UID, 0); +} + + + +uint32_t AQH_DeviceMessage_GetManufacturer(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint32At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_DEVICE_MANUF, 0); +} + + + +uint16_t AQH_DeviceMessage_GetDeviceType(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint16At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_DEVICE_DEVTYPE, 0); +} + + + +uint8_t AQH_DeviceMessage_GetDeviceVersion(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint8At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_DEVICE_DEVVERSION, 0); +} + + + +uint8_t AQH_DeviceMessage_GetDeviceRevision(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint8At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_DEVICE_DEVREVISION, 0); +} + + + +uint8_t AQH_DeviceMessage_GetFirmwareVariant(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint8At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_DEVICE_FWVARIANT, 0); +} + + + +uint8_t AQH_DeviceMessage_GetFirmwareVersionMajor(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint8At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_DEVICE_FWVMAJOR, 0); +} + + + +uint8_t AQH_DeviceMessage_GetFirmwareVersionMinor(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint8At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_DEVICE_FWVMINOR, 0); +} + + + +uint8_t AQH_DeviceMessage_GetFirmwareVersionPatchlevel(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint8At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_DEVICE_FWVPATCH, 0); +} + + + +void AQH_DeviceMessage_DumpToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *dbuf, const char *sText) +{ + if (msg) { + GWEN_Buffer_AppendArgs(dbuf, + "0x%02x->0x%02x: DEVICE %s (uid=0x%08x, dev=%08x:%04x v%d.%d (", + AQH_NodeMessage_GetSourceAddress(msg), + AQH_NodeMessage_GetDestAddress(msg), + sText, + (unsigned int) AQH_DeviceMessage_GetUid(msg), + AQH_DeviceMessage_GetManufacturer(msg), + AQH_DeviceMessage_GetDeviceType(msg), + AQH_DeviceMessage_GetDeviceVersion(msg), + AQH_DeviceMessage_GetDeviceRevision(msg)); + _addDeviceId(msg, dbuf); + GWEN_Buffer_AppendArgs(dbuf, + "), fw=%d.%d.%d (%d))\n", + AQH_DeviceMessage_GetFirmwareVersionMajor(msg), + AQH_DeviceMessage_GetFirmwareVersionMinor(msg), + AQH_DeviceMessage_GetFirmwareVersionPatchlevel(msg), + AQH_DeviceMessage_GetFirmwareVariant(msg)); + } +} + + + +void _addDeviceId(const AQH_MESSAGE *msg, GWEN_BUFFER *dbuf) +{ + uint32_t v; + + v=AQH_DeviceMessage_GetManufacturer(msg); + if (_isAllGraphic(v, 4)) + _printChars(v, 4, dbuf); + else + GWEN_Buffer_AppendArgs(dbuf, "%08x", v); + + GWEN_Buffer_AppendByte(dbuf, ' '); + + v=AQH_DeviceMessage_GetDeviceType(msg); + if (_isAllGraphic(v, 2)) { + _printChars(v, 2, dbuf); + GWEN_Buffer_AppendArgs(dbuf, "%d", AQH_DeviceMessage_GetDeviceVersion(msg)); + } + else { + GWEN_Buffer_AppendArgs(dbuf, "%04x", v); + GWEN_Buffer_AppendArgs(dbuf, " v%d", AQH_DeviceMessage_GetDeviceVersion(msg)); + } +} + + + +int _isAllGraphic(uint32_t value, int len) +{ + int i; + + for (i=0; i>8; + } + return 1; +} + + + +void _printChars(uint32_t value, int len, GWEN_BUFFER *dbuf) +{ + int i; + + for (i=0; i>8; + } +} + + diff --git a/aqhome/msg/node/m_device.h b/aqhome/msg/node/m_device.h new file mode 100644 index 0000000..e066846 --- /dev/null +++ b/aqhome/msg/node/m_device.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_M_DEVICE_H +#define AQH_M_DEVICE_H + + +#include +#include + +#include + + + + +AQHOME_API uint32_t AQH_DeviceMessage_GetUid(const AQH_MESSAGE *msg); +AQHOME_API uint32_t AQH_DeviceMessage_GetManufacturer(const AQH_MESSAGE *msg); +AQHOME_API uint16_t AQH_DeviceMessage_GetDeviceType(const AQH_MESSAGE *msg); +AQHOME_API uint8_t AQH_DeviceMessage_GetDeviceVersion(const AQH_MESSAGE *msg); +AQHOME_API uint8_t AQH_DeviceMessage_GetDeviceRevision(const AQH_MESSAGE *msg); +AQHOME_API uint8_t AQH_DeviceMessage_GetFirmwareVariant(const AQH_MESSAGE *msg); +AQHOME_API uint8_t AQH_DeviceMessage_GetFirmwareVersionMajor(const AQH_MESSAGE *msg); +AQHOME_API uint8_t AQH_DeviceMessage_GetFirmwareVersionMinor(const AQH_MESSAGE *msg); +AQHOME_API uint8_t AQH_DeviceMessage_GetFirmwareVersionPatchlevel(const AQH_MESSAGE *msg); + +AQHOME_API void AQH_DeviceMessage_DumpToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *dbuf, const char *sText); + + + + + + + + + + +#endif diff --git a/aqhome/msg/node/m_node.c b/aqhome/msg/node/m_node.c new file mode 100644 index 0000000..a0b0e6c --- /dev/null +++ b/aqhome/msg/node/m_node.c @@ -0,0 +1,262 @@ +/**************************************************************************** + * 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 "aqhome/msg/node/m_node.h" + +#include + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static uint8_t _calcCrc8Checksum(const uint8_t *ptr, uint8_t len); + + + +/* ------------------------------------------------------------------------------------------------ + * implementation + * ------------------------------------------------------------------------------------------------ + */ + +AQH_MESSAGE *AQH_NodeMessage_new(uint8_t destAddr, uint8_t srcAddr, uint8_t code, uint8_t payloadLen, const uint8_t *payload) +{ + AQH_MESSAGE *msg; + uint8_t *ptr; + uint32_t len; + + len=AQH_MSG_OFFS_ALL_DATA_BEGIN+payloadLen+1; /* dest, len, code, src, payload, crc8 */ + msg=AQH_Message_new(); + AQH_Message_SetData(msg, NULL, len); /* auto-malloc len bytes */ + + ptr=AQH_Message_GetMsgPointer(msg); + ptr[AQH_MSG_OFFS_ALL_DEST_ADDRESS]=destAddr & 0xff; + ptr[AQH_MSG_OFFS_ALL_PAYLOAD_LEN]=payloadLen+2; /* code, src, payload */ + ptr[AQH_MSG_OFFS_ALL_MSG_TYPE]=code; + ptr[AQH_MSG_OFFS_ALL_SRC_ADDRESS]=srcAddr; + + if (payloadLen && payload) + memmove(ptr+AQH_MSG_OFFS_ALL_DATA_BEGIN, payload, payloadLen); + AQH_Message_SetUsedSize(msg, len); + AQH_NodeMessage_AddChecksum(msg); + + return msg; +} + + + +AQH_MESSAGE *AQH_NodeMessage_fromBuffer(const uint8_t *ptr, uint32_t len) +{ + if (ptr && len) { + AQH_MESSAGE *msg; + + msg=AQH_Message_new(); + AQH_Message_SetData(msg, ptr, len); + AQH_Message_SetUsedSize(msg, len); + return msg; + } + return NULL; +} + + + +uint8_t AQH_NodeMessage_GetDestAddress(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint8At(msg, AQH_MSG_OFFS_ALL_DEST_ADDRESS, 0); +} + + + +uint8_t AQH_NodeMessage_GetMsgType(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint8At(msg, AQH_MSG_OFFS_ALL_MSG_TYPE, 0); +} + + + +uint8_t AQH_NodeMessage_GetSourceAddress(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint8At(msg, AQH_MSG_OFFS_ALL_SRC_ADDRESS, 0); +} + + + +uint8_t AQH_NodeMessage_GetPayloadLength(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint8At(msg, AQH_MSG_OFFS_ALL_PAYLOAD_LEN, 2)-2; /* minus src addr, command */ +} + + + +uint8_t *AQH_NodeMessage_GetPayloadPointer(const AQH_MESSAGE *msg) +{ + return msg?(AQH_Message_GetMsgPointer(msg)+AQH_MSG_OFFS_ALL_DATA_BEGIN):NULL; +} + + + +void AQH_NodeMessage_AddChecksum(AQH_MESSAGE *msg) +{ + if (msg) { + uint8_t *ptr; + uint32_t msgLenWithoutChecksum; + uint8_t checksum; + + ptr=AQH_Message_GetMsgPointer(msg); + msgLenWithoutChecksum=AQH_Message_GetUsedSize(msg); + checksum=_calcCrc8Checksum(ptr, msgLenWithoutChecksum); + AQH_Message_WriteUint8At(msg, msgLenWithoutChecksum, checksum); + AQH_Message_IncUsedSize(msg, 1); + } +} + + + +int AQH_NodeMessage_IsValid(AQH_MESSAGE *msg) +{ + if (msg) { + uint8_t *ptr; + uint32_t len; + uint8_t checksum; + + ptr=AQH_Message_GetMsgPointer(msg); + len=AQH_Message_GetUsedSize(msg); + checksum=_calcCrc8Checksum(ptr, len); + return (checksum==0)?1:0; + } + return 0; +} + + + +void AQH_NodeMessage_DumpToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *dbuf, const char *sText) +{ + if (msg) { + GWEN_Buffer_AppendArgs(dbuf, + "0x%02x->0x%02x: %s %d (\"%s\")\n", + AQH_NodeMessage_GetSourceAddress(msg), + AQH_NodeMessage_GetDestAddress(msg), + sText, + AQH_NodeMessage_GetMsgType(msg), + AQH_NodeMessage_MsgTypeToChar(AQH_NodeMessage_GetMsgType(msg))); + GWEN_Text_DumpString2Buffer((const char*)AQH_Message_GetMsgPointer(msg), AQH_Message_GetUsedSize(msg), dbuf, 34); + } +} + + + +const char *AQH_NodeMessage_MsgTypeToChar(uint8_t i) +{ + switch(i) { + case AQH_MSG_TYPE_PING: return "Ping"; + case AQH_MSG_TYPE_PONG: return "Pong"; + case AQH_MSG_TYPE_COMSENDSTATS: return "SendStats"; + case AQH_MSG_TYPE_COMRECVSTATS: return "RecvStats"; + case AQH_MSG_TYPE_TWIBUSMEMBER: return "TwiBusMember"; + case AQH_MSG_TYPE_DEBUG: return "Debug"; + case AQH_MSG_TYPE_VALUE: return "Value"; + case AQH_MSG_TYPE_VALUE2: return "Value2"; + case AQH_MSG_TYPE_NEED_ADDRESS: return "NeedAddress"; + case AQH_MSG_TYPE_HAVE_ADDRESS: return "HaveAddress"; + case AQH_MSG_TYPE_CLAIM_ADDRESS: return "ClaimAddress"; + case AQH_MSG_TYPE_DENY_ADDRESS: return "DenyAddress"; + case AQH_MSG_TYPE_ADDRESS_RANGE: return "Range"; + + case AQH_MSG_TYPE_FLASH_START: return "FlashStart"; + case AQH_MSG_TYPE_FLASH_END: return "FlashEnd"; + case AQH_MSG_TYPE_FLASH_READY: return "FlashReady"; + case AQH_MSG_TYPE_FLASH_DATA: return "FlashData"; + case AQH_MSG_TYPE_FLASH_RSP: return "FlashResponse"; + + case AQH_MSG_TYPE_DEVICE: return "Device"; + case AQH_MSG_TYPE_MEMSTATS: return "MemStats"; + case AQH_MSG_TYPE_SYSSTATS: return "SysStats"; + case AQH_MSG_TYPE_REBOOT_REQ: return "RebootRequest"; + case AQH_MSG_TYPE_REBOOT_RSP: return "RebootResponse"; + default: return "(unknown)"; + } +} + + + +uint32_t AQH_NodeMessage_GetMsgGroup(uint8_t msgType) +{ + switch(msgType) { + case AQH_MSG_TYPE_PING: + case AQH_MSG_TYPE_PONG: + case AQH_MSG_TYPE_COMSENDSTATS: + case AQH_MSG_TYPE_COMRECVSTATS: + case AQH_MSG_TYPE_TWIBUSMEMBER: + case AQH_MSG_TYPE_DEBUG: + case AQH_MSG_TYPE_DEVICE: + case AQH_MSG_TYPE_MEMSTATS: + case AQH_MSG_TYPE_SYSSTATS: + return AQH_MSG_TYPEGROUP_INFO; + + case AQH_MSG_TYPE_VALUE: + case AQH_MSG_TYPE_VALUE2: + case AQH_MSG_TYPE_VALUE_REPORT: + case AQH_MSG_TYPE_VALUE_SET: + case AQH_MSG_TYPE_VALUE_SET_ACK: + case AQH_MSG_TYPE_VALUE_SET_NACK: + return AQH_MSG_TYPEGROUP_VALUES; + + case AQH_MSG_TYPE_NEED_ADDRESS: + case AQH_MSG_TYPE_HAVE_ADDRESS: + case AQH_MSG_TYPE_CLAIM_ADDRESS: + case AQH_MSG_TYPE_DENY_ADDRESS: + case AQH_MSG_TYPE_ADDRESS_RANGE: + return AQH_MSG_TYPEGROUP_ADDRESS; + + case AQH_MSG_TYPE_NET_SET_ACCEPTED_MSGGROUPS: + return AQH_MSG_TYPEGROUP_ADMIN; + + case AQH_MSG_TYPE_FLASH_START: + case AQH_MSG_TYPE_FLASH_END: + case AQH_MSG_TYPE_FLASH_READY: + case AQH_MSG_TYPE_FLASH_DATA: + case AQH_MSG_TYPE_FLASH_RSP: + case AQH_MSG_TYPE_REBOOT_REQ: + case AQH_MSG_TYPE_REBOOT_RSP: + return AQH_MSG_TYPEGROUP_FLASH; + + default: + return 0; + } +} + + + +uint8_t _calcCrc8Checksum(const uint8_t *ptr, uint8_t len) +{ + int i; + uint8_t x=0xff; + + for (i=0; i +#include + +#include + + +#define AQH_MAXMSGSIZE 128 + + +#define AQH_MSG_OFFS_ALL_DEST_ADDRESS 0 +#define AQH_MSG_OFFS_ALL_PAYLOAD_LEN 1 +#define AQH_MSG_OFFS_ALL_PAYLOAD_BEGIN 2 +#define AQH_MSG_OFFS_ALL_MSG_TYPE 2 +#define AQH_MSG_OFFS_ALL_SRC_ADDRESS 3 +#define AQH_MSG_OFFS_ALL_DATA_BEGIN 4 + + +#define AQH_MSG_TYPE_PING 10 +#define AQH_MSG_TYPE_PONG 11 +#define AQH_MSG_TYPE_COMSENDSTATS 20 +#define AQH_MSG_TYPE_COMRECVSTATS 21 +#define AQH_MSG_TYPE_TWIBUSMEMBER 30 +#define AQH_MSG_TYPE_DEBUG 40 +#define AQH_MSG_TYPE_VALUE 50 /* deprecated */ +#define AQH_MSG_TYPE_VALUE2 51 /* deprecated */ +#define AQH_MSG_TYPE_NEED_ADDRESS 60 +#define AQH_MSG_TYPE_HAVE_ADDRESS 61 +#define AQH_MSG_TYPE_CLAIM_ADDRESS 62 +#define AQH_MSG_TYPE_DENY_ADDRESS 63 +#define AQH_MSG_TYPE_ADDRESS_RANGE 64 + +#define AQH_MSG_TYPE_FLASH_START 70 +#define AQH_MSG_TYPE_FLASH_END 71 +#define AQH_MSG_TYPE_FLASH_READY 72 +#define AQH_MSG_TYPE_FLASH_DATA 73 +#define AQH_MSG_TYPE_FLASH_RSP 74 + +#define AQH_MSG_TYPE_DEVICE 80 +#define AQH_MSG_TYPE_MEMSTATS 81 +#define AQH_MSG_TYPE_SYSSTATS 82 + +#define AQH_MSG_TYPE_REBOOT_REQ 90 +#define AQH_MSG_TYPE_REBOOT_RSP 91 + +#define AQH_MSG_TYPE_VALUE_REPORT 100 +#define AQH_MSG_TYPE_VALUE_SET 101 +#define AQH_MSG_TYPE_VALUE_SET_ACK 102 +#define AQH_MSG_TYPE_VALUE_SET_NACK 103 + + +/* internal msg types via NET interface */ +#define AQH_MSG_TYPE_NET_SET_ACCEPTED_MSGGROUPS 200 + + +#define AQH_MSG_TYPEGROUP_INFO 0x00000001 +#define AQH_MSG_TYPEGROUP_VALUES 0x00000002 +#define AQH_MSG_TYPEGROUP_ADDRESS 0x00000004 +#define AQH_MSG_TYPEGROUP_FLASH 0x00000008 +#define AQH_MSG_TYPEGROUP_ADMIN 0x00000010 +#define AQH_MSG_TYPEGROUP_ALL 0xffffffff + + +#if 0 +#define AQH_MSG_MODULES_MASK_TIMER 0x02 +#define AQH_MSG_MODULES_MASK_COM 0x04 +#define AQH_MSG_MODULES_MASK_LED 0x08 +#define AQH_MSG_MODULES_MASK_TWIMASTER 0x10 +#define AQH_MSG_MODULES_MASK_LCD 0x20 +#define AQH_MSG_MODULES_MASK_SI7021 0x40 +#define AQH_MSG_MODULES_MASK_STATS 0x80 +#endif + + +AQHOME_API AQH_MESSAGE *AQH_NodeMessage_new(uint8_t destAddr, uint8_t srcAddr, uint8_t code, uint8_t payloadLen, const uint8_t *payload); +AQH_MESSAGE *AQH_NodeMessage_fromBuffer(const uint8_t *ptr, uint32_t len); + +AQHOME_API uint8_t AQH_NodeMessage_GetDestAddress(const AQH_MESSAGE *msg); +AQHOME_API uint8_t AQH_NodeMessage_GetMsgType(const AQH_MESSAGE *msg); +AQHOME_API uint8_t AQH_NodeMessage_GetSourceAddress(const AQH_MESSAGE *msg); + +/** + * Return size of payload (i.e. length of data after AQH_MSG_OFFS_ALL_DATA_BEGIN). + */ +AQHOME_API uint8_t AQH_NodeMessage_GetPayloadLength(const AQH_MESSAGE *msg); + +/** + * Return pointer to payload (i.e. data after AQH_MSG_OFFS_ALL_DATA_BEGIN). + */ +AQHOME_API uint8_t *AQH_NodeMessage_GetPayloadPointer(const AQH_MESSAGE *msg); + +/** + * Append checksum (uses @ref AQH_Message_GetUsedSize). + */ +AQHOME_API void AQH_NodeMessage_AddChecksum(AQH_MESSAGE *msg); + +/** + * Verify checksum. + */ +AQHOME_API int AQH_NodeMessage_IsValid(AQH_MESSAGE *msg); + + +AQHOME_API const char *AQH_NodeMessage_MsgTypeToChar(uint8_t i); +AQHOME_API uint32_t AQH_NodeMessage_GetMsgGroup(uint8_t msgType); + + +AQHOME_API void AQH_NodeMessage_DumpToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *dbuf, const char *sText); + + +#endif diff --git a/aqhome/msg/node/m_recvstats.c b/aqhome/msg/node/m_recvstats.c new file mode 100644 index 0000000..bd0a02e --- /dev/null +++ b/aqhome/msg/node/m_recvstats.c @@ -0,0 +1,97 @@ +/**************************************************************************** + * 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 +#endif + + + +#include "aqhome/msg/node/m_recvstats.h" +#include "aqhome/msg/node/m_node.h" + +#include + + +#define AQH_MSG_OFFS_RECVSTATS_UID 0 /* 4 bytes */ +#define AQH_MSG_OFFS_RECVSTATS_PACKETSIN 4 /* 2 bytes */ +#define AQH_MSG_OFFS_RECVSTATS_CRCERRORS 6 /* 2 bytes */ +#define AQH_MSG_OFFS_RECVSTATS_IOERRORS 8 /* 2 bytes */ +#define AQH_MSG_OFFS_RECVSTATS_NOBUFFER 10 /* 2 bytes */ +#define AQH_MSG_OFFS_RECVSTATS_HANDLED 12 /* 2 bytes */ +#define AQH_MSG_OFFS_RECVSTATS_MISSED 14 /* 2 bytes */ + + + +uint32_t AQH_RecvStatsMessage_GetUid(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint32At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_RECVSTATS_UID, 0); +} + + + +uint16_t AQH_RecvStatsMessage_GetPacketsIn(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint16At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_RECVSTATS_PACKETSIN, 0); +} + + + +uint16_t AQH_RecvStatsMessage_GetCrcErrors(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint16At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_RECVSTATS_CRCERRORS, 0); +} + + + +uint16_t AQH_RecvStatsMessage_GetIoErrors(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint16At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_RECVSTATS_IOERRORS, 0); +} + + + +uint16_t AQH_RecvStatsMessage_GetNoBufferErrors(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint16At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_RECVSTATS_NOBUFFER, 0); +} + + + +uint16_t AQH_RecvStatsMessage_GetHandled(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint16At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_RECVSTATS_HANDLED, 0); +} + + + +uint16_t AQH_RecvStatsMessage_GetMissed(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint16At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_RECVSTATS_MISSED, 0); +} + + + +void AQH_RecvStatsMessage_DumpToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *dbuf, const char *sText) +{ + GWEN_Buffer_AppendArgs(dbuf, + "0x%02x->0x%02x: RECVSTATS %s " + "(uid=0x%08x, in=%d, crc errs=%d, io errs=%d, nobuf errs=%d, handled=%d, missed=%d)\n", + AQH_NodeMessage_GetSourceAddress(msg), + AQH_NodeMessage_GetDestAddress(msg), + sText, + (unsigned int) AQH_RecvStatsMessage_GetUid(msg), + AQH_RecvStatsMessage_GetPacketsIn(msg), + AQH_RecvStatsMessage_GetCrcErrors(msg), + AQH_RecvStatsMessage_GetIoErrors(msg), + AQH_RecvStatsMessage_GetNoBufferErrors(msg), + AQH_RecvStatsMessage_GetHandled(msg), + AQH_RecvStatsMessage_GetMissed(msg)); +} + + diff --git a/aqhome/msg/node/m_recvstats.h b/aqhome/msg/node/m_recvstats.h new file mode 100644 index 0000000..d83d04a --- /dev/null +++ b/aqhome/msg/node/m_recvstats.h @@ -0,0 +1,32 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_M_RECVSTATS_H +#define AQH_M_RECVSTATS_H + + +#include +#include + +#include + + + +AQHOME_API uint32_t AQH_RecvStatsMessage_GetUid(const AQH_MESSAGE *msg); +AQHOME_API uint16_t AQH_RecvStatsMessage_GetPacketsIn(const AQH_MESSAGE *msg); +AQHOME_API uint16_t AQH_RecvStatsMessage_GetCrcErrors(const AQH_MESSAGE *msg); +AQHOME_API uint16_t AQH_RecvStatsMessage_GetIoErrors(const AQH_MESSAGE *msg); +AQHOME_API uint16_t AQH_RecvStatsMessage_GetNoBufferErrors(const AQH_MESSAGE *msg); +AQHOME_API uint16_t AQH_RecvStatsMessage_GetHandled(const AQH_MESSAGE *msg); +AQHOME_API uint16_t AQH_RecvStatsMessage_GetMissed(const AQH_MESSAGE *msg); + +AQHOME_API void AQH_RecvStatsMessage_DumpToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *dbuf, const char *sText); + + + +#endif diff --git a/aqhome/msg/node/m_sendstats.c b/aqhome/msg/node/m_sendstats.c new file mode 100644 index 0000000..adb436f --- /dev/null +++ b/aqhome/msg/node/m_sendstats.c @@ -0,0 +1,70 @@ +/**************************************************************************** + * 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 +#endif + + + +#include "aqhome/msg/node/m_sendstats.h" +#include "aqhome/msg/node/m_node.h" + +#include + + +#define AQH_MSG_OFFS_SENDSTATS_UID 0 /* 4 bytes */ +#define AQH_MSG_OFFS_SENDSTATS_PACKETSOUT 4 /* 2 bytes */ +#define AQH_MSG_OFFS_SENDSTATS_COLLISIONS 6 /* 2 bytes */ +#define AQH_MSG_OFFS_SENDSTATS_BUSY 8 /* 2 bytes */ + + + +uint32_t AQH_SendStatsMessage_GetUid(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint32At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_SENDSTATS_UID, 0); +} + + + +uint16_t AQH_SendStatsMessage_GetPacketsOut(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint16At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_SENDSTATS_PACKETSOUT, 0); +} + + + +uint16_t AQH_SendStatsMessage_GetCollisions(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint16At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_SENDSTATS_COLLISIONS, 0); +} + + + +uint16_t AQH_SendStatsMessage_GetBusyErrors(const AQH_MESSAGE *msg) +{ + return AQH_Message_ReadUint16At(msg, AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_SENDSTATS_BUSY, 0); +} + + + +void AQH_SendStatsMessage_DumpToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *dbuf, const char *sText) +{ + if (msg) + GWEN_Buffer_AppendArgs(dbuf, + "0x%02x->0x%02x: SENDSTATS %s (uid=0x%08x, out=%d, collisions=%d, busy line=%d)\n", + AQH_NodeMessage_GetSourceAddress(msg), + AQH_NodeMessage_GetDestAddress(msg), + sText, + (unsigned int) AQH_SendStatsMessage_GetUid(msg), + AQH_SendStatsMessage_GetPacketsOut(msg), + AQH_SendStatsMessage_GetCollisions(msg), + AQH_SendStatsMessage_GetBusyErrors(msg)); +} + + diff --git a/aqhome/msg/node/m_sendstats.h b/aqhome/msg/node/m_sendstats.h new file mode 100644 index 0000000..a90e00d --- /dev/null +++ b/aqhome/msg/node/m_sendstats.h @@ -0,0 +1,34 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQH_M_SENDSTATS_H +#define AQH_M_SENDSTATS_H + + +#include +#include + +#include + + + +AQHOME_API uint32_t AQH_SendStatsMessage_GetUid(const AQH_MESSAGE *msg); +AQHOME_API uint16_t AQH_SendStatsMessage_GetPacketsOut(const AQH_MESSAGE *msg); +AQHOME_API uint16_t AQH_SendStatsMessage_GetCollisions(const AQH_MESSAGE *msg); +AQHOME_API uint16_t AQH_SendStatsMessage_GetBusyErrors(const AQH_MESSAGE *msg); + +AQHOME_API void AQH_SendStatsMessage_DumpToBuffer(const AQH_MESSAGE *msg, GWEN_BUFFER *dbuf, const char *sText); + + + + + + + + +#endif