changed from m_isActive to m_isPassive, made defaults more flexible (every char besides r/w/p/0-9 can be used for defining messages to listen to - aka cyc), fix for defaults field list and duplicate message definitions, multiple message types now need to be separated by comma, optimized finding messages

This commit is contained in:
john30
2014-11-30 20:12:59 +01:00
parent 46fb6763bc
commit 377c9c61c0
2 changed files with 150 additions and 127 deletions
+83 -68
View File
@@ -28,21 +28,21 @@
using namespace std; using namespace std;
Message::Message(const string clazz, const string name, const bool isSet, Message::Message(const string clazz, const string name, const bool isSet,
const bool isActive, const string comment, const bool isPassive, const string comment,
const unsigned char srcAddress, const unsigned char dstAddress, const unsigned char srcAddress, const unsigned char dstAddress,
const vector<unsigned char> id, DataField* data, const vector<unsigned char> id, DataField* data,
const unsigned int pollPriority) const unsigned int pollPriority)
: m_class(clazz), m_name(name), m_isSet(isSet), : m_class(clazz), m_name(name), m_isSet(isSet),
m_isActive(isActive), m_comment(comment), m_isPassive(isPassive), m_comment(comment),
m_srcAddress(srcAddress), m_dstAddress(dstAddress), m_srcAddress(srcAddress), m_dstAddress(dstAddress),
m_id(id), m_data(data), m_pollPriority(pollPriority) m_id(id), m_data(data), m_pollPriority(pollPriority)
{ {
int exp = 7; int exp = 7;
unsigned long long key = (unsigned long long)(id.size()-2) << (8 * exp + 5); unsigned long long key = (unsigned long long)(id.size()-2) << (8 * exp + 5);
if (isActive == true) if (isPassive == true)
key |= 0x1fLL << (8 * exp--); key |= (unsigned long long)getMasterNumber(srcAddress) << (8 * exp--); // 0..25
else else
key |= (unsigned long long)getMasterNumber(srcAddress) << (8 * exp--); key |= 0x1fLL << (8 * exp--); // special value for active
key |= (unsigned long long)dstAddress << (8 * exp--); key |= (unsigned long long)dstAddress << (8 * exp--);
for (vector<unsigned char>::const_iterator it=id.begin(); it<id.end(); it++) for (vector<unsigned char>::const_iterator it=id.begin(); it<id.end(); it++)
key |= (unsigned long long)(*it) << (8 * exp--); key |= (unsigned long long)(*it) << (8 * exp--);
@@ -52,26 +52,36 @@ Message::Message(const string clazz, const string name, const bool isSet,
/** /**
* @brief Helper method for getting a default if the value is empty. * @brief Helper method for getting a default if the value is empty.
* @param value the value to check. * @param value the value to check.
* @param defaults a @a verctor of defaults, or NULL. * @param defaults a @a vector of defaults, or NULL.
* @param pos the position in defaults. * @param pos the position in defaults.
* @return the default if available and value is empty, or the value. * @return the default if available and value is empty, or the value.
*/ */
string getDefault(string value, vector<string>* defaults, size_t pos) string getDefault(string value, vector<string>* defaults, size_t pos)
{ {
/*cout<<"getDefault("<<value<<",";
if (defaults==NULL)
cout<<"NULL";
else
cout<<static_cast<unsigned>(defaults->size());
cout<<","<<static_cast<unsigned>(pos)<<"=";*/
if (value.length() > 0 || defaults == NULL || pos > defaults->size()) { if (value.length() > 0 || defaults == NULL || pos > defaults->size()) {
//cout<<value<<endl;
return value; return value;
} }
string ret = defaults->at(pos); value = defaults->at(pos);
return ret; //cout<<value<<endl;
return value;
} }
result_t Message::create(vector<string>::iterator& it, const vector<string>::iterator end, result_t Message::create(vector<string>::iterator& it, const vector<string>::iterator end,
vector<string>* defaults, DataFieldTemplates* templates, Message*& returnValue) vector< vector<string> >* defaultsRows,
DataFieldTemplates* templates, Message*& returnValue)
{ {
// [type];[class];name;[comment];[QQ];ZZ;id;fields... // [type];[class];name;[comment];[QQ];ZZ;id;fields...
result_t result; result_t result;
bool isSet, isActive; bool isSet = false, isPassive = true;
char defaultsChar;
unsigned int pollPriority = 0; unsigned int pollPriority = 0;
size_t defaultPos = 1; size_t defaultPos = 1;
if (it == end) if (it == end)
@@ -80,15 +90,15 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
const char* str = (*it++).c_str(); const char* str = (*it++).c_str();
if (it == end) if (it == end)
return RESULT_ERR_EOF; return RESULT_ERR_EOF;
if (strcasecmp(str, "W") == 0) { if (str[0] == 0 || strcasecmp(str, "R") == 0) { // default: active get
isActive = true; isPassive = false;
defaultsChar = 'r';
} else if (strcasecmp(str, "W") == 0) { // active set
isPassive = false;
isSet = true; isSet = true;
} else if (str[0] == 'C' || str[0] == 'c') { defaultsChar = 'w';
isActive = false; } else if (str[0] == 'P' || str[0] == 'p') { // poll (=active get)
isSet = str[1] == 'W' || str[1] == 'w'; isPassive = false;
} else if (str[0] == 'P' || str[0] == 'p') { // poll priority
isActive = true;
isSet = false;
if (str[1] == 0) if (str[1] == 0)
pollPriority = 1; pollPriority = 1;
else { else {
@@ -97,16 +107,28 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
if (result != RESULT_OK) if (result != RESULT_OK)
return result; return result;
} }
} else if (str[0] >= '0' && str[0] <= '9') { // poll priority defaultsChar = 'r';
isActive = true; } else if (str[0] >= '0' && str[0] <= '9') { // poll priority (=active get)
isSet = false; isPassive = false;
result_t result; result_t result;
pollPriority = parseInt(str, 10, 1, 9, result); pollPriority = parseInt(str, 10, 1, 9, result);
if (result != RESULT_OK) if (result != RESULT_OK)
return result; return result;
} else { // default "r" defaultsChar = 'r';
isActive = true; } else { // any other: passive set/get
isSet = false; isSet = str[1] == 'W' || str[1] == 'w';
defaultsChar = str[0];
}
vector<string>* defaults = NULL;
if (defaultsRows != NULL && defaultsRows->size() > 0) {
for (vector< vector<string> >::reverse_iterator it = defaultsRows->rbegin(); it != defaultsRows->rend(); it++) {
string check = (*it)[0];
if (check[0] == defaultsChar) {
defaults = &(*it);
break;
}
}
} }
string clazz = getDefault(*it++, defaults, defaultPos++); string clazz = getDefault(*it++, defaults, defaultPos++);
@@ -153,9 +175,9 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
string token = *it++; string token = *it++;
if (useDefaults == 1) { if (useDefaults == 1) {
if (pos == 0 && token.size() > 0) { if (pos == 0 && token.size() > 0) {
useDefaults = false; useDefaults = 0;
} else { } else {
token.append(getDefault("", defaults, defaultPos)); token = getDefault("", defaults, defaultPos).append(token);
} }
} }
istringstream input(token); istringstream input(token);
@@ -189,9 +211,9 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
} }
vector<string>::iterator realEnd = end; vector<string>::iterator realEnd = end;
if (defaults!=NULL && defaults->size() > defaultPos + 3) { // need at least "[name];[part];type" (optional: "[divisor|values][;[unit][;[comment]]]]")
vector<string> newTypes; vector<string> newTypes;
while (defaults->at(defaultPos + 3).size() > 0) { if (defaults!=NULL && defaults->size() > defaultPos + 2) { // need at least "[name];[part];type" (optional: "[divisor|values][;[unit][;[comment]]]]")
while (defaults->size() > defaultPos + 2 && defaults->at(defaultPos + 2).size() > 0) {
for (size_t i = 0; i < 6; i++) { for (size_t i = 0; i < 6; i++) {
if (defaults->size() > defaultPos) if (defaults->size() > defaultPos)
newTypes.push_back(defaults->at(defaultPos)); newTypes.push_back(defaults->at(defaultPos));
@@ -200,8 +222,6 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
defaultPos++; defaultPos++;
} }
if (defaults->size() <= defaultPos + 3)
break;
} }
if (newTypes.size() > 0) { if (newTypes.size() > 0) {
while (it != end) { while (it != end) {
@@ -216,13 +236,15 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
returnValue = new Message(clazz, name, isSet, isActive, comment, srcAddress, dstAddress, id, data, pollPriority); returnValue = new Message(clazz, name, isSet, isPassive, comment, srcAddress, dstAddress, id, data, pollPriority);
return RESULT_OK; return RESULT_OK;
} }
result_t Message::prepare(const unsigned char srcAddress, SymbolString& masterData, istringstream& input, char separator) result_t Message::prepareMaster(const unsigned char srcAddress, SymbolString& masterData, istringstream& input, char separator)
{ {
if (m_isActive == true) { if (m_isPassive == true)
return RESULT_ERR_INVALID_ARG; // prepare not possible
masterData.clear(); masterData.clear();
masterData.push_back(srcAddress, false); masterData.push_back(srcAddress, false);
masterData.push_back(m_dstAddress, false); masterData.push_back(m_dstAddress, false);
@@ -237,53 +259,54 @@ result_t Message::prepare(const unsigned char srcAddress, SymbolString& masterDa
if (result != RESULT_OK) if (result != RESULT_OK)
return result; return result;
masterData.push_back(masterData.getCRC(), false, false); masterData.push_back(masterData.getCRC(), false, false);
/*if (slaveData.size() > 0) {
return RESULT_ERR_INVALID_ARG; // TODO support answering MS queries (set slave length, calc crc)
}*/
return RESULT_OK; return RESULT_OK;
} }
return RESULT_ERR_INVALID_ARG; // prepare not possible
}
result_t Message::decode(SymbolString& masterData, SymbolString& slaveData, result_t Message::decode(SymbolString& masterData, SymbolString& slaveData,
ostringstream& output, char separator, bool answer) ostringstream& output, char separator)
{ {
result_t result = m_data->read(masterData, m_id.size() - 2, slaveData, 0, output, false, separator); result_t result = m_data->read(masterData, m_id.size() - 2, slaveData, 0, output, false, separator);
if (result != RESULT_OK) if (result != RESULT_OK)
return result; return result;
if (m_isActive == true && answer == true) { /*if (m_isPassive == false && answer == true) {
istringstream input; // TODO create input from database of internal variables istringstream input; // TODO create input from database of internal variables
result_t result = m_data->write(input, masterData, m_id.size() - 2, slaveData, 0, separator); result_t result = m_data->write(input, masterData, m_id.size() - 2, slaveData, 0, separator);
if (result != RESULT_OK) if (result != RESULT_OK)
return result; return result;
} }*/
return RESULT_OK; return RESULT_OK;
} }
result_t MessageMap::add(Message* message) result_t MessageMap::add(Message* message)
{ {
if (message->isPassive() == false) {
string key = message->getClass().append(";").append(message->getName()); string key = message->getClass().append(";").append(message->getName());
if (message->isActive() == true)
key.append(message->isSet() ? ";W" : ";R"); key.append(message->isSet() ? ";W" : ";R");
else
key.append(";C");
map<string, Message*>::iterator nameIt = m_messagesByName.find(key); map<string, Message*>::iterator nameIt = m_messagesByName.find(key);
if (nameIt != m_messagesByName.end()) { if (nameIt != m_messagesByName.end()) {
return RESULT_ERR_DUPLICATE; // duplicate key return RESULT_ERR_DUPLICATE; // duplicate key
} }
if (message->isActive() == false) { m_messagesByName[key] = message;
unsigned long long pkey = message->getKey(); return RESULT_OK;
map<unsigned long long, Message*>::iterator keyIt = m_passiveMessagesByKey.find(pkey); }
unsigned long long key = message->getKey();
map<unsigned long long, Message*>::iterator keyIt = m_passiveMessagesByKey.find(key);
if (keyIt != m_passiveMessagesByKey.end()) { if (keyIt != m_passiveMessagesByKey.end()) {
return RESULT_ERR_DUPLICATE; // duplicate key return RESULT_ERR_DUPLICATE; // duplicate key
} }
unsigned char idLength = message->getId().size() - 2; unsigned char idLength = message->getId().size() - 2;
if (idLength < m_minIdLength)
m_minIdLength = idLength;
if (idLength > m_maxIdLength) if (idLength > m_maxIdLength)
m_maxIdLength = idLength; m_maxIdLength = idLength;
m_passiveMessagesByKey[pkey] = message; m_passiveMessagesByKey[key] = message;
}
m_messagesByName[key] = message;
return RESULT_OK; return RESULT_OK;
} }
@@ -296,19 +319,12 @@ result_t MessageMap::addFromFile(vector<string>& row, DataFieldTemplates* arg, v
types.append("r"); types.append("r");
result_t result = RESULT_ERR_EOF; result_t result = RESULT_ERR_EOF;
for (size_t i=0; i<types.length(); i++) { istringstream stream(types);
string type = types.substr(i, 1); string type;
vector<string>* defaultRow = NULL; while (getline(stream, type, ',') != 0) {
if (defaults != NULL && defaults->size() > 0) { row[0] = type;
for (vector< vector<string> >::reverse_iterator it = defaults->rbegin(); it != defaults->rend(); it++) {
if ((*it)[0] == type || (type[0] >= '0' && type[0] <= '9' && ((*it)[0][0] == 'r' && (*it)[0][0] == 'R'))) {
defaultRow = &(*it);
break;
}
}
}
vector<string>::iterator it = row.begin(); vector<string>::iterator it = row.begin();
result = Message::create(it, row.end(), defaultRow, arg, message); result = Message::create(it, row.end(), defaults, arg, message);
if (result != RESULT_OK) { if (result != RESULT_OK) {
printErrorPos(row.begin(), row.end(), it); printErrorPos(row.begin(), row.end(), it);
return result; return result;
@@ -321,15 +337,11 @@ result_t MessageMap::addFromFile(vector<string>& row, DataFieldTemplates* arg, v
return result; return result;
} }
Message* MessageMap::find(const string& clazz, const string& name, const bool isActive, const bool isSet) Message* MessageMap::find(const string& clazz, const string& name, const bool isSet)
{ {
string key = clazz; string key = clazz;
for (int i=0; i<2; i++) { for (int i=0; i<2; i++) {
key.append(";").append(name); key.append(";").append(name).append(isSet ? ";W" : ";R");
if (isActive == true)
key.append(isSet ? ";W" : ";R");
else
key.append(";C");
map<string, Message*>::iterator it = m_messagesByName.find(key); map<string, Message*>::iterator it = m_messagesByName.find(key);
if (it != m_messagesByName.end()) if (it != m_messagesByName.end())
return it->second; return it->second;
@@ -339,17 +351,20 @@ Message* MessageMap::find(const string& clazz, const string& name, const bool is
return NULL; return NULL;
} }
Message* MessageMap::find(SymbolString& master) { Message* MessageMap::find(SymbolString& master)
{
if (master.size() < 5) if (master.size() < 5)
return NULL; return NULL;
unsigned char maxIdLength = master[4]; unsigned char maxIdLength = master[4];
if (maxIdLength < m_minIdLength)
return NULL;
if (maxIdLength > m_maxIdLength) if (maxIdLength > m_maxIdLength)
maxIdLength = m_maxIdLength; maxIdLength = m_maxIdLength;
if (master.size() < 5+maxIdLength) if (master.size() < 5+maxIdLength)
return NULL; return NULL;
unsigned long long sourceMask = 0x1fLL << (8 * 7); unsigned long long sourceMask = 0x1fLL << (8 * 7);
for (int idLength=maxIdLength; idLength>=0; idLength--) { for (int idLength=maxIdLength; idLength>=m_maxIdLength; idLength--) {
int exp = 7; int exp = 7;
unsigned long long key = (unsigned long long)idLength << (8 * exp + 5); unsigned long long key = (unsigned long long)idLength << (8 * exp + 5);
key |= (unsigned long long)getMasterNumber(master[0]) << (8 * exp--); key |= (unsigned long long)getMasterNumber(master[0]) << (8 * exp--);
+42 -34
View File
@@ -37,22 +37,21 @@ class Message
public: public:
/** /**
* @brief Constructs a new instance. * @brief Construct a new instance.
* @param class the optional device class. * @param class the optional device class.
* @param name the message name (unique within the same class and type). * @param name the message name (unique within the same class and type).
* @param isSet whether this is a set message. * @param isSet whether this is a set message.
* @param isActive true if message can be initiated by the daemon * @param isPassive true if message can only be initiated by a participant other than us,
* itself any any other participant, false if message can only be initiated * false if message can be initiated by any participant.
* by a participant other than the daemon.
* @param comment the comment. * @param comment the comment.
* @param srcAddress the source address (optional if passive), or @a SYN for any. * @param srcAddress the source address, or @a SYN for any (only relevant if passive).
* @param dstAddress the destination address. * @param dstAddress the destination address.
* @param id the primary, secondary, and optional further ID bytes. * @param id the primary, secondary, and optional further ID bytes.
* @param data the @a DataField for encoding/decoding the message. * @param data the @a DataField for encoding/decoding the message.
* @param pollPriority the priority for polling, or 0 for no polling at all. * @param pollPriority the priority for polling, or 0 for no polling at all.
*/ */
Message(const string clazz, const string name, const bool isSet, Message(const string clazz, const string name, const bool isSet,
const bool isActive, const string comment, const bool isPassive, const string comment,
const unsigned char srcAddress, const unsigned char dstAddress, const unsigned char srcAddress, const unsigned char dstAddress,
const vector<unsigned char> id, DataField* data, const vector<unsigned char> id, DataField* data,
const unsigned int pollPriority); const unsigned int pollPriority);
@@ -64,15 +63,15 @@ public:
* @brief Factory method for creating a new instance. * @brief Factory method for creating a new instance.
* @param it the iterator to traverse for the definition parts. * @param it the iterator to traverse for the definition parts.
* @param end the iterator pointing to the end of the definition parts. * @param end the iterator pointing to the end of the definition parts.
* @param defaults a @a vector with known default values, or NULL. * @param defaultsRows a @a vector with rows containing defaults, or NULL.
* @param templates the @a DataFieldTemplates to be referenced by name, or NULL. * @param templates the @a DataFieldTemplates to be referenced by name, or NULL.
* @param returnValue the variable in which to store the created instance. * @param returnValue the variable in which to store the created instance.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
* Note: the caller needs to free the created instance. * Note: the caller needs to free the created instance.
*/ */
static result_t create(vector<string>::iterator& it, const vector<string>::iterator end, static result_t create(vector<string>::iterator& it, const vector<string>::iterator end,
vector<string>* defaults, vector< vector<string> >* defaultsRows,
DataFieldTemplates*, Message*& returnValue); DataFieldTemplates* templates, Message*& returnValue);
/** /**
* @brief Get the optional device class. * @brief Get the optional device class.
* @return the optional device class. * @return the optional device class.
@@ -89,13 +88,11 @@ public:
*/ */
bool isSet() const { return m_isSet; } bool isSet() const { return m_isSet; }
/** /**
* @brief Get whether message can be initiated by the daemon itself and any other * @brief Get whether message can be initiated only by a participant other than us.
* participant. * @return true if message can only be initiated by a participant other than us,
* @return true if message can be initiated by the daemon itself and any other * false if message can be initiated by any participant.
* participant, false if message can only be initiated by a participant
* other than the daemon.
*/ */
bool isActive() const { return m_isActive; } bool isPassive() const { return m_isPassive; }
/** /**
* @brief Get the comment. * @brief Get the comment.
* @return the comment. * @return the comment.
@@ -117,7 +114,7 @@ public:
*/ */
vector<unsigned char> getId() const { return m_id; } vector<unsigned char> getId() const { return m_id; }
/** /**
* @brief Returns the key for storing in @a MessageSet. * @brief Return the key for storing in @a MessageSet.
* @return the key for storing in @a MessageSet. * @return the key for storing in @a MessageSet.
*/ */
unsigned long long getKey() { return m_key; } unsigned long long getKey() { return m_key; }
@@ -134,17 +131,24 @@ public:
//result_t read(SymbolString& masterData, SymbolString& slaveData, ostringstream& output, //result_t read(SymbolString& masterData, SymbolString& slaveData, ostringstream& output,
// bool verbose=false, char separator=';') = 0; // bool verbose=false, char separator=';') = 0;
/** /**
* @brief Writes the value to the master or slave @a SymbolString. * @brief Prepare master @a SymbolString for sending to the bus.
* @param input the @a istringstream to parse the formatted value from. * @param masterData the master data @a SymbolString for writing symbols to.
* @param masterData the unescaped master data @a SymbolString for writing binary data. * @param input the @a istringstream to parse the formatted value(s) from.
* @param slaveData the unescaped slave data @a SymbolString for writing binary data.
* @param separator the separator character between multiple fields. * @param separator the separator character between multiple fields.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
result_t prepare(const unsigned char srcAddress, SymbolString& masterData, result_t prepareMaster(const unsigned char srcAddress, SymbolString& masterData,
istringstream& input, char separator=';'); istringstream& input, char separator=';');
/**
* @brief Decode a received message.
* @param masterData the unescaped received master @a SymbolString.
* @param slaveData the unescaped received slave @a SymbolString.
* @param output the @a ostringstream to append the formatted value to.
* @param separator the separator character between multiple fields.
* @return @a RESULT_OK on success, or an error code.
*/
result_t decode(SymbolString& masterData, SymbolString& slaveData, result_t decode(SymbolString& masterData, SymbolString& slaveData,
ostringstream& output, char separator=';', bool answer=false); ostringstream& output, char separator=';');
private: private:
@@ -154,13 +158,12 @@ private:
const string m_name; const string m_name;
/** whether this is a set message. */ /** whether this is a set message. */
const bool m_isSet; const bool m_isSet;
/** true if message can be initiated by the daemon itself and any other /** true if message can only be initiated by a participant other than us,
* participant, false if message can only be initiated by a participant * false if message can be initiated by any participant. */
* other than the daemon. */ const bool m_isPassive;
const bool m_isActive;
/** the comment. */ /** the comment. */
const string m_comment; const string m_comment;
/** the source address (optional if passive), or @a SYN for any. */ /** the source address, or @a SYN for any (only relevant if passive). */
const unsigned char m_srcAddress; const unsigned char m_srcAddress;
/** the destination address. */ /** the destination address. */
const unsigned char m_dstAddress; const unsigned char m_dstAddress;
@@ -183,15 +186,15 @@ class MessageMap : public FileReader<DataFieldTemplates*>
public: public:
/** /**
* @brief Constructs a new instance. * @brief Construct a new instance.
*/ */
MessageMap() : FileReader(true), m_maxIdLength(0) {} MessageMap() : FileReader(true), m_minIdLength(4), m_maxIdLength(0) {}
/** /**
* @brief Destructor. * @brief Destructor.
*/ */
virtual ~MessageMap() { clear(); } virtual ~MessageMap() { clear(); }
/** /**
* @brief Adds a @a Message instance to this set. * @brief Add a @a Message instance to this set.
* @param message the @a Message instance to add. * @param message the @a Message instance to add.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
* Note: the caller may not free the added instance on success. * Note: the caller may not free the added instance on success.
@@ -200,14 +203,16 @@ public:
// @copydoc // @copydoc
virtual result_t addFromFile(vector<string>& row, DataFieldTemplates* arg, vector< vector<string> >* defaults); virtual result_t addFromFile(vector<string>& row, DataFieldTemplates* arg, vector< vector<string> >* defaults);
/** /**
* @brief Finds the @a Message instance for the specified class and name. * @brief Find the @a Message instance for the specified class and name.
* @param master the master @a SymbolString for identifying the @a Message. * @param class the optional device class.
* @param name the message name.
* @param isSet whether this is a set message.
* @return the @a Message instance, or NULL. * @return the @a Message instance, or NULL.
* Note: the caller may not free the returned instance. * Note: the caller may not free the returned instance.
*/ */
Message* find(const string& clazz, const string& name, const bool isActive, const bool isSet); Message* find(const string& clazz, const string& name, const bool isSet);
/** /**
* @brief Finds the @a Message instance for the specified master data. * @brief Find the @a Message instance for the specified master data.
* @param master the master @a SymbolString for identifying the @a Message. * @param master the master @a SymbolString for identifying the @a Message.
* @return the @a Message instance, or NULL. * @return the @a Message instance, or NULL.
* Note: the caller may not free the returned instance. * Note: the caller may not free the returned instance.
@@ -221,6 +226,9 @@ public:
private: private:
/** the minimum ID length used by any of the known @a Message instances. */
unsigned char m_minIdLength;
/** the maximum ID length used by any of the known @a Message instances. */ /** the maximum ID length used by any of the known @a Message instances. */
unsigned char m_maxIdLength; unsigned char m_maxIdLength;