Skip to main content

components/
buzzer.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 2026.
4
5//! Component for a PWM-based buzzer driver.
6//!
7//! This creates a `Buzzer` syscall driver using a PWM pin and a virtual alarm.
8//! It internally allocates the `VirtualMuxAlarm`, `PwmBuzzer`, and `Buzzer`
9//! objects.
10//!
11//! Usage
12//! -----
13//! ```rust
14//! let buzzer = components::buzzer::BuzzerComponent::new(
15//!     board_kernel,
16//!     capsules_extra::buzzer_driver::DRIVER_NUM,
17//!     mux_alarm,
18//!     virtual_pwm_buzzer,
19//! )
20//! .finalize(components::buzzer_component_static!(AlarmHw, PwmHw));
21//! ```
22
23use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
24use capsules_core::virtualizers::virtual_pwm::PwmPinUser;
25use capsules_extra::buzzer_driver::Buzzer;
26use capsules_extra::buzzer_pwm::PwmBuzzer;
27use core::mem::MaybeUninit;
28use kernel::capabilities::MemoryAllocationCapability;
29use kernel::component::Component;
30use kernel::hil;
31
32#[macro_export]
33macro_rules! buzzer_component_static {
34    ($A:ty, $P:ty $(,)?) => {{
35        use capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm;
36        use capsules_core::virtualizers::virtual_pwm::PwmPinUser;
37        use capsules_extra::buzzer_driver::Buzzer;
38        use capsules_extra::buzzer_pwm::PwmBuzzer;
39        let alarm = kernel::static_buf!(VirtualMuxAlarm<'static, $A>);
40        let pwm_buzzer = kernel::static_buf!(
41            PwmBuzzer<'static, VirtualMuxAlarm<'static, $A>, PwmPinUser<'static, $P>>
42        );
43        let buzzer = kernel::static_buf!(
44            Buzzer<
45                'static,
46                PwmBuzzer<'static, VirtualMuxAlarm<'static, $A>, PwmPinUser<'static, $P>>,
47            >
48        );
49        (alarm, pwm_buzzer, buzzer)
50    }};
51}
52
53pub type BuzzerComponentType<A, P> = capsules_extra::buzzer_driver::Buzzer<
54    'static,
55    capsules_extra::buzzer_pwm::PwmBuzzer<
56        'static,
57        capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, A>,
58        capsules_core::virtualizers::virtual_pwm::PwmPinUser<'static, P>,
59    >,
60>;
61
62pub struct BuzzerComponent<
63    A: 'static + hil::time::Alarm<'static>,
64    P: 'static + hil::pwm::Pwm,
65    CAP: MemoryAllocationCapability + 'static,
66> {
67    board_kernel: &'static kernel::Kernel,
68    driver_num: usize,
69    mux_alarm: &'static MuxAlarm<'static, A>,
70    pwm_pin: &'static PwmPinUser<'static, P>,
71    mem_cap: CAP,
72}
73
74impl<
75    A: 'static + hil::time::Alarm<'static>,
76    P: 'static + hil::pwm::Pwm,
77    CAP: MemoryAllocationCapability + 'static,
78> BuzzerComponent<A, P, CAP>
79{
80    pub fn new(
81        board_kernel: &'static kernel::Kernel,
82        driver_num: usize,
83        mux_alarm: &'static MuxAlarm<'static, A>,
84        pwm_pin: &'static PwmPinUser<'static, P>,
85        mem_cap: CAP,
86    ) -> Self {
87        Self {
88            board_kernel,
89            driver_num,
90            mux_alarm,
91            pwm_pin,
92            mem_cap,
93        }
94    }
95}
96
97impl<
98    A: 'static + hil::time::Alarm<'static>,
99    P: 'static + hil::pwm::Pwm,
100    CAP: MemoryAllocationCapability + 'static,
101> Component for BuzzerComponent<A, P, CAP>
102{
103    type StaticInput = (
104        &'static mut MaybeUninit<VirtualMuxAlarm<'static, A>>,
105        &'static mut MaybeUninit<
106            PwmBuzzer<'static, VirtualMuxAlarm<'static, A>, PwmPinUser<'static, P>>,
107        >,
108        &'static mut MaybeUninit<
109            Buzzer<
110                'static,
111                PwmBuzzer<'static, VirtualMuxAlarm<'static, A>, PwmPinUser<'static, P>>,
112            >,
113        >,
114    );
115    type Output = &'static Buzzer<
116        'static,
117        PwmBuzzer<'static, VirtualMuxAlarm<'static, A>, PwmPinUser<'static, P>>,
118    >;
119
120    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
121        let virtual_alarm_buzzer = static_buffer.0.write(VirtualMuxAlarm::new(self.mux_alarm));
122        virtual_alarm_buzzer.setup();
123
124        let pwm_buzzer = static_buffer.1.write(PwmBuzzer::new(
125            self.pwm_pin,
126            virtual_alarm_buzzer,
127            capsules_extra::buzzer_pwm::DEFAULT_MAX_BUZZ_TIME_MS,
128        ));
129
130        let buzzer = static_buffer.2.write(Buzzer::new(
131            pwm_buzzer,
132            capsules_extra::buzzer_driver::DEFAULT_MAX_BUZZ_TIME_MS,
133            self.board_kernel
134                .create_grant(self.driver_num, &self.mem_cap),
135        ));
136
137        hil::buzzer::Buzzer::set_client(pwm_buzzer, buzzer);
138        hil::time::Alarm::set_alarm_client(virtual_alarm_buzzer, pwm_buzzer);
139
140        buzzer
141    }
142}