From 43b50875f9ad1a9d3722fb8e02c0be34e26144d4 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 30 Nov 2014 10:23:50 +0100 Subject: [PATCH] added defaults, allow poll priority as number only, verbose print csv error position, splitted id into pbsb+id again, moved printErrorPos to data.h --- src/lib/ebus/message.cpp | 171 +++++++++++++++++++++-------- src/lib/ebus/message.h | 6 +- src/lib/ebus/test/test_message.cpp | 41 ++----- 3 files changed, 140 insertions(+), 78 deletions(-) diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index a30a0a6b..7f736d45 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -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* 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::iterator& it, const vector::iterator end, - DataFieldTemplates* templates, Message*& returnValue) + vector* 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::iterator& it, const vector::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::iterator& it, const vector::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::iterator& it, const vector::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::iterator& it, const vector::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::iterator& it, const vector::ite if (isValidAddress(dstAddress) == false) return RESULT_ERR_INVALID_ARG; - istringstream input(*it++); // message id (PBSB + optional master data) vector 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::iterator realEnd = end; + if (defaults!=NULL && defaults->size() > defaultPos + 3) { // need at least "[name];[part];type" (optional: "[divisor|values][;[unit][;[comment]]]]") + vector 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::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::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& row, DataFieldTemplates* arg) +result_t MessageMap::addFromFile(vector& row, DataFieldTemplates* arg, vector< vector >* defaults) { Message* message = NULL; - vector::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* defaultRow = NULL; + if (defaults != NULL && defaults->size() > 0) { + for (vector< vector >::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::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; } diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index a36674fd..6863570d 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -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::iterator& it, const vector::iterator end, + vector* 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& row, DataFieldTemplates* arg); + virtual result_t addFromFile(vector& row, DataFieldTemplates* arg, vector< vector >* defaults); /** * @brief Finds the @a Message instance for the specified class and name. * @param master the master @a SymbolString for identifying the @a Message. diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 389d845f..204f3afc 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -41,42 +41,17 @@ void verify(bool expectFailMatch, string type, string input, << gotStr << "<, expected >" << expectStr << "<" << endl; } -void printErrorPos(vector::iterator it, const vector::iterator end, vector::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::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)