added support for reciprocal divisor, corrected divisor for derived number types (was combined with base datatype divisor instead of actual field divisor)

This commit is contained in:
john30
2015-03-07 11:48:08 +01:00
parent f4f2bbe2a6
commit ed3ef3f5e4
3 changed files with 159 additions and 70 deletions
+89 -30
View File
@@ -101,7 +101,7 @@ unsigned int parseInt(const char* str, int base, const unsigned int minValue, co
return 0;
}
if (ret < minValue || ret > maxValue) {
if (minValue > ret || ret > maxValue) {
result = RESULT_ERR_OUT_OF_RANGE; // invalid value
return 0;
}
@@ -112,6 +112,27 @@ unsigned int parseInt(const char* str, int base, const unsigned int minValue, co
return (unsigned int)ret;
}
int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result, unsigned int* length) {
char* strEnd = NULL;
long int ret = strtol(str, &strEnd, base);
if (strEnd == NULL || *strEnd != 0) {
result = RESULT_ERR_INVALID_NUM; // invalid value
return 0;
}
if (minValue > ret || ret > maxValue) {
result = RESULT_ERR_OUT_OF_RANGE; // invalid value
return 0;
}
if (length != NULL)
*length = (unsigned int)(strEnd - str);
result = RESULT_OK;
return (int)ret;
}
void printErrorPos(vector<string>::iterator begin, const vector<string>::iterator end, vector<string>::iterator pos, string filename, size_t lineNo, result_t result)
{
if (pos > begin)
@@ -157,7 +178,7 @@ result_t DataField::create(vector<string>::iterator& it,
do {
string unit, comment;
PartType partType;
unsigned int divisor = 0;
int divisor = 0;
const bool isTemplate = dstAddress == SYN;
bool hasPartStr = false;
string token;
@@ -210,7 +231,7 @@ result_t DataField::create(vector<string>::iterator& it,
const string divisorStr = *it++;
if (!divisorStr.empty()) {
if (divisorStr.find('=') == string::npos)
divisor = parseInt(divisorStr.c_str(), 10, 1, MAX_DIVISOR, result);
divisor = parseSignedInt(divisorStr.c_str(), 10, -MAX_DIVISOR, MAX_DIVISOR, result);
else {
istringstream stream(divisorStr);
while (getline(stream, token, VALUE_SEPARATOR) != 0) {
@@ -337,9 +358,26 @@ result_t DataField::create(vector<string>::iterator& it,
if (values.empty() || (dataType->flags & LST) == 0) {
if (divisor == 0)
divisor = 1;
if ((dataType->bitCount % 8) == 0) {
divisor *= dataType->divisorOrFirstBit;
if (divisor > MAX_DIVISOR) {
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;
}
@@ -475,7 +513,7 @@ result_t SingleDataField::write(istringstream& input,
result_t StringDataField::derive(string name, string comment,
string unit, const PartType partType,
unsigned int divisor, map<unsigned int, string> values,
int divisor, map<unsigned int, string> values,
vector<SingleDataField*>& fields)
{
if (m_partType != pt_any && partType == pt_any)
@@ -852,19 +890,20 @@ result_t NumericDataField::writeRawValue(unsigned int value,
NumberDataField::NumberDataField(const string name, const string comment,
const string unit, const dataType_t dataType, const PartType partType,
const unsigned char length, const unsigned char bitCount,
const unsigned int divisor)
const int divisor)
: NumericDataField(name, comment, unit, dataType, partType, length, bitCount,
(dataType.bitCount % 8) == 0 ? 0 : (unsigned char)dataType.divisorOrFirstBit),
m_divisor(divisor), m_precision(0)
{
for (unsigned int exp = 1; exp < MAX_DIVISOR; exp *= 10, m_precision++)
if (exp >= divisor)
break;
if (divisor > 1)
for (unsigned int exp = 1; exp < MAX_DIVISOR; exp *= 10, m_precision++)
if (exp >= (unsigned int)divisor)
break;
}
result_t NumberDataField::derive(string name, string comment,
string unit, const PartType partType,
unsigned int divisor, map<unsigned int, string> values,
int divisor, map<unsigned int, string> values,
vector<SingleDataField*>& fields)
{
if (m_partType != pt_any && partType == pt_any)
@@ -875,23 +914,37 @@ result_t NumberDataField::derive(string name, string comment,
comment = m_comment;
if (unit.empty())
unit = m_unit;
if (divisor == 0)
divisor = m_divisor;
else if ((m_dataType.bitCount % 8) == 0) {
divisor *= m_dataType.divisorOrFirstBit;
if (divisor > MAX_DIVISOR) {
return RESULT_ERR_OUT_OF_RANGE;
}
}
if (!values.empty()) {
if (divisor != 1)
if (divisor != 0 || m_divisor != 1)
return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field
fields.push_back(new ValueListDataField(name, comment, unit, m_dataType, partType, m_length, m_bitCount, values));
}
else
fields.push_back(new NumberDataField(name, comment, unit, m_dataType, partType, m_length, m_bitCount, divisor));
else {
if (divisor == 0)
divisor = m_divisor;
else if ((m_dataType.bitCount % 8) == 0) {
if (divisor < 0) {
if (m_divisor > 1)
return RESULT_ERR_INVALID_ARG;
if (m_divisor < 0)
divisor *= -m_divisor;
} else if (m_divisor < 0) {
if (divisor > 1)
return RESULT_ERR_INVALID_ARG;
if (divisor < 0)
divisor *= -m_divisor;
} else
divisor *= m_divisor;
if (-MAX_DIVISOR > divisor || divisor > MAX_DIVISOR) {
return RESULT_ERR_OUT_OF_RANGE;
}
}
fields.push_back(new NumberDataField(name, comment, unit, m_dataType, partType, m_length, m_bitCount, divisor));
}
return RESULT_OK;
}
@@ -924,7 +977,9 @@ result_t NumberDataField::readSymbols(SymbolString& input,
bool negative = (m_dataType.flags & SIG) != 0 && (value & (1 << (m_bitCount - 1))) != 0;
if (m_bitCount == 32) {
if (!negative) {
if (m_divisor <= 1)
if (m_divisor < 0)
output << static_cast<float>((float)value * (float)(-m_divisor));
else if (m_divisor <= 1)
output << static_cast<unsigned>(value);
else
output << setprecision(m_precision)
@@ -938,7 +993,9 @@ result_t NumberDataField::readSymbols(SymbolString& input,
else
signedValue = (int) value;
if (m_divisor <= 1) {
if (m_divisor < 0)
output << static_cast<float>((float)signedValue * (float)(-m_divisor));
else if (m_divisor <= 1) {
if ((m_dataType.flags & (FIX|BCD)) == (FIX|BCD))
output << setw(m_length * 2) << setfill('0');
output << static_cast<int>(signedValue) << setw(0);
@@ -962,7 +1019,7 @@ result_t NumberDataField::writeSymbols(istringstream& input,
return RESULT_ERR_EOF; // input too short
else {
char* strEnd = NULL;
if (m_divisor <= 1) {
if (m_divisor >= 0 && m_divisor <= 1) {
if ((m_dataType.flags & SIG) != 0) {
long int signedValue = strtol(str, &strEnd, 10);
if (signedValue < 0 && m_bitCount != 32)
@@ -974,13 +1031,15 @@ result_t NumberDataField::writeSymbols(istringstream& input,
value = (unsigned int)strtoul(str, &strEnd, 10);
if (strEnd == NULL || *strEnd != 0)
return RESULT_ERR_INVALID_NUM; // invalid value
}
else {
} else {
char* strEnd = NULL;
double dvalue = strtod(str, &strEnd);
if (strEnd == NULL || *strEnd != 0)
return RESULT_ERR_INVALID_NUM; // invalid value
dvalue = round(dvalue * m_divisor);
if (m_divisor < 0)
dvalue = round(dvalue / -m_divisor);
else
dvalue = round(dvalue * m_divisor);
if ((m_dataType.flags & SIG) != 0) {
if (dvalue < -(1LL << (8 * m_length)) || dvalue >= (1LL << (8 * m_length)))
return RESULT_ERR_OUT_OF_RANGE; // value out of range
@@ -1014,7 +1073,7 @@ result_t NumberDataField::writeSymbols(istringstream& input,
result_t ValueListDataField::derive(string name, string comment,
string unit, const PartType partType,
unsigned int divisor, map<unsigned int, string> values,
int divisor, map<unsigned int, string> values,
vector<SingleDataField*>& fields)
{
if (m_partType != pt_any && partType == pt_any)
@@ -1166,7 +1225,7 @@ unsigned char DataFieldSet::getLength(PartType partType)
result_t DataFieldSet::derive(string name, string comment,
string unit, const PartType partType,
unsigned int divisor, map<unsigned int, string> values,
int divisor, map<unsigned int, string> values,
vector<SingleDataField*>& fields)
{
if (!values.empty())
+30 -18
View File
@@ -75,14 +75,14 @@ static const unsigned int REQ = 0x100;//!< value may not be NULL
/** The structure for defining field types with their properties. */
typedef struct {
const char* name; //!< field identifier
const unsigned char bitCount; //!< number of bits (maximum length if @a ADJ flag is set, must be multiple of 8 with flag @a BCD)
const BaseType type; //!< base data type
const unsigned short flags; //!< flags (e.g. @a BCD)
const unsigned int replacement; //!< replacement value (fill-up value for @a bt_str / @a bt_hexstr, no replacement if equal to @a minValueOrLength for @a bt_num)
const unsigned int minValueOrLength; //!< minimum binary value (minimum length of string for @a StringDataField)
const unsigned int maxValueOrLength; //!< maximum binary value (maximum length of string for @a StringDataField)
const unsigned short divisorOrFirstBit; //!< @a bt_number: divisor or offset to first bit (if (@a bitCount%8)!=0)
const char* name; //!< field identifier
const unsigned char bitCount; //!< number of bits (maximum length if @a ADJ flag is set, must be multiple of 8 with flag @a BCD)
const BaseType type; //!< base data type
const unsigned short flags; //!< flags (e.g. @a BCD)
const unsigned int replacement; //!< replacement value (fill-up value for @a bt_str / @a bt_hexstr, no replacement if equal to @a minValueOrLength for @a bt_num)
const unsigned int minValueOrLength; //!< minimum binary value (minimum length of string for @a StringDataField)
const unsigned int maxValueOrLength; //!< maximum binary value (maximum length of string for @a StringDataField)
const short divisorOrFirstBit; //!< @a bt_number: divisor (negative for reciprocal) or offset to first bit (if (@a bitCount%8)!=0)
} dataType_t;
/** the maximum position within master or slave data. */
@@ -100,6 +100,18 @@ typedef struct {
*/
unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, result_t& result, unsigned int* length=NULL);
/**
* Parse a signed int value.
* @param str the string to parse.
* @param base the numerical base.
* @param minValue the minimum resulting value.
* @param maxValue the maximum resulting value.
* @param result the variable in which to store an error code when parsing failed or the value is out of bounds.
* @param length the optional variable in which to store the number of read characters.
* @return the parsed value.
*/
int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result, unsigned int* length=NULL);
/**
* Print the error position of the iterator to stdout.
* @param begin the iterator to the beginning of the items.
@@ -171,14 +183,14 @@ public:
* @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.
* @param divisor the extra divisor to apply on the value, or 1 for none (if applicable).
* @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, or empty to use this fields assignments (if applicable).
* @param fields the @a vector to which created @a SingleDataField instances shall be added.
* @return @a RESULT_OK on success, or an error code.
*/
virtual result_t derive(string name, string comment,
string unit, const PartType partType,
unsigned int divisor, map<unsigned int, string> values,
int divisor, map<unsigned int, string> values,
vector<SingleDataField*>& fields) = 0;
/**
@@ -383,7 +395,7 @@ public:
// @copydoc
virtual result_t derive(string name, string comment,
string unit, const PartType partType,
unsigned int divisor, map<unsigned int, string> values,
int divisor, map<unsigned int, string> values,
vector<SingleDataField*>& fields);
// @copydoc
@@ -480,12 +492,12 @@ public:
* @param partType the message part in which the field is stored.
* @param length the number of symbols in the message part in which the field is stored.
* @param bitCount the number of bits in the binary value (may be less than @a length * 8).
* @param divisor the extra divisor to apply on the value, or 1 for none.
* @param divisor the extra divisor (negative for reciprocal) to apply on the value, or 1 for none.
*/
NumberDataField(const string name, const string comment,
const string unit, const dataType_t dataType, const PartType partType,
const unsigned char length, const unsigned char bitCount,
const unsigned int divisor);
const int divisor);
/**
* Destructor.
@@ -495,7 +507,7 @@ public:
// @copydoc
virtual result_t derive(string name, string comment,
string unit, const PartType partType,
unsigned int divisor, map<unsigned int, string> values,
int divisor, map<unsigned int, string> values,
vector<SingleDataField*>& fields);
// @copydoc
@@ -511,8 +523,8 @@ protected:
private:
/** the combined divisor to apply on the value, or 1 for none. */
const unsigned int m_divisor;
/** the combined divisor (negative for reciprocal) to apply on the value, or 1 for none. */
const int m_divisor;
/** the precision for formatting the value. */
unsigned char m_precision;
@@ -553,7 +565,7 @@ public:
// @copydoc
virtual result_t derive(string name, string comment,
string unit, const PartType partType, unsigned int divisor,
string unit, const PartType partType, int divisor,
map<unsigned int, string> values,
vector<SingleDataField*>& fields);
@@ -611,7 +623,7 @@ public:
// @copydoc
virtual result_t derive(string name, string comment,
string unit, const PartType partType,
unsigned int divisor, map<unsigned int, string> values,
int divisor, map<unsigned int, string> values,
vector<SingleDataField*>& fields);
/**
+40 -22
View File
@@ -119,40 +119,52 @@ int main()
{"x,,bcd:4","", "10feffff0100009a00", "00", "rw"},
{"x,,str:16", "0123456789ABCDEF", "10feffff1130313233343536373839414243444546", "00", ""},
{"x,,uch:17", "", "10feffff00", "00", "c"},
{"x,s,uch", "0", "1025ffff0310111213", "0300010203", "W"},
{"x,s,uch", "0", "1025ffff00", "0100", ""},
{"x,s,uch", "0", "1025ffff0310111213", "0300010203", "W"},
{"x,s,uch", "0", "1025ffff00", "0100", ""},
{"x,s,uch,,,,y,m,uch", "3;2","1025ffff0103", "0102", ""},
{"x,,uch", "38", "10feffff0126", "00", ""},
{"x,,uch", "0", "10feffff0100", "00", ""},
{"x,,uch", "254", "10feffff01fe", "00", ""},
{"x,,uch", "-", "10feffff01ff", "00", ""},
{"x,,sch", "-90", "10feffff01a6", "00", ""},
{"x,,sch", "0", "10feffff0100", "00", ""},
{"x,,sch", "-1", "10feffff01ff", "00", ""},
{"x,,sch", "-", "10feffff0180", "00", ""},
{"x,,sch", "-127", "10feffff0181", "00", ""},
{"x,,sch", "127", "10feffff017f", "00", ""},
{"x,,d1b", "-90", "10feffff01a6", "00", ""},
{"x,,d1b", "0", "10feffff0100", "00", ""},
{"x,,d1b", "-1", "10feffff01ff", "00", ""},
{"x,,d1b", "-", "10feffff0180", "00", ""},
{"x,,d1b", "-127", "10feffff0181", "00", ""},
{"x,,d1b", "127", "10feffff017f", "00", ""},
{"x,,d1c", "19.5", "10feffff0127", "00", ""},
{"x,,d1c", "0.0", "10feffff0100", "00", ""},
{"x,,d1c", "100.0", "10feffff01c8", "00", ""},
{"x,,d1c", "-", "10feffff01ff", "00", ""},
{"x,,uch", "38", "10feffff0126", "00", ""},
{"x,,uch", "0", "10feffff0100", "00", ""},
{"x,,uch", "254", "10feffff01fe", "00", ""},
{"x,,uch", "-", "10feffff01ff", "00", ""},
{"x,,uch,10", "3.8", "10feffff0126", "00", ""},
{"x,,uch,-10", "380","10feffff0126", "00", ""},
{"x,,sch", "-90", "10feffff01a6", "00", ""},
{"x,,sch", "0", "10feffff0100", "00", ""},
{"x,,sch", "-1", "10feffff01ff", "00", ""},
{"x,,sch", "-", "10feffff0180", "00", ""},
{"x,,sch", "-127", "10feffff0181", "00", ""},
{"x,,sch", "127", "10feffff017f", "00", ""},
{"x,,sch,10", "-9.0","10feffff01a6", "00", ""},
{"x,,sch,-10","-900","10feffff01a6", "00", ""},
{"x,,d1b", "-90", "10feffff01a6", "00", ""},
{"x,,d1b", "0", "10feffff0100", "00", ""},
{"x,,d1b", "-1", "10feffff01ff", "00", ""},
{"x,,d1b", "-", "10feffff0180", "00", ""},
{"x,,d1b", "-127", "10feffff0181", "00", ""},
{"x,,d1b", "127", "10feffff017f", "00", ""},
{"x,,d1b,-10","-900","10feffff01a6", "00", ""},
{"x,,d1c", "19.5", "10feffff0127", "00", ""},
{"x,,d1c", "0.0", "10feffff0100", "00", ""},
{"x,,d1c", "100.0", "10feffff01c8", "00", ""},
{"x,,d1c", "-", "10feffff01ff", "00", ""},
{"x,,uin", "38", "10feffff022600", "00", ""},
{"x,,uin", "0", "10feffff020000", "00", ""},
{"x,,uin", "65534", "10feffff02feff", "00", ""},
{"x,,uin", "-", "10feffff02ffff", "00", ""},
{"x,,uin,10", "3.8", "10feffff022600", "00", ""},
{"x,,uin,-10","380", "10feffff022600", "00", ""},
{"uin10,uin,-10","", "", "", "t"}, // template
{"x,,uin10","380", "10feffff022600", "00", ""}, // template reference
{"x,,uin10,-10","3800","10feffff022600", "00", ""}, // template reference, valid divider product
{"x,,uin10,10","","", "", "c"}, // template reference, invalid divider product
{"x,,sin", "-90", "10feffff02a6ff", "00", ""},
{"x,,sin", "0", "10feffff020000", "00", ""},
{"x,,sin", "-1", "10feffff02ffff", "00", ""},
{"x,,sin", "-", "10feffff020080", "00", ""},
{"x,,sin", "-32767", "10feffff020180", "00", ""},
{"x,,sin", "32767", "10feffff02ff7f", "00", ""},
{"x,,sin,10","-9.0", "10feffff02a6ff", "00", ""},
{"x,,sin,-10","-900","10feffff02a6ff", "00", ""},
{"x,,flt", "-0.090", "10feffff02a6ff", "00", ""},
{"x,,flt", "0.000", "10feffff020000", "00", ""},
{"x,,flt", "-0.001", "10feffff02ffff", "00", ""},
@@ -175,9 +187,13 @@ int main()
{"x,,ulg", "0", "10feffff0400000000", "00", ""},
{"x,,ulg", "4294967294", "10feffff04feffffff", "00", ""},
{"x,,ulg", "-", "10feffff04ffffffff", "00", ""},
{"x,,ulg,10","3.8", "10feffff0426000000", "00", ""},
{"x,,ulg,-10","380", "10feffff0426000000", "00", ""},
{"x,,slg", "-90", "10feffff04a6ffffff", "00", ""},
{"x,,slg", "0", "10feffff0400000000", "00", ""},
{"x,,slg", "-1", "10feffff04ffffffff", "00", ""},
{"x,,slg,10", "-9.0", "10feffff04a6ffffff", "00", ""},
{"x,,slg,-10", "-900", "10feffff04a6ffffff", "00", ""},
{"x,,bi3", "1", "10feffff0108", "00", ""},
{"x,,bi3", "0", "10feffff0100", "00", ""},
{"x,,bi3,0=off;1=on","on", "10feffff0108", "00", ""},
@@ -203,6 +219,8 @@ int main()
{"x,,bi6:2,,,,y,,bi0:2,,,,t,,uch", "2;1;9","10feffff03800109", "00", ""}, // bit combination
{"temp,d2b,,°C,Aussentemperatur","","", "", "t"}, // template with relative pos
{"x,,temp","18.004","10fe0700020112", "00", ""}, // reference to template
{"x,,temp,10","1.8004","10fe0700020112", "00", ""}, // reference to template, valid divider product
{"x,,temp,-10","","", "", "c"}, // reference to template, invalid divider product
{"relrel,d2b,,,,y,d1c","","", "", "t"}, // template struct with relative pos
{"x,,relrel","18.004;9.5","10fe070003011213", "00", ""}, // reference to template struct
{"trelrel,temp;temp","","", "", "t"}, // template struct with relative pos and ref to templates