added defaults, allow poll priority as number only, verbose print csv error position, splitted id into pbsb+id again, moved printErrorPos to data.h
This commit is contained in:
+128
-43
@@ -49,13 +49,31 @@ Message::Message(const string clazz, const string name, const bool isSet,
|
||||
m_key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper method for getting a default if the value is empty.
|
||||
* @param value the value to check.
|
||||
* @param defaults a @a verctor of defaults, or NULL.
|
||||
* @param pos the position in defaults.
|
||||
* @return the default if available and value is empty, or the value.
|
||||
*/
|
||||
string getDefault(string value, vector<string>* defaults, size_t pos)
|
||||
{
|
||||
if (value.length() > 0 || defaults == NULL || pos > defaults->size()) {
|
||||
return value;
|
||||
}
|
||||
|
||||
string ret = defaults->at(pos);
|
||||
return ret;
|
||||
}
|
||||
|
||||
result_t Message::create(vector<string>::iterator& it, const vector<string>::iterator end,
|
||||
DataFieldTemplates* templates, Message*& returnValue)
|
||||
vector<string>* defaults, DataFieldTemplates* templates, Message*& returnValue)
|
||||
{
|
||||
// [type];[class];name;[comment];[QQ];ZZ;id;fields...
|
||||
result_t result;
|
||||
bool isSet, isActive;
|
||||
unsigned int pollPriority = 0;
|
||||
size_t defaultPos = 1;
|
||||
if (it == end)
|
||||
return RESULT_ERR_EOF;
|
||||
|
||||
@@ -68,7 +86,7 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
|
||||
} else if (str[0] == 'C' || str[0] == 'c') {
|
||||
isActive = false;
|
||||
isSet = str[1] == 'W' || str[1] == 'w';
|
||||
} else if (str[0] == 'P' || str[0] == 'p') {
|
||||
} else if (str[0] == 'P' || str[0] == 'p') { // poll priority
|
||||
isActive = true;
|
||||
isSet = false;
|
||||
if (str[1] == 0)
|
||||
@@ -79,12 +97,19 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
|
||||
if (result != RESULT_OK)
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
} else if (str[0] >= '0' && str[0] <= '9') { // poll priority
|
||||
isActive = true;
|
||||
isSet = false;
|
||||
result_t result;
|
||||
pollPriority = parseInt(str, 10, 1, 9, result);
|
||||
if (result != RESULT_OK)
|
||||
return result;
|
||||
} else { // default "r"
|
||||
isActive = true;
|
||||
isSet = false;
|
||||
}
|
||||
|
||||
string clazz = *it++;
|
||||
string clazz = getDefault(*it++, defaults, defaultPos++);
|
||||
if (it == end)
|
||||
return RESULT_ERR_EOF;
|
||||
|
||||
@@ -93,17 +118,18 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
|
||||
return RESULT_ERR_EOF;
|
||||
if (name.length() == 0)
|
||||
return RESULT_ERR_INVALID_ARG; // empty name
|
||||
defaultPos++;
|
||||
|
||||
string comment = *it++;
|
||||
string comment = getDefault(*it++, defaults, defaultPos++);
|
||||
if (it == end)
|
||||
return RESULT_ERR_EOF;
|
||||
|
||||
str = (*it++).c_str();
|
||||
str = getDefault(*it++, defaults, defaultPos++).c_str();
|
||||
if (it == end)
|
||||
return RESULT_ERR_EOF;
|
||||
unsigned char srcAddress;
|
||||
if (*str == 0 || isActive == true)
|
||||
srcAddress = SYN; // no specific source defined, or ignore for active message
|
||||
if (*str == 0)
|
||||
srcAddress = SYN; // no specific source defined
|
||||
else {
|
||||
srcAddress = parseInt(str, 16, 0, 0xff, result);
|
||||
if (result != RESULT_OK)
|
||||
@@ -112,7 +138,7 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
|
||||
return RESULT_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
str = (*it++).c_str();
|
||||
str = getDefault(*it++, defaults, defaultPos++).c_str();
|
||||
if (it == end)
|
||||
return RESULT_ERR_EOF;
|
||||
|
||||
@@ -122,35 +148,74 @@ result_t Message::create(vector<string>::iterator& it, const vector<string>::ite
|
||||
if (isValidAddress(dstAddress) == false)
|
||||
return RESULT_ERR_INVALID_ARG;
|
||||
|
||||
istringstream input(*it++); // message id (PBSB + optional master data)
|
||||
vector<unsigned char> id;
|
||||
string token;
|
||||
if (it == end)
|
||||
return RESULT_ERR_EOF;
|
||||
while (input.eof() == false) {
|
||||
while (input.peek() == ' ')
|
||||
input.get();
|
||||
if (input.eof() == true) // no more digits
|
||||
break;
|
||||
token.clear();
|
||||
token.push_back(input.get());
|
||||
if (input.eof() == true)
|
||||
return RESULT_ERR_INVALID_ARG; // too short hex
|
||||
token.push_back(input.get());
|
||||
for (int pos=0, useDefaults=1; pos<2; pos++) { // message id (PBSB, optional master data)
|
||||
string token = *it++;
|
||||
if (useDefaults == 1) {
|
||||
if (pos == 0 && token.size() > 0) {
|
||||
useDefaults = false;
|
||||
} else {
|
||||
token.append(getDefault("", defaults, defaultPos));
|
||||
}
|
||||
}
|
||||
istringstream input(token);
|
||||
if (it == end)
|
||||
return RESULT_ERR_EOF;
|
||||
while (input.eof() == false) {
|
||||
while (input.peek() == ' ')
|
||||
input.get();
|
||||
if (input.eof() == true) // no more digits
|
||||
break;
|
||||
token.clear();
|
||||
token.push_back(input.get());
|
||||
if (input.eof() == true) {
|
||||
return RESULT_ERR_INVALID_ARG; // too short hex
|
||||
}
|
||||
token.push_back(input.get());
|
||||
|
||||
unsigned char value = parseInt(token.c_str(), 16, 0, 0xff, result);
|
||||
if (result != RESULT_OK)
|
||||
return result; // invalid hex value
|
||||
id.push_back(value);
|
||||
unsigned char value = parseInt(token.c_str(), 16, 0, 0xff, result);
|
||||
if (result != RESULT_OK) {
|
||||
return result; // invalid hex value
|
||||
}
|
||||
id.push_back(value);
|
||||
}
|
||||
if (pos == 0 && id.size() != 2) {
|
||||
return RESULT_ERR_INVALID_ARG; // missing/too short/too PBSB
|
||||
}
|
||||
defaultPos++;
|
||||
}
|
||||
if (id.size() < 2 || id.size() > 6)
|
||||
if (id.size() < 2 || id.size() > 6) {
|
||||
return RESULT_ERR_INVALID_ARG; // missing/too short/too long ID
|
||||
}
|
||||
|
||||
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;
|
||||
while (defaults->at(defaultPos + 3).size() > 0) {
|
||||
for (size_t i = 0; i < 6; i++) {
|
||||
if (defaults->size() > defaultPos)
|
||||
newTypes.push_back(defaults->at(defaultPos));
|
||||
else
|
||||
newTypes.push_back("");
|
||||
|
||||
defaultPos++;
|
||||
}
|
||||
if (defaults->size() <= defaultPos + 3)
|
||||
break;
|
||||
}
|
||||
if (newTypes.size() > 0) {
|
||||
while (it != end) {
|
||||
newTypes.push_back(*it++);
|
||||
}
|
||||
it = newTypes.begin();
|
||||
realEnd = newTypes.end();
|
||||
}
|
||||
}
|
||||
DataField* data = NULL;
|
||||
result = DataField::create(it, end, templates, data, isSet, dstAddress);
|
||||
if (result != RESULT_OK)
|
||||
result = DataField::create(it, realEnd, templates, data, isSet, dstAddress);
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
|
||||
}
|
||||
returnValue = new Message(clazz, name, isSet, isActive, comment, srcAddress, dstAddress, id, data, pollPriority);
|
||||
return RESULT_OK;
|
||||
}
|
||||
@@ -201,14 +266,16 @@ result_t MessageMap::add(Message* message)
|
||||
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 (nameIt != m_messagesByName.end()) {
|
||||
return RESULT_ERR_DUPLICATE; // 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())
|
||||
if (keyIt != m_passiveMessagesByKey.end()) {
|
||||
return RESULT_ERR_DUPLICATE; // duplicate key
|
||||
}
|
||||
|
||||
unsigned char idLength = message->getId().size() - 2;
|
||||
if (idLength > m_maxIdLength)
|
||||
@@ -221,18 +288,36 @@ result_t MessageMap::add(Message* message)
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
result_t MessageMap::addFromFile(vector<string>& row, DataFieldTemplates* arg)
|
||||
result_t MessageMap::addFromFile(vector<string>& row, DataFieldTemplates* arg, vector< vector<string> >* defaults)
|
||||
{
|
||||
Message* message = NULL;
|
||||
vector<string>::iterator it = row.begin();
|
||||
result_t result = Message::create(it, row.end(), arg, message);
|
||||
if (result != RESULT_OK)
|
||||
return result;
|
||||
|
||||
result = add(message);
|
||||
if (result != RESULT_OK)
|
||||
delete message;
|
||||
string types = row[0];
|
||||
if (types.length() == 0)
|
||||
types.append("r");
|
||||
result_t result = RESULT_ERR_EOF;
|
||||
|
||||
for (size_t i=0; i<types.length(); i++) {
|
||||
string type = types.substr(i, 1);
|
||||
vector<string>* defaultRow = NULL;
|
||||
if (defaults != NULL && defaults->size() > 0) {
|
||||
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();
|
||||
result = Message::create(it, row.end(), defaultRow, arg, message);
|
||||
if (result != RESULT_OK) {
|
||||
printErrorPos(row.begin(), row.end(), it);
|
||||
return result;
|
||||
}
|
||||
result = add(message);
|
||||
if (result != RESULT_OK) {
|
||||
delete message;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,12 +64,14 @@ public:
|
||||
* @brief Factory method for creating a new instance.
|
||||
* @param it the iterator to traverse for 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 templates the @a DataFieldTemplates to be referenced by name, or NULL.
|
||||
* @param returnValue the variable in which to store the created instance.
|
||||
* @return @a RESULT_OK on success, or an error code.
|
||||
* Note: the caller needs to free the created instance.
|
||||
*/
|
||||
static result_t create(vector<string>::iterator& it, const vector<string>::iterator end,
|
||||
vector<string>* defaults,
|
||||
DataFieldTemplates*, Message*& returnValue);
|
||||
/**
|
||||
* @brief Get the optional device class.
|
||||
@@ -183,7 +185,7 @@ public:
|
||||
/**
|
||||
* @brief Constructs a new instance.
|
||||
*/
|
||||
MessageMap() : m_maxIdLength(0) {}
|
||||
MessageMap() : FileReader(true), m_maxIdLength(0) {}
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
@@ -196,7 +198,7 @@ public:
|
||||
*/
|
||||
result_t add(Message* message);
|
||||
// @copydoc
|
||||
virtual result_t addFromFile(vector<string>& row, DataFieldTemplates* arg);
|
||||
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.
|
||||
* @param master the master @a SymbolString for identifying the @a Message.
|
||||
|
||||
@@ -41,42 +41,17 @@ void verify(bool expectFailMatch, string type, string input,
|
||||
<< gotStr << "<, expected >" << expectStr << "<" << endl;
|
||||
}
|
||||
|
||||
void printErrorPos(vector<string>::iterator it, const vector<string>::iterator end, vector<string>::iterator pos)
|
||||
{
|
||||
cout << "Erroneous item is here:" << endl;
|
||||
bool first = true;
|
||||
int cnt = 0;
|
||||
if (pos > it)
|
||||
pos--;
|
||||
while (it != end) {
|
||||
if (first == true)
|
||||
first = false;
|
||||
else {
|
||||
cout << ';';
|
||||
if (it <= pos) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
if (it < pos) {
|
||||
cnt += (*it).length();
|
||||
}
|
||||
cout << (*it++);
|
||||
}
|
||||
cout << endl;
|
||||
cout << setw(cnt) << " " << setw(0) << "^" << endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// message= [type];class;name;[comment];[QQ];ZZ;PBSB;fields...
|
||||
// field= name;[pos];type[;[divisor|values][;[unit][;[comment]]]]
|
||||
string checks[][5] = {
|
||||
// "message", "flags"
|
||||
{"c;;first;;;fe;0700;x;;bda", "26.10.2014", "fffe0700042610061451", "00", "p"},
|
||||
{"w;;first;;;15;b5090400;date;;bda", "26.10.2014", "ff15b5090604002610061445", "00", "m"},
|
||||
{"r;ehp;time;;;08;b5090d2800;;;time", "15:00:17", "ff08b509030d2800ea", "0311000f00", "m"},
|
||||
{"r;ehp;date;;;08;b5090d2900;;;hda:3", "23.11.2014", "ff08b509030d290071", "03170b0e5a", "m"},
|
||||
{"c;ehp;ActualEnvironmentPower;Energiebezug;;08;B50929BA00;;s;IGN:2;;;;;s;power", "8", "1008b5090329ba00", "03ba0008", "p"},
|
||||
{"c;;first;;;fe;0700;;x;;bda", "26.10.2014", "fffe0700042610061451", "00", "p"},
|
||||
{"w;;first;;;15;b509;0400;date;;bda", "26.10.2014", "ff15b5090604002610061445", "00", "m"},
|
||||
{"r;ehp;time;;;08;b509;0d2800;;;time", "15:00:17", "ff08b509030d2800ea", "0311000f00", "m"},
|
||||
{"r;ehp;date;;;08;b509;0d2900;;;hda:3", "23.11.2014", "ff08b509030d290071", "03170b0e5a", "m"},
|
||||
{"c;ehp;ActualEnvironmentPower;Energiebezug;;08;B509;29BA00;;s;IGN:2;;;;;s;power", "8", "1008b5090329ba00", "03ba0008", "p"},
|
||||
};
|
||||
DataFieldTemplates* templates = new DataFieldTemplates();
|
||||
result_t result = templates->readFromFile("_types.csv");
|
||||
@@ -86,13 +61,13 @@ int main()
|
||||
cout << "read templates error: " << getResultCode(result) << endl;
|
||||
|
||||
MessageMap* messages = new MessageMap();
|
||||
result = messages->readFromFile("ehp00.csv", templates);
|
||||
result = messages->readFromFile("neu-ehp00.csv", templates);
|
||||
if (result == RESULT_OK)
|
||||
cout << "read messages OK" << endl;
|
||||
else
|
||||
cout << "read messages error: " << getResultCode(result) << endl;
|
||||
|
||||
Message *message = NULL;
|
||||
Message* message = NULL;
|
||||
Message* deleteMessage = NULL;
|
||||
for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) {
|
||||
string check[5] = checks[i];
|
||||
@@ -116,7 +91,7 @@ int main()
|
||||
deleteMessage = NULL;
|
||||
}
|
||||
vector<string>::iterator it = entries.begin();
|
||||
result_t result = Message::create(it, entries.end(), templates, deleteMessage);
|
||||
result_t result = Message::create(it, entries.end(), NULL, templates, deleteMessage);
|
||||
|
||||
if (failedCreate == true) {
|
||||
if (result == RESULT_OK)
|
||||
|
||||
Reference in New Issue
Block a user