mirror of
https://github.com/halleysfifthinc/AVCLAN-Mockingboard.git
synced 2026-08-07 01:13:18 +00:00
Port Queue to C++
Some knock-on changes to keep a simple design:
- Bake the data array into AVCLAN_frame_t
- Bundle the response/reaction with AVCLAN_frame_t
- (Needed to maintain correct/simple ownership semantics with the
cache and outgoing/incoming queues)
- Switch status frame update ticks to use a regular
cache-originating/owned frame
This commit is contained in:
@@ -116,12 +116,13 @@ typedef struct print_struct {
|
||||
} log_t;
|
||||
|
||||
typedef struct AVCLAN_frame_struct {
|
||||
uint8_t reaction;
|
||||
bool is_unicast;
|
||||
uint16_t controller_addr; // formerly "master"
|
||||
uint16_t peripheral_addr; // formerly "slave"
|
||||
uint8_t control;
|
||||
uint8_t length;
|
||||
uint8_t *data;
|
||||
uint8_t data[MAXMSGLEN];
|
||||
} AVCLAN_frame_t;
|
||||
|
||||
// A single bus symbol. bit_zero/bit_one carry data (and double as parity
|
||||
|
||||
@@ -25,11 +25,11 @@ static const uint8_t cdloading_resp[] = {dev_CD_CHANGER,
|
||||
0x01,
|
||||
0x02};
|
||||
|
||||
response_t AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
|
||||
response_t respond = r_Nothing;
|
||||
void AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
|
||||
out->reaction = r_Nothing;
|
||||
|
||||
if (AVCLAN_ismuted() || in->length < 3)
|
||||
return respond;
|
||||
return;
|
||||
|
||||
// 0xFF placeholders are variant bytes filled by writing directly to
|
||||
// out->data[N] after memcpy.
|
||||
@@ -60,7 +60,7 @@ response_t AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
|
||||
memcpy(out->data, lancheck_resp, sizeof(lancheck_resp));
|
||||
out->data[3] = Lancheck_Scan_Resp;
|
||||
out->data[4] = 0x01;
|
||||
respond = r_Handled;
|
||||
out->reaction = r_SendOnly;
|
||||
break;
|
||||
case PACK3(dev_LAN, dev_COMM_CTRL, Lancheck_Req):
|
||||
out->length = sizeof(lancheck_resp);
|
||||
@@ -69,7 +69,7 @@ response_t AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
|
||||
memcpy(out->data, lancheck_resp, sizeof(lancheck_resp));
|
||||
out->data[3] = Lancheck_Resp;
|
||||
out->data[4] = 0x00;
|
||||
respond = r_Handled;
|
||||
out->reaction = r_SendOnly;
|
||||
break;
|
||||
case PACK3(dev_LAN, dev_COMM_CTRL, Lancheck_End_Req):
|
||||
out->is_unicast = true;
|
||||
@@ -77,7 +77,7 @@ response_t AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
|
||||
out->length = sizeof(lancheck_resp) - 1;
|
||||
memcpy(out->data, lancheck_resp, out->length);
|
||||
out->data[3] = Lancheck_End_Resp;
|
||||
respond = r_Handled;
|
||||
out->reaction = r_SendOnly;
|
||||
break;
|
||||
case PACK3(dev_COMM_v1, dev_COMM_CTRL, Current_Function):
|
||||
case PACK3(dev_COMM_v2, dev_COMM_CTRL, Current_Function):
|
||||
@@ -89,7 +89,7 @@ response_t AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
|
||||
cd_status.state = cd_SEEKING | cd_SEEKING_TRACK;
|
||||
cd_status.flags2 = 0xc0;
|
||||
AVCLAN_generateStatus(out, true, dev_STATUS);
|
||||
respond = r_StartPlaying;
|
||||
out->reaction = r_StartPlaying;
|
||||
}
|
||||
break;
|
||||
case PACK3(dev_COMM_v1, dev_COMM_CTRL, Ping_Req):
|
||||
@@ -100,7 +100,7 @@ response_t AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
|
||||
Ping_Resp, 0xFF, b3};
|
||||
out->length = sizeof(ping_resp);
|
||||
memcpy(out->data, ping_resp, sizeof(ping_resp));
|
||||
respond = r_Handled;
|
||||
out->reaction = r_SendOnly;
|
||||
break;
|
||||
}
|
||||
case PACK3(dev_COMM_v1, dev_COMM_CTRL, List_Functions_Req):
|
||||
@@ -112,7 +112,7 @@ response_t AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
|
||||
dev_CD_CHANGER};
|
||||
out->length = sizeof(list_functions_resp);
|
||||
memcpy(out->data, list_functions_resp, sizeof(list_functions_resp));
|
||||
respond = r_Handled;
|
||||
out->reaction = r_SendOnly;
|
||||
break;
|
||||
}
|
||||
// case Restart_Lan: not handled
|
||||
@@ -130,7 +130,7 @@ response_t AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
|
||||
out->data[3] = Enable_Function_Resp;
|
||||
cd_status.state = 0;
|
||||
cd_status.flags2 = 0x80;
|
||||
respond = r_StatusReport;
|
||||
out->reaction = r_StatusReport;
|
||||
break;
|
||||
case PACK3(dev_COMM_v1, dev_CD_CHANGER, Disable_Function_Req):
|
||||
[[fallthrough]];
|
||||
@@ -145,7 +145,7 @@ response_t AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
|
||||
cd_status.flags2 = 0x80;
|
||||
out->is_unicast = true;
|
||||
out->peripheral_addr = HU_ADDR;
|
||||
respond = r_StatusReport;
|
||||
out->reaction = r_StatusReport;
|
||||
}
|
||||
break;
|
||||
case PACK3(dev_CMD_SW, dev_CD_CHANGER, Eject): {
|
||||
@@ -166,7 +166,7 @@ response_t AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
|
||||
out->length = sizeof(msg);
|
||||
memcpy(out->data, msg, sizeof(msg));
|
||||
}
|
||||
respond = r_Handled;
|
||||
out->reaction = r_SendOnly;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -182,7 +182,7 @@ response_t AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
|
||||
0x10, 0x01, 0x01};
|
||||
out->length = sizeof(cdinitreport_resp);
|
||||
memcpy(&out->data[1], cdinitreport_resp, sizeof(cdinitreport_resp));
|
||||
respond = r_Handled;
|
||||
out->reaction = r_SendOnly;
|
||||
break;
|
||||
}
|
||||
case PACK3(dev_CMD_SW, dev_CD_CHANGER, Playback_Request): [[fallthrough]];
|
||||
@@ -195,7 +195,7 @@ response_t AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
|
||||
serializeCDStatus(&out->data[4]);
|
||||
out->is_unicast = true;
|
||||
out->peripheral_addr = HU_ADDR;
|
||||
respond = r_Handled;
|
||||
out->reaction = r_SendOnly;
|
||||
break;
|
||||
case PACK3(dev_CMD_SW, dev_CD_CHANGER, Loading_Request2): [[fallthrough]];
|
||||
case PACK3(dev_STATUS, dev_CD_CHANGER, Loading_Request2):
|
||||
@@ -206,7 +206,7 @@ response_t AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
|
||||
out->data[3] = Loading_Response2;
|
||||
out->is_unicast = true;
|
||||
out->peripheral_addr = HU_ADDR;
|
||||
respond = r_Handled;
|
||||
out->reaction = r_SendOnly;
|
||||
break;
|
||||
case PACK3(dev_CMD_SW, dev_CD_CHANGER, Track_Seek_Up):
|
||||
cd_status.state = cd_SEEKING_TRACK;
|
||||
@@ -219,7 +219,7 @@ response_t AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
|
||||
cd_status.flags2 = 0xc0;
|
||||
AVCLAN_generateStatus(out, true, dev_CMD_SW);
|
||||
AVCLAN_mediaFunction(MEDIA_SKIP_FORWARD);
|
||||
respond = r_TrackChange;
|
||||
out->reaction = r_TrackChange;
|
||||
break;
|
||||
case PACK3(dev_CMD_SW, dev_CD_CHANGER, Track_Seek_Down):
|
||||
cd_status.state = cd_SEEKING_TRACK;
|
||||
@@ -235,7 +235,7 @@ response_t AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
|
||||
cd_status.flags2 = 0xc0;
|
||||
AVCLAN_generateStatus(out, true, dev_CMD_SW);
|
||||
AVCLAN_mediaFunction(MEDIA_SKIP_BACKWARD);
|
||||
respond = r_TrackChange;
|
||||
out->reaction = r_TrackChange;
|
||||
break;
|
||||
case PACK3(dev_CMD_SW, dev_CD_CHANGER, Track_Fast_Forward): {
|
||||
cd_status.state |= cd_SEEKING;
|
||||
@@ -248,7 +248,7 @@ response_t AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
|
||||
AVCLAN_mediaFunction(MEDIA_SKIP_FORWARD);
|
||||
statustimer_reset(); // Skipped to a whole/round sec; ensure next tick
|
||||
// is ~1 sec from now
|
||||
respond = r_Handled;
|
||||
out->reaction = r_SendOnly;
|
||||
break;
|
||||
}
|
||||
case PACK3(dev_CMD_SW, dev_CD_CHANGER, Track_Rewind): {
|
||||
@@ -268,67 +268,66 @@ response_t AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out) {
|
||||
AVCLAN_mediaFunction(MEDIA_SKIP_BACKWARD);
|
||||
statustimer_reset(); // Skipped to a whole/round sec; ensure next tick
|
||||
// is ~1 sec from now
|
||||
respond = r_Handled;
|
||||
out->reaction = r_SendOnly;
|
||||
break;
|
||||
}
|
||||
case PACK3(dev_CMD_SW, dev_CD_CHANGER, CD_Enable_Random):
|
||||
cd_status.flags |= cd_RANDOM;
|
||||
AVCLAN_generateStatus(out, true, dev_CMD_SW);
|
||||
respond = r_StatusReport;
|
||||
out->reaction = r_StatusReport;
|
||||
break;
|
||||
case PACK3(dev_CMD_SW, dev_CD_CHANGER, CD_Disable_Random):
|
||||
cd_status.flags &= ~cd_RANDOM;
|
||||
AVCLAN_generateStatus(out, true, dev_CMD_SW);
|
||||
respond = r_StatusReport;
|
||||
out->reaction = r_StatusReport;
|
||||
break;
|
||||
case PACK3(dev_CMD_SW, dev_CD_CHANGER, CD_Enable_Repeat):
|
||||
cd_status.flags |= cd_REPEAT;
|
||||
AVCLAN_generateStatus(out, true, dev_CMD_SW);
|
||||
respond = r_StatusReport;
|
||||
out->reaction = r_StatusReport;
|
||||
break;
|
||||
case PACK3(dev_CMD_SW, dev_CD_CHANGER, CD_Disable_Repeat):
|
||||
cd_status.flags &= ~cd_REPEAT;
|
||||
AVCLAN_generateStatus(out, true, dev_CMD_SW);
|
||||
respond = r_StatusReport;
|
||||
out->reaction = r_StatusReport;
|
||||
break;
|
||||
case PACK3(dev_CMD_SW, dev_CD_CHANGER, CD_Enable_Disk_Random):
|
||||
cd_status.flags |= cd_DISK_RANDOM;
|
||||
AVCLAN_generateStatus(out, true, dev_CMD_SW);
|
||||
respond = r_StatusReport;
|
||||
out->reaction = r_StatusReport;
|
||||
break;
|
||||
case PACK3(dev_CMD_SW, dev_CD_CHANGER, CD_Disable_Disk_Random):
|
||||
cd_status.flags &= ~cd_DISK_RANDOM;
|
||||
AVCLAN_generateStatus(out, true, dev_CMD_SW);
|
||||
respond = r_StatusReport;
|
||||
out->reaction = r_StatusReport;
|
||||
break;
|
||||
case PACK3(dev_CMD_SW, dev_CD_CHANGER, CD_Enable_Disk_Repeat):
|
||||
cd_status.flags |= cd_DISK_REPEAT;
|
||||
AVCLAN_generateStatus(out, true, dev_CMD_SW);
|
||||
respond = r_StatusReport;
|
||||
out->reaction = r_StatusReport;
|
||||
break;
|
||||
case PACK3(dev_CMD_SW, dev_CD_CHANGER, CD_Disable_Disk_Repeat):
|
||||
cd_status.flags &= ~cd_DISK_REPEAT;
|
||||
AVCLAN_generateStatus(out, true, dev_CMD_SW);
|
||||
respond = r_StatusReport;
|
||||
out->reaction = r_StatusReport;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return respond;
|
||||
}
|
||||
|
||||
#undef PACK3
|
||||
|
||||
RFrame_t *AVCLAN_statemachine(RFrame_t *resp) {
|
||||
AVCLAN_frame_t *out = resp->frame;
|
||||
switch (resp->r) {
|
||||
void AVCLAN_statemachine(AVCLAN_frame_t *out) {
|
||||
reaction_t r = out->reaction;
|
||||
out->reaction = r_Nothing;
|
||||
switch (r) {
|
||||
case r_Ejection: {
|
||||
const uint8_t play[] = {0x00, dev_COMM_CTRL, dev_COMM_v1,
|
||||
Insertion, dev_CD_CHANGER, 0x01};
|
||||
out->length = sizeof(play);
|
||||
memcpy(out->data, play, sizeof(play));
|
||||
}
|
||||
resp->r = r_Report_Load;
|
||||
out->reaction = r_Report_Load;
|
||||
break;
|
||||
case r_Report_Load:
|
||||
out->is_unicast = false;
|
||||
@@ -337,7 +336,7 @@ RFrame_t *AVCLAN_statemachine(RFrame_t *resp) {
|
||||
memcpy(out->data, cdloading_resp, sizeof(cdloading_resp));
|
||||
out->data[1] = dev_STATUS;
|
||||
out->data[2] = Loading_Status_Report;
|
||||
resp->r = r_Handled;
|
||||
out->reaction = r_SendOnly;
|
||||
break;
|
||||
case r_TrackChange:
|
||||
AVCLAN_setTime(0x00, 0x00);
|
||||
@@ -347,24 +346,23 @@ RFrame_t *AVCLAN_statemachine(RFrame_t *resp) {
|
||||
case r_NormalizeState:
|
||||
AVCLAN_normalizeState();
|
||||
AVCLAN_generateStatus(out, true, dev_STATUS);
|
||||
resp->r = r_Handled;
|
||||
out->reaction = r_SendOnly;
|
||||
break;
|
||||
case r_StartPlaying:
|
||||
AVCLAN_normalizeState();
|
||||
AVCLAN_generateStatus(out, true, dev_STATUS);
|
||||
resp->r = r_BeganPlaying;
|
||||
out->reaction = r_BeganPlaying;
|
||||
break;
|
||||
case r_BeganPlaying:
|
||||
AVCLAN_startPlaying(); // only start PIT after normalizing state
|
||||
resp->r = r_Nothing;
|
||||
out->reaction = r_Nothing;
|
||||
break;
|
||||
case r_StatusReport:
|
||||
AVCLAN_generateStatus(out, true, dev_STATUS);
|
||||
resp->r = r_Handled;
|
||||
out->reaction = r_SendOnly;
|
||||
break;
|
||||
case r_Handled: [[fallthrough]];
|
||||
case r_SendOnly: [[fallthrough]];
|
||||
case r_Nothing: [[fallthrough]];
|
||||
default: resp->r = r_Nothing;
|
||||
default: out->reaction = r_Nothing;
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
@@ -17,12 +17,11 @@ extern "C" {
|
||||
|
||||
/// Message state machine
|
||||
// - r_Nothing (0x00) means don't send current message
|
||||
// - r_Handled means send current message and stop/finished state machine
|
||||
// - All other instances mean send current message and imply the presence of
|
||||
// follow-up messages within state machine
|
||||
typedef enum : uint8_t {
|
||||
r_Nothing = 0x00,
|
||||
r_Handled, // No follow-up needed
|
||||
r_SendOnly, // No further follow-up needed (beyond sending current)
|
||||
r_StatusReport = 0x02, // Needs follow-up status report
|
||||
r_NormalizeState, // cd_status needs normalized and resent
|
||||
r_StartPlaying, // ~equivalent to normalizeState, but cycles to BeganPlaying
|
||||
@@ -30,15 +29,10 @@ typedef enum : uint8_t {
|
||||
r_TrackChange, // Time needs reset
|
||||
r_Ejection,
|
||||
r_Report_Load,
|
||||
} response_t;
|
||||
} reaction_t;
|
||||
|
||||
typedef struct RFrame_struct {
|
||||
response_t r;
|
||||
AVCLAN_frame_t *frame;
|
||||
} RFrame_t;
|
||||
|
||||
response_t AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out);
|
||||
RFrame_t *AVCLAN_statemachine(RFrame_t *resp);
|
||||
void AVCLAN_handleframe(const AVCLAN_frame_t *in, AVCLAN_frame_t *out);
|
||||
void AVCLAN_statemachine(AVCLAN_frame_t *out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+5
-21
@@ -75,30 +75,14 @@ void AVCLAN_setTime(uint8_t mins, uint8_t secs) {
|
||||
cd_status.secs = secs;
|
||||
}
|
||||
|
||||
// Only used for regularly scheduled periodic updates
|
||||
AVCLAN_frame_t *AVCLAN_getStatusFrame() {
|
||||
static uint8_t status_data[sizeof(AVCLAN_CD_Status_t) + 3] = {0};
|
||||
static AVCLAN_frame_t status = {.is_unicast = false,
|
||||
.controller_addr = DEVICE_ADDR,
|
||||
.peripheral_addr = 0x1FF,
|
||||
.control = 0xF,
|
||||
.length = sizeof(status_data),
|
||||
.data = status_data};
|
||||
|
||||
return &status;
|
||||
}
|
||||
|
||||
// Used for changed status messages
|
||||
void AVCLAN_generateStatus(AVCLAN_frame_t *status, bool is_unicast,
|
||||
devices to) {
|
||||
*status = (AVCLAN_frame_t){
|
||||
.is_unicast = is_unicast,
|
||||
.controller_addr = DEVICE_ADDR,
|
||||
.peripheral_addr = (is_unicast) ? HU_ADDR : 0x1FF,
|
||||
.control = 0xF,
|
||||
.length = sizeof(AVCLAN_CD_Status_t) + ((is_unicast) ? 4 : 3),
|
||||
.data = status->data, // don't overwrite data pointer
|
||||
};
|
||||
status->is_unicast = is_unicast;
|
||||
status->controller_addr = DEVICE_ADDR;
|
||||
status->peripheral_addr = (is_unicast) ? HU_ADDR : 0x1FF;
|
||||
status->control = 0xF;
|
||||
status->length = sizeof(AVCLAN_CD_Status_t) + ((is_unicast) ? 4 : 3);
|
||||
|
||||
uint8_t *data = status->data;
|
||||
if (is_unicast)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# AVR / ATtiny3216 hardware target (port).
|
||||
|
||||
include(CMakeDependentOption)
|
||||
include(FetchContent)
|
||||
|
||||
# --- Port implementation sources -------------------------------------------
|
||||
target_sources(avclan PRIVATE
|
||||
@@ -79,8 +79,21 @@ try_compile(LIBC_VERSION_TEST
|
||||
COMPILE_DEFINITIONS -mmcu=${AVR_MCU}
|
||||
)
|
||||
|
||||
if (AVCLAN_TARGET STREQUAL "avr-attiny3216")
|
||||
FetchContent_Declare(
|
||||
avr_libstdcpp
|
||||
GIT_REPOSITORY https://github.com/modm-io/avr-libstdcpp.git
|
||||
GIT_TAG 5354296040a2289c911062daa82336762231e897
|
||||
)
|
||||
FetchContent_MakeAvailable(avr_libstdcpp)
|
||||
add_library(libstdcpp INTERFACE)
|
||||
target_include_directories(libstdcpp SYSTEM
|
||||
INTERFACE ${avr_libstdcpp_SOURCE_DIR}/include)
|
||||
target_link_libraries(avclan INTERFACE libstdcpp)
|
||||
endif()
|
||||
|
||||
|
||||
if(NOT LIBC_VERSION_TEST)
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
attiny_atpack
|
||||
URL http://packs.download.atmel.com/Atmel.ATtiny_DFP.2.0.368.atpack
|
||||
|
||||
Reference in New Issue
Block a user