allow mixing references to base type and templates in message definition

This commit is contained in:
john30
2015-03-13 22:12:11 +01:00
parent d226818b7e
commit 0f93369bee
3 changed files with 128 additions and 124 deletions
+97 -113
View File
@@ -274,132 +274,33 @@ result_t DataField::create(vector<string>::iterator& it,
comment = str; comment = str;
} }
string typeName; bool firstType = true;
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); istringstream stream(typeStr);
bool found = false;
while (result == RESULT_OK && getline(stream, token, VALUE_SEPARATOR) != 0) { while (result == RESULT_OK && getline(stream, token, VALUE_SEPARATOR) != 0) {
DataField* templ = templates->get(token); DataField* templ = templates->get(token);
unsigned char length;
if (templ == NULL) { if (templ == NULL) {
if (!found) size_t pos = token.find(LENGTH_SEPARATOR);
break; // fallback to direct definition if (pos == string::npos)
result = RESULT_ERR_NOTFOUND; // cannot mix reference and direct definition length = 0; // no length specified
}
else { else {
found = true; length = (unsigned char)parseInt(token.substr(pos+1).c_str(), 10, 1, MAX_POS, result);
result = templ->derive("", "", "", partType, divisor, values, fields);
}
}
if (result != RESULT_OK) if (result != RESULT_OK)
break; break;
if (found)
continue; // go to next definition
} }
typeName = typeStr; string typeName = token.substr(0, pos);
}
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; SingleDataField* add = NULL;
const char* typeNameStr = typeName.c_str(); result = SingleDataField::create(typeName.c_str(), length, firstType ? name : "", firstType ? comment : "", firstType ? unit : "", partType, divisor, values, add);
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) if (add != NULL)
fields.push_back(add); fields.push_back(add);
else if (result == RESULT_OK) else if (result == RESULT_OK)
result = RESULT_ERR_NOTFOUND; // type not found result = RESULT_ERR_NOTFOUND; // type not found
}
else
result = templ->derive(firstType ? name : "", firstType ? comment : "", firstType ? unit : "", partType, divisor, values, fields);
firstType = false;
}
} while (it != end && result == RESULT_OK); } 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<unsigned int, string> 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) void SingleDataField::dump(ostream& output)
{ {
+20 -1
View File
@@ -180,7 +180,7 @@ public:
virtual unsigned char getLength(PartType partType) = 0; 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 name the field name.
* @param comment the field comment, or empty to use this fields comment. * @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 unit the value unit, or empty to use this fields unit (if applicable).
@@ -287,6 +287,25 @@ public:
*/ */
virtual ~SingleDataField() {} 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<unsigned int, string> values,
SingleDataField* &returnField);
/** /**
* Get the value unit. * Get the value unit.
* @return the value unit. * @return the value unit.
+1
View File
@@ -227,6 +227,7 @@ int main()
{"trelrel,temp;temp","","", "", "t"}, // template struct with relative pos and ref to templates {"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,,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,,,,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(); DataFieldTemplates* templates = new DataFieldTemplates();
DataField* fields = NULL; DataField* fields = NULL;