Skip to main content

device_driver/
command.rs

1use core::marker::PhantomData;
2
3use crate::{Address, Block, Fieldset, FieldsetMetadata, NotFieldset, NotRepeating, Repeating};
4
5/// Common properties shared by [`CommandInterface`] & [`AsyncCommandInterface`]
6pub trait CommandInterfaceBase {
7    /// The error type
8    type Error;
9    /// The address type used by this interface. Should likely be an integer.
10    type AddressType: Address;
11}
12
13impl<T: CommandInterfaceBase> CommandInterfaceBase for &mut T {
14    type Error = T::Error;
15    type AddressType = T::AddressType;
16}
17
18#[diagnostic::on_unimplemented(
19    label = "cannot use blocking command operations when the device interface doesn't know how to dispatch commands",
20    note = "to enable command operations, implement the trait on this type"
21)]
22/// A trait to represent the interface to the device.
23///
24/// This is called to dispatch commands.
25pub trait CommandInterface: CommandInterfaceBase {
26    /// Dispatch a command on the device by sending the command.
27    ///
28    /// The input is the content that needs to be sent to the device.
29    /// The output is the buffer where the response needs to be written to.
30    ///
31    /// The slices are empty if the respective in or out fields are not specified.
32    fn dispatch_command(
33        &mut self,
34        address: Self::AddressType,
35        input: &mut [u8],
36        _input_metadata: &FieldsetMetadata,
37        output: &mut [u8],
38        _output_metadata: &FieldsetMetadata,
39    ) -> Result<(), Self::Error>;
40}
41
42#[diagnostic::do_not_recommend]
43impl<T: CommandInterface> CommandInterface for &mut T {
44    fn dispatch_command(
45        &mut self,
46        address: Self::AddressType,
47        input: &mut [u8],
48        input_metadata: &FieldsetMetadata,
49        output: &mut [u8],
50        output_metadata: &FieldsetMetadata,
51    ) -> Result<(), Self::Error> {
52        (*self).dispatch_command(address, input, input_metadata, output, output_metadata)
53    }
54}
55
56#[diagnostic::on_unimplemented(
57    label = "cannot use async command operations when the device interface doesn't know how to dispatch commands",
58    note = "to enable command operations, implement the trait on this type"
59)]
60/// A trait to represent the interface to the device.
61///
62/// This is called to asynchronously dispatch commands.
63pub trait AsyncCommandInterface: CommandInterfaceBase {
64    /// Dispatch a command on the device by sending the command.
65    ///
66    /// The input is the content that needs to be sent to the device.
67    /// The output is the buffer where the response needs to be written to.
68    ///
69    /// The slices are empty if the respective in or out fields are not specified.
70    async fn dispatch_command(
71        &mut self,
72        address: Self::AddressType,
73        input: &mut [u8],
74        _input_metadata: &FieldsetMetadata,
75        output: &mut [u8],
76        _output_metadata: &FieldsetMetadata,
77    ) -> Result<(), Self::Error>;
78}
79
80#[diagnostic::do_not_recommend]
81impl<T: AsyncCommandInterface> AsyncCommandInterface for &mut T {
82    fn dispatch_command(
83        &mut self,
84        address: Self::AddressType,
85        input: &mut [u8],
86        input_metadata: &FieldsetMetadata,
87        output: &mut [u8],
88        output_metadata: &FieldsetMetadata,
89    ) -> impl Future<Output = Result<(), Self::Error>> {
90        (*self).dispatch_command(address, input, input_metadata, output, output_metadata)
91    }
92}
93
94/// Intermediate type for doing command operations
95pub struct CommandOperation<'b, B, AddressType, InFieldset, OutFieldset, Repeat>
96where
97    B: Block,
98    B::Interface: CommandInterfaceBase<AddressType = AddressType>,
99    AddressType: Address,
100{
101    block: &'b mut B,
102    address: AddressType,
103    _phantom: PhantomData<(InFieldset, OutFieldset, Repeat)>,
104}
105
106impl<'d, B, AddressType, InFieldset, OutFieldset, Repeat>
107    CommandOperation<'d, B, AddressType, InFieldset, OutFieldset, Repeat>
108where
109    B: Block,
110    B::Interface: CommandInterfaceBase<AddressType = AddressType>,
111    AddressType: Address,
112{
113    #[doc(hidden)]
114    pub fn new(block: &'d mut B, address: AddressType) -> Self {
115        Self {
116            block,
117            address,
118            _phantom: PhantomData,
119        }
120    }
121
122    /// Dispatch the command to the device
123    pub fn dispatch(self) -> Result<(), <B::Interface as CommandInterfaceBase>::Error>
124    where
125        B::Interface: CommandInterface,
126        InFieldset: NotFieldset,
127        OutFieldset: NotFieldset,
128        Repeat: NotRepeating,
129    {
130        self.block.interface().dispatch_command(
131            self.address,
132            &mut [],
133            &FieldsetMetadata::DEFAULT,
134            &mut [],
135            &FieldsetMetadata::DEFAULT,
136        )
137    }
138
139    /// Dispatch the command to the device
140    #[track_caller]
141    pub fn dispatch_at(
142        self,
143        index: Repeat::Index,
144    ) -> Result<(), <B::Interface as CommandInterfaceBase>::Error>
145    where
146        B::Interface: CommandInterface,
147        InFieldset: NotFieldset,
148        OutFieldset: NotFieldset,
149        Repeat: Repeating,
150    {
151        self.block.interface().dispatch_command(
152            Repeat::calc_address(self.address, index),
153            &mut [],
154            &FieldsetMetadata::DEFAULT,
155            &mut [],
156            &FieldsetMetadata::DEFAULT,
157        )
158    }
159
160    /// Dispatch the command to the device
161    pub fn dispatch_async(
162        self,
163    ) -> impl Future<Output = Result<(), <B::Interface as CommandInterfaceBase>::Error>>
164    where
165        B::Interface: AsyncCommandInterface,
166        InFieldset: NotFieldset,
167        OutFieldset: NotFieldset,
168        Repeat: NotRepeating,
169    {
170        self.block.interface().dispatch_command(
171            self.address,
172            &mut [],
173            &FieldsetMetadata::DEFAULT,
174            &mut [],
175            &FieldsetMetadata::DEFAULT,
176        )
177    }
178
179    /// Dispatch the command to the device
180    pub fn dispatch_at_async(
181        self,
182        index: Repeat::Index,
183    ) -> impl Future<Output = Result<(), <B::Interface as CommandInterfaceBase>::Error>>
184    where
185        B::Interface: AsyncCommandInterface,
186        InFieldset: NotFieldset,
187        OutFieldset: NotFieldset,
188        Repeat: Repeating,
189    {
190        self.block.interface().dispatch_command(
191            Repeat::calc_address(self.address, index),
192            &mut [],
193            &FieldsetMetadata::DEFAULT,
194            &mut [],
195            &FieldsetMetadata::DEFAULT,
196        )
197    }
198
199    /// Dispatch the command to the device with an input
200    pub fn dispatch_in(
201        self,
202        f: impl FnOnce(&mut InFieldset),
203    ) -> Result<(), <B::Interface as CommandInterfaceBase>::Error>
204    where
205        B::Interface: CommandInterface,
206        InFieldset: Fieldset,
207        OutFieldset: NotFieldset,
208        Repeat: NotRepeating,
209    {
210        let mut in_fields = InFieldset::ZERO;
211        f(&mut in_fields);
212
213        self.block.interface().dispatch_command(
214            self.address,
215            in_fields.as_slice_mut(),
216            &InFieldset::METADATA,
217            &mut [],
218            &FieldsetMetadata::DEFAULT,
219        )
220    }
221
222    /// Dispatch the command to the device with an input
223    #[track_caller]
224    pub fn dispatch_in_at(
225        self,
226        index: Repeat::Index,
227        f: impl FnOnce(&mut InFieldset),
228    ) -> Result<(), <B::Interface as CommandInterfaceBase>::Error>
229    where
230        B::Interface: CommandInterface,
231        InFieldset: Fieldset,
232        OutFieldset: NotFieldset,
233        Repeat: Repeating,
234    {
235        let mut in_fields = InFieldset::ZERO;
236        f(&mut in_fields);
237
238        self.block.interface().dispatch_command(
239            Repeat::calc_address(self.address, index),
240            in_fields.as_slice_mut(),
241            &InFieldset::METADATA,
242            &mut [],
243            &FieldsetMetadata::DEFAULT,
244        )
245    }
246
247    /// Dispatch the command to the device with an input
248    pub async fn dispatch_in_async(
249        self,
250        f: impl FnOnce(&mut InFieldset),
251    ) -> Result<(), <B::Interface as CommandInterfaceBase>::Error>
252    where
253        B::Interface: AsyncCommandInterface,
254        InFieldset: Fieldset,
255        OutFieldset: NotFieldset,
256        Repeat: NotRepeating,
257    {
258        let mut in_fields = InFieldset::ZERO;
259        f(&mut in_fields);
260
261        self.block
262            .interface()
263            .dispatch_command(
264                self.address,
265                in_fields.as_slice_mut(),
266                &InFieldset::METADATA,
267                &mut [],
268                &FieldsetMetadata::DEFAULT,
269            )
270            .await
271    }
272
273    /// Dispatch the command to the device with an input
274    pub async fn dispatch_in_at_async(
275        self,
276        index: Repeat::Index,
277        f: impl FnOnce(&mut InFieldset),
278    ) -> Result<(), <B::Interface as CommandInterfaceBase>::Error>
279    where
280        B::Interface: AsyncCommandInterface,
281        InFieldset: Fieldset,
282        OutFieldset: NotFieldset,
283        Repeat: Repeating,
284    {
285        let mut in_fields = InFieldset::ZERO;
286        f(&mut in_fields);
287
288        self.block
289            .interface()
290            .dispatch_command(
291                Repeat::calc_address(self.address, index),
292                in_fields.as_slice_mut(),
293                &InFieldset::METADATA,
294                &mut [],
295                &FieldsetMetadata::DEFAULT,
296            )
297            .await
298    }
299
300    /// Dispatch the command to the device with an output
301    pub fn dispatch_out(self) -> Result<OutFieldset, <B::Interface as CommandInterfaceBase>::Error>
302    where
303        B::Interface: CommandInterface,
304        InFieldset: NotFieldset,
305        OutFieldset: Fieldset,
306        Repeat: NotRepeating,
307    {
308        let mut out_fields = OutFieldset::ZERO;
309
310        self.block.interface().dispatch_command(
311            self.address,
312            &mut [],
313            &FieldsetMetadata::DEFAULT,
314            out_fields.as_slice_mut(),
315            &OutFieldset::METADATA,
316        )?;
317
318        Ok(out_fields)
319    }
320
321    /// Dispatch the command to the device with an output
322    #[track_caller]
323    pub fn dispatch_out_at(
324        self,
325        index: Repeat::Index,
326    ) -> Result<OutFieldset, <B::Interface as CommandInterfaceBase>::Error>
327    where
328        B::Interface: CommandInterface,
329        InFieldset: NotFieldset,
330        OutFieldset: Fieldset,
331        Repeat: Repeating,
332    {
333        let mut out_fields = OutFieldset::ZERO;
334
335        self.block.interface().dispatch_command(
336            Repeat::calc_address(self.address, index),
337            &mut [],
338            &FieldsetMetadata::DEFAULT,
339            out_fields.as_slice_mut(),
340            &OutFieldset::METADATA,
341        )?;
342
343        Ok(out_fields)
344    }
345
346    /// Dispatch the command to the device with an output
347    pub async fn dispatch_out_async(
348        self,
349    ) -> Result<OutFieldset, <B::Interface as CommandInterfaceBase>::Error>
350    where
351        B::Interface: AsyncCommandInterface,
352        InFieldset: NotFieldset,
353        OutFieldset: Fieldset,
354        Repeat: NotRepeating,
355    {
356        let mut out_fields = OutFieldset::ZERO;
357
358        self.block
359            .interface()
360            .dispatch_command(
361                self.address,
362                &mut [],
363                &FieldsetMetadata::DEFAULT,
364                out_fields.as_slice_mut(),
365                &OutFieldset::METADATA,
366            )
367            .await?;
368
369        Ok(out_fields)
370    }
371
372    /// Dispatch the command to the device with an output
373    pub async fn dispatch_out_at_async(
374        self,
375        index: Repeat::Index,
376    ) -> Result<OutFieldset, <B::Interface as CommandInterfaceBase>::Error>
377    where
378        B::Interface: AsyncCommandInterface,
379        InFieldset: NotFieldset,
380        OutFieldset: Fieldset,
381        Repeat: Repeating,
382    {
383        let mut out_fields = OutFieldset::ZERO;
384
385        self.block
386            .interface()
387            .dispatch_command(
388                Repeat::calc_address(self.address, index),
389                &mut [],
390                &FieldsetMetadata::DEFAULT,
391                out_fields.as_slice_mut(),
392                &OutFieldset::METADATA,
393            )
394            .await?;
395
396        Ok(out_fields)
397    }
398
399    /// Dispatch the command to the device with an input and output
400    pub fn dispatch_inout(
401        self,
402        f: impl FnOnce(&mut InFieldset),
403    ) -> Result<OutFieldset, <B::Interface as CommandInterfaceBase>::Error>
404    where
405        B::Interface: CommandInterface,
406        InFieldset: Fieldset,
407        OutFieldset: Fieldset,
408        Repeat: NotRepeating,
409    {
410        let mut in_fields = InFieldset::ZERO;
411        f(&mut in_fields);
412
413        let mut out_fields = OutFieldset::ZERO;
414
415        self.block.interface().dispatch_command(
416            self.address,
417            in_fields.as_slice_mut(),
418            &InFieldset::METADATA,
419            out_fields.as_slice_mut(),
420            &OutFieldset::METADATA,
421        )?;
422
423        Ok(out_fields)
424    }
425
426    /// Dispatch the command to the device with an input and output
427    #[track_caller]
428    pub fn dispatch_inout_at(
429        self,
430        index: Repeat::Index,
431        f: impl FnOnce(&mut InFieldset),
432    ) -> Result<OutFieldset, <B::Interface as CommandInterfaceBase>::Error>
433    where
434        B::Interface: CommandInterface,
435        InFieldset: Fieldset,
436        OutFieldset: Fieldset,
437        Repeat: Repeating,
438    {
439        let mut in_fields = InFieldset::ZERO;
440        f(&mut in_fields);
441
442        let mut out_fields = OutFieldset::ZERO;
443
444        self.block.interface().dispatch_command(
445            Repeat::calc_address(self.address, index),
446            in_fields.as_slice_mut(),
447            &InFieldset::METADATA,
448            out_fields.as_slice_mut(),
449            &OutFieldset::METADATA,
450        )?;
451
452        Ok(out_fields)
453    }
454
455    /// Dispatch the command to the device with an input and output
456    pub async fn dispatch_inout_async(
457        self,
458        f: impl FnOnce(&mut InFieldset),
459    ) -> Result<OutFieldset, <B::Interface as CommandInterfaceBase>::Error>
460    where
461        B::Interface: AsyncCommandInterface,
462        InFieldset: Fieldset,
463        OutFieldset: Fieldset,
464        Repeat: NotRepeating,
465    {
466        let mut in_fields = InFieldset::ZERO;
467        f(&mut in_fields);
468
469        let mut out_fields = OutFieldset::ZERO;
470
471        self.block
472            .interface()
473            .dispatch_command(
474                self.address,
475                in_fields.as_slice_mut(),
476                &InFieldset::METADATA,
477                out_fields.as_slice_mut(),
478                &OutFieldset::METADATA,
479            )
480            .await?;
481
482        Ok(out_fields)
483    }
484
485    /// Dispatch the command to the device with an input and output
486    pub async fn dispatch_inout_at_async(
487        self,
488        index: Repeat::Index,
489        f: impl FnOnce(&mut InFieldset),
490    ) -> Result<OutFieldset, <B::Interface as CommandInterfaceBase>::Error>
491    where
492        B::Interface: AsyncCommandInterface,
493        InFieldset: Fieldset,
494        OutFieldset: Fieldset,
495        Repeat: Repeating,
496    {
497        let mut in_fields = InFieldset::ZERO;
498        f(&mut in_fields);
499
500        let mut out_fields = OutFieldset::ZERO;
501
502        self.block
503            .interface()
504            .dispatch_command(
505                Repeat::calc_address(self.address, index),
506                in_fields.as_slice_mut(),
507                &InFieldset::METADATA,
508                out_fields.as_slice_mut(),
509                &OutFieldset::METADATA,
510            )
511            .await?;
512
513        Ok(out_fields)
514    }
515}