Merge branch 'developer' into MH01_debug

This commit is contained in:
2026-01-05 15:26:15 +01:00
55 changed files with 3924 additions and 1098 deletions

View File

@@ -17,6 +17,7 @@ set(SOURCES
src/sls_detector_exceptions.cpp
src/md5_helper.cpp
src/Version.cpp
src/bit_utils.cpp
)
# Header files to install as a part of the library
@@ -29,6 +30,7 @@ set(PUBLICHEADERS
include/sls/ToString.h
include/sls/TypeTraits.h
include/sls/TimeHelper.h
include/sls/bit_utils.h
)
# Additional headers to be installed if SLS_DEVEL_HEADERS

View File

@@ -11,6 +11,7 @@
#include "sls/TimeHelper.h"
#include "sls/TypeTraits.h"
#include "sls/bit_utils.h"
#include "sls/sls_detector_defs.h"
#include "sls/sls_detector_exceptions.h"
#include "sls/string_utils.h"
@@ -65,6 +66,7 @@ std::ostream &operator<<(std::ostream &os,
std::string ToString(const slsDetectorDefs::pedestalParameters &r);
std::ostream &operator<<(std::ostream &os,
const slsDetectorDefs::pedestalParameters &r);
const std::string &ToString(const std::string &s);
/** Convert std::chrono::duration with specified output unit */
@@ -324,6 +326,8 @@ template <> defs::gainMode StringTo(const std::string &s);
template <> defs::polarity StringTo(const std::string &s);
template <> defs::timingInfoDecoder StringTo(const std::string &s);
template <> defs::collectionMode StringTo(const std::string &s);
template <> RegisterAddress StringTo(const std::string &s);
template <> RegisterValue StringTo(const std::string &s);
template <> uint8_t StringTo(const std::string &s);
template <> uint16_t StringTo(const std::string &s);

View File

@@ -3,6 +3,7 @@
#pragma once
#include <bitset>
#include <cstdint>
#include <vector>
namespace sls {
template <typename T> std::vector<int> getSetBits(T val) {
@@ -18,4 +19,87 @@ template <typename T> std::vector<int> getSetBits(T val) {
}
return set_bits;
}
class RegisterAddress {
private:
uint32_t value_{0};
public:
constexpr RegisterAddress() noexcept = default;
constexpr explicit RegisterAddress(uint32_t value) : value_(value) {}
std::string str() const;
constexpr uint32_t value() const noexcept { return value_; }
constexpr bool operator==(const RegisterAddress &other) const {
return (value_ == other.value_);
}
constexpr bool operator!=(const RegisterAddress &other) const {
return (value_ != other.value_);
}
};
class BitAddress {
private:
RegisterAddress addr_{0};
uint32_t bitPos_{0};
public:
constexpr BitAddress() noexcept = default;
BitAddress(RegisterAddress address, uint32_t bitPosition);
std::string str() const;
constexpr RegisterAddress address() const noexcept { return addr_; }
constexpr uint32_t bitPosition() const noexcept { return bitPos_; }
constexpr bool operator==(const BitAddress &other) const {
return (addr_ == other.addr_ && bitPos_ == other.bitPos_);
}
constexpr bool operator!=(const BitAddress &other) const {
return !(*this == other);
}
};
class RegisterValue {
private:
uint32_t value_{0};
public:
constexpr RegisterValue() noexcept = default;
explicit constexpr RegisterValue(uint32_t value) noexcept : value_(value) {}
std::string str() const;
constexpr uint32_t value() const noexcept { return value_; }
constexpr RegisterValue &operator|=(const RegisterValue &rhs) noexcept {
value_ |= rhs.value();
return *this;
}
constexpr RegisterValue operator|(const RegisterValue &rhs) const noexcept {
RegisterValue tmp(*this);
tmp |= rhs;
return tmp;
}
constexpr RegisterValue &operator|=(uint32_t rhs) noexcept {
value_ |= rhs;
return *this;
}
constexpr RegisterValue operator|(uint32_t rhs) const noexcept {
RegisterValue tmp(*this);
tmp |= rhs;
return tmp;
}
constexpr bool operator==(const RegisterValue &other) const noexcept {
return value_ == other.value_;
}
constexpr bool operator!=(const RegisterValue &other) const noexcept {
return value_ != other.value_;
}
};
std::ostream &operator<<(std::ostream &os, const RegisterAddress &r);
std::ostream &operator<<(std::ostream &os, const BitAddress &r);
std::ostream &operator<<(std::ostream &os, const RegisterValue &r);
} // namespace sls

View File

@@ -181,20 +181,18 @@ typename std::enable_if<is_container<T>::value, bool>::type
stableRemoveDuplicates(T &c) {
auto containerSize = c.size();
std::set<typename T::value_type> seen;
c.erase(
std::remove_if(c.begin(), c.end(),
[&](const typename T::value_type& val) {
return !seen.insert(val).second; // erase if already seen
}),
c.end()
);
c.erase(std::remove_if(
c.begin(), c.end(),
[&](const typename T::value_type &val) {
return !seen.insert(val).second; // erase if already seen
}),
c.end());
if (c.size() != containerSize) {
return true;
}
return false;
}
} // namespace sls
#endif // CONTAINER_UTILS_H

