1pub mod error;
2
3use async_trait::async_trait;
4
5use error::*;
6use num_bigint::BigInt;
7use rusty_mms::{ListOfVariablesItem, MmsAccessError, MmsBasicObjectClass, MmsObjectClass, MmsObjectName, MmsObjectScope, MmsVariableAccessSpecification, VariableSpecification};
8use rusty_mms_service::{
9 RustyMmsServiceClient,
10 data::{MmsServiceAccessResult, MmsServiceData, MmsServiceDeleteObjectScope},
11};
12
13#[async_trait]
14pub trait IccpClient: Send + Sync {
15 }
41
42pub enum QualityFlag {
43 Bit0,
44 Bit1,
45 Bit2,
46 Bit3,
47 Bit4,
48 Bit5,
49 Bit6,
50 Bit7,
51}
52
53pub enum IccpData {
54 RealQ(f32, Vec<QualityFlag>),
55}
56
57pub enum IccpAccessResult {
58 Success(IccpData),
59 Failure(MmsAccessError),
60}
61
62pub enum IccpScope {
63 Vcc,
64 ICC(String), }
66
67#[async_trait]
68pub trait IccpServer: Send + Sync + Clone {
69 }
71
72pub struct RustyIccpClient {
73 mms_client: Box<dyn RustyMmsServiceClient>,
74}
75
76impl RustyIccpClient {
77 pub fn new(mms_client: Box<dyn RustyMmsServiceClient>) -> Self {
78 RustyIccpClient { mms_client }
79 }
80
81 pub async fn get_data_values(&mut self, names: Vec<String>) -> Result<Vec<IccpAccessResult>, IccpError> {
82 let spec = names.into_iter().map(|x| ListOfVariablesItem { variable_specification: VariableSpecification::Name(MmsObjectName::VmdSpecific(x)) }).collect();
83 let results = self.mms_client.read(rusty_mms::MmsVariableAccessSpecification::ListOfVariables(spec)).await?;
84
85 Ok(results
86 .into_iter()
87 .map(|x| match x {
88 MmsServiceAccessResult::Failure(x) => Ok(IccpAccessResult::Failure(x)),
89 MmsServiceAccessResult::Success(x) => Ok(IccpAccessResult::Success(convert_mms_service_data_to_iccp_data(x)?)),
90 })
91 .collect::<Result<Vec<IccpAccessResult>, IccpError>>()?)
92 }
93
94 pub async fn get_data_set_names(&mut self, scope: IccpScope) -> Result<Vec<String>, IccpError> {
95 let mms_scope = match scope {
96 IccpScope::Vcc => MmsObjectScope::Vmd,
97 IccpScope::ICC(x) => MmsObjectScope::Domain(x),
98 };
99
100 let mut full_results = vec![];
101 let mut continue_after = None;
102 loop {
103 let results = self.mms_client.get_name_list(MmsObjectClass::Basic(MmsBasicObjectClass::NamedVariableList), mms_scope.clone(), continue_after).await?;
104 let last_result = results.identifiers.last().cloned();
105 full_results.extend(results.identifiers);
106
107 if !results.more_follows {
108 return Ok(full_results);
109 }
110 continue_after = Some(last_result.ok_or_else(|| IccpError::ProtocolError("No results to choose from.".into()))?)
111 }
112 }
113
114 pub async fn get_data_value_names(&mut self, scope: IccpScope) -> Result<Vec<String>, IccpError> {
115 let mms_scope = match scope {
116 IccpScope::Vcc => MmsObjectScope::Vmd,
117 IccpScope::ICC(x) => MmsObjectScope::Domain(x),
118 };
119
120 let mut full_results = vec![];
121 let mut continue_after = None;
122 loop {
123 let results = self.mms_client.get_name_list(MmsObjectClass::Basic(MmsBasicObjectClass::NamedVariable), mms_scope.clone(), continue_after).await?;
124 let last_result = results.identifiers.last().cloned();
125 full_results.extend(results.identifiers);
126
127 if !results.more_follows {
128 return Ok(full_results);
129 }
130 continue_after = Some(last_result.ok_or_else(|| IccpError::ProtocolError("No results to choose from.".into()))?)
131 }
132 }
133
134 pub async fn create_data_set(&mut self, domain: String, name: String, identifiers: Vec<String>) -> Result<(), IccpError> {
135 self.mms_client
136 .define_named_variable_list(MmsObjectName::DomainSpecific(domain, name), identifiers.into_iter().map(|x| ListOfVariablesItem { variable_specification: VariableSpecification::Name(MmsObjectName::VmdSpecific(x)) }).collect())
137 .await?;
138 Ok(())
139 }
140
141 pub async fn delete_data_sets(&mut self, domain: String, identifiers: Vec<String>) -> Result<(), IccpError> {
142 self.mms_client.delete_named_variable_list(MmsServiceDeleteObjectScope::Specific(identifiers.into_iter().map(|x| MmsObjectName::DomainSpecific(domain.clone(), x)).collect())).await?;
143 Ok(())
144 }
145
146 pub async fn delete_domain_data_sets(&mut self, domain: String) -> Result<(), IccpError> {
147 self.mms_client.delete_named_variable_list(MmsServiceDeleteObjectScope::Domain(domain)).await?;
148 Ok(())
149 }
150
151 pub async fn start_transfer_set(&mut self, domain: String, name: String) -> Result<(), IccpError> {
152 let transfer_set_name_structure = self
153 .mms_client
154 .read(MmsVariableAccessSpecification::ListOfVariables(vec![ListOfVariablesItem { variable_specification: VariableSpecification::Name(MmsObjectName::DomainSpecific(domain.clone(), "Next_DSTransfer_Set".into())) }]))
155 .await?;
156
157 let transfer_set_name = match transfer_set_name_structure.as_slice() {
158 [MmsServiceAccessResult::Success(MmsServiceData::Structure(x))] => match x.as_slice() {
159 [MmsServiceData::Integer(_scope), MmsServiceData::VisibleString(_domain), MmsServiceData::VisibleString(transfer_set_name)] => transfer_set_name,
160 _ => return Err(IccpError::ProtocolError("Failed to get transfer set name".into())),
161 },
162 _ => return Err(IccpError::ProtocolError("Failed to get transfer set name".into())),
163 };
164
165 self.mms_client
166 .write(
167 MmsVariableAccessSpecification::ListOfVariables(vec![ListOfVariablesItem { variable_specification: VariableSpecification::Name(MmsObjectName::DomainSpecific(domain.clone(), transfer_set_name.clone())) }]),
168 vec![
169 MmsServiceData::Structure(vec![MmsServiceData::Structure(vec![
170 MmsServiceData::Integer(BigInt::from(1)),
171 MmsServiceData::VisibleString(domain.clone()),
172 MmsServiceData::VisibleString(name),
173 ])]),
174 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)), ],
187 )
188 .await?;
189 Ok(())
190 }
191}
192
193fn convert_mms_service_data_to_iccp_data(mms_data: MmsServiceData) -> Result<IccpData, IccpError> {
194 match mms_data {
195 MmsServiceData::Structure(struct_data) => match struct_data.as_slice() {
196 [MmsServiceData::FloatingPoint(value), MmsServiceData::BitString(_)] => Ok(IccpData::RealQ(value.to_f32()?, vec![])),
197 x => Err(IccpError::ProtocolError(format!("Unknown MMS Structure Data: {x:?}"))),
198 },
199 x => Err(IccpError::ProtocolError(format!("Unknown MMS Data: {x:?}"))),
200 }
201}