From 39987b31c70d981269fe218fd9aab93d738c6e7d Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Wed, 12 Jul 2023 01:45:24 +0200 Subject: [PATCH] aqhome: re-implemented aqhomed. - added IPC endpoint2 --- apps/aqhomed/0BUILD | 15 + apps/aqhomed/aqhomed.c | 184 +++++++++++ apps/aqhomed/aqhomed.h | 48 +++ apps/aqhomed/aqhomed_p.h | 50 +++ apps/aqhomed/db.c | 278 ++++++++++++++++ apps/aqhomed/db.h | 23 ++ apps/aqhomed/fini.c | 85 +++++ apps/aqhomed/fini.h | 23 ++ apps/aqhomed/init.c | 519 +++++++++++++++++++++++++++++ apps/aqhomed/init.h | 23 ++ apps/aqhomed/loop.c | 168 ++++++++++ apps/aqhomed/loop.h | 23 ++ apps/aqhomed/main.c | 605 +++------------------------------- apps/aqhomed/tty_log.c | 131 ++++++++ apps/aqhomed/tty_log.h | 23 ++ apps/aqhomed/tty_write.c | 225 +++++++++++++ apps/aqhomed/tty_write.h | 23 ++ aqhome/ipc/0BUILD | 3 + aqhome/ipc/endpoint2_ipc.c | 139 ++++++++ aqhome/ipc/endpoint2_ipc.h | 31 ++ aqhome/ipc/endpoint2_ipc_p.h | 38 +++ aqhome/mqtt/endpoint2_mqttc.c | 28 ++ aqhome/mqtt/endpoint2_mqttc.h | 3 + aqhome/msg/endpoint2_tty.c | 14 +- aqhome/msg/endpoint2_tty.h | 2 +- 25 files changed, 2140 insertions(+), 564 deletions(-) create mode 100644 apps/aqhomed/aqhomed.c create mode 100644 apps/aqhomed/aqhomed.h create mode 100644 apps/aqhomed/aqhomed_p.h create mode 100644 apps/aqhomed/db.c create mode 100644 apps/aqhomed/db.h create mode 100644 apps/aqhomed/fini.c create mode 100644 apps/aqhomed/fini.h create mode 100644 apps/aqhomed/init.c create mode 100644 apps/aqhomed/init.h create mode 100644 apps/aqhomed/loop.c create mode 100644 apps/aqhomed/loop.h create mode 100644 apps/aqhomed/tty_log.c create mode 100644 apps/aqhomed/tty_log.h create mode 100644 apps/aqhomed/tty_write.c create mode 100644 apps/aqhomed/tty_write.h create mode 100644 aqhome/ipc/endpoint2_ipc.c create mode 100644 aqhome/ipc/endpoint2_ipc.h create mode 100644 aqhome/ipc/endpoint2_ipc_p.h diff --git a/apps/aqhomed/0BUILD b/apps/aqhomed/0BUILD index 9b5043f..c5fc923 100644 --- a/apps/aqhomed/0BUILD +++ b/apps/aqhomed/0BUILD @@ -33,11 +33,26 @@ + aqhomed.h + aqhomed_p.h + init.h + fini.h + loop.h + db.h + tty_log.h + tty_write.h $(local/typefiles) main.c + aqhomed.c + init.c + fini.c + loop.c + db.c + tty_log.c + tty_write.c diff --git a/apps/aqhomed/aqhomed.c b/apps/aqhomed/aqhomed.c new file mode 100644 index 0000000..2d10c68 --- /dev/null +++ b/apps/aqhomed/aqhomed.c @@ -0,0 +1,184 @@ +/**************************************************************************** + * 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 "./aqhomed_p.h" +#include "./tty_log.h" +#include "./tty_write.h" + +#include "aqhome/msg/endpoint2_tty.h" +#include "aqhome/ipc/endpoint2_ipc.h" +#include "aqhome/mqtt/endpoint2_mqttc.h" + +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define I18N(msg) msg +#define I18S(msg) msg + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +AQHOMED *AqHomed_new(void) +{ + AQHOMED *aqh; + + GWEN_NEW_OBJECT(AQHOMED, aqh); + aqh->rootEndpoint=GWEN_MsgEndpoint2_new("root", 0); + aqh->nodeDb=AQH_NodeDb_new(); + + return aqh; +} + + + +void AqHomed_free(AQHOMED *aqh) +{ + if (aqh) { + GWEN_MsgEndpoint2_free(aqh->rootEndpoint); + aqh->rootEndpoint=NULL; + aqh->ttyEndpoint=NULL; + aqh->ipcdEndpoint=NULL; + aqh->mqttEndpoint=NULL; + GWEN_DB_Group_free(aqh->dbArgs); + AQH_NodeDb_free(aqh->nodeDb); + aqh->dbArgs=NULL; + free(aqh->logFile); + free(aqh->writeFolder); + free(aqh->pidFile); + free(aqh->dbFile); + + GWEN_FREE_OBJECT(aqh); + } +} + + + +GWEN_MSG_ENDPOINT2 *AqHomed_GetTtyEndpoint(const AQHOMED *aqh) +{ + return aqh?aqh->ttyEndpoint:NULL; +} + + + +GWEN_MSG_ENDPOINT2 *AqHomed_GetIpcdEndpoint(const AQHOMED *aqh) +{ + return aqh?aqh->ipcdEndpoint:NULL; +} + + + +GWEN_MSG_ENDPOINT2 *AqHomed_GetMqttEndpoint(const AQHOMED *aqh) +{ + return aqh?aqh->mqttEndpoint:NULL; +} + + + +GWEN_DB_NODE *AqHomed_GetDbArgs(const AQHOMED *aqh) +{ + return aqh?aqh->dbArgs:NULL; +} + + + +const char *AqHomed_GetLogFile(const AQHOMED *aqh) +{ + return aqh?aqh->logFile:NULL; +} + + + +void AqHomed_SetLogFile(AQHOMED *aqh, const char *s) +{ + if (aqh) { + free(aqh->logFile); + aqh->logFile=s?strdup(s):NULL; + } +} + + + +const char *AqHomed_GetWriteFolder(const AQHOMED *aqh) +{ + return aqh?aqh->writeFolder:NULL; +} + + + +void AqHomed_SetWriteFolder(AQHOMED *aqh, const char *s) +{ + if (aqh) { + free(aqh->writeFolder); + aqh->writeFolder=s?strdup(s):NULL; + } +} + + + +const char *AqHomed_GetPidFile(const AQHOMED *aqh) +{ + return aqh?aqh->pidFile:NULL; +} + + + +void AqHomed_SetPidFile(AQHOMED *aqh, const char *s) +{ + if (aqh) { + free(aqh->pidFile); + aqh->pidFile=s?strdup(s):NULL; + } +} + + + +const char *AqHomed_GetDbFile(const AQHOMED *aqh) +{ + return aqh?aqh->dbFile:NULL; +} + + + +void AqHomed_SetDbFile(AQHOMED *aqh, const char *s) +{ + if (aqh) { + free(aqh->dbFile); + aqh->dbFile=s?strdup(s):NULL; + } +} + + + + + + + + diff --git a/apps/aqhomed/aqhomed.h b/apps/aqhomed/aqhomed.h new file mode 100644 index 0000000..c4e48c0 --- /dev/null +++ b/apps/aqhomed/aqhomed.h @@ -0,0 +1,48 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQHOMED_H +#define AQHOMED_H + + +#include +#include + + +#define AQHOME_ENDPOINTGROUP_NODE 1 +#define AQHOME_ENDPOINTGROUP_IPC 2 +#define AQHOME_ENDPOINTGROUP_MQTT 4 + + +typedef struct AQHOMED AQHOMED; + +AQHOMED *AqHomed_new(void); +void AqHomed_free(AQHOMED *aqh); + +GWEN_MSG_ENDPOINT2 *AqHomed_GetTtyEndpoint(const AQHOMED *aqh); +GWEN_MSG_ENDPOINT2 *AqHomed_GetIpcdEndpoint(const AQHOMED *aqh); +GWEN_MSG_ENDPOINT2 *AqHomed_GetMqttEndpoint(const AQHOMED *aqh); + +GWEN_DB_NODE *AqHomed_GetDbArgs(const AQHOMED *aqh); + +const char *AqHomed_GetLogFile(const AQHOMED *aqh); +void AqHomed_SetLogFile(AQHOMED *aqh, const char *s); + +const char *AqHomed_GetWriteFolder(const AQHOMED *aqh); +void AqHomed_SetWriteFolder(AQHOMED *aqh, const char *s); + +const char *AqHomed_GetPidFile(const AQHOMED *aqh); +void AqHomed_SetPidFile(AQHOMED *aqh, const char *s); + +const char *AqHomed_GetDbFile(const AQHOMED *aqh); +void AqHomed_SetDbFile(AQHOMED *aqh, const char *s); + + +#endif + + diff --git a/apps/aqhomed/aqhomed_p.h b/apps/aqhomed/aqhomed_p.h new file mode 100644 index 0000000..60c3258 --- /dev/null +++ b/apps/aqhomed/aqhomed_p.h @@ -0,0 +1,50 @@ +/**************************************************************************** + * 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 AQHOMED_P_H +#define AQHOMED_P_H + + +#include "./aqhomed.h" + +#include "aqhome/nodes/nodedb.h" + + +/* default values */ +#define AQHOMED_DEFAULT_NODEADDR 240 +#define AQHOMED_DEFAULT_PIDFILE "/var/run/aqhomed.pid" +#define AQHOMED_DEFAULT_DEVICE "/dev/ttyUSB0" +#define AQHOMED_DEFAULT_IPC_PORT 45454 +#define AQHOMED_DEFAULT_MQTT_CLIENTID "aqhomed" +#define AQHOMED_DEFAULT_MQTT_TOPIC_PREFIX "aqhome/sensors" +#define AQHOMED_DEFAULT_MQTT_KEEPALIVE 600 +#define AQHOMED_DEFAULT_MQTT_PORT 1883 + + + +struct AQHOMED { + GWEN_MSG_ENDPOINT2 *rootEndpoint; + + GWEN_MSG_ENDPOINT2 *ttyEndpoint; + GWEN_MSG_ENDPOINT2 *ipcdEndpoint; + GWEN_MSG_ENDPOINT2 *mqttEndpoint; + + AQH_NODE_DB *nodeDb; + + GWEN_DB_NODE *dbArgs; + + char *dbFile; + char *logFile; + char *writeFolder; + char *pidFile; + + int nodeAddress; +}; + +#endif + diff --git a/apps/aqhomed/db.c b/apps/aqhomed/db.c new file mode 100644 index 0000000..521ccc7 --- /dev/null +++ b/apps/aqhomed/db.c @@ -0,0 +1,278 @@ +/**************************************************************************** + * 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 "./db.h" +#include "./aqhomed_p.h" + +#include "aqhome/msg/msg_node.h" +#include "aqhome/msg/msg_sendstats.h" +#include "aqhome/msg/msg_recvstats.h" +#include "aqhome/msg/msg_value2.h" +#include "aqhome/msg/msg_needaddr.h" +#include "aqhome/msg/msg_claimaddr.h" +#include "aqhome/msg/msg_haveaddr.h" +#include "aqhome/msg/msg_device.h" +#include "aqhome/msg/msg_flashready.h" + + +#include +#include +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _handleMsgValue2(AQHOMED *aqh, const GWEN_MSG *msg); +static void _handleMsgNeedAddress(AQHOMED *aqh, const GWEN_MSG *msg); +static void _handleMsgClaimAddress(AQHOMED *aqh, const GWEN_MSG *msg); +static void _handleMsgHaveAddress(AQHOMED *aqh, const GWEN_MSG *msg); +static void _handleMsgComSendStat(AQHOMED *aqh, const GWEN_MSG *msg); +static void _handleMsgComRecvStat(AQHOMED *aqh, const GWEN_MSG *msg); +static void _handleMsgDevice(AQHOMED *aqh, const GWEN_MSG *msg); +static void _handleMsgFlashReady(AQHOMED *aqh, const GWEN_MSG *msg); + +static AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(AQHOMED *aqh, const GWEN_MSG *msg, uint32_t uid); +static void _updateTimestampLastChange(AQH_NODE_INFO *ni); + + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +void AqHomed_NodeMsgToDb(AQHOMED *aqh, const GWEN_MSG *msg) +{ + int msgIsValid; + uint8_t msgType; + + DBG_INFO(AQH_LOGDOMAIN, + " - msg %d (%s) from %d to %d", + AQH_NodeMsg_GetMsgType(msg), + AQH_NodeMsg_MsgTypeToChar(AQH_NodeMsg_GetMsgType(msg)), + AQH_NodeMsg_GetSourceAddress(msg), + AQH_NodeMsg_GetDestAddress(msg)); + + msgIsValid=(AQH_NodeMsg_IsChecksumValid(msg) && AQH_NodeMsg_IsMsgComplete(msg)); + msgType=AQH_NodeMsg_GetMsgType(msg); + + if (msgIsValid) { + switch(msgType) { + case AQH_MSG_TYPE_COMSENDSTATS: _handleMsgComSendStat(aqh, msg); break; + case AQH_MSG_TYPE_COMRECVSTATS: _handleMsgComRecvStat(aqh, msg); break; + case AQH_MSG_TYPE_VALUE2: _handleMsgValue2(aqh, msg); break; + case AQH_MSG_TYPE_NEED_ADDRESS: _handleMsgNeedAddress(aqh, msg); break; + case AQH_MSG_TYPE_CLAIM_ADDRESS: _handleMsgClaimAddress(aqh, msg); break; + case AQH_MSG_TYPE_HAVE_ADDRESS: _handleMsgHaveAddress(aqh, msg); break; + case AQH_MSG_TYPE_DEVICE: _handleMsgDevice(aqh, msg); break; + case AQH_MSG_TYPE_FLASH_READY: _handleMsgFlashReady(aqh, msg); break; + default: break; + } + } +} + + + +void _handleMsgValue2(AQHOMED *aqh, const GWEN_MSG *msg) +{ + AQH_NODE_INFO *ni; + uint32_t uid; + + uid=AQH_Value2Msg_GetUid(msg); + ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid); + if (ni==NULL) { + DBG_INFO(AQH_LOGDOMAIN, "Error handling message"); + } +} + + + +void _handleMsgNeedAddress(AQHOMED *aqh, const GWEN_MSG *msg) +{ + AQH_NODE_INFO *ni; + uint32_t uid; + + uid=AQH_NeedAddrMsg_GetUid(msg); + ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid); + if (ni==NULL) { + DBG_INFO(AQH_LOGDOMAIN, "Error handling message"); + } +} + + + +void _handleMsgClaimAddress(AQHOMED *aqh, const GWEN_MSG *msg) +{ + AQH_NODE_INFO *ni; + uint32_t uid; + + uid=AQH_ClaimAddrMsg_GetUid(msg); + ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid); + if (ni==NULL) { + DBG_INFO(AQH_LOGDOMAIN, "Error handling message"); + } +} + + + +void _handleMsgHaveAddress(AQHOMED *aqh, const GWEN_MSG *msg) +{ + AQH_NODE_INFO *ni; + uint32_t uid; + + uid=AQH_HaveAddrMsg_GetUid(msg); + ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid); + if (ni==NULL) { + DBG_INFO(AQH_LOGDOMAIN, "Error handling message"); + } +} + + + +void _handleMsgComSendStat(AQHOMED *aqh, const GWEN_MSG *msg) +{ + AQH_NODE_INFO *ni; + uint32_t uid; + + uid=AQH_SendStatsMsg_GetUid(msg); + ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid); + if (ni==NULL) { + DBG_INFO(AQH_LOGDOMAIN, "Error handling message"); + } + AQH_NodeInfo_SetStatsPacketsOut(ni, AQH_SendStatsMsg_GetPacketsOut(msg)); + AQH_NodeInfo_SetStatsCollisions(ni, AQH_SendStatsMsg_GetCollisions(msg)); + AQH_NodeInfo_SetStatsBusy(ni, AQH_SendStatsMsg_GetBusyErrors(msg)); + AQH_NodeDb_SetModified(aqh->nodeDb); + _updateTimestampLastChange(ni); +} + + + +void _handleMsgComRecvStat(AQHOMED *aqh, const GWEN_MSG *msg) +{ + AQH_NODE_INFO *ni; + uint32_t uid; + + uid=AQH_RecvStatsMsg_GetUid(msg); + ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid); + if (ni==NULL) { + DBG_INFO(AQH_LOGDOMAIN, "Error handling message"); + } + AQH_NodeInfo_SetStatsPacketsIn(ni, AQH_RecvStatsMsg_GetPacketsIn(msg)); + AQH_NodeInfo_SetStatsCrcErrors(ni, AQH_RecvStatsMsg_GetCrcErrors(msg)); + AQH_NodeInfo_SetStatsIoErrors(ni, AQH_RecvStatsMsg_GetIoErrors(msg)); + AQH_NodeDb_SetModified(aqh->nodeDb); + _updateTimestampLastChange(ni); +} + + + +void _handleMsgDevice(AQHOMED *aqh, const GWEN_MSG *msg) +{ + AQH_NODE_INFO *ni; + uint32_t uid; + + uid=AQH_DeviceMsg_GetUid(msg); + ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid); + if (ni) { + AQH_NodeInfo_SetFirmwareType(ni, AQH_DeviceMsg_GetFirmwareType(msg)); + AQH_NodeInfo_SetFirmwareVersion(ni, (AQH_DeviceMsg_GetFirmwareHigh(msg)<<8) | AQH_DeviceMsg_GetFirmwareLow(msg)); + AQH_NodeInfo_SetModules(ni, AQH_DeviceMsg_GetModuleMask(msg)); + _updateTimestampLastChange(ni); + AQH_NodeDb_SetModified(aqh->nodeDb); + } + else { + DBG_INFO(AQH_LOGDOMAIN, "Error handling message"); + } +} + + + +void _handleMsgFlashReady(AQHOMED *aqh, const GWEN_MSG *msg) +{ + AQH_NODE_INFO *ni; + uint32_t uid; + + uid=AQH_FlashReadyMsg_GetUid(msg); + ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid); + if (ni) { + AQH_NodeInfo_SetFirmwareType(ni, AQH_FlashReadyMsg_GetFirmwareType(msg)); + AQH_NodeInfo_SetFirmwareVersion(ni, AQH_FlashReadyMsg_GetFirmwareVersion(msg)); + _updateTimestampLastChange(ni); + AQH_NodeDb_SetModified(aqh->nodeDb); + } + else { + DBG_INFO(AQH_LOGDOMAIN, "Error handling message"); + } +} + + + +AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(AQHOMED *aqh, const GWEN_MSG *msg, uint32_t uid) +{ + uint8_t busAddr; + AQH_NODE_INFO *ni; + + busAddr=AQH_NodeMsg_GetSourceAddress(msg); + ni=AQH_NodeDb_GetNodeInfoByUid(aqh->nodeDb, uid); + if (ni) { + uint8_t storedBusAddr; + + storedBusAddr=AQH_NodeInfo_GetBusAddress(ni); + if (busAddr!=0 && storedBusAddr!=busAddr) { + DBG_INFO(AQH_LOGDOMAIN, "Changed busaddr for %08x from %02x to %02x", uid, storedBusAddr, busAddr); + AQH_NodeInfo_SetBusAddress(ni, busAddr); + _updateTimestampLastChange(ni); + AQH_NodeDb_SetModified(aqh->nodeDb); + } + } + else { + int rv; + + ni=AQH_NodeInfo_new(); + AQH_NodeInfo_SetBusAddress(ni, busAddr); + AQH_NodeInfo_SetUid(ni, uid); + _updateTimestampLastChange(ni); + rv=AQH_NodeDb_AddNodeInfo(aqh->nodeDb, ni); + if (rv<0) { + DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); + AQH_NodeInfo_free(ni); + return NULL; + } + else { + DBG_INFO(AQH_LOGDOMAIN, "Added node %08x (%02x)", uid, busAddr); + } + } + return ni; +} + + + +void _updateTimestampLastChange(AQH_NODE_INFO *ni) +{ + GWEN_TIMESTAMP *t; + + t=GWEN_Timestamp_NowInLocalTime(); + AQH_NodeInfo_SetTimestampLastChange(ni, t); + GWEN_Timestamp_free(t); +} + + + diff --git a/apps/aqhomed/db.h b/apps/aqhomed/db.h new file mode 100644 index 0000000..cdd5f01 --- /dev/null +++ b/apps/aqhomed/db.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * 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 AQHOMED_DB_H +#define AQHOMED_DB_H + + +#include "./aqhomed.h" + + + +void AqHomed_NodeMsgToDb(AQHOMED *aqh, const GWEN_MSG *msg); + + + +#endif + + diff --git a/apps/aqhomed/fini.c b/apps/aqhomed/fini.c new file mode 100644 index 0000000..50b27a6 --- /dev/null +++ b/apps/aqhomed/fini.c @@ -0,0 +1,85 @@ +/**************************************************************************** + * 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 "./fini.h" +#include "./aqhomed_p.h" + +#include +#include +#include +#include + + +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define I18N(msg) msg +#define I18S(msg) msg + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _disconnectTree(GWEN_MSG_ENDPOINT2 *ep); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +void AqHomed_Fini(AQHOMED *aqh) +{ + if (aqh) { + if (aqh->rootEndpoint) { + _disconnectTree(aqh->rootEndpoint); + GWEN_MsgEndpoint2_Disconnect(aqh->rootEndpoint); + } + aqh->rootEndpoint=NULL; + aqh->ttyEndpoint=NULL; + aqh->ipcdEndpoint=NULL; + aqh->mqttEndpoint=NULL; + + if (aqh->pidFile) + remove(aqh->pidFile); + } +} + + + +void _disconnectTree(GWEN_MSG_ENDPOINT2 *ep) +{ + GWEN_MSG_ENDPOINT2 *epChild; + + epChild=GWEN_MsgEndpoint2_Tree2_GetFirstChild(ep); + while(epChild) { + _disconnectTree(epChild); + epChild=GWEN_MsgEndpoint2_Tree2_GetNext(epChild); + } /* while */ + + GWEN_MsgEndpoint2_Disconnect(ep); +} + + + + diff --git a/apps/aqhomed/fini.h b/apps/aqhomed/fini.h new file mode 100644 index 0000000..4e41d91 --- /dev/null +++ b/apps/aqhomed/fini.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * 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 AQHOMED_FINI_H +#define AQHOMED_FINI_H + + +#include "./aqhomed.h" + + + +void AqHomed_Fini(AQHOMED *aqh); + + + +#endif + + diff --git a/apps/aqhomed/init.c b/apps/aqhomed/init.c new file mode 100644 index 0000000..7461657 --- /dev/null +++ b/apps/aqhomed/init.c @@ -0,0 +1,519 @@ +/**************************************************************************** + * 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 "./init.h" +#include "./aqhomed_p.h" +#include "./tty_log.h" +#include "./tty_write.h" + +#include "aqhome/msg/endpoint2_tty.h" +#include "aqhome/ipc/endpoint2_ipc.h" +#include "aqhome/mqtt/endpoint2_mqttc.h" + +#include +#include +#include +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_SYS_STAT_H +# include +#endif + +#include +#include +#include +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define I18N(msg) msg +#define I18S(msg) msg + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static int _setupTty(AQHOMED *aqh, GWEN_DB_NODE *dbArgs); +static void _setupIpc(AQHOMED *aqh, GWEN_DB_NODE *dbArgs); +static GWEN_MSG_ENDPOINT2 *_acceptIpcFn(GWEN_MSG_ENDPOINT2 *ep, GWEN_SOCKET *sk, const GWEN_INETADDRESS *addr, void *data); +static void _setupMqtt(AQHOMED *aqh, GWEN_DB_NODE *dbArgs); +static void _setupLog(AQHOMED *aqh, GWEN_DB_NODE *dbArgs); +static void _setupWriter(AQHOMED *aqh, GWEN_DB_NODE *dbArgs); +static void _setupDb(AQHOMED *aqh, GWEN_DB_NODE *dbArgs); + +static int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs); +static int _createPidFile(const char *pidFilename); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +int AqHomed_Init(AQHOMED *aqh, int argc, char **argv) +{ + GWEN_DB_NODE *dbArgs; + int rv; + const char *s; + + dbArgs=GWEN_DB_Group_new("args"); + rv=_readArgs(argc, argv, dbArgs); + if (rv<0) { + DBG_ERROR(NULL, "Error reading args (%d)", rv); + return rv; + } + aqh->dbArgs=dbArgs; + + s=GWEN_DB_GetCharValue(dbArgs, "pidfile", 0, AQHOMED_DEFAULT_PIDFILE); + if (s && *s) { + AqHomed_SetPidFile(aqh, s); + rv=_createPidFile(s); + if (rv<0) { + DBG_ERROR(NULL, "Error creating PID file (%d)", rv); + return rv; + } + } + + aqh->nodeAddress=GWEN_DB_GetIntValue(dbArgs, "nodeAddress", 0, AQHOMED_DEFAULT_NODEADDR); + + _setupDb(aqh, dbArgs); + + rv=_setupTty(aqh, dbArgs); + if (rv<0) { + DBG_ERROR(NULL, "Error setting up TTY endpoint (%d)", rv); + return rv; + } + + _setupIpc(aqh, dbArgs); + _setupMqtt(aqh, dbArgs); + _setupLog(aqh, dbArgs); + _setupWriter(aqh, dbArgs); + + return 0; +} + + + +int _setupTty(AQHOMED *aqh, GWEN_DB_NODE *dbArgs) +{ + const char *devicePath; + + devicePath=GWEN_DB_GetCharValue(dbArgs, "device", 0, AQHOMED_DEFAULT_DEVICE); + if (devicePath && *devicePath) { + GWEN_MSG_ENDPOINT2 *epTty; + + epTty=AQH_TtyEndpoint2_new(devicePath, AQHOME_ENDPOINTGROUP_NODE); + if (epTty==NULL) { + DBG_ERROR(NULL, "Error creating endpoint TTY"); + return GWEN_ERROR_GENERIC; + } + GWEN_MsgEndpoint2_Tree2_AddChild(aqh->rootEndpoint, epTty); + aqh->ttyEndpoint=epTty; + } + else { + DBG_ERROR(NULL, "Missing device path"); + return GWEN_ERROR_GENERIC; + } + + return 0; +} + + + +void _setupIpc(AQHOMED *aqh, GWEN_DB_NODE *dbArgs) +{ + const char *tcpAddress; + int tcpPort; + + tcpAddress=GWEN_DB_GetCharValue(dbArgs, "tcpAddress", 0, NULL); + tcpPort=GWEN_DB_GetIntValue(dbArgs, "tcpPort", 0, AQHOMED_DEFAULT_IPC_PORT); + + if (tcpAddress && *tcpAddress && tcpPort) { + GWEN_MSG_ENDPOINT2 *ep; + + ep=GWEN_TcpdEndpoint2_new(tcpAddress, tcpPort, NULL, AQHOME_ENDPOINTGROUP_IPC); + GWEN_TcpdEndpoint2_SetAcceptFn(ep, _acceptIpcFn, aqh); + + GWEN_MsgEndpoint2_Tree2_AddChild(aqh->rootEndpoint, ep); + aqh->ipcdEndpoint=ep; + } +} + + + +void _setupMqtt(AQHOMED *aqh, GWEN_DB_NODE *dbArgs) +{ + const char *mqttAddress; + int mqttPort; + const char *mqttClientId; + const char *mqttTopicPrefix; + int mqttKeepAlive; + + mqttAddress=GWEN_DB_GetCharValue(dbArgs, "mqttAddress", 0, NULL); + mqttPort=GWEN_DB_GetIntValue(dbArgs, "mqttPort", 0, AQHOMED_DEFAULT_MQTT_PORT); + mqttClientId=GWEN_DB_GetCharValue(dbArgs, "mqttClientId", 0, AQHOMED_DEFAULT_MQTT_CLIENTID); + mqttTopicPrefix=GWEN_DB_GetCharValue(dbArgs, "mqttTopicPrefix", 0, AQHOMED_DEFAULT_MQTT_TOPIC_PREFIX); + mqttKeepAlive=GWEN_DB_GetIntValue(dbArgs, "mqttKeepAlive", 0, AQHOMED_DEFAULT_MQTT_KEEPALIVE); + + if (mqttAddress && *mqttAddress && mqttPort) { + GWEN_MSG_ENDPOINT2 *ep; + int rv; + + ep=AQH_MqttClientEndpoint2_new(mqttClientId, mqttAddress, mqttPort, NULL, AQHOME_ENDPOINTGROUP_MQTT); + AQH_MqttClientEndpoint2_SetTopicPrefix(ep, mqttTopicPrefix); + AQH_MqttClientEndpoint2_SetKeepAliveTime(ep, mqttKeepAlive); + + GWEN_MsgEndpoint2_Tree2_AddChild(aqh->rootEndpoint, ep); + aqh->mqttEndpoint=ep; + + rv=AQH_MqttClientEndpoint2_StartConnect(ep); + if (rv<0 && rv!=GWEN_ERROR_IN_PROGRESS) { + DBG_ERROR(NULL, "Error connecting to MQTT server %s:%d (%d), will retry later", mqttAddress, mqttPort, rv); + } + } +} + + + +GWEN_MSG_ENDPOINT2 *_acceptIpcFn(GWEN_MSG_ENDPOINT2 *ep, + GWEN_SOCKET *sk, + const GWEN_INETADDRESS *addr, + GWEN_UNUSED void *data) +{ +/* AQHOMED *aqh; + * + * aqh=(AQHOMED*) data; + */ + DBG_INFO(NULL, "Incoming IPC connection"); + return AQH_IpcEndpoint2_CreateIpcTcpServiceForSocket(sk, NULL, AQHOME_ENDPOINTGROUP_IPC); +} + + + +void _setupLog(AQHOMED *aqh, GWEN_DB_NODE *dbArgs) +{ + const char *logFile; + + logFile=GWEN_DB_GetCharValue(dbArgs, "logfile", 0, NULL); + if (logFile && *logFile) + AqHomed_SetLogFile(aqh, logFile); +} + + + +void _setupWriter(AQHOMED *aqh, GWEN_DB_NODE *dbArgs) +{ + const char *writeToFolder; + + writeToFolder=GWEN_DB_GetCharValue(dbArgs, "writeToFolder", 0, NULL); + if (writeToFolder && *writeToFolder) + AqHomed_SetWriteFolder(aqh, writeToFolder); +} + + + +void _setupDb(AQHOMED *aqh, GWEN_DB_NODE *dbArgs) +{ + const char *s; + + s=GWEN_DB_GetCharValue(dbArgs, "dbfile", 0, NULL); + if (s && *s) { + GWEN_DB_NODE *dbNodeDb; + int rv; + + AqHomed_SetDbFile(aqh, s); + + dbNodeDb=GWEN_DB_Group_new("dbNodes"); + rv=GWEN_DB_ReadFile(dbNodeDb, s, GWEN_DB_FLAGS_DEFAULT); + if (rv==0) { + AQH_NodeDb_fromDb(aqh->nodeDb, dbNodeDb); + } + GWEN_DB_Group_free(dbNodeDb); + } +} + + + +int _createPidFile(const char *pidFilename) +{ + FILE *f; + int pidfd; + + if (remove(pidFilename)==0) { + DBG_ERROR(0, "Old PID file existed, removed. (Unclean shutdown?)"); + } + +#ifdef HAVE_SYS_STAT_H + pidfd = open(pidFilename, O_EXCL|O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + if (pidfd < 0) { + DBG_ERROR(NULL, "Could not create PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno)); + return GWEN_ERROR_IO; + } + + f = fdopen(pidfd, "w"); +#else /* HAVE_STAT_H */ + f=fopen(pidFilename,"w+"); +#endif /* HAVE_STAT_H */ + + /* write pid */ +#ifdef HAVE_GETPID + fprintf(f,"%d\n",getpid()); +#else + fprintf(f,"-1\n"); +#endif + if (fclose(f)) { + DBG_ERROR(0, "Could not close PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno)); + return GWEN_ERROR_IO; + } + return 0; +} + + + +int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs) +{ + int rv; + const GWEN_ARGS args[]= { + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "cfgdir", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "D", /* short option */ + "cfgdir", /* long option */ + I18S("Specify the configuration folder"), + I18S("Specify the configuration folder") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "charset", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + 0, /* short option */ + "charset", /* long option */ + I18S("Specify the output character set"), /* short description */ + I18S("Specify the output character set") /* long description */ + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "device", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "d", /* short option */ + "device", /* long option */ + I18S("Specify the device to communicate with (e.g. /dev/ttyUSB0)"), + I18S("Specify the device to communicate with (e.g. /dev/ttyUSB0)") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Int, /* type */ + "nodeAddress", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "n", /* short option */ + "node", /* long option */ + I18S("Specify the node address for the AqHome node adaptor (default 240)"), + I18S("Specify the node address for the AqHome node adaptor (default 240)") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "logFile", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "l", /* short option */ + "logfile", /* long option */ + I18S("Specify a logfile to log received messages to"), + I18S("Specify a logfile to log received messages to") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "tcpAddress", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "t", /* short option */ + "tcpaddress", /* long option */ + I18S("Specify the TCP address to listen on (disabled if missing)"), + I18S("Specify the TCP address to listen on (disabled if missing)") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Int, /* type */ + "tcpPort", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "P", /* short option */ + "tcpport", /* long option */ + I18S("Specify the TCP port to listen on"), + I18S("Specify the TCP port to listen on") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "mqttAddress", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "ma", /* short option */ + "mqttaddress", /* long option */ + I18S("Specify the address of the MQTT server to connect to (disabled if missing)"), + I18S("Specify the address of the MQTT server to connect to (disabled if missing)") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Int, /* type */ + "mqttPort", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "mp", /* short option */ + "mqttport", /* long option */ + I18S("Specify the port of the MQTT server (default: 1883)"), + I18S("Specify the port of the MQTT server (default: 1883)") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "mqttClientId", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + NULL, /* short option */ + "mqttclientid", /* long option */ + I18S("Specify client id for the MQTT server (default: \"aqhomed\")"), + I18S("Specify client id for the MQTT server (default: \"aqhomed\")") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "mqttTopicPrefix", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "mt", /* short option */ + "mqtttopicprefix", /* long option */ + I18S("Specify prefix of MQTT topics when publishing (defaults to \"aqhome/sensors\")"), + I18S("Specify prefix of MQTT topics when publishing (defaults to \"aqhome/sensors\")") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Int, /* type */ + "mqttKeepAlive", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "mk", /* short option */ + "mqttkeepalive", /* long option */ + I18S("Specify keepalive time in seconds (defaults: 600)"), + I18S("Specify keepalive time in seconds (defaults: 600)") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "dbfile", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "db", /* short option */ + "dbfile", /* long option */ + I18S("Specify DB file to read/write node database"), + I18S("Specify DB file to read/write node database") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "writeToFolder", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "W", /* short option */ + NULL, /* long option */ + I18S("Specify folder to write received values to"), + I18S("Specify folder to write received values to") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "pidfile", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "p", /* short option */ + "pidfile", /* long option */ + I18S("Specify the PID file"), + I18S("Specify the PID file") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Int, /* type */ + "timeout", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "T", /* short option */ + "timeout", /* long option */ + I18S("Specify timeout in second (default: no timeout)"), + I18S("Specify timeout in second (default: no timeout)") + }, + { + GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */ + GWEN_ArgsType_Int, /* type */ + "help", /* name */ + 0, /* minnum */ + 0, /* maxnum */ + "h", /* short option */ + "help", + I18S("Show this help screen."), + I18S("Show this help screen.") + } + }; + + rv=GWEN_Args_Check(argc, argv, 1, 0, args, dbArgs); + if (rv==GWEN_ARGS_RESULT_ERROR) { + fprintf(stderr, "ERROR: Could not parse arguments main\n"); + return GWEN_ERROR_INVALID; + } + else if (rv==GWEN_ARGS_RESULT_HELP) { + GWEN_BUFFER *ubuf; + + ubuf=GWEN_Buffer_new(0, 1024, 0, 1); + GWEN_Buffer_AppendArgs(ubuf, + I18N("This is version %s.\nUsage: %s [OPTIONS]\n\nOptions:\n"), + AQHOME_VERSION_STRING, + argv[0]); + if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) { + fprintf(stderr, "ERROR: Could not create help string\n"); + return 1; + } + GWEN_Buffer_AppendString(ubuf, "\n"); + + fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(ubuf)); + GWEN_Buffer_free(ubuf); + return GWEN_ERROR_CLOSE; + } + return 0; +} + + + + diff --git a/apps/aqhomed/init.h b/apps/aqhomed/init.h new file mode 100644 index 0000000..8935383 --- /dev/null +++ b/apps/aqhomed/init.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * 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 AQHOMED_INIT_H +#define AQHOMED_INIT_H + + +#include "./aqhomed.h" + + + +int AqHomed_Init(AQHOMED *aqh, int argc, char **argv); + + + +#endif + + diff --git a/apps/aqhomed/loop.c b/apps/aqhomed/loop.c new file mode 100644 index 0000000..430618a --- /dev/null +++ b/apps/aqhomed/loop.c @@ -0,0 +1,168 @@ +/**************************************************************************** + * 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 "./loop.h" +#include "./aqhomed_p.h" +#include "./tty_log.h" +#include "./tty_write.h" +#include "./db.h" + +#include "aqhome/msg/endpoint2_tty.h" +#include "aqhome/msg/msg_node.h" +#include "aqhome/msg/msg_value2.h" +#include "aqhome/ipc/endpoint2_ipc.h" +#include "aqhome/ipc/msg_ipc_forward.h" +#include "aqhome/ipc/msg_ipc_value.h" +#include "aqhome/mqtt/endpoint2_mqttc.h" + +#include +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define I18N(msg) msg +#define I18S(msg) msg + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _readTtyMessages(AQHOMED *aqh); +static void _handleTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg); +static void _forwardTtyMsgToIpcClients(AQHOMED *aqh, const GWEN_MSG *msg); +static void _forwardValue2MsgToIpc(GWEN_MSG_ENDPOINT2 *ep, const GWEN_MSG *nodeMsg); +static void _forwardAnyMsgToIpc(GWEN_MSG_ENDPOINT2 *ep, const GWEN_MSG *nodeMsg); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +void AqHomed_Loop(AQHOMED *aqh, int timeoutInMsecs) +{ + if (aqh) { + GWEN_MsgEndpoint2_ChildrenIoLoop(aqh->rootEndpoint, timeoutInMsecs); + _readTtyMessages(aqh); + + if (AQH_NodeDb_IsModified(aqh->nodeDb)) { + if (aqh->dbFile) { + GWEN_DB_NODE *dbNodeDb; + + dbNodeDb=GWEN_DB_Group_new("nodeDb"); + AQH_NodeDb_toDb(aqh->nodeDb, dbNodeDb); + GWEN_DB_WriteFile(dbNodeDb, aqh->dbFile, GWEN_DB_FLAGS_DEFAULT); + GWEN_DB_Group_free(dbNodeDb); + } + } + } +} + + + +void _readTtyMessages(AQHOMED *aqh) +{ + GWEN_MSG *msg; + + while( (msg=GWEN_MsgEndpoint2_TakeFirstReceivedMessage(aqh->ttyEndpoint)) ) { + _handleTtyMsg(aqh, msg); + GWEN_Msg_free(msg); + } +} + + + +void _handleTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg) +{ + if (aqh->logFile) + AqHomed_LogTtyMsg(aqh, msg); + if (aqh->writeFolder) + AqHomed_WriteTtyMsg(aqh, msg); + if (aqh->nodeDb) + AqHomed_NodeMsgToDb(aqh, msg); + if (aqh->ipcdEndpoint) + _forwardTtyMsgToIpcClients(aqh, msg); +} + + + +void _forwardTtyMsgToIpcClients(AQHOMED *aqh, const GWEN_MSG *msg) +{ + uint32_t msgGroup; + + msgGroup=AQH_NodeMsg_GetMsgGroup(AQH_NodeMsg_GetMsgType(msg)); + if (msgGroup) { + GWEN_MSG_ENDPOINT2 *ep; + + ep=GWEN_MsgEndpoint2_Tree2_GetFirstChild(aqh->ipcdEndpoint); + while(ep) { + if (msgGroup & AQH_IpcEndpoint2_GetAcceptedMsgGroups(ep)) { + DBG_INFO(NULL, "Endpoint accepts msg group %d", msgGroup); + switch(AQH_NodeMsg_GetMsgType(msg)) { + case AQH_MSG_TYPE_VALUE2: + _forwardValue2MsgToIpc(ep, msg); + break; + default: + _forwardAnyMsgToIpc(ep, msg); + break; + } + + } + ep=GWEN_MsgEndpoint2_Tree2_GetNext(ep); + } + } + else { + DBG_ERROR(NULL, "Message type %d not in any message group, ignoring message", AQH_NodeMsg_GetMsgType(msg)); + } +} + + + +void _forwardValue2MsgToIpc(GWEN_MSG_ENDPOINT2 *ep, const GWEN_MSG *nodeMsg) +{ + GWEN_MSG *ipcMsg; + + ipcMsg=AQH_ValueIpcMsg_new(AQH_MSGTYPE_IPC_VALUE, + AQH_Value2Msg_GetUid(nodeMsg), + AQH_Value2Msg_GetValueId(nodeMsg), + AQH_Value2Msg_GetValueType(nodeMsg), + AQH_Value2Msg_GetValueNom(nodeMsg), + AQH_Value2Msg_GetValueDenom(nodeMsg)); + GWEN_MsgEndpoint2_AddSendMessage(ep, ipcMsg); +} + + + +void _forwardAnyMsgToIpc(GWEN_MSG_ENDPOINT2 *ep, const GWEN_MSG *nodeMsg) +{ + GWEN_MSG *ipcMsg; + + ipcMsg=AQH_ForwardIpcMsg_new(AQH_MSGTYPE_IPC_FORWARD, GWEN_Msg_GetConstBuffer(nodeMsg), GWEN_Msg_GetBytesInBuffer(nodeMsg)); + GWEN_MsgEndpoint2_AddSendMessage(ep, ipcMsg); +} + + + + + diff --git a/apps/aqhomed/loop.h b/apps/aqhomed/loop.h new file mode 100644 index 0000000..c715173 --- /dev/null +++ b/apps/aqhomed/loop.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * 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 AQHOMED_LOOP_H +#define AQHOMED_LOOP_H + + +#include "./aqhomed.h" + + + +void AqHomed_Loop(AQHOMED *aqh, int timeoutInMsecs); + + + +#endif + + diff --git a/apps/aqhomed/main.c b/apps/aqhomed/main.c index 041d8a2..87c1050 100644 --- a/apps/aqhomed/main.c +++ b/apps/aqhomed/main.c @@ -13,64 +13,51 @@ #include #include -#include -#include -#include -#include -#include -#include -#include +#include "./aqhomed.h" +#include "./init.h" +#include "./fini.h" +#include "./loop.h" #include -#include #include -#include -#include #include +#include #ifdef HAVE_SIGNAL_H # include #endif -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif - -#include -#include -#include -#include -#include -#include +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ #define I18N(msg) msg #define I18S(msg) msg - -static int _serve(GWEN_DB_NODE *dbArgs); -static GWEN_MSG_ENDPOINT_MGR *_setupService(GWEN_DB_NODE *dbArgs); - -static int _setupTty(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_DB_NODE *dbArgs); -static int _setupLog(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_DB_NODE *dbArgs); -static int _setupWriter(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_DB_NODE *dbArgs); -static int _setupIpc(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_DB_NODE *dbArgs); -static int _setupMqtt(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_DB_NODE *dbArgs); - -static int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs); -static int _createPidFile(const char *pidFilename); - +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ #ifdef HAVE_SIGNAL_H static int _setSignalHandlers(void); static int _setupSigAction(struct sigaction *sa, int sig); static void _signalHandler(int s); +#endif + + + +/* ------------------------------------------------------------------------------------------------ + * static vars + * ------------------------------------------------------------------------------------------------ + */ + +#ifdef HAVE_SIGNAL_H static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT; #endif @@ -78,13 +65,16 @@ static int stopService=0; +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ int main(int argc, char **argv) { - GWEN_DB_NODE *dbArgs; int rv; + AQHOMED *aqh; GWEN_GUI *gui; - const char *s; rv=GWEN_Init(); if (rv) { @@ -93,509 +83,47 @@ int main(int argc, char **argv) } GWEN_Logger_Open(0, "aqhomed", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User); - GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning); + //GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning); GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Info); - rv=AQH_Init(); - if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); - return 2; - } - - dbArgs=GWEN_DB_Group_new("arguments"); - rv=_readArgs(argc, argv, dbArgs); - if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); - return 2; - } - else if (rv==1) { - DBG_INFO(NULL, "Help printed, done"); - return 0; - } - - gui=GWEN_Gui_CGui_new(); - s=GWEN_DB_GetCharValue(dbArgs, "charset", 0, NULL); - if (s && *s) - GWEN_Gui_SetCharSet(gui, s); - GWEN_Gui_SetGui(gui); - - rv=_serve(dbArgs); - if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); - return 2; - } - - GWEN_DB_Group_free(dbArgs); - GWEN_Gui_SetGui(NULL); - GWEN_Gui_free(gui); - - return 0; -} - - - -int _serve(GWEN_DB_NODE *dbArgs) -{ - const char *pidFile; - GWEN_MSG_ENDPOINT_MGR *emgr; - int rv; - int timeout; - time_t startTime; - - startTime=time(NULL); - rv=_setSignalHandlers(); if (rv<0) { DBG_INFO(NULL, "here (%d)", rv); return rv; } - timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0); - pidFile=GWEN_DB_GetCharValue(dbArgs, "pidfile", 0, "aqhomed.pid"); - if (pidFile && *pidFile) { - rv=_createPidFile(pidFile); - if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); - return rv; - } + rv=AQH_Init(); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return 2; } - emgr=_setupService(dbArgs); - if (emgr==NULL) { - DBG_INFO(NULL, "Error setting up service"); - return GWEN_ERROR_GENERIC; + gui=GWEN_Gui_CGui_new(); + GWEN_Gui_SetGui(gui); + + aqh=AqHomed_new(); + rv=AqHomed_Init(aqh, argc, argv); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return 2; } while(!stopService) { DBG_DEBUG(NULL, "Next loop"); - AQH_MsgManager_LoopOnce(emgr); - - if (timeout) { - time_t now; - - now=time(NULL); - if ((now-startTime)>timeout) { - DBG_INFO(NULL, "Timeout, stopping service"); - break; - } - } + AqHomed_Loop(aqh, 2000); } - if (pidFile && *pidFile) - remove(pidFile); + AqHomed_Fini(aqh); + AqHomed_free(aqh); - GWEN_MsgEndpointMgr_free(emgr); + GWEN_Gui_SetGui(NULL); + GWEN_Gui_free(gui); return 0; } -GWEN_MSG_ENDPOINT_MGR *_setupService(GWEN_DB_NODE *dbArgs) -{ - GWEN_MSG_ENDPOINT_MGR *emgr; - int nodeAddress; - const char *dbfile; - int rv; - - nodeAddress=GWEN_DB_GetIntValue(dbArgs, "nodeAddress", 0, 240); - dbfile=GWEN_DB_GetCharValue(dbArgs, "dbfile", 0, "aqhome.db"); - - emgr=AQH_MsgManager_new(nodeAddress & 0xff); - - if (dbfile && *dbfile) - AQH_MsgManager_SetDbFilename(emgr, dbfile); - - rv=_setupTty(emgr, dbArgs); - if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); - GWEN_MsgEndpointMgr_free(emgr); - return NULL; - } - - rv=_setupLog(emgr, dbArgs); - if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); - GWEN_MsgEndpointMgr_free(emgr); - return NULL; - } - - rv=_setupWriter(emgr, dbArgs); - if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); - GWEN_MsgEndpointMgr_free(emgr); - return NULL; - } - - rv=_setupIpc(emgr, dbArgs); - if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); - GWEN_MsgEndpointMgr_free(emgr); - return NULL; - } - - rv=_setupMqtt(emgr, dbArgs); - if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); - GWEN_MsgEndpointMgr_free(emgr); - return NULL; - } - - return emgr; -} - - - -int _setupTty(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_DB_NODE *dbArgs) -{ - const char *devicePath; - - devicePath=GWEN_DB_GetCharValue(dbArgs, "device", 0, "/dev/ttyUSB0"); - if (devicePath && *devicePath) { - GWEN_MSG_ENDPOINT *epTty; - - epTty=AQH_TtyNodeEndpoint_new(devicePath, AQH_MSGMGR_ENDPOINTGROUP_NODE); - if (epTty==NULL) { - DBG_ERROR(NULL, "Error creating endpoint TTY"); - return GWEN_ERROR_GENERIC; - } - GWEN_MsgEndpoint_SetAcceptedGroupIds(epTty, AQH_MSGMGR_ENDPOINTGROUP_NODE); - GWEN_MsgEndpointMgr_AddEndpoint(emgr, epTty); - } - else { - DBG_ERROR(NULL, "Missing device path"); - return GWEN_ERROR_GENERIC; - } - - return 0; -} - - - -int _setupLog(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_DB_NODE *dbArgs) -{ - const char *logFile; - - logFile=GWEN_DB_GetCharValue(dbArgs, "logfile", 0, NULL); - if (logFile && *logFile) { - GWEN_MSG_ENDPOINT *epLog; - - epLog=AQH_LogEndpoint_new(logFile, AQH_MSGMGR_ENDPOINTGROUP_NODE); - if (epLog==NULL) { - DBG_ERROR(AQH_LOGDOMAIN, "Error creating endpoint LOG"); - return GWEN_ERROR_GENERIC; - } - GWEN_MsgEndpoint_SetAcceptedGroupIds(epLog, AQH_MSGMGR_ENDPOINTGROUP_NODE); - GWEN_MsgEndpointMgr_AddEndpoint(emgr, epLog); - } - return 0; -} - - - -int _setupWriter(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_DB_NODE *dbArgs) -{ - const char *writeToFolder; - - writeToFolder=GWEN_DB_GetCharValue(dbArgs, "writeToFolder", 0, NULL); - if (writeToFolder && *writeToFolder) { - GWEN_MSG_ENDPOINT *epWrite; - - epWrite=AQH_WriteEndpoint_new(writeToFolder, AQH_MSGMGR_ENDPOINTGROUP_NODE); - if (epWrite==NULL) { - DBG_ERROR(AQH_LOGDOMAIN, "Error creating endpoint WRITE"); - return GWEN_ERROR_GENERIC; - } - GWEN_MsgEndpoint_SetAcceptedGroupIds(epWrite, AQH_MSG_TYPEGROUP_INFO | AQH_MSG_TYPEGROUP_VALUES); - GWEN_MsgEndpointMgr_AddEndpoint(emgr, epWrite); - } - return 0; -} - - - -int _setupIpc(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_DB_NODE *dbArgs) -{ - const char *tcpAddress; - int tcpPort; - - tcpAddress=GWEN_DB_GetCharValue(dbArgs, "tcpAddress", 0, NULL); - tcpPort=GWEN_DB_GetIntValue(dbArgs, "tcpPort", 0, 45454); - - if (tcpAddress && *tcpAddress && tcpPort) { - GWEN_MSG_ENDPOINT *epTcp; - - epTcp=AQH_TcpdIpcNodeEndpoint_new(tcpAddress, tcpPort, NULL, AQH_MSGMGR_ENDPOINTGROUP_NODE|AQH_MSGMGR_ENDPOINTGROUP_IPC); - if (epTcp==NULL) { - DBG_ERROR(AQH_LOGDOMAIN, "Error creating endpoint TCP"); - return GWEN_ERROR_GENERIC; - } - GWEN_MsgEndpoint_SetAcceptedGroupIds(epTcp, AQH_MSGMGR_ENDPOINTGROUP_NODE | AQH_MSGMGR_ENDPOINTGROUP_IPC); - GWEN_MsgEndpointMgr_AddEndpoint(emgr, epTcp); - } - return 0; -} - - - -int _setupMqtt(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_DB_NODE *dbArgs) -{ - const char *mqttAddress; - int mqttPort; - const char *mqttClientId; - const char *mqttTopicPrefix; - int mqttKeepAlive; - - mqttAddress=GWEN_DB_GetCharValue(dbArgs, "mqttAddress", 0, NULL); - mqttPort=GWEN_DB_GetIntValue(dbArgs, "mqttPort", 0, 1883); - mqttClientId=GWEN_DB_GetCharValue(dbArgs, "mqttClientId", 0, "aqhomed"); - mqttTopicPrefix=GWEN_DB_GetCharValue(dbArgs, "mqttTopicPrefix", 0, "aqhome/sensors"); - mqttKeepAlive=GWEN_DB_GetIntValue(dbArgs, "mqttKeepAlive", 0, 600); - - if (mqttAddress && *mqttAddress && mqttPort) { - GWEN_MSG_ENDPOINT *epMqtt; - - DBG_INFO(AQH_LOGDOMAIN, "Connecting to %s (port %d)", mqttAddress, mqttPort); - epMqtt=AQH_MqttClientEndpoint_new(mqttAddress, mqttPort, NULL, AQH_MSGMGR_ENDPOINTGROUP_MQTT); - if (epMqtt==NULL) { - DBG_ERROR(AQH_LOGDOMAIN, "Error creating endpoint TCP"); - return GWEN_ERROR_GENERIC; - } - GWEN_MsgEndpoint_SetAcceptedGroupIds(epMqtt, AQH_MSGMGR_ENDPOINTGROUP_NODE | AQH_MSGMGR_ENDPOINTGROUP_MQTT); - if (mqttClientId && *mqttClientId) - AQH_MqttClientEndpoint_SetClientId(epMqtt, mqttClientId); - if (mqttTopicPrefix && *mqttTopicPrefix) - AQH_MqttClientEndpoint_SetTopicPrefix(epMqtt, mqttTopicPrefix); - AQH_MqttClientEndpoint_SetKeepAliveTime(epMqtt, mqttKeepAlive); - - GWEN_MsgEndpointMgr_AddEndpoint(emgr, epMqtt); - } - return 0; -} - - - -int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs) -{ - int rv; - const GWEN_ARGS args[]= { - { - GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ - GWEN_ArgsType_Char, /* type */ - "cfgdir", /* name */ - 0, /* minnum */ - 1, /* maxnum */ - "D", /* short option */ - "cfgdir", /* long option */ - I18S("Specify the configuration folder"), - I18S("Specify the configuration folder") - }, - { - GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ - GWEN_ArgsType_Char, /* type */ - "charset", /* name */ - 0, /* minnum */ - 1, /* maxnum */ - 0, /* short option */ - "charset", /* long option */ - I18S("Specify the output character set"), /* short description */ - I18S("Specify the output character set") /* long description */ - }, - { - GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ - GWEN_ArgsType_Char, /* type */ - "device", /* name */ - 0, /* minnum */ - 1, /* maxnum */ - "d", /* short option */ - "device", /* long option */ - I18S("Specify the device to communicate with (e.g. /dev/ttyUSB0)"), - I18S("Specify the device to communicate with (e.g. /dev/ttyUSB0)") - }, - { - GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ - GWEN_ArgsType_Int, /* type */ - "nodeAddress", /* name */ - 0, /* minnum */ - 1, /* maxnum */ - "n", /* short option */ - "node", /* long option */ - I18S("Specify the node address for the AqHome node adaptor (default 240)"), - I18S("Specify the node address for the AqHome node adaptor (default 240)") - }, - { - GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ - GWEN_ArgsType_Char, /* type */ - "logFile", /* name */ - 0, /* minnum */ - 1, /* maxnum */ - "l", /* short option */ - "logfile", /* long option */ - I18S("Specify a logfile to log received messages to"), - I18S("Specify a logfile to log received messages to") - }, - { - GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ - GWEN_ArgsType_Char, /* type */ - "tcpAddress", /* name */ - 0, /* minnum */ - 1, /* maxnum */ - "t", /* short option */ - "tcpaddress", /* long option */ - I18S("Specify the TCP address to listen on (disabled if missing)"), - I18S("Specify the TCP address to listen on (disabled if missing)") - }, - { - GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ - GWEN_ArgsType_Int, /* type */ - "tcpPort", /* name */ - 0, /* minnum */ - 1, /* maxnum */ - "P", /* short option */ - "tcpport", /* long option */ - I18S("Specify the TCP port to listen on"), - I18S("Specify the TCP port to listen on") - }, - { - GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ - GWEN_ArgsType_Char, /* type */ - "mqttAddress", /* name */ - 0, /* minnum */ - 1, /* maxnum */ - "ma", /* short option */ - "mqttaddress", /* long option */ - I18S("Specify the address of the MQTT server to connect to (disabled if missing)"), - I18S("Specify the address of the MQTT server to connect to (disabled if missing)") - }, - { - GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ - GWEN_ArgsType_Int, /* type */ - "mqttPort", /* name */ - 0, /* minnum */ - 1, /* maxnum */ - "mp", /* short option */ - "mqttport", /* long option */ - I18S("Specify the port of the MQTT server (default: 1883)"), - I18S("Specify the port of the MQTT server (default: 1883)") - }, - { - GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ - GWEN_ArgsType_Char, /* type */ - "mqttClientId", /* name */ - 0, /* minnum */ - 1, /* maxnum */ - NULL, /* short option */ - "mqttclientid", /* long option */ - I18S("Specify client id for the MQTT server (default: \"aqhomed\")"), - I18S("Specify client id for the MQTT server (default: \"aqhomed\")") - }, - { - GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ - GWEN_ArgsType_Char, /* type */ - "mqttTopicPrefix", /* name */ - 0, /* minnum */ - 1, /* maxnum */ - "mt", /* short option */ - "mqtttopicprefix", /* long option */ - I18S("Specify prefix of MQTT topics when publishing (defaults to \"aqhome/sensors\")"), - I18S("Specify prefix of MQTT topics when publishing (defaults to \"aqhome/sensors\")") - }, - { - GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ - GWEN_ArgsType_Int, /* type */ - "mqttKeepAlive", /* name */ - 0, /* minnum */ - 1, /* maxnum */ - "mk", /* short option */ - "mqttkeepalive", /* long option */ - I18S("Specify keepalive time in seconds (defaults: 600)"), - I18S("Specify keepalive time in seconds (defaults: 600)") - }, - { - GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ - GWEN_ArgsType_Char, /* type */ - "dbfile", /* name */ - 0, /* minnum */ - 1, /* maxnum */ - "db", /* short option */ - "dbfile", /* long option */ - I18S("Specify DB file to read/write node database"), - I18S("Specify DB file to read/write node database") - }, - { - GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ - GWEN_ArgsType_Char, /* type */ - "writeToFolder", /* name */ - 0, /* minnum */ - 1, /* maxnum */ - "W", /* short option */ - NULL, /* long option */ - I18S("Specify folder to write received values to"), - I18S("Specify folder to write received values to") - }, - { - GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ - GWEN_ArgsType_Char, /* type */ - "pidfile", /* name */ - 0, /* minnum */ - 1, /* maxnum */ - "p", /* short option */ - "pidfile", /* long option */ - I18S("Specify the PID file"), - I18S("Specify the PID file") - }, - { - GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ - GWEN_ArgsType_Int, /* type */ - "timeout", /* name */ - 0, /* minnum */ - 1, /* maxnum */ - "T", /* short option */ - "timeout", /* long option */ - I18S("Specify timeout in second (default: no timeout)"), - I18S("Specify timeout in second (default: no timeout)") - }, - { - GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */ - GWEN_ArgsType_Int, /* type */ - "help", /* name */ - 0, /* minnum */ - 0, /* maxnum */ - "h", /* short option */ - "help", - I18S("Show this help screen."), - I18S("Show this help screen.") - } - }; - - rv=GWEN_Args_Check(argc, argv, 1, 0, args, dbArgs); - if (rv==GWEN_ARGS_RESULT_ERROR) { - fprintf(stderr, "ERROR: Could not parse arguments main\n"); - return GWEN_ERROR_INVALID; - } - else if (rv==GWEN_ARGS_RESULT_HELP) { - GWEN_BUFFER *ubuf; - - ubuf=GWEN_Buffer_new(0, 1024, 0, 1); - GWEN_Buffer_AppendArgs(ubuf, - I18N("This is version %s.\nUsage: %s [OPTIONS]\n\nOptions:\n"), - AQHOME_VERSION_STRING, - argv[0]); - if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) { - fprintf(stderr, "ERROR: Could not create help string\n"); - return 1; - } - GWEN_Buffer_AppendString(ubuf, "\n"); - - fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(ubuf)); - GWEN_Buffer_free(ubuf); - return GWEN_ERROR_CLOSE; - } - return 0; -} - - - int _setSignalHandlers(void) { #ifdef HAVE_SIGNAL_H @@ -661,44 +189,3 @@ void _signalHandler(int s) } - -int _createPidFile(const char *pidFilename) -{ - FILE *f; - int pidfd; - - if (remove(pidFilename)==0) { - DBG_ERROR(0, "Old PID file existed, removed. (Unclean shutdown?)"); - } - -#ifdef HAVE_SYS_STAT_H - pidfd = open(pidFilename, O_EXCL|O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); - if (pidfd < 0) { - DBG_ERROR(NULL, "Could not create PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno)); - return GWEN_ERROR_IO; - } - - f = fdopen(pidfd, "w"); -#else /* HAVE_STAT_H */ - f=fopen(pidFilename,"w+"); -#endif /* HAVE_STAT_H */ - - /* write pid */ -#ifdef HAVE_GETPID - fprintf(f,"%d\n",getpid()); -#else - fprintf(f,"-1\n"); -#endif - if (fclose(f)) { - DBG_ERROR(0, "Could not close PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno)); - return GWEN_ERROR_IO; - } - return 0; -} - - - - - - - diff --git a/apps/aqhomed/tty_log.c b/apps/aqhomed/tty_log.c new file mode 100644 index 0000000..0ac05aa --- /dev/null +++ b/apps/aqhomed/tty_log.c @@ -0,0 +1,131 @@ +/**************************************************************************** + * 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 "./tty_log.h" +#include "./aqhomed_p.h" + +#include "aqhome/msg/msg_value.h" +#include "aqhome/msg/msg_value2.h" +#include "aqhome/msg/msg_sendstats.h" +#include "aqhome/msg/msg_recvstats.h" +#include "aqhome/msg/msg_memstats.h" +#include "aqhome/msg/msg_sysstats.h" +#include "aqhome/msg/msg_ping.h" +#include "aqhome/msg/msg_pong.h" +#include "aqhome/msg/msg_needaddr.h" +#include "aqhome/msg/msg_claimaddr.h" +#include "aqhome/msg/msg_haveaddr.h" +#include "aqhome/msg/msg_denyaddr.h" +#include "aqhome/msg/msg_device.h" +#include "aqhome/msg/msg_flashready.h" +#include "aqhome/msg/msg_flashstart.h" +#include "aqhome/msg/msg_flashresponse.h" +#include "aqhome/msg/msg_flashend.h" +#include "aqhome/msg/msg_flashdata.h" +#include "aqhome/msg/msg_reboot.h" + +#include +#include +#include +#include +#include + +#include + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _writeToLogFile(const char *filename, const char *txt); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +void AqHomed_LogTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg) +{ + if (aqh && aqh->logFile) { + uint8_t msgType; + int msgIsValid; + GWEN_BUFFER *dbuf; + GWEN_TIME *ti; + + 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_NodeMsg_IsChecksumValid(msg) && AQH_NodeMsg_IsMsgComplete(msg)); + msgType=AQH_NodeMsg_GetMsgType(msg); + + if (msgIsValid) { + switch(msgType) { + case AQH_MSG_TYPE_PING: AQH_PingMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_PONG: AQH_PongMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_COMSENDSTATS: AQH_SendStatsMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_COMRECVSTATS: AQH_RecvStatsMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_TWIBUSMEMBER: AQH_NodeMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_DEBUG: AQH_NodeMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_VALUE: AQH_ValueMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_VALUE2: AQH_Value2Msg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_NEED_ADDRESS: AQH_NeedAddrMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_CLAIM_ADDRESS: AQH_ClaimAddrMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_HAVE_ADDRESS: AQH_HaveAddrMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_DENY_ADDRESS: AQH_DenyAddrMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_DEVICE: AQH_DeviceMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_MEMSTATS: AQH_MemStatsMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_SYSSTATS: AQH_SysStatsMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_FLASH_READY: AQH_FlashReadyMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_FLASH_START: AQH_FlashStartMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_FLASH_RSP: AQH_FlashResponseMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_FLASH_END: AQH_FlashEndMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_FLASH_DATA: AQH_FlashDataMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_REBOOT_REQ: AQH_RebootRequestMsg_DumpToBuffer(msg, dbuf, "received"); break; + case AQH_MSG_TYPE_REBOOT_RSP: AQH_RebootResponseMsg_DumpToBuffer(msg, dbuf, "received"); break; + default: AQH_NodeMsg_DumpToBuffer(msg, dbuf, "received"); break; + } + } + else { + AQH_NodeMsg_DumpToBuffer(msg, dbuf, "(invalid) received"); + } + _writeToLogFile(aqh->logFile, 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(AQH_LOGDOMAIN, "Error logging."); + } + fclose(f); + } + } +} + + + diff --git a/apps/aqhomed/tty_log.h b/apps/aqhomed/tty_log.h new file mode 100644 index 0000000..29add37 --- /dev/null +++ b/apps/aqhomed/tty_log.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * 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 AQHOMED_TTY_LOG_H +#define AQHOMED_TTY_LOG_H + + +#include "./aqhomed.h" + + + +void AqHomed_LogTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg); + + + +#endif + + diff --git a/apps/aqhomed/tty_write.c b/apps/aqhomed/tty_write.c new file mode 100644 index 0000000..3c6fb3d --- /dev/null +++ b/apps/aqhomed/tty_write.c @@ -0,0 +1,225 @@ +/**************************************************************************** + * 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 "./tty_write.h" +#include "./aqhomed_p.h" + +#include "aqhome/msg/msg_value2.h" +#include "aqhome/msg/msg_sendstats.h" +#include "aqhome/msg/msg_recvstats.h" + +#include +#include + +#include + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _processValue2Message(AQHOMED *aqh, const GWEN_MSG *nodeMsg); +static void _processSendStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg); +static void _processRecvStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg); +static void _writeDouble(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, double v); +static void _writeInt(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, int v); +static void _writeString(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, const char *v); +static void _writeToFile(const char *filename, const char *txt); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +void AqHomed_WriteTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg) +{ + if (aqh && aqh->writeFolder) { + switch(AQH_NodeMsg_GetMsgType(msg)) { + case AQH_MSG_TYPE_VALUE2: + _processValue2Message(aqh, msg); + break; + case AQH_MSG_TYPE_COMSENDSTATS: + _processSendStatsMessage(aqh, msg); + break; + case AQH_MSG_TYPE_COMRECVSTATS: + _processRecvStatsMessage(aqh, msg); + break; + default: + break; + } + } +} + + + +void _processValue2Message(AQHOMED *aqh, const GWEN_MSG *nodeMsg) +{ + const char *sType; + + sType=AQH_Value2Msg_GetValueTypeName(nodeMsg); + if (sType && *sType) { + if (AQH_Value2Msg_GetValueType(nodeMsg)==AQH_MSG_VALUE2_TYPE_DOOR) + _writeString(aqh, + AQH_Value2Msg_GetUid(nodeMsg), + AQH_Value2Msg_GetValueId(nodeMsg), + sType, + AQH_Value2Msg_GetValueAsWindowStateString(nodeMsg)); + else + _writeDouble(aqh, + AQH_Value2Msg_GetUid(nodeMsg), + AQH_Value2Msg_GetValueId(nodeMsg), + sType, + AQH_Value2Msg_GetValue(nodeMsg)); + } + _writeDouble(aqh, + AQH_Value2Msg_GetUid(nodeMsg), + AQH_Value2Msg_GetValueId(nodeMsg), + "value", + AQH_Value2Msg_GetValue(nodeMsg)); +} + + + +void _processSendStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg) +{ + uint16_t packetsOutInt; + + packetsOutInt=AQH_SendStatsMsg_GetPacketsOut(nodeMsg); + if (packetsOutInt) { + double packetsOut; + double collisions; + double busy; + double collisionsPercentage=0.0; + double busyPercentage=0.0; + + packetsOut=(double) packetsOutInt; + collisions=(double)AQH_SendStatsMsg_GetCollisions(nodeMsg); + busy=(double)AQH_SendStatsMsg_GetBusyErrors(nodeMsg); + + collisionsPercentage=collisions*100.0/packetsOut; + busyPercentage=busy*100.0/packetsOut; + + _writeInt(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/packetsOut", packetsOutInt); + _writeInt(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/collisions", (int) AQH_SendStatsMsg_GetCollisions(nodeMsg)); + _writeDouble(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/collisionsPercent", collisionsPercentage); + _writeDouble(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/busyPercent", busyPercentage); + } +} + + + +void _processRecvStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg) +{ + uint16_t packetsInInt; + + packetsInInt=AQH_RecvStatsMsg_GetPacketsIn(nodeMsg); + if (packetsInInt) { + double packetsIn; + double crcErrors; + double ioErrors; + double crcErrorsPercentage=0.0; + double ioErrorsPercentage=0.0; + + packetsIn=(double) packetsInInt; + crcErrors=(double)AQH_RecvStatsMsg_GetCrcErrors(nodeMsg); + ioErrors=(double)AQH_RecvStatsMsg_GetIoErrors(nodeMsg); + + crcErrorsPercentage=crcErrors*100.0/packetsIn; + ioErrorsPercentage=ioErrors*100.0/packetsIn; + + _writeInt(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/packetsIn", packetsInInt); + _writeInt(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/crcerrors", (int) AQH_RecvStatsMsg_GetCrcErrors(nodeMsg)); + _writeInt(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/ioerrors", (int) AQH_RecvStatsMsg_GetIoErrors(nodeMsg)); + _writeDouble(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/crcerrorsPercent", crcErrorsPercentage); + _writeDouble(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/ioerrorsPercent", ioErrorsPercentage); + } +} + + + +void _writeDouble(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, double v) +{ + char numBuf[16]; + + snprintf(numBuf, sizeof(numBuf)-1, "%f", v); + numBuf[sizeof(numBuf)-1]=0; + _writeString(aqh, uid, valueId, valuePath, numBuf); +} + + + +void _writeInt(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, int v) +{ + char numBuf[16]; + + snprintf(numBuf, sizeof(numBuf)-1, "%d", v); + numBuf[sizeof(numBuf)-1]=0; + _writeString(aqh, uid, valueId, valuePath, numBuf); +} + + + +void _writeString(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, const char *v) +{ + GWEN_BUFFER *bufFilename; + + bufFilename=GWEN_Buffer_new(0, 64, 0, 1); + if (valueId>0) + GWEN_Buffer_AppendArgs(bufFilename, "%s/%08x/%d/%s", aqh->writeFolder, uid, valueId, valuePath); + else + GWEN_Buffer_AppendArgs(bufFilename, "%s/%08x/%s", aqh->writeFolder, uid, valuePath); + _writeToFile(GWEN_Buffer_GetStart(bufFilename), v); + GWEN_Buffer_free(bufFilename); +} + + + +void _writeToFile(const char *filename, const char *txt) +{ + if (txt && *txt) { + GWEN_BUFFER *tmpNameBuf; + int rv; + + tmpNameBuf=GWEN_Buffer_new(0, 256, 0, 1); + GWEN_Buffer_AppendString(tmpNameBuf, filename); + GWEN_Buffer_AppendString(tmpNameBuf, ".tmp"); + + rv=GWEN_Directory_GetPath(GWEN_Buffer_GetStart(tmpNameBuf), GWEN_PATH_FLAGS_VARIABLE); + if (rv<0) { + DBG_INFO(NULL, "Error getting path for %s (%d)", GWEN_Buffer_GetStart(tmpNameBuf), rv); + } + else { + FILE *f; + + f=fopen(GWEN_Buffer_GetStart(tmpNameBuf), "w"); + if (f) { + if (1!=fwrite(txt, strlen(txt), 1, f)) { + DBG_ERROR(NULL, "Error writing."); + fclose(f); + } + else { + fclose(f); + rename(GWEN_Buffer_GetStart(tmpNameBuf), filename); + } + } + } + GWEN_Buffer_free(tmpNameBuf); + } +} + + + diff --git a/apps/aqhomed/tty_write.h b/apps/aqhomed/tty_write.h new file mode 100644 index 0000000..40fc111 --- /dev/null +++ b/apps/aqhomed/tty_write.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * 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 AQHOMED_TTY_WRITE_H +#define AQHOMED_TTY_WRITE_H + + +#include "./aqhomed.h" + + + +void AqHomed_WriteTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg); + + + +#endif + + diff --git a/aqhome/ipc/0BUILD b/aqhome/ipc/0BUILD index dd84d0f..71d3962 100644 --- a/aqhome/ipc/0BUILD +++ b/aqhome/ipc/0BUILD @@ -45,6 +45,7 @@ + endpoint2_ipc.h endpoint_node_ipc.h endpoint_node_ipc_tcpd.h endpoint_ipc_tcpc.h @@ -61,12 +62,14 @@ + endpoint2_ipc_p.h $(local/typefiles) + endpoint2_ipc.c endpoint_node_ipc.c endpoint_node_ipc_tcpd.c endpoint_ipc_tcpc.c diff --git a/aqhome/ipc/endpoint2_ipc.c b/aqhome/ipc/endpoint2_ipc.c new file mode 100644 index 0000000..274d17c --- /dev/null +++ b/aqhome/ipc/endpoint2_ipc.c @@ -0,0 +1,139 @@ +/**************************************************************************** + * 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/ipc/endpoint2_ipc_p.h" + +#include +#include + + + + +#define AQH_MSG_ENDPOINT2_IPC_NAME "ipc" + + +GWEN_INHERIT(GWEN_MSG_ENDPOINT, AQH_ENDPOINT2_IPC) + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void GWENHYWFAR_CB _freeData(void *bp, void *p); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +void AQH_IpcEndpoint2_Extend(GWEN_MSG_ENDPOINT2 *ep) +{ + AQH_ENDPOINT2_IPC *xep; + + GWEN_NEW_OBJECT(AQH_ENDPOINT2_IPC, xep); + GWEN_INHERIT_SETDATA(GWEN_MSG_ENDPOINT2, AQH_ENDPOINT2_IPC, ep, xep, _freeData); +} + + + +void _freeData(void *bp, void *p) +{ + AQH_ENDPOINT2_IPC *xep; + + xep=(AQH_ENDPOINT2_IPC*) p; + GWEN_FREE_OBJECT(xep); +} + + + +uint32_t AQH_IpcEndpoint2_GetAcceptedMsgGroups(const GWEN_MSG_ENDPOINT2 *ep) +{ + if (ep) { + AQH_ENDPOINT2_IPC *xep; + + xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT2, AQH_ENDPOINT2_IPC, ep); + if (xep) { + return xep->acceptedMsgGroups; + } + } + + return 0; +} + + + +void AQH_IpcEndpoint2_SetAcceptedMsgGroups(GWEN_MSG_ENDPOINT2 *ep, uint32_t i) +{ + if (ep) { + AQH_ENDPOINT2_IPC *xep; + + xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT2, AQH_ENDPOINT2_IPC, ep); + if (xep) + xep->acceptedMsgGroups=i; + } +} + + + +void AQH_IpcEndpoint2_AddAcceptedMsgGroups(GWEN_MSG_ENDPOINT2 *ep, uint32_t i) +{ + if (ep) { + AQH_ENDPOINT2_IPC *xep; + + xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT2, AQH_ENDPOINT2_IPC, ep); + if (xep) + xep->acceptedMsgGroups|=i; + } +} + + + +void AQH_IpcEndpoint2_SubAcceptedMsgGroups(GWEN_MSG_ENDPOINT2 *ep, uint32_t i) +{ + if (ep) { + AQH_ENDPOINT2_IPC *xep; + + xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT2, AQH_ENDPOINT2_IPC, ep); + if (xep) + xep->acceptedMsgGroups&=~i; + } +} + + + +GWEN_MSG_ENDPOINT2 *AQH_IpcEndpoint2_CreateIpcTcpClient(const char *host, int port, const char *name, int groupId) +{ + GWEN_MSG_ENDPOINT2 *ep; + + ep=GWEN_IpcEndpoint2_CreateIpcTcpClient(host, port, name?name:AQH_MSG_ENDPOINT2_IPC_NAME, groupId); + AQH_IpcEndpoint2_Extend(ep); + return ep; +} + + + +GWEN_MSG_ENDPOINT2 *AQH_IpcEndpoint2_CreateIpcTcpServiceForSocket(GWEN_SOCKET *sk, const char *name, int groupId) +{ + GWEN_MSG_ENDPOINT2 *ep; + + ep=GWEN_IpcEndpoint2_CreateIpcTcpServiceForSocket(sk, name?name:AQH_MSG_ENDPOINT2_IPC_NAME, groupId); + AQH_IpcEndpoint2_Extend(ep); + return ep; +} + + + diff --git a/aqhome/ipc/endpoint2_ipc.h b/aqhome/ipc/endpoint2_ipc.h new file mode 100644 index 0000000..3203a63 --- /dev/null +++ b/aqhome/ipc/endpoint2_ipc.h @@ -0,0 +1,31 @@ +/**************************************************************************** + * 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_ENDPOINT2_IPC_H +#define AQH_ENDPOINT2_IPC_H + + +#include + +#include + + + +AQHOME_API void AQH_IpcEndpoint2_Extend(GWEN_MSG_ENDPOINT2 *ep); + +AQHOME_API GWEN_MSG_ENDPOINT2 *AQH_IpcEndpoint2_CreateIpcTcpClient(const char *host, int port, const char *name, int groupId); +AQHOME_API GWEN_MSG_ENDPOINT2 *AQH_IpcEndpoint2_CreateIpcTcpServiceForSocket(GWEN_SOCKET *sk, const char *name, int groupId); + +AQHOME_API uint32_t AQH_IpcEndpoint2_GetAcceptedMsgGroups(const GWEN_MSG_ENDPOINT2 *ep); +AQHOME_API void AQH_IpcEndpoint2_SetAcceptedMsgGroups(GWEN_MSG_ENDPOINT2 *ep, uint32_t i); +AQHOME_API void AQH_IpcEndpoint2_AddAcceptedMsgGroups(GWEN_MSG_ENDPOINT2 *ep, uint32_t i); +AQHOME_API void AQH_IpcEndpoint2_SubAcceptedMsgGroups(GWEN_MSG_ENDPOINT2 *ep, uint32_t i); + + +#endif + diff --git a/aqhome/ipc/endpoint2_ipc_p.h b/aqhome/ipc/endpoint2_ipc_p.h new file mode 100644 index 0000000..aa46ce4 --- /dev/null +++ b/aqhome/ipc/endpoint2_ipc_p.h @@ -0,0 +1,38 @@ +/**************************************************************************** + * 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_ENDPOINT2_IPC_P_H +#define AQH_ENDPOINT2_IPC_P_H + + +#include + +#include + +#include "aqhome/ipc/endpoint2_ipc.h" + + +typedef struct AQH_ENDPOINT2_IPC AQH_ENDPOINT2_IPC; +struct AQH_ENDPOINT2_IPC { + uint32_t acceptedMsgGroups; +}; + + + + + +#endif + + + + + + + + + diff --git a/aqhome/mqtt/endpoint2_mqttc.c b/aqhome/mqtt/endpoint2_mqttc.c index 71d8d94..6db06b0 100644 --- a/aqhome/mqtt/endpoint2_mqttc.c +++ b/aqhome/mqtt/endpoint2_mqttc.c @@ -155,6 +155,34 @@ uint16_t AQH_MqttClientEndpoint2_GetNextPacketId(const GWEN_MSG_ENDPOINT2 *ep) +const char *AQH_MqttClientEndpoint2_GetTopicPrefix(const GWEN_MSG_ENDPOINT2 *ep) +{ + if (ep) { + GWEN_MSG_ENDPOINT2 *epChild; + + epChild=GWEN_MsgEndpoint2_Tree2_GetFirstChild(ep); + if (epChild) + return AQH_MqttEndpoint2_GetTopicPrefix(epChild); + } + return NULL; +} + + + +void AQH_MqttClientEndpoint2_SetTopicPrefix(GWEN_MSG_ENDPOINT2 *ep, const char *s) +{ + if (ep) { + GWEN_MSG_ENDPOINT2 *epChild; + + epChild=GWEN_MsgEndpoint2_Tree2_GetFirstChild(ep); + if (epChild) + AQH_MqttEndpoint2_SetTopicPrefix(epChild, s); + } +} + + + + void _addSockets(GWEN_MSG_ENDPOINT2 *ep, GWEN_SOCKETSET *readSet, GWEN_SOCKETSET *writeSet, GWEN_SOCKETSET *xSet) diff --git a/aqhome/mqtt/endpoint2_mqttc.h b/aqhome/mqtt/endpoint2_mqttc.h index 8324c29..6597295 100644 --- a/aqhome/mqtt/endpoint2_mqttc.h +++ b/aqhome/mqtt/endpoint2_mqttc.h @@ -31,6 +31,9 @@ AQHOME_API void AQH_MqttClientEndpoint2_SetKeepAliveTime(GWEN_MSG_ENDPOINT2 *ep, AQHOME_API uint16_t AQH_MqttClientEndpoint2_GetNextPacketId(const GWEN_MSG_ENDPOINT2 *ep); +AQHOME_API const char *AQH_MqttClientEndpoint2_GetTopicPrefix(const GWEN_MSG_ENDPOINT2 *ep); +AQHOME_API void AQH_MqttClientEndpoint2_SetTopicPrefix(GWEN_MSG_ENDPOINT2 *ep, const char *s); + AQHOME_API int AQH_MqttClientEndpoint2_StartConnect(GWEN_MSG_ENDPOINT2 *ep); diff --git a/aqhome/msg/endpoint2_tty.c b/aqhome/msg/endpoint2_tty.c index 5a9764c..1377dc8 100644 --- a/aqhome/msg/endpoint2_tty.c +++ b/aqhome/msg/endpoint2_tty.c @@ -69,7 +69,7 @@ static int _isAttnLow(GWEN_MSG_ENDPOINT2 *ep); */ -GWEN_MSG_ENDPOINT2 *AQH_TtyEndpoint_new(const char *devicePath, int groupId) +GWEN_MSG_ENDPOINT2 *AQH_TtyEndpoint2_new(const char *devicePath, int groupId) { GWEN_MSG_ENDPOINT2 *ep; AQH_MSG_ENDPOINT2_TTY *xep; @@ -117,7 +117,7 @@ void _addSockets(GWEN_MSG_ENDPOINT2 *ep, GWEN_SOCKETSET *readSet, GWEN_SOCKETSET int rv; /* (re)connect, set state */ - DBG_INFO(GWEN_LOGDOMAIN, "Starting to (re-)connect"); + DBG_INFO(AQH_LOGDOMAIN, "Starting to (re-)connect"); rv=GWEN_TtyEndpoint2_Connect(ep); if (rv<0) { DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); @@ -141,6 +141,7 @@ int GWEN_TtyEndpoint2_Connect(GWEN_MSG_ENDPOINT2 *ep) if (GWEN_MsgEndpoint2_GetState(ep)==GWEN_MSG_ENDPOINT_STATE_UNCONNECTED) { int fd; + DBG_INFO(AQH_LOGDOMAIN, "Connecting TTY device"); fd=_openDevice(ep); if (fd<0) { DBG_INFO(AQH_LOGDOMAIN, "here (%d)", fd); @@ -152,6 +153,8 @@ int GWEN_TtyEndpoint2_Connect(GWEN_MSG_ENDPOINT2 *ep) sk=GWEN_Socket_fromFile(fd); GWEN_MsgEndpoint2_SetSocket(ep, sk); GWEN_MsgEndpoint2_SetState(ep, GWEN_MSG_ENDPOINT_STATE_CONNECTED); + GWEN_MsgEndpoint2_DiscardInput(ep); + _attnHigh(ep); return 0; } } @@ -171,8 +174,9 @@ int _getSocketFd(GWEN_MSG_ENDPOINT2 *ep) GWEN_SOCKET *sk; sk=GWEN_MsgEndpoint2_GetSocket(ep); - if (sk) + if (sk) { return GWEN_Socket_GetSocketInt(sk); + } } return GWEN_ERROR_GENERIC; } @@ -188,11 +192,13 @@ int _openDevice(GWEN_MSG_ENDPOINT2 *ep) xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT2, AQH_MSG_ENDPOINT2_TTY, ep); assert(xep); + DBG_INFO(AQH_LOGDOMAIN, "Opening device %s", xep->deviceName); fd=open(xep->deviceName, O_NOCTTY | O_NDELAY | O_RDWR); if (fd<0) { DBG_ERROR(AQH_LOGDOMAIN, "Error on open(%s): %s (%d)", xep->deviceName, strerror(errno), errno); return GWEN_ERROR_IO; } + DBG_INFO(AQH_LOGDOMAIN, "Device %s open (socket %d)", xep->deviceName, fd); rv=tcgetattr(fd, &(xep->previousOptions)); if (rv<0) { DBG_ERROR(AQH_LOGDOMAIN, "Error on tcgetattr(%s): %s (%d)", xep->deviceName, strerror(errno), errno); @@ -284,7 +290,7 @@ int _getBytesNeededForMessage(GWEN_UNUSED GWEN_MSG_ENDPOINT2 *ep, GWEN_MSG *msg) bytesInMsg=GWEN_Msg_GetBytesInBuffer(msg); if (bytesInMsg