a653rs/apex/
sampling.rs

1/// bindings for ARINC653P1-5 3.6.2.1 sampling
2pub mod basic {
3    use crate::apex::time::basic::*;
4    use crate::apex::types::basic::*;
5
6    pub type SamplingPortName = ApexName;
7
8    // TODO P2 extension
9
10    /// According to ARINC 653P1-5 this may either be 32 or 64 bits.
11    /// Internally we will use 64-bit by default.
12    /// The implementing Hypervisor may cast this to 32-bit if needed
13    pub type SamplingPortId = ApexLongInteger;
14
15    #[repr(u32)]
16    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
17    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18    #[cfg_attr(feature = "strum", derive(strum::FromRepr))]
19    pub enum Validity {
20        Invalid = 0,
21        Valid = 1,
22    }
23
24    #[derive(Debug, Clone, PartialEq, Eq)]
25    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26    pub struct ApexSamplingPortStatus {
27        pub refresh_period: ApexSystemTime,
28        pub max_message_size: MessageSize,
29        pub port_direction: PortDirection,
30        pub last_msg_validity: Validity,
31    }
32
33    pub trait ApexSamplingPortP4 {
34        // Only during Warm/Cold-Start
35        fn create_sampling_port(
36            sampling_port_name: SamplingPortName,
37            max_message_size: MessageSize,
38            port_direction: PortDirection,
39            refresh_period: ApexSystemTime,
40        ) -> Result<SamplingPortId, ErrorReturnCode>;
41
42        fn write_sampling_message(
43            sampling_port_id: SamplingPortId,
44            message: &[ApexByte],
45        ) -> Result<(), ErrorReturnCode>;
46
47        /// # Safety
48        ///
49        /// This function is safe, as long as the buffer can hold whatever is received
50        unsafe fn read_sampling_message(
51            sampling_port_id: SamplingPortId,
52            message: &mut [ApexByte],
53        ) -> Result<(Validity, MessageSize), ErrorReturnCode>;
54    }
55
56    pub trait ApexSamplingPortP1: ApexSamplingPortP4 {
57        fn get_sampling_port_id(
58            sampling_port_name: SamplingPortName,
59        ) -> Result<SamplingPortId, ErrorReturnCode>;
60
61        fn get_sampling_port_status(
62            sampling_port_id: SamplingPortId,
63        ) -> Result<ApexSamplingPortStatus, ErrorReturnCode>;
64    }
65}
66
67/// abstractions for ARINC653P1-5 3.6.2.1 sampling
68pub mod abstraction {
69    use core::borrow::Borrow;
70    use core::marker::PhantomData;
71    use core::ops::Deref;
72    use core::sync::atomic::AtomicPtr;
73    use core::time::Duration;
74
75    use super::basic::{ApexSamplingPortP1, ApexSamplingPortP4, ApexSamplingPortStatus};
76    // Reexport important basic-types for downstream-user
77    pub use super::basic::{SamplingPortId, Validity};
78    use crate::apex::types::basic::PortDirection;
79    use crate::prelude::*;
80
81    #[derive(Debug, Clone, PartialEq, Eq)]
82    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
83    pub struct SamplingPortStatus {
84        pub refresh_period: SystemTime,
85        pub max_message_size: MessageSize,
86        pub port_direction: PortDirection,
87        pub last_msg_validity: Validity,
88    }
89
90    impl From<ApexSamplingPortStatus> for SamplingPortStatus {
91        fn from(s: ApexSamplingPortStatus) -> Self {
92            SamplingPortStatus {
93                refresh_period: s.refresh_period.into(),
94                max_message_size: s.max_message_size,
95                port_direction: s.port_direction,
96                last_msg_validity: s.last_msg_validity,
97            }
98        }
99    }
100
101    #[derive(Debug, Clone)]
102    pub struct ConstSamplingPortSource<const MSG_SIZE: MessageSize, S: ApexSamplingPortP4Ext>(
103        SamplingPortSource<S>,
104    );
105
106    impl<const MSG_SIZE: MessageSize, S: ApexSamplingPortP4Ext> Deref
107        for ConstSamplingPortSource<MSG_SIZE, S>
108    {
109        type Target = SamplingPortSource<S>;
110
111        fn deref(&self) -> &Self::Target {
112            &self.0
113        }
114    }
115
116    impl<const MSG_SIZE: MessageSize, S: ApexSamplingPortP4Ext> AsRef<SamplingPortSource<S>>
117        for ConstSamplingPortSource<MSG_SIZE, S>
118    {
119        fn as_ref(&self) -> &SamplingPortSource<S> {
120            &self.0
121        }
122    }
123
124    impl<const MSG_SIZE: MessageSize, S: ApexSamplingPortP4Ext> Borrow<SamplingPortSource<S>>
125        for ConstSamplingPortSource<MSG_SIZE, S>
126    {
127        fn borrow(&self) -> &SamplingPortSource<S> {
128            &self.0
129        }
130    }
131
132    impl<const MSG_SIZE: MessageSize, S: ApexSamplingPortP4Ext> TryFrom<SamplingPortSource<S>>
133        for ConstSamplingPortSource<MSG_SIZE, S>
134    {
135        type Error = Error;
136
137        fn try_from(port: SamplingPortSource<S>) -> Result<Self, Self::Error> {
138            if port.msg_size != MSG_SIZE {
139                return Err(Error::InvalidConfig);
140            }
141
142            Ok(ConstSamplingPortSource(port))
143        }
144    }
145
146    #[derive(Debug, Clone)]
147    pub struct ConstSamplingPortDestination<const MSG_SIZE: MessageSize, S: ApexSamplingPortP4Ext>(
148        SamplingPortDestination<S>,
149    );
150
151    impl<const MSG_SIZE: MessageSize, S: ApexSamplingPortP4Ext> Deref
152        for ConstSamplingPortDestination<MSG_SIZE, S>
153    {
154        type Target = SamplingPortDestination<S>;
155
156        fn deref(&self) -> &Self::Target {
157            &self.0
158        }
159    }
160
161    impl<const MSG_SIZE: MessageSize, S: ApexSamplingPortP4Ext> AsRef<SamplingPortDestination<S>>
162        for ConstSamplingPortDestination<MSG_SIZE, S>
163    {
164        fn as_ref(&self) -> &SamplingPortDestination<S> {
165            &self.0
166        }
167    }
168
169    impl<const MSG_SIZE: MessageSize, S: ApexSamplingPortP4Ext> Borrow<SamplingPortDestination<S>>
170        for ConstSamplingPortDestination<MSG_SIZE, S>
171    {
172        fn borrow(&self) -> &SamplingPortDestination<S> {
173            &self.0
174        }
175    }
176
177    impl<const MSG_SIZE: MessageSize, S: ApexSamplingPortP4Ext> TryFrom<SamplingPortDestination<S>>
178        for ConstSamplingPortDestination<MSG_SIZE, S>
179    {
180        type Error = Error;
181
182        fn try_from(port: SamplingPortDestination<S>) -> Result<Self, Self::Error> {
183            if port.msg_size != MSG_SIZE {
184                return Err(Error::InvalidConfig);
185            }
186
187            Ok(ConstSamplingPortDestination(port))
188        }
189    }
190
191    #[derive(Debug)]
192    pub struct SamplingPortSource<S: ApexSamplingPortP4Ext> {
193        _b: PhantomData<AtomicPtr<S>>,
194        id: SamplingPortId,
195        msg_size: MessageSize,
196    }
197
198    impl<S: ApexSamplingPortP4Ext> Clone for SamplingPortSource<S> {
199        fn clone(&self) -> Self {
200            Self {
201                _b: self._b,
202                id: self.id,
203                msg_size: self.msg_size,
204            }
205        }
206    }
207
208    impl<const MSG_SIZE: MessageSize, S: ApexSamplingPortP4Ext>
209        From<ConstSamplingPortSource<MSG_SIZE, S>> for SamplingPortSource<S>
210    {
211        fn from(port: ConstSamplingPortSource<MSG_SIZE, S>) -> Self {
212            port.0
213        }
214    }
215
216    #[derive(Debug)]
217    pub struct SamplingPortDestination<S: ApexSamplingPortP4Ext> {
218        _b: PhantomData<AtomicPtr<S>>,
219        id: SamplingPortId,
220        msg_size: MessageSize,
221        refresh: Duration,
222    }
223
224    impl<S: ApexSamplingPortP4Ext> Clone for SamplingPortDestination<S> {
225        fn clone(&self) -> Self {
226            Self {
227                _b: self._b,
228                id: self.id,
229                msg_size: self.msg_size,
230                refresh: self.refresh,
231            }
232        }
233    }
234
235    impl<const MSG_SIZE: MessageSize, S: ApexSamplingPortP4Ext>
236        From<ConstSamplingPortDestination<MSG_SIZE, S>> for SamplingPortDestination<S>
237    {
238        fn from(port: ConstSamplingPortDestination<MSG_SIZE, S>) -> Self {
239            port.0
240        }
241    }
242
243    pub trait ApexSamplingPortP4Ext: ApexSamplingPortP4 + Sized {
244        fn sampling_port_send_unchecked(
245            id: SamplingPortId,
246            buffer: &[ApexByte],
247        ) -> Result<(), Error>;
248
249        /// # Safety
250        ///
251        /// This function is safe, as long as the buffer can hold whatever is received
252        unsafe fn sampling_port_receive_unchecked(
253            id: SamplingPortId,
254            buffer: &mut [ApexByte],
255        ) -> Result<(Validity, &[ApexByte]), Error>;
256    }
257
258    pub trait ApexSamplingPortP1Ext: ApexSamplingPortP1 + Sized {
259        /// Returns Err(Error::InvalidConfig) if sampling port with name does not exists or
260        /// if the message size of the found sampling port is different than MSG_SIZE
261        fn get_const_sampling_port_source<const MSG_SIZE: MessageSize>(
262            name: Name,
263        ) -> Result<ConstSamplingPortSource<MSG_SIZE, Self>, Error>;
264
265        /// Returns Err(Error::InvalidConfig) if sampling port with name does not exists or
266        /// if the message size of the found sampling port is different than MSG_SIZE
267        fn get_const_sampling_port_destination<const MSG_SIZE: MessageSize>(
268            name: Name,
269        ) -> Result<ConstSamplingPortDestination<MSG_SIZE, Self>, Error>;
270
271        /// Returns Err(Error::InvalidConfig) if sampling port with name does not exists
272        fn get_sampling_port_source(name: Name) -> Result<SamplingPortSource<Self>, Error>;
273
274        /// Returns Err(Error::InvalidConfig) if sampling port with name does not exists
275        fn get_sampling_port_destination(
276            name: Name,
277        ) -> Result<SamplingPortDestination<Self>, Error>;
278    }
279
280    impl<S: ApexSamplingPortP4> ApexSamplingPortP4Ext for S {
281        fn sampling_port_send_unchecked(
282            id: SamplingPortId,
283            buffer: &[ApexByte],
284        ) -> Result<(), Error> {
285            S::write_sampling_message(id, buffer)?;
286            Ok(())
287        }
288
289        unsafe fn sampling_port_receive_unchecked(
290            id: SamplingPortId,
291            buffer: &mut [ApexByte],
292        ) -> Result<(Validity, &[ApexByte]), Error> {
293            let (val, len) = S::read_sampling_message(id, buffer)?;
294            Ok((val, &buffer[..(len as usize)]))
295        }
296    }
297
298    impl<S: ApexSamplingPortP1> ApexSamplingPortP1Ext for S {
299        /// Returns Err(Error::InvalidConfig) if sampling port with name does not exists or
300        /// if the message size of the found sampling port is different than MSG_SIZE
301        fn get_const_sampling_port_source<const MSG_SIZE: MessageSize>(
302            name: Name,
303        ) -> Result<ConstSamplingPortSource<MSG_SIZE, Self>, Error> {
304            S::get_sampling_port_source(name)?.try_into()
305        }
306
307        /// Returns Err(Error::InvalidConfig) if sampling port with name does not exists or
308        /// if the message size of the found sampling port is different than MSG_SIZE
309        fn get_const_sampling_port_destination<const MSG_SIZE: MessageSize>(
310            name: Name,
311        ) -> Result<ConstSamplingPortDestination<MSG_SIZE, Self>, Error> {
312            S::get_sampling_port_destination(name)?.try_into()
313        }
314
315        /// Returns Err(Error::InvalidConfig) if sampling port with name does not exists
316        fn get_sampling_port_source(name: Name) -> Result<SamplingPortSource<Self>, Error> {
317            let id = S::get_sampling_port_id(name.into())?;
318            // According to ARINC653P1-5 3.6.2.1.5 this can only fail if the sampling_port_id
319            //  does not exist in the current partition.
320            // But since we retrieve the sampling_port_id directly from the hypervisor
321            //  there is no possible way for it not existing
322            let SamplingPortStatus {
323                refresh_period: _,
324                max_message_size: msg_size,
325                port_direction,
326                ..
327            } = S::get_sampling_port_status(id).unwrap().into();
328
329            if port_direction != PortDirection::Source {
330                return Err(Error::InvalidConfig);
331            }
332
333            Ok(SamplingPortSource {
334                _b: Default::default(),
335                id,
336                msg_size,
337            })
338        }
339
340        /// Returns Err(Error::InvalidConfig) if sampling port with name does not exists
341        fn get_sampling_port_destination(
342            name: Name,
343        ) -> Result<SamplingPortDestination<Self>, Error> {
344            let id = S::get_sampling_port_id(name.into())?;
345            // According to ARINC653P1-5 3.6.2.1.5 this can only fail if the sampling_port_id
346            //  does not exist in the current partition.
347            // But since we retrieve the sampling_port_id directly from the hypervisor
348            //  there is no possible way for it not existing
349            let SamplingPortStatus {
350                refresh_period,
351                max_message_size: msg_size,
352                port_direction,
353                ..
354            } = S::get_sampling_port_status(id)?.into();
355
356            if port_direction != PortDirection::Destination {
357                return Err(Error::InvalidConfig);
358            }
359
360            Ok(SamplingPortDestination {
361                _b: Default::default(),
362                id,
363                msg_size,
364                // According to ARINC653P1-5 3.6.2.1.1 the refresh_period defined during
365                //  COLD/WARM-Start is always positive, hence this unwrap cannot fail
366                refresh: refresh_period.unwrap_duration(),
367            })
368        }
369    }
370
371    impl<S: ApexSamplingPortP4Ext> SamplingPortSource<S> {
372        pub fn send(&self, buffer: &[ApexByte]) -> Result<(), Error> {
373            buffer.validate_write(self.msg_size)?;
374            S::sampling_port_send_unchecked(self.id, buffer)
375        }
376
377        pub const fn id(&self) -> SamplingPortId {
378            self.id
379        }
380
381        pub const fn size(&self) -> MessageSize {
382            self.msg_size
383        }
384    }
385
386    impl<S: ApexSamplingPortP1Ext> SamplingPortSource<S> {
387        pub fn from_name(name: Name) -> Result<SamplingPortSource<S>, Error> {
388            S::get_sampling_port_source(name)
389        }
390
391        pub fn status(&self) -> SamplingPortStatus {
392            // According to ARINC653P1-5 3.6.2.1.5 this can only fail if the sampling_port_id
393            //  does not exist in the current partition.
394            // But since we retrieve the sampling_port_id directly from the hypervisor
395            //  there is no possible way for it to not exist
396            S::get_sampling_port_status(self.id).unwrap().into()
397        }
398    }
399
400    impl<S: ApexSamplingPortP4Ext> SamplingPortDestination<S> {
401        pub fn receive<'a>(
402            &self,
403            buffer: &'a mut [ApexByte],
404        ) -> Result<(Validity, &'a [ApexByte]), Error> {
405            buffer.validate_read(self.msg_size)?;
406            unsafe { S::sampling_port_receive_unchecked(self.id, buffer) }
407        }
408
409        pub const fn id(&self) -> SamplingPortId {
410            self.id
411        }
412
413        pub const fn size(&self) -> MessageSize {
414            self.msg_size
415        }
416
417        pub const fn refresh_period(&self) -> Duration {
418            self.refresh
419        }
420    }
421
422    impl<S: ApexSamplingPortP1Ext> SamplingPortDestination<S> {
423        pub fn from_name(name: Name) -> Result<SamplingPortDestination<S>, Error> {
424            S::get_sampling_port_destination(name)
425        }
426
427        pub fn status(&self) -> SamplingPortStatus {
428            // According to ARINC653P1-5 3.6.2.1.5 this can only fail if the sampling_port_id
429            //  does not exist in the current partition.
430            // But since we retrieve the sampling_port_id directly from the hypervisor
431            //  there is no possible way for it not existing
432            S::get_sampling_port_status(self.id).unwrap().into()
433        }
434    }
435
436    impl<S: ApexSamplingPortP4Ext> StartContext<S> {
437        pub fn create_const_sampling_port_source<const MSG_SIZE: MessageSize>(
438            &mut self,
439            name: Name,
440        ) -> Result<ConstSamplingPortSource<MSG_SIZE, S>, Error> {
441            let port = self.create_sampling_port_source(name, MSG_SIZE)?;
442            Ok(ConstSamplingPortSource(port))
443        }
444        pub fn create_const_sampling_port_destination<const MSG_SIZE: MessageSize>(
445            &mut self,
446            name: Name,
447            refresh: Duration,
448        ) -> Result<ConstSamplingPortDestination<MSG_SIZE, S>, Error> {
449            let port = self.create_sampling_port_destination(name, MSG_SIZE, refresh)?;
450            Ok(ConstSamplingPortDestination(port))
451        }
452
453        pub fn create_sampling_port_source(
454            &mut self,
455            name: Name,
456            msg_size: MessageSize,
457        ) -> Result<SamplingPortSource<S>, Error> {
458            let id = S::create_sampling_port(
459                name.into(),
460                msg_size,
461                PortDirection::Source,
462                // use random non-zero duration.
463                // while refresh_period is ignored for the source
464                //  it may produce an error if set to zero
465                SystemTime::Normal(Duration::from_nanos(1)).into(),
466            )?;
467            Ok(SamplingPortSource {
468                _b: Default::default(),
469                id,
470                msg_size,
471            })
472        }
473        pub fn create_sampling_port_destination(
474            &mut self,
475            name: Name,
476            msg_size: MessageSize,
477            refresh: Duration,
478        ) -> Result<SamplingPortDestination<S>, Error> {
479            let id = S::create_sampling_port(
480                name.into(),
481                msg_size,
482                PortDirection::Destination,
483                SystemTime::Normal(refresh).into(),
484            )?;
485            Ok(SamplingPortDestination {
486                _b: Default::default(),
487                id,
488                msg_size,
489                refresh,
490            })
491        }
492    }
493}