From 6814cdf3a169822f59fa71fdda454ee8ce66ffb8 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 25 Oct 2015 19:44:16 +0100 Subject: [PATCH] enhanced MessageMap to allow duplicates for full check, fix to avoid multiple identical derived messages --- src/lib/ebus/message.cpp | 79 +++++++++++++++++++++++++++------------- src/lib/ebus/message.h | 28 +++++++++++--- 2 files changed, 77 insertions(+), 30 deletions(-) diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index cfc7acb6..73f22fcf 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -66,14 +66,13 @@ Message::Message(const string circuit, const string name, const bool isWrite, Message::Message(const bool isWrite, const bool isPassive, const unsigned char pb, const unsigned char sb, - DataField* data, - Condition* condition) + DataField* data, const bool deleteData) : m_circuit(), m_name(), m_isWrite(isWrite), m_isPassive(isPassive), m_comment(), m_srcAddress(SYN), m_dstAddress(SYN), m_data(data), m_deleteData(true), m_pollPriority(0), - m_usedByCondition(false), m_condition(condition), + m_usedByCondition(false), m_condition(NULL), m_lastUpdateTime(0), m_lastChangeTime(0), m_pollCount(0), m_lastPollTime(0) { m_id.push_back(pb); @@ -303,6 +302,11 @@ Message* Message::derive(const unsigned char dstAddress) m_pollPriority, m_condition); } +unsigned long long Message::getDerivedKey(const unsigned char dstAddress) +{ + return (m_key & ~(0xffLL << (8*6))) | (unsigned long long)dstAddress << (8*6); +} + bool Message::setPollPriority(unsigned char priority) { if (priority == m_pollPriority || m_isPassive) @@ -636,6 +640,13 @@ string strtolower(const string& str) return ret; } +Message* getFirstAvailable(vector &messages) { + for (vector::iterator msgIt = messages.begin(); msgIt != messages.end(); msgIt++) + if ((*msgIt)->isAvailable()) + return *msgIt; + return NULL; +} + result_t Condition::create(vector::iterator& it, const vector::iterator end, SimpleCondition*& returnValue) { @@ -733,8 +744,19 @@ result_t SimpleCondition::resolve(MessageMap* messages, ostringstream& errorMess errorMessage << "condition " << m_circuit << " " << m_name << ": destination address missing"; return RESULT_ERR_INVALID_ADDR; } - // clone the message with dedicated dstAddress - message = message->derive(m_dstAddress); + // clone the message with dedicated dstAddress if necessary + unsigned long long key = message->getDerivedKey(m_dstAddress); + vector* derived = messages->getByKey(key); + if (derived==NULL) { + message = message->derive(m_dstAddress); + messages->add(message); + } else { + message = getFirstAvailable(*derived); + if (message==NULL) { + errorMessage << "condition " << m_circuit << " " << m_name << ": conditional derived message"; + return RESULT_ERR_INVALID_ARG; + } + } } if (!m_valueRanges.empty()) { @@ -800,24 +822,28 @@ result_t MessageMap::add(Message* message) { unsigned long long key = message->getKey(); bool conditional = message->isConditional(); - map >::iterator keyIt = m_messagesByKey.find(key); - if (keyIt != m_messagesByKey.end()) { - if (!conditional) - return RESULT_ERR_DUPLICATE; // duplicate key - vector* messages = &keyIt->second; - if (!messages->front()->isConditional()) - return RESULT_ERR_DUPLICATE; // duplicate key + if (!m_addAll) { + map >::iterator keyIt = m_messagesByKey.find(key); + if (keyIt != m_messagesByKey.end()) { + if (!conditional) + return RESULT_ERR_DUPLICATE; // duplicate key + vector* messages = &keyIt->second; + if (!messages->front()->isConditional()) + return RESULT_ERR_DUPLICATE; // duplicate key + } } bool isPassive = message->isPassive(); bool isWrite = message->isWrite(); string circuit = strtolower(message->getCircuit()); string name = strtolower(message->getName()); string nameKey = string(isPassive ? "P" : (isWrite ? "W" : "R")) + circuit + FIELD_SEPARATOR + name; - map >::iterator nameIt = m_messagesByName.find(nameKey); - if (nameIt != m_messagesByName.end()) { - vector* messages = &nameIt->second; - if (!messages->front()->isConditional() || !message->isConditional()) - return RESULT_ERR_DUPLICATE_NAME; // duplicate key + if (!m_addAll) { + map >::iterator nameIt = m_messagesByName.find(nameKey); + if (nameIt != m_messagesByName.end()) { + vector* messages = &nameIt->second; + if (!message->isConditional() || !messages->front()->isConditional()) + return RESULT_ERR_DUPLICATE_NAME; // duplicate key + } } m_messagesByName[nameKey].push_back(message); m_messageCount++; @@ -827,13 +853,16 @@ result_t MessageMap::add(Message* message) m_passiveMessageCount++; nameKey = string(isPassive ? "-P" : (isWrite ? "-W" : "-R")) + name; // also store without circuit - nameIt = m_messagesByName.find(nameKey); + map >::iterator nameIt = m_messagesByName.find(nameKey); if (nameIt == m_messagesByName.end()) - m_messagesByName[nameKey].push_back(message); // always store first message without circuit + m_messagesByName[nameKey].push_back(message); // always store first message without circuit (in order of circuit name) else { vector* messages = &nameIt->second; - if (messages->front()->isConditional() && conditional) - m_messagesByName[nameKey].push_back(message); // store further messages only if both are conditional + Message* first = messages->front(); + if (circuit < first->getCircuit()) + m_messagesByName[nameKey].at(0) = message; // always store first message without circuit (in order of circuit name) + else if (m_addAll || (conditional && first->isConditional())) + m_messagesByName[nameKey].push_back(message); // store further messages only if both are conditional or if storing everything } unsigned char idLength = (unsigned char)(message->getId().size() - 2); if (idLength < m_minIdLength) @@ -984,10 +1013,10 @@ result_t MessageMap::resolveConditions(bool verbose) { return overallResult; } -Message* getFirstAvailable(vector &messages) { - for (vector::iterator msgIt = messages.begin(); msgIt != messages.end(); msgIt++) - if ((*msgIt)->isAvailable()) - return *msgIt; +vector* MessageMap::getByKey(const unsigned long long key) { + map >::iterator it = m_messagesByKey.find(key); + if (it != m_messagesByKey.end()) + return &it->second; return NULL; } diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index 9c2b391b..f16a4bc2 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -77,12 +77,11 @@ public: * @param pb the primary ID byte. * @param sb the secondary ID byte. * @param data the @a DataField for encoding/decoding the message. - * @param condition the @a Condition for this message, or NULL. + * @param deleteData whether to delete the @a DataField during destruction. */ Message(const bool isWrite, const bool isPassive, const unsigned char pb, const unsigned char sb, - DataField* data, - Condition* condition=NULL); + DataField* data, const bool deleteData); /** * Destructor. @@ -167,6 +166,13 @@ public: */ unsigned long long getKey() { return m_key; } + /** + * Return the derived key for storing in @a MessageMap. + * @param dstAddress the destination address for the derivation. + * @return the derived key for storing in @a MessageMap. + */ + unsigned long long getDerivedKey(const unsigned char dstAddress); + /** * Get the polling priority, or 0 for no polling at all. * @return the polling priority, or 0 for no polling at all. @@ -596,9 +602,10 @@ public: /** * Construct a new instance. + * @param addAll whether to add all messages, even if duplicate. */ - MessageMap() : FileReader::FileReader(true), - m_minIdLength(4), m_maxIdLength(0), m_messageCount(0), m_conditionalMessageCount(0), m_passiveMessageCount(0) {} + MessageMap(const bool addAll=false) : FileReader::FileReader(true), + m_addAll(addAll), m_minIdLength(4), m_maxIdLength(0), m_messageCount(0), m_conditionalMessageCount(0), m_passiveMessageCount(0) {} /** * Destructor. @@ -639,6 +646,14 @@ public: */ result_t resolveConditions(bool verbose=false); + /** + * Get the stored @a Message instances for the key. + * @param key the key of the @a Message. + * @return the found @a Message instances, or NULL. + * Note: the caller may not free the returned instances. + */ + vector* getByKey(const unsigned long long key); + /** * Find the @a Message instance for the specified circuit and name. * @param circuit the optional circuit name. @@ -750,6 +765,9 @@ public: private: + /** whether to add all messages, even if duplicate. */ + const bool m_addAll; + /** the minimum ID length used by any of the known @a Message instances. */ unsigned char m_minIdLength;