capsules_extra/
analog_comparator.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//! Provides userspace access to the analog comparators on a board.
6//!
7//! Usage
8//! -----
9//!
10//! ```rust,ignore
11//! # use kernel::static_init;
12//!
13//! let ac_channels = static_init!(
14//!     [&'static sam4l::acifc::AcChannel; 2],
15//!     [
16//!         &sam4l::acifc::CHANNEL_AC0,
17//!         &sam4l::acifc::CHANNEL_AC1,
18//!     ]
19//! );
20//! let analog_comparator = static_init!(
21//!     capsules::analog_comparator::AnalogComparator<'static, sam4l::acifc::Acifc>,
22//!     capsules::analog_comparator::AnalogComparator::new(&mut sam4l::acifc::ACIFC, ac_channels)
23//! );
24//! sam4l::acifc::ACIFC.set_client(analog_comparator);
25//! ```
26//!
27//! ## Number of Analog Comparators
28//! The number of analog comparators available depends on the microcontroller/board used.
29//!
30//! ## Normal or Interrupt-based Comparison
31//! For a normal comparison or an interrupt-based comparison, just one analog
32//! comparator is necessary.
33//!
34//! For more information on how this capsule works, please take a look at the
35//! README: 00007_analog_comparator.md in doc/syscalls.
36
37// Author: Danilo Verhaert <verhaert@cs.stanford.edu>
38// Last modified August 9th, 2018
39
40/// Syscall driver number.
41use capsules_core::driver;
42pub const DRIVER_NUM: usize = driver::NUM::AnalogComparator as usize;
43
44use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
45use kernel::hil;
46use kernel::syscall::{CommandReturn, SyscallDriver};
47use kernel::utilities::cells::OptionalCell;
48use kernel::{ErrorCode, ProcessId};
49
50pub struct AnalogComparator<'a, A: hil::analog_comparator::AnalogComparator<'a> + 'a> {
51    // Analog Comparator driver
52    analog_comparator: &'a A,
53    channels: &'a [&'a <A as hil::analog_comparator::AnalogComparator<'a>>::Channel],
54
55    grants: Grant<App, UpcallCount<1>, AllowRoCount<0>, AllowRwCount<0>>,
56    current_process: OptionalCell<ProcessId>,
57}
58
59#[derive(Default)]
60pub struct App {}
61
62impl<'a, A: hil::analog_comparator::AnalogComparator<'a>> AnalogComparator<'a, A> {
63    pub fn new(
64        analog_comparator: &'a A,
65        channels: &'a [&'a <A as hil::analog_comparator::AnalogComparator<'a>>::Channel],
66        grant: Grant<App, UpcallCount<1>, AllowRoCount<0>, AllowRwCount<0>>,
67    ) -> AnalogComparator<'a, A> {
68        AnalogComparator {
69            // Analog Comparator driver
70            analog_comparator,
71            channels,
72            grants: grant,
73            current_process: OptionalCell::empty(),
74        }
75    }
76
77    // Do a single comparison on a channel
78    fn comparison(&self, channel: usize) -> Result<bool, ErrorCode> {
79        if channel >= self.channels.len() {
80            return Err(ErrorCode::INVAL);
81        }
82        // Convert channel index
83        let chan = self.channels[channel];
84        let result = self.analog_comparator.comparison(chan);
85
86        Ok(result)
87    }
88
89    // Start comparing on a channel
90    fn start_comparing(&self, channel: usize) -> Result<(), ErrorCode> {
91        if channel >= self.channels.len() {
92            return Err(ErrorCode::INVAL);
93        }
94        // Convert channel index
95        let chan = self.channels[channel];
96
97        self.analog_comparator.start_comparing(chan)
98    }
99
100    // Stop comparing on a channel
101    fn stop_comparing(&self, channel: usize) -> Result<(), ErrorCode> {
102        if channel >= self.channels.len() {
103            return Err(ErrorCode::INVAL);
104        }
105        // Convert channel index
106        let chan = self.channels[channel];
107
108        self.analog_comparator.stop_comparing(chan)
109    }
110}
111
112impl<'a, A: hil::analog_comparator::AnalogComparator<'a>> SyscallDriver
113    for AnalogComparator<'a, A>
114{
115    /// Control the analog comparator.
116    ///
117    /// ### `command_num`
118    ///
119    /// - `0`: Driver existence check.
120    /// - `1`: Perform a simple comparison. Input x chooses the desired
121    ///   comparator ACx (e.g. 0 or 1 for hail, 0-3 for imix)
122    /// - `2`: Start interrupt-based comparisons. Input x chooses the desired
123    ///   comparator ACx (e.g. 0 or 1 for hail, 0-3 for imix)
124    /// - `3`: Stop interrupt-based comparisons. Input x chooses the desired
125    ///   comparator ACx (e.g. 0 or 1 for hail, 0-3 for imix)
126    /// - `4`: Get number of channels.
127    fn command(
128        &self,
129        command_num: usize,
130        channel: usize,
131        _: usize,
132        processid: ProcessId,
133    ) -> CommandReturn {
134        if command_num == 0 {
135            // Handle unconditional driver existence check.
136            return CommandReturn::success();
137        }
138
139        // Check if this driver is free, or already dedicated to this process.
140        let match_or_empty_or_nonexistant = self.current_process.map_or(true, |current_process| {
141            self.grants
142                .enter(current_process, |_, _| current_process == processid)
143                .unwrap_or(true)
144        });
145        if match_or_empty_or_nonexistant {
146            self.current_process.set(processid);
147        } else {
148            return CommandReturn::failure(ErrorCode::NOMEM);
149        }
150
151        match command_num {
152            0 => CommandReturn::success_u32(self.channels.len() as u32),
153
154            1 => match self.comparison(channel) {
155                Ok(b) => CommandReturn::success_u32(b as u32),
156                Err(e) => CommandReturn::failure(e),
157            },
158
159            2 => self.start_comparing(channel).into(),
160
161            3 => self.stop_comparing(channel).into(),
162
163            4 => CommandReturn::success_u32(self.channels.len() as u32),
164
165            _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
166        }
167    }
168
169    fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
170        self.grants.enter(processid, |_, _| {})
171    }
172}
173
174impl<'a, A: hil::analog_comparator::AnalogComparator<'a>> hil::analog_comparator::Client
175    for AnalogComparator<'a, A>
176{
177    /// Upcall to userland, signaling the application
178    fn fired(&self, channel: usize) {
179        self.current_process.map(|processid| {
180            let _ = self.grants.enter(processid, |_app, upcalls| {
181                upcalls.schedule_upcall(0, (channel, 0, 0)).ok();
182            });
183        });
184    }
185}