From 546641d77002df1d3d32508f0b7228f516814bc6 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 24 Apr 2016 11:16:42 +0200 Subject: [PATCH] added "hex" command, added "--enablehex" commandline option (disabled by default), limit "write -h" to known messages only --- src/ebusd/main.cpp | 8 ++- src/ebusd/main.h | 1 + src/ebusd/mainloop.cpp | 113 +++++++++++++++++++++++++++++------------ src/ebusd/mainloop.h | 10 ++++ 4 files changed, 99 insertions(+), 33 deletions(-) diff --git a/src/ebusd/main.cpp b/src/ebusd/main.cpp index ff164c5e..454f285d 100644 --- a/src/ebusd/main.cpp +++ b/src/ebusd/main.cpp @@ -79,6 +79,7 @@ static struct options opt = { 0, // masterCount false, // generateSyn false, // foreground + false, // enableHex PID_FILE_NAME, // pidFile 8888, // port false, // localOnly @@ -117,7 +118,8 @@ static const char argpdoc[] = #define O_RCVTIM (O_SNDRET+1) #define O_MASCNT (O_RCVTIM+1) #define O_GENSYN (O_MASCNT+1) -#define O_PIDFIL (O_GENSYN+1) +#define O_HEXCMD (O_GENSYN+1) +#define O_PIDFIL (O_HEXCMD+1) #define O_LOCAL (O_PIDFIL+1) #define O_HTTPPT (O_LOCAL+1) #define O_HTMLPA (O_HTTPPT+1) @@ -153,6 +155,7 @@ static const struct argp_option argpoptions[] = { {NULL, 0, NULL, 0, "Daemon options:", 4 }, {"foreground", 'f', NULL, 0, "Run in foreground", 0 }, + {"enablehex", O_HEXCMD, NULL, 0, "Enable hex command", 0 }, {"pidfile", O_PIDFIL, "FILE", 0, "PID file name (only for daemon) [" PID_FILE_NAME "]", 0 }, {"port", 'p', "PORT", 0, "Listen for command line connections on PORT [8888]", 0 }, {"localhost", O_LOCAL, NULL, 0, "Listen for command line connections on 127.0.0.1 interface only", 0 }, @@ -305,6 +308,9 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) case 'f': // --foreground opt->foreground = true; break; + case O_HEXCMD: // --enablehex + opt->enableHex = true; + break; case O_PIDFIL: // --pidfile=/var/run/ebusd.pid if (arg == NULL || arg[0] == 0 || strcmp("/", arg) == 0) { argp_error(state, "invalid pidfile"); diff --git a/src/ebusd/main.h b/src/ebusd/main.h index d6444f7b..12174940 100644 --- a/src/ebusd/main.h +++ b/src/ebusd/main.h @@ -48,6 +48,7 @@ struct options bool generateSyn; //!< enable AUTO-SYN symbol generation bool foreground; //!< run in foreground + bool enableHex; //!< enable hex command const char* pidFile; //!< PID file name [/var/run/ebusd.pid] uint16_t port; //!< port to listen for command line connections [8888] bool localOnly; //!< listen on 127.0.0.1 interface only diff --git a/src/ebusd/mainloop.cpp b/src/ebusd/mainloop.cpp index f8ce4c4d..a60222f2 100644 --- a/src/ebusd/mainloop.cpp +++ b/src/ebusd/mainloop.cpp @@ -42,7 +42,7 @@ static const char* columnNames[] = { static const size_t columnCount = sizeof(columnNames) / sizeof(char*); MainLoop::MainLoop(const struct options opt, Device *device, MessageMap* messages) - : m_device(device), m_messages(messages), m_address(opt.address), m_scanConfig(opt.scanConfig) + : m_device(device), m_messages(messages), m_address(opt.address), m_scanConfig(opt.scanConfig), m_enableHex(opt.enableHex) { // setup Device m_device->setLogRaw(opt.logRaw); @@ -245,6 +245,11 @@ string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& conn return executeRead(args); if (strcasecmp(str, "W") == 0 || strcasecmp(str, "WRITE") == 0) return executeWrite(args); + if (strcasecmp(str, "HEX") == 0) { + if (m_enableHex) + return executeHex(args); + return "ERR: command not enabled"; + } if (strcasecmp(str, "F") == 0 || strcasecmp(str, "FIND") == 0) return executeFind(args); if (strcasecmp(str, "L") == 0 || strcasecmp(str, "LISTEN") == 0) @@ -412,10 +417,10 @@ string MainLoop::executeRead(vector &args) if (cacheMaster[1] == BROADCAST || isMaster(cacheMaster[1])) return getResultCode(RESULT_ERR_INVALID_ARG); - logNotice(lf_main, "hex read cmd: %s", cacheMaster.getDataStr(true, false).c_str()); + logNotice(lf_main, "read hex cmd: %s", cacheMaster.getDataStr(true, false).c_str()); // find message - Message* message = m_messages->find(cacheMaster); + Message* message = m_messages->find(cacheMaster, false, true, false, false); if (message == NULL) return getResultCode(RESULT_ERR_NOTFOUND); @@ -441,12 +446,12 @@ string MainLoop::executeRead(vector &args) if (ret==RESULT_OK) ret = message->decodeLastData(result); if (ret >= RESULT_OK) - logInfo(lf_main, "hex read %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), result.str().c_str()); + logInfo(lf_main, "read hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), result.str().c_str()); else - logError(lf_main, "hex read %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret)); + logError(lf_main, "read hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret)); return slave.getDataStr(); } - logError(lf_main, "hex read %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret)); + logError(lf_main, "read hex %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret)); return getResultCode(ret); } if (argPos == 0 || args.size() < argPos + 1 || args.size() > argPos + 2) @@ -461,14 +466,14 @@ string MainLoop::executeRead(vector &args) " -v be verbose (include circuit, name, field names, units, and comments)\n" " -n use numeric value of value=name pairs\n" " -i VALUE read additional message parameters from VALUE\n" - " NAME the NAME of the message to send\n" + " NAME NAME of the message to send\n" " FIELD only retrieve the field named FIELD\n" " N only retrieve the N'th field named FIELD (0-based)\n" " -h send hex read message (or answer from cache):\n" " ZZ destination address\n" " PB SB primary/secondary command byte\n" " NN number of following data bytes\n" - " Dx the data byte(s) to send"; + " Dx data byte(s) to send"; string fieldName; signed char fieldIndex = -2; @@ -584,10 +589,17 @@ string MainLoop::executeWrite(vector &args) if (ret != RESULT_OK) return getResultCode(ret); - logNotice(lf_main, "hex write cmd: %s", cacheMaster.getDataStr(true, false).c_str()); + logNotice(lf_main, "write hex cmd: %s", cacheMaster.getDataStr(true, false).c_str()); // find message - Message* message = m_messages->find(cacheMaster); + Message* message = m_messages->find(cacheMaster, false, false, true, false); + + if (message == NULL) + return getResultCode(RESULT_ERR_NOTFOUND); + if (!message->isWrite()) + return getResultCode(RESULT_ERR_INVALID_ARG); + if (circuit.length() > 0 && circuit!=message->getCircuit()) + return getResultCode(RESULT_ERR_INVALID_ARG); // non-matching circuit // send message SymbolString master(true); @@ -596,42 +608,38 @@ string MainLoop::executeWrite(vector &args) ret = m_busHandler->sendAndWait(master, slave); if (ret == RESULT_OK) { - if (message != NULL) { // also updates read messages - ret = message->storeLastData(cacheMaster, slave); - ostringstream result; - if (ret==RESULT_OK) - ret = message->decodeLastData(result); - if (ret >= RESULT_OK) - logInfo(lf_main, "hex write %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), result.str().c_str()); - else - logError(lf_main, "hex write %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret)); - } + // also update read messages + ret = message->storeLastData(cacheMaster, slave); + ostringstream result; + if (ret==RESULT_OK) + ret = message->decodeLastData(result); + if (ret >= RESULT_OK) + logInfo(lf_main, "write hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), result.str().c_str()); + else + logError(lf_main, "write hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret)); if (master[1] == BROADCAST) return "done broadcast"; if (isMaster(master[1])) return getResultCode(RESULT_OK); return slave.getDataStr(); } - if (message != NULL) - logError(lf_main, "hex write %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret)); - else - logError(lf_main, "hex write: %s", getResultCode(ret)); + logError(lf_main, "write hex %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret)); return getResultCode(ret); } if (argPos == 0 || circuit.empty() || (args.size() != argPos + 2 && args.size() != argPos + 1)) return "usage: write [-d ZZ] -c CIRCUIT NAME [VALUE[;VALUE]*]\n" - " or: write -h ZZPBSBNNDx\n" + " or: write [-c CIRCUIT] -h ZZPBSBNNDx\n" " Write value(s) or hex message.\n" " -d ZZ override destination address ZZ\n" - " -c CIRCUIT the CIRCUIT of the message to send\n" - " NAME the NAME of the message to send\n" + " -c CIRCUIT CIRCUIT of the message to send\n" + " NAME NAME of the message to send\n" " VALUE a single field VALUE\n" " -h send hex write message:\n" " ZZ destination address\n" " PB SB primary/secondary command byte\n" " NN number of following data bytes\n" - " Dx the data byte(s) to send"; + " Dx data byte(s) to send"; Message* message = m_messages->find(circuit, args[argPos], true); @@ -668,6 +676,46 @@ string MainLoop::executeWrite(vector &args) return result.str(); } +string MainLoop::executeHex(vector &args) +{ + size_t argPos = 1; + if (args.size() < argPos + 1 || (args.size() > argPos && args[argPos][0] == '-')) { + argPos = 0; // print usage + } + + if (argPos > 0) { + SymbolString cacheMaster(false); + result_t ret = parseHexMaster(args, argPos, cacheMaster); + if (ret != RESULT_OK) + return getResultCode(ret); + + logNotice(lf_main, "hex cmd: %s", cacheMaster.getDataStr(true, false).c_str()); + + // send message + SymbolString master(true); + master.addAll(cacheMaster); + SymbolString slave(false); + ret = m_busHandler->sendAndWait(master, slave); + + if (ret == RESULT_OK) { + if (master[1] == BROADCAST) + return "done broadcast"; + if (isMaster(master[1])) + return getResultCode(RESULT_OK); + return slave.getDataStr(); + } + logError(lf_main, "hex: %s", getResultCode(ret)); + return getResultCode(ret); + } + + return "usage: hex ZZPBSBNNDx\n" + " Send arbitrary data in hex (only if enabled).\n" + " ZZ destination address\n" + " PB SB primary/secondary command byte\n" + " NN number of following data bytes\n" + " Dx data byte(s) to send"; +} + string MainLoop::executeFind(vector &args) { size_t argPos = 1; @@ -774,7 +822,7 @@ string MainLoop::executeFind(vector &args) " (COL: type,circuit,name,comment,qq,zz,pbsb,id,fields)\n" " -e match NAME and optional CIRCUIT exactly (ignoring case)\n" " -c CIRCUIT limit to messages of CIRCUIT (or a part thereof without '-e')\n" - " NAME the NAME of the messages to find (or a part thereof without '-e')"; + " NAME NAME of the messages to find (or a part thereof without '-e')"; deque messages = m_messages->findAll( circuit, args.size() == argPos ? "" : args[argPos], exact, withRead, withWrite, withPassive @@ -943,8 +991,8 @@ string MainLoop::executeLog(vector &args) return "usage: log areas AREA[,AREA]*\n" " or: log level LEVEL\n" " Set log area(s) or log level.\n" - " AREA the log area to include (main|network|bus|update|all)\n" - " LEVEL the log level to set (error|notice|info|debug)"; + " AREA log area to include (main|network|bus|update|all)\n" + " LEVEL log level to set (error|notice|info|debug)"; if (result) return getResultCode(RESULT_OK); @@ -1036,7 +1084,8 @@ string MainLoop::executeHelp() " read|r Read value(s): read [-f] [-m SECONDS] [-c CIRCUIT] [-d ZZ] [-p PRIO] [-v] [-n] [-i VALUE[;VALUE]*] NAME [FIELD[.N]]\n" " Read hex message: read [-f] [-m SECONDS] [-c CIRCUIT] -h ZZPBSBNNDx\n" " write|w Write value(s): write [-d ZZ] -c CIRCUIT NAME [VALUE[;VALUE]*]\n" - " Write hex message: write -h ZZPBSBNNDx\n" + " Write hex message: write [-c CIRCUIT] -h ZZPBSBNNDx\n" + " hex Send hex data: hex ZZPBSBNNDx\n" " find|f Find message(s): find [-v] [-r] [-w] [-p] [-d] [-i ID] [-f] [-F COL[,COL]*] [-e] [-c CIRCUIT] [NAME]\n" " listen|l Listen for updates: listen [stop]\n" " state|s Report bus state\n" diff --git a/src/ebusd/mainloop.h b/src/ebusd/mainloop.h index 3f02fbca..ecc0ba5a 100644 --- a/src/ebusd/mainloop.h +++ b/src/ebusd/mainloop.h @@ -72,6 +72,9 @@ private: /** whether to pick configuration files matching initial scan. */ const bool m_scanConfig; + /** whether to enable the hex command. */ + const bool m_enableHex; + /** the created @a BusHandler instance. */ BusHandler* m_busHandler; @@ -127,6 +130,13 @@ private: */ string executeWrite(vector &args); + /** + * Execute the hex command. + * @param args the arguments passed to the command (starting with the command itself), or empty for help. + * @return the result string. + */ + string executeHex(vector &args); + /** * Execute the find command. * @param args the arguments passed to the command (starting with the command itself), or empty for help.