diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp old mode 100644 new mode 100755 index b993330e..72bff285 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -132,13 +132,13 @@ result_t DataField::create(std::vector::iterator& it, std::string unit, comment; PartType partType; unsigned int divisor = 0; - unsigned char offset, length, offsetCnt = 0; + unsigned char length; const bool isTemplate = dstAddress == SYN; std::string token; if (it == end) break; - // name;[pos];type[;[divisor|values][;[unit][;[comment]]]] + // name;[m|s][len];type[;[divisor|values][;[unit][;[comment]]]] const std::string name = *it++; if (it == end) break; @@ -152,13 +152,13 @@ result_t DataField::create(std::vector::iterator& it, firstComment = comment; } if (dstAddress == BROADCAST || isMaster(dstAddress) - || (isTemplate == false && isSetMessage == true && posStr[0] != 0 && posStr[0] <= '9') + || (isTemplate == false && isSetMessage == true && (posStr[0] == 0 || posStr[0] <= '9')) || posStr[0] == 'm') { // master data partType = pt_masterData; if (posStr[0] == 'm') posStr++; } - else if ((isTemplate == false && isSetMessage == false && posStr[0] != 0 && posStr[0] <= '9') + else if ((isTemplate == false && isSetMessage == false && (posStr[0] == 0 || posStr[0] <= '9')) || posStr[0] == 's') { // slave data partType = pt_slaveData; if (posStr[0] == 's') @@ -173,33 +173,10 @@ result_t DataField::create(std::vector::iterator& it, } if (posStr[0] == 0) { - if (fields.empty() == false) - offset = fields.back()->getNextOffset(partType); - else - offset = 0; length = 0; } else { - offset = 0; - length = 0; - std::istringstream stream(posStr); - while (std::getline(stream, token, '-') != 0) { - if (++offsetCnt > 2) - return RESULT_ERR_INVALID_ARG; //invalid pos definition - - unsigned int pos = parseInt(token.c_str(), 10, 1, MAX_POS + 1, result) - 1; // input is 1-based - if (result != RESULT_OK) - break; - - if (offsetCnt == 1) - offset = pos; - else if (pos >= offset) - length = pos + 1 - offset; - else { // wrong order e.g. 4-3 - length = offset - (pos + 1); - offset = pos; - } - } + length = parseInt(posStr, 10, 1, MAX_POS, result); if (result != RESULT_OK) break; } @@ -271,14 +248,9 @@ result_t DataField::create(std::vector::iterator& it, break; } found = true; - result = ref->second->derive(name, comment, unit, partType, offset, divisor, values, fields); + result = ref->second->derive(name, comment, unit, partType, divisor, values, fields); if (result != RESULT_OK) break; - offset = fields.back()->getNextOffset(partType); - } - if (offset > MAX_POS) { - result = RESULT_ERR_INVALID_ARG; // invalid pos definition - break; } if (found == true || result != RESULT_OK) break; @@ -301,10 +273,6 @@ result_t DataField::create(std::vector::iterator& it, useLength = numBytes; else if (useLength != numBytes) continue; // check for another one with same name but different length - if (offset + useLength > MAX_POS) { - result = RESULT_ERR_INVALID_ARG; // invalid pos definition - break; - } switch (dataType.type) { @@ -312,7 +280,7 @@ result_t DataField::create(std::vector::iterator& it, case bt_hexstr: case bt_dat: case bt_tim: - add = new StringDataField(name, comment, unit, dataType, partType, offset, useLength); + add = new StringDataField(name, comment, unit, dataType, partType, useLength); break; case bt_num: if (values.empty() == true && (dataType.flags & DAY) != 0) { @@ -326,7 +294,7 @@ result_t DataField::create(std::vector::iterator& it, else divisor *= dataType.divisor; - add = new NumberDataField(name, comment, unit, dataType, partType, offset, useLength, divisor); + add = new NumberDataField(name, comment, unit, dataType, partType, useLength, divisor); break; } if (values.begin()->first < dataType.minValueOrLength @@ -335,7 +303,7 @@ result_t DataField::create(std::vector::iterator& it, break; } - add = new ValueListDataField(name, comment, unit, dataType, partType, offset, useLength, values); + add = new ValueListDataField(name, comment, unit, dataType, partType, useLength, values); break; } } @@ -362,31 +330,26 @@ result_t DataField::create(std::vector::iterator& it, } -unsigned char SingleDataField::getNextOffset(PartType partType) +bool SingleDataField::hasFullByteOffset() { - if (partType != pt_any && partType != m_partType) - return 0; - - unsigned char offset = m_offset + m_length; - if ((m_dataType.numBits % 8) != 0 - && m_dataType.precisionOrFirstBit + (m_dataType.numBits % 8) < 8) - offset--; // not all bits of last offset fully consumed - - return offset; + return m_length > 1 || (m_dataType.numBits % 8) == 0 + || m_dataType.precisionOrFirstBit + (m_dataType.numBits % 8) >= 8; } -result_t SingleDataField::read(SymbolString& masterData, SymbolString& slaveData, - std::ostringstream& output, bool verbose, char separator) +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; - unsigned char baseOffset; + unsigned char offset; switch (m_partType) { case pt_masterData: - baseOffset = 5; // skip QQ ZZ PB SB NN + offset = 5 + masterOffset; // skip QQ ZZ PB SB NN break; case pt_slaveData: - baseOffset = 1; // skip NN + offset = 1 + slaveOffset; // skip NN break; default: return RESULT_ERR_INVALID_ARG; // invalid part type @@ -395,7 +358,7 @@ result_t SingleDataField::read(SymbolString& masterData, SymbolString& slaveData if (verbose) output << m_name << "="; - result_t result = readSymbols(input, baseOffset, output); + result_t result = readSymbols(input, offset, output); if (result != RESULT_OK) return result; @@ -407,28 +370,30 @@ result_t SingleDataField::read(SymbolString& masterData, SymbolString& slaveData return RESULT_OK; } -result_t SingleDataField::write(std::istringstream& input, SymbolString& masterData, - SymbolString& slaveData, char separator) +result_t SingleDataField::write(std::istringstream& input, + SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, + char separator) { SymbolString& output = m_partType == pt_masterData ? masterData : slaveData; - unsigned char baseOffset; + unsigned char offset; switch (m_partType) { case pt_masterData: - baseOffset = 5; // skip QQ ZZ PB SB NN + offset = 5 + masterOffset; // skip QQ ZZ PB SB NN break; case pt_slaveData: - baseOffset = 1; // skip NN + offset = 1 + slaveOffset; // skip NN break; default: return RESULT_ERR_INVALID_ARG; } - return writeSymbols(input, baseOffset, output); + return writeSymbols(input, offset, output); } result_t StringDataField::derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned char offset, + std::string unit, const PartType partType, unsigned int divisor, std::map values, std::vector& fields) { @@ -442,9 +407,8 @@ result_t StringDataField::derive(std::string name, std::string comment, comment = m_comment; if (unit.empty() == true) unit = m_unit; - offset += m_offset; - fields.push_back(new StringDataField(name, comment, unit, m_dataType, partType, offset, m_length)); + fields.push_back(new StringDataField(name, comment, unit, m_dataType, partType, m_length)); return RESULT_OK; } @@ -452,20 +416,19 @@ result_t StringDataField::derive(std::string name, std::string comment, result_t StringDataField::readSymbols(SymbolString& input, unsigned char baseOffset, std::ostringstream& output) { - size_t start = m_offset, end = m_offset + m_length; + size_t start = 0, count = m_length; int incr = 1; unsigned char ch, last = 0; - if (baseOffset + end > input.size()) { + if (baseOffset + m_length > input.size()) { return RESULT_ERR_INVALID_ARG; } if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first) - end = start - 1; - start = m_offset + m_length - 1; + start = m_length - 1; incr = -1; } - for (size_t offset = start, i = 0; offset != end; offset += incr, i++) { + for (size_t offset = start, i = 0; i < count; offset += incr, i++) { if (m_length == 4 && i == 2 && m_dataType.type == bt_dat) continue; // skip weekday in between ch = input[baseOffset + offset]; @@ -495,6 +458,7 @@ result_t StringDataField::readSymbols(SymbolString& input, if (i == 0) { ch /= 6; // hours offset -= incr; // repeat for minutes + count++; } else ch = (ch % 6) * 10; // minutes @@ -520,20 +484,19 @@ result_t StringDataField::readSymbols(SymbolString& input, result_t StringDataField::writeSymbols(std::istringstream& input, unsigned char baseOffset, SymbolString& output) { - size_t start = m_offset, end = m_offset + m_length; + size_t start = 0, count = m_length; int incr = 1; unsigned long int value = 0, last = 0; std::string token; if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first) - end = start - 1; - start = m_offset + m_length - 1; + start = m_length - 1; incr = -1; } result_t result; size_t i = 0; - for (size_t offset = start; offset != end; offset += incr, i++) { + for (size_t offset = start; i < count; offset += incr, i++) { switch (m_dataType.type) { case bt_hexstr: @@ -578,8 +541,9 @@ result_t StringDataField::writeSymbols(std::istringstream& input, return RESULT_ERR_INVALID_ARG; // invalid time part if (m_length == 1) { // truncated time if (i == 0) { - offset -= incr; // repeat for minutes last = value; + offset -= incr; // repeat for minutes + count++; continue; } if ((value % 10) != 0) @@ -620,21 +584,20 @@ result_t StringDataField::writeSymbols(std::istringstream& input, result_t NumericDataField::readRawValue(SymbolString& input, unsigned char baseOffset, unsigned int& value) { - size_t start = m_offset, end = m_offset + m_length; + size_t start = 0, count = m_length; int incr = 1; unsigned char ch; - if (baseOffset + end > input.size()) + if (baseOffset + m_length > input.size()) return RESULT_ERR_INVALID_ARG; // not enough data available if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first) - end = start - 1; - start = m_offset + m_length - 1; + start = m_length - 1; incr = -1; } value = 0; - for (size_t offset = start, exp = 1; offset != end; offset += incr) { + for (size_t offset = start, i = 0, exp = 1; i < count; offset += incr, i++) { ch = input[baseOffset + offset]; if ((m_dataType.flags & BCD) != 0) { if (ch == m_dataType.replacement) { @@ -665,13 +628,12 @@ result_t NumericDataField::readRawValue(SymbolString& input, result_t NumericDataField::writeRawValue(unsigned int value, unsigned char baseOffset, SymbolString& output) { - size_t start = m_offset, end = m_offset + m_length; + size_t start = 0, count = m_length; int incr = 1; unsigned char ch; if ((m_dataType.flags & REV) != 0) { // reverted binary representation (most significant byte first) - end = start - 1; - start = m_offset + m_length - 1; + start = m_length - 1; incr = -1; } @@ -680,7 +642,7 @@ result_t NumericDataField::writeRawValue(unsigned int value, value &= (1 << m_dataType.numBits) - 1; value <<= m_bitOffset; } - for (size_t offset = start, exp = 1; offset != end; offset += incr) { + for (size_t offset = start, i = 0, exp = 1; i < count; offset += incr, i++) { if ((m_dataType.flags & BCD) != 0) { if (value == m_dataType.replacement) ch = m_dataType.replacement; @@ -705,7 +667,7 @@ result_t NumericDataField::writeRawValue(unsigned int value, result_t NumberDataField::derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned char offset, + std::string unit, const PartType partType, unsigned int divisor, std::map values, std::vector& fields) { @@ -717,7 +679,6 @@ result_t NumberDataField::derive(std::string name, std::string comment, comment = m_comment; if (unit.empty() == true) unit = m_unit; - offset += m_offset; if (divisor == 0) divisor = m_divisor; else @@ -726,10 +687,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, offset, m_length, values)); + fields.push_back(new ValueListDataField(name, comment, unit, m_dataType, partType, m_length, values)); } else - fields.push_back(new NumberDataField(name, comment, unit, m_dataType, partType, offset, m_length, divisor)); + fields.push_back(new NumberDataField(name, comment, unit, m_dataType, partType, m_length, divisor)); return RESULT_OK; } @@ -839,7 +800,7 @@ result_t NumberDataField::writeSymbols(std::istringstream& input, result_t ValueListDataField::derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned char offset, + std::string unit, const PartType partType, unsigned int divisor, std::map values, std::vector& fields) { @@ -851,7 +812,6 @@ result_t ValueListDataField::derive(std::string name, std::string comment, comment = m_comment; if (unit.empty() == true) unit = m_unit; - offset += m_offset; if (divisor != 0 && divisor != 1) return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field @@ -863,7 +823,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, offset, m_length, values)); + fields.push_back(new ValueListDataField(name, comment, unit, m_dataType, partType, m_length, values)); return RESULT_OK; } @@ -914,21 +874,27 @@ DataFieldSet::~DataFieldSet() } } -unsigned char DataFieldSet::getNextOffset(PartType partType) +unsigned char DataFieldSet::getLength(PartType partType) { - return 0; + unsigned char length = 0; - for (std::vector::reverse_iterator it = m_fields.rbegin(); it < m_fields.rend(); it++) { + bool previousFullByteOffset[] = { true, true, true }; + for (std::vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { SingleDataField* field = *it; - if (partType == pt_any || partType == field->getPartType()) - return field->getNextOffset(partType); + if (field->getPartType() == partType) { + length += field->getLength(partType); + if (previousFullByteOffset[partType] == false) { + length--; + } + previousFullByteOffset[partType] = field->hasFullByteOffset(); + } } - return 0; + return length; } result_t DataFieldSet::derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned char offset, + std::string unit, const PartType partType, unsigned int divisor, std::map values, std::vector& fields) { @@ -936,7 +902,7 @@ result_t DataFieldSet::derive(std::string name, std::string comment, return RESULT_ERR_INVALID_ARG; // value list not allowed in set derive for (std::vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { - result_t result = (*it)->derive("", "", "", partType, offset, divisor, values, fields); + result_t result = (*it)->derive("", "", "", partType, divisor, values, fields); if (result != RESULT_OK) return result; } @@ -944,23 +910,34 @@ result_t DataFieldSet::derive(std::string name, std::string comment, return RESULT_OK; } -result_t DataFieldSet::read(SymbolString& masterData, SymbolString& slaveData, std::ostringstream& output, - bool verbose, char separator) +result_t DataFieldSet::read(SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, + std::ostringstream& output, bool verbose, char separator) { if (verbose) output << m_name << "={ "; bool first = true; + unsigned char offsets[] = { 0, masterOffset, slaveOffset }; + bool previousFullByteOffset[] = { true, true, true }; for (std::vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { if (first) first = false; else output << separator; - result_t result = (*it)->read(masterData, slaveData, output, verbose); + SingleDataField* field = *it; + PartType partType = field->getPartType(); + if (previousFullByteOffset[partType] == 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(); } if (verbose) { @@ -972,24 +949,36 @@ result_t DataFieldSet::read(SymbolString& masterData, SymbolString& slaveData, s return RESULT_OK; } -result_t DataFieldSet::write(std::istringstream& input, SymbolString& masterData, SymbolString& slaveData, +result_t DataFieldSet::write(std::istringstream& input, + SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, char separator) { std::string token; + unsigned char offsets[] = { 0, masterOffset, slaveOffset }; + bool previousFullByteOffset[] = { true, true, true }; for (std::vector::iterator it = m_fields.begin(); it < m_fields.end(); it++) { + SingleDataField* field = *it; + PartType partType = field->getPartType(); + if (previousFullByteOffset[partType] == false) { + offsets[partType]--; + } result_t result; if (m_fields.size() > 1) { if (std::getline(input, token, separator) == 0) return RESULT_ERR_INVALID_ARG; // incomplete std::istringstream single(token); - result = (*it)->write(single, masterData, slaveData); + result = (*it)->write(single, masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], separator); } else - result = (*it)->write(input, masterData, slaveData); + result = (*it)->write(input, masterData, offsets[pt_masterData], slaveData, offsets[pt_slaveData], separator); if (result != RESULT_OK) return result; + + offsets[partType] += field->getLength(partType); + previousFullByteOffset[partType] = field->hasFullByteOffset(); } return RESULT_OK; diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index c2fa4ec4..083df206 100644 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -28,7 +28,7 @@ /** the message part in which a data field is stored. */ enum PartType { - pt_any, // stored in any data (master or slave, relative offset) + pt_any, // stored in any data (master or slave) pt_masterData, // stored in master data pt_slaveData, // stored in slave data }; @@ -53,7 +53,7 @@ const unsigned int DAY = 0x20; // forced value list defaulting to week days /** 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 BCD) + 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 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) @@ -111,24 +111,23 @@ public: const std::map templates, DataField*& returnField, const bool isSetMessage=false, const unsigned char dstAddress=SYN); /** - * @brief Returns the offset to the first symbol in the message part for a field following this field. - * @param partType the message part for which to get the offset, or @a pt_any for any. - * @return the offset to the first symbol in the message part for a field following this field. + * @brief Returns the length of this field (or contained fields) in bytes. + * @param partType the message part of the contained fields to limit the length calculation to. + * @return the length of this field (or contained fields) in bytes. */ - virtual unsigned char getNextOffset(PartType partType=pt_any) = 0; + virtual unsigned char getLength(PartType partType) = 0; /** * @brief Derives a new 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). * @param partType the message part in which the field is stored. - * @param offset the (additional) offset to the first symbol in 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 values the value=text assignments, or empty to use this fields assignments (if applicable). * @param fields the @a std::vector to which created @a SingleDataField instances shall be added. */ virtual result_t derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned char offset, + std::string unit, const PartType partType, unsigned int divisor, std::map values, std::vector& fields) = 0; /** @@ -151,7 +150,9 @@ public: * @param separator the separator character between multiple fields. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t read(SymbolString& masterData, SymbolString& slaveData, std::ostringstream& output, + virtual result_t read(SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, + std::ostringstream& output, bool verbose=false, char separator=';') = 0; /** * @brief Writes the value to the master or slave @a SymbolString. @@ -161,7 +162,9 @@ public: * @param separator the separator character between multiple fields. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t write(std::istringstream& input, SymbolString& masterData, SymbolString& slaveData, + virtual result_t write(std::istringstream& input, + SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, char separator=';') = 0; protected: @@ -188,15 +191,14 @@ public: * @param unit the value unit. * @param dataType the data type definition. * @param partType the message part in which the field is stored. - * @param offset the offset to the first symbol in 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. */ SingleDataField(const std::string name, const std::string comment, const std::string unit, const dataType_t dataType, const PartType partType, - const unsigned char offset, const unsigned char length) + const unsigned char length) : DataField(name, comment), m_unit(unit), m_dataType(dataType), m_partType(partType), - m_offset(offset), m_length(length) {} + m_length(length) {} /** * @brief Destructor. */ @@ -212,44 +214,61 @@ public: */ PartType getPartType() const { return m_partType; } // @copydoc - virtual unsigned char getNextOffset(PartType partType=pt_any); + virtual unsigned char getLength(PartType partType) { return partType == m_partType ? m_length : 0; }; + // 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. + * @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(); /** * @brief Reads the value from the master or slave @a SymbolString. * @param masterData the unescaped master data @a SymbolString for reading binary data. + * @param masterOffset the extra offset for reading master data. * @param slaveData the unescaped slave data @a SymbolString for reading binary data. + * @param slaveOffset the extra offset for reading slave data. * @param output the ostringstream to append the formatted value to. * @param verbose whether to prepend the name, append the unit (if present), and append * the comment in square brackets (if present). * @return @a RESULT_OK on success, or an error code. */ - virtual result_t read(SymbolString& masterData, SymbolString& slaveData, std::ostringstream& output, - bool verbose=false, char separator=';'); + virtual result_t read(SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, + std::ostringstream& output, + bool verbose, char separator); /** * @brief Writes the value to the master or slave @a SymbolString. * @param input the @a std::istringstream to parse the formatted value from. * @param masterData the unescaped master data @a SymbolString for writing binary data. + * @param masterOffset the extra offset for writing master data. * @param slaveData the unescaped slave data @a SymbolString for writing binary data. + * @param slaveOffset the extra offset for writing slave data. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t write(std::istringstream& input, SymbolString& masterData, SymbolString& slaveData, - char separator=';'); + virtual result_t write(std::istringstream& input, + SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, + char separator); protected: /** * @brief Internal method for reading the field from a @a SymbolString. * @param input the unescaped @a SymbolString to read the binary value from. + * @param offset the offset in the @a SymbolString. * @param output the ostringstream to append the formatted value to. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t readSymbols(SymbolString& input, unsigned char baseOffset, std::ostringstream& output) = 0; + virtual result_t readSymbols(SymbolString& input, const unsigned char offset, std::ostringstream& output) = 0; /** * @brief Internal method for writing the field to a @a SymbolString. * @param input the @a std::istringstream to parse the formatted value from. + * @param offset the offset in the @a SymbolString. * @param output the unescaped @a SymbolString to write the binary value to. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t writeSymbols(std::istringstream& input, unsigned char baseOffset, SymbolString& output) = 0; + virtual result_t writeSymbols(std::istringstream& input, const unsigned char offset, SymbolString& output) = 0; /** the value unit. */ const std::string m_unit; @@ -257,8 +276,6 @@ protected: const dataType_t m_dataType; /** the message part in which the field is stored. */ const PartType m_partType; - /** the relative offset to the first symbol in the message part in which the field is stored. */ - const unsigned char m_offset; /** the number of symbols in the message part in which the field is stored. */ const unsigned char m_length; @@ -279,29 +296,28 @@ public: * @param unit the value unit. * @param dataType the data type definition. * @param partType the message part in which the field is stored. - * @param offset the offset to the first symbol in 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. */ StringDataField(const std::string name, const std::string comment, const std::string unit, const dataType_t dataType, const PartType partType, - const unsigned char offset, const unsigned char length) - : SingleDataField(name, comment, unit, dataType, partType, offset, length) {} + const unsigned char length) + : SingleDataField(name, comment, unit, dataType, partType, length) {} /** * @brief Destructor. */ virtual ~StringDataField() {} // @copydoc virtual result_t derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned char offset, + std::string unit, const PartType partType, unsigned int divisor, std::map values, std::vector& fields); protected: // @copydoc - virtual result_t readSymbols(SymbolString& input, unsigned char baseOffset, std::ostringstream& output); + virtual result_t readSymbols(SymbolString& input, const unsigned char offset, std::ostringstream& output); // @copydoc - virtual result_t writeSymbols(std::istringstream& input, unsigned char baseOffset, SymbolString& output); + virtual result_t writeSymbols(std::istringstream& input, const unsigned char offset, SymbolString& output); }; @@ -320,15 +336,13 @@ public: * @param unit the value unit. * @param dataType the data type definition. * @param partType the message part in which the field is stored. - * @param offset the offset to the first symbol in 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 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 offset, const unsigned char length, - const unsigned char bitOffset) - : SingleDataField(name, comment, unit, dataType, partType, offset, length), + const unsigned char length, const unsigned char bitOffset) + : SingleDataField(name, comment, unit, dataType, partType, length), m_bitOffset(bitOffset) {} /** * @brief Destructor. @@ -340,17 +354,19 @@ protected: /** * @brief Internal method for reading the raw value from a @a SymbolString. * @param input the unescaped @a SymbolString to read the binary value from. + * @param offset the offset in the @a SymbolString. * @param value the variable in which to store the raw value. * @return @a RESULT_OK on success, or an error code. */ - result_t readRawValue(SymbolString& input, unsigned char baseOffset, unsigned int& value); + result_t readRawValue(SymbolString& input, const unsigned char offset, unsigned int& value); /** * @brief Internal method for writing the raw value to a @a SymbolString. * @param value the raw value to write. + * @param offset the offset in the @a SymbolString. * @param output the unescaped @a SymbolString to write the binary value to. * @return @a RESULT_OK on success, or an error code. */ - result_t writeRawValue(unsigned int value, unsigned char baseOffset, SymbolString& output); + result_t writeRawValue(unsigned int value, const unsigned char offset, SymbolString& output); /** the offset to the first bit in the binary value. */ const unsigned char m_bitOffset; @@ -372,33 +388,31 @@ public: * @param unit the value unit. * @param dataType the data type definition. * @param partType the message part in which the field is stored. - * @param offset the offset to the first symbol in 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 divisor the extra divisor to apply on the value, or 1 for none. */ NumberDataField(const std::string name, const std::string comment, const std::string unit, const dataType_t dataType, const PartType partType, - const unsigned char offset, const unsigned char length, - const unsigned int divisor) - : NumericDataField(name, comment, unit, dataType, partType, offset, length, + const unsigned char length, const unsigned int divisor) + : NumericDataField(name, comment, unit, dataType, partType, length, (dataType.numBits%8) != 0 ? dataType.precisionOrFirstBit : 0), m_divisor(divisor) {} /** * @brief Destructor. */ virtual ~NumberDataField() {} + // @copydoc + virtual result_t derive(std::string name, std::string comment, + std::string unit, const PartType partType, + unsigned int divisor, std::map values, + std::vector& fields); protected: // @copydoc - virtual result_t derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned char offset, - unsigned int divisor, std::map values, - std::vector& fields); + virtual result_t readSymbols(SymbolString& input, const unsigned char offset, std::ostringstream& output); // @copydoc - virtual result_t readSymbols(SymbolString& input, unsigned char baseOffset, std::ostringstream& output); - // @copydoc - virtual result_t writeSymbols(std::istringstream& input, unsigned char baseOffset, SymbolString& output); + virtual result_t writeSymbols(std::istringstream& input, const unsigned char offset, SymbolString& output); /** the combined divisor to apply on the value, or 1 for none. */ const unsigned int m_divisor; @@ -420,33 +434,31 @@ public: * @param unit the value unit. * @param dataType the data type definition. * @param partType the message part in which the field is stored. - * @param offset the offset to the first symbol in 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 values the value=text assignments. */ ValueListDataField(const std::string name, const std::string comment, const std::string unit, const dataType_t dataType, const PartType partType, - const unsigned char offset, const unsigned char length, - const std::map values) - : NumericDataField(name, comment, unit, dataType, partType, offset, length, + const unsigned char length, const std::map values) + : NumericDataField(name, comment, unit, dataType, partType, length, (dataType.numBits%8) != 0 ? dataType.precisionOrFirstBit : 0), m_values(values) {} /** * @brief Destructor. */ virtual ~ValueListDataField() {} + // @copydoc + virtual result_t derive(std::string name, std::string comment, + std::string unit, const PartType partType, unsigned int divisor, + std::map values, + std::vector& fields); protected: // @copydoc - virtual result_t derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned char offset, - unsigned int divisor, std::map values, - std::vector& fields); + virtual result_t readSymbols(SymbolString& input, const unsigned char offset, std::ostringstream& output); // @copydoc - virtual result_t readSymbols(SymbolString& input, unsigned char baseOffset, std::ostringstream& output); - // @copydoc - virtual result_t writeSymbols(std::istringstream& input, unsigned char baseOffset, SymbolString& output); + virtual result_t writeSymbols(std::istringstream& input, const unsigned char offset, SymbolString& output); /** the value=text assignments. */ std::map m_values; @@ -476,10 +488,10 @@ public: */ virtual ~DataFieldSet(); // @copydoc - virtual unsigned char getNextOffset(PartType partType=pt_any); + virtual unsigned char getLength(PartType partType); // @copydoc virtual result_t derive(std::string name, std::string comment, - std::string unit, const PartType partType, unsigned char offset, + std::string unit, const PartType partType, unsigned int divisor, std::map values, std::vector& fields); /** @@ -499,26 +511,16 @@ public: * @return the number of available @a SingleDataField instances. */ size_t size() const { return m_fields.size(); } - /** - * @brief Reads the values from the master and/or slave @a SymbolString. - * @param masterData the unescaped master data @a SymbolString for reading binary data. - * @param slaveData the unescaped slave data @a SymbolString for reading binary data. - * @param output the @a std::ostringstream to append the formatted value to. - * @param vervose whether to prepend the name, append the unit (if present), and append - * the comment in square brackets (if present). - * @return @a RESULT_OK on success, or an error code. - */ - virtual result_t read(SymbolString& masterData, SymbolString& slaveData, std::ostringstream& output, - bool verbose=false, char separator=';'); - /** - * @brief Writes the values to the master and/or slave @a SymbolString. - * @param input the @a std::istringstream to parse the formatted value from. - * @param masterData the unescaped master data @a SymbolString for writing binary data. - * @param slaveData the unescaped slave data @a SymbolString for writing binary data. - * @return @a RESULT_OK on success, or an error code. - */ - virtual result_t write(std::istringstream& input, SymbolString& masterData, SymbolString& slaveData, - char separator=';'); + // @copydoc + virtual result_t read(SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, + std::ostringstream& output, + bool verbose, char separator); + // @copydoc + virtual result_t write(std::istringstream& input, + SymbolString& masterData, unsigned char masterOffset, + SymbolString& slaveData, unsigned char slaveOffset, + char separator); protected: diff --git a/src/lib/ebus/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp index a689a3b7..c40d8704 100644 --- a/src/lib/ebus/test/test_data.cpp +++ b/src/lib/ebus/test/test_data.cpp @@ -42,22 +42,22 @@ void verify(bool expectFailMatch, std::string type, std::string input, int main() { std::string checks[][5] = { - //name;[pos];type[;[divisor|values][;[unit][;[comment]]]], decoded value, master, slave, flags - {"x;1-10;str", "Hallo, Du!", "10fe07000a48616c6c6f2c20447521", "00", ""}, - {"x;1-10;str", "Hallo, Du ", "10fe07000a48616c6c6f2c20447520", "00", ""}, - {"x;1-10;str", " ", "10fe07000a20202020202020202020", "00", ""}, - {"x;1-11;str", "", "10fe07000a20202020202020202020", "00", "rW"}, + //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;;hex", "20", "10fe07000120", "00", ""}, - {"x;1-10;hex", "48 61 6c 6c 6f 2c 20 44 75 21", "10fe07000a48616c6c6f2c20447521", "00", ""}, - {"x;1-11;hex", "", "10fe07000a48616c6c6f2c20447521", "00", "rW"}, + {"x;10;hex", "48 61 6c 6c 6f 2c 20 44 75 21", "10fe07000a48616c6c6f2c20447521", "00", ""}, + {"x;11;hex", "", "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;1-3;bda","26.10.2014","10fe070003261014", "00", ""}, - {"x;1-3;bda","01.01.2000","10fe070003010100", "00", ""}, - {"x;1-3;bda","31.12.2099","10fe070003311299", "00", ""}, - {"x;1-3;bda","", "10fe070003321299", "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;;bti", "21:04:58", "10fe070003580421", "00", ""}, {"x;;bti", "00:00:00", "10fe070003000000", "00", ""}, {"x;;bti", "23:59:59", "10fe070003595923", "00", ""}, @@ -84,15 +84,11 @@ int main() {"x;;bcd", "99", "10feffff0199", "00", ""}, {"x;;bcd", "-", "10feffff01ff", "00", ""}, {"x;;bcd", "", "10feffff019a", "00", "rw"}, - {"x;16;uch", "15", "10feffff11000102030405060708090a0b0c0d0e0f10", "00", "W"}, + {"x;16;str", "0123456789ABCDEF", "10feffff1130313233343536373839414243444546", "00", ""}, {"x;17;uch", "", "10feffff00", "00", "c"}, - {"x;s3;uch", "2", "1025ffff0310111213", "0300010203", "W"}, - {"x;s3;uch", "2", "1025ffff00", "03000002", ""}, - {"x;3;uch", "2", "1025ffff03010101", "03000002", "W"}, - {"x;3;uch", "1", "1025ffff03010101", "03000002", "sW"}, - {"x;1;uch", "2", "1025ffff00", "0102", ""}, - {"x;1;uch", "1", "1025ffff0101", "00", "s"}, - {"x;s3;uch;;;;y;m2;uch", "2;3","1025ffff020003", "03000002", ""}, + {"x;s;uch", "0", "1025ffff0310111213", "0300010203", "W"}, + {"x;s;uch", "0", "1025ffff00", "0100", ""}, + {"x;s;uch;;;;y;m;uch", "2;3","1025ffff0103", "0102", ""}, {"x;;uch", "38", "10feffff0126", "00", ""}, {"x;;uch", "0", "10feffff0100", "00", ""}, {"x;;uch", "254", "10feffff01fe", "00", ""}, @@ -161,10 +157,9 @@ int main() {"x;;b34;0=off,1=on","on", "10feffff0108", "00", ""}, {"x;;b34;0=off,1=on","off","10feffff0100", "00", ""}, {"x;;uch;1=test,2=high,3=off,4=on","on","10feffff0104", "00", ""}, - {"x;s3;uch","3","1050ffff00", "03000003", ""}, - {"x;s3;uch","3","1050ffff00", "020000", "rW"}, + {"x;s;uch","3","1050ffff00", "0103", ""}, {"x;;d2b;;°C;Aussentemperatur","x=18.004 °C [Aussentemperatur]","10fe0700090112", "00", "v"}, - {"x;;bti;;;;y;;bda;;;;z;6;bdy", "21:04:58;26.10.2014;Sun","10fe07000758042126100614", "00", ""}, // combination + {"x;;bti;;;;y;;bda;;;;z;;bdy", "21:04:58;26.10.2014;Sun","10fe0700085804212610001406", "00", ""}, // combination {"x;;bi3;;;;y;;bi5", "1;-", "10feffff0108", "00", ""}, // bit combination {"x;;bi3;;;;y;;bi5", "1;1", "10feffff0128", "00", ""}, // bit combination {"x;;bi3;;;;y;;bi5", "-;1", "10feffff0120", "00", ""}, // bit combination @@ -173,25 +168,10 @@ int main() {"x;;bi3;;;;y;;bi5;;;;t;;uch", "-;-;9","10feffff020009", "00", "RW"}, // bit combination {"temp;;d2b;;°C;Aussentemperatur","","", "", "t"}, // template with relative pos {"x;;temp","18.004","10fe0700020112", "00", ""}, // reference to template - {"tempoff;2;d2b;;°C;Aussentemperatur","","", "", "t"},// template with offset pos - {"x;;tempoff","18.004","10fe070002ff0112", "00", "W"}, // reference to template {"relrel;;d2b;;;;y;;d1c","","", "", "t"}, // template struct with relative pos - {"x;2;relrel","18.004;9.5","10fe070004ff011213", "00", "W"}, // reference to template struct - {"reloff;;d2b;;;;y;1;d1c","","", "", "t"}, // template struct with relative+offset pos - {"x;2;reloff","18.004;0.5","10fe070003130112", "00", "W"}, // reference to template struct - {"offrel;2;d2b;;;;y;;d1c","","", "", "t"}, // template struct with offset+relative pos - {"x;2;offrel","18.004;9.5","10fe070005fffe011213", "00", "W"}, // reference to template struct - {"offoff;2;d2b;;;;y;1;d1c","","", "", "t"}, // template struct with offset pos - {"x;2;offoff","18.004;9.5","10fe070004ff130112", "00", "W"}, // reference to template struct + {"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 {"x;;trelrel","18.004;19.008","10fe07000401120213", "00", ""}, // reference to template struct - {"x;2;trelrel","18.004;19.008","10fe070005ff01120213", "00", "W"}, // reference to template struct - {"treloff;;temp,tempoff","","", "", "t"}, // template struct with relative+offset pos - {"x;2;treloff","18.004;19.008","10fe070006ff0112fe0213", "00", "W"}, // reference to template struct - {"toffrel;1;tempoff,temp","","", "", "t"}, // template struct with offset+relative pos - {"x;2;toffrel","18.004;19.008","10fe070003fffe01120213", "00", "W"}, // reference to template struct - {"toffoff;1;tempoff,tempoff","","", "", "t"}, // template struct with offset pos - {"x;2;toffoff","18.004;19.008","10fe070003fffe0112fd0213", "00", "W"}, // reference to template struct }; std::map templates; DataField* fields = NULL; @@ -261,7 +241,7 @@ int main() std::ostringstream output; SymbolString writeMstr = SymbolString(mstr.getDataStr().substr(0, 10), false); SymbolString writeSstr = SymbolString(sstr.getDataStr().substr(0, 2), false); - result = fields->read(mstr, sstr, output, verbose); + result = fields->read(mstr, 0, sstr, 0, output, verbose); if (failedRead == true) if (result == RESULT_OK) std::cout << " failed read " << fields->getName() << " >" @@ -280,7 +260,7 @@ int main() if (verbose == false) { std::istringstream input(expectStr); - result = fields->write(input, writeMstr, writeSstr); + result = fields->write(input, writeMstr, 0, writeSstr, 0); if (failedWrite == true) { if (result == RESULT_OK) std::cout << " failed write " << fields->getName() << " >"