mod amp;
mod audio;
mod commands;
mod handlers;
mod multiviewer;
mod network;
mod stats;
mod svd;
#[cfg(test)]
mod tests;
use std::net::Ipv4Addr;
use std::time::Instant;
use crate::event::Event;
use crate::state::State;
use crate::wire::{op, DeviceUid, Frame, Opcode};
pub use svd::{lookup_svd, Svd};
pub(crate) struct Rx<'a> {
pub(crate) frame: Frame<'a>,
pub(crate) address: Option<Ipv4Addr>,
pub(crate) timestamp: Instant,
}
impl Rx<'_> {
pub(crate) fn sender(&self) -> DeviceUid {
self.frame.remote_id()
}
pub(crate) fn uid_or_zero(&self, idx: usize) -> DeviceUid {
self.frame.uid(idx).unwrap_or(DeviceUid::ZERO)
}
}
pub(crate) fn process_frame(
state: &mut State,
data: &[u8],
address: Option<Ipv4Addr>,
timestamp: Instant,
) -> Vec<Event> {
let Ok(frame) = Frame::parse(data) else {
return Vec::new();
};
let sender = frame.remote_id();
if sender == state.uid {
return Vec::new();
}
state.frames_received = state.frames_received.saturating_add(1);
let rx = Rx {
frame,
address,
timestamp,
};
let mut ev = Vec::new();
dispatch(state, &rx, &mut ev);
if let Some(device) = state.device_mut(sender) {
device.touch(timestamp, Instant::now(), &mut ev);
}
ev
}
fn dispatch(state: &mut State, rx: &Rx<'_>, ev: &mut Vec<Event>) {
match rx.frame.opcode() {
op::SYS_HELLO => handlers::hello(state, rx, ev),
op::SYS_DISCOVER => commands::discover_request(state, rx, ev),
op::SYS_BAY_CONFIG | op::SYS_BAY_CONFIG_SECONDARY => handlers::bay_config(state, rx, ev),
op::SYS_LINKS => handlers::links(state, rx, ev),
op::DEV_CONNECT => handlers::connect_status(state, rx, ev),
op::DEV_POWER_CHANGE => handlers::power_change(state, rx, ev),
op::DEV_EDID => commands::edid(state, rx, ev),
op::MX_ROUTE => handlers::routing_change(state, rx, ev),
op::MX_SET_ROUTE => commands::set_route(state, rx, ev),
op::RC_IR => commands::ir_capture(state, rx, ev),
op::RC_KEY => handlers::rc_key(state, rx, ev),
op::RC_TX_KEY => commands::tx_key(state, rx, ev),
op::RC_ACTION => handlers::rc_action(state, rx, ev),
op::RC_TX_ACTION => commands::tx_action(state, rx, ev),
op::AUDIO_VOLUME_UP => commands::volume_step(state, rx, ev, true),
op::AUDIO_VOLUME_DOWN => commands::volume_step(state, rx, ev, false),
op::AUDIO_CLIP => commands::audio_clip(state, rx, ev),
op::AUDIO_VOLUME_MUTE => commands::volume_mute(state, rx, ev),
op::AUDIO_SET_ROUTE => commands::audio_set_route(state, rx, ev),
op::AUDIO_SET_VOLUME => handlers::volume_set(state, rx, ev),
op::SYS_TEMPERATURE => handlers::temperature(state, rx, ev),
op::PDU_STATE => commands::pdu_state(state, rx, ev),
op::V2IP_SOURCE_SWITCH => handlers::v2ip_source_switch(state, rx, ev),
op::V2IP_LINK_REMOTE => commands::v2ip_link_remote(state, rx, ev),
op::V2IP_DETECT_BAYS => commands::detect_bays(state, rx, ev),
op::CHANGE_BAY_NAME => commands::change_bay_name(state, rx, ev),
op::V2IP_MANUAL_SRC_SWITCH => handlers::v2ip_manual_source_switch(state, rx, ev),
op::SYS_BAY_V2IP_SOURCES => handlers::v2ip_sources(state, rx, ev),
op::BAY_HIDE => handlers::bay_hide(state, rx, ev),
op::SYS_REBOOT => commands::reboot(state, rx, ev),
op::NET_LINK_STATUS => network::network_status(state, rx, ev),
op::FIRMWARE_VERSION => handlers::firmware_version(state, rx, ev),
op::SYS_MONITORING_PULSE => commands::monitoring_pulse(state, rx, ev),
op::V2IP_UPGRADE_FPGA => commands::upgrade_fpga(state, rx, ev),
op::V2IP_BLIST_REGISTER => commands::blacklist(state, rx, ev, true),
op::V2IP_BLIST_UNREGISTER => commands::blacklist(state, rx, ev, false),
op::TOPOLOGY => handlers::topology(state, rx, ev),
op::BAY_SIGNAL_STATUS => svd::signal_status(state, rx, ev),
op::BAY_MIRROR_STATUS => handlers::mirror_status(state, rx, ev),
op::BAY_EDID_PROFILE => commands::edid_profile(state, rx, ev),
op::SETUP_STATUS => commands::setup_status(state, rx, ev),
op::SET_INSTALLER => commands::set_installer(state, rx, ev),
op::BAY_FILTER_STATUS => commands::filter_status(state, rx, ev),
op::BAY_STATUS => handlers::bay_status(state, rx, ev),
op::SYS_FACTORY_RESET => commands::factory_reset(state, rx, ev),
op::MESH_OPERATION => handlers::mesh_operation(state, rx, ev),
op::V2IP_DEVICE_CFG => handlers::v2ip_device_configuration(state, rx, ev),
op::AMP_ZONE_SETTINGS => amp::zone_settings(state, rx, ev),
op::AMP_DOLBY_STATE => amp::dolby_settings(state, rx, ev),
op::V2IP_STATS => stats::v2ip_stats(state, rx, ev),
op::V2IP_TILING => commands::v2ip_tiling(state, rx, ev),
op::V2IP_POWER_SAVE => commands::v2ip_power_save(state, rx, ev),
op::V2IP_MULTIVIEWER => multiviewer::multiviewer(state, rx, ev),
op::V2IP_AUDIO => audio::audio(state, rx, ev),
op::V2IP_BAY_MAPPINGS => handlers::v2ip_bay_mapping(state, rx, ev),
op::RC_SETTINGS => commands::rc_settings(state, rx, ev),
op::SYS_STATUS => handlers::system_status(state, rx, ev),
op::RC_IR_TX => commands::ir_transmit(state, rx, ev),
op::V2IP_VIDEO_WALL => commands::video_wall(state, rx, ev),
Opcode(_) => {}
}
}