diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 72bff285..4ec7d05b 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -29,11 +29,12 @@ /** the known data field types. */ static const dataType_t dataTypes[] = { + {"IGN",16*8,bt_str, IGN|ADJ, 0, 1, 16, 0, 0}, // >= 1 byte ignored data {"STR",16*8,bt_str, ADJ, ' ', 1, 16, 0, 0}, // >= 1 byte character string filled up with space {"HEX",16*8,bt_hexstr, ADJ, 0, 2, 47, 0, 0}, // >= 1 byte hex digit string, usually separated by space, e.g. 0a 1b 2c 3d - {"BDA", 32, bt_dat, BCD, 0, 10, 10, 0, 0}, // date in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is ignored weekday) + {"BDA", 32, bt_dat, BCD, 0, 10, 10, 0, 0}, // date with weekday in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is weekday) {"BDA", 24, bt_dat, BCD, 0, 10, 10, 0, 0}, // date in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99) - {"HDA", 32, bt_dat, 0, 0, 10, 10, 0, 0}, // date, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is ignored weekday) // TODO remove duplicate of BDA + {"HDA", 32, bt_dat, 0, 0, 10, 10, 0, 0}, // date with weekday, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is weekday) // TODO remove duplicate of BDA {"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) {"HTM", 16, bt_tim, 0, 0, 5, 5, 0, 0}, // time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x17,0x3b) @@ -52,41 +53,14 @@ static const dataType_t dataTypes[] = { {"D2C", 16, bt_num, SIG, 0x8000, 0x8001, 0x7fff, 16, 2}, // signed number (fraction 1/16), -2047.9 - +2047.9 {"ULG", 32, bt_num, LST, 0xffffffff, 0, 0xfffffffe, 1, 0}, // unsigned integer, 0 - 4294967294 {"SLG", 32, bt_num, SIG, 0x80000000, 0x80000001, 0xffffffff, 1, 0}, // signed integer, -2147483647 - +2147483647 - {"BI0", 1, bt_num, LST, 0, 0, 0x1, 1, 0}, // single bit 0 - {"BI1", 1, bt_num, LST, 0, 0, 0x1, 1, 1}, // single bit 1 - {"BI2", 1, bt_num, LST, 0, 0, 0x1, 1, 2}, // single bit 2 - {"BI3", 1, bt_num, LST, 0, 0, 0x1, 1, 3}, // single bit 3 - {"BI4", 1, bt_num, LST, 0, 0, 0x1, 1, 4}, // single bit 4 - {"BI5", 1, bt_num, LST, 0, 0, 0x1, 1, 5}, // single bit 5 - {"BI6", 1, bt_num, LST, 0, 0, 0x1, 1, 6}, // single bit 6 - {"BI7", 1, bt_num, LST, 0, 0, 0x1, 1, 7}, // single bit 7 - {"B01", 2, bt_num, LST, 0, 0, 0x3, 1, 0}, // two bits 0-1 - {"B12", 2, bt_num, LST, 0, 0, 0x3, 1, 1}, // two bits 1-2 - {"B23", 2, bt_num, LST, 0, 0, 0x3, 1, 2}, // two bits 2-3 - {"B34", 2, bt_num, LST, 0, 0, 0x3, 1, 3}, // two bits 3-4 - {"B45", 2, bt_num, LST, 0, 0, 0x3, 1, 4}, // two bits 4-5 - {"B56", 2, bt_num, LST, 0, 0, 0x3, 1, 5}, // two bits 5-6 - {"B67", 2, bt_num, LST, 0, 0, 0x3, 1, 6}, // two bits 6-7 - {"B02", 3, bt_num, LST, 0, 0, 0x7, 1, 0}, // three bits 0-2 - {"B13", 3, bt_num, LST, 0, 0, 0x7, 1, 1}, // three bits 1-3 - {"B24", 3, bt_num, LST, 0, 0, 0x7, 1, 2}, // three bits 2-4 - {"B35", 3, bt_num, LST, 0, 0, 0x7, 1, 3}, // three bits 3-5 - {"B46", 3, bt_num, LST, 0, 0, 0x7, 1, 4}, // three bits 4-6 - {"B57", 3, bt_num, LST, 0, 0, 0x7, 1, 5}, // three bits 5-7 - {"B03", 4, bt_num, LST, 0, 0, 0xf, 1, 0}, // four bits 0-3 - {"B14", 4, bt_num, LST, 0, 0, 0xf, 1, 1}, // four bits 1-4 - {"B25", 4, bt_num, LST, 0, 0, 0xf, 1, 2}, // four bits 2-5 - {"B36", 4, bt_num, LST, 0, 0, 0xf, 1, 3}, // four bits 3-6 - {"B47", 4, bt_num, LST, 0, 0, 0xf, 1, 4}, // four bits 4-7 - {"B04", 5, bt_num, LST, 0, 0, 0x1f, 1, 0}, // five bits 0-4 - {"B15", 5, bt_num, LST, 0, 0, 0x1f, 1, 1}, // five bits 1-5 - {"B26", 5, bt_num, LST, 0, 0, 0x1f, 1, 2}, // five bits 2-6 - {"B37", 5, bt_num, LST, 0, 0, 0x1f, 1, 3}, // five bits 3-7 - {"B05", 6, bt_num, LST, 0, 0, 0x3f, 1, 0}, // six bits 0-5 - {"B16", 6, bt_num, LST, 0, 0, 0x3f, 1, 1}, // six bits 1-6 - {"B27", 6, bt_num, LST, 0, 0, 0x3f, 1, 2}, // six bits 2-7 - {"B06", 7, bt_num, LST, 0, 0, 0x7f, 1, 0}, // seven bits 0-6 - {"B17", 7, bt_num, LST, 0, 0, 0x7f, 1, 1}, // seven bits 1-7 + {"BI0", 7, bt_num, ADJ|LST, 0, 0, 0xef, 1, 0}, // bit 0 (up to 7 bits until bit 6) + {"BI1", 7, bt_num, ADJ|LST, 0, 0, 0x7f, 1, 1}, // bit 1 (up to 7 bits until bit 7) + {"BI2", 6, bt_num, ADJ|LST, 0, 0, 0x3f, 1, 2}, // bit 2 (up to 6 bits until bit 7) + {"BI3", 5, bt_num, ADJ|LST, 0, 0, 0x1f, 1, 3}, // bit 3 (up to 5 bits until bit 7) + {"BI4", 4, bt_num, ADJ|LST, 0, 0, 0x0f, 1, 4}, // bit 4 (up to 4 bits until bit 7) + {"BI5", 3, bt_num, ADJ|LST, 0, 0, 0x07, 1, 5}, // bit 5 (up to 3 bits until bit 7) + {"BI6", 2, bt_num, ADJ|LST, 0, 0, 0x03, 1, 6}, // bit 6 (up to 2 bits until bit 7) + {"BI7", 1, bt_num, ADJ|LST, 0, 0, 0x01, 1, 7}, // bit 7 }; @@ -132,18 +106,17 @@ result_t DataField::create(std::vector::iterator& it, std::string unit, comment; PartType partType; unsigned int divisor = 0; - unsigned char length; const bool isTemplate = dstAddress == SYN; std::string token; if (it == end) break; - // name;[m|s][len];type[;[divisor|values][;[unit][;[comment]]]] + // name;part;type[:len][;[divisor|values][;[unit][;[comment]]]] const std::string name = *it++; if (it == end) break; - const char* posStr = (*it++).c_str(); + const char* partStr = (*it++).c_str(); if (it == end) break; @@ -151,18 +124,17 @@ result_t DataField::create(std::vector::iterator& it, firstName = name; firstComment = comment; } - if (dstAddress == BROADCAST || isMaster(dstAddress) - || (isTemplate == false && isSetMessage == true && (posStr[0] == 0 || posStr[0] <= '9')) - || posStr[0] == 'm') { // master data - partType = pt_masterData; - if (posStr[0] == 'm') - posStr++; + if (isTemplate == false && strcasecmp(partStr, "I") == 0) { + partType = pt_masterDataID; } - else if ((isTemplate == false && isSetMessage == false && (posStr[0] == 0 || posStr[0] <= '9')) - || posStr[0] == 's') { // slave data + else if (dstAddress == BROADCAST || isMaster(dstAddress) + || (isTemplate == false && isSetMessage == true && partStr[0] == 0) + || strcasecmp(partStr, "M") == 0) { // master data + partType = pt_masterData; + } + else if ((isTemplate == false && isSetMessage == false && partStr[0] == 0) + || strcasecmp(partStr, "S") == 0) { // slave data partType = pt_slaveData; - if (posStr[0] == 's') - posStr++; } else if (isTemplate) { partType = pt_any; @@ -172,17 +144,10 @@ result_t DataField::create(std::vector::iterator& it, break; } - if (posStr[0] == 0) { - length = 0; - } - else { - length = parseInt(posStr, 10, 1, MAX_POS, result); - if (result != RESULT_OK) - break; - } - - const char* typeStr = (*it++).c_str(); - if (typeStr[0] == 0) { + std::string typeStr = *it++; + if (typeStr.empty() == true) { + if (name.empty() == false || partStr[0] != 0) + result = RESULT_ERR_INVALID_ARG; break; } @@ -190,7 +155,7 @@ result_t DataField::create(std::vector::iterator& it, if (it != end) { std::string divisorStr = *it++; if (divisorStr.empty() == false) { - if (divisorStr.find_first_not_of("0123456789") == std::string::npos) { + if (divisorStr.find('=') == std::string::npos) { divisor = parseInt(divisorStr.c_str(), 10, 1, 10000, result); if (result != RESULT_OK) break; @@ -231,47 +196,73 @@ result_t DataField::create(std::vector::iterator& it, comment.clear(); } - // check for reference(s) to templates - if (templates.empty() == false) { - std::istringstream stream(typeStr); - bool found = false; - while (std::getline(stream, token, VALUE_SEPARATOR) != 0) { - std::map< std::string, DataField*>::const_iterator ref = templates.find(token); - if (ref == templates.end()) { - if (found == false) - break; // fallback to direct definition - result = RESULT_ERR_INVALID_ARG; // cannot mix reference and direct definition - break; + size_t pos = typeStr.find(':'); + unsigned char length; + if (pos == std::string::npos) { + length = 0; + // check for reference(s) to templates + if (templates.empty() == false) { + std::istringstream stream(typeStr); + bool found = false; + std::string lengthStr; + while (std::getline(stream, token, VALUE_SEPARATOR) != 0) { + std::map::const_iterator ref = templates.find(token); + if (ref == templates.end()) { + if (found == false) + break; // fallback to direct definition + result = RESULT_ERR_INVALID_ARG; // cannot mix reference and direct definition + break; + } + found = true; + result = ref->second->derive(name, comment, unit, partType, divisor, values, fields); + if (result != RESULT_OK) + break; } - if (length > 1) { - result = RESULT_ERR_INVALID_ARG; // different length not possible for derivation - break; - } - found = true; - result = ref->second->derive(name, comment, unit, partType, divisor, values, fields); - if (result != RESULT_OK) - break; + if (found == true || result != RESULT_OK) + break; // TODO check for found == true } - if (found == true || result != RESULT_OK) - break; } + else { + length = parseInt(typeStr.substr(pos+1).c_str(), 10, 1, MAX_POS, result); + if (result != RESULT_OK) + break; + typeStr = typeStr.substr(0, pos); + } + SingleDataField* add = NULL; + const char* typeName = typeStr.c_str(); for (size_t i = 0; result == RESULT_OK && add == NULL && i < sizeof(dataTypes) / sizeof(dataTypes[0]); i++) { dataType_t dataType = dataTypes[i]; - if (strcasecmp(typeStr, dataType.name) == 0) { - unsigned char numBytes = (dataType.numBits + 7) / 8; - unsigned char useLength = length; - if ((dataType.flags & ADJ) != 0) { - if (useLength == 0) - useLength = 1; // minimum length defaults to 1 - else if (useLength > numBytes) { + if (strcasecmp(typeName, dataType.name) == 0) { + unsigned char bitCount = dataType.maxBits; + unsigned char useLength = (bitCount + 7) / 8; + if ((dataType.flags & ADJ) != 0) { // adjustable length + if ((bitCount % 8) != 0) { + if (length == 0) { + useLength = 1; // default length: 1 byte + bitCount = 1; // default count: 1 bit + } + else if (length > bitCount) { + result = RESULT_ERR_INVALID_ARG; // invalid length + break; + } + else { + bitCount = length; + useLength = (length + 7) / 8; + } + } + else if (length == 0) { + useLength = 1; // default length: 1 byte + } + else if (length <= useLength) { + useLength = length; + } + else { result = RESULT_ERR_INVALID_ARG; // invalid length break; } } - else if (useLength == 0) - useLength = numBytes; - else if (useLength != numBytes) + else if (length > 0 && length != useLength) continue; // check for another one with same name but different length switch (dataType.type) @@ -294,7 +285,7 @@ result_t DataField::create(std::vector::iterator& it, else divisor *= dataType.divisor; - add = new NumberDataField(name, comment, unit, dataType, partType, useLength, divisor); + add = new NumberDataField(name, comment, unit, dataType, partType, useLength, bitCount, divisor); break; } if (values.begin()->first < dataType.minValueOrLength @@ -303,7 +294,7 @@ result_t DataField::create(std::vector::iterator& it, break; } - add = new ValueListDataField(name, comment, unit, dataType, partType, useLength, values); + add = new ValueListDataField(name, comment, unit, dataType, partType, useLength, bitCount, values); break; } } @@ -330,22 +321,17 @@ result_t DataField::create(std::vector::iterator& it, } -bool SingleDataField::hasFullByteOffset() -{ - return m_length > 1 || (m_dataType.numBits % 8) == 0 - || m_dataType.precisionOrFirstBit + (m_dataType.numBits % 8) >= 8; -} - result_t SingleDataField::read(SymbolString& masterData, unsigned char masterOffset, SymbolString& slaveData, unsigned char slaveOffset, std::ostringstream& output, bool verbose, char separator) { - SymbolString& input = m_partType == pt_masterData ? masterData : slaveData; + SymbolString& input = m_partType != pt_slaveData ? masterData : slaveData; unsigned char offset; switch (m_partType) { case pt_masterData: + case pt_masterDataID: offset = 5 + masterOffset; // skip QQ ZZ PB SB NN break; case pt_slaveData: @@ -355,7 +341,14 @@ result_t SingleDataField::read(SymbolString& masterData, unsigned char masterOff return RESULT_ERR_INVALID_ARG; // invalid part type } - if (verbose) + if (isIgnored() == true) { + if (offset + m_length > input.size()) { + return RESULT_ERR_INVALID_ARG; + } + return RESULT_OK; + } + + if (verbose == true) output << m_name << "="; result_t result = readSymbols(input, offset, output); @@ -375,11 +368,12 @@ result_t SingleDataField::write(std::istringstream& input, SymbolString& slaveData, unsigned char slaveOffset, char separator) { - SymbolString& output = m_partType == pt_masterData ? masterData : slaveData; + SymbolString& output = m_partType != pt_slaveData ? masterData : slaveData; unsigned char offset; switch (m_partType) { case pt_masterData: + case pt_masterDataID: offset = 5 + masterOffset; // skip QQ ZZ PB SB NN break; case pt_slaveData: @@ -423,6 +417,7 @@ result_t StringDataField::readSymbols(SymbolString& input, if (baseOffset + m_length > input.size()) { return RESULT_ERR_INVALID_ARG; } + if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first) start = m_length - 1; incr = -1; @@ -494,6 +489,12 @@ result_t StringDataField::writeSymbols(std::istringstream& input, incr = -1; } + if (isIgnored() == true) { + for (size_t offset = start, i = 0; i < count; offset += incr, i++) { + output[baseOffset + offset] = m_dataType.replacement; // fill up with replacement + } + return RESULT_OK; + } result_t result; size_t i = 0; for (size_t offset = start; i < count; offset += incr, i++) { @@ -581,6 +582,12 @@ result_t StringDataField::writeSymbols(std::istringstream& input, } +bool NumericDataField::hasFullByteOffset(bool after) +{ + return m_length > 1 || (m_bitCount % 8) == 0 + || (after == true && m_bitOffset + (m_bitCount % 8) >= 8); +} + result_t NumericDataField::readRawValue(SymbolString& input, unsigned char baseOffset, unsigned int& value) { @@ -619,9 +626,10 @@ result_t NumericDataField::readRawValue(SymbolString& input, if ((m_dataType.flags & BCD) == 0) { value >>= m_bitOffset; - if ((m_dataType.numBits % 8) != 0) - value &= (1 << m_dataType.numBits) - 1; + if ((m_bitCount % 8) != 0) + value &= (1 << m_bitCount) - 1; } + return RESULT_OK; } @@ -638,8 +646,9 @@ result_t NumericDataField::writeRawValue(unsigned int value, } if ((m_dataType.flags & BCD) == 0) { - if ((m_dataType.numBits % 8) != 0) - value &= (1 << m_dataType.numBits) - 1; + if ((m_bitCount % 8) != 0 && (value & ~((1 << m_bitCount) - 1)) != 0) + return RESULT_ERR_INVALID_ARG; + value <<= m_bitOffset; } for (size_t offset = start, i = 0, exp = 1; i < count; offset += incr, i++) { @@ -656,7 +665,7 @@ result_t NumericDataField::writeRawValue(unsigned int value, ch = (value / exp) & 0xff; exp = exp << 8; } - if (offset == start && (m_dataType.numBits % 8) != 0 && baseOffset + offset < output.size()) + if (offset == start && (m_bitCount % 8) != 0 && baseOffset + offset < output.size()) output[baseOffset + offset] |= ch; else output[baseOffset + offset] = ch; @@ -687,10 +696,10 @@ result_t NumberDataField::derive(std::string name, std::string comment, if (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, values)); + 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, divisor)); + fields.push_back(new NumberDataField(name, comment, unit, m_dataType, partType, m_length, m_bitCount, divisor)); return RESULT_OK; } @@ -710,27 +719,27 @@ result_t NumberDataField::readSymbols(SymbolString& input, return RESULT_OK; } - bool negative = (m_dataType.flags & SIG) != 0 && (value & (1 << (m_dataType.numBits - 1))) != 0; - if (m_dataType.numBits == 32) { + bool negative = (m_dataType.flags & SIG) != 0 && (value & (1 << (m_bitCount - 1))) != 0; + if (m_bitCount == 32) { if (negative == false) { if (m_divisor <= 1) output << static_cast(value); else - output << std::setprecision((m_dataType.numBits % 8) == 0 ? m_dataType.precisionOrFirstBit : 0) + output << std::setprecision((m_bitCount % 8) == 0 ? m_dataType.precisionOrFirstBit : 0) << std::fixed << static_cast(value / (float) m_divisor); return RESULT_OK; } signedValue = (int) value; // negative signed value } else if (negative) // negative signed value - signedValue = (int) value - (1 << m_dataType.numBits); + signedValue = (int) value - (1 << m_bitCount); else signedValue = (int) value; if (m_divisor <= 1) output << static_cast(signedValue); else - output << std::setprecision((m_dataType.numBits % 8) == 0 ? m_dataType.precisionOrFirstBit : 0) + output << std::setprecision((m_bitCount % 8) == 0 ? m_dataType.precisionOrFirstBit : 0) << std::fixed << static_cast(signedValue / (float) m_divisor); return RESULT_OK; @@ -742,18 +751,17 @@ result_t NumberDataField::writeSymbols(std::istringstream& input, unsigned int value; const char* str = input.str().c_str(); - if (strcasecmp(str, NULL_VALUE) == 0) - // replacement value - value = m_dataType.replacement; + 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_INVALID_ARG; // input too short//TODO LENGTH_SEPARATOR else { char* strEnd = NULL; if (m_divisor <= 1) { if ((m_dataType.flags & SIG) != 0) { int signedValue = strtol(str, &strEnd, 10); - if (signedValue < 0 && m_dataType.numBits != 32) - value = (unsigned int) (signedValue + (1 << m_dataType.numBits)); + if (signedValue < 0 && m_bitCount != 32) + value = (unsigned int) (signedValue + (1 << m_bitCount)); else value = (unsigned int) signedValue; } @@ -771,8 +779,8 @@ result_t NumberDataField::writeSymbols(std::istringstream& input, 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 - if (dvalue < 0 && m_dataType.numBits != 32) - value = (unsigned int) (dvalue + (1 << m_dataType.numBits)); + if (dvalue < 0 && m_bitCount != 32) + value = (unsigned int) (dvalue + (1 << m_bitCount)); else value = (unsigned int) dvalue; } @@ -784,7 +792,7 @@ result_t NumberDataField::writeSymbols(std::istringstream& input, } if ((m_dataType.flags & SIG) != 0) { // signed value - if ((value & (1 << (m_dataType.numBits - 1))) != 0) { // negative 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 } @@ -823,7 +831,7 @@ result_t ValueListDataField::derive(std::string name, std::string comment, else values = m_values; - fields.push_back(new ValueListDataField(name, comment, unit, m_dataType, partType, m_length, values)); + fields.push_back(new ValueListDataField(name, comment, unit, m_dataType, partType, m_length, m_bitCount, values)); return RESULT_OK; } @@ -854,14 +862,17 @@ result_t ValueListDataField::readSymbols(SymbolString& input, result_t ValueListDataField::writeSymbols(std::istringstream& input, unsigned char baseOffset, SymbolString& output) { + if (isIgnored() == true) + return writeRawValue(m_dataType.replacement, baseOffset, output); // replacement value + const char* str = input.str().c_str(); for (std::map::iterator it = m_values.begin(); it != m_values.end(); it++) if (it->second.compare(str) == 0) return writeRawValue(it->first, baseOffset, output); - if (strcasecmp(str, NULL_VALUE) == 0) // replacement value - return writeRawValue(m_dataType.replacement, baseOffset, output); + if (strcasecmp(str, NULL_VALUE) == 0) + return writeRawValue(m_dataType.replacement, baseOffset, output); // replacement value return RESULT_ERR_INVALID_ARG; // value assignment not found } @@ -878,15 +889,17 @@ unsigned char DataFieldSet::getLength(PartType partType) { unsigned char length = 0; - bool previousFullByteOffset[] = { true, true, true }; + bool previousFullByteOffset[] = { true, true, true, true }; + for (std::vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { SingleDataField* field = *it; if (field->getPartType() == partType) { - length += field->getLength(partType); - if (previousFullByteOffset[partType] == false) { + if (previousFullByteOffset[partType] == false && field->hasFullByteOffset(false) == false) length--; - } - previousFullByteOffset[partType] = field->hasFullByteOffset(); + + length += field->getLength(partType); + + previousFullByteOffset[partType] = field->hasFullByteOffset(true); } } @@ -918,29 +931,38 @@ result_t DataFieldSet::read(SymbolString& masterData, unsigned char masterOffset output << m_name << "={ "; bool first = true; - unsigned char offsets[] = { 0, masterOffset, slaveOffset }; - bool previousFullByteOffset[] = { true, true, true }; + unsigned char offsets[4]; + memset(offsets, 0, sizeof(offsets)); + offsets[pt_masterData] = masterOffset; + offsets[pt_slaveData] = slaveOffset; + bool previousFullByteOffset[] = { true, true, true, true }; for (std::vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { - if (first) - first = false; - else - output << separator; - SingleDataField* field = *it; + bool ignored = field->isIgnored(); PartType partType = field->getPartType(); - if (previousFullByteOffset[partType] == false) { - offsets[partType]--; + + if (ignored == false) { + if (first) + first = false; + else + output << separator; } + if (partType == pt_masterDataID) + partType = pt_masterData; + if (previousFullByteOffset[partType] == false && field->hasFullByteOffset(false) == false) + offsets[partType]--; + result_t result = field->read(masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], output, verbose, separator); if (result != RESULT_OK) return result; offsets[partType] += field->getLength(partType); - previousFullByteOffset[partType] = field->hasFullByteOffset(); + + previousFullByteOffset[partType] = field->hasFullByteOffset(true); } - if (verbose) { + if (verbose == true) { if (m_comment.length() > 0) output << " [" << m_comment << "]"; output << "}"; @@ -956,18 +978,28 @@ result_t DataFieldSet::write(std::istringstream& input, { std::string token; - unsigned char offsets[] = { 0, masterOffset, slaveOffset }; - bool previousFullByteOffset[] = { true, true, true }; + unsigned char offsets[4]; + memset(offsets, 0, sizeof(offsets)); + offsets[pt_masterData] = masterOffset; + offsets[pt_slaveData] = slaveOffset; + bool previousFullByteOffset[] = { true, true, true, true }; for (std::vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { SingleDataField* field = *it; + bool ignored = field->isIgnored(); PartType partType = field->getPartType(); - if (previousFullByteOffset[partType] == false) { + + if (partType == pt_masterDataID) + partType = pt_masterData; + if (previousFullByteOffset[partType] == false && field->hasFullByteOffset(false) == false) offsets[partType]--; - } + result_t result; if (m_fields.size() > 1) { - if (std::getline(input, token, separator) == 0) + if (ignored == true) + token.clear(); + else if (std::getline(input, token, separator) == 0) return RESULT_ERR_INVALID_ARG; // incomplete + std::istringstream single(token); result = (*it)->write(single, masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], separator); } @@ -978,7 +1010,7 @@ result_t DataFieldSet::write(std::istringstream& input, return result; offsets[partType] += field->getLength(partType); - previousFullByteOffset[partType] = field->hasFullByteOffset(); + previousFullByteOffset[partType] = field->hasFullByteOffset(true); } return RESULT_OK; diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index 083df206..c6533dab 100644 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -28,9 +28,10 @@ /** the message part in which a data field is stored. */ enum PartType { - pt_any, // stored in any data (master or slave) - pt_masterData, // stored in master data - pt_slaveData, // stored in slave data + pt_any, // stored in any data (master or slave) + pt_masterData, // stored in master data + pt_masterDataID, // stored in master data and also used as message ID part + pt_slaveData, // stored in slave data }; /** the available base data types. */ @@ -49,11 +50,12 @@ const unsigned int REV = 0x04; // reverted binary representation (most significa const unsigned int SIG = 0x08; // signed value const unsigned int LST = 0x10; // value list is possible (without applied divisor) const unsigned int DAY = 0x20; // forced value list defaulting to week days +const unsigned int IGN = 0x40; // ignore value during read and write /** the structure for defining field types with their properties. */ typedef struct { const char* name; // field identifier - const unsigned int numBits; // number of bits (maximum length if @a ADJ flag is set, must be multiple of 8 with flag @a BCD) + const unsigned int maxBits; // 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 int 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) @@ -208,6 +210,11 @@ public: * @return the value unit. */ std::string getUnit() const { return m_unit; } + /** + * @brief Get whether this field is ignored. + * @return whether this field is ignored. + */ + bool isIgnored() const { return (m_dataType.flags & IGN) != 0; } /** * @brief Get the message part in which the field is stored. * @return the message part in which the field is stored. @@ -218,10 +225,11 @@ public: // re-use same position as previous field as not all bits of fully consumed yet /** * @brief Get whether this field uses a full byte offset. + * @param after @p true to check after consuming the bits, false to check before. * @return true if this field uses a full byte offset, false if this field * only consumes a part of a byte and a subsequent field may re-use the same offset. */ - bool hasFullByteOffset(); + virtual bool hasFullByteOffset(bool after) { return true; } /** * @brief Reads the value from the master or slave @a SymbolString. * @param masterData the unescaped master data @a SymbolString for reading binary data. @@ -337,17 +345,20 @@ public: * @param dataType the data type definition. * @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. * @param bitOffset the offset to the first bit in the binary value. */ NumericDataField(const std::string name, const std::string comment, const std::string unit, const dataType_t dataType, const PartType partType, - const unsigned char length, const unsigned char bitOffset) + const unsigned char length, const unsigned char bitCount, const unsigned char bitOffset) : SingleDataField(name, comment, unit, dataType, partType, length), - m_bitOffset(bitOffset) {} + m_bitCount(bitCount), m_bitOffset(bitOffset) {} /** * @brief Destructor. */ virtual ~NumericDataField() {} + // @copydoc + virtual bool hasFullByteOffset(bool after); protected: @@ -368,9 +379,13 @@ protected: */ result_t writeRawValue(unsigned int value, const unsigned char offset, SymbolString& output); + /** the number of bits in the binary value. */ + const unsigned char m_bitCount; + /** the offset to the first bit in the binary value. */ const unsigned char m_bitOffset; + }; @@ -393,9 +408,10 @@ public: */ NumberDataField(const std::string name, const std::string comment, const std::string unit, const dataType_t dataType, const PartType partType, - const unsigned char length, const unsigned int divisor) - : NumericDataField(name, comment, unit, dataType, partType, length, - (dataType.numBits%8) != 0 ? dataType.precisionOrFirstBit : 0), + const unsigned char length, const unsigned char bitCount, + const unsigned int divisor) + : NumericDataField(name, comment, unit, dataType, partType, length, bitCount, + (dataType.maxBits < 8) ? dataType.precisionOrFirstBit : 0), m_divisor(divisor) {} /** * @brief Destructor. @@ -439,9 +455,10 @@ public: */ ValueListDataField(const std::string name, const std::string comment, const std::string unit, const dataType_t dataType, const PartType partType, - const unsigned char length, const std::map values) - : NumericDataField(name, comment, unit, dataType, partType, length, - (dataType.numBits%8) != 0 ? dataType.precisionOrFirstBit : 0), + const unsigned char length, const unsigned char bitCount, + const std::map values) + : NumericDataField(name, comment, unit, dataType, partType, length, bitCount, + (dataType.maxBits < 8) ? dataType.precisionOrFirstBit : 0), m_values(values) {} /** * @brief Destructor. diff --git a/src/lib/ebus/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp index c40d8704..0775085c 100644 --- a/src/lib/ebus/test/test_data.cpp +++ b/src/lib/ebus/test/test_data.cpp @@ -43,21 +43,23 @@ int main() { std::string checks[][5] = { //name;[len];type[;[divisor|values][;[unit][;[comment]]]], decoded value, master, slave, flags - {"x;10;str", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""}, - {"x;10;str", "Hallo, Du ", "10fe07000a48616c6c6f2c20447520", "00", ""}, - {"x;10;str", " ", "10fe07000a20202020202020202020", "00", ""}, - {"x;11;str", "", "10fe07000a20202020202020202020", "00", "rW"}, + {"x;;ign:10", "", "10fe07000a00000000000000000000", "00", ""}, + {"x;;str:10", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""}, + {"x;;str:10", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""}, + {"x;;str:10", "Hallo, Du ", "10fe07000a48616c6c6f2c20447520", "00", ""}, + {"x;;str:10", " ", "10fe07000a20202020202020202020", "00", ""}, + {"x;;str:11", "", "10fe07000a20202020202020202020", "00", "rW"}, {"x;;hex", "20", "10fe07000120", "00", ""}, - {"x;10;hex", "48 61 6c 6c 6f 2c 20 44 75 21", "10fe07000a48616c6c6f2c20447521", "00", ""}, - {"x;11;hex", "", "10fe07000a48616c6c6f2c20447521", "00", "rW"}, + {"x;;hex:10", "48 61 6c 6c 6f 2c 20 44 75 21", "10fe07000a48616c6c6f2c20447521", "00", ""}, + {"x;;hex:11", "", "10fe07000a48616c6c6f2c20447521", "00", "rW"}, {"x;;bda", "26.10.2014","10fe07000426100014", "00", ""}, {"x;;bda", "01.01.2000","10fe07000401010000", "00", ""}, {"x;;bda", "31.12.2099","10fe07000431120099", "00", ""}, {"x;;bda", "", "10fe07000432100014", "00", "rw"}, - {"x;3;bda","26.10.2014","10fe070003261014", "00", ""}, - {"x;3;bda","01.01.2000","10fe070003010100", "00", ""}, - {"x;3;bda","31.12.2099","10fe070003311299", "00", ""}, - {"x;3;bda","", "10fe070003321299", "00", "rw"}, + {"x;;bda:3","26.10.2014","10fe070003261014", "00", ""}, + {"x;;bda:3","01.01.2000","10fe070003010100", "00", ""}, + {"x;;bda:3","31.12.2099","10fe070003311299", "00", ""}, + {"x;;bda:3","", "10fe070003321299", "00", "rw"}, {"x;;bti", "21:04:58", "10fe070003580421", "00", ""}, {"x;;bti", "00:00:00", "10fe070003000000", "00", ""}, {"x;;bti", "23:59:59", "10fe070003595923", "00", ""}, @@ -84,8 +86,8 @@ int main() {"x;;bcd", "99", "10feffff0199", "00", ""}, {"x;;bcd", "-", "10feffff01ff", "00", ""}, {"x;;bcd", "", "10feffff019a", "00", "rw"}, - {"x;16;str", "0123456789ABCDEF", "10feffff1130313233343536373839414243444546", "00", ""}, - {"x;17;uch", "", "10feffff00", "00", "c"}, + {"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;;;;y;m;uch", "2;3","1025ffff0103", "0102", ""}, @@ -148,14 +150,15 @@ int main() {"x;;bi3", "-", "10feffff0100", "00", ""}, {"x;;bi3;0=off,1=on","on", "10feffff0108", "00", ""}, {"x;;bi3;0=off,1=on","off","10feffff0100", "00", ""}, - {"x;;b34", "1", "10feffff0108", "00", ""}, - {"x;;b34", "-", "10feffff0100", "00", ""}, - {"x;;b34", "3", "10feffff0118", "00", ""}, - {"x;;b34;1=on","on", "10feffff0108", "00", ""}, - {"x;;b34;1=on","-", "10feffff0100", "00", ""}, - {"x;;b34;0=off,1=on,2=auto,3=eco","auto", "10feffff0110", "00", ""}, - {"x;;b34;0=off,1=on","on", "10feffff0108", "00", ""}, - {"x;;b34;0=off,1=on","off","10feffff0100", "00", ""}, + {"x;;bi3:2", "1", "10feffff0108", "00", ""}, + {"x;;bi3:2", "1", "10feffff01ef", "00", "W"}, + {"x;;bi3:2", "-", "10feffff0100", "00", ""}, + {"x;;bi3:2", "3", "10feffff0118", "00", ""}, + {"x;;bi3:2;1=on","on", "10feffff0108", "00", ""}, + {"x;;bi3:2;1=on","-", "10feffff0100", "00", ""}, + {"x;;bi3:2;0=off,1=on,2=auto,3=eco","auto", "10feffff0110", "00", ""}, + {"x;;bi3:2;0=off,1=on","on", "10feffff0108", "00", ""}, + {"x;;bi3:2;0=off,1=on","off","10feffff0100", "00", ""}, {"x;;uch;1=test,2=high,3=off,4=on","on","10feffff0104", "00", ""}, {"x;s;uch","3","1050ffff00", "0103", ""}, {"x;;d2b;;°C;Aussentemperatur","x=18.004 °C [Aussentemperatur]","10fe0700090112", "00", "v"}, @@ -164,8 +167,8 @@ int main() {"x;;bi3;;;;y;;bi5", "1;1", "10feffff0128", "00", ""}, // bit combination {"x;;bi3;;;;y;;bi5", "-;1", "10feffff0120", "00", ""}, // bit combination {"x;;bi3;;;;y;;bi5", "-;-", "10feffff0100", "00", ""}, // bit combination - {"x;;bi3;;;;y;;bi7;;;;t;;uch", "-;-;9","10feffff020009", "00", ""}, // bit combination, auto pos incr - {"x;;bi3;;;;y;;bi5;;;;t;;uch", "-;-;9","10feffff020009", "00", "RW"}, // bit combination + {"x;;bi3;;;;y;;bi7;;;;t;;uch", "-;-;9","10feffff020009", "00", ""}, // bit combination + {"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 {"relrel;;d2b;;;;y;;d1c","","", "", "t"}, // template struct with relative pos @@ -202,7 +205,6 @@ int main() } std::vector::iterator it = entries.begin(); result_t result = DataField::create(it, entries.end(), templates, fields, isSet, isTemplate ? SYN : mstr[1]); - if (failedCreate == true) { if (result == RESULT_OK) std::cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << std::endl;