From 80a2b02345084f233849aaea9763b69d81e05d7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Fr=C3=B6jdh?= Date: Tue, 9 Dec 2025 18:27:02 +0100 Subject: [PATCH] Dev/decode my302 (#254) This PR adds support for decoding digital data from the my320 test chip. - Added BitOffset (strong type) - Expand 24 to 32 bit - Python bindings for decoding my302 - Improved docs --- RELEASE.md | 6 ++ docs/CMakeLists.txt | 18 ++-- docs/src/index.rst | 19 ++-- docs/src/pyCtbRawFile.rst | 11 --- docs/src/python/cluster/index.rst | 11 +++ docs/src/{ => python/cluster}/pyCluster.rst | 0 .../{ => python/cluster}/pyClusterVector.rst | 0 .../{ => python/cluster}/pyInterpolation.rst | 16 ++-- .../cluster}/pyVarClusterFinder.rst | 0 docs/src/python/file/index.rst | 14 +++ docs/src/{ => python/file}/pyClusterFile.rst | 0 docs/src/python/file/pyCtbRawFile.rst | 25 +++++ docs/src/{ => python/file}/pyFile.rst | 0 .../{ => python/file}/pyJungfrauDataFile.rst | 0 docs/src/{ => python/file}/pyRawFile.rst | 0 .../src/{ => python/file}/pyRawMasterFile.rst | 0 docs/src/python/file/pyTransform.rst | 27 ++++++ include/aare/decode.hpp | 22 ++++- include/aare/defs.hpp | 11 +++ python/aare/transform.py | 37 ++++++++ python/src/ctb_raw_file.hpp | 63 +++++++++++++ src/CtbRawFile.cpp | 1 - src/NDView.test.cpp | 9 ++ src/decode.cpp | 46 ++++++++++ src/decode.test.cpp | 92 +++++++++++++++++++ src/defs.cpp | 18 ++++ src/defs.test.cpp | 22 +++++ 27 files changed, 427 insertions(+), 41 deletions(-) delete mode 100644 docs/src/pyCtbRawFile.rst create mode 100644 docs/src/python/cluster/index.rst rename docs/src/{ => python/cluster}/pyCluster.rst (100%) rename docs/src/{ => python/cluster}/pyClusterVector.rst (100%) rename docs/src/{ => python/cluster}/pyInterpolation.rst (88%) rename docs/src/{ => python/cluster}/pyVarClusterFinder.rst (100%) create mode 100644 docs/src/python/file/index.rst rename docs/src/{ => python/file}/pyClusterFile.rst (100%) create mode 100644 docs/src/python/file/pyCtbRawFile.rst rename docs/src/{ => python/file}/pyFile.rst (100%) rename docs/src/{ => python/file}/pyJungfrauDataFile.rst (100%) rename docs/src/{ => python/file}/pyRawFile.rst (100%) rename docs/src/{ => python/file}/pyRawMasterFile.rst (100%) create mode 100644 docs/src/python/file/pyTransform.rst diff --git a/RELEASE.md b/RELEASE.md index 76f9636..fff69b9 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,5 +1,11 @@ # Release notes +## head + +### New Features: + +- Expanding 24 to 32 bit data +- Decoding digital data from Mythen 302 ### 2025.11.21 diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 78ffe82..9a25869 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -12,15 +12,19 @@ set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src) set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}) -file(GLOB SPHINX_SOURCE_FILES CONFIGURE_DEPENDS "src/*.rst") +file(GLOB_RECURSE SPHINX_SOURCE_FILES + CONFIGURE_DEPENDS + RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/src" + "${CMAKE_CURRENT_SOURCE_DIR}/src/*.rst" +) +foreach(relpath IN LISTS SPHINX_SOURCE_FILES) + set(src "${CMAKE_CURRENT_SOURCE_DIR}/src/${relpath}") + set(dst "${SPHINX_BUILD}/src/${relpath}") - -foreach(filename ${SPHINX_SOURCE_FILES}) - get_filename_component(fname ${filename} NAME) - message(STATUS "Copying ${filename} to ${SPHINX_BUILD}/src/${fname}") - configure_file(${filename} "${SPHINX_BUILD}/src/${fname}") -endforeach(filename ${SPHINX_SOURCE_FILES}) + message(STATUS "Copying ${src} to ${dst}") + configure_file("${src}" "${dst}" COPYONLY) +endforeach() configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in" diff --git a/docs/src/index.rst b/docs/src/index.rst index e7645b6..834c490 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -22,21 +22,14 @@ AARE .. toctree:: :caption: Python API - :maxdepth: 1 - - pyFile - pycalibration - pyCtbRawFile - pyClusterFile - pyClusterVector - pyCluster - pyInterpolation - pyJungfrauDataFile - pyRawFile - pyRawMasterFile - pyVarClusterFinder + :maxdepth: 3 + :hidden: + pycalibration + python/cluster/index + python/file/index pyFit + .. toctree:: diff --git a/docs/src/pyCtbRawFile.rst b/docs/src/pyCtbRawFile.rst deleted file mode 100644 index 6f0822d..0000000 --- a/docs/src/pyCtbRawFile.rst +++ /dev/null @@ -1,11 +0,0 @@ - -CtbRawFile -============ - -.. py:currentmodule:: aare - -.. autoclass:: CtbRawFile - :members: - :undoc-members: - :show-inheritance: - :inherited-members: \ No newline at end of file diff --git a/docs/src/python/cluster/index.rst b/docs/src/python/cluster/index.rst new file mode 100644 index 0000000..7f21894 --- /dev/null +++ b/docs/src/python/cluster/index.rst @@ -0,0 +1,11 @@ +Cluster & Interpolation +========================== + +.. toctree:: + :caption: Cluster & Interpolation + :maxdepth: 1 + + pyCluster + pyClusterVector + pyInterpolation + pyVarClusterFinder diff --git a/docs/src/pyCluster.rst b/docs/src/python/cluster/pyCluster.rst similarity index 100% rename from docs/src/pyCluster.rst rename to docs/src/python/cluster/pyCluster.rst diff --git a/docs/src/pyClusterVector.rst b/docs/src/python/cluster/pyClusterVector.rst similarity index 100% rename from docs/src/pyClusterVector.rst rename to docs/src/python/cluster/pyClusterVector.rst diff --git a/docs/src/pyInterpolation.rst b/docs/src/python/cluster/pyInterpolation.rst similarity index 88% rename from docs/src/pyInterpolation.rst rename to docs/src/python/cluster/pyInterpolation.rst index 5b5dc68..43f4d37 100644 --- a/docs/src/pyInterpolation.rst +++ b/docs/src/python/cluster/pyInterpolation.rst @@ -21,8 +21,8 @@ Supported are the following :math:`\eta`-functions: .. py:currentmodule:: aare -.. image:: ../figures/Eta2x2.png - :target: ../figures/Eta2x2.png +.. image:: ../../../figures/Eta2x2.png + :target: ../../../figures/Eta2x2.png :width: 650px :align: center :alt: Eta2x2 @@ -35,8 +35,8 @@ Supported are the following :math:`\eta`-functions: .. autofunction:: calculate_eta2 -.. image:: ../figures/Eta2x2Full.png - :target: ../figures/Eta2x2Full.png +.. image:: ../../../figures/Eta2x2Full.png + :target: ../../../figures/Eta2x2Full.png :width: 650px :align: center :alt: Eta2x2 Full @@ -49,8 +49,8 @@ Supported are the following :math:`\eta`-functions: .. autofunction:: calculate_full_eta2 -.. image:: ../figures/Eta3x3.png - :target: ../figures/Eta3x3.png +.. image:: ../../../figures/Eta3x3.png + :target: ../../../figures/Eta3x3.png :width: 650px :align: center :alt: Eta3x3 @@ -63,8 +63,8 @@ Supported are the following :math:`\eta`-functions: .. autofunction:: calculate_eta3 -.. image:: ../figures/Eta3x3Cross.png - :target: ../figures/Eta3x3Cross.png +.. image:: ../../../figures/Eta3x3Cross.png + :target: ../../../figures/Eta3x3Cross.png :width: 650px :align: center :alt: Cross Eta3x3 diff --git a/docs/src/pyVarClusterFinder.rst b/docs/src/python/cluster/pyVarClusterFinder.rst similarity index 100% rename from docs/src/pyVarClusterFinder.rst rename to docs/src/python/cluster/pyVarClusterFinder.rst diff --git a/docs/src/python/file/index.rst b/docs/src/python/file/index.rst new file mode 100644 index 0000000..0bcc4f9 --- /dev/null +++ b/docs/src/python/file/index.rst @@ -0,0 +1,14 @@ +File I/O +=================== + +.. toctree:: + :caption: File I/O + :maxdepth: 1 + + pyClusterFile + pyCtbRawFile + pyFile + pyJungfrauDataFile + pyRawFile + pyRawMasterFile + pyTransform diff --git a/docs/src/pyClusterFile.rst b/docs/src/python/file/pyClusterFile.rst similarity index 100% rename from docs/src/pyClusterFile.rst rename to docs/src/python/file/pyClusterFile.rst diff --git a/docs/src/python/file/pyCtbRawFile.rst b/docs/src/python/file/pyCtbRawFile.rst new file mode 100644 index 0000000..75d8355 --- /dev/null +++ b/docs/src/python/file/pyCtbRawFile.rst @@ -0,0 +1,25 @@ + +CtbRawFile +============ + +Read analog, digital and transceiver samples from a raw file containing +data from the Chip Test Board. Uses :mod:`aare.transform` to decode the +data into a format that the user can work with. + +.. code:: python + + import aare + from aare.transform import Mythen302Transform + my302 = Mythen302Transform(offset = 4) + + with aare.CtbRawFile(fname, transform = my302) as f: + for header, data in f: + #do something with the data + +.. py:currentmodule:: aare + +.. autoclass:: CtbRawFile + :members: + :undoc-members: + :show-inheritance: + :inherited-members: \ No newline at end of file diff --git a/docs/src/pyFile.rst b/docs/src/python/file/pyFile.rst similarity index 100% rename from docs/src/pyFile.rst rename to docs/src/python/file/pyFile.rst diff --git a/docs/src/pyJungfrauDataFile.rst b/docs/src/python/file/pyJungfrauDataFile.rst similarity index 100% rename from docs/src/pyJungfrauDataFile.rst rename to docs/src/python/file/pyJungfrauDataFile.rst diff --git a/docs/src/pyRawFile.rst b/docs/src/python/file/pyRawFile.rst similarity index 100% rename from docs/src/pyRawFile.rst rename to docs/src/python/file/pyRawFile.rst diff --git a/docs/src/pyRawMasterFile.rst b/docs/src/python/file/pyRawMasterFile.rst similarity index 100% rename from docs/src/pyRawMasterFile.rst rename to docs/src/python/file/pyRawMasterFile.rst diff --git a/docs/src/python/file/pyTransform.rst b/docs/src/python/file/pyTransform.rst new file mode 100644 index 0000000..1101065 --- /dev/null +++ b/docs/src/python/file/pyTransform.rst @@ -0,0 +1,27 @@ +Transform +=================== + +The transform module takes data read by :class:`aare.CtbRawFile` and decodes it +to a useful image format. Depending on detector it supports both analog +and digital samples. + +For convenience the following transform objects are defined with a short name + +.. code:: python + + moench05 = Moench05Transform() + moench05_1g = Moench05Transform1g() + moench05_old = Moench05TransformOld() + matterhorn02 = Matterhorn02Transform() + adc_sar_04_64to16 = AdcSar04Transform64to16() + adc_sar_05_64to16 = AdcSar05Transform64to16() + +.. py:currentmodule:: aare + +.. automodule:: aare.transform + :members: + :undoc-members: + :private-members: + :special-members: __call__ + :show-inheritance: + :inherited-members: \ No newline at end of file diff --git a/include/aare/decode.hpp b/include/aare/decode.hpp index fc2b1e1..3cec22d 100644 --- a/include/aare/decode.hpp +++ b/include/aare/decode.hpp @@ -1,11 +1,12 @@ // SPDX-License-Identifier: MPL-2.0 #pragma once - +#include "aare/defs.hpp" #include #include #include namespace aare { + uint16_t adc_sar_05_decode64to16(uint64_t input); uint16_t adc_sar_04_decode64to16(uint64_t input); void adc_sar_05_decode64to16(NDView input, @@ -13,6 +14,25 @@ void adc_sar_05_decode64to16(NDView input, void adc_sar_04_decode64to16(NDView input, NDView output); +/** + * @brief Called with a 32 bit unsigned integer, shift by offset + * and then return the lower 24 bits as an 32 bit integer + * @param input 32-ibt input value + * @param offset (should be in range 0-7 to allow for full 24 bits) + * @return uint32_t + */ +uint32_t mask32to24bits(uint32_t input, BitOffset offset={}); + +/** + * @brief Expand 24 bit values in a 8bit buffer to 32bit unsigned integers + * Used for detectors with 24bit counters in combination with CTB + * + * @param input View of the 24 bit data as uint8_t (no 24bit native data type exists) + * @param output Destination of the expanded data (32bit, unsigned) + * @param offset Offset within the first byte to where the data starts (0-7 bits) + */ +void expand24to32bit(NDView input, NDView output, BitOffset offset={}); + /** * @brief Apply custom weights to a 16-bit input value. Will sum up * weights[i]**i for each bit i that is set in the input value. diff --git a/include/aare/defs.hpp b/include/aare/defs.hpp index 1f75131..c92d247 100644 --- a/include/aare/defs.hpp +++ b/include/aare/defs.hpp @@ -372,4 +372,15 @@ constexpr uint16_t ADC_MASK = */ template <> DACIndex StringTo(const std::string &arg); +class BitOffset{ + uint8_t m_offset{}; + public: + BitOffset() = default; + explicit BitOffset(uint32_t offset); + uint8_t value() const {return m_offset;} + bool operator==(const BitOffset& other) const; + bool operator<(const BitOffset& other) const; + +}; + } // namespace aare \ No newline at end of file diff --git a/python/aare/transform.py b/python/aare/transform.py index efcba28..fddfc1e 100644 --- a/python/aare/transform.py +++ b/python/aare/transform.py @@ -49,6 +49,43 @@ class Matterhorn02Transform: else: return np.take(data.view(np.uint16), self.pixel_map[0:counters]) +class Mythen302Transform: + """ + Transform Mythen 302 test chip data from a buffer of bytes (uint8_t) + to a uint32 numpy array of [64,3] representing channels and counters. + Assumes data taken with rx_dbitlist 17 6, rx_dbitreorder 1 and Digital + Samples = 2310 [(64x3x24)/2 + some extra] + + .. note:: + + The offset is in number of bits 0-7 + + """ + _n_channels = 64 + _n_counters = 3 + + def __init__(self, offset=4): + self.offset = offset + + def __call__(self, data : np.ndarray): + """ + Transform buffer of data to a [64,3] np.ndarray of uint32. + + Parameters + ---------- + data : np.ndarray + Expected dtype: uint8 + + Returns + ---------- + image : np.ndarray + uint32 array of size 64, 3 + """ + res = _aare.decode_my302(data, self.offset) + res = res.reshape( + Mythen302Transform._n_channels, Mythen302Transform._n_counters + ) + return res #on import generate the pixel maps to avoid doing it every time moench05 = Moench05Transform() diff --git a/python/src/ctb_raw_file.hpp b/python/src/ctb_raw_file.hpp index 6e6aa51..a6702bd 100644 --- a/python/src/ctb_raw_file.hpp +++ b/python/src/ctb_raw_file.hpp @@ -96,6 +96,69 @@ void define_ctb_raw_file_io_bindings(py::module &m) { return output; }); + m.def("expand24to32bit", + [](py::array_t + &input, uint32_t offset){ + + aare::BitOffset bitoff(offset); + py::buffer_info buf = input.request(); + + constexpr uint32_t bytes_per_channel = 3; //24 bit + py::array_t output(buf.size/bytes_per_channel); + + NDView input_view(input.mutable_data(), + {input.size()}); + NDView output_view(output.mutable_data(), + {output.size()}); + + aare::expand24to32bit(input_view, output_view, bitoff); + return output; + + }); + + m.def("decode_my302", + [](py::array_t + &input, uint32_t offset){ + + // Physical layout of the chip + constexpr size_t channels = 64; + constexpr size_t counters = 3; + constexpr size_t bytes_per_channel = 3; //24 bit + constexpr int n_outputs = 2; + + ssize_t expected_size = channels*counters*bytes_per_channel; + + //If whe have an offset we need one extra byte per output + aare::BitOffset bitoff(offset); + if(bitoff.value()) + expected_size += n_outputs; + + if (input.size() != expected_size) { + throw std::runtime_error( + fmt::format("{} Expected an input size of {} bytes. Called " + "with input size of {}", + LOCATION, expected_size, input.size())); + } + + py::buffer_info buf = input.request(); + py::array_t output(channels * counters); + + for (int i = 0; i!=n_outputs; ++i){ + auto step = input.size()/n_outputs; + auto out_step = output.size()/n_outputs; + NDView input_view(input.mutable_data()+step*i, + {input.size()/n_outputs}); + NDView output_view(output.mutable_data()+out_step*i, + {output.size()/n_outputs}); + + aare::expand24to32bit(input_view, output_view, bitoff); + + } + + return output; + + }); + py::class_(m, "CtbRawFile") .def(py::init()) .def("read_frame", diff --git a/src/CtbRawFile.cpp b/src/CtbRawFile.cpp index c3e2910..8b8d3e5 100644 --- a/src/CtbRawFile.cpp +++ b/src/CtbRawFile.cpp @@ -61,7 +61,6 @@ void CtbRawFile::find_subfiles() { while (std::filesystem::exists(m_master.data_fname(0, m_num_subfiles))) m_num_subfiles++; - fmt::print("Found {} subfiles\n", m_num_subfiles); } void CtbRawFile::open_data_file(size_t subfile_index) { diff --git a/src/NDView.test.cpp b/src/NDView.test.cpp index c6de3bf..1b77907 100644 --- a/src/NDView.test.cpp +++ b/src/NDView.test.cpp @@ -5,6 +5,7 @@ #include #include #include +#include using aare::NDView; using aare::Shape; @@ -259,4 +260,12 @@ TEST_CASE("Create a view over a vector") { REQUIRE(v.shape()[0] == 12); REQUIRE(v[0] == 0); REQUIRE(v[11] == 11); +} + +TEST_CASE("NDView over byte"){ + std::vector buf(5); + auto v = aare::make_view(buf); + REQUIRE(v.shape()[0] == 5); + REQUIRE(v[0] == std::byte{0}); + } \ No newline at end of file diff --git a/src/decode.cpp b/src/decode.cpp index ef3ad44..2de470f 100644 --- a/src/decode.cpp +++ b/src/decode.cpp @@ -1,5 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 #include "aare/decode.hpp" +#include #include namespace aare { @@ -105,4 +106,49 @@ void apply_custom_weights(NDView input, NDView output, } } +uint32_t mask32to24bits(uint32_t input, BitOffset offset){ + constexpr uint32_t mask24bits{0xFFFFFF}; + return (input >> offset.value()) & mask24bits; +} + +void expand24to32bit(NDView input, NDView output, BitOffset bit_offset){ + + ssize_t bytes_per_channel = 3; //24bit + ssize_t min_input_size = output.size()*bytes_per_channel; + + //if we have an offset we need one more byte in the input data + if (bit_offset.value()) + min_input_size += 1; + + if (input.size() < min_input_size) + throw std::runtime_error(fmt::format( + "{} Mismatch between input and output size. Output " + "size of {} with bit offset {} requires an input of at least {} " + "bytes. Called with input size: {} output size: {}", + LOCATION, output.size(), bit_offset.value(), min_input_size, input.size(), output.size())); + + auto* in = input.data(); + + if(bit_offset.value()){ + //If there is a bit_offset we copy 4 bytes and then + //mask out the correct ones. + for (auto& v : output){ + uint32_t val{}; + std::memcpy(&val, in, sizeof(val)); + v = mask32to24bits(val, bit_offset); + in += bytes_per_channel; + } + }else{ + //If there is no offset we can directly copy the bits + //without masking + for (auto& v : output){ + uint32_t val{}; + std::memcpy(&val, in, 3); + v = val; + in += bytes_per_channel; + } + } + +} + } // namespace aare diff --git a/src/decode.test.cpp b/src/decode.test.cpp index b3f1b6e..d57b2f7 100644 --- a/src/decode.test.cpp +++ b/src/decode.test.cpp @@ -7,6 +7,8 @@ using Catch::Matchers::WithinAbs; #include +using aare::BitOffset; + TEST_CASE("test_adc_sar_05_decode64to16") { uint64_t input = 0; uint16_t output = aare::adc_sar_05_decode64to16(input); @@ -71,4 +73,94 @@ TEST_CASE("test_apply_custom_weights") { input = 0b111; output = aare::apply_custom_weights(input, weights); CHECK_THAT(output, WithinAbs(6.34, 0.001)); +} + +TEST_CASE("Mask 32 bit unsigned integer to 24 bit"){ + //any number less than 2**24 (16777216) should be the same + CHECK(aare::mask32to24bits(0)==0); + CHECK(aare::mask32to24bits(19)==19); + CHECK(aare::mask32to24bits(29875)==29875); + CHECK(aare::mask32to24bits(1092177)==1092177); + CHECK(aare::mask32to24bits(0xFFFF)==0xFFFF); + CHECK(aare::mask32to24bits(0xFFFFFFFF)==0xFFFFFF); + + // Offset specifies that the should ignore 0-7 bits + // at the start + CHECK(aare::mask32to24bits(0xFFFF, BitOffset(4))==0xFFF); + CHECK(aare::mask32to24bits(0xFF0000d9)==0xd9); + CHECK(aare::mask32to24bits(0xFF000d9F, BitOffset(4))==0xF000d9); + CHECK(aare::mask32to24bits(16777217)==1); + CHECK(aare::mask32to24bits(15,BitOffset(7))==0); + + //Highest bit set to 1 should just be excluded + //lowest 4 bits set to 1 + CHECK(aare::mask32to24bits(0x8000000f,BitOffset(7))==0); + +} + +TEST_CASE("Expand container with 24 bit data to 32"){ + { + uint8_t buffer[] = { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + }; + + aare::NDView input(&buffer[0], {9}); + aare::NDArray out({3}); + aare::expand24to32bit(input, out.view()); + + CHECK(out(0) == 0); + CHECK(out(1) == 0); + CHECK(out(2) == 0); + } + { + uint8_t buffer[] = { + 0x0F, 0x00, 0x00, + 0xFF, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, + }; + + aare::NDView input(&buffer[0], {9}); + aare::NDArray out({3}); + aare::expand24to32bit(input, out.view()); + + CHECK(out(0) == 0xF); + CHECK(out(1) == 0xFF); + CHECK(out(2) == 0xFFFFFF); + } + { + uint8_t buffer[] = { + 0x00, 0x00, 0xFF, + 0xFF, 0xFF, 0x00, + 0x00, 0xFF, 0x00, + }; + + aare::NDView input(&buffer[0], {9}); + aare::NDArray out({3}); + aare::expand24to32bit(input, out.view()); + + CHECK(out(0) == 0xFF0000); + CHECK(out(1) == 0xFFFF); + CHECK(out(2) == 0xFF00); + + REQUIRE_THROWS(aare::expand24to32bit(input, out.view(), BitOffset(4))); + } + { + //For use with offset we need an extra byte + uint8_t buffer[] = { + 0x00, 0x00, 0xFF, + 0xFF, 0xFF, 0x00, + 0x00, 0xFF, 0x00, 0x00 + }; + + aare::NDView input(&buffer[0], {10}); + aare::NDArray out({3}); //still output.size == 3 + aare::expand24to32bit(input, out.view(), BitOffset(4)); + + CHECK(out(0) == 0xFFF000); + CHECK(out(1) == 0xFFF); + CHECK(out(2) == 0xFF0); + } + } \ No newline at end of file diff --git a/src/defs.cpp b/src/defs.cpp index bcc30e5..6eabbc1 100644 --- a/src/defs.cpp +++ b/src/defs.cpp @@ -298,4 +298,22 @@ template <> DACIndex StringTo(const std::string &arg) { "\""); } +BitOffset::BitOffset(uint32_t offset){ + if (offset>7) + throw std::runtime_error(fmt::format("{} BitOffset needs to be <8: Called with {}", LOCATION, offset)); + + m_offset = static_cast(offset); + +} + +bool BitOffset::operator==(const BitOffset& other) const { + return m_offset == other.m_offset; + } + +bool BitOffset::operator<(const BitOffset& other) const { + return m_offset < other.m_offset; + } + + + } // namespace aare \ No newline at end of file diff --git a/src/defs.test.cpp b/src/defs.test.cpp index 0b19c0f..40fb168 100644 --- a/src/defs.test.cpp +++ b/src/defs.test.cpp @@ -83,6 +83,28 @@ TEST_CASE("DynamicCluster creation") { REQUIRE(c2.data() != nullptr); } +TEST_CASE("Basic ops on BitOffset"){ + REQUIRE_THROWS(aare::BitOffset(10)); + + aare::BitOffset offset(5); + REQUIRE(offset.value()==5); + + aare::BitOffset offset2; + REQUIRE(offset2.value()==0); + + aare::BitOffset offset3(offset); + REQUIRE(offset3.value()==5); + + REQUIRE(offset==offset3); + + //Now assign offset to offset2 which should get the value 5 + offset2 = offset; + REQUIRE(offset2.value()==5); + REQUIRE(offset2==offset); +} + + + // TEST_CASE("cluster set and get data") { // aare::DynamicCluster c2(33, 44, aare::Dtype(typeid(double)));