introduced MessageMap, nicer method names

This commit is contained in:
john30
2014-11-23 13:33:31 +01:00
parent ea63e9d461
commit d19d89a0b0
3 changed files with 238 additions and 41 deletions
+132 -16
View File
@@ -27,28 +27,50 @@
using namespace std; using namespace std;
Message::Message(const string clazz, const string name, const bool isSet,
const bool isActive, const string comment,
const unsigned char srcAddress, const unsigned char dstAddress,
const vector<unsigned char> id, DataField* data,
const unsigned int pollPriority)
: m_class(clazz), m_name(name), m_isSet(isSet),
m_isActive(isActive), m_comment(comment),
m_srcAddress(srcAddress), m_dstAddress(dstAddress),
m_id(id), m_data(data), m_pollPriority(pollPriority)
{
int exp = 7;
unsigned long long key = (unsigned long long)(id.size()-2) << (8 * exp + 5);
if (isActive == true)
key |= 0x1fLL << (8 * exp--);
else
key |= (unsigned long long)getMasterNumber(srcAddress) << (8 * exp--);
key |= (unsigned long long)dstAddress << (8 * exp--);
for (vector<unsigned char>::const_iterator it=id.begin(); it<id.end(); it++)
key |= (unsigned long long)(*it) << (8 * exp--);
m_key = key;
}
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,
const map<string, DataField*> templates, Message*& returnValue) const map<string, DataField*> templates, Message*& returnValue)
{ {
// [type];[class];name;[comment];[QQ];ZZ;id;fields...
result_t result; result_t result;
// [type];class;name;[comment];[QQ];ZZ;id;fields... bool isSet, isActive;
unsigned int pollPriority = 0;
if (it == end) if (it == end)
return RESULT_ERR_EOF; return RESULT_ERR_EOF;
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;
bool isSetMessage, isActiveMessage;
unsigned int pollPriority = 0;
if (strcasecmp(str, "W") == 0) { if (strcasecmp(str, "W") == 0) {
isActiveMessage = true; isActive = true;
isSetMessage = true; isSet = true;
} else if (str[0] == 'C' || str[0] == 'c') { } else if (str[0] == 'C' || str[0] == 'c') {
isActiveMessage = false; isActive = false;
isSetMessage = str[1] == 'W' || str[1] == 'w'; isSet = str[1] == 'W' || str[1] == 'w';
} else if (str[0] == 'P' || str[0] == 'p') { } else if (str[0] == 'P' || str[0] == 'p') {
isActiveMessage = true; isActive = true;
isSetMessage = false; isSet = false;
if (str[1] == 0) if (str[1] == 0)
pollPriority = 1; pollPriority = 1;
else { else {
@@ -58,8 +80,8 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
return result; return result;
} }
} else { } else {
isActiveMessage = true; isActive = true;
isSetMessage = false; isSet = false;
} }
string clazz = *it++; string clazz = *it++;
@@ -80,7 +102,7 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
if (it == end) if (it == end)
return RESULT_ERR_EOF; return RESULT_ERR_EOF;
unsigned char srcAddress; unsigned char srcAddress;
if (*str == 0 || isActiveMessage == true) if (*str == 0 || isActive == true)
srcAddress = SYN; // no specific source defined, or ignore for active message srcAddress = SYN; // no specific source defined, or ignore for active message
else { else {
srcAddress = parseInt(str, 16, 0, 0xff, result); srcAddress = parseInt(str, 16, 0, 0xff, result);
@@ -125,17 +147,17 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
return RESULT_ERR_INVALID_ARG; // missing/too short/too long ID return RESULT_ERR_INVALID_ARG; // missing/too short/too long ID
DataField* data = NULL; DataField* data = NULL;
result = DataField::create(it, end, templates, data, isSetMessage, dstAddress); result = DataField::create(it, end, templates, data, isSet, dstAddress);
if (result != RESULT_OK) if (result != RESULT_OK)
return result; return result;
returnValue = new Message(clazz, name, isSetMessage, isActiveMessage, comment, srcAddress, dstAddress, id, data, pollPriority); returnValue = new Message(clazz, name, isSet, isActive, 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::prepare(const unsigned char srcAddress, SymbolString& masterData, istringstream& input, char separator)
{ {
if (m_isActiveMessage == true) { if (m_isActive == true) {
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);
@@ -157,7 +179,7 @@ result_t Message::prepare(const unsigned char srcAddress, SymbolString& masterDa
result_t Message::handle(SymbolString& masterData, SymbolString& slaveData, result_t Message::handle(SymbolString& masterData, SymbolString& slaveData,
ostringstream& output, char separator, bool answer) ostringstream& output, char separator, bool answer)
{ {
if (m_isActiveMessage == true) { if (m_isActive == true) {
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;
@@ -170,3 +192,97 @@ result_t Message::handle(SymbolString& masterData, SymbolString& slaveData,
} }
return RESULT_OK; return RESULT_OK;
} }
result_t MessageMap::add(Message* message)
{
string key = message->getClass().append(";").append(message->getName());
if (message->isActive() == true)
key.append(message->isSet() ? ";W" : ";R");
else
key.append(";C");
map<string, Message*>::iterator nameIt = m_messagesByName.find(key);
if (nameIt != m_messagesByName.end())
return RESULT_ERR_INVALID_ARG; // duplicate key
if (message->isActive() == false) {
unsigned long long pkey = message->getKey();
map<unsigned long long, Message*>::iterator keyIt = m_passiveMessagesByKey.find(pkey);
if (keyIt != m_passiveMessagesByKey.end())
return RESULT_ERR_INVALID_ARG; // duplicate key
unsigned char idLength = message->getId().size() - 2;
if (idLength > m_maxIdLength)
m_maxIdLength = idLength;
m_passiveMessagesByKey[pkey] = message;
}
m_messagesByName[key] = message;
return RESULT_OK;
}
Message* MessageMap::find(const string clazz, const string name, const bool isActive, const bool isSet)
{
string key = clazz;
for (int i=0; i<2; i++) {
key.append(";").append(name);
if (isActive == true)
key.append(isSet ? ";W" : ";R");
else
key.append(";C");
map<string, Message*>::iterator it = m_messagesByName.find(key);
if (it != m_messagesByName.end())
return it->second;
key.clear(); // try again without class name
}
return NULL;
}
Message* MessageMap::find(SymbolString master) {
if (master.size() < 5)
return NULL;
unsigned char maxIdLength = master[4];
if (maxIdLength > m_maxIdLength)
maxIdLength = m_maxIdLength;
if (master.size() < 5+maxIdLength)
return NULL;
unsigned long long sourceMask = 0x1fLL << (8 * 7);
for (int idLength=maxIdLength; 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++)
key |= (unsigned long long)master[5 + i] << (8 * exp--);
map<unsigned long long , Message*>::iterator it = m_passiveMessagesByKey.find(key);
if (it != m_passiveMessagesByKey.end())
return it->second;
if ((key & sourceMask) != 0) {
key &= ~sourceMask; // try again without specific source master
it = m_passiveMessagesByKey.find(key);
if (it != m_passiveMessagesByKey.end())
return it->second;
}
}
return NULL;
}
void MessageMap::clear()
{
for (map<string, Message*>::iterator it=m_messagesByName.begin(); it!=m_messagesByName.end(); it++) {
delete it->second;
it->second = NULL;
}
m_messagesByName.clear();
m_passiveMessagesByKey.clear();
m_maxIdLength = 0;
}
+72 -15
View File
@@ -25,11 +25,12 @@
#include "symbol.h" #include "symbol.h"
#include <string> #include <string>
#include <vector> #include <vector>
#include <map>
using namespace std; using namespace std;
/** /**
* @brief Base class for all kinds of bus messages. * @brief Defines parameters of a message sent or received on the bus.
*/ */
class Message class Message
{ {
@@ -39,8 +40,8 @@ public:
* @brief Constructs a new instance. * @brief Constructs 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 isSetMessage whether this is a set message. * @param isSet whether this is a set message.
* @param isActiveMessage true if message can be initiated by the daemon * @param isActive true if message can be initiated by the daemon
* itself any any other participant, false if message can only be initiated * itself any any other participant, false if message can only be initiated
* by a participant other than the daemon. * by a participant other than the daemon.
* @param comment the comment. * @param comment the comment.
@@ -50,15 +51,11 @@ public:
* @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 isSetMessage, Message(const string clazz, const string name, const bool isSet,
const bool isActiveMessage, const string comment, const bool isActive, 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_isSetMessage(isSetMessage),
m_isActiveMessage(isActiveMessage), m_comment(comment),
m_srcAddress(srcAddress), m_dstAddress(dstAddress),
m_id(id), m_data(data), m_pollPriority(pollPriority) {}
/** /**
* @brief Destructor. * @brief Destructor.
*/ */
@@ -88,7 +85,7 @@ public:
* @brief Get whether this is a set message. * @brief Get whether this is a set message.
* @return whether this is a set message. * @return whether this is a set message.
*/ */
bool isSetMessage() const { return m_isSetMessage; } 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 by the daemon itself and any other
* participant. * participant.
@@ -96,7 +93,7 @@ public:
* participant, false if message can only be initiated by a participant * participant, false if message can only be initiated by a participant
* other than the daemon. * other than the daemon.
*/ */
bool isActiveMessage() const { return m_isActiveMessage; } bool isActive() const { return m_isActive; }
/** /**
* @brief Get the comment. * @brief Get the comment.
* @return the comment. * @return the comment.
@@ -117,6 +114,11 @@ public:
* @return the primary, secondary, and optionally further command ID bytes. * @return the primary, secondary, and optionally further command ID bytes.
*/ */
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.
* @return the key for storing in @a MessageSet.
*/
unsigned long long getKey() { return m_key; }
/** /**
* @brief Reads the value from the master or slave @a SymbolString. * @brief Reads the value from the master or slave @a SymbolString.
* @param masterData the unescaped master data @a SymbolString for reading binary data. * @param masterData the unescaped master data @a SymbolString for reading binary data.
@@ -142,7 +144,6 @@ public:
result_t handle(SymbolString& masterData, SymbolString& slaveData, result_t handle(SymbolString& masterData, SymbolString& slaveData,
ostringstream& output, char separator=';', bool answer=false); ostringstream& output, char separator=';', bool answer=false);
private: private:
/** the optional device class. */ /** the optional device class. */
@@ -150,11 +151,11 @@ private:
/** the message name (unique within the same class and type). */ /** the message name (unique within the same class and type). */
const string m_name; const string m_name;
/** whether this is a set message. */ /** whether this is a set message. */
const bool m_isSetMessage; const bool m_isSet;
/** true if message can be initiated by the daemon itself and any other /** true if message can be initiated by the daemon itself and any other
* participant, false if message can only be initiated by a participant * participant, false if message can only be initiated by a participant
* other than the daemon. */ * other than the daemon. */
const bool m_isActiveMessage; 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 (optional if passive), or @a SYN for any. */
@@ -163,6 +164,8 @@ private:
const unsigned char m_dstAddress; const unsigned char m_dstAddress;
/** the primary, secondary, and optionally further command ID bytes. */ /** the primary, secondary, and optionally further command ID bytes. */
const vector<unsigned char> m_id; const vector<unsigned char> m_id;
/** the key for storing in @a MessageSet. */
unsigned long long m_key;
/** the @a DataField for encoding/decoding the message. */ /** the @a DataField for encoding/decoding the message. */
DataField* m_data; DataField* m_data;
/** the priority for polling, or 0 for no polling at all. */ /** the priority for polling, or 0 for no polling at all. */
@@ -170,4 +173,58 @@ private:
}; };
/**
* @brief Holds a map of all known @a Message instances.
*/
class MessageMap
{
public:
/**
* @brief Constructs a new instance.
*/
MessageMap() : m_maxIdLength(0) {}
/**
* @brief Destructor.
*/
virtual ~MessageMap() { clear(); }
/**
* @brief Adds a @a Message instance to this set.
* @param message the @a Message instance to add.
* @return @a RESULT_OK on success, or an error code.
* Note: the caller may not free the created instance on success.
*/
result_t add(Message* message);
/**
* @brief Finds the @a Message instance for the specified class and name.
* @param master the master @a SymbolString for identifying the @a Message.
* @return the @a Message instance, or NULL.
* Note: the caller may not free the returned instance.
*/
Message* find(const string clazz, const string name, const bool isActive, const bool isSet);
/**
* @brief Finds the @a Message instance for the specified master data.
* @param master the master @a SymbolString for identifying the @a Message.
* @return the @a Message instance, or NULL.
* Note: the caller may not free the returned instance.
*/
Message* find(SymbolString master);
/**
* @brief Removes all @a Message instances.
*/
void clear();
private:
/** the maximum ID length used by any of the known @a Message instances. */
unsigned char m_maxIdLength;
/** the known @a Message instances by class and name. */
map<string, Message*> m_messagesByName;
/** the known passive @a Message instances by key. */
map<unsigned long long, Message*> m_passiveMessagesByKey;
};
#endif // LIBEBUS_MESSAGE_H_ #endif // LIBEBUS_MESSAGE_H_
+34 -10
View File
@@ -42,7 +42,7 @@ void verify(bool expectFailMatch, string type, string input,
void printErrorPos(vector<string>::iterator it, const vector<string>::iterator end, vector<string>::iterator pos) void printErrorPos(vector<string>::iterator it, const vector<string>::iterator end, vector<string>::iterator pos)
{ {
cout << "Errroneous item is here:" << endl; cout << "Erroneous item is here:" << endl;
bool first = true; bool first = true;
int cnt = 0; int cnt = 0;
if (pos > it) if (pos > it)
@@ -71,11 +71,13 @@ int main()
// field= name;[pos];type[;[divisor|values][;[unit][;[comment]]]] // field= name;[pos];type[;[divisor|values][;[unit][;[comment]]]]
string checks[][5] = { string checks[][5] = {
// "message", "flags" // "message", "flags"
{";;first;;;fe;0700;x;;bda", "26.10.2014", "fffe0700042610061451", "00", ""}, {"c;;first;;;fe;0700;x;;bda", "26.10.2014", "fffe0700042610061451", "00", ""},
{"w;;first;;;15;b5090400;date;;bda", "26.10.2014", "ff15b5090604002610061445", "00", ""}, {"w;;first;;;15;b5090400;date;;bda", "26.10.2014", "ff15b5090604002610061445", "00", ""},
}; };
map<string, DataField*> templates; map<string, DataField*> templates;
Message* message = NULL; Message *message = NULL;
Message* deleteMessage = NULL;
MessageMap* messages = new MessageMap();
for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) { for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) {
string check[5] = checks[i]; string check[5] = checks[i];
istringstream isstr(check[0]); istringstream isstr(check[0]);
@@ -83,6 +85,7 @@ int main()
SymbolString mstr = SymbolString(check[2], false); SymbolString mstr = SymbolString(check[2], false);
SymbolString sstr = SymbolString(check[3], false); SymbolString sstr = SymbolString(check[3], false);
string flags = check[4]; string flags = check[4];
bool dontMap = flags.find('m') != string::npos;
bool failedCreate = flags.find('c') != string::npos; bool failedCreate = flags.find('c') != string::npos;
bool failedPrepare = flags.find('p') != string::npos; bool failedPrepare = flags.find('p') != string::npos;
bool failedPrepareMatch = flags.find('P') != string::npos; bool failedPrepareMatch = flags.find('P') != string::npos;
@@ -92,12 +95,12 @@ int main()
while (getline(isstr, item, ';') != 0) while (getline(isstr, item, ';') != 0)
entries.push_back(item); entries.push_back(item);
if (message != NULL) { if (deleteMessage != NULL) {
delete message; delete deleteMessage;
message = NULL; deleteMessage = NULL;
} }
vector<string>::iterator it = entries.begin(); vector<string>::iterator it = entries.begin();
result_t result = Message::create(it, entries.end(), templates, message); result_t result = Message::create(it, entries.end(), templates, deleteMessage);
if (failedCreate == true) { if (failedCreate == true) {
if (result == RESULT_OK) if (result == RESULT_OK)
@@ -112,7 +115,7 @@ int main()
printErrorPos(entries.begin(), entries.end(), it); printErrorPos(entries.begin(), entries.end(), it);
continue; continue;
} }
if (message == NULL) { if (deleteMessage == NULL) {
cout << "\"" << check[0] << "\": create error: NULL" << endl; cout << "\"" << check[0] << "\": create error: NULL" << endl;
continue; continue;
} }
@@ -122,6 +125,23 @@ int main()
} }
cout << "\"" << check[0] << "\": create OK" << endl; cout << "\"" << check[0] << "\": create OK" << endl;
if (dontMap == false) {
result = messages->add(deleteMessage);
if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": add error: "
<< getResultCode(result) << endl;
continue;
}
cout << " map OK" << endl;
message = deleteMessage;
deleteMessage = NULL;
if (messages->find(mstr) == message)
cout << " find OK" << endl;
else
cout << " find error: NULL" << endl;
}
else
message = deleteMessage;
istringstream input(inputStr); istringstream input(inputStr);
SymbolString writeMstr = SymbolString(); SymbolString writeMstr = SymbolString();
result = message->prepare(0xff, writeMstr, input); result = message->prepare(0xff, writeMstr, input);
@@ -142,14 +162,18 @@ int main()
bool match = writeMstr==mstr; bool match = writeMstr==mstr;
verify(failedPrepareMatch, "prepare", inputStr, match, mstr.getDataStr(), writeMstr.getDataStr()); verify(failedPrepareMatch, "prepare", inputStr, match, mstr.getDataStr(), writeMstr.getDataStr());
}
delete message; if (deleteMessage != NULL) {
message = NULL; delete deleteMessage;
deleteMessage = NULL;
} }
for (map<string, DataField*>::iterator it = templates.begin(); it != templates.end(); it++) for (map<string, DataField*>::iterator it = templates.begin(); it != templates.end(); it++)
delete it->second; delete it->second;
delete messages;
return 0; return 0;
} }