pub mod error;
use async_trait::async_trait;
use error::*;
use num_bigint::BigInt;
use rusty_mms::{ListOfVariablesItem, MmsAccessError, MmsBasicObjectClass, MmsObjectClass, MmsObjectName, MmsObjectScope, MmsVariableAccessSpecification, VariableSpecification};
use rusty_mms_service::{
RustyMmsServiceClient,
data::{MmsServiceAccessResult, MmsServiceData, MmsServiceDeleteObjectScope},
};
#[async_trait]
pub trait IccpClient: Send + Sync {
}
pub enum QualityFlag {
Bit0,
Bit1,
Bit2,
Bit3,
Bit4,
Bit5,
Bit6,
Bit7,
}
pub enum IccpData {
RealQ(f32, Vec<QualityFlag>),
}
pub enum IccpAccessResult {
Success(IccpData),
Failure(MmsAccessError),
}
pub enum IccpScope {
Vcc,
ICC(String), }
#[async_trait]
pub trait IccpServer: Send + Sync + Clone {
}
pub struct RustyIccpClient {
mms_client: Box<dyn RustyMmsServiceClient>,
}
impl RustyIccpClient {
pub fn new(mms_client: Box<dyn RustyMmsServiceClient>) -> Self {
RustyIccpClient { mms_client }
}
pub async fn get_data_values(&mut self, names: Vec<String>) -> Result<Vec<IccpAccessResult>, IccpError> {
let spec = names.into_iter().map(|x| ListOfVariablesItem { variable_specification: VariableSpecification::Name(MmsObjectName::VmdSpecific(x)) }).collect();
let results = self.mms_client.read(rusty_mms::MmsVariableAccessSpecification::ListOfVariables(spec)).await?;
Ok(results
.into_iter()
.map(|x| match x {
MmsServiceAccessResult::Failure(x) => Ok(IccpAccessResult::Failure(x)),
MmsServiceAccessResult::Success(x) => Ok(IccpAccessResult::Success(convert_mms_service_data_to_iccp_data(x)?)),
})
.collect::<Result<Vec<IccpAccessResult>, IccpError>>()?)
}
pub async fn get_data_set_names(&mut self, scope: IccpScope) -> Result<Vec<String>, IccpError> {
let mms_scope = match scope {
IccpScope::Vcc => MmsObjectScope::Vmd,
IccpScope::ICC(x) => MmsObjectScope::Domain(x),
};
let mut full_results = vec![];
let mut continue_after = None;
loop {
let results = self.mms_client.get_name_list(MmsObjectClass::Basic(MmsBasicObjectClass::NamedVariableList), mms_scope.clone(), continue_after).await?;
let last_result = results.identifiers.last().cloned();
full_results.extend(results.identifiers);
if !results.more_follows {
return Ok(full_results);
}
continue_after = Some(last_result.ok_or_else(|| IccpError::ProtocolError("No results to choose from.".into()))?)
}
}
pub async fn get_data_value_names(&mut self, scope: IccpScope) -> Result<Vec<String>, IccpError> {
let mms_scope = match scope {
IccpScope::Vcc => MmsObjectScope::Vmd,
IccpScope::ICC(x) => MmsObjectScope::Domain(x),
};
let mut full_results = vec![];
let mut continue_after = None;
loop {
let results = self.mms_client.get_name_list(MmsObjectClass::Basic(MmsBasicObjectClass::NamedVariable), mms_scope.clone(), continue_after).await?;
let last_result = results.identifiers.last().cloned();
full_results.extend(results.identifiers);
if !results.more_follows {
return Ok(full_results);
}
continue_after = Some(last_result.ok_or_else(|| IccpError::ProtocolError("No results to choose from.".into()))?)
}
}
pub async fn create_data_set(&mut self, domain: String, name: String, identifiers: Vec<String>) -> Result<(), IccpError> {
self.mms_client
.define_named_variable_list(MmsObjectName::DomainSpecific(domain, name), identifiers.into_iter().map(|x| ListOfVariablesItem { variable_specification: VariableSpecification::Name(MmsObjectName::VmdSpecific(x)) }).collect())
.await?;
Ok(())
}
pub async fn delete_data_sets(&mut self, domain: String, identifiers: Vec<String>) -> Result<(), IccpError> {
self.mms_client.delete_named_variable_list(MmsServiceDeleteObjectScope::Specific(identifiers.into_iter().map(|x| MmsObjectName::DomainSpecific(domain.clone(), x)).collect())).await?;
Ok(())
}
pub async fn delete_domain_data_sets(&mut self, domain: String) -> Result<(), IccpError> {
self.mms_client.delete_named_variable_list(MmsServiceDeleteObjectScope::Domain(domain)).await?;
Ok(())
}
pub async fn start_transfer_set(&mut self, domain: String, name: String) -> Result<(), IccpError> {
let transfer_set_name_structure = self
.mms_client
.read(MmsVariableAccessSpecification::ListOfVariables(vec![ListOfVariablesItem { variable_specification: VariableSpecification::Name(MmsObjectName::DomainSpecific(domain.clone(), "Next_DSTransfer_Set".into())) }]))
.await?;
let transfer_set_name = match transfer_set_name_structure.as_slice() {
[MmsServiceAccessResult::Success(MmsServiceData::Structure(x))] => match x.as_slice() {
[MmsServiceData::Integer(_scope), MmsServiceData::VisibleString(_domain), MmsServiceData::VisibleString(transfer_set_name)] => transfer_set_name,
_ => return Err(IccpError::ProtocolError("Failed to get transfer set name".into())),
},
_ => return Err(IccpError::ProtocolError("Failed to get transfer set name".into())),
};
self.mms_client
.write(
MmsVariableAccessSpecification::ListOfVariables(vec![ListOfVariablesItem { variable_specification: VariableSpecification::Name(MmsObjectName::DomainSpecific(domain.clone(), transfer_set_name.clone())) }]),
vec![
MmsServiceData::Structure(vec![MmsServiceData::Structure(vec![
MmsServiceData::Integer(BigInt::from(1)),
MmsServiceData::VisibleString(domain.clone()),
MmsServiceData::VisibleString(name),
])]),
MmsServiceData::Integer(BigInt::from(0)), MmsServiceData::Integer(BigInt::from(0)), MmsServiceData::Integer(BigInt::from(0)), MmsServiceData::Integer(BigInt::from(10)), MmsServiceData::Integer(BigInt::from(600)), MmsServiceData::BitString(vec![false, true, true, true, false]), MmsServiceData::Boolean(false), MmsServiceData::Boolean(false), MmsServiceData::Boolean(true), MmsServiceData::Boolean(false), MmsServiceData::Boolean(true), MmsServiceData::Integer(BigInt::from(0)), ],
)
.await?;
Ok(())
}
}
fn convert_mms_service_data_to_iccp_data(mms_data: MmsServiceData) -> Result<IccpData, IccpError> {
match mms_data {
MmsServiceData::Structure(struct_data) => match struct_data.as_slice() {
[MmsServiceData::FloatingPoint(value), MmsServiceData::BitString(_)] => Ok(IccpData::RealQ(value.to_f32()?, vec![])),
x => Err(IccpError::ProtocolError(format!("Unknown MMS Structure Data: {x:?}"))),
},
x => Err(IccpError::ProtocolError(format!("Unknown MMS Data: {x:?}"))),
}
}