From 70e0569cd3a5057486e0931012f6b694ef25cea5 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 20 Sep 2015 11:29:29 +0200 Subject: [PATCH] use optional comment and unit for first field when deriving a DataFieldSet, use name only for singular template reference, also trim split parts, documentation --- src/lib/ebus/data.cpp | 31 ++++++++++++++++-------------- src/lib/ebus/data.h | 2 +- src/lib/ebus/message.cpp | 24 ++++++++++++----------- src/lib/ebus/test/test_message.cpp | 15 ++++++++++----- 4 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 1f97ec3c..b2c353c8 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -183,16 +183,16 @@ result_t DataField::create(vector::iterator& it, bool hasPartStr = false; string token; - // templates: name,type[:len][,[divisor|values][,[unit][,[comment]]]] - // normal: name,part,type[:len][,[divisor|values][,[unit][,[comment]]]] - const string name = *it++; + // template: name,type[:len][,[divisor|values][,[unit][,[comment]]]] + // std: name,part,type[:len][,[divisor|values][,[unit][,[comment]]]] + const string name = *it++; // name if (it == end) break; if (isTemplate) partType = pt_any; else { - const char* partStr = (*it++).c_str(); + const char* partStr = (*it++).c_str(); // part hasPartStr = partStr[0] != 0; if (it == end) { if (!name.empty() || hasPartStr) @@ -219,7 +219,7 @@ result_t DataField::create(vector::iterator& it, firstComment = comment; } - const string typeStr = *it++; + const string typeStr = *it++; // type[:len] if (typeStr.empty()) { if (!name.empty() || hasPartStr) result = RESULT_ERR_MISSING_TYPE; @@ -228,13 +228,14 @@ result_t DataField::create(vector::iterator& it, map values; if (it != end) { - const string divisorStr = *it++; + const string divisorStr = *it++; // [divisor|values] if (!divisorStr.empty()) { if (divisorStr.find('=') == string::npos) divisor = parseSignedInt(divisorStr.c_str(), 10, -MAX_DIVISOR, MAX_DIVISOR, result); else { istringstream stream(divisorStr); while (getline(stream, token, VALUE_SEPARATOR) != 0) { + DataFieldTemplates::trim(token); const char* str = token.c_str(); char* strEnd = NULL; unsigned long int id; @@ -258,7 +259,7 @@ result_t DataField::create(vector::iterator& it, if (it == end) unit = ""; else { - const string str = *it++; + const string str = *it++; // [unit] if (strcasecmp(str.c_str(), NULL_VALUE) == 0) unit = ""; else @@ -268,7 +269,7 @@ result_t DataField::create(vector::iterator& it, if (it == end) comment = ""; else { - const string str = *it++; + const string str = *it++; // [comment] if (strcasecmp(str.c_str(), NULL_VALUE) == 0) comment = ""; else @@ -278,6 +279,7 @@ result_t DataField::create(vector::iterator& it, bool firstType = true; istringstream stream(typeStr); while (result == RESULT_OK && getline(stream, token, VALUE_SEPARATOR) != 0) { + DataFieldTemplates::trim(token); DataField* templ = templates->get(token); unsigned char length; if (templ == NULL) { @@ -297,12 +299,12 @@ result_t DataField::create(vector::iterator& it, else if (result == RESULT_OK) result = RESULT_ERR_NOTFOUND; // type not found } - else - result = templ->derive(firstType ? name : "", firstType ? comment : "", firstType ? unit : "", partType, divisor, values, fields); - + else { + bool lastType = stream.eof(); + result = templ->derive((firstType && lastType) ? name : "", firstType ? comment : "", firstType ? unit : "", partType, divisor, values, fields); + } firstType = false; } - } while (it != end && result == RESULT_OK); if (result != RESULT_OK) { @@ -1256,11 +1258,12 @@ result_t DataFieldSet::derive(string name, string comment, { if (!values.empty()) return RESULT_ERR_INVALID_ARG; // value list not allowed in set derive - + bool first = true; for (vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { - result_t result = (*it)->derive("", "", "", partType, divisor, values, fields); + result_t result = (*it)->derive("", first?comment:"", first?unit:"", partType, divisor, values, fields); if (result != RESULT_OK) return result; + first = false; } return RESULT_OK; diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index 79790584..88280e3b 100644 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -190,7 +190,7 @@ public: /** * Derive a new @a DataField from this field. - * @param name the field name. + * @param name the field name, or empty to use this fields name. * @param comment the field comment, or empty to use this fields comment. * @param unit the value unit, or empty to use this fields unit (if applicable). * @param partType the message part in which the field is stored. diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 8a1124b8..6580b581 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -91,7 +91,7 @@ result_t Message::create(vector::iterator& it, const vector::ite vector< vector >* defaultsRows, DataFieldTemplates* templates, vector& messages) { - // [type],[circuit],name,[comment],[QQ[;QQ]*],[ZZ],id,fields... + // [type],[circuit],name,[comment],[QQ[;QQ]*],[ZZ],[PBSB],[ID],fields... result_t result; bool isWrite = false, isPassive = false; string defaultName; @@ -100,7 +100,7 @@ result_t Message::create(vector::iterator& it, const vector::ite if (it == end) return RESULT_ERR_EOF; - const char* str = (*it++).c_str(); + const char* str = (*it++).c_str(); // [type] if (it == end) return RESULT_ERR_EOF; size_t len = strlen(str); @@ -137,22 +137,22 @@ result_t Message::create(vector::iterator& it, const vector::ite } } - string circuit = getDefault(*it++, defaults, defaultPos++); + string circuit = getDefault(*it++, defaults, defaultPos++); // [circuit] if (it == end) return RESULT_ERR_EOF; - string name = *it++; + string name = *it++; // name if (it == end) return RESULT_ERR_EOF; if (name.length() == 0) return RESULT_ERR_INVALID_ARG; // empty name defaultPos++; - string comment = getDefault(*it++, defaults, defaultPos++); + string comment = getDefault(*it++, defaults, defaultPos++); // [comment] if (it == end) return RESULT_ERR_EOF; - str = getDefault(*it++, defaults, defaultPos++).c_str(); + str = getDefault(*it++, defaults, defaultPos++).c_str(); // [QQ[;QQ]*] if (it == end) return RESULT_ERR_EOF; unsigned char srcAddress; @@ -166,7 +166,7 @@ result_t Message::create(vector::iterator& it, const vector::ite return RESULT_ERR_INVALID_ADDR; } - str = getDefault(*it++, defaults, defaultPos++).c_str(); + str = getDefault(*it++, defaults, defaultPos++).c_str(); // [ZZ] if (it == end) return RESULT_ERR_EOF; vector dstAddresses; @@ -178,6 +178,7 @@ result_t Message::create(vector::iterator& it, const vector::ite string token; bool first = true; while (getline(stream, token, VALUE_SEPARATOR) != 0) { + DataFieldTemplates::trim(token); unsigned char dstAddress = (unsigned char)parseInt(token.c_str(), 16, 0, 0xff, result); if (result != RESULT_OK) return result; @@ -195,7 +196,7 @@ result_t Message::create(vector::iterator& it, const vector::ite vector id; bool useDefaults = true; - for (int pos = 0; pos < 2 && it != end; pos++) { // message id (PBSB, optional master data) + for (int pos = 0; pos < 2 && it != end; pos++) { // [PBSB],[ID] (optional master data) string token = *it++; if (useDefaults) { if (pos == 0 && token.size() > 0) @@ -212,7 +213,7 @@ result_t Message::create(vector::iterator& it, const vector::ite token.clear(); token.push_back((char)input.get()); if (input.eof()) { - return RESULT_ERR_INVALID_ARG; // too short hex + return RESULT_ERR_INVALID_ARG; // to short hex } token.push_back((char)input.get()); @@ -223,12 +224,12 @@ result_t Message::create(vector::iterator& it, const vector::ite id.push_back(value); } if (pos == 0 && id.size() != 2) - return RESULT_ERR_INVALID_ARG; // missing/too short/too PBSB + return RESULT_ERR_INVALID_ARG; // missing/to short/to long PBSB defaultPos++; } if (id.size() < 2 || id.size() > 6) { - return RESULT_ERR_INVALID_ARG; // missing/too short/too long ID + return RESULT_ERR_INVALID_ARG; // missing/to short/to long ID } vector::iterator realEnd = end; @@ -565,6 +566,7 @@ result_t MessageMap::addFromFile(vector::iterator& begin, const vector messages; while (getline(stream, type, VALUE_SEPARATOR) != 0) { + DataFieldTemplates::trim(type); *restart = type; begin = restart; messages.clear(); diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index c0cda326..0702c655 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -43,8 +43,9 @@ void verify(bool expectFailMatch, string type, string input, int main() { - // message= [type];circuit;name;[comment];[QQ[;QQ]*];ZZ;PBSB;fields... - // field= name;[pos];type[;[divisor|values][;[unit][;[comment]]]] + // message: [type],[circuit],name,[comment],[QQ[;QQ]*],[ZZ],[PBSB],[ID],fields... + // field: name,part,type[:len][,[divisor|values][,[unit][,[comment]]]] + // template: name,type[:len][,[divisor|values][,[unit][,[comment]]]] string checks[][5] = { // "message", "decoded", "master", "slave", "flags" {"date,HDA:3,,,Datum", "", "", "", "t"}, @@ -54,7 +55,10 @@ int main() {"temp2,D2B,,°C,Temperatur", "", "", "", "t"}, {"power,UCH,,kW", "", "", "", "t"}, {"sensor,UCH,0=ok;85=circuit;170=cutoff,,Fühlerstatus", "", "", "", "t"}, - {"tempsensor,temp;sensor", "", "", "", "t"}, + {"tempsensor,temp;sensor,,Temperatursensor", "", "", "", "t"}, + {"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor", "temp=-14.00 Temperatursensor [Temperatur];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"}, + {"r,message circuit,message name,message comment,,25,B509,0d2800,,,tempsensor,,field unit,field comment", "temp=-14.00 field unit [field comment];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"}, + {"r,message circuit,message name,message comment,,25,B509,0d2800,,,temp,,field unit,field comment,,,sensor", "temp=-14.00 field unit [field comment];sensor=ok [Fühlerstatus]", "ff25b509030d2800", "0320ff00", "mD"}, {"u,,first,,,fe,0700,,x,,bda", "26.10.2014", "fffe07000426100614", "00", "p"}, {"u,broadcast,hwStatus,,,fe,b505,27,,,UCH,,,,,,UCH,,,,,,UCH,,,", "0;19;0", "10feb505042700130097", "00", ""}, {"w,,first,,,15,b509,0400,date,,bda", "26.10.2014", "ff15b50906040026100614", "00", "m"}, @@ -97,7 +101,8 @@ int main() bool dontMap = flags.find('m') != string::npos; bool onlyMap = flags.find('M') != string::npos; bool failedCreate = flags.find('c') != string::npos; - bool decode = flags.find('d') != string::npos; + bool decodeVerbose = flags.find('D') != string::npos; + bool decode = decodeVerbose || (flags.find('d') != string::npos); bool failedPrepare = flags.find('p') != string::npos; bool failedPrepareMatch = flags.find('P') != string::npos; bool multi = flags.find('*') != string::npos; @@ -209,7 +214,7 @@ int main() if (message->isPassive() || decode) { ostringstream output; - result = message->decode(mstr, sstr, output); + result = message->decode(mstr, sstr, output, decodeVerbose?OF_VERBOSE:0); if (result != RESULT_OK) { cout << " \"" << check[2] << "\" / \"" << check[3] << "\": decode error: " << getResultCode(result) << endl;