1use core::cell::Cell;
78
79use kernel::utilities::cells::TakeCell;
80use kernel::ErrorCode;
81
82use kernel::hil::gpio::{ActivationMode, Pin};
83use kernel::hil::led::Led;
84use kernel::hil::time::{Alarm, AlarmClient, ConvertTicks};
85
86pub struct LedMatrixDriver<'a, L: Pin, A: Alarm<'a>> {
89 cols: &'a [&'a L],
90 rows: &'a [&'a L],
91 buffer: TakeCell<'a, [u8]>,
92 alarm: &'a A,
93 current_row: Cell<usize>,
94 timing: u8,
95 row_activation: ActivationMode,
96 col_activation: ActivationMode,
97}
98
99impl<'a, L: Pin, A: Alarm<'a>> LedMatrixDriver<'a, L, A> {
100 pub fn new(
101 cols: &'a [&'a L],
102 rows: &'a [&'a L],
103 buffer: &'a mut [u8],
104 alarm: &'a A,
105 col_activation: ActivationMode,
106 row_activation: ActivationMode,
107 refresh_rate: usize,
108 ) -> Self {
109 if (buffer.len() * 8) < cols.len() * rows.len() {
111 panic!("Matrix LED Driver: provided buffer is too small");
112 }
113
114 Self {
115 cols,
116 rows,
117 buffer: TakeCell::new(buffer),
118 alarm,
119 col_activation,
120 row_activation,
121 current_row: Cell::new(0),
122 timing: (1000 / (refresh_rate * rows.len())) as u8,
123 }
124 }
125
126 pub fn init(&self) {
127 for led in self.cols {
128 led.make_output();
129 self.col_clear(led);
130 }
131
132 for led in self.rows {
133 led.make_output();
134 self.row_clear(led);
135 }
136 self.next_row();
137 }
138
139 pub fn cols_len(&self) -> usize {
140 self.cols.len()
141 }
142
143 pub fn rows_len(&self) -> usize {
144 self.rows.len()
145 }
146
147 fn next_row(&self) {
148 self.row_clear(self.rows[self.current_row.get()]);
149 self.current_row
150 .set((self.current_row.get() + 1) % self.rows.len());
151 self.buffer.map(|bits| {
152 for led in 0..self.cols.len() {
153 let pos = self.current_row.get() * self.cols.len() + led;
154 if (bits[pos / 8] >> (pos % 8)) & 0x1 == 1 {
155 self.col_set(self.cols[led]);
156 } else {
157 self.col_clear(self.cols[led]);
158 }
159 }
160 });
161 self.row_set(self.rows[self.current_row.get()]);
162 let interval = self.alarm.ticks_from_ms(self.timing as u32);
163 self.alarm.set_alarm(self.alarm.now(), interval);
164 }
165
166 fn col_set(&self, l: &L) {
167 match self.col_activation {
168 ActivationMode::ActiveHigh => l.set(),
169 ActivationMode::ActiveLow => l.clear(),
170 }
171 }
172
173 fn col_clear(&self, l: &L) {
174 match self.col_activation {
175 ActivationMode::ActiveHigh => l.clear(),
176 ActivationMode::ActiveLow => l.set(),
177 }
178 }
179
180 fn row_set(&self, l: &L) {
181 match self.row_activation {
182 ActivationMode::ActiveHigh => l.set(),
183 ActivationMode::ActiveLow => l.clear(),
184 }
185 }
186
187 fn row_clear(&self, l: &L) {
188 match self.row_activation {
189 ActivationMode::ActiveHigh => l.clear(),
190 ActivationMode::ActiveLow => l.set(),
191 }
192 }
193
194 pub fn on(&self, col: usize, row: usize) -> Result<(), ErrorCode> {
195 self.on_index(row * self.rows.len() + col)
196 }
197
198 fn on_index(&self, led_index: usize) -> Result<(), ErrorCode> {
199 if led_index < self.rows.len() * self.cols.len() {
200 self.buffer
201 .map(|bits| bits[led_index / 8] |= 1 << (led_index % 8));
202 Ok(())
203 } else {
204 Err(ErrorCode::INVAL)
205 }
206 }
207
208 pub fn off(&self, col: usize, row: usize) -> Result<(), ErrorCode> {
209 self.off_index(row * self.rows.len() + col)
210 }
211
212 fn off_index(&self, led_index: usize) -> Result<(), ErrorCode> {
213 if led_index < self.rows.len() * self.cols.len() {
214 self.buffer
215 .map(|bits| bits[led_index / 8] &= !(1 << (led_index % 8)));
216 Ok(())
217 } else {
218 Err(ErrorCode::INVAL)
219 }
220 }
221
222 pub fn toggle(&self, col: usize, row: usize) -> Result<(), ErrorCode> {
223 self.toggle_index(row * self.rows.len() + col)
224 }
225
226 fn toggle_index(&self, led_index: usize) -> Result<(), ErrorCode> {
227 if led_index < self.rows.len() * self.cols.len() {
228 self.buffer
229 .map(|bits| bits[led_index / 8] ^= 1 << (led_index % 8));
230 Ok(())
231 } else {
232 Err(ErrorCode::INVAL)
233 }
234 }
235
236 fn read(&self, col: usize, row: usize) -> Result<bool, ErrorCode> {
237 if row < self.rows.len() && col < self.cols.len() {
238 let pos = row * self.rows.len() + col;
239 self.buffer.map_or(Err(ErrorCode::FAIL), |bits| {
240 match bits[pos / 8] & (1 << (pos % 8)) {
241 0 => Ok(false),
242 _ => Ok(true),
243 }
244 })
245 } else {
246 Err(ErrorCode::INVAL)
247 }
248 }
249}
250
251impl<'a, L: Pin, A: Alarm<'a>> AlarmClient for LedMatrixDriver<'a, L, A> {
252 fn alarm(&self) {
253 self.next_row();
254 }
255}
256
257pub struct LedMatrixLed<'a, L: Pin, A: Alarm<'a>> {
259 matrix: &'a LedMatrixDriver<'a, L, A>,
260 row: usize,
261 col: usize,
262}
263
264impl<'a, L: Pin, A: Alarm<'a>> LedMatrixLed<'a, L, A> {
265 pub fn new(matrix: &'a LedMatrixDriver<'a, L, A>, col: usize, row: usize) -> Self {
266 if col >= matrix.cols_len() || row >= matrix.rows_len() {
267 panic!("LED at position ({}, {}) does not exist", col, row);
268 }
269 LedMatrixLed { matrix, row, col }
270 }
271}
272
273impl<'a, L: Pin, A: Alarm<'a>> Led for LedMatrixLed<'a, L, A> {
274 fn init(&self) {}
275
276 fn on(&self) {
277 let _ = self.matrix.on(self.col, self.row);
278 }
279
280 fn off(&self) {
281 let _ = self.matrix.off(self.col, self.row);
282 }
283
284 fn toggle(&self) {
285 let _ = self.matrix.toggle(self.col, self.row);
286 }
287
288 fn read(&self) -> bool {
289 self.matrix.read(self.col, self.row).unwrap_or(false)
290 }
291}