Redesign (simplify) top-level avclan interface to use expected/nullable unique_ptr

- Peripheral::read/send now return `expected<unique_ptr<Frame>, Error>`
for a unified success/error interface.
- Peripheral::route returns `expected<unique_ptr<Frame>, Error>` to
distinguish intent: (intentional) non-response vs unable to respond
- Other functions with optional message semantics (handle,poll,react)
return a unique_ptr whose ownership-state indicates response intent
(i.e. send new message)

Bundled necessary changes:
- Switch Frame allocation from global to local (enabled via member
  function new/delete)
- Add new header-library tl::expected to shim avr-libstdcpp

Unrelated: Defensive `continue` added after `route`, to reduce Bus
activity check latency

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Allen Hill
2026-07-17 14:24:03 -07:00
parent 200a225add
commit 5208e083f3
17 changed files with 536 additions and 187 deletions
+17 -3
View File
@@ -31,11 +31,14 @@
#include <concepts>
#include <cstdio>
#include <memory>
#include <new>
#include "avclan.h"
#include "bus.hpp"
#include "frame.hpp"
#include "hal/phy.h"
#include "stdshim.hpp"
namespace {
using Read = avclan::detail::Error::Read;
@@ -191,7 +194,8 @@ void Bus::mute(bool mute) {
muted_ = mute; // Only update muted_ *AFTER* hardware has finished muting
};
auto Bus::read(uint16_t address, Frame *in, Frame::Print print) -> Read {
auto Bus::read(uint16_t address, Frame::Print print)
-> expected<std::unique_ptr<Frame>, Error::Read> {
struct errtype {
Read errno;
uint16_t val;
@@ -199,6 +203,12 @@ auto Bus::read(uint16_t address, Frame *in, Frame::Print print) -> Read {
using enum Read;
std::unique_ptr<Frame> in(new (std::nothrow) Frame);
if (!in) {
err.errno = POOL_EMPTY;
goto handle_err;
}
{ // bound handle lifetime
auto handle = get();
@@ -277,6 +287,7 @@ auto Bus::read(uint16_t address, Frame *in, Frame::Print print) -> Read {
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_TOO_SHORT: fputs("bad start bit (short)", stdout); break;
case STARTBIT_TOO_LONG: fputs("bad start bit (long)", stdout); break;
@@ -297,7 +308,7 @@ auto Bus::read(uint16_t address, Frame *in, Frame::Print print) -> Read {
printf("; read 0x%02X", err.val);
}
}
putchar('\n');
puts(":");
}
// Only print if some data has been correctly received
@@ -307,7 +318,10 @@ auto Bus::read(uint16_t address, Frame *in, Frame::Print print) -> Read {
in->print(print);
}
return err.errno;
if (err.errno != Read{0})
return unexpected(err.errno);
return in;
}
auto Bus::send(const Frame *out, Frame::Print print) -> Send {