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;
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,
const map<string, DataField*> templates, Message*& returnValue)
{
// [type];[class];name;[comment];[QQ];ZZ;id;fields...
result_t result;
// [type];class;name;[comment];[QQ];ZZ;id;fields...
bool isSet, isActive;
unsigned int pollPriority = 0;
if (it == end)
return RESULT_ERR_EOF;
const char* str = (*it++).c_str();
if (it == end)
return RESULT_ERR_EOF;
bool isSetMessage, isActiveMessage;
unsigned int pollPriority = 0;
if (strcasecmp(str, "W") == 0) {
isActiveMessage = true;
isSetMessage = true;
isActive = true;
isSet = true;
} else if (str[0] == 'C' || str[0] == 'c') {
isActiveMessage = false;
isSetMessage = str[1] == 'W' || str[1] == 'w';
isActive = false;
isSet = str[1] == 'W' || str[1] == 'w';
} else if (str[0] == 'P' || str[0] == 'p') {
isActiveMessage = true;
isSetMessage = false;
isActive = true;
isSet = false;
if (str[1] == 0)
pollPriority = 1;
else {
@@ -58,8 +80,8 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
return result;
}
} else {
isActiveMessage = true;
isSetMessage = false;
isActive = true;
isSet = false;
}
string clazz = *it++;
@@ -80,7 +102,7 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
if (it == end)
return RESULT_ERR_EOF;
unsigned char srcAddress;
if (*str == 0 || isActiveMessage == true)
if (*str == 0 || isActive == true)
srcAddress = SYN; // no specific source defined, or ignore for active message
else {
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
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)
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;
}
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.push_back(srcAddress, 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,
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);
if (result != RESULT_OK)
return result;
@@ -170,3 +192,97 @@ result_t Message::handle(SymbolString& masterData, SymbolString& slaveData,
}
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 <string>
#include <vector>
#include <map>
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
{
@@ -39,8 +40,8 @@ public:
* @brief Constructs a new instance.
* @param class the optional device class.
* @param name the message name (unique within the same class and type).
* @param isSetMessage whether this is a set message.
* @param isActiveMessage true if message can be initiated by the daemon
* @param isSet whether this is a set message.
* @param isActive true if message can be initiated by the daemon
* itself any any other participant, false if message can only be initiated
* by a participant other than the daemon.
* @param comment the comment.
@@ -50,15 +51,11 @@ public:
* @param data the @a DataField for encoding/decoding the message.
* @param pollPriority the priority for polling, or 0 for no polling at all.
*/
Message(const string clazz, const string name, const bool isSetMessage,
const bool isActiveMessage, const string comment,
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_isSetMessage(isSetMessage),
m_isActiveMessage(isActiveMessage), m_comment(comment),
m_srcAddress(srcAddress), m_dstAddress(dstAddress),
m_id(id), m_data(data), m_pollPriority(pollPriority) {}
const unsigned int pollPriority);
/**
* @brief Destructor.
*/
@@ -88,7 +85,7 @@ public:
* @brief Get 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
* participant.
@@ -96,7 +93,7 @@ public:
* participant, false if message can only be initiated by a participant
* other than the daemon.
*/
bool isActiveMessage() const { return m_isActiveMessage; }
bool isActive() const { return m_isActive; }
/**
* @brief Get the comment.
* @return the comment.
@@ -117,6 +114,11 @@ public:
* @return the primary, secondary, and optionally further command ID bytes.
*/
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.
* @param masterData the unescaped master data @a SymbolString for reading binary data.
@@ -142,7 +144,6 @@ public:
result_t handle(SymbolString& masterData, SymbolString& slaveData,
ostringstream& output, char separator=';', bool answer=false);
private:
/** the optional device class. */
@@ -150,11 +151,11 @@ private:
/** the message name (unique within the same class and type). */
const string m_name;
/** 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
* participant, false if message can only be initiated by a participant
* other than the daemon. */
const bool m_isActiveMessage;
const bool m_isActive;
/** the comment. */
const string m_comment;
/** the source address (optional if passive), or @a SYN for any. */
@@ -163,6 +164,8 @@ private:
const unsigned char m_dstAddress;
/** the primary, secondary, and optionally further command ID bytes. */
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. */
DataField* m_data;
/** 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_
+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)
{
cout << "Errroneous item is here:" << endl;
cout << "Erroneous item is here:" << endl;
bool first = true;
int cnt = 0;
if (pos > it)
@@ -71,11 +71,13 @@ int main()
// field= name;[pos];type[;[divisor|values][;[unit][;[comment]]]]
string checks[][5] = {
// "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", ""},
};
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++) {
string check[5] = checks[i];
istringstream isstr(check[0]);
@@ -83,6 +85,7 @@ int main()
SymbolString mstr = SymbolString(check[2], false);
SymbolString sstr = SymbolString(check[3], false);
string flags = check[4];
bool dontMap = flags.find('m') != string::npos;
bool failedCreate = flags.find('c') != string::npos;
bool failedPrepare = flags.find('p') != string::npos;
bool failedPrepareMatch = flags.find('P') != string::npos;
@@ -92,12 +95,12 @@ int main()
while (getline(isstr, item, ';') != 0)
entries.push_back(item);
if (message != NULL) {
delete message;
message = NULL;
if (deleteMessage != NULL) {
delete deleteMessage;
deleteMessage = NULL;
}
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 (result == RESULT_OK)
@@ -112,7 +115,7 @@ int main()
printErrorPos(entries.begin(), entries.end(), it);
continue;
}
if (message == NULL) {
if (deleteMessage == NULL) {
cout << "\"" << check[0] << "\": create error: NULL" << endl;
continue;
}
@@ -122,6 +125,23 @@ int main()
}
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);
SymbolString writeMstr = SymbolString();
result = message->prepare(0xff, writeMstr, input);
@@ -142,14 +162,18 @@ int main()
bool match = writeMstr==mstr;
verify(failedPrepareMatch, "prepare", inputStr, match, mstr.getDataStr(), writeMstr.getDataStr());
}
delete message;
message = NULL;
if (deleteMessage != NULL) {
delete deleteMessage;
deleteMessage = NULL;
}
for (map<string, DataField*>::iterator it = templates.begin(); it != templates.end(); it++)
delete it->second;
delete messages;
return 0;
}