From 6740a6376b35fa154cd2bd99e872a6de3f33d5a6 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 7 Mar 2015 14:07:58 +0100 Subject: [PATCH] solved todo: cache symbols instead of decoded values, use cache for verbose and field-selective read as well, include names and comments in verbose find --- src/ebusd/mainloop.cpp | 74 +++++++++++++++--------------- src/lib/ebus/data.cpp | 7 +-- src/lib/ebus/message.cpp | 70 ++++++++++++++++++++++------ src/lib/ebus/message.h | 21 +++++++-- src/lib/ebus/test/test_message.cpp | 3 +- 5 files changed, 116 insertions(+), 59 deletions(-) diff --git a/src/ebusd/mainloop.cpp b/src/ebusd/mainloop.cpp index 58cf1bf2..9dca87c9 100644 --- a/src/ebusd/mainloop.cpp +++ b/src/ebusd/mainloop.cpp @@ -239,35 +239,49 @@ string MainLoop::executeRead(vector &args) " FIELD only retrieve the field named FIELD\n" " N only retrieve the N'th field named FIELD (0-based)"; - if (args.size() == argPos + 2) - maxAge = 0; // force refresh to filter single field + string fieldName; + signed char fieldIndex = -2; + if (args.size() == argPos + 2) { + fieldName = args[argPos + 1]; + fieldIndex = -1; + size_t pos = fieldName.find_last_of('.'); + if (pos != string::npos) { + result_t result = RESULT_OK; + fieldIndex = (char)parseInt(fieldName.substr(pos+1).c_str(), 10, 0, MAX_POS, result); + if (result == RESULT_OK) + fieldName = fieldName.substr(0, pos); + } + } time_t now; time(&now); - Message* updateMessage = NULL; - if (maxAge > 0 && !verbose) { - updateMessage = m_messages->find(clazz, args[argPos], false, true); - - if (updateMessage != NULL && updateMessage->getLastUpdateTime() + maxAge > now) - return updateMessage->getLastValue(); // TODO switch from last value to last master/slave to support verbose cached/polled values as well - // else: check poll data or read directly from bus - } - + ostringstream result; Message* message = m_messages->find(clazz, args[argPos], false); - if (message == NULL) { - if (updateMessage != NULL) + if (maxAge > 0) { + Message* cacheMessage = m_messages->find(clazz, args[argPos], false, true); + bool hasCache = cacheMessage != NULL; + if (!hasCache || (message != NULL && message->getLastUpdateTime() > cacheMessage->getLastUpdateTime())) + cacheMessage = message; // message is newer/better + + if (cacheMessage != NULL && cacheMessage->getLastUpdateTime() + maxAge > now) { + result_t ret = cacheMessage->decodeLastData(result, verbose, fieldIndex==-2 ? NULL : fieldName.c_str(), fieldIndex); + if (ret != RESULT_OK) + return getResultCode(ret); + + return result.str(); + } + + if (message == NULL && hasCache) return "ERR: no data stored"; - - return getResultCode(RESULT_ERR_NOTFOUND); + // else: read directly from bus } - if (maxAge > 0 && message->getPollPriority() > 0 - && message->getLastUpdateTime() + maxAge > now) { - // get poll data - return message->getLastValue(); - } // else: read directly from bus + if (message == NULL) + return getResultCode(RESULT_ERR_NOTFOUND); + + // read directly from bus SymbolString master(true); istringstream input; result_t ret = message->prepareMaster(m_address, master, input); @@ -281,21 +295,8 @@ string MainLoop::executeRead(vector &args) SymbolString slave(false); ret = m_busHandler->sendAndWait(master, slave); - ostringstream result; if (ret == RESULT_OK) { - if (args.size() == argPos + 2) { - string fieldName = args[argPos + 1]; - size_t pos = fieldName.find_last_of('.'); - char fieldIndex = -1; - if (pos != string::npos) { - result_t result = RESULT_OK; - fieldIndex = (char)parseInt(fieldName.substr(pos+1).c_str(), 10, 0, MAX_POS, result); - if (result == RESULT_OK) - fieldName = fieldName.substr(0, pos); - } - ret = message->decode(pt_slaveData, slave, result, false, verbose, fieldName.c_str(), fieldIndex); - } else - ret = message->decode(pt_slaveData, slave, result, false, verbose); // decode data + ret = message->decode(pt_slaveData, slave, result, false, verbose, fieldIndex==-2 ? NULL : fieldName.c_str(), fieldIndex); } if (ret != RESULT_OK) { logError(lf_main, "read: %s", getResultCode(ret)); @@ -507,7 +508,7 @@ string MainLoop::executeFind(vector &args) if (lastup == 0) result << "no data stored"; else - result << message->getLastValue(); + message->decodeLastData(result, verbose); if (verbose) { if (lastup == 0) sprintf(str, "%02x", dstAddress); @@ -716,7 +717,8 @@ string MainLoop::getUpdates(time_t since, time_t until) if (lastchg < since || lastchg >= until) continue; result << message->getClass() << " " << message->getName() << " = "; - result << message->getLastValue() << endl; + message->decodeLastData(result); + result << endl; } return result.str(); diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 737bbe32..1c9d28c3 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -1288,14 +1288,15 @@ result_t DataFieldSet::read(const PartType partType, } } - if (findFieldIndex && !found) - return RESULT_ERR_NOTFOUND; + if (!found) { + return RESULT_EMPTY; + } if (verbose) { if (m_comment.length() > 0) output << " [" << m_comment << "]"; } - return found ? RESULT_OK : RESULT_EMPTY; + return RESULT_OK; } result_t DataFieldSet::write(istringstream& input, diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 0c6f8798..d254f17a 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -289,6 +289,10 @@ result_t Message::prepareMaster(const unsigned char srcAddress, SymbolString& ma result = m_data->write(input, pt_masterData, master, (unsigned char)(m_id.size() - 2), separator); if (result != RESULT_OK) return result; + if (master != m_lastMasterData) { + m_lastChangeTime = m_lastUpdateTime; + m_lastMasterData = master; + } masterData.addAll(master); return result; } @@ -307,6 +311,11 @@ result_t Message::prepareSlave(SymbolString& slaveData) result = m_data->write(input, pt_slaveData, slave, 0); if (result != RESULT_OK) return result; + time(&m_lastUpdateTime); + if (slave != m_lastSlaveData) { + m_lastChangeTime = m_lastUpdateTime; + m_lastSlaveData = slave; + } slaveData.addAll(slave); return result; } @@ -321,16 +330,24 @@ result_t Message::decode(const PartType partType, SymbolString& data, offset = (unsigned char)(m_id.size() - 2); else offset = 0; - size_t startPos = output.str().length(); result_t result = m_data->read(partType, data, offset, output, leadingSeparator, verbose, fieldName, fieldIndex, separator); - if (result < RESULT_OK) { + if (result < RESULT_OK) return result; - } + if (result == RESULT_EMPTY) + return RESULT_ERR_NOTFOUND; + time(&m_lastUpdateTime); - string value = output.str().substr(startPos); - if (value != m_lastValue) - m_lastChangeTime = m_lastUpdateTime; - m_lastValue = value; + if (partType == pt_masterData) { + if (data != m_lastMasterData) { + m_lastChangeTime = m_lastUpdateTime; + m_lastMasterData = data; + } + } else if (partType == pt_slaveData) { + if (data != m_lastSlaveData) { + m_lastChangeTime = m_lastUpdateTime; + m_lastSlaveData = data; + } + } return RESULT_OK; } @@ -341,23 +358,48 @@ result_t Message::decode(SymbolString& masterData, SymbolString& slaveData, unsigned char offset = (unsigned char)(m_id.size() - 2); size_t startPos = output.str().length(); result_t result = m_data->read(pt_masterData, masterData, offset, output, leadingSeparator, verbose, NULL, -1, separator); - if (result < RESULT_OK) { + if (result < RESULT_OK) return result; - } + bool empty = result==RESULT_EMPTY; offset = 0; leadingSeparator = output.str().length() > startPos; result = m_data->read(pt_slaveData, slaveData, offset, output, leadingSeparator, verbose, NULL, -1, separator); - if (result < RESULT_OK) { + if (result < RESULT_OK) return result; - } + if (empty && result == RESULT_EMPTY) + return RESULT_ERR_NOTFOUND; + time(&m_lastUpdateTime); - string value = output.str().substr(startPos); - if (value != m_lastValue) + if (masterData != m_lastMasterData) { m_lastChangeTime = m_lastUpdateTime; - m_lastValue = value; + m_lastMasterData = masterData; + } + if (slaveData != m_lastSlaveData) { + m_lastChangeTime = m_lastUpdateTime; + m_lastSlaveData = slaveData; + } return RESULT_OK; } +result_t Message::decodeLastData(ostringstream& output, + bool verbose, const char* fieldName, signed char fieldIndex, + char separator) +{ + bool leadingSeparator = false; + unsigned char offset = (unsigned char)(m_id.size() - 2); + size_t startPos = output.str().length(); + result_t result = m_data->read(pt_masterData, m_lastMasterData, offset, output, leadingSeparator, verbose, fieldName, fieldIndex, separator); + if (result < RESULT_OK) + return result; + bool empty = result==RESULT_EMPTY; + offset = 0; + leadingSeparator = output.str().length() > startPos; + result = m_data->read(pt_slaveData, m_lastSlaveData, offset, output, leadingSeparator, verbose, fieldName, fieldIndex, separator); + if (empty && result == RESULT_EMPTY) + return RESULT_ERR_NOTFOUND; + return result; +} + bool Message::isLessPollWeight(const Message* other) { unsigned int tw = m_pollPriority * m_pollCount; diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index 6b992c5f..a7d0c26d 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -209,10 +209,18 @@ public: bool verbose=false, char separator=UI_FIELD_SEPARATOR); /** - * Get the last decoded value. - * @return the last decoded value, or the empty string if it was not successful. + * Decode the value from the last stored data. + * @param output the @a ostringstream to append the formatted value to. + * @param verbose whether to prepend the name, append the unit (if present), and append + * the comment in square brackets (if present). + * @param fieldName the optional name of a field to limit the output to. + * @param fieldIndex the optional index of the named field to limit the output to, or -1. + * @param separator the separator character between multiple fields. + * @return @a RESULT_OK on success, or an error code. */ - string getLastValue() { return m_lastValue; } + result_t decodeLastData(ostringstream& output, + bool verbose=false, const char* fieldName=NULL, signed char fieldIndex=-1, + char separator=UI_FIELD_SEPARATOR); /** * Get the time when @a m_lastValue was last stored. @@ -281,8 +289,11 @@ private: /** the priority for polling, or 0 for no polling at all. */ const unsigned char m_pollPriority; - /** the last decoded value. */ - string m_lastValue; + /** the last seen master data. */ + SymbolString m_lastMasterData; + + /** the last seen slave data. */ + SymbolString m_lastSlaveData; /** the system time when @a m_lastValue was last stored, 0 for never. */ time_t m_lastUpdateTime; diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 7bfb84ad..e13f41d1 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -46,7 +46,7 @@ int main() // message= [type];class;name;[comment];[QQ];ZZ;PBSB;fields... // field= name;[pos];type[;[divisor|values][;[unit][;[comment]]]] string checks[][5] = { - // "message", "flags" + // "message", "decoded", "master", "slave", "flags" {"date,HDA:3,,,Datum", "", "", "", "t"}, {"time,VTI,,,", "", "", "", "t"}, {"dcfstate,UCH,0=nosignal;1=ok;2=sync;3=valid,,", "", "", "", "t"}, @@ -56,6 +56,7 @@ int main() {"sensor,UCH,0=ok;85=circuit;170=cutoff,,Fühlerstatus", "", "", "", "t"}, {"tempsensor,temp;sensor", "", "", "", "t"}, {"u,,first,,,fe,0700,,x,,bda", "26.10.2014", "fffe07000426100614", "00", "p"}, + {"u,broadcast,hwStatus,,,fe,b505,27,,,UCH,,,,,,UCH,,,,,,UCH,,,", "0;19;0", "10feb505042700130097", "00", ""}, {"w,,first,,,15,b509,0400,date,,bda", "26.10.2014", "ff15b50906040026100614", "00", "m"}, {"r,ehp,time,,,08,b509,0d2800,,,time", "15:00:17", "ff08b509030d2800", "0311000f", "md"}, {"r,ehp,date,,,08,b509,0d2900,,,date", "23.11.2014", "ff08b509030d2900", "03170b0e", "md"},