mirror of
https://github.com/halleysfifthinc/AVCLAN-Mockingboard.git
synced 2026-08-06 17:03:17 +00:00
Port Frame object to C++
This commit is contained in:
+1
-1
@@ -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
|
||||
# are contributed by its subdirectory.
|
||||
add_library(avclan STATIC
|
||||
src/avclan/avclan_frame.c
|
||||
src/avclan/frame.cc
|
||||
src/avclan/cdchanger.cc
|
||||
src/avclan/bus.cc
|
||||
)
|
||||
|
||||
@@ -11,11 +11,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define MAXMSGLEN 32
|
||||
|
||||
#define DEVICE_ADDR 0x360 // CD Changer address
|
||||
#define HU_ADDR 0x190 // Head-unit address
|
||||
|
||||
typedef enum : uint8_t {
|
||||
dev_LAN = 0x00,
|
||||
dev_COMM_CTRL = 0x01,
|
||||
@@ -109,23 +104,6 @@ typedef enum : uint8_t {
|
||||
Report_TOC = 0xf9,
|
||||
} 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
|
||||
// values); bit_start marks a frame start bit.
|
||||
typedef enum avclan_bit : uint8_t {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -9,7 +9,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "avclan_defs.h"
|
||||
#include "avclan_frame.h"
|
||||
#include "avclan_phy.h"
|
||||
#include "mediacontrol.h"
|
||||
#include "statustimer.h"
|
||||
|
||||
+6
-7
@@ -32,9 +32,9 @@
|
||||
#include "bus.hpp"
|
||||
#include "avclan.hpp"
|
||||
#include "avclan_defs.h"
|
||||
#include "avclan_frame.h"
|
||||
#include "avclan_phy.h" // bridge until phy has been ported
|
||||
#include "com232.h"
|
||||
#include "frame.hpp"
|
||||
|
||||
namespace {
|
||||
constexpr int ADDR_WIDTH = 12;
|
||||
@@ -45,8 +45,7 @@ void Bus::init() { AVCLAN_busInit(); };
|
||||
void Bus::mute(bool mute) { AVCLAN_muteDevice(mute); };
|
||||
bool Bus::is_muted() const { return AVCLAN_ismuted(); };
|
||||
|
||||
auto Bus::read(uint16_t address, AVCLAN_frame_t *in, log_t print)
|
||||
-> Error::Read {
|
||||
auto Bus::read(uint16_t address, Frame *in, Frame::Print print) -> Error::Read {
|
||||
struct errtype {
|
||||
Error::Read errno;
|
||||
union {
|
||||
@@ -113,7 +112,7 @@ auto Bus::read(uint16_t address, AVCLAN_frame_t *in, log_t print)
|
||||
goto handle_err;
|
||||
}
|
||||
|
||||
if (in->length == 0 || in->length > MAXMSGLEN) {
|
||||
if (in->length == 0 || in->length > Frame::MAXLENGTH) {
|
||||
err.errno = BAD_LENGTH_RANGE;
|
||||
err.val = in->length;
|
||||
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 (err.errno > BAD_DATA_PARITY)
|
||||
in->length = 0;
|
||||
AVCLAN_printframe(in, print.binary);
|
||||
in->print(print);
|
||||
}
|
||||
|
||||
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 {
|
||||
// Error enum is ordered such that a lower numeric value corresponds to
|
||||
// more success
|
||||
@@ -267,7 +266,7 @@ auto Bus::send(const AVCLAN_frame_t *out, log_t print) -> Error::Send {
|
||||
}
|
||||
|
||||
if (print.print)
|
||||
AVCLAN_printframe(out, print.binary);
|
||||
out->print(print);
|
||||
|
||||
return err.errno;
|
||||
}
|
||||
|
||||
+3
-2
@@ -52,6 +52,7 @@
|
||||
#include "avclan.hpp"
|
||||
#include "avclan_defs.h"
|
||||
#include "avclan_phy.h" // bridge until phy has been ported
|
||||
#include "frame.hpp"
|
||||
|
||||
namespace avclan {
|
||||
class Bus {
|
||||
@@ -63,8 +64,8 @@ public:
|
||||
void mute(bool mute);
|
||||
bool is_muted() const;
|
||||
|
||||
Error::Read read(uint16_t address, AVCLAN_frame_t *in, log_t print);
|
||||
Error::Send send(const AVCLAN_frame_t *out, log_t print);
|
||||
Error::Read read(uint16_t address, Frame *in, Frame::Print print);
|
||||
Error::Send send(const Frame *out, Frame::Print print);
|
||||
|
||||
static Handle get();
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "avclan_defs.h"
|
||||
#include "cdchanger.hpp"
|
||||
#include "frame.hpp"
|
||||
#include "mediacontrol.h"
|
||||
#include "statustimer.h"
|
||||
|
||||
@@ -53,7 +54,7 @@ void CDChanger::init() {
|
||||
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 auto from = static_cast<devices>(*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);
|
||||
out->reaction = r_Nothing;
|
||||
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 (mins > TWODIGIT_MAX)
|
||||
mins = 0;
|
||||
@@ -318,7 +319,7 @@ void CDChanger::enable(AVCLAN_frame_t *out) {
|
||||
bool CDChanger::pending() { return statustimer_tickPending(); }
|
||||
void CDChanger::resolvepending() { statustimer_clearTick(); }
|
||||
|
||||
void CDChanger::emit(AVCLAN_frame_t *out) {
|
||||
void CDChanger::emit(Frame *out) {
|
||||
generateStatus(out, true, dev_STATUS);
|
||||
out->reaction = r_StateReport;
|
||||
}
|
||||
@@ -377,7 +378,7 @@ void CDChanger::incrementTime() {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
status->is_unicast = is_unicast;
|
||||
if (!is_unicast)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "avclan.hpp"
|
||||
#include "avclan_defs.h"
|
||||
#include "frame.hpp"
|
||||
|
||||
namespace avclan {
|
||||
|
||||
@@ -59,13 +60,13 @@ public:
|
||||
static constexpr uint8_t id = dev_CD_CHANGER;
|
||||
void init();
|
||||
|
||||
void handle(const AVCLAN_frame_t *in, AVCLAN_frame_t *out);
|
||||
void react(AVCLAN_frame_t *out, detail::Error::Send err);
|
||||
void enable(AVCLAN_frame_t *out);
|
||||
void disable(AVCLAN_frame_t *out);
|
||||
void handle(const Frame *in, Frame *out);
|
||||
void react(Frame *out, detail::Error::Send err);
|
||||
void enable(Frame *out);
|
||||
void disable(Frame *out);
|
||||
static bool pending();
|
||||
static void resolvepending();
|
||||
void emit(AVCLAN_frame_t *out);
|
||||
void emit(Frame *out);
|
||||
void incrementTime();
|
||||
bool isPlaying() const;
|
||||
|
||||
@@ -74,8 +75,7 @@ private:
|
||||
void stopPlaying();
|
||||
void serialize(uint8_t *dst) const;
|
||||
void setTime(uint8_t mins, uint8_t secs);
|
||||
void generateStatus(AVCLAN_frame_t *status, bool is_unicast,
|
||||
devices to) const;
|
||||
void generateStatus(Frame *status, bool is_unicast, devices to) const;
|
||||
void normalizeState();
|
||||
|
||||
bool playing = false;
|
||||
|
||||
+12
-12
@@ -4,22 +4,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "avclan.hpp"
|
||||
#include "avclan_defs.h"
|
||||
#include "frame.hpp"
|
||||
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
|
||||
namespace avclan {
|
||||
template <class T>
|
||||
concept Device = requires { std::integral_constant<uint8_t, T::id>{}; } &&
|
||||
requires(T dev, const AVCLAN_frame_t *in, AVCLAN_frame_t *out,
|
||||
detail::Error::Send err) {
|
||||
dev.init();
|
||||
dev.handle(in, out);
|
||||
dev.enable(out);
|
||||
dev.react(out, err);
|
||||
{ dev.pending() } -> std::convertible_to<bool>;
|
||||
dev.resolvepending();
|
||||
dev.emit(out);
|
||||
};
|
||||
concept Device = requires {
|
||||
std::integral_constant<uint8_t, T::id>{};
|
||||
} && requires(T dev, const Frame *in, Frame *out, detail::Error::Send err) {
|
||||
dev.init();
|
||||
dev.handle(in, out);
|
||||
dev.enable(out);
|
||||
dev.react(out, err);
|
||||
{ dev.pending() } -> std::convertible_to<bool>;
|
||||
dev.resolvepending();
|
||||
dev.emit(out);
|
||||
};
|
||||
} // namespace avclan
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "avclan_defs.h"
|
||||
#include "bus.hpp"
|
||||
#include "device.hpp"
|
||||
#include "frame.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
@@ -24,16 +25,16 @@ public:
|
||||
|
||||
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);
|
||||
};
|
||||
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);
|
||||
};
|
||||
|
||||
#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;
|
||||
|
||||
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) || ...))
|
||||
((Devs::id == out->owning_device
|
||||
? std::get<Devs>(devices_).react(out, err),
|
||||
@@ -141,7 +142,7 @@ private:
|
||||
dev.resolvepending();
|
||||
}
|
||||
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;
|
||||
dev.handle(in, out);
|
||||
}
|
||||
|
||||
+27
-26
@@ -11,6 +11,7 @@
|
||||
#include "board.h"
|
||||
#include "cdchanger.hpp"
|
||||
#include "com232.h"
|
||||
#include "frame.hpp"
|
||||
#include "peripheral.hpp"
|
||||
#include "queue.hpp"
|
||||
|
||||
@@ -18,8 +19,10 @@ const char *const offon[] = {"OFF", "ON"};
|
||||
|
||||
constexpr uint8_t CACHE_SIZE = 32;
|
||||
|
||||
using namespace avclan;
|
||||
|
||||
namespace {
|
||||
AVCLAN_frame_t frames[CACHE_SIZE];
|
||||
Frame frames[CACHE_SIZE];
|
||||
|
||||
constinit Queue cache(frames);
|
||||
constinit Queue incoming = cache;
|
||||
@@ -60,17 +63,13 @@ int main() {
|
||||
|
||||
// Binary-mode REPL includes the full wire preamble (broadcast + 2*addr +
|
||||
// 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
|
||||
|
||||
// Temporary, direct access is questionable since cache has ownership
|
||||
for (auto &frame : frames) {
|
||||
frame.control = 0x0f;
|
||||
}
|
||||
|
||||
avclan::Bus phy;
|
||||
avclan::Peripheral<avclan::CDChanger> cd_changer(phy, 0x360);
|
||||
using Error = decltype(cd_changer)::Error;
|
||||
Bus phy;
|
||||
Peripheral<CDChanger> peripheral(phy, 0x360);
|
||||
using Error = decltype(peripheral)::Error;
|
||||
using Print = Frame::Print;
|
||||
|
||||
Setup();
|
||||
print_help();
|
||||
@@ -78,9 +77,9 @@ int main() {
|
||||
while (true) {
|
||||
if (AVCLAN_busActive()) {
|
||||
if (auto msg = cache.pop()) {
|
||||
auto err = cd_changer.read(msg.get(), (log_t){.print = printAllFrames,
|
||||
.binary = printBinary,
|
||||
.verbose = verbose});
|
||||
auto err = peripheral.read(msg.get(), Print{.print = printAllFrames,
|
||||
.binary = printBinary,
|
||||
.verbose = verbose});
|
||||
if (err == Error::Read{0x00})
|
||||
incoming.push(std::move(msg));
|
||||
} else {
|
||||
@@ -90,7 +89,7 @@ int main() {
|
||||
|
||||
if (const auto *in = incoming.peek()) {
|
||||
if (auto out = cache.pop()) {
|
||||
cd_changer.route(in, out.get());
|
||||
peripheral.route(in, out.get());
|
||||
incoming.pop();
|
||||
|
||||
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()) {
|
||||
dev.emit(status.get());
|
||||
outgoing.push(std::move(status));
|
||||
@@ -110,9 +109,9 @@ int main() {
|
||||
});
|
||||
|
||||
if (auto out = outgoing.pop()) {
|
||||
auto err = cd_changer.send(
|
||||
out.get(), (log_t){.print = printAllFrames, .binary = printBinary});
|
||||
cd_changer.react(out.get(), err);
|
||||
auto err = peripheral.send(
|
||||
out.get(), Print{.print = printAllFrames, .binary = printBinary});
|
||||
peripheral.react(out.get(), err);
|
||||
if (out->reaction > 0)
|
||||
outgoing.push(std::move(out));
|
||||
}
|
||||
@@ -139,8 +138,8 @@ int main() {
|
||||
case 'E': // Beep
|
||||
if (auto out = cache.pop()) {
|
||||
out->is_unicast = true;
|
||||
out->controller_addr = cd_changer.address();
|
||||
out->peripheral_addr = HU_ADDR;
|
||||
out->controller_addr = peripheral.address();
|
||||
out->peripheral_addr = peripheral.controller();
|
||||
{
|
||||
const uint8_t beep[] = {0x00, dev_CD_CHANGER, dev_BEEP_SPEAKERS,
|
||||
0x60, 0x01};
|
||||
@@ -154,15 +153,15 @@ int main() {
|
||||
case 'P':
|
||||
if (auto out = cache.pop()) {
|
||||
out->is_unicast = true;
|
||||
out->controller_addr = cd_changer.address();
|
||||
out->peripheral_addr = HU_ADDR;
|
||||
out->controller_addr = peripheral.address();
|
||||
out->peripheral_addr = peripheral.controller();
|
||||
{
|
||||
const uint8_t play[] = {0x00, dev_COMM_CTRL, dev_COMM_v1,
|
||||
Ejection, dev_CD_CHANGER, 0x01};
|
||||
out->length = 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));
|
||||
}
|
||||
break;
|
||||
@@ -224,7 +223,8 @@ int main() {
|
||||
if (readBinary) {
|
||||
if (data_tmp[seqIdx] == 0x17) {
|
||||
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;
|
||||
outgoing.push(std::move(out));
|
||||
}
|
||||
@@ -236,8 +236,9 @@ int main() {
|
||||
} else {
|
||||
if (auto out = cache.pop()) {
|
||||
out->is_unicast = seqIsUnicast;
|
||||
out->controller_addr = cd_changer.address();
|
||||
out->peripheral_addr = seqIsUnicast ? HU_ADDR : 0x1FF;
|
||||
out->controller_addr = peripheral.address();
|
||||
out->peripheral_addr =
|
||||
seqIsUnicast ? peripheral.controller() : 0x1FF;
|
||||
out->length = seqIdx;
|
||||
memcpy(out->data, data_tmp, seqIdx);
|
||||
out->reaction = 1;
|
||||
|
||||
Reference in New Issue
Block a user