View File

@@ -5,6 +5,7 @@
#include <cassert>
#include <cstdint>
#include <cstring>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
@@ -33,6 +34,35 @@ void strcpy_safe(char (&destination)[array_size], const std::string &source) {
destination[array_size - 1] = '\0';
}
// Runtime-checked variant — throws if it won't fit
template <size_t array_size>
void strcpy_checked(char (&destination)[array_size], const char *source) {
if (!source)
throw std::runtime_error("Null source pointer in strcpy_checked");
size_t len = std::strlen(source);
if (len >= (array_size - 1)) {
throw std::runtime_error("String length (" + std::to_string(len) +
") should be less than " +
std::to_string(array_size - 1) + " chars");
}
std::strncpy(destination, source, array_size - 1);
destination[array_size - 1] = '\0';
}
template <size_t array_size>
void strcpy_checked(char (&destination)[array_size],
const std::string &source) {
if (source.size() >= (array_size - 1)) {
throw std::runtime_error("String length (" +
std::to_string(source.size()) +
") should be less than " +
std::to_string(array_size - 1) + " chars");
}
std::strncpy(destination, source.c_str(), array_size - 1);
destination[array_size - 1] = '\0';
}
/*
Removes all occurrences of the specified char from a c string
Templated on array size to ensure no access after buffer limits.
@@ -58,6 +88,8 @@ std::vector<std::string> split(const std::string &strToSplit, char delimeter);
std::string RemoveUnit(std::string &str);
bool is_int(const std::string &s);
/** '0x200' is also an int here */
bool is_hex_or_dec_uint(const std::string &s);
bool replace_first(std::string *s, const std::string &substr,
const std::string &repl);

View File

@@ -0,0 +1,42 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#include "sls/bit_utils.h"
#include "sls/ToString.h"
#include "sls/sls_detector_exceptions.h"
namespace sls {
std::string RegisterAddress::str() const { return ToStringHex(value_); }
BitAddress::BitAddress(RegisterAddress address, uint32_t bitPosition)
: addr_(address) {
if (bitPosition > 31) {
throw RuntimeError("Bit position must be between 0 and 31.");
}
bitPos_ = bitPosition;
}
std::string BitAddress::str() const {
std::ostringstream os;
os << '[' << addr_.str() << ", " << ToString(bitPos_) << ']';
return os.str();
}
std::string RegisterValue::str() const { return ToStringHex(value_); }
std::ostream &operator<<(std::ostream &os, const RegisterAddress &r) {
os << r.str();
return os;
}
std::ostream &operator<<(std::ostream &os, const BitAddress &r) {
os << r.str();
return os;
}
std::ostream &operator<<(std::ostream &os, const RegisterValue &r) {
os << r.str();
return os;
}
} // namespace sls

View File

