Dev/decode my302 (#254)
Some checks failed
Build on RHEL8 / build (push) Failing after 0s
Build on RHEL9 / build (push) Failing after 0s

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
This commit is contained in:
Erik Fröjdh
2025-12-09 18:27:02 +01:00
committed by GitHub
parent e795310b16
commit 80a2b02345
27 changed files with 427 additions and 41 deletions

View File

@@ -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) {

View File

@@ -5,6 +5,7 @@
#include <iostream>
#include <numeric>
#include <vector>
#include <cstddef>
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<std::byte> buf(5);
auto v = aare::make_view(buf);
REQUIRE(v.shape()[0] == 5);
REQUIRE(v[0] == std::byte{0});
}

View File

@@ -1,5 +1,6 @@
// SPDX-License-Identifier: MPL-2.0
#include "aare/decode.hpp"
#include <fmt/format.h>
#include <cmath>
namespace aare {
@@ -105,4 +106,49 @@ void apply_custom_weights(NDView<uint16_t, 1> input, NDView<double, 1> output,
}
}
uint32_t mask32to24bits(uint32_t input, BitOffset offset){
constexpr uint32_t mask24bits{0xFFFFFF};
return (input >> offset.value()) & mask24bits;
}
void expand24to32bit(NDView<uint8_t,1> input, NDView<uint32_t,1> 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

View File

@@ -7,6 +7,8 @@
using Catch::Matchers::WithinAbs;
#include <vector>
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<uint8_t, 1> input(&buffer[0], {9});
aare::NDArray<uint32_t, 1> 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<uint8_t, 1> input(&buffer[0], {9});
aare::NDArray<uint32_t, 1> 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<uint8_t, 1> input(&buffer[0], {9});
aare::NDArray<uint32_t, 1> 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<uint8_t, 1> input(&buffer[0], {10});
aare::NDArray<uint32_t, 1> 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);
}
}

View File

@@ -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<uint8_t>(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

View File

@@ -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)));