no longer limit allowed message ID length (was 4 bytes)

This commit is contained in:
john30
2015-12-05 10:33:12 +01:00
parent ce4bc56412
commit 76d1adde59
3 changed files with 157 additions and 25 deletions
+90 -21
View File
@@ -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<unsigned char>::const_iterator it = id.begin(); it < id.end(); it++)
key |= (unsigned long long)*it << (8 * exp--);
for (vector<unsigned char>::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<string>::iterator& it, const vector<string>::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<unsigned char>& 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<size_t>* columns)
}
}
Message* getFirstAvailable(vector<Message*> &messages) {
for (vector<Message*>::iterator msgIt = messages.begin(); msgIt != messages.end(); msgIt++)
if ((*msgIt)->isAvailable())
Message* getFirstAvailable(vector<Message*> &messages, unsigned char idLength=0, SymbolString* master=NULL) {
for (vector<Message*>::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<Message*> &messages, Message* sameIdExtAs) {
unsigned char idLength = sameIdExtAs->getIdLength();
for (vector<Message*>::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<Message*> 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<unsigned long long , vector<Message*> >::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<Message*> 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;
+61 -3
View File
@@ -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<unsigned char> getId() const { return m_id; }
vector<unsigned char> 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<unsigned char>& 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<unsigned char> m_id;
/** the key for storing in @a MessageMap. */
/**
* the key for storing in @a MessageMap.
* <ul>
* <li>byte 7:
* <ul>
* <li>bits 5-7: length of ID bytes (without PB/SB)</li>
* <li>bits 0-4:
* <ul>
* <li>master number (1..25) of QQ for passive message</li>
* <li>0x1f for active write</li>
* <li>0x1e for active read</li>
* </ul>
* </ul>
* </li>
* <li>byte 6: ZZ or SYN for any</li>
* <li>byte 5: PB</li>
* <li>byte 4: SB</li>
* <li>bytes 3-0: ID bytes (with cyclic xor if more than 4)</li>
* </ul>
*/
unsigned long long m_key;
/** the @a DataField for encoding/decoding the message. */
+6 -1
View File
@@ -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<string>::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())