Port Frame object to C++

This commit is contained in:
Allen Hill
2026-07-05 19:35:58 -07:00
parent 66bbf8639e
commit e878a61313
14 changed files with 224 additions and 250 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ set(AVCLAN_TARGET avr-attiny3216 CACHE STRING "Hardware target (port) to build")
# <avr/...>, no register access). The selected target's port sources and flags # <avr/...>, no register access). The selected target's port sources and flags
# are contributed by its subdirectory. # are contributed by its subdirectory.
add_library(avclan STATIC add_library(avclan STATIC
src/avclan/avclan_frame.c src/avclan/frame.cc
src/avclan/cdchanger.cc src/avclan/cdchanger.cc
src/avclan/bus.cc src/avclan/bus.cc
) )
-22
View File
@@ -11,11 +11,6 @@
#include <stdint.h> #include <stdint.h>
#define MAXMSGLEN 32
#define DEVICE_ADDR 0x360 // CD Changer address
#define HU_ADDR 0x190 // Head-unit address
typedef enum : uint8_t { typedef enum : uint8_t {
dev_LAN = 0x00, dev_LAN = 0x00,
dev_COMM_CTRL = 0x01, dev_COMM_CTRL = 0x01,
@@ -109,23 +104,6 @@ typedef enum : uint8_t {
Report_TOC = 0xf9, Report_TOC = 0xf9,
} actions; } actions;
typedef struct print_struct {
bool print : 1; // print at all
bool binary : 1; // when also printing, format as binary instead of text
bool verbose : 1; // include extra context in error reports
} log_t;
typedef struct AVCLAN_frame_struct {
uint8_t reaction;
uint8_t owning_device;
bool is_unicast;
uint16_t controller_addr; // formerly "master"
uint16_t peripheral_addr; // formerly "slave"
uint8_t control;
uint8_t length;
uint8_t data[MAXMSGLEN];
} AVCLAN_frame_t;
// A single bus symbol. bit_zero/bit_one carry data (and double as parity // A single bus symbol. bit_zero/bit_one carry data (and double as parity
// values); bit_start marks a frame start bit. // values); bit_start marks a frame start bit.
typedef enum avclan_bit : uint8_t { typedef enum avclan_bit : uint8_t {
-114
View File
@@ -1,114 +0,0 @@
// copyright (C) 2006 Marcin Slonicki <marcin@softservice.com.pl>
// copyright (C) 2007 Louis Frigon
// Copyright (C) 2015 Allen Hill <allenofthehills@gmail.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#include <stdint.h>
#include <string.h>
#include "avclan_frame.h"
#include "avclan_phy.h" // bus symbol I/O + transaction guard (target-provided)
#include "com232.h" // error logging
void AVCLAN_printframe(const AVCLAN_frame_t *frame, bool binary) {
if (binary) {
uint8_t buffer[8];
buffer[0] = 0x10; // Data Link Escape, signaling binary data forthcoming
buffer[1] = frame->is_unicast;
// Send addresses in big-endian order
buffer[2] = (uint8_t)(frame->controller_addr >> 8);
buffer[3] = (uint8_t)frame->controller_addr;
buffer[4] = (uint8_t)(frame->peripheral_addr >> 8);
buffer[5] = (uint8_t)frame->peripheral_addr;
buffer[6] = frame->control;
buffer[7] = frame->length;
RS232_sendbytes((uint8_t *)&buffer, 8);
RS232_sendbytes(frame->data, frame->length);
buffer[0] = 0x17; // End of transmission block
buffer[1] = 0x0D; // \r
buffer[2] = 0x0A; // \n
RS232_sendbytes((uint8_t *)&buffer, 3);
} else {
RS232_PrintHex4(frame->is_unicast);
RS232_Print(" 0x");
RS232_PrintHex12(frame->controller_addr);
RS232_Print(" 0x");
RS232_PrintHex12(frame->peripheral_addr);
RS232_Print(" 0x");
RS232_PrintHex4(frame->control);
RS232_Print(" 0x");
RS232_PrintHex4(frame->length);
for (uint8_t i = 0; i < frame->length; i++) {
RS232_Print(" 0x");
RS232_PrintHex8(frame->data[i]);
}
RS232_Print("\n");
}
}
uint8_t AVCLAN_parseframe(const uint8_t *bytes, uint8_t len,
AVCLAN_frame_t *frame) {
struct errtype {
enum : uint8_t {
TOO_SHORT = 0x01,
MISMATCH_LENGTH,
LENGTH_TOO_BIG,
} errno;
uint8_t val;
} err = {0};
if (len < sizeof(AVCLAN_frame_t)) {
err.errno = TOO_SHORT;
goto handle_err;
}
const uint8_t *last = bytes + len;
frame->is_unicast = *bytes++;
frame->controller_addr = bytes[0] | ((uint16_t)bytes[1] << 8);
bytes += 2;
frame->peripheral_addr = bytes[0] | ((uint16_t)bytes[1] << 8);
bytes += 2;
frame->control = *bytes++;
frame->length = *bytes++;
if (frame->length > MAXMSGLEN) {
err.errno = LENGTH_TOO_BIG;
err.val = frame->length;
goto handle_err;
}
if ((bytes + frame->length) <= last) {
memcpy(frame->data, bytes, frame->length);
} else {
err.errno = MISMATCH_LENGTH;
goto handle_err;
}
if (false) {
handle_err:;
RS232_Print("ERR(parse): ");
switch (err.errno) {
case TOO_SHORT:
RS232_Print("not enough bytes too fill AVCLAN frame");
break;
case MISMATCH_LENGTH:
RS232_Print("frame->length is longer than remaining data");
break;
case LENGTH_TOO_BIG:
RS232_Print("frame->length exceeds MAXMSGLEN: 0x");
RS232_PrintHex8(err.val);
break;
default: break;
}
RS232_Print("\n");
}
return err.errno;
}
-48
View File
@@ -1,48 +0,0 @@
// copyright (C) 2006 Marcin Slonicki <marcin@softservice.com.pl>
// copyright (C) 2007 Louis Frigon
// Copyright (C) 2015 Allen Hill <allenofthehills@gmail.com>
// 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.
*/
#pragma once
#include <stdint.h>
#include "avclan_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
void AVCLAN_printframe(const AVCLAN_frame_t *frame, bool binary);
uint8_t AVCLAN_parseframe(const uint8_t *bytes, uint8_t len,
AVCLAN_frame_t *frame);
#ifdef __cplusplus
}
#endif
-1
View File
@@ -9,7 +9,6 @@
#pragma once #pragma once
#include "avclan_defs.h" #include "avclan_defs.h"
#include "avclan_frame.h"
#include "avclan_phy.h" #include "avclan_phy.h"
#include "mediacontrol.h" #include "mediacontrol.h"
#include "statustimer.h" #include "statustimer.h"
+6 -7
View File
@@ -32,9 +32,9 @@
#include "bus.hpp" #include "bus.hpp"
#include "avclan.hpp" #include "avclan.hpp"
#include "avclan_defs.h" #include "avclan_defs.h"
#include "avclan_frame.h"
#include "avclan_phy.h" // bridge until phy has been ported #include "avclan_phy.h" // bridge until phy has been ported
#include "com232.h" #include "com232.h"
#include "frame.hpp"
namespace { namespace {
constexpr int ADDR_WIDTH = 12; constexpr int ADDR_WIDTH = 12;
@@ -45,8 +45,7 @@ void Bus::init() { AVCLAN_busInit(); };
void Bus::mute(bool mute) { AVCLAN_muteDevice(mute); }; void Bus::mute(bool mute) { AVCLAN_muteDevice(mute); };
bool Bus::is_muted() const { return AVCLAN_ismuted(); }; bool Bus::is_muted() const { return AVCLAN_ismuted(); };
auto Bus::read(uint16_t address, AVCLAN_frame_t *in, log_t print) auto Bus::read(uint16_t address, Frame *in, Frame::Print print) -> Error::Read {
-> Error::Read {
struct errtype { struct errtype {
Error::Read errno; Error::Read errno;
union { union {
@@ -113,7 +112,7 @@ auto Bus::read(uint16_t address, AVCLAN_frame_t *in, log_t print)
goto handle_err; goto handle_err;
} }
if (in->length == 0 || in->length > MAXMSGLEN) { if (in->length == 0 || in->length > Frame::MAXLENGTH) {
err.errno = BAD_LENGTH_RANGE; err.errno = BAD_LENGTH_RANGE;
err.val = in->length; err.val = in->length;
goto handle_err; goto handle_err;
@@ -169,13 +168,13 @@ auto Bus::read(uint16_t address, AVCLAN_frame_t *in, log_t print)
if (print.print && (err.errno < STARTBIT_TOO_SHORT)) { if (print.print && (err.errno < STARTBIT_TOO_SHORT)) {
if (err.errno > BAD_DATA_PARITY) if (err.errno > BAD_DATA_PARITY)
in->length = 0; in->length = 0;
AVCLAN_printframe(in, print.binary); in->print(print);
} }
return err.errno; return err.errno;
} }
auto Bus::send(const AVCLAN_frame_t *out, log_t print) -> Error::Send { auto Bus::send(const Frame *out, Frame::Print print) -> Error::Send {
struct errtype { struct errtype {
// Error enum is ordered such that a lower numeric value corresponds to // Error enum is ordered such that a lower numeric value corresponds to
// more success // more success
@@ -267,7 +266,7 @@ auto Bus::send(const AVCLAN_frame_t *out, log_t print) -> Error::Send {
} }
if (print.print) if (print.print)
AVCLAN_printframe(out, print.binary); out->print(print);
return err.errno; return err.errno;
} }
+3 -2
View File
@@ -52,6 +52,7 @@
#include "avclan.hpp" #include "avclan.hpp"
#include "avclan_defs.h" #include "avclan_defs.h"
#include "avclan_phy.h" // bridge until phy has been ported #include "avclan_phy.h" // bridge until phy has been ported
#include "frame.hpp"
namespace avclan { namespace avclan {
class Bus { class Bus {
@@ -63,8 +64,8 @@ public:
void mute(bool mute); void mute(bool mute);
bool is_muted() const; bool is_muted() const;
Error::Read read(uint16_t address, AVCLAN_frame_t *in, log_t print); Error::Read read(uint16_t address, Frame *in, Frame::Print print);
Error::Send send(const AVCLAN_frame_t *out, log_t print); Error::Send send(const Frame *out, Frame::Print print);
static Handle get(); static Handle get();
}; };
+6 -5
View File
@@ -8,6 +8,7 @@
#include "avclan_defs.h" #include "avclan_defs.h"
#include "cdchanger.hpp" #include "cdchanger.hpp"
#include "frame.hpp"
#include "mediacontrol.h" #include "mediacontrol.h"
#include "statustimer.h" #include "statustimer.h"
@@ -53,7 +54,7 @@ void CDChanger::init() {
statustimer_init(this, &incrementTime_callback, &isPlaying_callback); statustimer_init(this, &incrementTime_callback, &isPlaying_callback);
} }
void CDChanger::handle(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) { void CDChanger::handle(const Frame *in, Frame *out) {
const uint8_t *data = &in->data[1]; const uint8_t *data = &in->data[1];
const auto from = static_cast<devices>(*data++); const auto from = static_cast<devices>(*data++);
/* const auto to = */ data++; /* const auto to = */ data++;
@@ -244,7 +245,7 @@ void CDChanger::handle(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
} }
} }
void CDChanger::react(AVCLAN_frame_t *out, detail::Error::Send err) { void CDChanger::react(Frame *out, detail::Error::Send err) {
auto resp = static_cast<reaction_t>(out->reaction); auto resp = static_cast<reaction_t>(out->reaction);
out->reaction = r_Nothing; out->reaction = r_Nothing;
switch (resp) { switch (resp) {
@@ -302,7 +303,7 @@ void CDChanger::react(AVCLAN_frame_t *out, detail::Error::Send err) {
} }
} }
void CDChanger::enable(AVCLAN_frame_t *out) { void CDChanger::enable(Frame *out) {
if (!isPlaying()) { if (!isPlaying()) {
if (mins > TWODIGIT_MAX) if (mins > TWODIGIT_MAX)
mins = 0; mins = 0;
@@ -318,7 +319,7 @@ void CDChanger::enable(AVCLAN_frame_t *out) {
bool CDChanger::pending() { return statustimer_tickPending(); } bool CDChanger::pending() { return statustimer_tickPending(); }
void CDChanger::resolvepending() { statustimer_clearTick(); } void CDChanger::resolvepending() { statustimer_clearTick(); }
void CDChanger::emit(AVCLAN_frame_t *out) { void CDChanger::emit(Frame *out) {
generateStatus(out, true, dev_STATUS); generateStatus(out, true, dev_STATUS);
out->reaction = r_StateReport; out->reaction = r_StateReport;
} }
@@ -377,7 +378,7 @@ void CDChanger::incrementTime() {
} }
// Used for changed status messages // Used for changed status messages
void CDChanger::generateStatus(AVCLAN_frame_t *status, bool is_unicast, void CDChanger::generateStatus(Frame *status, bool is_unicast,
devices to) const { devices to) const {
status->is_unicast = is_unicast; status->is_unicast = is_unicast;
if (!is_unicast) if (!is_unicast)
+7 -7
View File
@@ -9,6 +9,7 @@
#include "avclan.hpp" #include "avclan.hpp"
#include "avclan_defs.h" #include "avclan_defs.h"
#include "frame.hpp"
namespace avclan { namespace avclan {
@@ -59,13 +60,13 @@ public:
static constexpr uint8_t id = dev_CD_CHANGER; static constexpr uint8_t id = dev_CD_CHANGER;
void init(); void init();
void handle(const AVCLAN_frame_t *in, AVCLAN_frame_t *out); void handle(const Frame *in, Frame *out);
void react(AVCLAN_frame_t *out, detail::Error::Send err); void react(Frame *out, detail::Error::Send err);
void enable(AVCLAN_frame_t *out); void enable(Frame *out);
void disable(AVCLAN_frame_t *out); void disable(Frame *out);
static bool pending(); static bool pending();
static void resolvepending(); static void resolvepending();
void emit(AVCLAN_frame_t *out); void emit(Frame *out);
void incrementTime(); void incrementTime();
bool isPlaying() const; bool isPlaying() const;
@@ -74,8 +75,7 @@ private:
void stopPlaying(); void stopPlaying();
void serialize(uint8_t *dst) const; void serialize(uint8_t *dst) const;
void setTime(uint8_t mins, uint8_t secs); void setTime(uint8_t mins, uint8_t secs);
void generateStatus(AVCLAN_frame_t *status, bool is_unicast, void generateStatus(Frame *status, bool is_unicast, devices to) const;
devices to) const;
void normalizeState(); void normalizeState();
bool playing = false; bool playing = false;
+4 -4
View File
@@ -4,16 +4,16 @@
#pragma once #pragma once
#include "avclan.hpp" #include "avclan.hpp"
#include "avclan_defs.h" #include "frame.hpp"
#include <concepts> #include <concepts>
#include <cstdint> #include <cstdint>
namespace avclan { namespace avclan {
template <class T> template <class T>
concept Device = requires { std::integral_constant<uint8_t, T::id>{}; } && concept Device = requires {
requires(T dev, const AVCLAN_frame_t *in, AVCLAN_frame_t *out, std::integral_constant<uint8_t, T::id>{};
detail::Error::Send err) { } && requires(T dev, const Frame *in, Frame *out, detail::Error::Send err) {
dev.init(); dev.init();
dev.handle(in, out); dev.handle(in, out);
dev.enable(out); dev.enable(out);
+118
View File
@@ -0,0 +1,118 @@
// copyright (C) 2006 Marcin Slonicki <marcin@softservice.com.pl>
// copyright (C) 2007 Louis Frigon
// Copyright (C) 2015 Allen Hill <allenofthehills@gmail.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#include <cstdint>
#include <cstring>
#include "com232.h" // error logging
#include "frame.hpp"
namespace {
using Error = avclan::Frame::Error;
using enum Error::Parse;
} // namespace
namespace avclan {
void Frame::print(Frame::Print print) const {
if (print.binary) {
uint8_t buffer[8];
uint8_t *bptr = buffer;
*bptr++ = 0x10; // Data Link Escape, signaling binary data forthcoming
*bptr++ = static_cast<uint8_t>(is_unicast);
// Send addresses in big-endian order
*bptr++ = static_cast<uint8_t>(controller_addr >> 8);
*bptr++ = static_cast<uint8_t>(controller_addr);
*bptr++ = static_cast<uint8_t>(peripheral_addr >> 8);
*bptr++ = static_cast<uint8_t>(peripheral_addr);
*bptr++ = control;
*bptr++ = length;
RS232_sendbytes(buffer, 8);
RS232_sendbytes(data, length);
bptr = buffer;
*bptr++ = 0x17; // End of transmission block
*bptr++ = 0x0D; // \r
*bptr++ = 0x0A; // \n
RS232_sendbytes(buffer, 3);
} else {
RS232_PrintHex4(static_cast<uint8_t>(is_unicast));
RS232_Print(" 0x");
RS232_PrintHex12(controller_addr);
RS232_Print(" 0x");
RS232_PrintHex12(peripheral_addr);
RS232_Print(" 0x");
RS232_PrintHex4(control);
RS232_Print(" 0x");
RS232_PrintHex4(length);
for (uint8_t i = 0; i < length; i++) {
RS232_Print(" 0x");
RS232_PrintHex8(data[i]);
}
RS232_Print("\n");
}
}
Error::Parse Frame::parse(const uint8_t *bytes, uint8_t len) {
struct errtype {
Error::Parse errno;
uint8_t val;
} err = {};
const uint8_t *last = bytes + len;
if (len < sizeof(avclan::Frame)) {
err.errno = TOO_SHORT;
goto handle_err;
}
is_unicast = (*bytes++ != 0U);
controller_addr = bytes[0] | ((uint16_t)bytes[1] << 8);
bytes += 2;
peripheral_addr = bytes[0] | ((uint16_t)bytes[1] << 8);
bytes += 2;
control = *bytes++;
length = *bytes++;
if (length > MAXLENGTH) {
err.errno = LENGTH_TOO_BIG;
err.val = length;
goto handle_err;
}
if ((bytes + length) <= last) {
memcpy(data, bytes, length);
} else {
err.errno = MISMATCH_LENGTH;
goto handle_err;
}
if (false) { // NOLINT(readability-simplify-boolean-expr)
handle_err:;
RS232_Print("ERR(parse): ");
switch (err.errno) {
case TOO_SHORT:
RS232_Print("not enough bytes too fill AVCLAN frame");
break;
case MISMATCH_LENGTH:
RS232_Print("frame->length is longer than remaining data");
break;
case LENGTH_TOO_BIG:
RS232_Print("frame->length exceeds MAXLENGTH: 0x");
RS232_PrintHex8(err.val);
break;
default: break;
}
RS232_Print("\n");
}
return err.errno;
}
} // namespace avclan
+38
View File
@@ -0,0 +1,38 @@
// copyright (C) 2006 Marcin Slonicki <marcin@softservice.com.pl>
// copyright (C) 2007 Louis Frigon
// Copyright (C) 2015 Allen Hill <allenofthehills@gmail.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <cstdint>
namespace avclan {
struct Frame {
struct Print {
bool print : 1 = false; // print at all
bool binary : 1 = false; // if printing, format as binary instead of text
bool verbose : 1 = false; // include extra context in error reports
};
struct Error {
enum class Parse : uint8_t {
TOO_SHORT = 0x01,
MISMATCH_LENGTH,
LENGTH_TOO_BIG,
};
};
static constexpr int MAXLENGTH = 32;
Error::Parse parse(const uint8_t *bytes, uint8_t len);
void print(Print print) const;
uint8_t reaction;
uint8_t owning_device;
bool is_unicast;
uint16_t controller_addr; // formerly "master"
uint16_t peripheral_addr; // formerly "slave"
uint8_t control = 0xF;
uint8_t length;
uint8_t data[MAXLENGTH];
};
} // namespace avclan
+6 -5
View File
@@ -7,6 +7,7 @@
#include "avclan_defs.h" #include "avclan_defs.h"
#include "bus.hpp" #include "bus.hpp"
#include "device.hpp" #include "device.hpp"
#include "frame.hpp"
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
@@ -24,16 +25,16 @@ public:
uint16_t address() const { return address_; }; uint16_t address() const { return address_; };
Error::Read read(AVCLAN_frame_t *in, log_t print) { Error::Read read(Frame *in, Frame::Print print) {
return bus.read(address_, in, print); return bus.read(address_, in, print);
}; };
Error::Send send(const AVCLAN_frame_t *out, log_t print) { Error::Send send(const Frame *out, Frame::Print print) {
return bus.send(out, print); return bus.send(out, print);
}; };
#define PACK3(a, b, c) (((uint32_t)(a) << 16) | ((uint32_t)(b) << 8) | (c)) #define PACK3(a, b, c) (((uint32_t)(a) << 16) | ((uint32_t)(b) << 8) | (c))
void route(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) { void route(const Frame *in, Frame *out) {
out->reaction = 0; out->reaction = 0;
if (AVCLAN_ismuted() || in->length < 3) if (AVCLAN_ismuted() || in->length < 3)
@@ -119,7 +120,7 @@ public:
} }
} }
void react(AVCLAN_frame_t *out, Error::Send err) { void react(Frame *out, Error::Send err) {
if (((Devs::id == out->owning_device) || ...)) if (((Devs::id == out->owning_device) || ...))
((Devs::id == out->owning_device ((Devs::id == out->owning_device
? std::get<Devs>(devices_).react(out, err), ? std::get<Devs>(devices_).react(out, err),
@@ -141,7 +142,7 @@ private:
dev.resolvepending(); dev.resolvepending();
} }
template <Device Dev> template <Device Dev>
void device_preroute(Dev dev, const AVCLAN_frame_t *in, AVCLAN_frame_t *out) { void device_preroute(Dev dev, const Frame *in, Frame *out) {
out->owning_device = Dev::id; out->owning_device = Dev::id;
dev.handle(in, out); dev.handle(in, out);
} }
+25 -24
View File
@@ -11,6 +11,7 @@
#include "board.h" #include "board.h"
#include "cdchanger.hpp" #include "cdchanger.hpp"
#include "com232.h" #include "com232.h"
#include "frame.hpp"
#include "peripheral.hpp" #include "peripheral.hpp"
#include "queue.hpp" #include "queue.hpp"
@@ -18,8 +19,10 @@ const char *const offon[] = {"OFF", "ON"};
constexpr uint8_t CACHE_SIZE = 32; constexpr uint8_t CACHE_SIZE = 32;
using namespace avclan;
namespace { namespace {
AVCLAN_frame_t frames[CACHE_SIZE]; Frame frames[CACHE_SIZE];
constinit Queue cache(frames); constinit Queue cache(frames);
constinit Queue incoming = cache; constinit Queue incoming = cache;
@@ -60,17 +63,13 @@ int main() {
// Binary-mode REPL includes the full wire preamble (broadcast + 2*addr + // Binary-mode REPL includes the full wire preamble (broadcast + 2*addr +
// control + length), so size for the worst case. // control + length), so size for the worst case.
uint8_t data_tmp[MAXMSGLEN + sizeof(AVCLAN_frame_t)]; uint8_t data_tmp[Frame::MAXLENGTH + sizeof(Frame)];
uint8_t seqIdx = 0; // current index in data_tmp uint8_t seqIdx = 0; // current index in data_tmp
// Temporary, direct access is questionable since cache has ownership Bus phy;
for (auto &frame : frames) { Peripheral<CDChanger> peripheral(phy, 0x360);
frame.control = 0x0f; using Error = decltype(peripheral)::Error;
} using Print = Frame::Print;
avclan::Bus phy;
avclan::Peripheral<avclan::CDChanger> cd_changer(phy, 0x360);
using Error = decltype(cd_changer)::Error;
Setup(); Setup();
print_help(); print_help();
@@ -78,7 +77,7 @@ int main() {
while (true) { while (true) {
if (AVCLAN_busActive()) { if (AVCLAN_busActive()) {
if (auto msg = cache.pop()) { if (auto msg = cache.pop()) {
auto err = cd_changer.read(msg.get(), (log_t){.print = printAllFrames, auto err = peripheral.read(msg.get(), Print{.print = printAllFrames,
.binary = printBinary, .binary = printBinary,
.verbose = verbose}); .verbose = verbose});
if (err == Error::Read{0x00}) if (err == Error::Read{0x00})
@@ -90,7 +89,7 @@ int main() {
if (const auto *in = incoming.peek()) { if (const auto *in = incoming.peek()) {
if (auto out = cache.pop()) { if (auto out = cache.pop()) {
cd_changer.route(in, out.get()); peripheral.route(in, out.get());
incoming.pop(); incoming.pop();
if (out->reaction > 0) if (out->reaction > 0)
@@ -100,7 +99,7 @@ int main() {
} }
} }
cd_changer.poll_devices([&](auto dev) { peripheral.poll_devices([&](auto dev) {
if (auto status = cache.pop()) { if (auto status = cache.pop()) {
dev.emit(status.get()); dev.emit(status.get());
outgoing.push(std::move(status)); outgoing.push(std::move(status));
@@ -110,9 +109,9 @@ int main() {
}); });
if (auto out = outgoing.pop()) { if (auto out = outgoing.pop()) {
auto err = cd_changer.send( auto err = peripheral.send(
out.get(), (log_t){.print = printAllFrames, .binary = printBinary}); out.get(), Print{.print = printAllFrames, .binary = printBinary});
cd_changer.react(out.get(), err); peripheral.react(out.get(), err);
if (out->reaction > 0) if (out->reaction > 0)
outgoing.push(std::move(out)); outgoing.push(std::move(out));
} }
@@ -139,8 +138,8 @@ int main() {
case 'E': // Beep case 'E': // Beep
if (auto out = cache.pop()) { if (auto out = cache.pop()) {
out->is_unicast = true; out->is_unicast = true;
out->controller_addr = cd_changer.address(); out->controller_addr = peripheral.address();
out->peripheral_addr = HU_ADDR; out->peripheral_addr = peripheral.controller();
{ {
const uint8_t beep[] = {0x00, dev_CD_CHANGER, dev_BEEP_SPEAKERS, const uint8_t beep[] = {0x00, dev_CD_CHANGER, dev_BEEP_SPEAKERS,
0x60, 0x01}; 0x60, 0x01};
@@ -154,15 +153,15 @@ int main() {
case 'P': case 'P':
if (auto out = cache.pop()) { if (auto out = cache.pop()) {
out->is_unicast = true; out->is_unicast = true;
out->controller_addr = cd_changer.address(); out->controller_addr = peripheral.address();
out->peripheral_addr = HU_ADDR; out->peripheral_addr = peripheral.controller();
{ {
const uint8_t play[] = {0x00, dev_COMM_CTRL, dev_COMM_v1, const uint8_t play[] = {0x00, dev_COMM_CTRL, dev_COMM_v1,
Ejection, dev_CD_CHANGER, 0x01}; Ejection, dev_CD_CHANGER, 0x01};
out->length = sizeof(play); out->length = sizeof(play);
memcpy(out->data, play, sizeof(play)); memcpy(out->data, play, sizeof(play));
} }
out->reaction = avclan::CDChanger::reaction_t::r_Ejection; out->reaction = CDChanger::reaction_t::r_Ejection;
outgoing.push(std::move(out)); outgoing.push(std::move(out));
} }
break; break;
@@ -224,7 +223,8 @@ int main() {
if (readBinary) { if (readBinary) {
if (data_tmp[seqIdx] == 0x17) { if (data_tmp[seqIdx] == 0x17) {
if (auto out = cache.pop()) { if (auto out = cache.pop()) {
if (!AVCLAN_parseframe(data_tmp, --seqIdx, out.get())) { if (out->parse(data_tmp, --seqIdx) ==
Frame::Error::Parse{0}) {
out->reaction = 1; out->reaction = 1;
outgoing.push(std::move(out)); outgoing.push(std::move(out));
} }
@@ -236,8 +236,9 @@ int main() {
} else { } else {
if (auto out = cache.pop()) { if (auto out = cache.pop()) {
out->is_unicast = seqIsUnicast; out->is_unicast = seqIsUnicast;
out->controller_addr = cd_changer.address(); out->controller_addr = peripheral.address();
out->peripheral_addr = seqIsUnicast ? HU_ADDR : 0x1FF; out->peripheral_addr =
seqIsUnicast ? peripheral.controller() : 0x1FF;
out->length = seqIdx; out->length = seqIdx;
memcpy(out->data, data_tmp, seqIdx); memcpy(out->data, data_tmp, seqIdx);
out->reaction = 1; out->reaction = 1;