From 0f93369beef6f75ed1e96281632f62a144a90a54 Mon Sep 17 00:00:00 2001 From: john30 Date: Fri, 13 Mar 2015 22:12:11 +0100 Subject: [PATCH] allow mixing references to base type and templates in message definition --- src/lib/ebus/data.cpp | 230 +++++++++++++++----------------- src/lib/ebus/data.h | 21 ++- src/lib/ebus/test/test_data.cpp | 1 + 3 files changed, 128 insertions(+), 124 deletions(-) diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index f292370f..1071e983 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -274,132 +274,33 @@ result_t DataField::create(vector::iterator& it, comment = str; } - string typeName; - size_t pos = typeStr.find(LENGTH_SEPARATOR); - unsigned char length; - if (pos == string::npos) { - length = 0; - // check for reference(s) to templates - if (templates != NULL) { - istringstream stream(typeStr); - bool found = false; - while (result == RESULT_OK && getline(stream, token, VALUE_SEPARATOR) != 0) { - DataField* templ = templates->get(token); - if (templ == NULL) { - if (!found) - break; // fallback to direct definition - result = RESULT_ERR_NOTFOUND; // cannot mix reference and direct definition - } - else { - found = true; - result = templ->derive("", "", "", partType, divisor, values, fields); - } + bool firstType = true; + istringstream stream(typeStr); + while (result == RESULT_OK && getline(stream, token, VALUE_SEPARATOR) != 0) { + DataField* templ = templates->get(token); + unsigned char length; + if (templ == NULL) { + size_t pos = token.find(LENGTH_SEPARATOR); + if (pos == string::npos) + length = 0; // no length specified + else { + length = (unsigned char)parseInt(token.substr(pos+1).c_str(), 10, 1, MAX_POS, result); + if (result != RESULT_OK) + break; } - if (result != RESULT_OK) - break; - if (found) - continue; // go to next definition + string typeName = token.substr(0, pos); + SingleDataField* add = NULL; + result = SingleDataField::create(typeName.c_str(), length, firstType ? name : "", firstType ? comment : "", firstType ? unit : "", partType, divisor, values, add); + if (add != NULL) + fields.push_back(add); + else if (result == RESULT_OK) + result = RESULT_ERR_NOTFOUND; // type not found } - typeName = typeStr; + else + result = templ->derive(firstType ? name : "", firstType ? comment : "", firstType ? unit : "", partType, divisor, values, fields); + + firstType = false; } - else { - length = (unsigned char)parseInt(typeStr.substr(pos+1).c_str(), 10, 1, MAX_POS, result); - if (result != RESULT_OK) - break; - typeName = typeStr.substr(0, pos); - } - - SingleDataField* add = NULL; - const char* typeNameStr = typeName.c_str(); - for (size_t i = 0; result == RESULT_OK && add == NULL && i < sizeof(dataTypes) / sizeof(dataType_t); i++) { - const dataType_t* dataType = &dataTypes[i]; - if (strcasecmp(typeNameStr, dataType->name) == 0) { - unsigned char bitCount = dataType->bitCount; - unsigned char byteCount = (unsigned char)((bitCount + 7) / 8); - if ((dataType->flags & ADJ) != 0) { // adjustable length - if ((bitCount % 8) != 0) { - if (length == 0) - bitCount = 1; // default bit count: 1 bit - else if (length <= bitCount) - bitCount = length; - else { - result = RESULT_ERR_OUT_OF_RANGE; // invalid length - break; - } - - byteCount = (unsigned char)((bitCount + 7) / 8); - } - else if (length == 0) - byteCount = 1; //default byte count: 1 byte - else if (length <= byteCount) - byteCount = length; - else { - result = RESULT_ERR_OUT_OF_RANGE; // invalid length - break; - } - } - else if (length > 0 && length != byteCount) - continue; // check for another one with same name but different length - - switch (dataType->type) - { - case bt_str: - case bt_hexstr: - case bt_dat: - case bt_tim: - add = new StringDataField(name, comment, unit, *dataType, partType, byteCount); - break; - case bt_num: - if (values.empty() && (dataType->flags & DAY) != 0) { - for (unsigned int i = 0; i < sizeof(dayNames) / sizeof(dayNames[0]); i++) - values[dataType->minValueOrLength + i] = dayNames[i]; - } - if (values.empty() || (dataType->flags & LST) == 0) { - if (divisor == 0) - divisor = 1; - - if ((dataType->bitCount % 8) == 0) { - if (divisor < 0) { - if (dataType->divisorOrFirstBit > 1) { - result = RESULT_ERR_INVALID_ARG; - break; - } - if (dataType->divisorOrFirstBit < 0) - divisor *= -dataType->divisorOrFirstBit; - } else if (dataType->divisorOrFirstBit < 0) { - if (divisor > 1) { - result = RESULT_ERR_INVALID_ARG; - break; - } - if (divisor < 0) - divisor *= -dataType->divisorOrFirstBit; - } else - divisor *= dataType->divisorOrFirstBit; - - if (-MAX_DIVISOR > divisor || divisor > MAX_DIVISOR) { - result = RESULT_ERR_OUT_OF_RANGE; - break; - } - } - - add = new NumberDataField(name, comment, unit, *dataType, partType, byteCount, bitCount, divisor); - break; - } - if (values.begin()->first < dataType->minValueOrLength - || values.rbegin()->first > dataType->maxValueOrLength) { - result = RESULT_ERR_OUT_OF_RANGE; - break; - } - //TODO add special field for fixed values (exactly one value in the list of values) - add = new ValueListDataField(name, comment, unit, *dataType, partType, byteCount, bitCount, values); - break; - } - } - } - if (add != NULL) - fields.push_back(add); - else if (result == RESULT_OK) - result = RESULT_ERR_NOTFOUND; // type not found } while (it != end && result == RESULT_OK); @@ -430,6 +331,89 @@ void DataField::dumpString(ostream& output, const string str, const bool prepend } } +result_t SingleDataField::create(const char* typeNameStr, const unsigned char length, + const string name, const string comment, const string unit, + const PartType partType, int divisor, map values, + SingleDataField* &returnField) +{ + for (size_t i = 0; i < sizeof(dataTypes) / sizeof(dataType_t); i++) { + const dataType_t* dataType = &dataTypes[i]; + if (strcasecmp(typeNameStr, dataType->name) == 0) { + unsigned char bitCount = dataType->bitCount; + unsigned char byteCount = (unsigned char)((bitCount + 7) / 8); + if ((dataType->flags & ADJ) != 0) { // adjustable length + if ((bitCount % 8) != 0) { + if (length == 0) + bitCount = 1; // default bit count: 1 bit + else if (length <= bitCount) + bitCount = length; + else + return RESULT_ERR_OUT_OF_RANGE; // invalid length + + byteCount = (unsigned char)((bitCount + 7) / 8); + } + else if (length == 0) + byteCount = 1; //default byte count: 1 byte + else if (length <= byteCount) + byteCount = length; + else + return RESULT_ERR_OUT_OF_RANGE; // invalid length + } + else if (length > 0 && length != byteCount) + continue; // check for another one with same name but different length + + switch (dataType->type) + { + case bt_str: + case bt_hexstr: + case bt_dat: + case bt_tim: + returnField = new StringDataField(name, comment, unit, *dataType, partType, byteCount); + return RESULT_OK; + case bt_num: + if (values.empty() && (dataType->flags & DAY) != 0) { + for (unsigned int i = 0; i < sizeof(dayNames) / sizeof(dayNames[0]); i++) + values[dataType->minValueOrLength + i] = dayNames[i]; + } + if (values.empty() || (dataType->flags & LST) == 0) { + if (divisor == 0) + divisor = 1; + + if ((dataType->bitCount % 8) == 0) { + if (divisor < 0) { + if (dataType->divisorOrFirstBit > 1) + return RESULT_ERR_INVALID_ARG; + + if (dataType->divisorOrFirstBit < 0) + divisor *= -dataType->divisorOrFirstBit; + } else if (dataType->divisorOrFirstBit < 0) { + if (divisor > 1) + return RESULT_ERR_INVALID_ARG; + + if (divisor < 0) + divisor *= -dataType->divisorOrFirstBit; + } else + divisor *= dataType->divisorOrFirstBit; + + if (-MAX_DIVISOR > divisor || divisor > MAX_DIVISOR) + return RESULT_ERR_OUT_OF_RANGE; + } + + returnField = new NumberDataField(name, comment, unit, *dataType, partType, byteCount, bitCount, divisor); + return RESULT_OK; + } + if (values.begin()->first < dataType->minValueOrLength + || values.rbegin()->first > dataType->maxValueOrLength) + return RESULT_ERR_OUT_OF_RANGE; + + //TODO add special field for fixed values (exactly one value in the list of values) + returnField = new ValueListDataField(name, comment, unit, *dataType, partType, byteCount, bitCount, values); + return RESULT_OK; + } + } + } + return RESULT_ERR_NOTFOUND; +} void SingleDataField::dump(ostream& output) { diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index fbea75d8..452974de 100644 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -180,7 +180,7 @@ public: virtual unsigned char getLength(PartType partType) = 0; /** - * Derives a new DataField from this field. + * Derive a new @a DataField from this field. * @param name the field 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). @@ -287,6 +287,25 @@ public: */ virtual ~SingleDataField() {} + /** + * Factory method for creating a new @a SingleDataField instance derived from a base type. + * @param typeNameStr the base type name string. + * @param length the base type length, or 0 for default. + * @param name the field name. + * @param comment the field comment. + * @param unit the value unit. + * @param partType the message part in which the field is stored. + * @param divisor the extra divisor (negative for reciprocal) to apply on the value, or 1 for none (if applicable). + * @param values the value=text assignments. + * @param returnField the variable in which the created @a SingleDataField instance shall be stored. + * @return @a RESULT_OK on success, or an error code. + * Note: the caller needs to free the created instance. + */ + static result_t create(const char* typeNameStr, const unsigned char length, + const string name, const string comment, const string unit, + const PartType partType, int divisor, map values, + SingleDataField* &returnField); + /** * Get the value unit. * @return the value unit. diff --git a/src/lib/ebus/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp index 3351eefb..fe953d11 100644 --- a/src/lib/ebus/test/test_data.cpp +++ b/src/lib/ebus/test/test_data.cpp @@ -227,6 +227,7 @@ int main() {"trelrel,temp;temp","","", "", "t"}, // template struct with relative pos and ref to templates {"x,,trelrel","18.004;19.008","10fe07000401120213", "00", ""}, // reference to template struct {"x,,temp,,,,y,,d1c","18.004;9.5","10fe070003011213", "00", ""}, // reference to template, normal def + {"x,,temp;HEX:2","18.004;13 14","10fe07000401121314", "00", ""}, // reference to template and base type }; DataFieldTemplates* templates = new DataFieldTemplates(); DataField* fields = NULL;