From 5f7e192e27bb3b51dce3310e3fdbcba1393d91df Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Sat, 22 Apr 2023 19:13:59 +0200 Subject: [PATCH] implemented ipc messages getdevices req/rsp --- apps/aqhome-tool/0BUILD | 2 + apps/aqhome-tool/getdevices.c | 220 ++++++++++++++++++++++++++++ apps/aqhome-tool/getdevices.h | 20 +++ apps/aqhome-tool/main.c | 2 + apps/aqhome-tool/utils.c | 41 ++++++ apps/aqhome-tool/utils.h | 4 + aqhome/ipc/0BUILD | 6 + aqhome/ipc/msg_ipc.h | 4 + aqhome/ipc/msg_ipc_error.c | 74 ++++++++++ aqhome/ipc/msg_ipc_error.h | 33 +++++ aqhome/ipc/msg_ipc_getdevices_req.c | 52 +++++++ aqhome/ipc/msg_ipc_getdevices_req.h | 27 ++++ aqhome/ipc/msg_ipc_getdevices_rsp.c | 162 ++++++++++++++++++++ aqhome/ipc/msg_ipc_getdevices_rsp.h | 40 +++++ aqhome/ipc/msg_ipc_value.h | 2 + aqhome/msgmanager.c | 97 +++++++++++- 16 files changed, 782 insertions(+), 4 deletions(-) create mode 100644 apps/aqhome-tool/getdevices.c create mode 100644 apps/aqhome-tool/getdevices.h create mode 100644 aqhome/ipc/msg_ipc_error.c create mode 100644 aqhome/ipc/msg_ipc_error.h create mode 100644 aqhome/ipc/msg_ipc_getdevices_req.c create mode 100644 aqhome/ipc/msg_ipc_getdevices_req.h create mode 100644 aqhome/ipc/msg_ipc_getdevices_rsp.c create mode 100644 aqhome/ipc/msg_ipc_getdevices_rsp.h diff --git a/apps/aqhome-tool/0BUILD b/apps/aqhome-tool/0BUILD index 151a413..bb9a4c6 100644 --- a/apps/aqhome-tool/0BUILD +++ b/apps/aqhome-tool/0BUILD @@ -35,6 +35,7 @@ ping.h flash.h + getdevices.h utils.h @@ -43,6 +44,7 @@ main.c ping.c flash.c + getdevices.c utils.c diff --git a/apps/aqhome-tool/getdevices.c b/apps/aqhome-tool/getdevices.c new file mode 100644 index 0000000..f6f02f9 --- /dev/null +++ b/apps/aqhome-tool/getdevices.c @@ -0,0 +1,220 @@ +/**************************************************************************** + * 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 "./getdevices.h" +#include "./utils.h" + +#include "aqhome/ipc/msg_ipc_getdevices_req.h" +#include "aqhome/ipc/msg_ipc_getdevices_rsp.h" +#include "aqhome/ipc/msg_ipc_error.h" +#include "aqhome/ipc/endpoint_ipc_tcpc.h" +#include "aqhome/msg/msg_node.h" + +#include +#include +#include +#include +#include + +#include +#include + + +#define I18S(msg) msg +#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg) + + + +static int _doGetDevices(GWEN_DB_NODE *dbArgs); +static int _sendGetDevices(GWEN_MSG_ENDPOINT *epTcp); + + + +int AQH_Tool_GetDevices(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv) +{ + GWEN_DB_NODE *dbLocalArgs; + int rv; + const GWEN_ARGS args[]= { + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "tcpAddress", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "t", /* short option */ + "tcpaddress", /* long option */ + I18S("Specify TCP address to connect to (defaults to 127.0.0.1)"), + I18S("Specify TCP address to connect to (defaults to 127.0.0.1)") + }, + { + 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_Int, /* type */ + "timeout", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "T", /* short option */ + NULL, /* long option */ + I18S("Specify timeout in seconds for PONG response"), + I18S("Specify timeout in seconds for PONG response") + }, + { + GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */ + GWEN_ArgsType_Int, /* type */ + "help", /* name */ + 0, /* minnum */ + 0, /* maxnum */ + "h", /* short option */ + "help", /* long option */ + "Show this help screen", /* short description */ + "Show this help screen" /* long description */ + } + }; + + dbLocalArgs=GWEN_DB_GetGroup(dbGlobalArgs, GWEN_DB_FLAGS_DEFAULT, "local"); + rv=GWEN_Args_Check(argc, argv, 1, + GWEN_ARGS_MODE_ALLOW_FREEPARAM, + args, + dbLocalArgs); + if (rv==GWEN_ARGS_RESULT_ERROR) { + fprintf(stderr, "ERROR: Could not parse arguments\n"); + return 1; + } + else if (rv==GWEN_ARGS_RESULT_HELP) { + GWEN_BUFFER *ubuf; + + ubuf=GWEN_Buffer_new(0, 1024, 0, 1); + if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) { + fprintf(stderr, "ERROR: Could not create help string\n"); + return 1; + } + fprintf(stderr, "%s\n", GWEN_Buffer_GetStart(ubuf)); + GWEN_Buffer_free(ubuf); + return 0; + } + + return _doGetDevices(dbLocalArgs); +} + + + +int _doGetDevices(GWEN_DB_NODE *dbArgs) +{ + GWEN_MSG_ENDPOINT_MGR *emgr; + GWEN_MSG_ENDPOINT *epTcp; + int rv; + int timeoutInSeconds; + + emgr=GWEN_MsgEndpointMgr_new(); + + epTcp=Utils_SetupIpcEndpoint(emgr, dbArgs); + if (epTcp==NULL) { + DBG_ERROR(NULL, "ERROR creating TCP connection"); + return 2; + } + GWEN_MsgEndpointMgr_AddEndpoint(emgr, epTcp); + + timeoutInSeconds=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 5); + + rv=Utils_SendAcceptedMsgGroups(epTcp, 0); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return 2; + } + + rv=_sendGetDevices(epTcp); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return 2; + } + + for (;;) { + GWEN_MSG *msg; + uint16_t code; + + msg=Utils_WaitForSpecificIpcMessage(emgr, epTcp, AQH_MSGTYPE_IPC_GETDEVICES_RSP, timeoutInSeconds); + if (msg==NULL) { + DBG_INFO(NULL, "No GET_DEVICE response received."); + GWEN_MsgEndpointMgr_free(emgr); + return 2; + } + code=GWEN_IpcMsg_GetCode(msg); + if (code==AQH_MSGTYPE_IPC_ERROR) { + fprintf(stdout, "No device list (%d)\n", AQH_ErrorIpcMsg_GetErrorCode(msg)); + GWEN_Msg_free(msg); + break; + } + else if (code==AQH_MSGTYPE_IPC_GETDEVICES_RSP) { + uint16_t fwVersion; + int64_t ts64; + GWEN_TIMESTAMP *ts; + uint8_t flags; + + flags=AQH_GetDevicesResponseIpcMsg_GetFlags(msg); + fwVersion=AQH_GetDevicesResponseIpcMsg_GetFirmwareVersion(msg); + ts64=AQH_GetDevicesResponseIpcMsg_GetTimestamp(msg); + ts=GWEN_Timestamp_fromInt64(ts64); /* TODO: fix timestamp */ + + fprintf(stdout, "- node: %02x (uid=%04x, firmware type=%02x, firmware version=%d.%d, timeStamp: %016lx)\n", + AQH_GetDevicesResponseIpcMsg_GetBusAddress(msg), + AQH_GetDevicesResponseIpcMsg_GetUid(msg), + AQH_GetDevicesResponseIpcMsg_GetFirmwareType(msg), + (fwVersion>>8) & 0xff, + fwVersion & 0xff, + (unsigned long int)ts64); + GWEN_Timestamp_free(ts); + GWEN_Msg_free(msg); + if (flags & AQH_MSGIPC_GETDEVICES_RSP_FLAGS_LAST) { + DBG_INFO(NULL, "Last"); + break; + } + } + else { + GWEN_Msg_free(msg); + return GWEN_ERROR_GENERIC; + } + } + + GWEN_MsgEndpointMgr_free(emgr); + return 0; +} + + + +int _sendGetDevices(GWEN_MSG_ENDPOINT *epTcp) +{ + GWEN_MSG *msgOut; + + msgOut=AQH_GetDevicesRequestIpcMsg_new(AQH_MSGTYPE_IPC_GETDEVICES_REQ); + if (msgOut==NULL) { + DBG_ERROR(NULL, "Error creating message"); + return GWEN_ERROR_GENERIC; + } + GWEN_MsgEndpoint_AddSendMessage(epTcp, msgOut); + return 0; +} + + + + + + diff --git a/apps/aqhome-tool/getdevices.h b/apps/aqhome-tool/getdevices.h new file mode 100644 index 0000000..e6949d6 --- /dev/null +++ b/apps/aqhome-tool/getdevices.h @@ -0,0 +1,20 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQHOME_TOOL_GETDEVICES_H +#define AQHOME_TOOL_GETDEVICES_H + + +#include + + +int AQH_Tool_GetDevices(GWEN_DB_NODE *dbArgs, int argc, char **argv); + + +#endif + diff --git a/apps/aqhome-tool/main.c b/apps/aqhome-tool/main.c index 2345976..2e06669 100644 --- a/apps/aqhome-tool/main.c +++ b/apps/aqhome-tool/main.c @@ -12,6 +12,7 @@ #include "./ping.h" #include "./flash.h" +#include "./getdevices.h" #include #include @@ -67,6 +68,7 @@ int main(int argc, char **argv) const GWEN_FUNCS cmdDefArray[]= { GWEN_FE_DAH("ping", AQH_Tool_Ping, I18N("Ping a given node on the network")), GWEN_FE_DAH("flash", AQH_Tool_Flash, I18N("Flash a given node on the network")), + GWEN_FE_DAH("getdevices", AQH_Tool_GetDevices, I18N("Request list of known devices on the network")), GWEN_FE_END(), }; const GWEN_FUNCS *func; diff --git a/apps/aqhome-tool/utils.c b/apps/aqhome-tool/utils.c index 173d668..3fb5973 100644 --- a/apps/aqhome-tool/utils.c +++ b/apps/aqhome-tool/utils.c @@ -93,6 +93,47 @@ GWEN_MSG *Utils_WaitForSpecificNodeMessage(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG +GWEN_MSG *Utils_WaitForSpecificIpcMessage(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *epTcp, + int msgCode, + int timeoutInSeconds) +{ + time_t startTime; + + startTime=time(NULL); + + for (;;) { + GWEN_MSG *msg; + time_t now; + + GWEN_MsgEndpointMgr_RunAllEndpoints(emgr); + GWEN_MsgEndpointMgr_IoLoopOnce(emgr); + msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(epTcp); + if (msg) { + uint16_t code; + + code=GWEN_IpcMsg_GetCode(msg); + if (code==msgCode) { + DBG_INFO(NULL, "Received expected IPC message"); + return msg; + } + else if (code==AQH_MSGTYPE_IPC_ERROR) { + DBG_INFO(NULL, "Received IPC error message"); + return msg; + } + GWEN_Msg_free(msg); + } + now=time(NULL); + if (now-startTime>timeoutInSeconds) { + DBG_INFO(NULL, "Timeout"); + break; + } + } + + return NULL; +} + + + int Utils_FlushOutMessageQueue(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *epTcp, int timeoutInSeconds) { time_t startTime; diff --git a/apps/aqhome-tool/utils.h b/apps/aqhome-tool/utils.h index f33b611..dcffd0c 100644 --- a/apps/aqhome-tool/utils.h +++ b/apps/aqhome-tool/utils.h @@ -22,6 +22,10 @@ GWEN_MSG *Utils_WaitForSpecificNodeMessage(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG int nodeAddr, int timeoutInSeconds); +GWEN_MSG *Utils_WaitForSpecificIpcMessage(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *epTcp, + int msgCode, + int timeoutInSeconds); + int Utils_FlushOutMessageQueue(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *epTcp, int timeoutInSeconds); int Utils_SendAcceptedMsgGroups(GWEN_MSG_ENDPOINT *epTcp, uint32_t groups); diff --git a/aqhome/ipc/0BUILD b/aqhome/ipc/0BUILD index f9ca1f6..dd84d0f 100644 --- a/aqhome/ipc/0BUILD +++ b/aqhome/ipc/0BUILD @@ -53,7 +53,10 @@ msg_ipc_forward.h msg_ipc_value.h msg_ipc_ping.h + msg_ipc_error.h msg_ipc_setaccmsggrps.h + msg_ipc_getdevices_req.h + msg_ipc_getdevices_rsp.h @@ -71,7 +74,10 @@ msg_ipc_forward.c msg_ipc_value.c msg_ipc_ping.c + msg_ipc_error.c msg_ipc_setaccmsggrps.c + msg_ipc_getdevices_req.c + msg_ipc_getdevices_rsp.c diff --git a/aqhome/ipc/msg_ipc.h b/aqhome/ipc/msg_ipc.h index 4c7790d..50f7086 100644 --- a/aqhome/ipc/msg_ipc.h +++ b/aqhome/ipc/msg_ipc.h @@ -24,6 +24,10 @@ #define AQH_MSGTYPE_IPC_VALUE 0x200 #define AQH_MSGTYPE_IPC_PING 0x300 #define AQH_MSGTYPE_IPC_SETACCMSGGRPS 0x400 +#define AQH_MSGTYPE_IPC_GETDEVICES_REQ 0x500 +#define AQH_MSGTYPE_IPC_GETDEVICES_RSP 0x600 +#define AQH_MSGTYPE_IPC_ERROR 0x700 + diff --git a/aqhome/ipc/msg_ipc_error.c b/aqhome/ipc/msg_ipc_error.c new file mode 100644 index 0000000..65d40ec --- /dev/null +++ b/aqhome/ipc/msg_ipc_error.c @@ -0,0 +1,74 @@ +/**************************************************************************** + * 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 + +#include +#include + +#include +#include +#include +#include +#include +#include + + +#define AQH_MSGIPC_ERROR_OFFS_ERRORCODE 0 /* 2 bytes */ + +#define AQH_MSGIPC_ERROR_MINSIZE (GWEN_MSGIPC_OFFS_PAYLOAD+AQH_MSGIPC_ERROR_OFFS_ERRORCODE+2) + + + + +GWEN_MSG *AQH_ErrorIpcMsg_new(uint16_t code, uint16_t errorCode) +{ + GWEN_MSG *msg; + uint8_t *ptr; + + msg=GWEN_IpcMsg_new(AQH_IPC_PROTOCOL_ID, AQH_IPC_PROTOCOL_VERSION, code, AQH_MSGIPC_ERROR_MINSIZE, NULL); + ptr=GWEN_Msg_GetBuffer(msg); + ptr[GWEN_MSGIPC_OFFS_PAYLOAD+AQH_MSGIPC_ERROR_OFFS_ERRORCODE+0]=errorCode & 0xff; + ptr[GWEN_MSGIPC_OFFS_PAYLOAD+AQH_MSGIPC_ERROR_OFFS_ERRORCODE+1]=errorCode & 0xff; + + return msg; +} + + + +uint16_t AQH_ErrorIpcMsg_GetErrorCode(const GWEN_MSG *msg) +{ + return GWEN_Msg_GetUint16At(msg, GWEN_MSGIPC_OFFS_PAYLOAD+AQH_MSGIPC_ERROR_OFFS_ERRORCODE, 0); +} + + + + + +void AQH_ErrorIpcMsg_DumpToBuffer(const GWEN_MSG *msg, GWEN_BUFFER *dbuf, const char *sText) +{ + if (GWEN_Msg_GetBytesInBuffer(msg)>=AQH_MSGIPC_ERROR_MINSIZE) { + GWEN_Buffer_AppendArgs(dbuf, + "ERROR (code=%d, proto=%d, proto version=%d, error=%d)\n", + GWEN_IpcMsg_GetCode(msg), + GWEN_IpcMsg_GetProtoId(msg), + GWEN_IpcMsg_GetProtoVersion(msg), + AQH_ErrorIpcMsg_GetErrorCode(msg)); + } +} + + + + + + + diff --git a/aqhome/ipc/msg_ipc_error.h b/aqhome/ipc/msg_ipc_error.h new file mode 100644 index 0000000..fdc2c5f --- /dev/null +++ b/aqhome/ipc/msg_ipc_error.h @@ -0,0 +1,33 @@ +/**************************************************************************** + * 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_IPC_ERROR_H +#define AQH_MSG_IPC_ERROR_H + + +#include +#include +#include + +#include +#include + + +#define AQH_MSG_IPC_ERROR_OK 0 +#define AQH_MSG_IPC_ERROR_NODATA 1 + + +AQHOME_API GWEN_MSG *AQH_ErrorIpcMsg_new(uint16_t code, uint16_t errorCode); +AQHOME_API uint16_t AQH_ErrorIpcMsg_GetErrorCode(const GWEN_MSG *msg); +AQHOME_API void AQH_ErrorIpcMsg_DumpToBuffer(const GWEN_MSG *msg, GWEN_BUFFER *dbuf, const char *sText); + + +#endif + + + diff --git a/aqhome/ipc/msg_ipc_getdevices_req.c b/aqhome/ipc/msg_ipc_getdevices_req.c new file mode 100644 index 0000000..7fd508c --- /dev/null +++ b/aqhome/ipc/msg_ipc_getdevices_req.c @@ -0,0 +1,52 @@ +/**************************************************************************** + * 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 + +#include +#include + +#include +#include +#include +#include +#include +#include + + +#define AQH_MSGIPC_GETDEVICES_REQ_MINSIZE (GWEN_MSGIPC_OFFS_PAYLOAD) + + + + +GWEN_MSG *AQH_GetDevicesRequestIpcMsg_new(uint16_t code) +{ + return GWEN_IpcMsg_new(AQH_IPC_PROTOCOL_ID, AQH_IPC_PROTOCOL_VERSION, code, AQH_MSGIPC_GETDEVICES_REQ_MINSIZE, NULL); +} + + + +void AQH_GetDevicesRequestIpcMsg_DumpToBuffer(const GWEN_MSG *msg, GWEN_BUFFER *dbuf, const char *sText) +{ + if (GWEN_Msg_GetBytesInBuffer(msg)>=AQH_MSGIPC_GETDEVICES_REQ_MINSIZE) { + GWEN_Buffer_AppendArgs(dbuf, + "GET_DEVICES REQ (code=%d, proto=%d, proto version=%d)\n", + GWEN_IpcMsg_GetCode(msg), + GWEN_IpcMsg_GetProtoId(msg), + GWEN_IpcMsg_GetProtoVersion(msg)); + } +} + + + + + diff --git a/aqhome/ipc/msg_ipc_getdevices_req.h b/aqhome/ipc/msg_ipc_getdevices_req.h new file mode 100644 index 0000000..7de7a97 --- /dev/null +++ b/aqhome/ipc/msg_ipc_getdevices_req.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQH_MSGIPC_GETDEVICES_REQ_H +#define AQH_MSGIPC_GETDEVICES_REQ_H + + +#include +#include + +#include +#include + + +AQHOME_API GWEN_MSG *AQH_GetDevicesRequestIpcMsg_new(uint16_t code); + +AQHOME_API void AQH_GetDevicesRequestIpcMsg_DumpToBuffer(const GWEN_MSG *msg, GWEN_BUFFER *dbuf, const char *sText); + + + +#endif + diff --git a/aqhome/ipc/msg_ipc_getdevices_rsp.c b/aqhome/ipc/msg_ipc_getdevices_rsp.c new file mode 100644 index 0000000..7845b44 --- /dev/null +++ b/aqhome/ipc/msg_ipc_getdevices_rsp.c @@ -0,0 +1,162 @@ +/**************************************************************************** + * 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 + +#include +#include + +#include +#include +#include +#include +#include +#include + + +#define AQH_MSGIPC_GETDEVICES_RSP_OFFS_FLAGS 0 /* 1 bytes */ +#define AQH_MSGIPC_GETDEVICES_RSP_OFFS_BUSADDR 1 /* 1 bytes */ +#define AQH_MSGIPC_GETDEVICES_RSP_OFFS_UID 2 /* 4 bytes */ +#define AQH_MSGIPC_GETDEVICES_RSP_OFFS_FWTYPE 6 /* 2 bytes */ +#define AQH_MSGIPC_GETDEVICES_RSP_OFFS_FWVER 8 /* 2 bytes */ +#define AQH_MSGIPC_GETDEVICES_RSP_OFFS_MODULES 10 /* 2 bytes */ +#define AQH_MSGIPC_GETDEVICES_RSP_OFFS_LASTCHG 12 /* 8 bytes */ + + +#define AQH_MSGIPC_GETDEVICES_RSP_MINSIZE (GWEN_MSGIPC_OFFS_PAYLOAD+AQH_MSGIPC_GETDEVICES_RSP_OFFS_LASTCHG+8) + + + + +GWEN_MSG *AQH_GetDevicesResponseIpcMsg_new(uint16_t code, uint8_t flags, const AQH_NODE_INFO *ni) +{ + GWEN_MSG *msg; + uint8_t *ptr; + uint32_t u32; + uint64_t u64=0; + const GWEN_TIMESTAMP *t; + + msg=GWEN_IpcMsg_new(AQH_IPC_PROTOCOL_ID, AQH_IPC_PROTOCOL_VERSION, code, AQH_MSGIPC_GETDEVICES_RSP_MINSIZE, NULL); + ptr=GWEN_Msg_GetBuffer(msg)+GWEN_MSGIPC_OFFS_PAYLOAD; + + *(ptr++)=flags & 0xff; + + *(ptr++)=AQH_NodeInfo_GetBusAddress(ni); + + u32=AQH_NodeInfo_GetUid(ni); + *(ptr++)=u32 & 0xff; + *(ptr++)=(u32>>8) & 0xff; + *(ptr++)=(u32>>16) & 0xff; + *(ptr++)=(u32>>24) & 0xff; + + u32=AQH_NodeInfo_GetFirmwareType(ni); + *(ptr++)=u32 & 0xff; + *(ptr++)=(u32>>8) & 0xff; + + u32=AQH_NodeInfo_GetFirmwareVersion(ni); + *(ptr++)=u32 & 0xff; + *(ptr++)=(u32>>8) & 0xff; + + u32=AQH_NodeInfo_GetModules(ni); + *(ptr++)=u32 & 0xff; + *(ptr++)=(u32>>8) & 0xff; + + t=AQH_NodeInfo_GetTimestampLastChange(ni); + if (t) + u64=(uint64_t)GWEN_Timestamp_toInt64(t); + *(ptr++)=u64 & 0xff; + *(ptr++)=(u64>>8) & 0xff; + *(ptr++)=(u64>>16) & 0xff; + *(ptr++)=(u64>>24) & 0xff; + *(ptr++)=(u64>>32) & 0xff; + *(ptr++)=(u64>>40) & 0xff; + *(ptr++)=(u64>>48) & 0xff; + *(ptr++)=(u64>>56) & 0xff; + + return msg; +} + + + +uint8_t AQH_GetDevicesResponseIpcMsg_GetFlags(const GWEN_MSG *msg) +{ + return GWEN_Msg_GetUint8At(msg, GWEN_MSGIPC_OFFS_PAYLOAD+AQH_MSGIPC_GETDEVICES_RSP_OFFS_FLAGS, 0); +} + + + +uint8_t AQH_GetDevicesResponseIpcMsg_GetBusAddress(const GWEN_MSG *msg) +{ + return GWEN_Msg_GetUint16At(msg, GWEN_MSGIPC_OFFS_PAYLOAD+AQH_MSGIPC_GETDEVICES_RSP_OFFS_BUSADDR, 0); +} + + + +uint32_t AQH_GetDevicesResponseIpcMsg_GetUid(const GWEN_MSG *msg) +{ + return GWEN_Msg_GetUint32At(msg, GWEN_MSGIPC_OFFS_PAYLOAD+AQH_MSGIPC_GETDEVICES_RSP_OFFS_UID, 0); +} + + + +uint16_t AQH_GetDevicesResponseIpcMsg_GetFirmwareType(const GWEN_MSG *msg) +{ + return GWEN_Msg_GetUint16At(msg, GWEN_MSGIPC_OFFS_PAYLOAD+AQH_MSGIPC_GETDEVICES_RSP_OFFS_FWTYPE, 0); +} + + + +uint16_t AQH_GetDevicesResponseIpcMsg_GetFirmwareVersion(const GWEN_MSG *msg) +{ + return GWEN_Msg_GetUint16At(msg, GWEN_MSGIPC_OFFS_PAYLOAD+AQH_MSGIPC_GETDEVICES_RSP_OFFS_FWVER, 0); +} + + + +uint16_t AQH_GetDevicesResponseIpcMsg_GetModules(const GWEN_MSG *msg) +{ + return GWEN_Msg_GetUint16At(msg, GWEN_MSGIPC_OFFS_PAYLOAD+AQH_MSGIPC_GETDEVICES_RSP_OFFS_MODULES, 0); +} + + + +int64_t AQH_GetDevicesResponseIpcMsg_GetTimestamp(const GWEN_MSG *msg) +{ + uint64_t v; + + v=(uint64_t) GWEN_Msg_GetUint32At(msg, GWEN_MSGIPC_OFFS_PAYLOAD+AQH_MSGIPC_GETDEVICES_RSP_OFFS_LASTCHG, 0); + v|=((uint64_t)GWEN_Msg_GetUint32At(msg, GWEN_MSGIPC_OFFS_PAYLOAD+AQH_MSGIPC_GETDEVICES_RSP_OFFS_LASTCHG+4, 0))<<32; + return (int64_t) v; +} + + + +void AQH_GetDevicesResponseIpcMsg_DumpToBuffer(const GWEN_MSG *msg, GWEN_BUFFER *dbuf, const char *sText) +{ + if (GWEN_Msg_GetBytesInBuffer(msg)>=AQH_MSGIPC_GETDEVICES_RSP_MINSIZE) { + GWEN_Buffer_AppendArgs(dbuf, + "GET_DEVICES_RSP (code=%d, proto=%d, proto version=%d, uid=0x%08x, bus addr=0x%02x, flags=0x%02x)\n", + GWEN_IpcMsg_GetCode(msg), + GWEN_IpcMsg_GetProtoId(msg), + GWEN_IpcMsg_GetProtoVersion(msg), + (unsigned int) AQH_GetDevicesResponseIpcMsg_GetUid(msg), + AQH_GetDevicesResponseIpcMsg_GetBusAddress(msg), + AQH_GetDevicesResponseIpcMsg_GetFlags(msg)); + } +} + + + + + + + diff --git a/aqhome/ipc/msg_ipc_getdevices_rsp.h b/aqhome/ipc/msg_ipc_getdevices_rsp.h new file mode 100644 index 0000000..bf1a8fd --- /dev/null +++ b/aqhome/ipc/msg_ipc_getdevices_rsp.h @@ -0,0 +1,40 @@ +/**************************************************************************** + * 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_MSGIPC_GETDEVICES_RSP_H +#define AQH_MSGIPC_GETDEVICES_RSP_H + + +#include +#include +#include + +#include +#include + + +#define AQH_MSGIPC_GETDEVICES_RSP_FLAGS_LAST 0x01 + + +AQHOME_API GWEN_MSG *AQH_GetDevicesResponseIpcMsg_new(uint16_t code, uint8_t flags, const AQH_NODE_INFO *ni); + +AQHOME_API uint8_t AQH_GetDevicesResponseIpcMsg_GetFlags(const GWEN_MSG *msg); +AQHOME_API uint8_t AQH_GetDevicesResponseIpcMsg_GetBusAddress(const GWEN_MSG *msg); + +AQHOME_API uint32_t AQH_GetDevicesResponseIpcMsg_GetUid(const GWEN_MSG *msg); +AQHOME_API uint16_t AQH_GetDevicesResponseIpcMsg_GetFirmwareType(const GWEN_MSG *msg); +AQHOME_API uint16_t AQH_GetDevicesResponseIpcMsg_GetFirmwareVersion(const GWEN_MSG *msg); +AQHOME_API uint16_t AQH_GetDevicesResponseIpcMsg_GetModules(const GWEN_MSG *msg); +AQHOME_API int64_t AQH_GetDevicesResponseIpcMsg_GetTimestamp(const GWEN_MSG *msg); + +AQHOME_API void AQH_GetDevicesResponseIpcMsg_DumpToBuffer(const GWEN_MSG *msg, GWEN_BUFFER *dbuf, const char *sText); + + + +#endif + diff --git a/aqhome/ipc/msg_ipc_value.h b/aqhome/ipc/msg_ipc_value.h index 2af8a69..1bd85e4 100644 --- a/aqhome/ipc/msg_ipc_value.h +++ b/aqhome/ipc/msg_ipc_value.h @@ -32,6 +32,8 @@ AQHOME_API int16_t AQH_ValueIpcMsg_GetValueNom(const GWEN_MSG *msg); AQHOME_API int16_t AQH_ValueIpcMsg_GetValueDenom(const GWEN_MSG *msg); AQHOME_API double AQH_ValueIpcMsg_GetValueAsDouble(const GWEN_MSG *msg); +AQHOME_API void AQH_ValueIpcMsg_DumpToBuffer(const GWEN_MSG *msg, GWEN_BUFFER *dbuf, const char *sText); + #endif diff --git a/aqhome/msgmanager.c b/aqhome/msgmanager.c index 89e2257..9b62140 100644 --- a/aqhome/msgmanager.c +++ b/aqhome/msgmanager.c @@ -22,6 +22,7 @@ #include "aqhome/msg/msg_haveaddr.h" #include "aqhome/msg/msg_device.h" #include "aqhome/msg/msg_ping.h" +#include "aqhome/msg/msg_flashready.h" #include "aqhome/msg/endpoint_tty.h" #include "aqhome/msg/endpoint_node.h" #include "aqhome/mqtt/endpoint_mqttc.h" @@ -29,6 +30,8 @@ #include "aqhome/ipc/msg_ipc_ping.h" #include "aqhome/ipc/msg_ipc_setaccmsggrps.h" #include "aqhome/ipc/msg_ipc_forward.h" +#include "aqhome/ipc/msg_ipc_getdevices_rsp.h" +#include "aqhome/ipc/msg_ipc_error.h" #include #include @@ -54,12 +57,15 @@ static void _handleMsgHaveAddress(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT static void _handleMsgComSendStat(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg); static void _handleMsgComRecvStat(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg); static void _handleMsgDevice(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg); +static void _handleMsgFlashReady(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg); static void _handleIpcMsgPing(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg); static void _handleIpcMsgSetAccMsgGrps(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg); static void _handleIpcMsgForward(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg); +static void _handleIpcMsgGetDevicesReq(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg); static AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(GWEN_MSG_ENDPOINT_MGR *emgr, const GWEN_MSG *msg, uint32_t uid); +static void _updateTimestampLastChange(AQH_NODE_INFO *ni); @@ -230,6 +236,7 @@ void _handleNodeMsg(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *ep, const GW case AQH_MSG_TYPE_CLAIM_ADDRESS: _handleMsgClaimAddress(emgr, ep, msg); break; case AQH_MSG_TYPE_HAVE_ADDRESS: _handleMsgHaveAddress(emgr, ep, msg); break; case AQH_MSG_TYPE_DEVICE: _handleMsgDevice(emgr, ep, msg); break; + case AQH_MSG_TYPE_FLASH_READY: _handleMsgFlashReady(emgr, ep, msg); break; default: break; } } @@ -245,10 +252,11 @@ void _handleIpcMsg(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *ep, const GWE code=GWEN_IpcMsg_GetCode(msg); DBG_ERROR(AQH_LOGDOMAIN, "Received IPC packet"); switch(code) { - case AQH_MSGTYPE_IPC_PING: _handleIpcMsgPing(emgr, ep, msg); break; - case AQH_MSGTYPE_IPC_SETACCMSGGRPS: _handleIpcMsgSetAccMsgGrps(emgr, ep, msg); break; + case AQH_MSGTYPE_IPC_PING: _handleIpcMsgPing(emgr, ep, msg); break; + case AQH_MSGTYPE_IPC_SETACCMSGGRPS: _handleIpcMsgSetAccMsgGrps(emgr, ep, msg); break; case AQH_MSGTYPE_IPC_FORWARD: _handleIpcMsgForward(emgr, ep, msg); break; - default: break; + case AQH_MSGTYPE_IPC_GETDEVICES_REQ: _handleIpcMsgGetDevicesReq(emgr, ep, msg); break; + default: break; } } @@ -301,6 +309,46 @@ void _handleIpcMsgForward(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *ep, co +void _handleIpcMsgGetDevicesReq(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg) +{ + AQH_MSG_MANAGER *xmgr; + + xmgr=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT_MGR, AQH_MSG_MANAGER, emgr); + if (xmgr) { + AQH_NODE_INFO_LIST *nodeInfoList; + + DBG_ERROR(AQH_LOGDOMAIN, "Received IPC GetDevicesRequest message"); + nodeInfoList=AQH_NodeDb_GetAllNodeInfos(xmgr->nodeDb); + if (nodeInfoList && AQH_NodeInfo_List_GetCount(nodeInfoList)) { + const AQH_NODE_INFO *ni; + + ni=AQH_NodeInfo_List_First(nodeInfoList); + while(ni) { + const AQH_NODE_INFO *niNext; + GWEN_MSG *msgOut; + + niNext=AQH_NodeInfo_List_Next(ni); + DBG_INFO(AQH_LOGDOMAIN, "Sending response for node %02x (%08x)", AQH_NodeInfo_GetBusAddress(ni), AQH_NodeInfo_GetUid(ni)); + msgOut=AQH_GetDevicesResponseIpcMsg_new(AQH_MSGTYPE_IPC_GETDEVICES_RSP, niNext?0:AQH_MSGIPC_GETDEVICES_RSP_FLAGS_LAST, ni); + GWEN_MsgEndpoint_AddSendMessage(ep, msgOut); + ni=niNext; + } + } + else { + GWEN_MSG *msgOut; + + DBG_INFO(AQH_LOGDOMAIN, "No nodes"); + msgOut=AQH_ErrorIpcMsg_new(AQH_MSGTYPE_IPC_ERROR, AQH_MSG_IPC_ERROR_NODATA); + GWEN_MsgEndpoint_AddSendMessage(ep, msgOut); + } + } +} + + + + + + void _handleMsgValue2(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg) { AQH_MSG_MANAGER *xmgr; @@ -395,6 +443,7 @@ void _handleMsgComSendStat(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *ep, c AQH_NodeInfo_SetStatsCollisions(ni, AQH_SendStatsMsg_GetCollisions(msg)); AQH_NodeInfo_SetStatsBusy(ni, AQH_SendStatsMsg_GetBusyErrors(msg)); AQH_NodeDb_SetModified(xmgr->nodeDb); + _updateTimestampLastChange(ni); } } @@ -418,6 +467,7 @@ void _handleMsgComRecvStat(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *ep, c AQH_NodeInfo_SetStatsCrcErrors(ni, AQH_RecvStatsMsg_GetCrcErrors(msg)); AQH_NodeInfo_SetStatsIoErrors(ni, AQH_RecvStatsMsg_GetIoErrors(msg)); AQH_NodeDb_SetModified(xmgr->nodeDb); + _updateTimestampLastChange(ni); } } @@ -438,6 +488,32 @@ void _handleMsgDevice(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *ep, const 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(xmgr->nodeDb); + } + else { + DBG_INFO(AQH_LOGDOMAIN, "Error handling message"); + } + } +} + + + +void _handleMsgFlashReady(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg) +{ + AQH_MSG_MANAGER *xmgr; + + xmgr=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT_MGR, AQH_MSG_MANAGER, emgr); + if (xmgr) { + AQH_NODE_INFO *ni; + uint32_t uid; + + uid=AQH_FlashReadyMsg_GetUid(msg); + ni=_getOrCreateNodeAndUpdateUidAddr(emgr, 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(xmgr->nodeDb); } else { @@ -465,7 +541,8 @@ AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(GWEN_MSG_ENDPOINT_MGR *emgr, con 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); + AQH_NodeInfo_SetBusAddress(ni, busAddr); + _updateTimestampLastChange(ni); AQH_NodeDb_SetModified(xmgr->nodeDb); } } @@ -475,6 +552,7 @@ AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(GWEN_MSG_ENDPOINT_MGR *emgr, con ni=AQH_NodeInfo_new(); AQH_NodeInfo_SetBusAddress(ni, busAddr); AQH_NodeInfo_SetUid(ni, uid); + _updateTimestampLastChange(ni); rv=AQH_NodeDb_AddNodeInfo(xmgr->nodeDb, ni); if (rv<0) { DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); @@ -492,6 +570,17 @@ AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(GWEN_MSG_ENDPOINT_MGR *emgr, con +void _updateTimestampLastChange(AQH_NODE_INFO *ni) +{ + GWEN_TIMESTAMP *t; + + t=GWEN_Timestamp_NowInLocalTime(); + AQH_NodeInfo_SetTimestampLastChange(ni, t); + GWEN_Timestamp_free(t); +} + + +