use sim_citizen_derive::Citizen;
use sim_kernel::CapabilityName;
use crate::{
AUTO_CONTROL_EXEC, AUTO_DIAGNOSTICS_READ, AUTO_MANIFEST_READ, AUTO_ORDER, AUTO_SERVICE_WRITE,
AUTO_TELEMETRY_READ, AUTO_TRANSPORT_CONNECT,
};
mod fields;
#[derive(Clone, Debug, PartialEq, Eq, Citizen)]
#[citizen(symbol = "auto/VehicleId", version = 0)]
pub struct VehicleId {
pub namespace: String,
pub key: String,
}
impl Default for VehicleId {
fn default() -> Self {
vehicle_id_example()
}
}
impl VehicleId {
pub fn new(namespace: impl Into<String>, key: impl Into<String>) -> Self {
Self {
namespace: namespace.into(),
key: key.into(),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Citizen)]
#[citizen(symbol = "auto/Dtc", version = 0)]
pub struct Dtc {
pub system: String,
pub code: String,
pub description: String,
#[citizen(with = "fields::dtc_status_field")]
pub status: DtcStatus,
}
impl Default for Dtc {
fn default() -> Self {
dtc_example()
}
}
impl Dtc {
pub fn new(
system: impl Into<String>,
code: impl Into<String>,
description: impl Into<String>,
) -> Self {
Self::with_status(system, code, description, DtcStatus::default())
}
pub fn with_status(
system: impl Into<String>,
code: impl Into<String>,
description: impl Into<String>,
status: DtcStatus,
) -> Self {
Self {
system: system.into(),
code: code.into(),
description: description.into(),
status,
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Citizen)]
#[citizen(symbol = "auto/DtcStatus", version = 0)]
pub struct DtcStatus {
pub test_failed: bool,
pub test_failed_this_operation_cycle: bool,
pub pending: bool,
pub confirmed: bool,
pub test_not_completed_since_clear: bool,
pub test_failed_since_clear: bool,
pub test_not_completed_this_operation_cycle: bool,
pub warning_indicator: bool,
}
impl DtcStatus {
pub fn from_byte(byte: u8) -> Self {
Self {
test_failed: byte & 0x01 != 0,
test_failed_this_operation_cycle: byte & 0x02 != 0,
pending: byte & 0x04 != 0,
confirmed: byte & 0x08 != 0,
test_not_completed_since_clear: byte & 0x10 != 0,
test_failed_since_clear: byte & 0x20 != 0,
test_not_completed_this_operation_cycle: byte & 0x40 != 0,
warning_indicator: byte & 0x80 != 0,
}
}
pub fn to_byte(self) -> u8 {
u8::from(self.test_failed)
| (u8::from(self.test_failed_this_operation_cycle) << 1)
| (u8::from(self.pending) << 2)
| (u8::from(self.confirmed) << 3)
| (u8::from(self.test_not_completed_since_clear) << 4)
| (u8::from(self.test_failed_since_clear) << 5)
| (u8::from(self.test_not_completed_this_operation_cycle) << 6)
| (u8::from(self.warning_indicator) << 7)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Citizen)]
#[citizen(symbol = "auto/BrandCaps", version = 0)]
pub struct BrandCaps {
pub brand: String,
pub capabilities: Vec<CapabilityName>,
}
impl Default for BrandCaps {
fn default() -> Self {
brand_caps_example()
}
}
impl BrandCaps {
pub fn new(brand: impl Into<String>, capabilities: Vec<CapabilityName>) -> Self {
Self {
brand: brand.into(),
capabilities,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Citizen)]
#[citizen(symbol = "auto/AutoLane", version = 0)]
pub struct AutoLane {
pub name: String,
}
impl Default for AutoLane {
fn default() -> Self {
auto_lane_example()
}
}
impl AutoLane {
pub fn new(name: impl Into<String>) -> Self {
Self { name: name.into() }
}
}
#[derive(Clone, Debug, PartialEq, Eq, Citizen)]
#[citizen(symbol = "auto/EffectClass", version = 0)]
pub struct EffectClass {
pub name: String,
}
impl Default for EffectClass {
fn default() -> Self {
effect_class_example()
}
}
impl EffectClass {
pub fn new(name: impl Into<String>) -> Self {
Self { name: name.into() }
}
}
#[derive(Clone, Debug, PartialEq, Eq, Citizen)]
#[citizen(symbol = "auto/OpCap", version = 0)]
pub struct OpCap {
pub operation: String,
pub capability: CapabilityName,
pub effect_class: String,
}
impl Default for OpCap {
fn default() -> Self {
op_cap_example()
}
}
impl OpCap {
pub fn new(
operation: impl Into<String>,
capability: CapabilityName,
effect_class: impl Into<String>,
) -> Self {
Self {
operation: operation.into(),
capability,
effect_class: effect_class.into(),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Citizen)]
#[citizen(symbol = "auto/TransportSpec", version = 0)]
pub struct TransportSpec {
pub name: String,
pub protocol: String,
pub lane: String,
pub read_capability: CapabilityName,
pub write_capability: CapabilityName,
}
impl Default for TransportSpec {
fn default() -> Self {
transport_spec_example()
}
}
impl TransportSpec {
pub fn new(
name: impl Into<String>,
protocol: impl Into<String>,
lane: impl Into<String>,
read_capability: CapabilityName,
write_capability: CapabilityName,
) -> Self {
Self {
name: name.into(),
protocol: protocol.into(),
lane: lane.into(),
read_capability,
write_capability,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Citizen)]
#[citizen(symbol = "auto/SiteManifest", version = 0)]
pub struct SiteManifest {
pub site: String,
pub vehicle: String,
pub brand: String,
pub makes: Vec<String>,
pub lanes: Vec<String>,
pub transports: Vec<String>,
pub operations: Vec<String>,
#[citizen(with = "fields::op_caps_field")]
pub op_caps: Vec<OpCap>,
pub ceiling: Vec<CapabilityName>,
}
impl Default for SiteManifest {
fn default() -> Self {
site_manifest_example()
}
}
impl SiteManifest {
pub fn new(
site: impl Into<String>,
vehicle: impl Into<String>,
brand: impl Into<String>,
lanes: Vec<String>,
transports: Vec<String>,
operations: Vec<String>,
) -> Self {
let brand = brand.into();
Self {
site: site.into(),
vehicle: vehicle.into(),
makes: vec![brand.clone()],
brand,
lanes,
transports,
operations,
op_caps: Vec::new(),
ceiling: Vec::new(),
}
}
pub fn with_makes(mut self, makes: Vec<String>) -> Self {
self.makes = makes;
self
}
pub fn with_op_caps(mut self, op_caps: Vec<OpCap>) -> Self {
self.op_caps = op_caps;
self
}
pub fn with_ceiling(mut self, ceiling: Vec<CapabilityName>) -> Self {
self.ceiling = ceiling;
self
}
}
pub fn diagnostic_lane() -> AutoLane {
auto_lane("diagnostics")
}
pub fn telemetry_lane() -> AutoLane {
auto_lane("telemetry")
}
pub fn manifest_lane() -> AutoLane {
auto_lane("manifest")
}
pub fn auto_lane(name: impl Into<String>) -> AutoLane {
AutoLane::new(name)
}
pub fn diagnostic_effect() -> EffectClass {
EffectClass::new("diagnostic-read")
}
pub fn control_effect() -> EffectClass {
EffectClass::new("control-write")
}
fn vehicle_id_example() -> VehicleId {
VehicleId::new("fixture", "vehicle-alpha")
}
fn dtc_example() -> Dtc {
Dtc::with_status(
"body",
"B0000",
"modeled diagnostic",
DtcStatus::from_byte(0x08),
)
}
fn brand_caps_example() -> BrandCaps {
BrandCaps::new(
"fixture-brand",
vec![
CapabilityName::new(AUTO_DIAGNOSTICS_READ),
CapabilityName::new(AUTO_TELEMETRY_READ),
],
)
}
fn auto_lane_example() -> AutoLane {
diagnostic_lane()
}
fn effect_class_example() -> EffectClass {
diagnostic_effect()
}
fn op_cap_example() -> OpCap {
OpCap::new(
"diagnostics/read-dtc",
CapabilityName::new(AUTO_DIAGNOSTICS_READ),
"diagnostic-read",
)
}
fn transport_spec_example() -> TransportSpec {
TransportSpec::new(
"fixture-transport",
"modeled-bus",
"diagnostics",
CapabilityName::new(AUTO_TRANSPORT_CONNECT),
CapabilityName::new(AUTO_SERVICE_WRITE),
)
}
fn site_manifest_example() -> SiteManifest {
SiteManifest::new(
"fixture-site",
"vehicle-alpha",
"fixture-brand",
vec!["diagnostics".to_owned(), "telemetry".to_owned()],
vec!["fixture-transport".to_owned()],
vec!["diagnostics/read-dtc".to_owned()],
)
}
#[allow(dead_code)]
fn capability_examples() -> [CapabilityName; 5] {
[
CapabilityName::new(AUTO_CONTROL_EXEC),
CapabilityName::new(AUTO_MANIFEST_READ),
CapabilityName::new(AUTO_SERVICE_WRITE),
CapabilityName::new(AUTO_ORDER),
CapabilityName::new(AUTO_TELEMETRY_READ),
]
}