More work on node/pc interface.

- added AQH_MSG_ENDPOINT
- added AQH_MsgEndpointLog
- added AQH_MsgEndpointTcp
- added AQH_MsgEndpointTty
- added AQH_MsgEndpointMgr
This commit is contained in:
Martin Preuss
2023-02-20 23:45:10 +01:00
parent e1bf53e93f
commit caa85edfc6
20 changed files with 2104 additions and 6 deletions

View File

@@ -57,6 +57,16 @@
msg_haveaddr.h msg_haveaddr.h
msg_claimaddr.h msg_claimaddr.h
msg_denyaddr.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
</headers> </headers>
@@ -72,6 +82,12 @@
msg_haveaddr.c msg_haveaddr.c
msg_claimaddr.c msg_claimaddr.c
msg_denyaddr.c msg_denyaddr.c
msg_setaccmsggrps.c
msgendpoint.c
msgendpointtcp.c
msgendpointtty.c
msgendpointlog.c
msgendpointmanager.c
</sources> </sources>
<useTargets> <useTargets>

View File

@@ -32,7 +32,7 @@ int testRecv()
fprintf(stdout, "Opening device...\n"); fprintf(stdout, "Opening device...\n");
sr=AQH_Serial_new("/dev/ttyUSB0", 240); sr=AQH_Serial_new("/dev/ttyUSB0", 240);
rv=AQH_Serial_Open(sr); rv=AQH_Serial_Open(sr, AQH_SerialReadWriteMode_ReadOnly);
if (rv<0) { if (rv<0) {
DBG_ERROR(NULL, "ERROR opening device (%d)", rv); DBG_ERROR(NULL, "ERROR opening device (%d)", rv);
AQH_Serial_free(sr); AQH_Serial_free(sr);
@@ -77,7 +77,7 @@ int testSend()
fprintf(stdout, "Opening device...\n"); fprintf(stdout, "Opening device...\n");
sr=AQH_Serial_new("/dev/ttyUSB0", 240); sr=AQH_Serial_new("/dev/ttyUSB0", 240);
rv=AQH_Serial_Open(sr); rv=AQH_Serial_Open(sr, AQH_SerialReadWriteMode_ReadWrite);
if (rv<0) { if (rv<0) {
DBG_ERROR(NULL, "ERROR opening device (%d)", rv); DBG_ERROR(NULL, "ERROR opening device (%d)", rv);
AQH_Serial_free(sr); AQH_Serial_free(sr);
@@ -268,7 +268,7 @@ int testLoop()
fprintf(stdout, "Opening device...\n"); fprintf(stdout, "Opening device...\n");
sr=AQH_Serial_new("/dev/ttyUSB0", 240); sr=AQH_Serial_new("/dev/ttyUSB0", 240);
rv=AQH_Serial_Open(sr); rv=AQH_Serial_Open(sr, AQH_SerialReadWriteMode_ReadWrite);
if (rv<0) { if (rv<0) {
DBG_ERROR(NULL, "ERROR opening device (%d)", rv); DBG_ERROR(NULL, "ERROR opening device (%d)", rv);
AQH_Serial_free(sr); AQH_Serial_free(sr);
@@ -335,10 +335,60 @@ int testLoop()
int testReadLoop()
int main(void)
{ {
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 testRecv();
//return testSend(); //return testSend();
return testLoop(); return testLoop();

View File

@@ -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) uint8_t *AQH_Msg_GetBuffer(AQH_MSG *msg)
{ {
if (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) uint8_t _calcChecksum(const uint8_t *ptr, uint8_t len)
{ {
int i; int i;

View File

@@ -15,6 +15,7 @@
#include <aqhome/api.h> #include <aqhome/api.h>
#include <gwenhywfar/list.h> #include <gwenhywfar/list.h>
#include <gwenhywfar/buffer.h>
@@ -39,6 +40,9 @@
#define AQH_MSG_TYPE_DENY_ADDRESS 63 #define AQH_MSG_TYPE_DENY_ADDRESS 63
#define AQH_MSG_TYPE_ADDRESS_RANGE 64 #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 AQH_MSG *AQH_Msg_new();
AQHOME_API void AQH_Msg_free(AQH_MSG *msg); 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 uint8_t *AQH_Msg_GetBuffer(AQH_MSG *msg);
AQHOME_API const uint8_t *AQH_Msg_GetConstBuffer(const 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_IsChecksumValid(const AQH_MSG *msg);
AQHOME_API int AQH_Msg_AddChecksum(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 #endif

View File

@@ -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 <config.h>
#endif
#include "aqhome/msg_setaccmsggrps.h"
#include <gwenhywfar/misc.h>
#include <gwenhywfar/list.h>
#include <gwenhywfar/error.h>
#include <gwenhywfar/debug.h>
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));
}
}

View File

@@ -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 <aqhome/api.h>
#include "aqhome/msg.h"
#include <gwenhywfar/list.h>
#include <gwenhywfar/buffer.h>
#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

555
aqhome/msgendpoint.c Normal file
View File

@@ -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 <config.h>
#endif
#include "aqhome/msgendpoint_p.h"
#include <gwenhywfar/misc.h>
#include <gwenhywfar/list.h>
#include <gwenhywfar/error.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/text.h>
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#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; i<len; i++) {
if (ep->currentlyReceivedMsg==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;
}

125
aqhome/msgendpoint.h Normal file
View File

@@ -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 <aqhome/api.h>
#include "aqhome/msg.h"
#include <gwenhywfar/list.h>
#include <gwenhywfar/inherit.h>
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 <gwenhywfar/buffer.h>
#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

51
aqhome/msgendpoint_p.h Normal file
View File

@@ -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 <aqhome/api.h>
#include "aqhome/msgendpoint.h"
#include <gwenhywfar/list.h>
#include <gwenhywfar/buffer.h>
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

155
aqhome/msgendpointlog.c Normal file
View File

@@ -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 <config.h>
#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 <gwenhywfar/list.h>
#include <gwenhywfar/inherit.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/gwentime.h>
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);
}
}
}

27
aqhome/msgendpointlog.h Normal file
View File

@@ -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 <aqhome/api.h>
#include "aqhome/msgendpoint.h"
#include <gwenhywfar/list.h>
#include <gwenhywfar/inherit.h>
AQHOME_API AQH_MSG_ENDPOINT *AQH_MsgEndpointLog_new(const char *filename);
#endif

25
aqhome/msgendpointlog_p.h Normal file
View File

@@ -0,0 +1,25 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef 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

307
aqhome/msgendpointmanager.c Normal file
View File

@@ -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 <config.h>
#endif
#include "aqhome/msgendpointmanager_p.h"
#include "aqhome/msg_setaccmsggrps.h"
#include <gwenhywfar/misc.h>
#include <gwenhywfar/list.h>
#include <gwenhywfar/error.h>
#include <gwenhywfar/debug.h>
#include <errno.h>
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;
}
}

View File

@@ -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 <aqhome/api.h>
#include "aqhome/msg.h"
#include "aqhome/msgendpoint.h"
#include <gwenhywfar/list.h>
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

View File

@@ -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

222
aqhome/msgendpointtcp.c Normal file
View File

@@ -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 <config.h>
#endif
#include "aqhome/msgendpointtcp.h"
#include <gwenhywfar/list.h>
#include <gwenhywfar/inherit.h>
#include <gwenhywfar/debug.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#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;
}

27
aqhome/msgendpointtcp.h Normal file
View File

@@ -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 <aqhome/api.h>
#include "aqhome/msgendpoint.h"
#include <gwenhywfar/list.h>
#include <gwenhywfar/inherit.h>
AQHOME_API AQH_MSG_ENDPOINT *AQH_MsgEndpointTcp_new(const char *host, int port);
#endif

270
aqhome/msgendpointtty.c Normal file
View File

@@ -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 <config.h>
#endif
#include "aqhome/msgendpointtty_p.h"
#include <gwenhywfar/list.h>
#include <gwenhywfar/inherit.h>
#include <gwenhywfar/debug.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <unistd.h>
#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;
}

27
aqhome/msgendpointtty.h Normal file
View File

@@ -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 <aqhome/api.h>
#include "aqhome/msgendpoint.h"
#include <gwenhywfar/list.h>
#include <gwenhywfar/inherit.h>
AQHOME_API AQH_MSG_ENDPOINT *AQH_MsgEndpointTty_new(const char *devName);
#endif

30
aqhome/msgendpointtty_p.h Normal file
View File

@@ -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 <termios.h>
typedef struct AQH_MSG_ENDPOINT_TTY AQH_MSG_ENDPOINT_TTY;
struct AQH_MSG_ENDPOINT_TTY {
char *deviceName;
struct termios previousOptions;
int intendedAttnState;
};
#endif