@@ -256,24 +256,22 @@ std::string getAbsolutePathFromCurrentProcess(const std::string &fname) {
return fname;
}
//in case PATH_MAX defines the longest possible path on linux and macOS
//use string instead of char array to avoid overflow
std::string path(PATH_MAX, '\0');
// in case PATH_MAX defines the longest possible path on linux and macOS
// use string instead of char array to avoid overflow
std::string path(PATH_MAX, '\0');
#if defined(__APPLE__)
#if defined(__APPLE__)
uint32_t size = PATH_MAX;
if (_NSGetExecutablePath(path.data(), &size) != 0) {
throw std::runtime_error("Failed to get executable path");
}
// Resolve any symlinks and .. components
std::string resolved(PATH_MAX, '\0');
std::string resolved(PATH_MAX, '\0');
if (!realpath(path.data(), resolved.data())) {
throw std::runtime_error("realpath failed for executable");
}
path = resolved;
#else
#else
ssize_t len = readlink("/proc/self/exe", path.data(), PATH_MAX - 1);
if (len < 0) {
@@ -281,7 +279,7 @@ std::string getAbsolutePathFromCurrentProcess(const std::string &fname) {
}
path[len] = '\0';
#endif
#endif
// get dir path and attach file name
std::string absPath = (std::string(dirname(path.data())) + '/' + fname);

View File

@@ -179,8 +179,7 @@ IpAddr InterfaceNameToIp(const std::string &ifn) {
MacAddr InterfaceNameToMac(const std::string &inf) {
#ifdef __APPLE__
throw RuntimeError(
"InterfaceNameToMac not implemented on macOS yet");
throw RuntimeError("InterfaceNameToMac not implemented on macOS yet");
#else
// TODO! Copied from genericSocket needs to be refactored!

View File

@@ -43,6 +43,15 @@ bool is_int(const std::string &s) {
}) == s.end();
}
bool is_hex_or_dec_uint(const std::string &s) {
try {
StringTo<uint32_t>(s);
return true;
} catch (...) {
}
return false;
}
bool replace_first(std::string *s, const std::string &substr,
const std::string &repl) {
auto pos = s->find(substr);

View File

@@ -84,8 +84,8 @@ TEST_CASE("Shutdown socket without hanging when waiting for data") {
// Start a thread and wait for package
// if the socket is left open we would block
std::future<bool> ret =
std::async(std::launch::async, &UdpRxSocket::ReceivePacket, &s, (char *)&buff);
std::future<bool> ret = std::async(
std::launch::async, &UdpRxSocket::ReceivePacket, &s, (char *)&buff);
s.Shutdown();
auto r = ret.get();

View File

@@ -2,6 +2,7 @@
// Copyright (C) 2021 Contributors to the SLS Detector Package
#include "catch.hpp"
#include "sls/bit_utils.h"
#include <sstream>
#include <vector>
namespace sls {
@@ -42,4 +43,108 @@ TEST_CASE("Get set bits from 523") {
REQUIRE(vec == std::vector<int>{0, 1, 3, 9});
}
TEST_CASE("Convert RegisterAddress using classes ", "[support][.bit_utils]") {
std::vector<uint32_t> vec_addr{0x305, 0xffffffff, 0x0, 0x34550987,
0x1fff1fff};
std::vector<std::string> vec_ans{"0x305", "0xffffffff", "0x0", "0x34550987",
"0x1fff1fff"};
for (size_t i = 0; i != vec_addr.size(); ++i) {
auto reg0 = RegisterAddress(vec_addr[i]);
auto reg1 = RegisterAddress(vec_addr[i]);
auto reg2 = RegisterAddress(vec_addr[0]);
CHECK(reg0 == reg1);
if (i != 0)
CHECK(reg2 != reg1);
CHECK(reg0.value() == vec_addr[i]);
CHECK(reg1.value() == vec_addr[i]);
CHECK(reg0.str() == vec_ans[i]);
CHECK(reg1.str() == vec_ans[i]);
}
}
TEST_CASE("Convert RegisterValue using classes ", "[support][.bit_utils]") {
std::vector<uint32_t> vec_addr{0x305, 0xffffffff, 0x0, 500254562,
0x1fff1fff};
std::vector<std::string> vec_ans{"0x305", "0xffffffff", "0x0", "0x1dd14762",
"0x1fff1fff"};
for (size_t i = 0; i != vec_addr.size(); ++i) {
auto reg0 = RegisterValue(vec_addr[i]);
auto reg2 = RegisterValue(vec_addr[0]);
if (i != 0)
CHECK(reg2 != reg0);
CHECK(reg0.value() == vec_addr[i]);
CHECK(reg0.str() == vec_ans[i]);
CHECK((reg0 | 0xffffffffu) == RegisterValue(0xffffffffu));
CHECK((reg0 | 0x0) == reg0);
CHECK((reg0 | 0x1) == reg0);
}
}
TEST_CASE("Convert BitAddress using classes", "[support][.bit_utils]") {
std::vector<RegisterAddress> vec_addr{
RegisterAddress(0x305), RegisterAddress(0xffffffffu),
RegisterAddress(0x0), RegisterAddress(0x34550987),
RegisterAddress(0x1fff1fff)};
std::vector<std::string> vec_addr_str{"0x305", "0xffffffff", "0x0",
"0x34550987", "0x1fff1fff"};
std::vector<uint32_t> vec_bitpos{0, 15, 31, 7, 23};
std::vector<std::string> vec_bitpos_str{"0", "15", "31", "7", "23"};
std::vector<std::string> vec_ans{
"[0x305, 0]", "[0xffffffff, 15]", "[0x0, 31]",
"[0x34550987, 7]", "[0x1fff1fff, 23]",
};
for (size_t i = 0; i != vec_addr.size(); ++i) {
auto reg0 = BitAddress(vec_addr[i], vec_bitpos[i]);
BitAddress reg1(vec_addr[i], vec_bitpos[i]);
CHECK(reg1.address() == vec_addr[i]);
CHECK(reg1.bitPosition() == vec_bitpos[i]);
auto reg2 = BitAddress(vec_addr[0], vec_bitpos[0]);
CHECK(reg0 == reg1);
if (i != 0)
CHECK(reg2 != reg1);
CHECK(reg0.address() == vec_addr[i]);
CHECK(reg1.address() == vec_addr[i]);
CHECK(reg0.bitPosition() == vec_bitpos[i]);
CHECK(reg1.bitPosition() == vec_bitpos[i]);
CHECK(std::to_string(reg0.bitPosition()) == vec_bitpos_str[i]);
CHECK(std::to_string(reg1.bitPosition()) == vec_bitpos_str[i]);
CHECK(reg0.str() == vec_ans[i]);
CHECK(reg1.str() == vec_ans[i]);
}
}
TEST_CASE("Output operator gives same result as string",
"[support][.bit_utils]") {
{
RegisterAddress addr{0x3456af};
std::ostringstream os;
os << addr;
CHECK(os.str() == "0x3456af");
CHECK(os.str() == addr.str());
}
{
BitAddress addr{RegisterAddress(0x3456af), 15};
std::ostringstream os;
os << addr;
CHECK(os.str() == "[0x3456af, 15]");
CHECK(os.str() == addr.str());
}
{
RegisterValue addr{0x3456af};
std::ostringstream os;
os << addr;
CHECK(os.str() == "0x3456af");
CHECK(os.str() == addr.str());
}
}
} // namespace sls

View File

@@ -175,13 +175,12 @@ TEST_CASE("remove duplicates but keep order, all elements the same ") {
}
TEST_CASE("remove duplicates but keep order, pattern ") {
std::vector<int> v{8,1,2,8,8,3,2};
std::vector<int> v{8, 1, 2, 8, 8, 3, 2};
auto r = stableRemoveDuplicates(v);
CHECK(r == true); // did indeed remove elements
CHECK(v == std::vector<int>{8,1,2,3});
CHECK(v == std::vector<int>{8, 1, 2, 3});
}
TEST_CASE("remove duplicated empty vector") {
std::vector<int> v;
auto r = removeDuplicates(v);