diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e9f9c09..dd97995b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Added +- `hk::Dataset::deSerializeWithValidityBlob`, the counterpart of serializing with validity blob - functions to configure pus routing - FreeRTOS monotonic clock which is not subjected to time jumps of the system clock - add CFDP subsystem ID diff --git a/src/fsfw/housekeeping/Dataset.h b/src/fsfw/housekeeping/Dataset.h index d48129c3..1b428221 100644 --- a/src/fsfw/housekeeping/Dataset.h +++ b/src/fsfw/housekeeping/Dataset.h @@ -118,6 +118,35 @@ class Dataset : public SerializeIF { return result; } + /** + * Counterpart of doSerializeWithValidityBlob: reads the values, then sets the validity of each + * serializable from the validity blob. deSerialize ignores the blob. + */ + ReturnValue_t deSerializeWithValidityBlob(const uint8_t **buffer, size_t *size, + const Endianness streamEndianness) { + const size_t validityMaskSize = (serializables.size() + 7) / 8; + size_t valuesSize = 0; + for (auto &serializable : serializables) { + valuesSize += serializable.get().getSerializedSize(); + } + // Checked up front so a short stream leaves the dataset untouched + if (*size < valuesSize + validityMaskSize) { + return SerializeIF::STREAM_TOO_SHORT; + } + ReturnValue_t result = Dataset::deSerialize(buffer, size, streamEndianness); + if (result != returnvalue::OK) { + return result; + } + for (size_t idx = 0; idx < serializables.size(); idx++) { + bool valid = false; + bitutil::get(*buffer + idx / 8, idx % 8, valid); + serializables[idx].get().setValid(valid); + } + *buffer += validityMaskSize; + *size -= validityMaskSize; + return returnvalue::OK; + } + bool serializeWithValidityBlob = false; private: diff --git a/unittests/datapool/testDataset.cpp b/unittests/datapool/testDataset.cpp index 0d2c048c..af177bff 100644 --- a/unittests/datapool/testDataset.cpp +++ b/unittests/datapool/testDataset.cpp @@ -82,4 +82,52 @@ TEST_CASE("Pool Dataset Test", "[datapool]") { CHECK(buf[31] == 0b10000000); CHECK(buf[32] == 0); } + + SECTION("Pool Dataset Deserialization With Validity") { + uint8_t buf[64]{}; + TestDatasetLarger source; + source.setChildrenValidity(true); + source.test1 = 502392; + source.test1.setValid(false); + source.test7 = -5; + source.test8.entry[1] = 1234; + source.test8.setValid(false); + source.serializeWithValidityBlob = true; + size_t serLen = 0; + uint8_t* dataPtr = buf; + REQUIRE(source.serialize(&dataPtr, &serLen, sizeof(buf), SerializeIF::Endianness::NETWORK) == + returnvalue::OK); + + TestDatasetLarger target; + target.setChildrenValidity(true); + const uint8_t* readPtr = buf; + size_t remaining = serLen; + CHECK(target.deSerializeWithValidityBlob(&readPtr, &remaining, + SerializeIF::Endianness::NETWORK) == returnvalue::OK); + CHECK(remaining == 0); + CHECK(readPtr == buf + serLen); + CHECK(target.test0.isValid()); + CHECK(!target.test1.isValid()); + CHECK(target.test1.get() == 502392); + CHECK(target.test7.isValid()); + CHECK(target.test7.get() == -5); + CHECK(!target.test8.isValid()); + CHECK(target.test8.entry[1] == 1234); + } + + SECTION("Pool Dataset Deserialization With Validity Short Stream") { + uint8_t buf[64]{}; + TestDatasetSmall target; + target.test0 = 7; + target.test0.setValid(true); + const uint8_t* readPtr = buf; + // One byte short of the 5 value bytes and the 1 byte validity blob + size_t remaining = 5; + CHECK(target.deSerializeWithValidityBlob(&readPtr, &remaining, + SerializeIF::Endianness::NETWORK) == + SerializeIF::STREAM_TOO_SHORT); + CHECK(remaining == 5); + CHECK(target.test0.get() == 7); + CHECK(target.test0.isValid()); + } }