enhanced MessageMap to allow duplicates for full check, fix to avoid multiple identical derived messages
This commit is contained in:
+54
-25
@@ -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<Message*> &messages) {
|
||||
for (vector<Message*>::iterator msgIt = messages.begin(); msgIt != messages.end(); msgIt++)
|
||||
if ((*msgIt)->isAvailable())
|
||||
return *msgIt;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
result_t Condition::create(vector<string>::iterator& it, const vector<string>::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<Message*>* 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<unsigned long long, vector<Message*> >::iterator keyIt = m_messagesByKey.find(key);
|
||||
if (keyIt != m_messagesByKey.end()) {
|
||||
if (!conditional)
|
||||
return RESULT_ERR_DUPLICATE; // duplicate key
|
||||
vector<Message*>* messages = &keyIt->second;
|
||||
if (!messages->front()->isConditional())
|
||||
return RESULT_ERR_DUPLICATE; // duplicate key
|
||||
if (!m_addAll) {
|
||||
map<unsigned long long, vector<Message*> >::iterator keyIt = m_messagesByKey.find(key);
|
||||
if (keyIt != m_messagesByKey.end()) {
|
||||
if (!conditional)
|
||||
return RESULT_ERR_DUPLICATE; // duplicate key
|
||||
vector<Message*>* 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<string, vector<Message*> >::iterator nameIt = m_messagesByName.find(nameKey);
|
||||
if (nameIt != m_messagesByName.end()) {
|
||||
vector<Message*>* messages = &nameIt->second;
|
||||
if (!messages->front()->isConditional() || !message->isConditional())
|
||||
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
|
||||
if (!m_addAll) {
|
||||
map<string, vector<Message*> >::iterator nameIt = m_messagesByName.find(nameKey);
|
||||
if (nameIt != m_messagesByName.end()) {
|
||||
vector<Message*>* 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<string, vector<Message*> >::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<Message*>* 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<Message*> &messages) {
|
||||
for (vector<Message*>::iterator msgIt = messages.begin(); msgIt != messages.end(); msgIt++)
|
||||
if ((*msgIt)->isAvailable())
|
||||
return *msgIt;
|
||||
vector<Message*>* MessageMap::getByKey(const unsigned long long key) {
|
||||
map<unsigned long long, vector<Message*> >::iterator it = m_messagesByKey.find(key);
|
||||
if (it != m_messagesByKey.end())
|
||||
return &it->second;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
+23
-5
@@ -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<DataFieldTemplates*>::FileReader(true),
|
||||
m_minIdLength(4), m_maxIdLength(0), m_messageCount(0), m_conditionalMessageCount(0), m_passiveMessageCount(0) {}
|
||||
MessageMap(const bool addAll=false) : FileReader<DataFieldTemplates*>::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<Message*>* 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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user