reworked result codes, added new base type VTI (vaillant specific time), added support for replacement value for time types

This commit is contained in:
john30
2014-12-06 12:46:15 +01:00
parent 9cea334407
commit 15249302fb
6 changed files with 142 additions and 104 deletions
+90 -64
View File
@@ -39,6 +39,7 @@ static const dataType_t dataTypes[] = {
{"HDA", 24, bt_dat, 0, 0, 10, 10, 0, 0}, // date, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99) // TODO remove duplicate of BDA
{"BTI", 24, bt_tim, BCD|REV, 0, 8, 8, 0, 0}, // time in BCD, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x59,0x59,0x23)
{"HTI", 24, bt_tim, 0, 0, 8, 8, 0, 0}, // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x17,0x3b,0x3b)
{"VTI", 24, bt_tim, REV, 0x63, 8, 8, 0, 0}, // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x3b,0x3b,0x17, replacement 0x63) [Vaillant type]
{"HTM", 16, bt_tim, 0, 0, 5, 5, 0, 0}, // time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x17,0x3b)
{"TTM", 8, bt_tim, 0, 0x90, 5, 5, 0, 0}, // truncated time (only multiple of 10 minutes), 00:00 - 24:00 (minutes div 10 + hour * 6 as integer)
{"BDY", 8, bt_num, DAY|LST, 0x07, 0, 6, 1, 0}, // weekday, "Mon" - "Sun" (0x00 - 0x06) [ebus type]
@@ -80,12 +81,12 @@ unsigned int parseInt(const char* str, int base, const unsigned int minValue, co
unsigned int ret = strtoul(str, &strEnd, base);
if (strEnd == NULL || *strEnd != 0) {
result = RESULT_ERR_INVALID_ARG; // invalid value
result = RESULT_ERR_INVALID_NUM; // invalid value
return 0;
}
if (ret < minValue || ret > maxValue) {
result = RESULT_ERR_INVALID_ARG; // invalid value
result = RESULT_ERR_OUT_OF_RANGE; // invalid value
return 0;
}
if (length != NULL)
@@ -130,7 +131,10 @@ result_t DataField::create(vector<string>::iterator& it,
vector<SingleDataField*> fields;
string firstName, firstComment;
result_t result = RESULT_OK;
while (it != end && result == RESULT_OK) {
if (it == end)
return RESULT_ERR_EOF;
do {
string unit, comment;
PartType partType;
unsigned int divisor = 0;
@@ -163,14 +167,14 @@ result_t DataField::create(vector<string>::iterator& it,
partType = pt_any;
}
else {
result = RESULT_ERR_INVALID_ARG;
result = RESULT_ERR_INVALID_PART;
break;
}
string typeStr = *it++;
if (typeStr.empty() == true) {
if (name.empty() == false || partStr[0] != 0)
result = RESULT_ERR_INVALID_ARG;
result = RESULT_ERR_MISSING_TYPE;
break;
}
@@ -178,11 +182,8 @@ result_t DataField::create(vector<string>::iterator& it,
if (it != end) {
string divisorStr = *it++;
if (divisorStr.empty() == false) {
if (divisorStr.find('=') == string::npos) {
if (divisorStr.find('=') == string::npos)
divisor = parseInt(divisorStr.c_str(), 10, 1, 10000, result);
if (result != RESULT_OK)
break;
}
else {
istringstream stream(divisorStr);
while (getline(stream, token, VALUE_SEPARATOR) != 0) {
@@ -190,15 +191,15 @@ result_t DataField::create(vector<string>::iterator& it,
char* strEnd = NULL;
unsigned int id = strtoul(str, &strEnd, 10);
if (strEnd == NULL || strEnd == str || *strEnd != '=') {
result = RESULT_ERR_INVALID_ARG;
result = RESULT_ERR_INVALID_LIST;
break;
}
values[id] = string(strEnd + 1);
}
if (result != RESULT_OK)
break;
}
if (result != RESULT_OK)
break;
}
}
@@ -227,18 +228,17 @@ result_t DataField::create(vector<string>::iterator& it,
istringstream stream(typeStr);
bool found = false;
string lengthStr;
while (getline(stream, token, VALUE_SEPARATOR) != 0) {
while (result == RESULT_OK && getline(stream, token, VALUE_SEPARATOR) != 0) {
DataField* templ = templates->get(token);
if (templ == NULL) {
if (found == false)
break; // fallback to direct definition
result = RESULT_ERR_INVALID_ARG; // cannot mix reference and direct definition
break;
result = RESULT_ERR_NOTFOUND; // cannot mix reference and direct definition
}
else {
found = true;
result = templ->derive("", "", "", partType, divisor, values, fields);
}
found = true;
result = templ->derive("", "", "", partType, divisor, values, fields);
if (result != RESULT_OK)
break;
}
if (result != RESULT_OK)
break;
@@ -267,7 +267,7 @@ result_t DataField::create(vector<string>::iterator& it,
bitCount = 1; // default count: 1 bit
}
else if (length > bitCount) {
result = RESULT_ERR_INVALID_ARG; // invalid length
result = RESULT_ERR_OUT_OF_RANGE; // invalid length
break;
}
else {
@@ -282,7 +282,7 @@ result_t DataField::create(vector<string>::iterator& it,
useLength = length;
}
else {
result = RESULT_ERR_INVALID_ARG; // invalid length
result = RESULT_ERR_OUT_OF_RANGE; // invalid length
break;
}
}
@@ -314,7 +314,7 @@ result_t DataField::create(vector<string>::iterator& it,
}
if (values.begin()->first < dataType.minValueOrLength
|| values.rbegin()->first > dataType.maxValueOrLength) {
result = RESULT_ERR_INVALID_ARG;
result = RESULT_ERR_OUT_OF_RANGE;
break;
}
@@ -326,14 +326,16 @@ result_t DataField::create(vector<string>::iterator& it,
if (add != NULL)
fields.push_back(add);
else if (result == RESULT_OK)
result = RESULT_ERR_INVALID_ARG; // type not found
}
result = RESULT_ERR_NOTFOUND; // type not found
} while (it != end && result == RESULT_OK);
if (fields.empty() == true || result != RESULT_OK) {
while (fields.empty() == false) {
while (fields.empty() == false) { // cleanup already created fields
delete fields.back();
fields.pop_back();
}
return result == RESULT_OK ? RESULT_ERR_INVALID_ARG :result;
return result == RESULT_OK ? RESULT_ERR_INVALID_ARG : result;
}
if (fields.size() == 1)
@@ -371,11 +373,11 @@ result_t SingleDataField::read(SymbolString& masterData, unsigned char masterOff
offset = 1 + slaveOffset; // skip NN
break;
default:
return RESULT_ERR_INVALID_ARG; // invalid part type
return RESULT_ERR_INVALID_PART;
}
if (isIgnored() == true) {
if (offset + m_length > input.size()) {
return RESULT_ERR_INVALID_ARG;
return RESULT_ERR_INVALID_POS;
}
return RESULT_OK;
}
@@ -411,7 +413,7 @@ result_t SingleDataField::write(istringstream& input,
offset = 1 + slaveOffset; // skip NN
break;
default:
return RESULT_ERR_INVALID_ARG;
return RESULT_ERR_INVALID_PART;
}
return writeSymbols(input, offset, output);
}
@@ -423,7 +425,7 @@ result_t StringDataField::derive(string name, string comment,
vector<SingleDataField*>& fields)
{
if (m_partType != pt_any && partType == pt_any)
return RESULT_ERR_INVALID_ARG; // cannot create a template from a concrete instance
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
if (divisor != 0 || values.empty() == false)
return RESULT_ERR_INVALID_ARG; // cannot set divisor or values for string field
if (name.empty() == true)
@@ -455,7 +457,7 @@ result_t StringDataField::readSymbols(SymbolString& input,
unsigned char ch, last = 0;
if (baseOffset + m_length > input.size()) {
return RESULT_ERR_INVALID_ARG;
return RESULT_ERR_INVALID_POS;
}
if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first)
@@ -469,7 +471,7 @@ result_t StringDataField::readSymbols(SymbolString& input,
ch = input[baseOffset + offset];
if ((m_dataType.flags & BCD) != 0 || m_dataType.type == bt_dat) {
if ((ch & 0xf0) > 0x90 || (ch & 0x0f) > 0x09)
return RESULT_ERR_INVALID_ARG; // invalid BCD
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
ch = (ch >> 4) * 10 + (ch & 0x0f);
}
switch (m_dataType.type)
@@ -484,11 +486,21 @@ result_t StringDataField::readSymbols(SymbolString& input,
if (i + 1 == m_length)
output << (2000 + ch);
else if (ch < 1 || (i == 0 && ch > 31) || (i == 1 && ch > 12))
return RESULT_ERR_INVALID_ARG; // invalid date
return RESULT_ERR_OUT_OF_RANGE; // invalid date
else
output << setw(2) << setfill('0') << static_cast<unsigned>(ch) << ".";
break;
case bt_tim:
if (m_dataType.replacement != 0 && ch == m_dataType.replacement) {
if (m_length == 1) { // truncated time
output << NULL_VALUE << ":" << NULL_VALUE;
break;
}
if (i > 0)
output << ":";
output << NULL_VALUE;
break;
}
if (m_length == 1) { // truncated time
if (i == 0) {
ch /= 6; // hours
@@ -498,8 +510,8 @@ result_t StringDataField::readSymbols(SymbolString& input,
else
ch = (ch % 6) * 10; // minutes
}
if ((i == 0 && ch > 24) || (i > 0 && (ch > 59 || ( last == 24 && ch > 0) )))
return RESULT_ERR_INVALID_ARG; // invalid time
if ((i == 0 && ch > 24) || (i > 0 && (ch > 59 || (last == 24 && ch > 0) )))
return RESULT_ERR_OUT_OF_RANGE; // invalid time
if (i > 0)
output << ":";
output << setw(2) << setfill('0') << static_cast<unsigned>(ch);
@@ -549,10 +561,10 @@ result_t StringDataField::writeSymbols(istringstream& input,
token.clear();
token.push_back(input.get());
if (input.eof() == true)
return RESULT_ERR_INVALID_ARG; // too short hex value
return RESULT_ERR_INVALID_NUM; // too short hex value
token.push_back(input.get());
if (input.eof() == true)
return RESULT_ERR_INVALID_ARG; // too short hex value
return RESULT_ERR_INVALID_NUM; // too short hex value
value = parseInt(token.c_str(), 16, 0, 0xff, result);
if (result != RESULT_OK)
@@ -563,7 +575,7 @@ result_t StringDataField::writeSymbols(istringstream& input,
if (m_length == 4 && i == 2)
continue; // skip weekday in between
if (input.eof() == true || getline(input, token, '.') == 0)
return RESULT_ERR_INVALID_ARG; // incomplete
return RESULT_ERR_EOF; // incomplete
value = parseInt(token.c_str(), 10, 0, 2099, result);
if (result != RESULT_OK)
return result; // invalid date part
@@ -578,7 +590,7 @@ result_t StringDataField::writeSymbols(istringstream& input,
t.tm_year = (value < 100 ? value + 2000 : value) - 1900;
t.tm_isdst = 0; // automatic
if (mktime(&t) < 0)
return RESULT_ERR_INVALID_ARG; // invalid date
return RESULT_ERR_INVALID_NUM; // invalid date
unsigned char daysSinceSunday = (unsigned char)t.tm_wday; // Sun=0
if ((m_dataType.flags & BCD) != 0)
output[baseOffset + offset - incr] = (6+daysSinceSunday) % 7; // Sun=0x06
@@ -588,18 +600,32 @@ result_t StringDataField::writeSymbols(istringstream& input,
if (value >= 2000)
value -= 2000;
else if (value > 99)
return RESULT_ERR_INVALID_ARG; // invalid year
return RESULT_ERR_OUT_OF_RANGE; // invalid year
} else if (value < 1 || (i == 0 && value > 31) || (i == 1 && value > 12))
return RESULT_ERR_INVALID_ARG; // invalid date part
return RESULT_ERR_OUT_OF_RANGE; // invalid date part
break;
case bt_tim:
if (input.eof() == true || getline(input, token, LENGTH_SEPARATOR) == 0)
return RESULT_ERR_INVALID_ARG; // incomplete
return RESULT_ERR_EOF; // incomplete
if (m_dataType.replacement != 0 && strcmp(token.c_str(), NULL_VALUE) == 0) {
value = m_dataType.replacement;
if (m_length == 1) { // truncated time
if (i == 0) {
last = value;
offset -= incr; // repeat for minutes
count++;
continue;
}
if (last != m_dataType.replacement)
return RESULT_ERR_INVALID_NUM; // invalid truncated time minutes
}
break;
}
value = parseInt(token.c_str(), 10, 0, 59, result);
if (result != RESULT_OK)
return result; // invalid time part
if ((i == 0 && value > 24) || (i > 0 && (last == 24 && value > 0) ))
return RESULT_ERR_INVALID_ARG; // invalid time part
return RESULT_ERR_OUT_OF_RANGE; // invalid time part
if (m_length == 1) { // truncated time
if (i == 0) {
last = value;
@@ -608,10 +634,10 @@ result_t StringDataField::writeSymbols(istringstream& input,
continue;
}
if ((value % 10) != 0)
return RESULT_ERR_INVALID_ARG; // invalid truncated time minutes
return RESULT_ERR_INVALID_NUM; // invalid truncated time minutes
value = last * 6 + (value / 10);
if (value > 24 * 6)
return RESULT_ERR_INVALID_ARG; // invalid time
return RESULT_ERR_OUT_OF_RANGE; // invalid time
}
break;
default:
@@ -628,16 +654,16 @@ result_t StringDataField::writeSymbols(istringstream& input,
last = value;
if ((m_dataType.flags & BCD) != 0 || m_dataType.type == bt_dat) {
if (value > 99)
return RESULT_ERR_INVALID_ARG; // invalid BCD
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
value = ((value / 10) << 4) | (value % 10);
}
if (value > 0xff)
return RESULT_ERR_INVALID_ARG; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
output[baseOffset + offset] = (unsigned char)value;
}
if (i < m_length)
return RESULT_ERR_INVALID_ARG; // input too short
return RESULT_ERR_EOF; // input too short
return RESULT_OK;
}
@@ -669,7 +695,7 @@ result_t NumericDataField::readRawValue(SymbolString& input,
unsigned char ch;
if (baseOffset + m_length > input.size())
return RESULT_ERR_INVALID_ARG; // not enough data available
return RESULT_ERR_INVALID_POS; // not enough data available
if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first)
start = m_length - 1;
@@ -685,7 +711,7 @@ result_t NumericDataField::readRawValue(SymbolString& input,
return RESULT_OK;
}
if ((ch & 0xf0) > 0x90 || (ch & 0x0f) > 0x09)
return RESULT_ERR_INVALID_ARG; // invalid BCD
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
ch = (ch >> 4) * 10 + (ch & 0x0f);
value += ch * exp;
@@ -720,7 +746,7 @@ result_t NumericDataField::writeRawValue(unsigned int value,
if ((m_dataType.flags & BCD) == 0) {
if ((m_bitCount % 8) != 0 && (value & ~((1 << m_bitCount) - 1)) != 0)
return RESULT_ERR_INVALID_ARG;
return RESULT_ERR_OUT_OF_RANGE;
value <<= m_bitOffset;
}
@@ -754,7 +780,7 @@ result_t NumberDataField::derive(string name, string comment,
vector<SingleDataField*>& fields)
{
if (m_partType != pt_any && partType == pt_any)
return RESULT_ERR_INVALID_ARG; // cannot create a template from a concrete instance
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
if (name.empty() == true)
name = m_name;
if (comment.empty() == true)
@@ -834,7 +860,7 @@ result_t NumberDataField::writeSymbols(istringstream& input,
if (isIgnored() == true || strcasecmp(str, NULL_VALUE) == 0)
value = m_dataType.replacement; // replacement value
else if (str == NULL || *str == 0)
return RESULT_ERR_INVALID_ARG; // input too short
return RESULT_ERR_EOF; // input too short
else {
char* strEnd = NULL;
if (m_divisor <= 1) {
@@ -848,17 +874,17 @@ result_t NumberDataField::writeSymbols(istringstream& input,
else
value = strtoul(str, &strEnd, 10);
if (strEnd == NULL || *strEnd != 0)
return RESULT_ERR_INVALID_ARG; // invalid value
return RESULT_ERR_INVALID_NUM; // invalid value
}
else {
char* strEnd = NULL;
double dvalue = strtod(str, &strEnd);
if (strEnd == NULL || *strEnd != 0)
return RESULT_ERR_INVALID_ARG; // invalid value
return RESULT_ERR_INVALID_NUM; // invalid value
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_INVALID_ARG; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
if (dvalue < 0 && m_bitCount != 32)
value = (unsigned int) (dvalue + (1 << m_bitCount));
else
@@ -866,7 +892,7 @@ result_t NumberDataField::writeSymbols(istringstream& input,
}
else {
if (dvalue < 0.0 || dvalue >= (1LL << (8 * m_length)))
return RESULT_ERR_INVALID_ARG; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
value = (unsigned int) dvalue;
}
}
@@ -874,13 +900,13 @@ result_t NumberDataField::writeSymbols(istringstream& input,
if ((m_dataType.flags & SIG) != 0) { // signed value
if ((value & (1 << (m_bitCount - 1))) != 0) { // negative signed value
if (value < m_dataType.minValueOrLength)
return RESULT_ERR_INVALID_ARG; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
else if (value > m_dataType.maxValueOrLength)
return RESULT_ERR_INVALID_ARG; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
else if (value < m_dataType.minValueOrLength || value > m_dataType.maxValueOrLength)
return RESULT_ERR_INVALID_ARG; // value out of range
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
return writeRawValue(value, baseOffset, output);
@@ -893,7 +919,7 @@ result_t ValueListDataField::derive(string name, string comment,
vector<SingleDataField*>& fields)
{
if (m_partType != pt_any && partType == pt_any)
return RESULT_ERR_INVALID_ARG; // cannot create a template from a concrete instance
return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance
if (name.empty() == true)
name = m_name;
if (comment.empty() == true)
@@ -951,7 +977,7 @@ result_t ValueListDataField::readSymbols(SymbolString& input,
return RESULT_OK;
}
return RESULT_ERR_INVALID_ARG; // value assignment not found
return RESULT_ERR_NOTFOUND; // value assignment not found
}
result_t ValueListDataField::writeSymbols(istringstream& input,
@@ -969,7 +995,7 @@ result_t ValueListDataField::writeSymbols(istringstream& input,
if (strcasecmp(str, NULL_VALUE) == 0)
return writeRawValue(m_dataType.replacement, baseOffset, output); // replacement value
return RESULT_ERR_INVALID_ARG; // value assignment not found
return RESULT_ERR_NOTFOUND; // value assignment not found
}
DataFieldSet::~DataFieldSet()
@@ -1095,7 +1121,7 @@ result_t DataFieldSet::write(istringstream& input,
if (ignored == true)
token.clear();
else if (getline(input, token, separator) == 0)
return RESULT_ERR_INVALID_ARG; // incomplete
return RESULT_ERR_EOF; // incomplete
istringstream single(token);
result = (*it)->write(single, masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], separator);