// copyright (C) 2006 Marcin Slonicki // copyright (C) 2007 Louis Frigon // Copyright (C) 2015 Allen Hill // SPDX-License-Identifier: GPL-3.0-or-later /* AVC LAN Frame Format │ Bits │ Description ──────────────────────────────────────── | 1 │ Start bit | 1 │ Direct/broadcast | 12 │ Controller address | 1 │ Parity | 12 │ Peripheral address | 1 │ Parity | 1 │ *Acknowledge* (read below) | 4 │ Control | 1 │ Parity | 1 │ *Acknowledge* | 8 │ Message length (n) | 1 │ Parity | 1 │ *Acknowledge* ──────── | 8 │ Data | 1 │ Parity | 1 │ *Acknowledge* *repeat `n` times* No acknowledge bits are sent for broadcast frames. */ #include #include #include #include #include "avclan.h" #include "bus.hpp" #include "frame.hpp" #include "hal/phy.h" #include "stdshim.hpp" namespace { using Read = avclan::detail::Error::Read; using Send = avclan::detail::Error::Send; using Bit = avclan::detail::Bit; 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{}; } // namespace namespace avclan { class Bus::Handle { // A live handle exclusively borrows the Bus for the duration of a // transaction; holding the reference is what forces `get()` (and thus // `read`/`send`) to require a mutable Bus, even though the bus hardware // itself is reached through free `phy_*` functions. Bus &bus_; explicit Handle(Bus &bus) : bus_{bus} { phy_guard_enter(); }; friend Bus; public: ~Handle() { phy_guard_leave(); }; Handle(const Handle &) = delete; Handle(Handle &&) = delete; // NOLINTNEXTLINE(readability-convert-member-functions-to-static) Send sendstartbit() { return phy_send_startbit(); }; // NOLINTNEXTLINE(readability-convert-member-functions-to-static) Read readstartbit() { return phy_read_startbit(); }; template Trailer> requires(sizeof(T) < 3 && N < 16 && !std::same_as) Send send(T bits, Trailer /*tag*/) { const Bit parity = sendbits(bits); if constexpr (std::is_same_v) sendbits<1>(to_underlying(parity)); return Send{0}; }; template requires(sizeof(T) < 3 && N < 16) Send send(T bits, with_ack_t /*tag*/, bool expect_ack) { send(bits, with_parity); if (expect_ack) return read_ACK(); sendbits<1>(1U); // still need to fill the ack bit slot return Send{0}; }; template Trailer> requires(sizeof(T) < 3 && N < 16 && !std::same_as) Read read(T *bits, Trailer /*tag*/) { const Bit calc_parity = readbits(bits); if constexpr (std::is_same_v) { uint8_t read_parity; readbits<1>(&read_parity); if (to_underlying(calc_parity) != read_parity) return Read::BAD_PARITY; } return Read{0}; }; template requires(sizeof(T) < 3 && N < 16) 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 { uint8_t slot; readbits<1>(&slot); } return Read{0}; }; template requires(sizeof(T) < 3 && N < 16) Read read(T *bits, with_ack_t /*tag*/, bool ack) { return read(bits, with_ack, [=]() { return ack; }); } private: static void send_ACK() { phy_send_ack(); }; static Send read_ACK() { return phy_read_ack(); }; template Bit sendbits(T bits); template Bit readbits(T *bits); template requires(N > 1 && N < 8) Bit sendbits(uint8_t bits) { return phy_send_bits_u8(&bits, N); }; template requires(N <= 16) Bit sendbits(uint16_t bits) { return phy_send_bits_u16(&bits, N); }; template requires(N < 8) Bit readbits(uint8_t *bits) { return static_cast(phy_read_bits_u8(bits, N)); }; template requires(N <= 16) Bit readbits(uint16_t *bits) { return static_cast(phy_read_bits_u16(bits, N)); }; }; template <> inline Bit Bus::Handle::sendbits<8>(uint8_t bits) { return phy_send_byte(&bits); }; template <> inline Bit Bus::Handle::sendbits<1>(uint8_t bits) { const Bit bit{static_cast(bits & 1U)}; phy_send_bit(bit); return bit; }; template <> inline Bit Bus::Handle::readbits<8>(uint8_t *bits) { return phy_read_byte(bits); }; void Bus::init() { // Idempotent: the single Bus is shared by reference, so every Peripheral's // ctor calls init() on it — but the hardware must be brought up exactly once // (phy_init is not assumed re-entrant/idempotent). if (inited_) return; phy_init(); muted_ = false; // phy_init leaves the bus TX unmuted inited_ = true; }; // NOLINTNEXTLINE(readability-convert-member-functions-to-static) bool Bus::is_active() const { return phy_active(); }; void Bus::mute(bool mute) { phy_mute(mute); muted_ = mute; // Only update muted_ *AFTER* hardware has finished muting }; auto Bus::read(uint16_t address, Frame::Print print) -> expected, Error::Read> { struct errtype { Read errno; uint16_t val; } err = {}; using enum Read; std::unique_ptr in(new (std::nothrow) Frame); if (!in) { err.errno = POOL_EMPTY; goto handle_err; } { // bound handle lifetime auto handle = get(); bool shouldACK = false; uint8_t tmp = 0; err.errno = handle.readstartbit(); if (err.errno != Read{0}) goto handle_err; handle.read<1>(&tmp, no_parity); in->is_unicast = (tmp != 0U); if (auto rerr = handle.read<12>(&in->controller_addr, with_parity); rerr == BAD_PARITY) { err.errno = BAD_CONTROLLER_PARITY; if (print.verbose) err.val = in->controller_addr; goto handle_err; } // Using lambda for delayed evaluation of peripheral_addr field // deref, which will be written by the time the lambda is evaluated auto should_ack_lambda = [&]() { shouldACK = !is_muted() && (in->peripheral_addr == address); return shouldACK; }; if (auto rerr = handle.read<12>(&in->peripheral_addr, with_ack, should_ack_lambda); rerr == BAD_PARITY) { err.errno = BAD_PERIPHERAL_PARITY; if (print.verbose) err.val = in->peripheral_addr; goto handle_err; } if (auto rerr = handle.read<4>(&in->control, with_ack, shouldACK); rerr == BAD_PARITY) { err.errno = BAD_CONTROL_PARITY; if (print.verbose) err.val = in->control; goto handle_err; } if (auto rerr = handle.read<8>(&in->length, with_ack, shouldACK); rerr == BAD_PARITY) { err.errno = BAD_LENGTH_PARITY; if (print.verbose) err.val = in->length; goto handle_err; } if (in->length == 0 || in->length > Frame::MAXLENGTH) { err.errno = BAD_LENGTH_RANGE; err.val = in->length; goto handle_err; } for (uint8_t i = 0; i < in->length; i++) { if (auto rerr = handle.read<8>(&in->data[i], with_ack, shouldACK); rerr == BAD_PARITY) { err.errno = BAD_DATA_PARITY; if (print.verbose) err.val = in->data[i]; goto handle_err; } } } // destroy handle if (false) { // NOLINT(readability-simplify-boolean-expr) handle_err:; fputs("ERR(read): ", stdout); switch (err.errno) { case POOL_EMPTY: puts("failed Frame alloc"); break; case BAD_STARTBIT: fputs("bad start bit (other)", stdout); break; case STARTBIT_MISSED: fputs("missed start bit", stdout); break; case STARTBIT_MALFORMED: fputs("malformed start bit (external cause)", stdout); break; case STARTBIT_TOO_LONG: fputs("bad start bit (long)", stdout); break; case BAD_CONTROLLER_PARITY: fputs("reading controller addr.", stdout); goto VERBOSE; case BAD_PERIPHERAL_PARITY: fputs("reading peripheral addr.", stdout); goto VERBOSE; case BAD_CONTROL_PARITY: fputs("reading control", stdout); goto VERBOSE; case BAD_LENGTH_PARITY: fputs("reading length", stdout); goto VERBOSE; case BAD_LENGTH_RANGE: printf("bad length 0x%02X:", err.val); break; case BAD_DATA_PARITY: fputs("reading data", stdout); goto VERBOSE; case BAD_PARITY: __builtin_unreachable(); VERBOSE: if (print.verbose) { printf("; read 0x%02X:", err.val); } } putchar('\n'); } // Only print if some data has been correctly received if (print.print && (err.errno < STARTBIT_MISSED)) { if (err.errno > BAD_DATA_PARITY) in->length = 0; in->print(print); } if (err.errno != Read{0}) return unexpected(err.errno); return in; } auto Bus::send(const Frame &out, Frame::Print print) -> Send { struct errtype { // Error enum is ordered such that a lower numeric value corresponds to // more success Send errno; uint8_t val; } err = {}; using enum Send; if (is_muted()) { err.errno = MUTED; goto handle_err; } { // bound handle lifetime auto handle = get(); if (handle.sendstartbit() == BUSY) { // Some other device is already driving the bus err.errno = BUSY; goto handle_err; } handle.send<1>(static_cast(out.is_unicast), no_parity); handle.send<12>(out.controller_addr, with_parity); if (auto serr = handle.send<12>(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, with_ack, out.is_unicast); serr == NAK) { err.errno = NAK_CONTROL; goto handle_err; } if (auto serr = handle.send<8>(out.length, with_ack, out.is_unicast); serr == NAK) { err.errno = NAK_MESSAGE_LENGTH; goto handle_err; } for (uint8_t i = 0; i < out.length; i++) { if (auto serr = handle.send<8>(out.data[i], with_ack, out.is_unicast); serr == NAK) { err.errno = NAK_DATA; err.val = i; goto handle_err; } } } // destroy handle // back to read mode if (false) { // NOLINT(readability-simplify-boolean-expr) handle_err:; fputs("Error", stdout); switch (err.errno) { case MUTED: fputs(": Device muted", stdout); break; case BUSY: fputs(": Busy bus", stdout); break; case NAK_ADDRESS: case NAK_CONTROL: case NAK_MESSAGE_LENGTH: case NAK_DATA: case NAK: fputs(" NAK: ", stdout); switch (err.errno) { case NAK_ADDRESS: fputs("address", stdout); break; case NAK_CONTROL: fputs("Control", stdout); break; case NAK_MESSAGE_LENGTH: fputs("Message length", stdout); break; case NAK_DATA: printf(" data[%u]", err.val); break; case NAK: case MUTED: case BUSY: __builtin_unreachable(); } break; } putchar('\n'); } if (print.print) out.print(print); return err.errno; } Bus::Handle Bus::get() { return Handle{*this}; }; #if !defined(NDEBUG) && defined(MEASURE_BUS) // Debug bit-timing measurement on the one physical bus; instance-scoped for the // same reason as is_active(). // NOLINTNEXTLINE(readability-convert-member-functions-to-static) void Bus::measure() { phy_measure(); } #endif } // namespace avclan