From 76d1adde59e2c1aaa93d6d57d84b83da59dbc5e8 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 5 Dec 2015 10:33:12 +0100 Subject: [PATCH] no longer limit allowed message ID length (was 4 bytes) --- src/lib/ebus/message.cpp | 111 +++++++++++++++++++++++------ src/lib/ebus/message.h | 64 ++++++++++++++++- src/lib/ebus/test/test_message.cpp | 7 +- 3 files changed, 157 insertions(+), 25 deletions(-) diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 36660f28..7f213f3c 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -29,6 +29,9 @@ using namespace std; +/** the maximum length of the command ID bytes (in addition to PB/SB) for which the key is distinct. */ +#define MAX_ID_KEYLEN 4 + /** the bit mask of the source master number in the message key. */ #define ID_SOURCE_MASK (0x1fLL << (8 * 7)) @@ -65,8 +68,11 @@ Message::Message(const string circuit, const string name, key |= (isWrite ? 0x1fLL : 0x1eLL) << (8 * 7); // special values for active key |= (unsigned long long)dstAddress << (8 * 6); int exp = 5; - for (vector::const_iterator it = id.begin(); it < id.end(); it++) - key |= (unsigned long long)*it << (8 * exp--); + for (vector::const_iterator it = id.begin(); it < id.end(); it++) { + key ^= (unsigned long long)*it << (8 * exp--); + if (exp == 0) + exp = 3; + } m_key = key; } @@ -260,7 +266,7 @@ result_t Message::create(vector::iterator& it, const vector::ite defaultPos++; } - if (id.size() < 2 || id.size() > 6) { + if (id.size() < 2) { return RESULT_ERR_INVALID_ARG; // missing/to short/to long ID } @@ -324,6 +330,44 @@ Message* Message::derive(const unsigned char dstAddress) m_pollPriority, m_condition); } +bool Message::checkIdMatch(vector& id) +{ + if (id.size() > m_id.size()) + return false; + bool match = true; + for (size_t pos = 0; pos < id.size(); pos++) { + if (id[pos] != m_id[pos]) { + match = false; + break; + } + } + return match; +} + +bool Message::checkIdExtension(SymbolString* master) +{ + unsigned char idLen = getIdLength(); + if (master->size() < 5 + idLen) // QQ, ZZ, PB, SB, NN + return false; + for (unsigned char pos = 2+MAX_ID_KEYLEN; pos < idLen; pos++) { + if (m_id[pos] != (*master)[3 + pos]) // pos includes PB+SB + return false; + } + return true; +} + +bool Message::checkIdExtension(Message* other) +{ + if (m_id.size() != other->m_id.size()) + return false; + unsigned char idLen = getIdLength(); + for (unsigned char pos = 2+MAX_ID_KEYLEN; pos < idLen; pos++) { + if (m_id[pos] != other->m_id[pos]) + return false; + } + return true; +} + unsigned long long Message::getDerivedKey(const unsigned char dstAddress) { return (m_key & ~(0xffLL << (8*6))) | (unsigned long long)dstAddress << (8*6); @@ -624,10 +668,30 @@ void Message::dump(ostream& output, vector* columns) } } -Message* getFirstAvailable(vector &messages) { - for (vector::iterator msgIt = messages.begin(); msgIt != messages.end(); msgIt++) - if ((*msgIt)->isAvailable()) +Message* getFirstAvailable(vector &messages, unsigned char idLength=0, SymbolString* master=NULL) { + for (vector::iterator msgIt = messages.begin(); msgIt != messages.end(); msgIt++) { + Message* message = *msgIt; + if (idLength > MAX_ID_KEYLEN && master) { + if (message->getIdLength() != idLength || !message->checkIdExtension(master)) + continue; + } + if (message->isAvailable()) return *msgIt; + } + return NULL; +} + +Message* getFirstAvailable(vector &messages, Message* sameIdExtAs) { + unsigned char idLength = sameIdExtAs->getIdLength(); + for (vector::iterator msgIt = messages.begin(); msgIt != messages.end(); msgIt++) { + Message* message = *msgIt; + if (idLength > MAX_ID_KEYLEN) { + if (!message->checkIdExtension(sameIdExtAs)) + continue; + } + if (message->isAvailable()) + return *msgIt; + } return NULL; } @@ -750,7 +814,7 @@ result_t SimpleCondition::resolve(MessageMap* messages, ostringstream& errorMess message = message->derive(m_dstAddress); messages->add(message); } else { - message = getFirstAvailable(*derived); + message = getFirstAvailable(*derived, message); if (message==NULL) { errorMessage << ": conditional derived message"; return RESULT_ERR_INVALID_ARG; @@ -879,7 +943,7 @@ result_t MessageMap::add(Message* message, bool storeByName) m_passiveMessageCount++; addPollMessage(message); } - unsigned char idLength = (unsigned char)(message->getId().size() - 2); + unsigned char idLength = message->getIdLength(); if (idLength > m_maxIdLength) m_maxIdLength = idLength; m_messagesByKey[key].push_back(message); @@ -1145,20 +1209,23 @@ deque MessageMap::findAll(SymbolString& master) maxIdLength = m_maxIdLength; if (master.size() < 5+maxIdLength) return ret; - - for (int idLength = maxIdLength; ret.size()==0 && idLength >= 0; idLength--) { - int exp = 7; - unsigned long long key = (unsigned long long)idLength << (8 * exp + 5); - key |= (unsigned long long)getMasterNumber(master[0]) << (8 * exp--); - key |= (unsigned long long)master[1] << (8 * exp--); - key |= (unsigned long long)master[2] << (8 * exp--); - key |= (unsigned long long)master[3] << (8 * exp--); - for (unsigned char i = 0; i < idLength; i++) + unsigned long long baseKey = (unsigned long long)getMasterNumber(master[0]) << (8 * 7); + baseKey |= (unsigned long long)master[1] << (8 * 6); + baseKey |= (unsigned long long)master[2] << (8 * 5); + baseKey |= (unsigned long long)master[3] << (8 * 4); + for (unsigned char idLength = maxIdLength; ret.size()==0; idLength--) { + unsigned long long key = (unsigned long long)idLength << (8 * 7 + 5); + key |= baseKey; + int exp = 3; + for (unsigned char i = 0; i < idLength; i++) { key |= (unsigned long long)master[5 + i] << (8 * exp--); + if (exp == 0) + exp = 3; + } map >::iterator it = m_messagesByKey.find(key); if (it != m_messagesByKey.end()) { - Message* message = getFirstAvailable(it->second); + Message* message = getFirstAvailable(it->second, idLength, &master); if (message) ret.push_back(message); } @@ -1166,23 +1233,25 @@ deque MessageMap::findAll(SymbolString& master) key &= ~ID_SOURCE_MASK; it = m_messagesByKey.find(key & ~ID_SOURCE_MASK); // try again without specific source master if (it != m_messagesByKey.end()) { - Message* message = getFirstAvailable(it->second); + Message* message = getFirstAvailable(it->second, idLength, &master); if (message) ret.push_back(message); } } it = m_messagesByKey.find(key | ID_SOURCE_ACTIVE_READ); // try again with special value for active read if (it != m_messagesByKey.end()) { - Message* message = getFirstAvailable(it->second); + Message* message = getFirstAvailable(it->second, idLength, &master); if (message) ret.push_back(message); } it = m_messagesByKey.find(key | ID_SOURCE_ACTIVE_WRITE); // try again with special value for active write if (it != m_messagesByKey.end()) { - Message* message = getFirstAvailable(it->second); + Message* message = getFirstAvailable(it->second, idLength, &master); if (message) ret.push_back(message); } + if (idLength == 0) + break; } return ret; diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index 5d3816eb..7fedeb73 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -190,10 +190,49 @@ public: unsigned char getDstAddress() const { return m_dstAddress; } /** - * Get the command ID bytes. + * Get the primary command byte. + * @return the primary command byte. + */ + unsigned char getPrimaryCommand() const { return m_id[0]; } + + /** + * Get the secondary command byte. + * @return the secondary command byte. + */ + unsigned char getSecondaryCommand() const { return m_id[1]; } + + /** + * Get the full command ID bytes. * @return the primary, secondary, and optionally further command ID bytes. */ - vector getId() const { return m_id; } + vector getFullId() const { return m_id; } + + /** + * Get the length of the ID bytes (without primary and secondary command bytes). + * @return the length of the ID bytes (without primary and secondary command bytes). + */ + unsigned char getIdLength() const { return (unsigned char)(m_id.size() - 2); } + + /** + * Check if the full command ID starts with the given value. + * @param id the ID bytes to check against. + * @return true if the full command ID starts with the given value. + */ + bool checkIdMatch(vector& id); + + /** + * Check the ID extension (bytes exceeding @a MAX_ID_KEYLEN) against the master @a SymbolString data. + * @param master the master @a SymbolString to check against. + * @return true if the ID extension matches, false otherwise. + */ + bool checkIdExtension(SymbolString* master); + + /** + * Check the ID extension (bytes exceeding @a MAX_ID_KEYLEN) against the other @a Message. + * @param other the other @a Message to check against. + * @return true if the ID extension matches, false otherwise. + */ + bool checkIdExtension(Message* other); /** * Return the key for storing in @a MessageMap. @@ -386,7 +425,26 @@ private: /** the primary, secondary, and optionally further command ID bytes. */ vector m_id; - /** the key for storing in @a MessageMap. */ + /** + * the key for storing in @a MessageMap. + *
    + *
  • byte 7: + *
      + *
    • bits 5-7: length of ID bytes (without PB/SB)
    • + *
    • bits 0-4: + *
        + *
      • master number (1..25) of QQ for passive message
      • + *
      • 0x1f for active write
      • + *
      • 0x1e for active read
      • + *
      + *
    + *
  • + *
  • byte 6: ZZ or SYN for any
  • + *
  • byte 5: PB
  • + *
  • byte 4: SB
  • + *
  • bytes 3-0: ID bytes (with cyclic xor if more than 4)
  • + *
