From e0ffd2802441d6b6dff732d3f0dfbdc58da38b82 Mon Sep 17 00:00:00 2001 From: john30 Date: Mon, 25 May 2015 13:32:12 +0200 Subject: [PATCH] added hex option to read command, update cache on successfule hex write --- src/ebusd/mainloop.cpp | 216 ++++++++++++++++++++++++++++------------- src/ebusd/mainloop.h | 19 ++++ 2 files changed, 168 insertions(+), 67 deletions(-) diff --git a/src/ebusd/mainloop.cpp b/src/ebusd/mainloop.cpp index fd541871..6909760f 100644 --- a/src/ebusd/mainloop.cpp +++ b/src/ebusd/mainloop.cpp @@ -206,15 +206,61 @@ string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& conn return "ERR: command not found"; } +result_t MainLoop::parseHexMaster(vector &args, size_t argPos, SymbolString& master) +{ + ostringstream msg; + while (argPos < args.size()) { + if ((args[argPos].length() % 2) != 0) { + return RESULT_ERR_INVALID_NUM; + } + msg << args[argPos++]; + } + if (msg.str().size() < 4*2) // at least ZZ, PB, SB, NN + return RESULT_ERR_INVALID_ARG; + + result_t ret; + unsigned int length = parseInt(msg.str().substr(3*2, 2).c_str(), 16, 0, MAX_POS, ret); + if (ret == RESULT_OK && (4+length)*2 != msg.str().size()) + return RESULT_ERR_INVALID_ARG; + + ret = master.push_back(m_address, false); + if (ret == RESULT_OK) + ret = master.parseHex(msg.str()); + if (ret == RESULT_OK && !isValidAddress(master[1])) + ret = RESULT_ERR_INVALID_ADDR; + + return ret; +} + +result_t MainLoop::readFromBus(Message* message, SymbolString& master, string inputStr, SymbolString& slave) +{ + istringstream input(inputStr); + result_t ret = message->prepareMaster(m_address, master, input); + if (ret != RESULT_OK) { + logError(lf_main, "prepare message: %s", getResultCode(ret)); + return ret; + } + + // send message + logInfo(lf_main, "send message: %s", master.getDataStr().c_str()); + ret = m_busHandler->sendAndWait(master, slave); + if (ret != RESULT_OK) + logError(lf_main, "send message: %s", getResultCode(ret)); + + return ret; +} + string MainLoop::executeRead(vector &args) { size_t argPos = 1; + bool hex = false, verbose = false; time_t maxAge = 5*60; - bool verbose = false; string circuit; unsigned char dstAddress = SYN; while (args.size() > argPos && args[argPos][0] == '-') { - if (args[argPos] == "-f") { + if (args[argPos] == "-h") { + hex = true; + } else if (args[argPos] == "-f") { maxAge = 0; } else if (args[argPos] == "-v") { @@ -259,17 +305,73 @@ string MainLoop::executeRead(vector &args) } argPos++; } + if (hex && (dstAddress != SYN || verbose || args.size() < argPos + 1)) { + argPos = 0; // print usage + } + + time_t now; + time(&now); + + while (hex && argPos > 0 && args.size() > argPos) { + SymbolString cacheMaster(false); + result_t ret = parseHexMaster(args, argPos, cacheMaster); + if (ret != RESULT_OK) + return getResultCode(ret); + 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()); + + // find message + Message* message = m_messages->find(cacheMaster); + + 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 + if (message->getLastUpdateTime() + maxAge > now || (message->isPassive() && message->getLastUpdateTime() != 0)) { + SymbolString& slave = message->getLastSlaveData(); + logNotice(lf_main, "hex read from cache %s %s", message->getCircuit().c_str(), message->getName().c_str()); + return slave.getDataStr(); + } + + // send message + SymbolString master(true); + master.addAll(cacheMaster); + SymbolString slave(false); + ret = m_busHandler->sendAndWait(master, slave); + + if (ret == RESULT_OK) { + ostringstream result; + ret = message->decode(pt_slaveData, slave, result); + if (ret >= RESULT_OK) + logInfo(lf_main, "hex read cache update: %s", result.str().c_str()); + else + logError(lf_main, "hex read cache update: %s", getResultCode(ret)); + return slave.getDataStr(); + } + logError(lf_main, "hex read: %s", getResultCode(ret)); + return getResultCode(ret); + } if (argPos == 0 || args.size() < argPos + 1 || args.size() > argPos + 2) - return "usage: read [-v] [-f] [-m SECONDS] [-d ZZ] [-c CIRCUIT] NAME [FIELD[.N]]\n" - " Read value(s).\n" - " -v be verbose (include field names, units, and comments)\n" + return "usage: read [-f] [-m SECONDS] [-c CIRCUIT] [-d ZZ] [-v] NAME [FIELD[.N]]\n" + " or: read [-f] [-m SECONDS] [-c CIRCUIT] -h ZZPBSBNNDx\n" + " Read value(s) or hex message.\n" " -f force reading from the bus (same as '-m 0')\n" " -m SECONDS only return cached value if age is less than SECONDS [300]\n" - " -d ZZ override destination address ZZ\n" " -c CIRCUIT limit to messages of CIRCUIT\n" + " -d ZZ override destination address ZZ\n" + " -v be verbose (include field names, units, and comments)\n" " NAME the 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 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"; string fieldName; signed char fieldIndex = -2; @@ -285,9 +387,6 @@ string MainLoop::executeRead(vector &args) } } - time_t now; - time(&now); - ostringstream result; Message* message = m_messages->find(circuit, args[argPos], false); @@ -299,9 +398,12 @@ string MainLoop::executeRead(vector &args) if (cacheMessage != NULL && (cacheMessage->getLastUpdateTime() + maxAge > now || (cacheMessage->isPassive() && cacheMessage->getLastUpdateTime() != 0))) { result_t ret = cacheMessage->decodeLastData(result, false, verbose?df_verbose:df_standard, fieldIndex==-2 ? NULL : fieldName.c_str(), fieldIndex); - if (ret != RESULT_OK) + if (ret != RESULT_OK) { + if (ret < RESULT_OK) + logError(lf_main, "read cached: %s", getResultCode(ret)); return getResultCode(ret); - + } + logInfo(lf_main, "read cached: %s", result.str().c_str()); return result.str(); } @@ -317,27 +419,19 @@ string MainLoop::executeRead(vector &args) // read directly from bus SymbolString master(true); - istringstream input; - result_t ret = message->prepareMaster(m_address, master, input, UI_FIELD_SEPARATOR, dstAddress); - if (ret != RESULT_OK) { - logError(lf_main, "prepare read: %s", getResultCode(ret)); - return getResultCode(ret); - } - logInfo(lf_main, "read cmd: %s", master.getDataStr().c_str()); - - // send message SymbolString slave(false); - ret = m_busHandler->sendAndWait(master, slave); + result_t ret = readFromBus(message, master, "", slave); + if (ret != RESULT_OK) + return getResultCode(ret); - if (ret == RESULT_OK) { - ret = message->decode(pt_slaveData, slave, result, false, verbose?df_verbose:df_standard, fieldIndex==-2 ? NULL : fieldName.c_str(), fieldIndex); - } + ret = message->decode(pt_slaveData, slave, result, false, verbose?df_verbose:df_standard, fieldIndex==-2 ? NULL : fieldName.c_str(), fieldIndex); if (ret < RESULT_OK) { logError(lf_main, "read: %s", getResultCode(ret)); return getResultCode(ret); } if (ret > RESULT_OK) return getResultCode(ret); + logInfo(lf_main, "read: %s", result.str().c_str()); return result.str(); } @@ -351,41 +445,36 @@ string MainLoop::executeWrite(vector &args) argPos = 0; break; } - ostringstream msg; - while (argPos < args.size()) { - if ((args[argPos].length() % 2) != 0) { - return getResultCode(RESULT_ERR_INVALID_NUM); - } - msg << args[argPos++]; - } - if (msg.str().size() < 4*2) // at least ZZ, PB, SB, NN - return getResultCode(RESULT_ERR_INVALID_ARG); - result_t ret; - unsigned int length = parseInt(msg.str().substr(3*2, 2).c_str(), 16, 0, MAX_POS, ret); - if (ret == RESULT_OK && (4+length)*2 != msg.str().size()) - return getResultCode(RESULT_ERR_INVALID_ARG); - - SymbolString master(true); - ret = master.push_back(m_address, false); - if (ret == RESULT_OK) - ret = master.parseHex(msg.str()); - if (ret == RESULT_OK && !isValidAddress(master[1])) - ret = RESULT_ERR_INVALID_ADDR; + SymbolString cacheMaster(false); + result_t ret = parseHexMaster(args, argPos, cacheMaster); if (ret != RESULT_OK) return getResultCode(ret); - logNotice(lf_main, "write hex cmd: %s", master.getDataStr().c_str()); + logNotice(lf_main, "hex write cmd: %s", cacheMaster.getDataStr(true, false).c_str()); + + // find message + Message* message = m_messages->find(cacheMaster); // send message + SymbolString master(true); + master.addAll(cacheMaster); SymbolString slave(false); ret = m_busHandler->sendAndWait(master, slave); if (ret == RESULT_OK) { + if (message != NULL) { // also updates read messages + ostringstream result; + ret = message->decode(cacheMaster, slave, result); + if (ret >= RESULT_OK) + logInfo(lf_main, "hex write cache update: %s", result.str().c_str()); + else + logError(lf_main, "hex write cache update: %s", getResultCode(ret)); + } if (master[1] == BROADCAST || isMaster(master[1])) return getResultCode(RESULT_OK); return slave.getDataStr(); } - logError(lf_main, "write hex: %s", getResultCode(ret)); + logError(lf_main, "hex write: %s", getResultCode(ret)); return getResultCode(ret); } @@ -399,7 +488,7 @@ string MainLoop::executeWrite(vector &args) " CIRCUIT the CIRCUIT of the message to send\n" " NAME the NAME of the message to send\n" " VALUE a single field VALUE\n" - " -h directly write hex message:\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" @@ -411,27 +500,19 @@ string MainLoop::executeWrite(vector &args) return getResultCode(RESULT_ERR_NOTFOUND); SymbolString master(true); - istringstream input(args.size() == argPos + 2 ? "" : args[argPos + 2]); // allow missing values - result_t ret = message->prepareMaster(m_address, master, input); - if (ret != RESULT_OK) { - logError(lf_main, "prepare write: %s", getResultCode(ret)); - return getResultCode(ret); - } - logInfo(lf_main, "write cmd: %s", master.getDataStr().c_str()); - - // send message SymbolString slave(false); - ret = m_busHandler->sendAndWait(master, slave); + result_t ret = readFromBus(message, master, args.size() == argPos + 2 ? "" : args[argPos + 2], slave); // allow missing values + if (ret != RESULT_OK) + return getResultCode(ret); ostringstream result; - if (ret == RESULT_OK) { - if (master[1] == BROADCAST || isMaster(master[1])) - return getResultCode(RESULT_OK); + if (master[1] == BROADCAST || isMaster(master[1])) + return getResultCode(RESULT_OK); + + ret = message->decode(pt_slaveData, slave, result); // decode data + if (ret >= RESULT_OK && result.str().empty()) + return getResultCode(RESULT_OK); - ret = message->decode(pt_slaveData, slave, result); // decode data - if (ret >= RESULT_OK && result.str().empty()) - return getResultCode(RESULT_OK); - } if (ret != RESULT_OK) { logError(lf_main, "write: %s", getResultCode(ret)); return getResultCode(ret); @@ -743,9 +824,10 @@ string MainLoop::executeQuit(vector &args, bool& connected) string MainLoop::executeHelp() { return "usage:\n" - " read|r Read value(s): read [-v] [-f] [-m SECONDS] [-d ZZ] [-c CIRCUIT] NAME [FIELD[.N]]\n" + " read|r Read value(s): read [-f] [-m SECONDS] [-c CIRCUIT] [-d ZZ] [-v] NAME [FIELD[.N]]\n" + " Read hex message: read [-f] [-m SECONDS] [-c CIRCUIT] -h ZZPBSBNNDx\n" " write|w Write value(s): write [-c] CIRCUIT NAME [VALUE[;VALUE]*]\n" - " Write hex message: write -h ZZPBSBNNDx'\n" + " Write hex message: write -h ZZPBSBNNDx\n" " find|f Find message(s): find [-v] [-r] [-w] [-p] [-d] [-i PB] [-f] [-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 750635df..76edf589 100644 --- a/src/ebusd/mainloop.h +++ b/src/ebusd/mainloop.h @@ -96,6 +96,25 @@ private: */ string decodeMessage(const string& data, const bool isHttp, bool& connected, bool& listening, bool& running); + /** + * Parse the hex master message from the remaining arguments. + * @param args the arguments passed to the command. + * @param argIndex the index of the first argument to parse. + * @param master the master @a SymbolString to write the data to. + * @return the result from parsing the arguments. + */ + result_t parseHexMaster(vector &args, size_t argPos, SymbolString& master); + + /** + * Prepare the master part for the @a Message, send it to the bus and wait for the answer. + * @param message the @a Message instance. + * @param master the master data @a SymbolString for writing symbols to. + * @param inputStr the input @a string from which to read master values (if any). + * @param slave the @a SymbolString that will be filled with retrieved slave data. + * @return the result code. + */ + result_t readFromBus(Message* message, SymbolString& master, string inputStr, SymbolString& slave); + /** * Execute the read command. * @param args the arguments passed to the command (starting with the command itself), or empty for help.