components/
isl29035.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//! Components for the ISL29035 sensor.
6//!
7//! This provides two Components, Isl29035Component, which provides
8//! direct access to the ISL29035 within the kernel, and
9//! AmbientLightComponent, which provides the ambient light system
10//! call interface to the ISL29035. Note that only one of these
11//! Components should be instantiated, as AmbientLightComponent itself
12//! creates an Isl29035Component, which depends on a static buffer: if you
13//! allocate both, then the two instances of Isl29035Component will conflict
14//! on the buffer.
15//!
16//! Usage
17//! -----
18//! ```rust
19//! let isl29035 = Isl29035Component::new(mux_i2c, mux_alarm)
20//!     .finalize(components::isl29035_component_static!(sam4l::ast::Ast));
21//! let ambient_light =
22//!     AmbientLightComponent::new(board_kernel, capsules_extra::ambient_light::DRIVER_NUM, isl29035)
23//!         .finalize(components::ambient_light_component_static!());
24//! ```
25
26// Author: Philip Levis <pal@cs.stanford.edu>
27// Last modified: 6/20/2018
28
29use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
30use capsules_core::virtualizers::virtual_i2c::{I2CDevice, MuxI2C};
31use capsules_extra::ambient_light::AmbientLight;
32use capsules_extra::isl29035::Isl29035;
33use core::mem::MaybeUninit;
34use kernel::capabilities;
35use kernel::component::Component;
36use kernel::create_capability;
37use kernel::hil;
38use kernel::hil::i2c;
39use kernel::hil::time::{self, Alarm};
40
41// Setup static space for the objects.
42#[macro_export]
43macro_rules! isl29035_component_static {
44    ($A:ty, $I:ty $(,)?) => {{
45        let alarm = kernel::static_buf!(
46            capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, $A>
47        );
48        let i2c_device =
49            kernel::static_buf!(capsules_core::virtualizers::virtual_i2c::I2CDevice<'static, $I>);
50        let i2c_buffer = kernel::static_buf!([u8; capsules_extra::isl29035::BUF_LEN]);
51        let isl29035 = kernel::static_buf!(
52            capsules_extra::isl29035::Isl29035<
53                'static,
54                capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, $A>,
55            >
56        );
57
58        (alarm, i2c_device, i2c_buffer, isl29035)
59    };};
60}
61
62#[macro_export]
63macro_rules! ambient_light_component_static {
64    () => {{
65        kernel::static_buf!(capsules_extra::ambient_light::AmbientLight<'static>)
66    };};
67}
68
69pub struct Isl29035Component<
70    A: 'static + time::Alarm<'static>,
71    I: 'static + i2c::I2CMaster<'static>,
72> {
73    i2c_mux: &'static MuxI2C<'static, I>,
74    alarm_mux: &'static MuxAlarm<'static, A>,
75}
76
77impl<A: 'static + time::Alarm<'static>, I: 'static + i2c::I2CMaster<'static>>
78    Isl29035Component<A, I>
79{
80    pub fn new(i2c: &'static MuxI2C<'static, I>, alarm: &'static MuxAlarm<'static, A>) -> Self {
81        Isl29035Component {
82            i2c_mux: i2c,
83            alarm_mux: alarm,
84        }
85    }
86}
87
88impl<A: 'static + time::Alarm<'static>, I: 'static + i2c::I2CMaster<'static>> Component
89    for Isl29035Component<A, I>
90{
91    type StaticInput = (
92        &'static mut MaybeUninit<VirtualMuxAlarm<'static, A>>,
93        &'static mut MaybeUninit<I2CDevice<'static, I>>,
94        &'static mut MaybeUninit<[u8; capsules_extra::isl29035::BUF_LEN]>,
95        &'static mut MaybeUninit<Isl29035<'static, VirtualMuxAlarm<'static, A>>>,
96    );
97    type Output = &'static Isl29035<'static, VirtualMuxAlarm<'static, A>>;
98
99    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
100        let isl29035_i2c = static_buffer.1.write(I2CDevice::new(self.i2c_mux, 0x44));
101        let isl29035_i2c_buffer = static_buffer
102            .2
103            .write([0; capsules_extra::isl29035::BUF_LEN]);
104        let isl29035_virtual_alarm = static_buffer.0.write(VirtualMuxAlarm::new(self.alarm_mux));
105        isl29035_virtual_alarm.setup();
106
107        let isl29035 = static_buffer.3.write(Isl29035::new(
108            isl29035_i2c,
109            isl29035_virtual_alarm,
110            isl29035_i2c_buffer,
111        ));
112        isl29035_i2c.set_client(isl29035);
113        isl29035_virtual_alarm.set_alarm_client(isl29035);
114        isl29035
115    }
116}
117
118pub struct AmbientLightComponent<L: 'static + hil::sensors::AmbientLight<'static>> {
119    board_kernel: &'static kernel::Kernel,
120    driver_num: usize,
121    light_sensor: &'static L,
122}
123
124impl<L: 'static + hil::sensors::AmbientLight<'static>> AmbientLightComponent<L> {
125    pub fn new(
126        board_kernel: &'static kernel::Kernel,
127        driver_num: usize,
128        light_sensor: &'static L,
129    ) -> Self {
130        AmbientLightComponent {
131            board_kernel,
132            driver_num,
133            light_sensor,
134        }
135    }
136}
137
138impl<L: 'static + hil::sensors::AmbientLight<'static>> Component for AmbientLightComponent<L> {
139    type StaticInput = &'static mut MaybeUninit<AmbientLight<'static>>;
140    type Output = &'static AmbientLight<'static>;
141
142    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
143        let grant_cap = create_capability!(capabilities::MemoryAllocationCapability);
144
145        let ambient_light = static_buffer.write(AmbientLight::new(
146            self.light_sensor,
147            self.board_kernel.create_grant(self.driver_num, &grant_cap),
148        ));
149        hil::sensors::AmbientLight::set_client(self.light_sensor, ambient_light);
150        ambient_light
151    }
152}