use crate::core::firmware::FirmwareVersion;
use crate::core::model::Model;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PushMode {
Full,
DeltaOnly,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CameraTransport {
Rtsp322,
JpegTcp6000,
None,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ChamberTemperature {
RealSensor,
ReportedSynthetic,
Unsupported,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct HardwareFeatures {
pub lidar: bool,
pub chamber_temperature: ChamberTemperature,
pub aux_fan: bool,
pub chamber_fan: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DeveloperMode {
Available,
Unavailable,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AcsPolicy {
Required,
NotRequired,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EvidenceGrade {
Observed,
VendorSpec,
DocSpec,
Inferred,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RegistryStatus {
Supported,
FirmwareNewerThanKnown,
UnknownModel,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ControlPermit {
Allowed,
RequiresDeveloperMode,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ControlRefusal {
UnknownModel,
FirmwareNewerThanKnown,
DeveloperModeUnavailable,
UnknownControlBoundary,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Capabilities {
pub model: Model,
pub push_mode: Option<PushMode>,
pub camera_transport: Option<CameraTransport>,
pub hardware: Option<HardwareFeatures>,
pub developer_mode: Option<DeveloperMode>,
pub acs_policy: Option<AcsPolicy>,
pub evidence: Option<EvidenceGrade>,
pub registry_status: RegistryStatus,
}
impl Capabilities {
pub fn control_permission(&self) -> Result<ControlPermit, ControlRefusal> {
match self.registry_status {
RegistryStatus::UnknownModel => return Err(ControlRefusal::UnknownModel),
RegistryStatus::FirmwareNewerThanKnown => {
return Err(ControlRefusal::FirmwareNewerThanKnown);
}
RegistryStatus::Supported => {}
}
match (self.acs_policy, self.developer_mode) {
(Some(AcsPolicy::NotRequired), _) => Ok(ControlPermit::Allowed),
(Some(AcsPolicy::Required), Some(DeveloperMode::Available)) => {
Ok(ControlPermit::RequiresDeveloperMode)
}
(Some(AcsPolicy::Required), Some(DeveloperMode::Unavailable)) => {
Err(ControlRefusal::DeveloperModeUnavailable)
}
_ => Err(ControlRefusal::UnknownControlBoundary),
}
}
pub fn control_allowed(&self) -> bool {
self.control_permission().is_ok()
}
pub fn control_assessment(&self) -> ControlAssessment {
match self.registry_status {
RegistryStatus::FirmwareNewerThanKnown => ControlAssessment::NewerFirmwareUntested,
RegistryStatus::UnknownModel => {
ControlAssessment::Refused(ControlRefusal::UnknownModel)
}
RegistryStatus::Supported => match self.control_permission() {
Ok(ControlPermit::Allowed) => ControlAssessment::Allowed,
Ok(ControlPermit::RequiresDeveloperMode) => {
ControlAssessment::RequiresDeveloperMode
}
Err(refusal) => ControlAssessment::Refused(refusal),
},
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ControlAssessment {
Allowed,
RequiresDeveloperMode,
NewerFirmwareUntested,
Refused(ControlRefusal),
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct ControlBoundary {
developer_mode_since: FirmwareVersion,
acs_policy: AcsPolicy,
}
struct ModelProfile {
model: Model,
push_mode: PushMode,
camera_transport: CameraTransport,
hardware: HardwareFeatures,
evidence: EvidenceGrade,
max_known_firmware: FirmwareVersion,
control_boundary: Option<ControlBoundary>,
}
pub struct CapabilityRegistry {
profiles: Vec<ModelProfile>,
}
impl CapabilityRegistry {
fn profile(&self, model: &Model) -> Option<&ModelProfile> {
self.profiles.iter().find(|p| &p.model == model)
}
}
pub fn resolve(
registry: &CapabilityRegistry,
model: &Model,
firmware: &FirmwareVersion,
) -> Capabilities {
let Some(profile) = registry.profile(model) else {
return Capabilities {
model: model.clone(),
push_mode: None,
camera_transport: None,
hardware: None,
developer_mode: None,
acs_policy: None,
evidence: None,
registry_status: RegistryStatus::UnknownModel,
};
};
let registry_status = if firmware > &profile.max_known_firmware {
RegistryStatus::FirmwareNewerThanKnown
} else {
RegistryStatus::Supported
};
let (developer_mode, acs_policy) = match &profile.control_boundary {
Some(cb) => {
let dev = if firmware >= &cb.developer_mode_since {
DeveloperMode::Available
} else {
DeveloperMode::Unavailable
};
(Some(dev), Some(cb.acs_policy))
}
None => (None, None),
};
Capabilities {
model: model.clone(),
push_mode: Some(profile.push_mode),
camera_transport: Some(profile.camera_transport),
hardware: Some(profile.hardware),
developer_mode,
acs_policy,
evidence: Some(profile.evidence),
registry_status,
}
}
pub fn default_registry() -> CapabilityRegistry {
let fw = |s: &str| FirmwareVersion::parse(s).expect("valid firmware literal");
let a1_family_hw = HardwareFeatures {
lidar: false,
chamber_temperature: ChamberTemperature::ReportedSynthetic, aux_fan: false,
chamber_fan: false,
};
let p1_hw = HardwareFeatures {
lidar: false,
chamber_temperature: ChamberTemperature::ReportedSynthetic,
aux_fan: true,
chamber_fan: true,
};
let x1_hw = HardwareFeatures {
lidar: true,
chamber_temperature: ChamberTemperature::RealSensor,
aux_fan: true,
chamber_fan: true,
};
let a1_boundary = || {
Some(ControlBoundary {
developer_mode_since: fw("01.05.00"),
acs_policy: AcsPolicy::Required,
})
};
let p1_boundary = || {
Some(ControlBoundary {
developer_mode_since: fw("01.08.02"),
acs_policy: AcsPolicy::Required,
})
};
let x1_boundary = || {
Some(ControlBoundary {
developer_mode_since: fw("01.08.03"),
acs_policy: AcsPolicy::Required,
})
};
CapabilityRegistry {
profiles: vec![
ModelProfile {
model: Model::A1Mini,
push_mode: PushMode::DeltaOnly,
camera_transport: CameraTransport::JpegTcp6000,
hardware: a1_family_hw,
evidence: EvidenceGrade::Observed,
max_known_firmware: fw("01.07.02"),
control_boundary: a1_boundary(),
},
ModelProfile {
model: Model::A1,
push_mode: PushMode::DeltaOnly,
camera_transport: CameraTransport::JpegTcp6000,
hardware: a1_family_hw,
evidence: EvidenceGrade::VendorSpec,
max_known_firmware: fw("01.07.02"),
control_boundary: a1_boundary(),
},
ModelProfile {
model: Model::P1P,
push_mode: PushMode::DeltaOnly,
camera_transport: CameraTransport::JpegTcp6000,
hardware: p1_hw,
evidence: EvidenceGrade::VendorSpec,
max_known_firmware: fw("01.08.04"),
control_boundary: p1_boundary(),
},
ModelProfile {
model: Model::P1S,
push_mode: PushMode::DeltaOnly,
camera_transport: CameraTransport::JpegTcp6000,
hardware: p1_hw,
evidence: EvidenceGrade::VendorSpec,
max_known_firmware: fw("01.08.04"),
control_boundary: p1_boundary(),
},
ModelProfile {
model: Model::X1Carbon,
push_mode: PushMode::Full,
camera_transport: CameraTransport::Rtsp322,
hardware: x1_hw,
evidence: EvidenceGrade::VendorSpec,
max_known_firmware: fw("01.08.05"),
control_boundary: x1_boundary(),
},
ModelProfile {
model: Model::X1E,
push_mode: PushMode::Full,
camera_transport: CameraTransport::Rtsp322,
hardware: x1_hw,
evidence: EvidenceGrade::VendorSpec,
max_known_firmware: fw("01.08.05"),
control_boundary: x1_boundary(),
},
ModelProfile {
model: Model::H2D,
push_mode: PushMode::Full,
camera_transport: CameraTransport::Rtsp322,
hardware: HardwareFeatures {
lidar: false,
chamber_temperature: ChamberTemperature::RealSensor,
aux_fan: true,
chamber_fan: true,
},
evidence: EvidenceGrade::Inferred,
max_known_firmware: fw("01.02.00"),
control_boundary: None,
},
],
}
}
#[cfg(test)]
mod tests {
use super::*;
fn fw(s: &str) -> FirmwareVersion {
FirmwareVersion::parse(s).unwrap()
}
#[test]
fn observed_a1mini_descriptive_facts() {
let reg = default_registry();
let caps = resolve(®, &Model::A1Mini, &fw("01.07.02"));
assert_eq!(caps.push_mode, Some(PushMode::DeltaOnly));
assert_eq!(caps.camera_transport, Some(CameraTransport::JpegTcp6000));
assert_eq!(caps.evidence, Some(EvidenceGrade::Observed));
assert_eq!(caps.registry_status, RegistryStatus::Supported);
let hw = caps.hardware.unwrap();
assert!(!hw.lidar);
assert_eq!(
hw.chamber_temperature,
ChamberTemperature::ReportedSynthetic
);
assert!(!hw.aux_fan && !hw.chamber_fan);
}
#[test]
fn a1mini_real_firmware_is_supported_not_newer_than_known() {
let reg = default_registry();
let caps = resolve(®, &Model::A1Mini, &fw("01.07.02.00"));
assert_eq!(caps.registry_status, RegistryStatus::Supported);
assert_eq!(
caps.control_permission(),
Ok(ControlPermit::RequiresDeveloperMode)
);
}
#[test]
fn developer_mode_threshold_and_control_below_it() {
let reg = default_registry();
let below = resolve(®, &Model::A1Mini, &fw("01.04.99"));
assert_eq!(below.developer_mode, Some(DeveloperMode::Unavailable));
assert_eq!(
below.control_permission(),
Err(ControlRefusal::DeveloperModeUnavailable)
);
}
#[test]
fn unknown_model_refuses_control() {
let reg = default_registry();
let caps = resolve(®, &Model::Unknown("z9".into()), &fw("01.00.00"));
assert_eq!(caps.registry_status, RegistryStatus::UnknownModel);
assert_eq!(caps.push_mode, None);
assert_eq!(caps.control_permission(), Err(ControlRefusal::UnknownModel));
}
#[test]
fn firmware_newer_than_known_refuses_control() {
let reg = default_registry();
let caps = resolve(®, &Model::A1Mini, &fw("01.99.00"));
assert_eq!(caps.registry_status, RegistryStatus::FirmwareNewerThanKnown);
assert_eq!(
caps.control_permission(),
Err(ControlRefusal::FirmwareNewerThanKnown)
);
assert_eq!(caps.push_mode, Some(PushMode::DeltaOnly));
}
#[test]
fn control_assessment_degrades_newer_firmware_to_a_warning_not_a_wall() {
let reg = default_registry();
let newer = resolve(®, &Model::A1Mini, &fw("01.99.00"));
assert_eq!(
newer.control_permission(),
Err(ControlRefusal::FirmwareNewerThanKnown)
);
assert_eq!(
newer.control_assessment(),
ControlAssessment::NewerFirmwareUntested
);
let ok = resolve(®, &Model::A1Mini, &fw("01.07.02"));
assert_eq!(
ok.control_assessment(),
ControlAssessment::RequiresDeveloperMode
);
let unknown = resolve(®, &Model::Unknown("z9".into()), &fw("01.00.00"));
assert_eq!(
unknown.control_assessment(),
ControlAssessment::Refused(ControlRefusal::UnknownModel)
);
let below = resolve(®, &Model::A1Mini, &fw("01.04.99"));
assert_eq!(
below.control_assessment(),
ControlAssessment::Refused(ControlRefusal::DeveloperModeUnavailable)
);
}
#[test]
fn x1_carbon_is_full_push_rtsp_and_has_lidar() {
let reg = default_registry();
let caps = resolve(®, &Model::X1Carbon, &fw("01.08.03"));
assert_eq!(caps.push_mode, Some(PushMode::Full));
assert_eq!(caps.camera_transport, Some(CameraTransport::Rtsp322));
let hw = caps.hardware.unwrap();
assert!(hw.lidar);
assert_eq!(hw.chamber_temperature, ChamberTemperature::RealSensor);
assert_eq!(
caps.control_permission(),
Ok(ControlPermit::RequiresDeveloperMode)
);
}
#[test]
fn inferred_h2d_keeps_descriptive_info_but_refuses_control() {
let reg = default_registry();
let caps = resolve(®, &Model::H2D, &fw("01.01.05"));
assert_eq!(caps.registry_status, RegistryStatus::Supported);
assert_eq!(caps.push_mode, Some(PushMode::Full)); assert_eq!(caps.evidence, Some(EvidenceGrade::Inferred));
assert_eq!(caps.developer_mode, None);
assert_eq!(
caps.control_permission(),
Err(ControlRefusal::UnknownControlBoundary)
);
}
}