components/
cdc.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Component for CDC-ACM over USB support.
6//!
7//! This provides a component for using the CDC-ACM driver. This allows for
8//! serial communication over USB.
9//!
10//! Usage
11//! -----
12//! ```rust
13//! static STRINGS: &'static [&str; 3] = &[
14//!     "XYZ Corp.",      // Manufacturer
15//!     "The Zorpinator", // Product
16//!     "Serial No. 5",   // Serial number
17//! ];
18//! let cdc_acm = components::cdc::CdcAcmComponent::new(
19//!     &nrf52::usbd::USBD,
20//!     capsules_extra::usb::usbc_client::MAX_CTRL_PACKET_SIZE_NRF52840,
21//!     0x2341,
22//!     0x005a,
23//!     STRINGS)
24//! .finalize(components::cdc_acm_component_static!(nrf52::usbd::Usbd));
25//! ```
26
27use core::mem::MaybeUninit;
28
29use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
30use kernel::component::Component;
31use kernel::hil;
32use kernel::hil::time::Alarm;
33
34// Setup static space for the objects.
35#[macro_export]
36macro_rules! cdc_acm_component_static {
37    ($U:ty, $A:ty $(,)?) => {{
38        let alarm = kernel::static_buf!(
39            capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, $A>
40        );
41        let cdc = kernel::static_buf!(
42            capsules_extra::usb::cdc::CdcAcm<
43                'static,
44                $U,
45                capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, $A>,
46            >
47        );
48
49        (alarm, cdc)
50    };};
51}
52
53pub struct CdcAcmComponent<
54    U: 'static + hil::usb::UsbController<'static>,
55    A: 'static + Alarm<'static>,
56> {
57    usb: &'static U,
58    max_ctrl_packet_size: u8,
59    vendor_id: u16,
60    product_id: u16,
61    strings: &'static [&'static str; 3],
62    alarm_mux: &'static MuxAlarm<'static, A>,
63    host_initiated_function: Option<&'static (dyn Fn() + 'static)>,
64}
65
66impl<U: 'static + hil::usb::UsbController<'static>, A: 'static + Alarm<'static>>
67    CdcAcmComponent<U, A>
68{
69    pub fn new(
70        usb: &'static U,
71        max_ctrl_packet_size: u8,
72        vendor_id: u16,
73        product_id: u16,
74        strings: &'static [&'static str; 3],
75        alarm_mux: &'static MuxAlarm<'static, A>,
76        host_initiated_function: Option<&'static (dyn Fn() + 'static)>,
77    ) -> Self {
78        Self {
79            usb,
80            max_ctrl_packet_size,
81            vendor_id,
82            product_id,
83            strings,
84            alarm_mux,
85            host_initiated_function,
86        }
87    }
88}
89
90impl<U: 'static + hil::usb::UsbController<'static>, A: 'static + Alarm<'static>> Component
91    for CdcAcmComponent<U, A>
92{
93    type StaticInput = (
94        &'static mut MaybeUninit<VirtualMuxAlarm<'static, A>>,
95        &'static mut MaybeUninit<
96            capsules_extra::usb::cdc::CdcAcm<'static, U, VirtualMuxAlarm<'static, A>>,
97        >,
98    );
99    type Output =
100        &'static capsules_extra::usb::cdc::CdcAcm<'static, U, VirtualMuxAlarm<'static, A>>;
101
102    fn finalize(self, s: Self::StaticInput) -> Self::Output {
103        let cdc_alarm = s.0.write(VirtualMuxAlarm::new(self.alarm_mux));
104        cdc_alarm.setup();
105
106        let cdc = s.1.write(capsules_extra::usb::cdc::CdcAcm::new(
107            self.usb,
108            self.max_ctrl_packet_size,
109            self.vendor_id,
110            self.product_id,
111            self.strings,
112            cdc_alarm,
113            self.host_initiated_function,
114        ));
115        kernel::deferred_call::DeferredCallClient::register(cdc);
116        self.usb.set_client(cdc);
117        cdc_alarm.set_alarm_client(cdc);
118
119        cdc
120    }
121}