diff --git a/src/avclan/bus.cc b/src/avclan/bus.cc index 1dacd76..f3dbacb 100644 --- a/src/avclan/bus.cc +++ b/src/avclan/bus.cc @@ -69,10 +69,10 @@ auto Bus::read(uint16_t address, Frame *in, Frame::Print print) -> Error::Read { if (err.errno != Error::Read{0}) goto handle_err; - handle.read<1>(&tmp, false); + handle.read<1>(&tmp, no_parity); in->is_unicast = (tmp != 0U); - if (auto rerr = handle.read(&in->controller_addr, false); + if (auto rerr = handle.read(&in->controller_addr, with_parity); rerr == BAD_PARITY) { err.errno = BAD_CONTROLLER_PARITY; 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( - &in->peripheral_addr, + &in->peripheral_addr, with_ack, // Using lambda for delayed evaluation of peripheral_addr field // 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; } - if (auto rerr = handle.read(&in->control, shouldACK); + if (auto rerr = + handle.read(&in->control, with_ack, shouldACK); rerr == BAD_PARITY) { err.errno = BAD_CONTROL_PARITY; if (print.verbose) { @@ -106,7 +107,7 @@ auto Bus::read(uint16_t address, Frame *in, Frame::Print print) -> Error::Read { goto handle_err; } - if (auto rerr = handle.read(&in->length, shouldACK); + if (auto rerr = handle.read(&in->length, with_ack, shouldACK); rerr == BAD_PARITY) { err.errno = BAD_LENGTH_PARITY; 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++) { - if (auto rerr = handle.read(&in->data[i], shouldACK); + if (auto rerr = + handle.read(&in->data[i], with_ack, shouldACK); rerr == BAD_PARITY) { err.errno = BAD_DATA_PARITY; if (print.verbose) { @@ -199,24 +201,27 @@ auto Bus::send(const Frame *out, Frame::Print print) -> Error::Send { goto handle_err; } - handle.send<1>(static_cast(out->is_unicast), false); + handle.send<1>(static_cast(out->is_unicast), no_parity); - handle.send(out->controller_addr, false); + handle.send(out->controller_addr, with_parity); - if (auto serr = - handle.send(out->controller_addr, out->is_unicast); + if (auto serr = handle.send(out->peripheral_addr, with_ack, + out->is_unicast); serr == NAK) { err.errno = NAK_ADDRESS; goto handle_err; } - if (auto serr = handle.send<4>(out->control, out->is_unicast); + if (auto serr = + handle.send(out->control, with_ack, out->is_unicast); serr == NAK) { err.errno = NAK_CONTROL; goto handle_err; } - if (auto serr = handle.send<8>(out->length, out->is_unicast); serr == NAK) { + if (auto serr = + handle.send(out->length, with_ack, out->is_unicast); + serr == NAK) { err.errno = NAK_MESSAGE_LENGTH; 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 // function that sent an extra `1` bit after each byte/parity) // 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(out->data[i], with_ack, out->is_unicast); serr == NAK) { err.errno = NAK_DATA; err.val = i; diff --git a/src/avclan/bus.hpp b/src/avclan/bus.hpp index 980ddec..66e51ff 100644 --- a/src/avclan/bus.hpp +++ b/src/avclan/bus.hpp @@ -48,6 +48,7 @@ #pragma once #include +#include #include "avclan.hpp" #include "avclan_defs.h" @@ -55,6 +56,16 @@ #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; @@ -83,38 +94,62 @@ public: bool sendstartbit(); Error::Read readstartbit(); + template + requires(sizeof(T) < 3 && N < 16) && + requires { std::is_base_of_v; } + Error::Send send(T bits, Trailer /*tag*/) { + const auto parity = sendbits(bits); + + if constexpr (std::is_same_v) + sendbits<1>(static_cast(parity)); + + return Send{0}; + }; + template requires(sizeof(T) < 3 && N < 16) - Error::Send send(T bits, bool ack) { - const auto parity = sendbits(bits); - sendbits<1>(static_cast(parity)); + Error::Send send(T bits, with_ack_t /*tag*/, bool expect_ack) { + send(bits, with_parity); - if (ack && !read_ACK()) + if (expect_ack && !read_ACK()) return Send::NAK; return Send{0}; }; + template + requires(sizeof(T) < 3 && N < 16) && + requires { std::is_base_of_v; } + Error::Read read(T *bits, Trailer /*tag*/) { + const auto calc_parity = readbits(bits); + if constexpr (std::is_same_v) { + uint8_t read_parity; + readbits<1>(&read_parity); + if (calc_parity != read_parity) + return Read::BAD_PARITY; + } + return Read{0}; + }; + template requires(sizeof(T) < 3 && N < 16) - Error::Read read(T *bits, F &&ack) { - const auto calc_parity = readbits(bits); - uint8_t read_parity; - readbits<1>(&read_parity); - if (calc_parity != read_parity) { + Error::Read read(T *bits, with_ack_t /*tag*/, F &&ack) { + if (read(bits, with_parity) == Read::BAD_PARITY) return Read::BAD_PARITY; - } + if (ack()) { send_ACK(); - } else - readbits<1>(&read_parity); + } else { + uint8_t slot; + readbits<1>(&slot); + } return Read{0}; }; template requires(sizeof(T) < 3 && N < 16) - Error::Read read(T *bits, bool ack) { - return read(bits, [=]() { return ack; }); + Error::Read read(T *bits, with_ack_t /*tag*/, bool ack) { + return read(bits, with_ack, [=]() { return ack; }); } private: