From c26f7b3b07f61af17771b9234088eabf089388df Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 29 Jun 2019 08:16:26 +0200 Subject: [PATCH] also detect subsequent fields with less than 8 bits not fitting into 1 byte --- src/lib/ebus/data.cpp | 34 ++++++++++++++++++++++----------- src/lib/ebus/data.h | 5 ++++- src/lib/ebus/test/test_data.cpp | 3 +++ 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 3f47def2..483d923f 100755 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -647,8 +647,11 @@ size_t SingleDataField::getLength(PartType partType, size_t maxLength) const { return remainder ? maxLength : m_length; } -bool SingleDataField::hasFullByteOffset(bool after) const { +bool SingleDataField::hasFullByteOffset(bool after, int16_t& previousFirstBit) const { if (m_length > 1) { + if (after) { + previousFirstBit = -1; + } return true; } int16_t firstBit; @@ -658,8 +661,13 @@ bool SingleDataField::hasFullByteOffset(bool after) const { } else { firstBit = 0; } - return (m_dataType->getBitCount() % 8) == 0 - || (after && firstBit + (m_dataType->getBitCount() % 8) >= 8); + bool ret = (m_dataType->getBitCount() % 8) == 0 + || (firstBit == previousFirstBit) || (after && firstBit + (m_dataType->getBitCount() % 8) >= 8); + // std::cout<<(after?"after,":"before,")<<"prev="<(previousFirstBit)<<",first="<(firstBit)<<",length="<(m_dataType->getBitCount())<<" => "<<(ret?"true":"false")<<"\n"; + if (after) { + previousFirstBit = ret ? -1 : firstBit; + } + return ret; } size_t SingleDataField::getCount(PartType partType, const char* fieldName) const { @@ -915,9 +923,10 @@ const DataFieldSet* DataFieldSet::clone() const { size_t DataFieldSet::getLength(PartType partType, size_t maxLength) const { size_t length = 0; bool previousFullByteOffset[] = { true, true, true, true }; + int16_t previousFirstBit[] = { -1, -1, -1, -1 }; for (const auto field : m_fields) { if (field->getPartType() == partType) { - if (!previousFullByteOffset[partType] && !field->hasFullByteOffset(false)) { + if (!previousFullByteOffset[partType] && !field->hasFullByteOffset(false, previousFirstBit[partType])) { length--; } size_t fieldLength = field->getLength(partType, maxLength); @@ -928,7 +937,7 @@ size_t DataFieldSet::getLength(PartType partType, size_t maxLength) const { } length = length + fieldLength; - previousFullByteOffset[partType] = field->hasFullByteOffset(true); + previousFullByteOffset[partType] = field->hasFullByteOffset(true, previousFirstBit[partType]); } } @@ -1010,12 +1019,13 @@ void DataFieldSet::dump(bool prependFieldSeparator, bool asJson, ostream* output result_t DataFieldSet::read(const SymbolString& data, size_t offset, const char* fieldName, ssize_t fieldIndex, unsigned int* output) const { bool previousFullByteOffset = true, found = false, findFieldIndex = fieldIndex >= 0; + int16_t previousFirstBit = -1; PartType partType = data.isMaster() ? pt_masterData : pt_slaveData; for (const auto field : m_fields) { if (field->getPartType() != partType) { continue; } - if (!previousFullByteOffset && !field->hasFullByteOffset(false)) { + if (!previousFullByteOffset && !field->hasFullByteOffset(false, previousFirstBit)) { offset--; } result_t result = field->read(data, offset, fieldName, fieldIndex, output); @@ -1023,7 +1033,7 @@ result_t DataFieldSet::read(const SymbolString& data, size_t offset, return result; } offset += field->getLength(partType, data.getDataSize()-offset); - previousFullByteOffset = field->hasFullByteOffset(true); + previousFullByteOffset = field->hasFullByteOffset(true, previousFirstBit); if (result != RESULT_EMPTY) { found = true; } @@ -1049,6 +1059,7 @@ result_t DataFieldSet::read(const SymbolString& data, size_t offset, bool leadingSeparator, const char* fieldName, ssize_t fieldIndex, OutputFormat outputFormat, ssize_t outputIndex, ostream* output) const { bool previousFullByteOffset = true, found = false, findFieldIndex = fieldIndex >= 0; + int16_t previousFirstBit = -1; if (outputIndex < 0 && (!m_uniqueNames || ((outputFormat & OF_JSON) && !(outputFormat & OF_NAMES)))) { outputIndex = 0; } @@ -1060,7 +1071,7 @@ result_t DataFieldSet::read(const SymbolString& data, size_t offset, } continue; } - if (!previousFullByteOffset && !field->hasFullByteOffset(false)) { + if (!previousFullByteOffset && !field->hasFullByteOffset(false, previousFirstBit)) { offset--; } result_t result = field->read(data, offset, leadingSeparator, fieldName, fieldIndex, @@ -1069,7 +1080,7 @@ result_t DataFieldSet::read(const SymbolString& data, size_t offset, return result; } offset += field->getLength(partType, data.getDataSize()-offset); - previousFullByteOffset = field->hasFullByteOffset(true); + previousFullByteOffset = field->hasFullByteOffset(true, previousFirstBit); if (result != RESULT_EMPTY) { found = true; leadingSeparator = true; @@ -1099,12 +1110,13 @@ result_t DataFieldSet::write(char separator, size_t offset, istringstream* input string token; PartType partType = data->isMaster() ? pt_masterData : pt_slaveData; bool previousFullByteOffset = true; + int16_t previousFirstBit = -1; size_t baseOffset = offset; for (const auto field : m_fields) { if (field->getPartType() != partType) { continue; } - if (!previousFullByteOffset && !field->hasFullByteOffset(false)) { + if (!previousFullByteOffset && !field->hasFullByteOffset(false, previousFirstBit)) { offset--; } result_t result; @@ -1124,7 +1136,7 @@ result_t DataFieldSet::write(char separator, size_t offset, istringstream* input return result; } offset += fieldLength; - previousFullByteOffset = field->hasFullByteOffset(true); + previousFullByteOffset = field->hasFullByteOffset(true, previousFirstBit); } if (usedLength != nullptr) { diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index b6256feb..4d9eb34c 100755 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -401,10 +401,13 @@ class SingleDataField : public DataField { /** * Get whether this field uses a full byte offset. * @param after @p true to check after consuming the bits, @p false to check before. + * @param previousFirstBit the index to the first bit of the previous field, or -1 + * if the previous field used a full byte offset. Will be updated during the call + * when after was true. * @return @p true if this field uses a full byte offset, @p false if this field * only consumes a part of a byte and a subsequent field may re-use the same offset. */ - bool hasFullByteOffset(bool after) const; + bool hasFullByteOffset(bool after, int16_t& previousFirstBit) const; // @copydoc size_t getCount(PartType partType = pt_any, const char* fieldName = nullptr) const override; diff --git a/src/lib/ebus/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp index 3ca8fd9a..13b812dc 100755 --- a/src/lib/ebus/test/test_data.cpp +++ b/src/lib/ebus/test/test_data.cpp @@ -228,6 +228,9 @@ int main() { {"x,,ttq", "23:45", "10fe0700015f", "00", ""}, {"x,,ttq", "24:00", "10fe07000160", "00", ""}, {"x,,ttq", "-:-", "10fe07000100", "00", ""}, + {"x,,ttq,,,,,,ttq", "23:00;05:45", "10fe0700025c17", "00", ""}, + {"x,,ttq,,,,,,bi7,,,,,,ttq", "23:00;0;05:45", "10fe0700025c17", "00", ""}, + {"x,,ttq,,,,,,bi7,,,,,,ttq", "23:00;1;05:45", "10fe070002dc17", "00", ""}, {"x,,ttq", "", "10fe07000161", "00", "rw"}, {"x,,ttq,2", "", "", "", "c"}, {"x,,ttq,,,,y,,bi7", "23:45;0", "10fe0700015f", "00", ""}, // bit combination