Finalize C <=> C++ interface

This commit is contained in:
Allen Hill
2026-07-06 19:39:49 -07:00
parent 7ceed80128
commit 9fd8c5636e
20 changed files with 396 additions and 346 deletions
+8 -117
View File
@@ -52,139 +52,30 @@
#include <type_traits>
#include "avclan.h"
#include "avclan_phy.h" // bridge until phy has been ported
#include "frame.hpp"
namespace avclan {
struct trailer_bits_t {};
struct no_parity_t : trailer_bits_t {}; // raw bits (the broadcast bit)
struct with_parity_t : trailer_bits_t {}; // bits + parity (controller address)
struct with_ack_t : trailer_bits_t {
}; // bits + parity + ACK slot (all other fields)
inline constexpr no_parity_t no_parity{};
inline constexpr with_parity_t with_parity{};
inline constexpr with_ack_t with_ack{};
class Bus {
public:
class Handle;
using Error = detail::Error;
void init();
bool is_active() const;
void mute(bool mute);
bool is_muted() const;
#ifndef NDEBUG
void measure();
#endif
Error::Read read(uint16_t address, Frame *in, Frame::Print print);
Error::Send send(const Frame *out, Frame::Print print);
private:
class Handle;
static Handle get();
};
class Bus::Handle {
Handle();
friend Bus;
public:
~Handle();
Handle(const Handle &) = delete;
Handle(Handle &&) = delete;
using Error = detail::Error;
bool sendstartbit();
Error::Read readstartbit();
template <auto N, std::unsigned_integral T,
std::derived_from<trailer_bits_t> Trailer>
requires(sizeof(T) < 3 && N < 16 && !std::same_as<Trailer, with_ack_t>)
Error::Send send(T bits, Trailer /*tag*/) {
const auto parity = sendbits<N>(bits);
if constexpr (std::is_same_v<Trailer, with_parity_t>)
sendbits<1>(static_cast<uint8_t>(parity));
return Send{0};
};
template <auto N, std::unsigned_integral T>
requires(sizeof(T) < 3 && N < 16)
Error::Send send(T bits, with_ack_t /*tag*/, bool expect_ack) {
send<N>(bits, with_parity);
if (expect_ack && !read_ACK())
return Send::NAK;
return Send{0};
};
template <auto N, std::unsigned_integral T,
std::derived_from<trailer_bits_t> Trailer>
requires(sizeof(T) < 3 && N < 16 && !std::same_as<Trailer, with_ack_t>)
Error::Read read(T *bits, Trailer /*tag*/) {
const auto calc_parity = readbits<N>(bits);
if constexpr (std::is_same_v<Trailer, with_parity_t>) {
uint8_t read_parity;
readbits<1>(&read_parity);
if (static_cast<uint8_t>(calc_parity) != read_parity)
return Read::BAD_PARITY;
}
return Read{0};
};
template <auto N, std::unsigned_integral T, class F>
requires(sizeof(T) < 3 && N < 16)
Error::Read read(T *bits, with_ack_t /*tag*/, F &&ack) {
if (read<N>(bits, with_parity) == Read::BAD_PARITY)
return Read::BAD_PARITY;
if (ack()) {
send_ACK();
} else {
uint8_t slot;
readbits<1>(&slot);
}
return Read{0};
};
template <auto N, std::unsigned_integral T>
requires(sizeof(T) < 3 && N < 16)
Error::Read read(T *bits, with_ack_t /*tag*/, bool ack) {
return read<N>(bits, with_ack, [=]() { return ack; });
}
private:
using Read = Error::Read;
using Send = Error::Send;
using Bit = detail::Bit;
static void send_ACK();
static uint8_t read_ACK();
template <auto N, class T> Bit sendbits(T bits);
template <auto N, class T> Bit readbits(T *bits);
// Temporary specializations bridging to legacy C API
// Replace with proper (single?) template when phy has been ported
template <auto N>
requires(N > 1 && N < 8)
Bit sendbits(uint8_t bits) {
return AVCLAN_sendbitsi(&bits, N);
};
template <auto N>
requires(N <= 16)
Bit sendbits(uint16_t bits) {
return AVCLAN_sendbitsl(&bits, N);
};
template <auto N>
requires(N < 8)
Bit readbits(uint8_t *bits) {
return static_cast<Bit>(AVCLAN_readbitsi(bits, N));
};
template <auto N>
requires(N <= 16)
Bit readbits(uint16_t *bits) {
return static_cast<Bit>(AVCLAN_readbitsl(bits, N));
};
};
} // namespace avclan