capsules_extra/
sk68xx.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 2025.
4
5//! Single-wire LED.
6//!
7//! Tested with the SK68XXMINI on the ESP32-C3-DevKitM-1.
8//!
9//! Datasheet: <https://www.rose-lighting.com/wp-content/uploads/sites/53/2020/05/SK68XX-MINI-HS-REV.04-EN23535RGB-thick.pdf>
10
11use core::cell::Cell;
12
13use kernel::hil::gpio::Pin;
14use kernel::hil::led::Led;
15
16/// The single-wire, tri-color (RGB) LED.
17///
18/// The pulses need to be calibrated based on the clock speed of the chip.
19/// - `T0H`: Number of nops needed for about 0.28 us. This is then scaled for
20///   `T0L`, `T1H`, and `T1L`.
21pub struct Sk68xx<'a, P: Pin, const T0H: usize> {
22    pin: &'a P,
23    nop: fn(),
24    red: Cell<bool>,
25    green: Cell<bool>,
26    blue: Cell<bool>,
27}
28
29impl<'a, P: Pin, const T0H: usize> Sk68xx<'a, P, T0H> {
30    pub fn new(pin: &'a P, nop: fn()) -> Self {
31        Self {
32            pin,
33            nop,
34            red: Cell::new(false),
35            green: Cell::new(false),
36            blue: Cell::new(false),
37        }
38    }
39
40    pub fn init(&self) {
41        self.pin.make_output();
42        self.pin.clear();
43        // Wait for 80 us.
44        for _ in 0..(286 * T0H) {
45            (self.nop)();
46        }
47    }
48
49    fn write(&self) {
50        let red = self.red.get();
51        let green = self.green.get();
52        let blue = self.blue.get();
53
54        for i in 0..24 {
55            let high = if i < 8 {
56                // Green
57                green
58            } else if i < 16 {
59                // Red
60                red
61            } else {
62                // Blue
63                blue
64            };
65            if high {
66                // High for 0.74 us
67                self.pin.set();
68                for _ in 0..(T0H * 3) {
69                    (self.nop)();
70                }
71
72                // Low for 0.52 us
73                self.pin.clear();
74                for _ in 0..(T0H * 2) {
75                    (self.nop)();
76                }
77            } else {
78                // High for 0.28 us
79                self.pin.set();
80                for _ in 0..T0H {
81                    (self.nop)();
82                }
83
84                // Low for 0.94 us
85                self.pin.clear();
86                for _ in 0..(T0H * 4) {
87                    (self.nop)();
88                }
89            }
90        }
91
92        // 80 us rest period after to reset the writing and permit a subsequent
93        // write to the LED.
94        for _ in 0..(286 * T0H) {
95            (self.nop)();
96        }
97    }
98
99    fn update_red(&self, on: bool) {
100        self.red.set(on);
101        self.write();
102    }
103
104    fn update_green(&self, on: bool) {
105        self.green.set(on);
106        self.write();
107    }
108
109    fn update_blue(&self, on: bool) {
110        self.blue.set(on);
111        self.write();
112    }
113
114    fn toggle_red(&self) {
115        self.red.set(!self.red.get());
116        self.write();
117    }
118
119    fn toggle_green(&self) {
120        self.green.set(!self.green.get());
121        self.write();
122    }
123
124    fn toggle_blue(&self) {
125        self.blue.set(!self.blue.get());
126        self.write();
127    }
128
129    fn get_red(&self) -> bool {
130        self.red.get()
131    }
132
133    fn get_green(&self) -> bool {
134        self.green.get()
135    }
136
137    fn get_blue(&self) -> bool {
138        self.blue.get()
139    }
140}
141
142// One of the LEDs on the tri-color LED.
143//
144// - Index 0: Red
145// - Index 1: Green
146// - Index 2: Blue
147pub struct Sk68xxLed<'a, P: Pin, const T0H: usize> {
148    sk68xx: &'a Sk68xx<'a, P, T0H>,
149    index: usize,
150}
151
152impl<'a, P: Pin, const T0H: usize> Sk68xxLed<'a, P, T0H> {
153    pub fn new(sk68xx: &'a Sk68xx<'a, P, T0H>, index: usize) -> Self {
154        Self { sk68xx, index }
155    }
156}
157
158impl<P: Pin, const T0H: usize> Led for Sk68xxLed<'_, P, T0H> {
159    fn init(&self) {}
160
161    fn on(&self) {
162        match self.index {
163            0 => self.sk68xx.update_red(true),
164            1 => self.sk68xx.update_green(true),
165            2 => self.sk68xx.update_blue(true),
166            _ => {}
167        }
168    }
169
170    fn off(&self) {
171        match self.index {
172            0 => self.sk68xx.update_red(false),
173            1 => self.sk68xx.update_green(false),
174            2 => self.sk68xx.update_blue(false),
175            _ => {}
176        }
177    }
178
179    fn toggle(&self) {
180        match self.index {
181            0 => self.sk68xx.toggle_red(),
182            1 => self.sk68xx.toggle_green(),
183            2 => self.sk68xx.toggle_blue(),
184            _ => {}
185        }
186    }
187
188    fn read(&self) -> bool {
189        match self.index {
190            0 => self.sk68xx.get_red(),
191            1 => self.sk68xx.get_green(),
192            2 => self.sk68xx.get_blue(),
193            _ => false,
194        }
195    }
196}