fixup bus send/read parity & acking

This commit is contained in:
Allen Hill
2026-07-06 11:31:17 -07:00
parent 6e4812e6b8
commit 30ad2dc67f
2 changed files with 68 additions and 27 deletions
+19 -13
View File
@@ -69,10 +69,10 @@ auto Bus::read(uint16_t address, Frame *in, Frame::Print print) -> Error::Read {
if (err.errno != Error::Read{0}) if (err.errno != Error::Read{0})
goto handle_err; goto handle_err;
handle.read<1>(&tmp, false); handle.read<1>(&tmp, no_parity);
in->is_unicast = (tmp != 0U); in->is_unicast = (tmp != 0U);
if (auto rerr = handle.read<ADDR_WIDTH>(&in->controller_addr, false); if (auto rerr = handle.read<ADDR_WIDTH>(&in->controller_addr, with_parity);
rerr == BAD_PARITY) { rerr == BAD_PARITY) {
err.errno = BAD_CONTROLLER_PARITY; err.errno = BAD_CONTROLLER_PARITY;
if (print.verbose) { if (print.verbose) {
@@ -82,7 +82,7 @@ auto Bus::read(uint16_t address, Frame *in, Frame::Print print) -> Error::Read {
} }
if (auto rerr = handle.read<ADDR_WIDTH>( if (auto rerr = handle.read<ADDR_WIDTH>(
&in->peripheral_addr, &in->peripheral_addr, with_ack,
// Using lambda for delayed evaluation of peripheral_addr field // Using lambda for delayed evaluation of peripheral_addr field
// deref, which will be written by the time the lambda is evaluated // deref, which will be written by the time the lambda is evaluated
[&]() { [&]() {
@@ -97,7 +97,8 @@ auto Bus::read(uint16_t address, Frame *in, Frame::Print print) -> Error::Read {
goto handle_err; goto handle_err;
} }
if (auto rerr = handle.read<CONTROL_WIDTH>(&in->control, shouldACK); if (auto rerr =
handle.read<CONTROL_WIDTH>(&in->control, with_ack, shouldACK);
rerr == BAD_PARITY) { rerr == BAD_PARITY) {
err.errno = BAD_CONTROL_PARITY; err.errno = BAD_CONTROL_PARITY;
if (print.verbose) { if (print.verbose) {
@@ -106,7 +107,7 @@ auto Bus::read(uint16_t address, Frame *in, Frame::Print print) -> Error::Read {
goto handle_err; goto handle_err;
} }
if (auto rerr = handle.read<BYTE_WIDTH>(&in->length, shouldACK); if (auto rerr = handle.read<BYTE_WIDTH>(&in->length, with_ack, shouldACK);
rerr == BAD_PARITY) { rerr == BAD_PARITY) {
err.errno = BAD_LENGTH_PARITY; err.errno = BAD_LENGTH_PARITY;
if (print.verbose) { if (print.verbose) {
@@ -122,7 +123,8 @@ auto Bus::read(uint16_t address, Frame *in, Frame::Print print) -> Error::Read {
} }
for (uint8_t i = 0; i < in->length; i++) { for (uint8_t i = 0; i < in->length; i++) {
if (auto rerr = handle.read<BYTE_WIDTH>(&in->data[i], shouldACK); if (auto rerr =
handle.read<BYTE_WIDTH>(&in->data[i], with_ack, shouldACK);
rerr == BAD_PARITY) { rerr == BAD_PARITY) {
err.errno = BAD_DATA_PARITY; err.errno = BAD_DATA_PARITY;
if (print.verbose) { if (print.verbose) {
@@ -199,24 +201,27 @@ auto Bus::send(const Frame *out, Frame::Print print) -> Error::Send {
goto handle_err; goto handle_err;
} }
handle.send<1>(static_cast<uint8_t>(out->is_unicast), false); handle.send<1>(static_cast<uint8_t>(out->is_unicast), no_parity);
handle.send<ADDR_WIDTH>(out->controller_addr, false); handle.send<ADDR_WIDTH>(out->controller_addr, with_parity);
if (auto serr = if (auto serr = handle.send<ADDR_WIDTH>(out->peripheral_addr, with_ack,
handle.send<ADDR_WIDTH>(out->controller_addr, out->is_unicast); out->is_unicast);
serr == NAK) { serr == NAK) {
err.errno = NAK_ADDRESS; err.errno = NAK_ADDRESS;
goto handle_err; goto handle_err;
} }
if (auto serr = handle.send<4>(out->control, out->is_unicast); if (auto serr =
handle.send<CONTROL_WIDTH>(out->control, with_ack, out->is_unicast);
serr == NAK) { serr == NAK) {
err.errno = NAK_CONTROL; err.errno = NAK_CONTROL;
goto handle_err; goto handle_err;
} }
if (auto serr = handle.send<8>(out->length, out->is_unicast); serr == NAK) { if (auto serr =
handle.send<BYTE_WIDTH>(out->length, with_ack, out->is_unicast);
serr == NAK) {
err.errno = NAK_MESSAGE_LENGTH; err.errno = NAK_MESSAGE_LENGTH;
goto handle_err; goto handle_err;
} }
@@ -226,7 +231,8 @@ auto Bus::send(const Frame *out, Frame::Print print) -> Error::Send {
// necessary (i.e. This deviates from the previous broadcast specific // necessary (i.e. This deviates from the previous broadcast specific
// function that sent an extra `1` bit after each byte/parity) // function that sent an extra `1` bit after each byte/parity)
// Explanation for why audio-group broadcast state report isn't working? // Explanation for why audio-group broadcast state report isn't working?
if (auto serr = handle.send<8>(out->data[i], out->is_unicast); if (auto serr =
handle.send<BYTE_WIDTH>(out->data[i], with_ack, out->is_unicast);
serr == NAK) { serr == NAK) {
err.errno = NAK_DATA; err.errno = NAK_DATA;
err.val = i; err.val = i;
+49 -14
View File
@@ -48,6 +48,7 @@
#pragma once #pragma once
#include <concepts> #include <concepts>
#include <type_traits>
#include "avclan.hpp" #include "avclan.hpp"
#include "avclan_defs.h" #include "avclan_defs.h"
@@ -55,6 +56,16 @@
#include "frame.hpp" #include "frame.hpp"
namespace avclan { 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 { class Bus {
public: public:
class Handle; class Handle;
@@ -83,38 +94,62 @@ public:
bool sendstartbit(); bool sendstartbit();
Error::Read readstartbit(); Error::Read readstartbit();
template <auto N, std::unsigned_integral T, class Trailer>
requires(sizeof(T) < 3 && N < 16) &&
requires { std::is_base_of_v<trailer_bits_t, Trailer>; }
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> template <auto N, std::unsigned_integral T>
requires(sizeof(T) < 3 && N < 16) requires(sizeof(T) < 3 && N < 16)
Error::Send send(T bits, bool ack) { Error::Send send(T bits, with_ack_t /*tag*/, bool expect_ack) {
const auto parity = sendbits<N>(bits); send<N>(bits, with_parity);
sendbits<1>(static_cast<uint8_t>(parity));
if (ack && !read_ACK()) if (expect_ack && !read_ACK())
return Send::NAK; return Send::NAK;
return Send{0}; return Send{0};
}; };
template <auto N, std::unsigned_integral T, class Trailer>
requires(sizeof(T) < 3 && N < 16) &&
requires { std::is_base_of_v<trailer_bits_t, Trailer>; }
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 (calc_parity != read_parity)
return Read::BAD_PARITY;
}
return Read{0};
};
template <auto N, std::unsigned_integral T, class F> template <auto N, std::unsigned_integral T, class F>
requires(sizeof(T) < 3 && N < 16) requires(sizeof(T) < 3 && N < 16)
Error::Read read(T *bits, F &&ack) { Error::Read read(T *bits, with_ack_t /*tag*/, F &&ack) {
const auto calc_parity = readbits<N>(bits); if (read<N>(bits, with_parity) == Read::BAD_PARITY)
uint8_t read_parity;
readbits<1>(&read_parity);
if (calc_parity != read_parity) {
return Read::BAD_PARITY; return Read::BAD_PARITY;
}
if (ack()) { if (ack()) {
send_ACK(); send_ACK();
} else } else {
readbits<1>(&read_parity); uint8_t slot;
readbits<1>(&slot);
}
return Read{0}; return Read{0};
}; };
template <auto N, std::unsigned_integral T> template <auto N, std::unsigned_integral T>
requires(sizeof(T) < 3 && N < 16) requires(sizeof(T) < 3 && N < 16)
Error::Read read(T *bits, bool ack) { Error::Read read(T *bits, with_ack_t /*tag*/, bool ack) {
return read<N>(bits, [=]() { return ack; }); return read<N>(bits, with_ack, [=]() { return ack; });
} }
private: private: