/**************************************************************************** * 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_MsgEndpoint_GetNextMessageId(epTcp), 0, 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; }