From b36efd408613bb0bfc236e093969d33dd8524526 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 16 Apr 2017 15:03:29 +0200 Subject: [PATCH] added circuit level attributes for JSON output, corrected sorting of messages in result of MessageMap::findAll() --- src/ebusd/mainloop.cpp | 29 ++-------- src/lib/ebus/message.cpp | 113 +++++++++++++++++++++++++++++---------- src/lib/ebus/message.h | 23 +++++++- 3 files changed, 112 insertions(+), 53 deletions(-) diff --git a/src/ebusd/mainloop.cpp b/src/ebusd/mainloop.cpp index 6f3348bd..1f223aee 100644 --- a/src/ebusd/mainloop.cpp +++ b/src/ebusd/mainloop.cpp @@ -1610,6 +1610,7 @@ string MainLoop::executeGet(vector &args, bool& connected) { deque messages = m_messages->findAll(circuit, name, getUserLevels(user), exact, true, false, true); bool first = true; + verbosity |= (numeric ? OF_NUMERIC : 0) | OF_JSON | (full ? OF_ALL_ATTRS : 0); for (deque::iterator it = messages.begin(); it != messages.end();) { Message* message = *it++; symbol_t dstAddress = message->getDstAddress(); @@ -1643,34 +1644,12 @@ string MainLoop::executeGet(vector &args, bool& connected) { } lastCircuit = message->getCircuit(); result << "\n \"" << lastCircuit << "\": {"; - // TODO add circuit specific values first = true; - } - if (first) { - first = false; - } else { - result << ","; - } - result << "\n \"" << message->getName() << "\": {"; - result << "\n \"lastup\": " << setw(0) << dec << static_cast(lastup); - if (lastup != 0) { - result << ",\n \"zz\": \"" << setfill('0') << setw(2) << hex << static_cast(dstAddress) << "\""; - size_t pos = (size_t) result.tellp(); - result << ",\n \"fields\": {"; - result_t dret = message->decodeLastData( - result, verbosity | (numeric ? OF_NUMERIC : 0) | OF_JSON | (full ? OF_ALL_ATTRS : 0)); - if (dret == RESULT_OK) { - result << "\n }"; - } else { - string prefix = result.str().substr(0, pos); - result.str(""); - result.clear(); // remove written fields - result << prefix << ",\n \"decodeerror\": \"" << getResultCode(dret) << "\""; + if (full && m_messages->decodeCircuit(lastCircuit, result, verbosity)) { // add circuit specific values + first = false; } } - result << ",\n \"passive\": " << (message->isPassive() ? "true" : "false"); - result << ",\n \"write\": " << (message->isWrite() ? "true" : "false"); - result << "\n }"; + message->decode(result, verbosity, !first); } if (lastCircuit.length() > 0) { diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 8f6a8428..d2bc34e6 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -1004,6 +1004,33 @@ void Message::dumpField(ostream& output, size_t fieldId, bool withConditions) co } } +void Message::decode(ostringstream& output, OutputFormat outputFormat, bool leadingSeparator, + vector* fields) const { + if (leadingSeparator) { + output << ","; + } + output << "\n \"" << getName() << "\": {"; + output << "\n \"lastup\": " << setw(0) << dec << static_cast(getLastUpdateTime()); + if (getLastUpdateTime() != 0) { + output << ",\n \"zz\": \"" << setfill('0') << setw(2) << hex << static_cast(getDstAddress()) << "\""; + appendAttributes(output, OF_JSON | outputFormat); + size_t pos = (size_t) output.tellp(); + output << ",\n \"fields\": {"; + result_t dret = decodeLastData(output, outputFormat); + if (dret == RESULT_OK) { + output << "\n }"; + } else { + string prefix = output.str().substr(0, pos); + output.str(""); + output.clear(); // remove written fields + output << prefix << ",\n \"decodeerror\": \"" << getResultCode(dret) << "\""; + } + } + output << ",\n \"passive\": " << (isPassive() ? "true" : "false"); + output << ",\n \"write\": " << (isWrite() ? "true" : "false"); + output << "\n }"; +} + ChainedMessage::ChainedMessage(const string circuit, const string level, const string name, const bool isWrite, const map& attributes, @@ -1767,7 +1794,8 @@ result_t MessageMap::add(Message* message, bool storeByName) { } string name = message->getName(); FileReader::tolower(name); - string nameKey = string(isPassive ? "P" : (isWrite ? "W" : "R")) + circuit + FIELD_SEPARATOR + name; + string suffix = FIELD_SEPARATOR + name + (isPassive ? "P" : (isWrite ? "W" : "R")); + string nameKey = circuit + suffix; if (!m_addAll) { map >::iterator nameIt = m_messagesByName.find(nameKey); if (nameIt != m_messagesByName.end()) { @@ -1778,7 +1806,7 @@ result_t MessageMap::add(Message* message, bool storeByName) { } } m_messagesByName[nameKey].push_back(message); - nameKey = string(isPassive ? "-P" : (isWrite ? "-W" : "-R")) + name; // also store without circuit + nameKey = suffix; // also store without circuit map >::iterator nameIt = m_messagesByName.find(nameKey); if (nameIt == m_messagesByName.end()) { // always store first message without circuit (in order of circuit name) @@ -1926,11 +1954,14 @@ result_t MessageMap::addDefaultFromFile(map& row, vector< map& row, vector< map > subDefaults = subRows; // ensure to have a copy getSubDefaults()[type] = subDefaults; @@ -2362,16 +2403,17 @@ Message* MessageMap::find(const string& circuit, const string& name, const strin FileReader::tolower(lcircuit); string lname = name; FileReader::tolower(lname); + string suffix = FIELD_SEPARATOR + lname + (isPassive ? "P" : (isWrite ? "W" : "R")); for (int i = 0; i < 2; i++) { - string key; + string nameKey; if (i == 0) { - key = string(isPassive ? "P" : (isWrite ? "W" : "R")) + lcircuit + FIELD_SEPARATOR + lname; - } else if (lcircuit.length() == 0) { - key = string(isPassive ? "-P" : (isWrite ? "-W" : "-R")) + lname; // second try: without circuit + nameKey = lcircuit + suffix; + } else if (lcircuit.empty()) { + nameKey = suffix; // second try: without circuit } else { continue; // not allowed without circuit } - auto it = m_messagesByName.find(key); + auto it = m_messagesByName.find(nameKey); if (it != m_messagesByName.end()) { Message* message = getFirstAvailable(it->second); if (message && message->hasLevel(levels)) { @@ -2395,7 +2437,7 @@ deque MessageMap::findAll(const string& circuit, const string& name, c bool checkLevel = levels != "*"; bool checkName = lname.length() > 0; for (auto it : m_messagesByName) { - if (it.first[0] == '-') { // avoid duplicates: instances stored multiple times have a key starting with "-" + if (it.first[0] == FIELD_SEPARATOR) { // avoid duplicates: instances stored multiple times have a special key continue; } for (auto message : it.second) { @@ -2544,6 +2586,19 @@ void MessageMap::addPollMessage(Message* message, bool toFront) { } } +bool MessageMap::decodeCircuit(const string circuit, ostringstream& output, OutputFormat outputFormat) const { + auto it = m_circuitData.find(circuit); + if (it == m_circuitData.end()) { + return false; + } + if (outputFormat & OF_JSON) { + output << "\"name\": \"" << it->second->getName() << "\""; + } else { + output << it->second->getName() << "="; + } + return it->second->appendAttributes(output, outputFormat); +} + void MessageMap::clear() { m_loadedFiles.clear(); m_loadedFileInfos.clear(); @@ -2553,26 +2608,26 @@ void MessageMap::clear() { m_pollMessages.pop(); } // free message instances by name - for (map >::iterator it = m_messagesByName.begin(); it != m_messagesByName.end(); it++) { - vector nameMessages = it->second; - if (it->first[0] != '-') { // avoid double free: instances stored multiple times have a key starting with "-" - for (vector::iterator nit = nameMessages.begin(); nit != nameMessages.end(); nit++) { - Message* message = *nit; - map >::iterator keyIt = m_messagesByKey.find(message->getKey()); - if (keyIt != m_messagesByKey.end()) { - vector* keyMessages = &keyIt->second; - if (!keyMessages->empty()) { - for (vector::iterator kit = keyMessages->begin(); kit != keyMessages->end(); kit++) { - if (*kit == message) { - keyMessages->erase(kit--); - } + for (auto it : m_messagesByName) { + vector nameMessages = it.second; + if (it.first[0] == FIELD_SEPARATOR) { // avoid double free: instances stored multiple times have a special key + continue; + } + for (Message* message : it.second) { + map >::iterator keyIt = m_messagesByKey.find(message->getKey()); + if (keyIt != m_messagesByKey.end()) { + vector* keyMessages = &keyIt->second; + if (!keyMessages->empty()) { + for (vector::iterator kit = keyMessages->begin(); kit != keyMessages->end(); kit++) { + if (*kit == message) { + keyMessages->erase(kit--); } } } - delete message; } + delete message; } - nameMessages.clear(); + it.second.clear(); } // free remaining message instances by key for (map >::iterator it = m_messagesByKey.begin(); it != m_messagesByKey.end(); it++) { @@ -2605,6 +2660,10 @@ void MessageMap::clear() { m_messagesByKey.clear(); m_conditions.clear(); m_instructions.clear(); + for (auto& it : m_circuitData) { + delete it.second; + } + m_circuitData.clear(); m_maxIdLength = m_maxBroadcastIdLength = 0; m_additionalScanMessages = false; } diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index a8ab018a..14111662 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -597,6 +597,15 @@ class Message : public AttributedItem { */ virtual void dumpField(ostream& output, size_t fieldId, bool withConditions = false) const; + /** + * Decode the message from the last stored data. + * @param output the @a ostringstream to append the decoded value(s) to. + * @param outputFormat the @a OutputFormat options to use. + * @param leadingSeparator whether to prepend a separator before the first value. + * @param fields the list of message and/or data field fields to write, or NULL for all. + */ + virtual void decode(ostringstream& output, OutputFormat outputFormat = 0, bool leadingSeparator = false, + vector* fields = NULL) const; protected: /** the optional circuit name. */ @@ -1449,6 +1458,15 @@ class MessageMap : public MappedFileReader { */ void addPollMessage(Message* message, bool toFront = false); + /** + * Decode circuit specific data. + * @param circuit the name of the circuit. + * @param output the @a ostringstream to append the decoded value(s) to. + * @param outputFormat the @a OutputFormat options to use. + * @return true if data was added, false otherwise. + */ + bool decodeCircuit(const string circuit, ostringstream& output, OutputFormat outputFormat) const; + /** * Removes all @a Message instances. */ @@ -1542,7 +1560,7 @@ class MessageMap : public MappedFileReader { /** the number of distinct passive @a Message instances stored in @a m_messagesByKey. */ size_t m_passiveMessageCount; - /** the known @a Message instances by lowercase circuit and name. */ + /** the known @a Message instances by lowercase circuit (optional), name, and type. */ map > m_messagesByName; /** the known @a Message instances by key. */ @@ -1556,6 +1574,9 @@ class MessageMap : public MappedFileReader { /** the list of @a Instruction instances by filename. */ map > m_instructions; + + /** additional attributes by circuit name. */ + map m_circuitData; }; } // namespace ebusd