+ */ unsigned long long m_key; /** the @a DataField for encoding/decoding the message. */ diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 664191a1..42bb2ba7 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -74,6 +74,11 @@ int main() {"r,ehp,time,,,08;10,b509,0d2800,,,time", "", "", "", "c"}, {"r,ehp,time,,,08;09,b509,0d2800,,,time", "15:00:17", "ff08b509030d2800", "0311000f", "md*"}, {"r,ehp,date,,,08,b509,0d2900,,,date", "23.11.2014", "ff08b509030d2900", "03170b0e", "md"}, + {"r,700,date,,,15,b524,020000003400,,,IGN:4,,,,,,date", "23.11.2015", "ff15b52406020000003400", "0703003400170b0f", "d"}, + {"r,700,time,,,15,b524,020000003500,,,IGN:4,,,,,,HTI", "12:29:06", "ff15b52406020000003500", "07030035000c1d06", "d"}, + {"", "23.11.2015", "ff15b52406020000003400", "0703003400170b0f", "d"}, + {"", "12:29:06", "ff15b52406020000003500", "07030035000c1d06", "d"}, + {"w,700,date,,,15,b524,020000003400,,,date", "23.11.2015", "ff15b52409020000003400170b0f", "00", "m"}, {"r,ehp,error,,,08,b509,0d2800,index,m,UCH,,,,,,time", "3;15:00:17", "ff08b509040d280003", "0311000f", "mdi"}, {"r,ehp,error,,,08,b509,0d2800,index,m,UCH,,,,,,time", "index=3;time=15:00:17", "ff08b509040d280003", "0311000f", "mD"}, {"u,ehp,ActualEnvironmentPower,Energiebezug,,08,B509,29BA00,,s,IGN:2,,,,,s,power", "8", "1008b5090329ba00", "03ba0008", "pm"}, @@ -163,7 +168,7 @@ int main() // store defaults or condition vector::iterator it = entries.begin(); size_t oldSize = conditions.size(); - result = messages->addDefaultFromFile(defaultsRows, entries, it, "", "", "no file", 1); + result = messages->addDefaultFromFile(defaultsRows, entries, it, "", "", "", "no file", 1); if (result != RESULT_OK) cout << "\"" << check[0] << "\": defaults read error: " << getResultCode(result) << endl; else if (it != entries.end())