From 4c942d2584c27b4af3be9f7f3f091eac4348eba3 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Mon, 20 Feb 2023 23:45:10 +0100 Subject: [PATCH] More work on node/pc interface. - added AQH_MSG_ENDPOINT - added AQH_MsgEndpointLog - added AQH_MsgEndpointTcp - added AQH_MsgEndpointTty - added AQH_MsgEndpointMgr --- aqhome/0BUILD | 16 + aqhome/libtest.c | 62 +++- aqhome/msg.c | 26 ++ aqhome/msg.h | 7 + aqhome/msg_setaccmsggrps.c | 73 +++++ aqhome/msg_setaccmsggrps.h | 37 +++ aqhome/msgendpoint.c | 555 ++++++++++++++++++++++++++++++++++ aqhome/msgendpoint.h | 125 ++++++++ aqhome/msgendpoint_p.h | 51 ++++ aqhome/msgendpointlog.c | 155 ++++++++++ aqhome/msgendpointlog.h | 27 ++ aqhome/msgendpointlog_p.h | 25 ++ aqhome/msgendpointmanager.c | 307 +++++++++++++++++++ aqhome/msgendpointmanager.h | 41 +++ aqhome/msgendpointmanager_p.h | 27 ++ aqhome/msgendpointtcp.c | 222 ++++++++++++++ aqhome/msgendpointtcp.h | 27 ++ aqhome/msgendpointtty.c | 270 +++++++++++++++++ aqhome/msgendpointtty.h | 27 ++ aqhome/msgendpointtty_p.h | 30 ++ 20 files changed, 2104 insertions(+), 6 deletions(-) create mode 100644 aqhome/msg_setaccmsggrps.c create mode 100644 aqhome/msg_setaccmsggrps.h create mode 100644 aqhome/msgendpoint.c create mode 100644 aqhome/msgendpoint.h create mode 100644 aqhome/msgendpoint_p.h create mode 100644 aqhome/msgendpointlog.c create mode 100644 aqhome/msgendpointlog.h create mode 100644 aqhome/msgendpointlog_p.h create mode 100644 aqhome/msgendpointmanager.c create mode 100644 aqhome/msgendpointmanager.h create mode 100644 aqhome/msgendpointmanager_p.h create mode 100644 aqhome/msgendpointtcp.c create mode 100644 aqhome/msgendpointtcp.h create mode 100644 aqhome/msgendpointtty.c create mode 100644 aqhome/msgendpointtty.h create mode 100644 aqhome/msgendpointtty_p.h diff --git a/aqhome/0BUILD b/aqhome/0BUILD index 9477712..0a29de1 100644 --- a/aqhome/0BUILD +++ b/aqhome/0BUILD @@ -57,6 +57,16 @@ msg_haveaddr.h msg_claimaddr.h msg_denyaddr.h + msg_setaccmsggrps.h + msgendpoint.h + msgendpoint_p.h + msgendpointtcp.h + msgendpointtty.h + msgendpointtty_p.h + msgendpointlog.h + msgendpointlog_p.h + msgendpointmanager.h + msgendpointmanager_p.h @@ -72,6 +82,12 @@ msg_haveaddr.c msg_claimaddr.c msg_denyaddr.c + msg_setaccmsggrps.c + msgendpoint.c + msgendpointtcp.c + msgendpointtty.c + msgendpointlog.c + msgendpointmanager.c diff --git a/aqhome/libtest.c b/aqhome/libtest.c index 12e448c..ff848cf 100644 --- a/aqhome/libtest.c +++ b/aqhome/libtest.c @@ -32,7 +32,7 @@ int testRecv() fprintf(stdout, "Opening device...\n"); sr=AQH_Serial_new("/dev/ttyUSB0", 240); - rv=AQH_Serial_Open(sr); + rv=AQH_Serial_Open(sr, AQH_SerialReadWriteMode_ReadOnly); if (rv<0) { DBG_ERROR(NULL, "ERROR opening device (%d)", rv); AQH_Serial_free(sr); @@ -77,7 +77,7 @@ int testSend() fprintf(stdout, "Opening device...\n"); sr=AQH_Serial_new("/dev/ttyUSB0", 240); - rv=AQH_Serial_Open(sr); + rv=AQH_Serial_Open(sr, AQH_SerialReadWriteMode_ReadWrite); if (rv<0) { DBG_ERROR(NULL, "ERROR opening device (%d)", rv); AQH_Serial_free(sr); @@ -268,7 +268,7 @@ int testLoop() fprintf(stdout, "Opening device...\n"); sr=AQH_Serial_new("/dev/ttyUSB0", 240); - rv=AQH_Serial_Open(sr); + rv=AQH_Serial_Open(sr, AQH_SerialReadWriteMode_ReadWrite); if (rv<0) { DBG_ERROR(NULL, "ERROR opening device (%d)", rv); AQH_Serial_free(sr); @@ -335,10 +335,60 @@ int testLoop() - - -int main(void) +int testReadLoop() { + AQH_SERIAL *sr; + int rv; + int i; + GWEN_BUFFER *dbuf; + time_t tLast; + + fprintf(stdout, "Opening device...\n"); + sr=AQH_Serial_new("/dev/ttyUSB0", 240); + rv=AQH_Serial_Open(sr, AQH_SerialReadWriteMode_ReadOnly); + if (rv<0) { + DBG_ERROR(NULL, "ERROR opening device (%d)", rv); + AQH_Serial_free(sr); + return 2; + } + fprintf(stdout, "Device open, waiting for packets\n"); + AQH_Serial_SetPacketReceivedFn(sr, _packetReceived); + + tLast=time(NULL); + for (;;) { + time_t t; + + rv=AQH_Serial_ReadOnlyLoop(sr); + if (rv<0) { + AQH_Serial_Close(sr); + AQH_Serial_free(sr); + break; + } + t=time(NULL); + } + + return 0; +} + + + + + +int main(int argc, char **argv) +{ + const char *cmd; + + if (argc<2) + return testLoop(); + + cmd=argv[1]; + if (strcasecmp(cmd, "monitor")==0 || strcasecmp(cmd, "mon")==0) + return testReadLoop(); + else if (strcasecmp(cmd, "pingtest")==0) { + } + else if (strcasecmp(cmd, "rwtest")==0) { + return testLoop(); + } //return testRecv(); //return testSend(); return testLoop(); diff --git a/aqhome/msg.c b/aqhome/msg.c index d4c01cb..98a085f 100644 --- a/aqhome/msg.c +++ b/aqhome/msg.c @@ -51,6 +51,20 @@ void AQH_Msg_free(AQH_MSG *msg) +AQH_MSG *AQH_Msg_dup(const AQH_MSG *srcMsg) +{ + AQH_MSG *msg; + + msg=AQH_Msg_new(); + memmove(msg->buffer, srcMsg->buffer, AQH_MAXMSGSIZE); + msg->bytesInBuffer=srcMsg->bytesInBuffer; + msg->currentPos=srcMsg->currentPos; + + return msg; +} + + + uint8_t *AQH_Msg_GetBuffer(AQH_MSG *msg) { if (msg) @@ -230,6 +244,18 @@ int AQH_Msg_AddChecksum(AQH_MSG *msg) +void AQH_Msg_DumpToBuffer(const AQH_MSG *msg, GWEN_BUFFER *dbuf, const char *sText) +{ + GWEN_Buffer_AppendArgs(dbuf, + "0x%02x->0x%02x: %d %s\n", + AQH_Msg_GetSourceAddress(msg), + AQH_Msg_GetDestAddress(msg), + AQH_Msg_GetMsgType(msg), + sText); +} + + + uint8_t _calcChecksum(const uint8_t *ptr, uint8_t len) { int i; diff --git a/aqhome/msg.h b/aqhome/msg.h index b21d34a..d2da22b 100644 --- a/aqhome/msg.h +++ b/aqhome/msg.h @@ -15,6 +15,7 @@ #include #include +#include @@ -39,6 +40,9 @@ #define AQH_MSG_TYPE_DENY_ADDRESS 63 #define AQH_MSG_TYPE_ADDRESS_RANGE 64 +/* internal msg types via NET interface */ +#define AQH_MSG_TYPE_NET_SET_ACCEPTED_MSGGROUPS 200 + @@ -49,6 +53,7 @@ GWEN_LIST_FUNCTION_LIB_DEFS(AQH_MSG, AQH_Msg, AQHOME_API) AQHOME_API AQH_MSG *AQH_Msg_new(); AQHOME_API void AQH_Msg_free(AQH_MSG *msg); +AQHOME_API AQH_MSG *AQH_Msg_dup(const AQH_MSG *srcMsg); AQHOME_API uint8_t *AQH_Msg_GetBuffer(AQH_MSG *msg); AQHOME_API const uint8_t *AQH_Msg_GetConstBuffer(const AQH_MSG *msg); @@ -69,6 +74,8 @@ AQHOME_API int AQH_Msg_IsMsgComplete(const AQH_MSG *msg); AQHOME_API int AQH_Msg_IsChecksumValid(const AQH_MSG *msg); AQHOME_API int AQH_Msg_AddChecksum(AQH_MSG *msg); +AQHOME_API void AQH_Msg_DumpToBuffer(const AQH_MSG *msg, GWEN_BUFFER *dbuf, const char *sText); + #endif diff --git a/aqhome/msg_setaccmsggrps.c b/aqhome/msg_setaccmsggrps.c new file mode 100644 index 0000000..6999dae --- /dev/null +++ b/aqhome/msg_setaccmsggrps.c @@ -0,0 +1,73 @@ +/**************************************************************************** + * 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_setaccmsggrps.h" + +#include +#include +#include +#include + + + + +AQH_MSG *AQH_MsgSetAcceptedMsgGroups_new(uint8_t destAddr, uint32_t groups) +{ + AQH_MSG *msg; + + msg=AQH_Msg_new(); + AQH_Msg_AddByte(msg, destAddr); /* DESTADDR */ + AQH_Msg_AddByte(msg, 2+4); /* MSGLEN: srcAddr(1), msgType(1), groups (4) */ + AQH_Msg_AddByte(msg, AQH_MSG_TYPE_NET_SET_ACCEPTED_MSGGROUPS); /* MSGTYPE */ + AQH_Msg_AddByte(msg, 0); /* SRCADDR (admin, no src address needed) */ + AQH_Msg_AddByte(msg, groups & 0xff); /* 4 bytes remaining payload */ + AQH_Msg_AddByte(msg, (groups>>8) & 0xff); + AQH_Msg_AddByte(msg, (groups>>16) & 0xff); + AQH_Msg_AddByte(msg, (groups>>24) & 0xff); + AQH_Msg_AddChecksum(msg); + AQH_Msg_RewindCurrentPos(msg); + + return msg; +} + + + +uint32_t AQH_MsgSetAcceptedMsgGroups_GetMsgGroups(const AQH_MSG *msg) +{ + if ((AQH_Msg_GetMsgType(msg)==AQH_MSG_TYPE_NET_SET_ACCEPTED_MSGGROUPS) && + (AQH_Msg_GetBytesInBuffer(msg)>=AQH_MSG_SETACCMSGGRPS_MINSIZE)) { + const uint8_t *ptr; + + ptr=AQH_Msg_GetConstBuffer(msg)+AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_SETACCMSGGRPS_GRPS; + return (uint32_t)(ptr[0])+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24); + } + return 0; +} + + + +void AQH_MsgSetAcceptedMsgGroups_DumpToBuffer(const AQH_MSG *msg, GWEN_BUFFER *dbuf, const char *sText) +{ + if ((AQH_Msg_GetMsgType(msg)==AQH_MSG_TYPE_NET_SET_ACCEPTED_MSGGROUPS) && + (AQH_Msg_GetBytesInBuffer(msg)>=AQH_MSG_SETACCMSGGRPS_MINSIZE)) { + GWEN_Buffer_AppendArgs(dbuf, + "0x%02x->0x%02x: ACCEPTED_MSG_GROUPS %s (groups=0x%08x)\n", + AQH_Msg_GetSourceAddress(msg), + AQH_Msg_GetDestAddress(msg), + sText, + (unsigned int) AQH_MsgSetAcceptedMsgGroups_GetMsgGroups(msg)); + + } +} + + + diff --git a/aqhome/msg_setaccmsggrps.h b/aqhome/msg_setaccmsggrps.h new file mode 100644 index 0000000..8560267 --- /dev/null +++ b/aqhome/msg_setaccmsggrps.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQH_MSG_SETACCMSGGRPS_H +#define AQH_MSG_SETACCMSGGRPS_H + + +#include + +#include "aqhome/msg.h" + +#include +#include + + + +#define AQH_MSG_OFFS_SETACCMSGGRPS_GRPS 0 + +#define AQH_MSG_SETACCMSGGRPS_MINSIZE (AQH_MSG_OFFS_ALL_DATA_BEGIN+AQH_MSG_OFFS_SETACCMSGGRPS_GRPS+4) + + + +AQHOME_API AQH_MSG *AQH_MsgSetAcceptedMsgGroups_new(uint8_t destAddr, uint32_t groups); + +AQHOME_API uint32_t AQH_MsgSetAcceptedMsgGroups_GetMsgGroups(const AQH_MSG *msg); +AQHOME_API void AQH_MsgSetAcceptedMsgGroups_DumpToBuffer(const AQH_MSG *msg, GWEN_BUFFER *dbuf, const char *sText); + + +#endif + + + diff --git a/aqhome/msgendpoint.c b/aqhome/msgendpoint.c new file mode 100644 index 0000000..9b6bfe7 --- /dev/null +++ b/aqhome/msgendpoint.c @@ -0,0 +1,555 @@ +/**************************************************************************** + * 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/msgendpoint_p.h" + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#ifdef HAVE_ARPA_INET_H +# include +#endif + + +#define AQH_MSG_ENDPOINT_BUFFERSIZE 32 + + +GWEN_LIST_FUNCTIONS(AQH_MSG_ENDPOINT, AQH_MsgEndpoint) +GWEN_INHERIT_FUNCTIONS(AQH_MSG_ENDPOINT) + + +static int _internalHandleReadable(AQH_MSG_ENDPOINT *ep); +static int _internalHandleWritable(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_MGR *emgr); +static int _setSocketNonBlocking(int fd); + + + + +AQH_MSG_ENDPOINT *AQH_MsgEndpoint_new(int fd, int groupId) +{ + AQH_MSG_ENDPOINT *ep; + + GWEN_NEW_OBJECT(AQH_MSG_ENDPOINT, ep); + GWEN_INHERIT_INIT(AQH_MSG_ENDPOINT, ep); + GWEN_LIST_INIT(AQH_MSG_ENDPOINT, ep); + ep->fd=fd; + ep->groupId=groupId; + ep->receivedMessageList=AQH_Msg_List_new(); + ep->sendMessageList=AQH_Msg_List_new(); + + return ep; +} + + + +void AQH_MsgEndpoint_free(AQH_MSG_ENDPOINT *ep) +{ + if (ep) { + GWEN_LIST_FINI(AQH_MSG_ENDPOINT, ep); + GWEN_INHERIT_FINI(AQH_MSG_ENDPOINT, ep); + if (ep->fd>=0) + close(ep->fd); + AQH_Msg_free(ep->currentlyReceivedMsg); + AQH_Msg_List_free(ep->receivedMessageList); + AQH_Msg_List_free(ep->sendMessageList); + GWEN_FREE_OBJECT(ep); + } +} + + + +int AQH_MsgEndpoint_GetFd(const AQH_MSG_ENDPOINT *ep) +{ + return ep->fd; +} + + + +uint32_t AQH_MsgEndpoint_GetGroupId(const AQH_MSG_ENDPOINT *ep) +{ + return ep->groupId; +} + + + +uint32_t AQH_MsgEndpoint_GetAcceptedMsgGroups(const AQH_MSG_ENDPOINT *ep) +{ + return ep->acceptedMsgGroups; +} + + + +void AQH_MsgEndpoint_SetAcceptedMsgGroups(AQH_MSG_ENDPOINT *ep, uint32_t f) +{ + ep->acceptedMsgGroups=f; +} + + + +void AQH_MsgEndpoint_AddAcceptedMsgGroups(AQH_MSG_ENDPOINT *ep, uint32_t f) +{ + ep->acceptedMsgGroups|=f; +} + + + +void AQH_MsgEndpoint_DelAcceptedMsgGroups(AQH_MSG_ENDPOINT *ep, uint32_t f) +{ + ep->acceptedMsgGroups&=~f; +} + + + +uint32_t AQH_MsgEndpoint_GetAcceptedEndpointGroups(const AQH_MSG_ENDPOINT *ep) +{ + return ep->acceptedEndpointGroups; +} + + + +void AQH_MsgEndpoint_SetAcceptedEndpointGroups(AQH_MSG_ENDPOINT *ep, uint32_t f) +{ + ep->acceptedEndpointGroups=f; +} + + + +void AQH_MsgEndpoint_AddAcceptedEndpointGroups(AQH_MSG_ENDPOINT *ep, uint32_t f) +{ + ep->acceptedEndpointGroups|=f; +} + + + +void AQH_MsgEndpoint_DelAcceptedEndpointGroups(AQH_MSG_ENDPOINT *ep, uint32_t f) +{ + ep->acceptedEndpointGroups&=~f; +} + + + +uint32_t AQH_MsgEndpoint_GetFlags(const AQH_MSG_ENDPOINT *ep) +{ + return ep->flags; +} + + + +void AQH_MsgEndpoint_SetFlags(AQH_MSG_ENDPOINT *ep, uint32_t f) +{ + ep->flags=f; +} + + + +void AQH_MsgEndpoint_AddFlags(AQH_MSG_ENDPOINT *ep, uint32_t f) +{ + ep->flags|=f; +} + + + +void AQH_MsgEndpoint_SubFlags(AQH_MSG_ENDPOINT *ep, uint32_t f) +{ + ep->flags&=~f; +} + + + + +AQH_MSG_LIST *AQH_MsgEndpoint_GetReceivedMessageList(const AQH_MSG_ENDPOINT *ep) +{ + return ep->receivedMessageList; +} + + + +AQH_MSG *AQH_MsgEndpoint_TakeFirstReceivedMessage(AQH_MSG_ENDPOINT *ep) +{ + AQH_MSG *msg; + + msg=AQH_Msg_List_First(ep->receivedMessageList); + if (msg) + AQH_Msg_List_Del(msg); + return msg; +} + + + +AQH_MSG_LIST *AQH_MsgEndpoint_GetSendMessageList(const AQH_MSG_ENDPOINT *ep) +{ + return ep->sendMessageList; +} + + + +void AQH_MsgEndpoint_AddReceivedMessage(AQH_MSG_ENDPOINT *ep, AQH_MSG *m) +{ + AQH_Msg_List_Add(m, ep->receivedMessageList); +} + + + +void AQH_MsgEndpoint_AddSendMessage(AQH_MSG_ENDPOINT *ep, AQH_MSG *m) +{ + AQH_Msg_List_Add(m, ep->sendMessageList); +} + + + +AQH_MSG *AQH_MsgEndpoint_GetCurrentlyReceivedMsg(const AQH_MSG_ENDPOINT *ep) +{ + return ep->currentlyReceivedMsg; +} + + + +void AQH_MsgEndpoint_SetCurrentlyReceivedMsg(AQH_MSG_ENDPOINT *ep, AQH_MSG *m) +{ + AQH_Msg_free(ep->currentlyReceivedMsg); + ep->currentlyReceivedMsg=m; +} + + + +int AQH_MsgEndpoint_HandleReadable(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_MGR *emgr) +{ + return (ep->handleReadableFn)?(ep->handleReadableFn(ep, emgr)):_internalHandleReadable(ep); +} + + + +int AQH_MsgEndpoint_HandleWritable(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_MGR *emgr) +{ + return (ep->handleWritableFn)?(ep->handleWritableFn(ep, emgr)):_internalHandleWritable(ep, emgr); +} + + + +void AQH_MsgEndpoint_Run(AQH_MSG_ENDPOINT *ep) +{ + if (ep->runFn) + ep->runFn(ep); +} + + + +int AQH_MsgEndpoint_StartMsg(AQH_MSG_ENDPOINT *ep) +{ + int rv; + + rv=(ep->startMsgFn)?(ep->startMsgFn(ep)):0; + if (rv==0) + ep->sendingMessage=1; + return rv; +} + + + +int AQH_MsgEndpoint_EndMsg(AQH_MSG_ENDPOINT *ep) +{ + int rv; + + rv=(ep->endMsgFn)?(ep->endMsgFn(ep)):0; + if (rv==0) + ep->sendingMessage=0; + return rv; +} + + + +int AQH_MsgEndpoint_CheckMsg(AQH_MSG_ENDPOINT *ep) +{ + return (ep->checkMsgFn)?(ep->checkMsgFn(ep)):1; +} + + + +AQH_MSG_ENDPOINT_HANDLEREADABLE_FN AQH_MsgEndpoint_SetHandleReadableFn(AQH_MSG_ENDPOINT *ep, + AQH_MSG_ENDPOINT_HANDLEREADABLE_FN f) +{ + AQH_MSG_ENDPOINT_HANDLEREADABLE_FN oldFn; + + oldFn=ep->handleReadableFn; + ep->handleReadableFn=f; + return oldFn; +} + + + +AQH_MSG_ENDPOINT_HANDLEWRITABLE_FN AQH_MsgEndpoint_SetHandleWritableFn(AQH_MSG_ENDPOINT *ep, + AQH_MSG_ENDPOINT_HANDLEWRITABLE_FN f) +{ + AQH_MSG_ENDPOINT_HANDLEWRITABLE_FN oldFn; + + oldFn=ep->handleWritableFn; + ep->handleWritableFn=f; + return oldFn; +} + + + +AQH_MSG_ENDPOINT_GET_READFD_FN AQH_MsgEndpoint_SetGetReadFdFn(AQH_MSG_ENDPOINT *ep, + AQH_MSG_ENDPOINT_GET_READFD_FN f) +{ + AQH_MSG_ENDPOINT_GET_READFD_FN oldFn; + + oldFn=ep->getReadFdFn; + ep->getReadFdFn=f; + return oldFn; +} + + + +AQH_MSG_ENDPOINT_GET_WRITEFD_FN AQH_MsgEndpoint_SetGetWriteFdFn(AQH_MSG_ENDPOINT *ep, + AQH_MSG_ENDPOINT_GET_WRITEFD_FN f) +{ + AQH_MSG_ENDPOINT_GET_WRITEFD_FN oldFn; + + oldFn=ep->getWriteFdFn; + ep->getWriteFdFn=f; + return oldFn; +} + + + +AQH_MSG_ENDPOINT_RUN_FN AQH_MsgEndpoint_SetRunFn(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_RUN_FN f) +{ + AQH_MSG_ENDPOINT_RUN_FN oldFn; + + oldFn=ep->runFn; + ep->runFn=f; + return oldFn; +} + + + +AQH_MSG_ENDPOINT_STARTMSG_FN AQH_MsgEndpoint_SetStartMsgFn(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_STARTMSG_FN f) +{ + AQH_MSG_ENDPOINT_STARTMSG_FN oldFn; + + oldFn=ep->startMsgFn; + ep->startMsgFn=f; + return oldFn; +} + + + +AQH_MSG_ENDPOINT_ENDMSG_FN AQH_MsgEndpoint_SetEndMsgFn(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_ENDMSG_FN f) +{ + AQH_MSG_ENDPOINT_ENDMSG_FN oldFn; + + oldFn=ep->endMsgFn; + ep->endMsgFn=f; + return oldFn; +} + + + +AQH_MSG_ENDPOINT_CHECKMSG_FN AQH_MsgEndpoint_SetCheckMsgFn(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_CHECKMSG_FN f) +{ + AQH_MSG_ENDPOINT_CHECKMSG_FN oldFn; + + oldFn=ep->checkMsgFn; + ep->checkMsgFn=f; + return oldFn; +} + + + +int AQH_MsgEndpoint_GetReadFd(AQH_MSG_ENDPOINT *ep) +{ + return (ep->getReadFdFn)?(ep->getReadFdFn(ep)):(ep->fd); +} + + + +int AQH_MsgEndpoint_GetWriteFd(AQH_MSG_ENDPOINT *ep) +{ + if (ep->getWriteFdFn) + return ep->getWriteFdFn(ep); + else { + int somethingToWrite; + + somethingToWrite=(AQH_Msg_List_First(ep->sendMessageList)!=NULL)?1:0; + if (somethingToWrite) + return ep->fd; + } + return GWEN_ERROR_NO_DATA; +} + + + + +int AQH_MsgEndpoint_DiscardInput(AQH_MSG_ENDPOINT *ep) +{ + int rv; + uint8_t buffer[AQH_MSG_ENDPOINT_BUFFERSIZE]; + + do { + rv=read(ep->fd, buffer, sizeof(buffer)); + } while( (rv>0 || (rv<0) && errno==EINTR)); + if (rv<0 && errno!=EAGAIN && errno!=EWOULDBLOCK) { + DBG_ERROR(NULL, "Error on read(): %s (%d)", strerror(errno), errno); + return GWEN_ERROR_IO; + } + else if (rv==0) { + DBG_ERROR(NULL, "EOF met on read()"); + return GWEN_ERROR_IO; + } + return 0; +} + + + +int _internalHandleReadable(AQH_MSG_ENDPOINT *ep) +{ + int rv; + uint8_t buffer[AQH_MSG_ENDPOINT_BUFFERSIZE*2]; + int len; + int i; + + do { + rv=read(ep->fd, buffer, sizeof(buffer)); + } while( (rv<0) && errno==EINTR); + if (rv<0) { + if (errno==EAGAIN || errno==EWOULDBLOCK) + return GWEN_ERROR_TRY_AGAIN; + DBG_ERROR(NULL, "Error on read(): %s (%d)", strerror(errno), errno); + return GWEN_ERROR_IO; + } + else if (rv==0) { + DBG_ERROR(NULL, "EOF met on read()"); + return GWEN_ERROR_IO; + } + len=rv; + + for (i=0; icurrentlyReceivedMsg==NULL) + ep->currentlyReceivedMsg=AQH_Msg_new(); + rv=AQH_Msg_AddByte(ep->currentlyReceivedMsg, buffer[i]); + if (rv<0) { + DBG_ERROR(NULL, "here (%d)", rv); + return rv; + } + rv=AQH_Msg_IsMsgComplete(ep->currentlyReceivedMsg); + if (rv<0) { + /* invalid message */ + DBG_ERROR(NULL, "Invalid message, discarding"); + AQH_Msg_free(ep->currentlyReceivedMsg); + ep->currentlyReceivedMsg=NULL; + rv=AQH_MsgEndpoint_DiscardInput(ep); + if (rv<0) { + DBG_ERROR(NULL, "here (%d)", rv); + return rv; + } + } + else if (rv>0) { + if (!AQH_Msg_IsChecksumValid(ep->currentlyReceivedMsg)) { + DBG_ERROR(NULL, "Invalid checksum, discarding message"); + GWEN_Text_DumpString(AQH_Msg_GetBuffer(ep->currentlyReceivedMsg), AQH_Msg_GetBytesInBuffer(ep->currentlyReceivedMsg), 6); + AQH_Msg_free(ep->currentlyReceivedMsg); + ep->currentlyReceivedMsg=NULL; + rv=AQH_MsgEndpoint_DiscardInput(ep); + if (rv<0) { + DBG_ERROR(NULL, "here (%d)", rv); + return rv; + } + } + else { + /* valid msg received, add to list */ + AQH_Msg_List_Add(ep->currentlyReceivedMsg, ep->receivedMessageList); + ep->currentlyReceivedMsg=NULL; + } + } + } + + return 0; +} + + + +int _internalHandleWritable(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_MGR *emgr) +{ + AQH_MSG *msg; + + msg=AQH_Msg_List_First(ep->sendMessageList); + if (msg) { + uint8_t pos; + int len; + int remaining; + int rv; + + rv=AQH_MsgEndpoint_CheckMsg(ep); + if (rv<0 || rv==1) { + DBG_ERROR(NULL, "Line busy, not sending"); + usleep(100); + return 0; + } + pos=AQH_Msg_GetCurrentPos(msg); + remaining=AQH_Msg_GetRemainingBytes(msg); + if (remaining>0) { + const uint8_t *buf; + + rv=AQH_MsgEndpoint_StartMsg(ep); + if (rv<0) { + DBG_ERROR(NULL, "here (%d)", rv); + return rv; + } + + buf=AQH_Msg_GetBuffer(msg)+pos; + do { + rv=write(ep->fd, buf, remaining); + } while(rv<0 && errno==EINTR); + if (rv<0) { + if (errno==EAGAIN || errno==EWOULDBLOCK) + return GWEN_ERROR_TRY_AGAIN; + DBG_ERROR(NULL, "Error on write(): %s (%d)", strerror(errno), errno); + return GWEN_ERROR_IO; + } + AQH_Msg_IncCurrentPos(msg, rv); + if (rv==remaining) { + rv=AQH_MsgEndpoint_EndMsg(ep); + // TODO: callback msg sent + AQH_Msg_List_Del(msg); + AQH_Msg_free(msg); + if (rv<0) { + DBG_ERROR(NULL, "here (%d)", rv); + return rv; + } + } + } + } + return 0; +} + + + diff --git a/aqhome/msgendpoint.h b/aqhome/msgendpoint.h new file mode 100644 index 0000000..25fb7d2 --- /dev/null +++ b/aqhome/msgendpoint.h @@ -0,0 +1,125 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQH_MSGENDPOINT_H +#define AQH_MSGENDPOINT_H + + +#include + +#include "aqhome/msg.h" + +#include +#include + + +typedef struct AQH_MSG_ENDPOINT AQH_MSG_ENDPOINT; +GWEN_LIST_FUNCTION_LIB_DEFS(AQH_MSG_ENDPOINT, AQH_MsgEndpoint, AQHOME_API) +GWEN_INHERIT_FUNCTION_LIB_DEFS(AQH_MSG_ENDPOINT, AQHOME_API) + + +#include "aqhome/msgendpointmanager.h" + +#include + + + + +#define AQH_MSG_ENDPOINT_ENDPOINTGROUP_BUS 0x0001 +#define AQH_MSG_ENDPOINT_ENDPOINTGROUP_NET 0x0002 + + +#define AQH_MSG_ENDPOINT_MSGGROUP_INFO 0x00000001 +#define AQH_MSG_ENDPOINT_MSGGROUP_VALUES 0x00000002 +#define AQH_MSG_ENDPOINT_MSGGROUP_ADDRESS 0x00000004 +#define AQH_MSG_ENDPOINT_MSGGROUP_FLASH 0x00000008 +#define AQH_MSG_ENDPOINT_MSGGROUP_ADMIN 0x00000010 +#define AQH_MSG_ENDPOINT_MSGGROUP_ALL 0xffffffff + +#define AQH_MSG_ENDPOINT_FLAGS_NOMESSAGES 0x0001 +#define AQH_MSG_ENDPOINT_FLAGS_NOIO 0x0002 + + + +typedef int (*AQH_MSG_ENDPOINT_HANDLEREADABLE_FN)(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_MGR *emgr); +typedef int (*AQH_MSG_ENDPOINT_HANDLEWRITABLE_FN)(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_MGR *emgr); +typedef void (*AQH_MSG_ENDPOINT_RUN_FN)(AQH_MSG_ENDPOINT *ep); +typedef int (*AQH_MSG_ENDPOINT_GET_READFD_FN)(AQH_MSG_ENDPOINT *ep); +typedef int (*AQH_MSG_ENDPOINT_GET_WRITEFD_FN)(AQH_MSG_ENDPOINT *ep); + +typedef int (*AQH_MSG_ENDPOINT_STARTMSG_FN)(AQH_MSG_ENDPOINT *ep); +typedef int (*AQH_MSG_ENDPOINT_ENDMSG_FN)(AQH_MSG_ENDPOINT *ep); +typedef int (*AQH_MSG_ENDPOINT_CHECKMSG_FN)(AQH_MSG_ENDPOINT *ep); + + + +AQHOME_API AQH_MSG_ENDPOINT *AQH_MsgEndpoint_new(int fd, int groupId); +AQHOME_API void AQH_MsgEndpoint_free(AQH_MSG_ENDPOINT *ep); + +AQHOME_API int AQH_MsgEndpoint_GetFd(const AQH_MSG_ENDPOINT *ep); + +AQHOME_API uint32_t AQH_MsgEndpoint_GetGroupId(const AQH_MSG_ENDPOINT *ep); + +AQHOME_API uint32_t AQH_MsgEndpoint_GetAcceptedMsgGroups(const AQH_MSG_ENDPOINT *ep); +AQHOME_API void AQH_MsgEndpoint_SetAcceptedMsgGroups(AQH_MSG_ENDPOINT *ep, uint32_t f); +AQHOME_API void AQH_MsgEndpoint_AddAcceptedMsgGroups(AQH_MSG_ENDPOINT *ep, uint32_t f); +AQHOME_API void AQH_MsgEndpoint_DelAcceptedMsgGroups(AQH_MSG_ENDPOINT *ep, uint32_t f); + +AQHOME_API uint32_t AQH_MsgEndpoint_GetAcceptedEndpointGroups(const AQH_MSG_ENDPOINT *ep); +AQHOME_API void AQH_MsgEndpoint_SetAcceptedEndpointGroups(AQH_MSG_ENDPOINT *ep, uint32_t f); +AQHOME_API void AQH_MsgEndpoint_AddAcceptedEndpointGroups(AQH_MSG_ENDPOINT *ep, uint32_t f); +AQHOME_API void AQH_MsgEndpoint_DelAcceptedEndpointGroups(AQH_MSG_ENDPOINT *ep, uint32_t f); + +AQHOME_API uint32_t AQH_MsgEndpoint_GetFlags(const AQH_MSG_ENDPOINT *ep); +AQHOME_API void AQH_MsgEndpoint_SetFlags(AQH_MSG_ENDPOINT *ep, uint32_t f); +AQHOME_API void AQH_MsgEndpoint_AddFlags(AQH_MSG_ENDPOINT *ep, uint32_t f); +AQHOME_API void AQH_MsgEndpoint_SubFlags(AQH_MSG_ENDPOINT *ep, uint32_t f); + +AQHOME_API AQH_MSG_LIST *AQH_MsgEndpoint_GetReceivedMessageList(const AQH_MSG_ENDPOINT *ep); +AQHOME_API AQH_MSG_LIST *AQH_MsgEndpoint_GetSendMessageList(const AQH_MSG_ENDPOINT *ep); + +AQHOME_API void AQH_MsgEndpoint_AddReceivedMessage(AQH_MSG_ENDPOINT *ep, AQH_MSG *m); +AQHOME_API AQH_MSG *AQH_MsgEndpoint_TakeFirstReceivedMessage(AQH_MSG_ENDPOINT *ep); +AQHOME_API void AQH_MsgEndpoint_AddSendMessage(AQH_MSG_ENDPOINT *ep, AQH_MSG *m); + +AQHOME_API AQH_MSG *AQH_MsgEndpoint_GetCurrentlyReceivedMsg(const AQH_MSG_ENDPOINT *ep); +AQHOME_API void AQH_MsgEndpoint_SetCurrentlyReceivedMsg(AQH_MSG_ENDPOINT *ep, AQH_MSG *m); + + +AQHOME_API int AQH_MsgEndpoint_GetReadFd(AQH_MSG_ENDPOINT *ep); +AQHOME_API int AQH_MsgEndpoint_GetWriteFd(AQH_MSG_ENDPOINT *ep); + +AQHOME_API int AQH_MsgEndpoint_HandleReadable(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_MGR *emgr); +AQHOME_API int AQH_MsgEndpoint_HandleWritable(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_MGR *emgr); +AQHOME_API void AQH_MsgEndpoint_Run(AQH_MSG_ENDPOINT *ep); + +AQHOME_API int AQH_MsgEndpoint_DiscardInput(AQH_MSG_ENDPOINT *ep); + +AQHOME_API int AQH_MsgEndpoint_StartMsg(AQH_MSG_ENDPOINT *ep); +AQHOME_API int AQH_MsgEndpoint_EndMsg(AQH_MSG_ENDPOINT *ep); +AQHOME_API int AQH_MsgEndpoint_CheckMsg(AQH_MSG_ENDPOINT *ep); + + +AQHOME_API AQH_MSG_ENDPOINT_HANDLEREADABLE_FN AQH_MsgEndpoint_SetHandleReadableFn(AQH_MSG_ENDPOINT *ep, + AQH_MSG_ENDPOINT_HANDLEREADABLE_FN f); +AQHOME_API AQH_MSG_ENDPOINT_HANDLEWRITABLE_FN AQH_MsgEndpoint_SetHandleWritableFn(AQH_MSG_ENDPOINT *ep, + AQH_MSG_ENDPOINT_HANDLEWRITABLE_FN f); +AQHOME_API AQH_MSG_ENDPOINT_GET_READFD_FN AQH_MsgEndpoint_SetGetReadFdFn(AQH_MSG_ENDPOINT *ep, + AQH_MSG_ENDPOINT_GET_READFD_FN f); +AQHOME_API AQH_MSG_ENDPOINT_GET_WRITEFD_FN AQH_MsgEndpoint_SetGetWriteFdFn(AQH_MSG_ENDPOINT *ep, + AQH_MSG_ENDPOINT_GET_WRITEFD_FN f); + +AQHOME_API AQH_MSG_ENDPOINT_RUN_FN AQH_MsgEndpoint_SetRunFn(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_RUN_FN f); +AQHOME_API AQH_MSG_ENDPOINT_STARTMSG_FN AQH_MsgEndpoint_SetStartMsgFn(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_STARTMSG_FN f); +AQHOME_API AQH_MSG_ENDPOINT_ENDMSG_FN AQH_MsgEndpoint_SetEndMsgFn(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_ENDMSG_FN f); +AQHOME_API AQH_MSG_ENDPOINT_CHECKMSG_FN AQH_MsgEndpoint_SetCheckMsgFn(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_CHECKMSG_FN f); + + + +#endif + diff --git a/aqhome/msgendpoint_p.h b/aqhome/msgendpoint_p.h new file mode 100644 index 0000000..10b788f --- /dev/null +++ b/aqhome/msgendpoint_p.h @@ -0,0 +1,51 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQH_MSGENDPOINT_P_H +#define AQH_MSGENDPOINT_P_H + + +#include + +#include "aqhome/msgendpoint.h" + +#include +#include + + +struct AQH_MSG_ENDPOINT { + GWEN_INHERIT_ELEMENT(AQH_MSG_ENDPOINT) + GWEN_LIST_ELEMENT(AQH_MSG_ENDPOINT) + + int fd; + AQH_MSG_LIST *receivedMessageList; + AQH_MSG_LIST *sendMessageList; + AQH_MSG *currentlyReceivedMsg; + + AQH_MSG_ENDPOINT_HANDLEREADABLE_FN handleReadableFn; + AQH_MSG_ENDPOINT_HANDLEWRITABLE_FN handleWritableFn; + AQH_MSG_ENDPOINT_GET_READFD_FN getReadFdFn; + AQH_MSG_ENDPOINT_GET_WRITEFD_FN getWriteFdFn; + AQH_MSG_ENDPOINT_RUN_FN runFn; + AQH_MSG_ENDPOINT_STARTMSG_FN startMsgFn; + AQH_MSG_ENDPOINT_ENDMSG_FN endMsgFn; + AQH_MSG_ENDPOINT_CHECKMSG_FN checkMsgFn; + + uint32_t flags; + uint32_t groupId; + uint32_t acceptedEndpointGroups; + uint32_t acceptedMsgGroups; + + int sendingMessage; +}; + + + + +#endif + diff --git a/aqhome/msgendpointlog.c b/aqhome/msgendpointlog.c new file mode 100644 index 0000000..29e4acc --- /dev/null +++ b/aqhome/msgendpointlog.c @@ -0,0 +1,155 @@ +/**************************************************************************** + * 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/msgendpointlog_p.h" + +#include "aqhome/msg_value.h" +#include "aqhome/msg_sendstats.h" +#include "aqhome/msg_ping.h" +#include "aqhome/msg_pong.h" +#include "aqhome/msg_needaddr.h" +#include "aqhome/msg_claimaddr.h" +#include "aqhome/msg_haveaddr.h" +#include "aqhome/msg_denyaddr.h" + +#include +#include +#include +#include + + + +GWEN_INHERIT(AQH_MSG_ENDPOINT, AQH_MSG_ENDPOINT_LOG) + + +static void GWENHYWFAR_CB _freeData(void *bp, void *p); +static void _run(AQH_MSG_ENDPOINT *ep); +static void _logMessage(AQH_MSG_ENDPOINT *ep, const AQH_MSG *msg); +static void _writeToLogFile(const char *filename, const char *txt); + + + + + +AQH_MSG_ENDPOINT *AQH_MsgEndpointLog_new(const char *filename) +{ + int fd; + AQH_MSG_ENDPOINT *ep; + AQH_MSG_ENDPOINT_LOG *xep; + + ep=AQH_MsgEndpoint_new(-1, AQH_MSG_ENDPOINT_ENDPOINTGROUP_NET); + GWEN_NEW_OBJECT(AQH_MSG_ENDPOINT_LOG, xep); + xep->filename=strdup(filename); + GWEN_INHERIT_SETDATA(AQH_MSG_ENDPOINT, AQH_MSG_ENDPOINT_LOG, ep, xep, _freeData); + AQH_MsgEndpoint_SetAcceptedEndpointGroups(ep, AQH_MSG_ENDPOINT_ENDPOINTGROUP_BUS); + AQH_MsgEndpoint_SetAcceptedMsgGroups(ep, AQH_MSG_ENDPOINT_MSGGROUP_ALL); + AQH_MsgEndpoint_AddFlags(ep, AQH_MSG_ENDPOINT_FLAGS_NOIO); + AQH_MsgEndpoint_SetRunFn(ep, _run); + + return ep; +} + + + +void _freeData(void *bp, void *p) +{ + AQH_MSG_ENDPOINT_LOG *xep; + + xep=(AQH_MSG_ENDPOINT_LOG*) p; + free(xep->filename); + GWEN_FREE_OBJECT(xep); +} + + + +void _run(AQH_MSG_ENDPOINT *ep) +{ + AQH_MSG_LIST *msgList; + + msgList=AQH_MsgEndpoint_GetSendMessageList(ep); + if (msgList && AQH_Msg_List_GetCount(msgList)) { + AQH_MSG *msg; + + msg=AQH_Msg_List_First(msgList); + while(msg) { + AQH_MSG *next; + + next=AQH_Msg_List_Next(msg); + _logMessage(ep, msg); + AQH_Msg_free(msg); + msg=next; + } + } +} + + + +void _logMessage(AQH_MSG_ENDPOINT *ep, const AQH_MSG *msg) +{ + AQH_MSG_ENDPOINT_LOG *xep; + const uint8_t *ptr; + uint8_t len; + uint8_t msgType; + int msgIsValid; + GWEN_BUFFER *dbuf; + GWEN_TIME *ti; + + xep=GWEN_INHERIT_GETDATA(AQH_MSG_ENDPOINT, AQH_MSG_ENDPOINT_LOG, ep); + dbuf=GWEN_Buffer_new(0, 256, 0, 1); + ti=GWEN_CurrentTime(); + GWEN_Time_toString(ti, "YYYY-MM-DD hh:mm:ss ", dbuf); + GWEN_Time_free(ti); + ti=NULL; + + msgIsValid=(AQH_Msg_IsChecksumValid(msg) && AQH_Msg_IsMsgComplete(msg)); + ptr=AQH_Msg_GetConstBuffer(msg); + len=AQH_Msg_GetBytesInBuffer(msg); + msgType=AQH_Msg_GetMsgType(msg); + + switch(msgType) { + case AQH_MSG_TYPE_PING: AQH_MsgPing_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_PONG: AQH_MsgPong_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_COMSENDSTATS: AQH_MsgSendStats_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_TWIBUSMEMBER: AQH_Msg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_DEBUG: AQH_Msg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_VALUE: AQH_MsgValue_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_NEED_ADDRESS: AQH_MsgNeedAddr_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_CLAIM_ADDRESS: AQH_MsgClaimAddr_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_HAVE_ADDRESS: AQH_MsgHaveAddr_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_DENY_ADDRESS: AQH_MsgDenyAddr_DumpToBuffer(msg, dbuf, "received"); break; + default: AQH_MsgValue_DumpToBuffer(msg, dbuf, "received"); break; + } + _writeToLogFile(xep->filename, GWEN_Buffer_GetStart(dbuf)); + GWEN_Buffer_free(dbuf); +} + + + +void _writeToLogFile(const char *filename, const char *txt) +{ + if (txt && *txt) { + FILE *f; + + f=fopen(filename, "a+"); + if (f) { + if (1!=fwrite(txt, strlen(txt), 1, f)) { + DBG_ERROR(NULL, "Error logging."); + } + fclose(f); + } + } +} + + + + diff --git a/aqhome/msgendpointlog.h b/aqhome/msgendpointlog.h new file mode 100644 index 0000000..4939db6 --- /dev/null +++ b/aqhome/msgendpointlog.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQH_MSGENDPOINT_LOG_H +#define AQH_MSGENDPOINT_LOG_H + + +#include + +#include "aqhome/msgendpoint.h" + +#include +#include + + +AQHOME_API AQH_MSG_ENDPOINT *AQH_MsgEndpointLog_new(const char *filename); + + + + +#endif + diff --git a/aqhome/msgendpointlog_p.h b/aqhome/msgendpointlog_p.h new file mode 100644 index 0000000..47bdb38 --- /dev/null +++ b/aqhome/msgendpointlog_p.h @@ -0,0 +1,25 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQH_MSGENDPOINT_LOG_P_H +#define AQH_MSGENDPOINT_LOG_P_H + + +#include "aqhome/msgendpointlog.h" + + +typedef struct AQH_MSG_ENDPOINT_LOG AQH_MSG_ENDPOINT_LOG; +struct AQH_MSG_ENDPOINT_LOG { + char *filename; +}; + + + + +#endif + diff --git a/aqhome/msgendpointmanager.c b/aqhome/msgendpointmanager.c new file mode 100644 index 0000000..2fc4b26 --- /dev/null +++ b/aqhome/msgendpointmanager.c @@ -0,0 +1,307 @@ +/**************************************************************************** + * 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/msgendpointmanager_p.h" +#include "aqhome/msg_setaccmsggrps.h" + +#include +#include +#include +#include + +#include + + + +static int _ioLoopOnce(AQH_MSG_ENDPOINT_MGR *emgr); +static void _msgLoopOnce(AQH_MSG_ENDPOINT_MGR *emgr); +static void _runAllEndpoints(AQH_MSG_ENDPOINT_MGR *emgr); +static void _distributeMsg(AQH_MSG_ENDPOINT_MGR *emgr, AQH_MSG_ENDPOINT *ep, const AQH_MSG *msg); +static void _handleAdminMsg(AQH_MSG_ENDPOINT_MGR *emgr, AQH_MSG_ENDPOINT *ep, const AQH_MSG *msg); +static void _handleMsgSetAcceptedMsgGroups(AQH_MSG_ENDPOINT_MGR *emgr, AQH_MSG_ENDPOINT *ep, const AQH_MSG *msg); +static uint32_t _getMsgGroup(uint8_t msgType); + + + + +AQH_MSG_ENDPOINT_MGR *AQH_MsgEndpointMgr_new(uint8_t busAddr) +{ + AQH_MSG_ENDPOINT_MGR *emgr; + + GWEN_NEW_OBJECT(AQH_MSG_ENDPOINT_MGR, emgr); + emgr->endpointList=AQH_MsgEndpoint_List_new(); + emgr->busAddr=busAddr; + return emgr; +} + + + +void AQH_MsgEndpointMgr_free(AQH_MSG_ENDPOINT_MGR *emgr) +{ + if (emgr) { + AQH_MsgEndpoint_List_free(emgr->endpointList); + GWEN_FREE_OBJECT(emgr); + } +} + + + +uint8_t AQH_MsgEndpointMgr_GetBusAddr(const AQH_MSG_ENDPOINT_MGR *emgr) +{ + return emgr->busAddr; +} + + + +AQH_MSG_ENDPOINT_LIST *AQH_MsgEndpointMgr_GetEndpointList(const AQH_MSG_ENDPOINT_MGR *emgr) +{ + return emgr->endpointList; +} + + + +void AQH_MsgEndpointMgr_AddEndpoint(AQH_MSG_ENDPOINT_MGR *emgr, AQH_MSG_ENDPOINT *ep) +{ + AQH_MsgEndpoint_List_Add(ep, emgr->endpointList); +} + + + +void AQH_MsgEndpointMgr_DelEndpoint(AQH_MSG_ENDPOINT_MGR *emgr, AQH_MSG_ENDPOINT *ep) +{ + AQH_MsgEndpoint_List_Del(ep); +} + + + +int AQH_MsgEndpointMgr_LoopOnce(AQH_MSG_ENDPOINT_MGR *emgr) +{ + int rv; + + rv=_ioLoopOnce(emgr); + _msgLoopOnce(emgr); + _runAllEndpoints(emgr); + return rv; +} + + + +int _ioLoopOnce(AQH_MSG_ENDPOINT_MGR *emgr) +{ + AQH_MSG_ENDPOINT *ep; + fd_set readSet; + fd_set writeSet; + int highestRdFd=-1; + int highestWrFd=-1; + struct timeval tv; + int rv; + + FD_ZERO(&readSet); + FD_ZERO(&writeSet); + tv.tv_sec=2; + tv.tv_usec=0; + + ep=AQH_MsgEndpoint_List_First(emgr->endpointList); + while(ep) { + if (!(AQH_MsgEndpoint_GetFlags(ep) & AQH_MSG_ENDPOINT_FLAGS_NOIO)) { + int fd; + + fd=AQH_MsgEndpoint_GetReadFd(ep); + if (fd!=-1) { + FD_SET(fd, &readSet); + highestRdFd=(fd>highestRdFd)?fd:highestRdFd; + } + + fd=AQH_MsgEndpoint_GetWriteFd(ep); + if (fd!=-1) { + FD_SET(fd, &writeSet); + highestWrFd=(fd>highestWrFd)?fd:highestWrFd; + } + } + ep=AQH_MsgEndpoint_List_Next(ep); + } + + rv=select(((highestRdFd>highestWrFd)?highestRdFd:highestWrFd)+1, + (highestRdFd<0)?NULL:&readSet, + (highestWrFd<0)?NULL:&writeSet, + NULL, + &tv); + if (rv<0) { + if (errno!=EINTR) { + DBG_ERROR(NULL, "Error on select"); + return GWEN_ERROR_IO; + } + } + else if (rv==0) { + /* timeout */ + return GWEN_ERROR_TRY_AGAIN; + } + else if (rv) { + ep=AQH_MsgEndpoint_List_First(emgr->endpointList); + while(ep) { + AQH_MSG_ENDPOINT *epNext; + int fd; + int rv; + + epNext=AQH_MsgEndpoint_List_Next(ep); + fd=AQH_MsgEndpoint_GetFd(ep); + if (fd!=-1 && FD_ISSET(fd, &readSet)) { + rv=AQH_MsgEndpoint_HandleReadable(ep, emgr); + if (rv<0 && rv!=GWEN_ERROR_TRY_AGAIN) { + fd=-1; + AQH_MsgEndpointMgr_DelEndpoint(emgr, ep); + } + } + if (fd!=-1 && FD_ISSET(fd, &writeSet)) { + rv=AQH_MsgEndpoint_HandleWritable(ep, emgr); + if (rv<0 && rv!=GWEN_ERROR_TRY_AGAIN) { + fd=-1; + AQH_MsgEndpointMgr_DelEndpoint(emgr, ep); + } + } + ep=epNext; + } + } + + return 0; +} + + + +void _msgLoopOnce(AQH_MSG_ENDPOINT_MGR *emgr) +{ + AQH_MSG_ENDPOINT *ep; + + ep=AQH_MsgEndpoint_List_First(emgr->endpointList); + while(ep) { + AQH_MSG *msg; + + while( (msg=AQH_MsgEndpoint_TakeFirstReceivedMessage(ep)) ) { + uint32_t msgGroup; + + msgGroup=_getMsgGroup(AQH_Msg_GetMsgType(msg)); + if (msgGroup & AQH_MSG_ENDPOINT_MSGGROUP_ADMIN) { + if (!(AQH_MsgEndpoint_GetGroupId(ep) & AQH_MSG_ENDPOINT_ENDPOINTGROUP_BUS)) + /* only handle admin messages not from nodes */ + _handleAdminMsg(emgr, ep, msg); + } + else + _distributeMsg(emgr, ep, msg); + AQH_Msg_free(msg); + } + + ep=AQH_MsgEndpoint_List_Next(ep); + } +} + + + +void _runAllEndpoints(AQH_MSG_ENDPOINT_MGR *emgr) +{ + AQH_MSG_ENDPOINT *ep; + + ep=AQH_MsgEndpoint_List_First(emgr->endpointList); + while(ep) { + AQH_MSG_ENDPOINT *next; + + next=AQH_MsgEndpoint_List_Next(ep); + AQH_MsgEndpoint_Run(ep); + ep=next; + } +} + + + +void _distributeMsg(AQH_MSG_ENDPOINT_MGR *emgr, AQH_MSG_ENDPOINT *srcEp, const AQH_MSG *msg) +{ + AQH_MSG_ENDPOINT *ep; + int srcGroupId; + uint32_t msgGroup; + + msgGroup=_getMsgGroup(AQH_Msg_GetMsgType(msg)); + srcGroupId=AQH_MsgEndpoint_GetGroupId(srcEp); + + ep=AQH_MsgEndpoint_List_First(emgr->endpointList); + while(ep) { + uint32_t acceptedGroupIds; + uint32_t acceptedMsgGroups; + + acceptedGroupIds=AQH_MsgEndpoint_GetAcceptedMsgGroups(ep); + acceptedMsgGroups=AQH_MsgEndpoint_GetAcceptedMsgGroups(ep); + + if ( + !(AQH_MsgEndpoint_GetFlags(ep) & AQH_MSG_ENDPOINT_FLAGS_NOMESSAGES) && + (acceptedMsgGroups & msgGroup) && + (acceptedGroupIds & srcGroupId) + ) { + /* endpoint accepts this message */ + AQH_MsgEndpoint_AddSendMessage(ep, AQH_Msg_dup(msg)); + } + ep=AQH_MsgEndpoint_List_Next(ep); + } +} + + + +void _handleAdminMsg(AQH_MSG_ENDPOINT_MGR *emgr, AQH_MSG_ENDPOINT *ep, const AQH_MSG *msg) +{ + uint8_t mt; + + mt=AQH_Msg_GetMsgType(msg); + switch(mt) { + case AQH_MSG_TYPE_NET_SET_ACCEPTED_MSGGROUPS: + _handleMsgSetAcceptedMsgGroups(emgr, ep, msg); + break; + default: + break; + } +} + + + +void _handleMsgSetAcceptedMsgGroups(AQH_MSG_ENDPOINT_MGR *emgr, AQH_MSG_ENDPOINT *ep, const AQH_MSG *msg) +{ + AQH_MsgEndpoint_SetAcceptedMsgGroups(ep, AQH_MsgSetAcceptedMsgGroups_GetMsgGroups(msg)); +} + + + +uint32_t _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: + return AQH_MSG_ENDPOINT_MSGGROUP_INFO; + case AQH_MSG_TYPE_VALUE: + return AQH_MSG_ENDPOINT_MSGGROUP_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_ENDPOINT_MSGGROUP_ADDRESS; + case AQH_MSG_TYPE_NET_SET_ACCEPTED_MSGGROUPS: + return AQH_MSG_ENDPOINT_MSGGROUP_ADMIN; + default: + return 0; + } +} + + + + + + diff --git a/aqhome/msgendpointmanager.h b/aqhome/msgendpointmanager.h new file mode 100644 index 0000000..54ee800 --- /dev/null +++ b/aqhome/msgendpointmanager.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQH_MSGENDPOINT_MGR_H +#define AQH_MSGENDPOINT_MGR_H + + +typedef struct AQH_MSG_ENDPOINT_MGR AQH_MSG_ENDPOINT_MGR; + + +#include + +#include "aqhome/msg.h" +#include "aqhome/msgendpoint.h" + +#include + + + +AQHOME_API AQH_MSG_ENDPOINT_MGR *AQH_MsgEndpointMgr_new(uint8_t busAddr); +AQHOME_API void AQH_MsgEndpointMgr_free(AQH_MSG_ENDPOINT_MGR *emgr); + +AQHOME_API uint8_t AQH_MsgEndpointMgr_GetBusAddr(const AQH_MSG_ENDPOINT_MGR *emgr); + +AQHOME_API AQH_MSG_ENDPOINT_LIST *AQH_MsgEndpointMgr_GetEndpointList(const AQH_MSG_ENDPOINT_MGR *emgr); + +AQHOME_API void AQH_MsgEndpointMgr_AddEndpoint(AQH_MSG_ENDPOINT_MGR *emgr, AQH_MSG_ENDPOINT *ep); +AQHOME_API void AQH_MsgEndpointMgr_DelEndpoint(AQH_MSG_ENDPOINT_MGR *emgr, AQH_MSG_ENDPOINT *ep); + +AQHOME_API int AQH_MsgEndpointMgr_LoopOnce(AQH_MSG_ENDPOINT_MGR *emgr); + + + + +#endif + diff --git a/aqhome/msgendpointmanager_p.h b/aqhome/msgendpointmanager_p.h new file mode 100644 index 0000000..67d03b2 --- /dev/null +++ b/aqhome/msgendpointmanager_p.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQH_MSGENDPOINT_MGR_P_H +#define AQH_MSGENDPOINT_MGR_P_H + + +#include "aqhome/msgendpointmanager.h" + + + + +struct AQH_MSG_ENDPOINT_MGR { + uint8_t busAddr; + AQH_MSG_ENDPOINT_LIST *endpointList; +}; + + + + +#endif + diff --git a/aqhome/msgendpointtcp.c b/aqhome/msgendpointtcp.c new file mode 100644 index 0000000..482fc9a --- /dev/null +++ b/aqhome/msgendpointtcp.c @@ -0,0 +1,222 @@ +/**************************************************************************** + * 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/msgendpointtcp.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +#define AQH_MSG_ENDPOINTTCP_BACKLOG 10 + + + +static int _setupListeningSocket(const char *host, int port); +static int _setSocketNonBlocking(int fd); +static int _getReadFd(AQH_MSG_ENDPOINT *ep); +static int _getWriteFd(AQH_MSG_ENDPOINT *ep); +static int _handleReadable(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_MGR *emgr); +static int _handleWritable(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_MGR *emgr); + + + + + +AQH_MSG_ENDPOINT *AQH_MsgEndpointTcp_new(const char *host, int port) +{ + int fd; + AQH_MSG_ENDPOINT *ep; + + fd=_setupListeningSocket(host, port); + if (fd<0) { + DBG_INFO(NULL, "here"); + return NULL; + } + + ep=AQH_MsgEndpoint_new(fd, AQH_MSG_ENDPOINT_ENDPOINTGROUP_NET); + AQH_MsgEndpoint_SetAcceptedEndpointGroups(ep, AQH_MSG_ENDPOINT_ENDPOINTGROUP_BUS); + AQH_MsgEndpoint_AddFlags(ep, AQH_MSG_ENDPOINT_FLAGS_NOMESSAGES); + + AQH_MsgEndpoint_SetHandleReadableFn(ep, _handleReadable); + AQH_MsgEndpoint_SetHandleWritableFn(ep, _handleWritable); + AQH_MsgEndpoint_SetGetReadFdFn(ep, _getReadFd); + AQH_MsgEndpoint_SetGetWriteFdFn(ep, _getWriteFd); + + return ep; +} + + + +int _setupListeningSocket(const char *host, int port) +{ + struct sockaddr_in addr; + int rv; + int sk; + int i; + + memset(&addr, 0, sizeof(addr)); + addr.sin_port=htons(port); + addr.sin_family=AF_INET; + + if (inet_aton(host, &(addr.sin_addr))==0) { + /* bad address */ + } + + sk=socket(AF_INET, SOCK_STREAM, 0); + if (sk<0) { + /* socket error */ + DBG_ERROR(NULL, "socket(): %s", strerror(errno)); + } + + i=1; + rv=setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)); + if (rv<0) { + DBG_ERROR(NULL, "setsockopt(): %s", strerror(errno)); + close(sk); + return GWEN_ERROR_IO; + } + + rv=_setSocketNonBlocking(sk); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + close(sk); + return rv; + } + + + rv=bind(sk, (struct sockaddr*) &addr, sizeof(addr)); + if (rv<0) { + DBG_ERROR(NULL, "bind(): %s", strerror(errno)); + close(sk); + return GWEN_ERROR_IO; + } + + rv=listen(sk, AQH_MSG_ENDPOINTTCP_BACKLOG); + if (rv<0) { + DBG_ERROR(NULL, "listen(): %s", strerror(errno)); + close(sk); + return GWEN_ERROR_IO; + } + + return sk; +} + + + +int _setSocketNonBlocking(int fd) +{ + int prevFlags; + int newFlags; + + /* get current socket flags */ + prevFlags=fcntl(fd, F_GETFL); + if (prevFlags==-1) { + DBG_ERROR(NULL, "fcntl(): %s", strerror(errno)); + return GWEN_ERROR_IO; + } + + /* set nonblocking/blocking */ + newFlags=prevFlags|O_NONBLOCK; + + if (-1==fcntl(fd, F_SETFL, newFlags)) { + DBG_ERROR(NULL, "fcntl(): %s", strerror(errno)); + return GWEN_ERROR_IO; + } + + return 0; +} + + + + +int _getReadFd(AQH_MSG_ENDPOINT *ep) +{ + return AQH_MsgEndpoint_GetFd(ep); +} + + + +int _getWriteFd(AQH_MSG_ENDPOINT *ep) +{ + return -1; +} + + + +int _handleReadable(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_MGR *emgr) +{ + int fd; + int newSock; + int rv; + struct sockaddr_in clientAddr; + socklen_t len; + AQH_MSG_ENDPOINT *newEp; + + fd=AQH_MsgEndpoint_GetFd(ep); + memset(&clientAddr, 0, sizeof(clientAddr)); + do { + len=sizeof(clientAddr); + rv=accept(fd, (struct sockaddr*) &clientAddr, &len); + } while(rv<0 && errno==EINTR); + if (rv<0) { + if (errno==EAGAIN || errno==EWOULDBLOCK) + return GWEN_ERROR_TRY_AGAIN; + DBG_ERROR(NULL, "Error on accept(): %s (%d)", strerror(errno), errno); + return GWEN_ERROR_IO; + } + newSock=rv; + + rv=_setSocketNonBlocking(newSock); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + close(newSock); + return rv; + } + + newEp=AQH_MsgEndpoint_new(newSock, AQH_MsgEndpoint_GetGroupId(ep)); + AQH_MsgEndpoint_SetFlags(newEp, AQH_MsgEndpoint_GetFlags(ep)); + AQH_MsgEndpoint_SubFlags(newEp, AQH_MSG_ENDPOINT_FLAGS_NOMESSAGES); + AQH_MsgEndpoint_SetAcceptedMsgGroups(newEp, AQH_MsgEndpoint_GetAcceptedMsgGroups(ep)); + AQH_MsgEndpoint_SetAcceptedEndpointGroups(newEp, AQH_MsgEndpoint_GetAcceptedEndpointGroups(ep)); + + AQH_MsgEndpointMgr_AddEndpoint(emgr, newEp); + return 0; +} + + + +int _handleWritable(AQH_MSG_ENDPOINT *ep, AQH_MSG_ENDPOINT_MGR *emgr) +{ + /* should not get called */ + return GWEN_ERROR_INVALID; +} + + + + + + + diff --git a/aqhome/msgendpointtcp.h b/aqhome/msgendpointtcp.h new file mode 100644 index 0000000..cb0732c --- /dev/null +++ b/aqhome/msgendpointtcp.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQH_MSGENDPOINT_TCP_H +#define AQH_MSGENDPOINT_TCP_H + + +#include + +#include "aqhome/msgendpoint.h" + +#include +#include + + +AQHOME_API AQH_MSG_ENDPOINT *AQH_MsgEndpointTcp_new(const char *host, int port); + + + + +#endif + diff --git a/aqhome/msgendpointtty.c b/aqhome/msgendpointtty.c new file mode 100644 index 0000000..a6b1a21 --- /dev/null +++ b/aqhome/msgendpointtty.c @@ -0,0 +1,270 @@ +/**************************************************************************** + * 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/msgendpointtty_p.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + + +#define AQH_MSG_ENDPOINT_TTY_BAUDRATE B19200 +#define AQH_MSG_ENDPOINT_TTY_BYTE_MICROSECS 520 + + + +GWEN_INHERIT(AQH_MSG_ENDPOINT, AQH_MSG_ENDPOINT_TTY) + + +static void GWENHYWFAR_CB _freeData(void *bp, void *p); + +static int _startMsg(AQH_MSG_ENDPOINT *ep); +static int _endMsg(AQH_MSG_ENDPOINT *ep); +static int _checkMsg(AQH_MSG_ENDPOINT *ep); + +static int _setupDevice(AQH_MSG_ENDPOINT *ep); +static int _attnLow(AQH_MSG_ENDPOINT *ep); +static int _attnHigh(AQH_MSG_ENDPOINT *ep); +static int _isAttnLow(AQH_MSG_ENDPOINT *ep); + + + + + + +AQH_MSG_ENDPOINT *AQH_MsgEndpointTty_new(const char *deviceName) +{ + AQH_MSG_ENDPOINT *ep; + AQH_MSG_ENDPOINT_TTY *xep; + int fd; + int rv; + + fd=open(deviceName, O_NOCTTY | O_NDELAY | O_RDWR); + if (fd<0) { + DBG_ERROR(NULL, "Error on open(%s): %s (%d)", deviceName, strerror(errno), errno); + return NULL; + } + + ep=AQH_MsgEndpoint_new(fd, AQH_MSG_ENDPOINT_ENDPOINTGROUP_BUS); + AQH_MsgEndpoint_SetAcceptedEndpointGroups(ep, AQH_MSG_ENDPOINT_ENDPOINTGROUP_NET); + + GWEN_NEW_OBJECT(AQH_MSG_ENDPOINT_TTY, xep); + GWEN_INHERIT_SETDATA(AQH_MSG_ENDPOINT, AQH_MSG_ENDPOINT_TTY, ep, xep, _freeData); + xep->deviceName=strdup(deviceName); + _attnHigh(ep); + + AQH_MsgEndpoint_SetStartMsgFn(ep, _startMsg); + AQH_MsgEndpoint_SetEndMsgFn(ep, _endMsg); + AQH_MsgEndpoint_SetCheckMsgFn(ep, _checkMsg); + + rv=_setupDevice(ep); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + AQH_MsgEndpoint_free(ep); + return NULL; + } + + return ep; +} + + + +void _freeData(void *bp, void *p) +{ + AQH_MSG_ENDPOINT *ep; + AQH_MSG_ENDPOINT_TTY *xep; + int fd; + + ep=(AQH_MSG_ENDPOINT*) bp; + xep=(AQH_MSG_ENDPOINT_TTY*) p; + fd=AQH_MsgEndpoint_GetFd(ep); + if (fd>=0) + tcsetattr(fd, TCSANOW, &xep->previousOptions); + free(xep->deviceName); + GWEN_FREE_OBJECT(xep); +} + + + +int _startMsg(AQH_MSG_ENDPOINT *ep) +{ + AQH_MSG_ENDPOINT_TTY *xep; + + xep=GWEN_INHERIT_GETDATA(AQH_MSG_ENDPOINT, AQH_MSG_ENDPOINT_TTY, ep); + if (xep->intendedAttnState==1) { + int rv; + + rv=_attnLow(ep); + if (rv<0) { + DBG_ERROR(NULL, "here (%d)", rv); + return rv; + } + usleep(AQH_MSG_ENDPOINT_TTY_BYTE_MICROSECS/5); + } + + return 0; +} + + + +int _endMsg(AQH_MSG_ENDPOINT *ep) +{ + _attnHigh(ep); +} + + + +int _checkMsg(AQH_MSG_ENDPOINT *ep) +{ + return _isAttnLow(ep); +} + + + +int _setupDevice(AQH_MSG_ENDPOINT *ep) +{ + AQH_MSG_ENDPOINT_TTY *xep; + int fd; + int status; + int i; + struct termios options; + int rv; + int m; + + xep=GWEN_INHERIT_GETDATA(AQH_MSG_ENDPOINT, AQH_MSG_ENDPOINT_TTY, ep); + fd=AQH_MsgEndpoint_GetFd(ep); + rv=tcgetattr(fd, &(xep->previousOptions)); + if (rv<0) { + DBG_ERROR(NULL, "Error on tcgetattr(%s): %s (%d)", xep->deviceName, strerror(errno), errno); + return GWEN_ERROR_IO; + } + memset(&options, 0, sizeof(options)); /* preset */ + + options.c_cflag=CLOCAL | CREAD | CS8; + options.c_iflag=IGNPAR | IGNBRK; + options.c_oflag=0; + options.c_lflag=0; + cfmakeraw(&options); + options.c_cc[VTIME]=0; /* read timeout in deciseconds */ + options.c_cc[VMIN]=0; /* no minimum number of receive bytes */ + + rv=cfsetispeed(&options, AQH_MSG_ENDPOINT_TTY_BAUDRATE); + if (rv<0) { + DBG_ERROR(NULL, "Error on cfsetispeed(%s): %s (%d)", xep->deviceName, strerror(errno), errno); + return GWEN_ERROR_IO; + } + rv=cfsetospeed(&options, AQH_MSG_ENDPOINT_TTY_BAUDRATE); + if (rv<0) { + DBG_ERROR(NULL, "Error on cfsetospeed(%s): %s (%d)", xep->deviceName, strerror(errno), errno); + return GWEN_ERROR_IO; + } + + rv=tcflush(fd, TCIOFLUSH); + if (rv<0) { + DBG_ERROR(NULL, "Error on tcflush(%s): %s (%d)", xep->deviceName, strerror(errno), errno); + return GWEN_ERROR_IO; + } + + rv=tcsetattr(fd, TCSANOW, &options); + if (rv<0) { + DBG_ERROR(NULL, "Error on tcsetattr(%s): %s (%d)", xep->deviceName, strerror(errno), errno); + return GWEN_ERROR_IO; + } + + _attnHigh(ep); + + return 0; +} + + + +int _attnLow(AQH_MSG_ENDPOINT *ep) +{ + AQH_MSG_ENDPOINT_TTY *xep; + int status; + int rv; + int fd; + + xep=GWEN_INHERIT_GETDATA(AQH_MSG_ENDPOINT, AQH_MSG_ENDPOINT_TTY, ep); + fd=AQH_MsgEndpoint_GetFd(ep); + rv=ioctl(fd, TIOCMGET, &status); /* GET the State of MODEM bits in Status */ + if (rv<0) { + DBG_ERROR(NULL, "Error on ioctl(%s): %s (%d)", xep->deviceName, strerror(errno), errno); + return GWEN_ERROR_IO; + } + status |= TIOCM_DTR | TIOCM_RTS; /* clear the DTR pin (cave: signals inverted!) */ + rv=ioctl(fd, TIOCMSET, &status); + if (rv<0) { + DBG_ERROR(NULL, "Error on ioctl(%s): %s (%d)", xep->deviceName, strerror(errno), errno); + return GWEN_ERROR_IO; + } + xep->intendedAttnState=0; + return 0; +} + + + +int _attnHigh(AQH_MSG_ENDPOINT *ep) +{ + AQH_MSG_ENDPOINT_TTY *xep; + int status; + int rv; + int fd; + + xep=GWEN_INHERIT_GETDATA(AQH_MSG_ENDPOINT, AQH_MSG_ENDPOINT_TTY, ep); + fd=AQH_MsgEndpoint_GetFd(ep); + rv=ioctl(fd, TIOCMGET, &status); + if (rv<0) { + DBG_ERROR(NULL, "Error on ioctl(%s): %s (%d)", xep->deviceName, strerror(errno), errno); + return GWEN_ERROR_IO; + } + status |= TIOCM_DTR; /* Set the DTR pin */ + status &= ~ (TIOCM_DTR | TIOCM_RTS); /* clear the DTR pin (cave: signals inverted!) */ + rv=ioctl(fd, TIOCMSET, &status); + if (rv<0) { + DBG_ERROR(NULL, "Error on ioctl(%s): %s (%d)", xep->deviceName, strerror(errno), errno); + return GWEN_ERROR_IO; + } + + xep->intendedAttnState=1; + return 0; +} + + + +int _isAttnLow(AQH_MSG_ENDPOINT *ep) +{ + AQH_MSG_ENDPOINT_TTY *xep; + int status; + int rv; + int fd; + + xep=GWEN_INHERIT_GETDATA(AQH_MSG_ENDPOINT, AQH_MSG_ENDPOINT_TTY, ep); + fd=AQH_MsgEndpoint_GetFd(ep); + rv=ioctl(fd, TIOCMGET, &status); + if (rv<0) { + DBG_ERROR(NULL, "Error on ioctl(%s): %s (%d)", xep->deviceName, strerror(errno), errno); + return GWEN_ERROR_IO; + } + //return (status & TIOCM_CTS)?1:0; + return (status & TIOCM_CTS)?1:0; +} + + + diff --git a/aqhome/msgendpointtty.h b/aqhome/msgendpointtty.h new file mode 100644 index 0000000..ec23c4a --- /dev/null +++ b/aqhome/msgendpointtty.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQH_MSGENDPOINT_TTY_H +#define AQH_MSGENDPOINT_TTY_H + + +#include + +#include "aqhome/msgendpoint.h" + +#include +#include + + +AQHOME_API AQH_MSG_ENDPOINT *AQH_MsgEndpointTty_new(const char *devName); + + + + +#endif + diff --git a/aqhome/msgendpointtty_p.h b/aqhome/msgendpointtty_p.h new file mode 100644 index 0000000..71ec424 --- /dev/null +++ b/aqhome/msgendpointtty_p.h @@ -0,0 +1,30 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQH_MSGENDPOINT_TTY_P_H +#define AQH_MSGENDPOINT_TTY_P_H + + +#include "aqhome/msgendpointtty.h" + +#include + + + +typedef struct AQH_MSG_ENDPOINT_TTY AQH_MSG_ENDPOINT_TTY; +struct AQH_MSG_ENDPOINT_TTY { + char *deviceName; + struct termios previousOptions; + int intendedAttnState; +}; + + + + +#endif +