From a839d9714088b3ae80bcf804d228c4be523b2f41 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Sun, 22 Sep 2024 21:25:05 +0200 Subject: [PATCH] aqhome-tool: added command "setnodevalue". --- apps/aqhome-tool/main.c | 2 + apps/aqhome-tool/nodes/0BUILD | 2 + apps/aqhome-tool/nodes/setnodevalue.c | 295 ++++++++++++++++++++++++++ apps/aqhome-tool/nodes/setnodevalue.h | 20 ++ 4 files changed, 319 insertions(+) create mode 100644 apps/aqhome-tool/nodes/setnodevalue.c create mode 100644 apps/aqhome-tool/nodes/setnodevalue.h diff --git a/apps/aqhome-tool/main.c b/apps/aqhome-tool/main.c index 6da94d4..bc2f54b 100644 --- a/apps/aqhome-tool/main.c +++ b/apps/aqhome-tool/main.c @@ -13,6 +13,7 @@ #include "./nodes/ping.h" #include "./nodes/flash.h" #include "./nodes/getnodes.h" +#include "./nodes/setnodevalue.h" #include "./data/getvalues.h" #include "./data/getdevices.h" #include "./data/adddata.h" @@ -77,6 +78,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("setnodevalue", AQH_Tool_SetNodeValue, I18N("Set a raw value in a node")), GWEN_FE_DAH("getnodes", AQH_Tool_GetNodes, I18N("Request list of known devices on the network")), GWEN_FE_DAH("getvalues", AQH_Tool_GetValues, I18N("Request list of known values on the data server")), GWEN_FE_DAH("getdevices", AQH_Tool_GetDevices, I18N("Request list of known devices on the data server")), diff --git a/apps/aqhome-tool/nodes/0BUILD b/apps/aqhome-tool/nodes/0BUILD index 7563f9a..9a91fb6 100644 --- a/apps/aqhome-tool/nodes/0BUILD +++ b/apps/aqhome-tool/nodes/0BUILD @@ -36,6 +36,7 @@ ping.h flash.h getnodes.h + setnodevalue.h @@ -44,6 +45,7 @@ ping.c flash.c getnodes.c + setnodevalue.c diff --git a/apps/aqhome-tool/nodes/setnodevalue.c b/apps/aqhome-tool/nodes/setnodevalue.c new file mode 100644 index 0000000..df4cbd9 --- /dev/null +++ b/apps/aqhome-tool/nodes/setnodevalue.c @@ -0,0 +1,295 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2024 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 "./setnodevalue.h" +#include "../utils.h" + +#include "aqhome/ipc/nodes/msg_ipc_setaccmsggrps.h" +#include "aqhome/ipc/nodes/msg_ipc_ping.h" +#include "aqhome/ipc/nodes/msg_ipc_forward.h" +#include "aqhome/ipc/endpoint_ipc.h" +#include "aqhome/msg/msg_node.h" +#include "aqhome/msg/msg_value3.h" + +#include +#include +#include +#include + +#include +#include + + +#define I18S(msg) msg +#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg) + + + +static int _doSetValue(GWEN_DB_NODE *dbArgs); +static GWEN_MSG *_waitForSetValueResponse(GWEN_MSG_ENDPOINT *epTcp, int nodeAddr, int msgId, int timeoutInSeconds); + + + +int AQH_Tool_SetNodeValue(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 */ + "nodeAddr", /* name */ + 1, /* minnum */ + 1, /* maxnum */ + "n", /* short option */ + "nodeaddr", /* long option */ + I18S("Specify bus addr of the node to send to"), + I18S("Specify bus addr of the node to send to") + }, + { + 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 response"), + I18S("Specify timeout in seconds for response") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Int, /* type */ + "valueId", /* name */ + 1, /* minnum */ + 1, /* maxnum */ + "V", /* short option */ + "valueId", /* long option */ + I18S("Specify id of value to change"), + I18S("Specify id of value to change") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Int, /* type */ + "value", /* name */ + 1, /* minnum */ + 1, /* maxnum */ + "v", /* short option */ + "value", /* long option */ + I18S("Specify value to send"), + I18S("Specify value to send") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Int, /* type */ + "denom", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "d", /* short option */ + "denom", /* long option */ + I18S("Specify denominator to send"), + I18S("Specify denominator to send") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Int, /* type */ + "msgId", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "m", /* short option */ + "msgId", /* long option */ + I18S("Specify a msg id"), + I18S("Specify a msg id") + }, + { + 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 _doSetValue(dbLocalArgs); +} + + + +int _doSetValue(GWEN_DB_NODE *dbArgs) +{ + GWEN_MSG_ENDPOINT *epTcp; + int rv; + int nodeAddr; + int timeoutInSeconds; + int valueId; + int value; + int denom; + int msgId; + GWEN_MSG *msgNode; + GWEN_MSG *msgOut; + GWEN_MSG *msg; + + epTcp=Utils_SetupNodesClientEndpoint(dbArgs); + if (epTcp==NULL) { + DBG_ERROR(NULL, "ERROR creating TCP connection"); + return 2; + } + + nodeAddr=GWEN_DB_GetIntValue(dbArgs, "nodeAddr", 0, 0); + timeoutInSeconds=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 5); + + valueId=GWEN_DB_GetIntValue(dbArgs, "valueId", 0, 0); + msgId=GWEN_DB_GetIntValue(dbArgs, "msgId", 0, 0); + value=GWEN_DB_GetIntValue(dbArgs, "value", 0, 0); + denom=GWEN_DB_GetIntValue(dbArgs, "denom", 0, 1); + + rv=Utils_SendAcceptedMsgGroups(epTcp, AQH_MSG_TYPEGROUP_ALL); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return 2; + } + + fprintf(stdout, "Sending SETVALUE request\n"); + msgNode=AQH_Value3Msg_new(0xc1, nodeAddr, AQH_MSG_TYPE_VALUE_SET, msgId, valueId, value, denom); + if (msgNode==NULL) { + DBG_ERROR(NULL, "Error creating message"); + return GWEN_ERROR_GENERIC; + } + msgOut=AQH_ForwardIpcMsg_new(AQH_MSGTYPE_IPC_NODES_FORWARD, GWEN_Msg_GetConstBuffer(msgNode), GWEN_Msg_GetBytesInBuffer(msgNode)); + if (msgOut==NULL) { + DBG_ERROR(NULL, "Error creating message"); + return GWEN_ERROR_GENERIC; + } + GWEN_MsgEndpoint_AddSendMessage(epTcp, msgOut); + + msg=_waitForSetValueResponse(epTcp, nodeAddr, msgId, timeoutInSeconds); + if (msg==NULL) { + DBG_INFO(NULL, "No SETVALUE response received."); + return 2; + } + + if (AQH_NodeMsg_GetMsgType(msg)==AQH_MSG_TYPE_VALUE_SET_ACK) { + fprintf(stdout, "Value set\n"); + } + else { + fprintf(stdout, "Value not set\n"); + } + GWEN_Msg_free(msg); + GWEN_MsgEndpoint_free(epTcp); + return 0; +} + + + +GWEN_MSG *_waitForSetValueResponse(GWEN_MSG_ENDPOINT *epTcp, int nodeAddr, int msgId, int timeoutInSeconds) +{ + time_t startTime; + + startTime=time(NULL); + + for (;;) { + GWEN_MSG *msg; + time_t now; + + while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(epTcp)) ) { + if (GWEN_IpcMsg_GetCode(msg)==AQH_MSGTYPE_IPC_NODES_FORWARD) { + GWEN_MSG *nodeMsg; + + DBG_INFO(NULL, "Received IPC FORWARD message"); + nodeMsg=AQH_ForwardIpcMsg_GetCopyOfNodeMsg(msg); + if (nodeMsg) { + int recvNodeAddr; + int recvMsgType; + + recvNodeAddr=AQH_NodeMsg_GetSourceAddress(nodeMsg); + recvMsgType=AQH_NodeMsg_GetMsgType(nodeMsg); + DBG_INFO(AQH_LOGDOMAIN, "Received node msg from %d (%d)", recvNodeAddr, recvNodeAddr); + if ((nodeAddr==0 || recvNodeAddr==nodeAddr) && + (recvMsgType==AQH_MSG_TYPE_VALUE_SET_ACK || recvMsgType==AQH_MSG_TYPE_VALUE_SET_NACK)) { + int recvMsgId; + + recvMsgId=AQH_Value3Msg_GetMsgId(nodeMsg); + if (recvMsgId==msgId) { + GWEN_Msg_free(msg); + return nodeMsg; + } + } + } + } + else { + DBG_INFO(NULL, "Received IPC message %d, ignoring", GWEN_IpcMsg_GetCode(msg)); + } + GWEN_Msg_free(msg); + } /* while */ + now=time(NULL); + if (now-startTime>timeoutInSeconds) { + DBG_INFO(NULL, "Timeout"); + break; + } + GWEN_MsgEndpoint_IoLoop(epTcp, 2000); /* 2000 ms */ + } + + return NULL; +} + + + + + diff --git a/apps/aqhome-tool/nodes/setnodevalue.h b/apps/aqhome-tool/nodes/setnodevalue.h new file mode 100644 index 0000000..d143d6e --- /dev/null +++ b/apps/aqhome-tool/nodes/setnodevalue.h @@ -0,0 +1,20 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2024 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_SETNODEVALUE_H +#define AQHOME_TOOL_SETNODEVALUE_H + + +#include + + +int AQH_Tool_SetNodeValue(GWEN_DB_NODE *dbArgs, int argc, char **argv); + + +#endif +