pub mod stream;
use crate::protocols::idn::protocol::{
ServiceMapEntry, IDNFLG_SCAN_STATUS_EXCLUDED, IDNFLG_SCAN_STATUS_MALFUNCTION,
IDNFLG_SCAN_STATUS_OCCUPIED, IDNFLG_SCAN_STATUS_OFFLINE, IDNFLG_SCAN_STATUS_REALTIME,
IDNFLG_SERVICEMAP_DSID, IDNVAL_STYPE_DMX512, IDNVAL_STYPE_LAPRO, IDNVAL_STYPE_UART,
};
use std::net::SocketAddr;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ServiceType {
LaserProjector,
Uart,
Dmx512,
Unknown(u8),
}
impl From<u8> for ServiceType {
fn from(value: u8) -> Self {
if (0x80..=0xBF).contains(&value) {
return ServiceType::LaserProjector;
}
match value {
IDNVAL_STYPE_UART => ServiceType::Uart,
IDNVAL_STYPE_DMX512 => ServiceType::Dmx512,
other => ServiceType::Unknown(other),
}
}
}
impl From<ServiceType> for u8 {
fn from(value: ServiceType) -> Self {
match value {
ServiceType::LaserProjector => IDNVAL_STYPE_LAPRO,
ServiceType::Uart => IDNVAL_STYPE_UART,
ServiceType::Dmx512 => IDNVAL_STYPE_DMX512,
ServiceType::Unknown(v) => v,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RelayInfo {
pub relay_number: u8,
pub name: String,
pub address: Option<SocketAddr>,
}
impl RelayInfo {
pub fn from_entry(entry: &ServiceMapEntry) -> Self {
Self {
relay_number: entry.relay_number,
name: entry.name_str().to_string(),
address: None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ServiceInfo {
pub service_id: u8,
pub service_type: ServiceType,
pub name: String,
pub flags: u8,
pub relay_number: u8,
}
impl ServiceInfo {
pub fn from_entry(entry: &ServiceMapEntry) -> Self {
Self {
service_id: entry.service_id,
service_type: ServiceType::from(entry.service_type),
name: entry.name_str().to_string(),
flags: entry.flags,
relay_number: entry.relay_number,
}
}
pub fn is_laser_projector(&self) -> bool {
matches!(self.service_type, ServiceType::LaserProjector)
}
pub fn is_default(&self) -> bool {
self.flags & IDNFLG_SERVICEMAP_DSID != 0
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ServerInfo {
pub unit_id: [u8; 16],
pub hostname: String,
pub protocol_version: (u8, u8),
pub status: u8,
pub addresses: Vec<SocketAddr>,
pub relays: Vec<RelayInfo>,
pub services: Vec<ServiceInfo>,
}
impl ServerInfo {
pub fn new(
unit_id: [u8; 16],
hostname: String,
protocol_version: (u8, u8),
status: u8,
) -> Self {
Self {
unit_id,
hostname,
protocol_version,
status,
addresses: Vec::new(),
relays: Vec::new(),
services: Vec::new(),
}
}
pub fn primary_address(&self) -> Option<&SocketAddr> {
self.addresses.first()
}
pub fn find_laser_projector(&self) -> Option<&ServiceInfo> {
self.services.iter().find(|s| s.is_laser_projector())
}
pub fn find_service(&self, service_id: u8) -> Option<&ServiceInfo> {
self.services.iter().find(|s| s.service_id == service_id)
}
pub fn has_malfunction(&self) -> bool {
self.status & IDNFLG_SCAN_STATUS_MALFUNCTION != 0
}
pub fn is_offline(&self) -> bool {
self.status & IDNFLG_SCAN_STATUS_OFFLINE != 0
}
pub fn is_occupied(&self) -> bool {
self.status & IDNFLG_SCAN_STATUS_OCCUPIED != 0
}
pub fn is_excluded(&self) -> bool {
self.status & IDNFLG_SCAN_STATUS_EXCLUDED != 0
}
pub fn supports_realtime(&self) -> bool {
self.status & IDNFLG_SCAN_STATUS_REALTIME != 0
}
}
#[derive(Debug, Clone)]
pub struct Addressed {
pub server: ServerInfo,
pub service: ServiceInfo,
pub address: SocketAddr,
}
impl Addressed {
pub fn new(server: ServerInfo, service: ServiceInfo, address: SocketAddr) -> Self {
Self {
server,
service,
address,
}
}
pub fn service_id(&self) -> u8 {
self.service.service_id
}
pub fn hostname(&self) -> &str {
&self.server.hostname
}
}
#[cfg(test)]
mod tests {
use super::*;
fn make_server(status: u8) -> ServerInfo {
ServerInfo::new([0u8; 16], "test".to_string(), (1, 0), status)
}
#[test]
fn test_is_excluded() {
let server = make_server(IDNFLG_SCAN_STATUS_EXCLUDED);
assert!(server.is_excluded());
let server = make_server(0);
assert!(!server.is_excluded());
let server = make_server(0xFF);
assert!(server.is_excluded());
}
}