1use core::cell::Cell;
15
16use crate::ssd1306::Command;
17use kernel::hil;
18use kernel::utilities::cells::{MapCell, OptionalCell, TakeCell};
19use kernel::utilities::leasable_buffer::SubSliceMut;
20use kernel::ErrorCode;
21
22pub const BUFFER_SIZE: usize = 132;
24
25const WIDTH: usize = 128;
26const HEIGHT: usize = 64;
27
28#[derive(Clone, Copy, PartialEq)]
30enum State {
31 Idle,
32 Init,
33 SimpleCommand,
34 WriteSetPage(u8),
35 WritePage(u8),
36}
37
38pub struct Sh1106<'a, I: hil::i2c::I2CDevice> {
39 i2c: &'a I,
40 state: Cell<State>,
41 client: OptionalCell<&'a dyn hil::screen::ScreenClient>,
42 setup_client: OptionalCell<&'a dyn hil::screen::ScreenSetupClient>,
43 buffer: TakeCell<'static, [u8]>,
44 write_buffer: MapCell<SubSliceMut<'static, u8>>,
45 enable_charge_pump: bool,
46
47 active_frame_x: Cell<u8>,
48 active_frame_y: Cell<u8>,
49 active_frame_width: Cell<u8>,
50 active_frame_height: Cell<u8>,
51}
52
53impl<'a, I: hil::i2c::I2CDevice> Sh1106<'a, I> {
54 pub fn new(i2c: &'a I, buffer: &'static mut [u8], enable_charge_pump: bool) -> Self {
55 Self {
56 i2c,
57 state: Cell::new(State::Idle),
58 client: OptionalCell::empty(),
59 setup_client: OptionalCell::empty(),
60 buffer: TakeCell::new(buffer),
61 write_buffer: MapCell::empty(),
62 enable_charge_pump,
63 active_frame_x: Cell::new(0),
64 active_frame_y: Cell::new(0),
65 active_frame_width: Cell::new(0),
66 active_frame_height: Cell::new(0),
67 }
68 }
69
70 pub fn init_screen(&self) {
71 let commands = [
72 Command::SetDisplayOnOff { on: false },
73 Command::SetDisplayClockDivide {
74 divide_ratio: 0,
75 oscillator_frequency: 0x8,
76 },
77 Command::SetMultiplexRatio {
78 ratio: HEIGHT as u8 - 1,
79 },
80 Command::SetDisplayOffset { vertical_shift: 0 },
81 Command::SetDisplayStartLine { line: 0 },
82 Command::SetChargePump {
83 enable: self.enable_charge_pump,
84 },
85 Command::SetMemoryAddressingMode { mode: 0 }, Command::SetSegmentRemap { reverse: true },
87 Command::SetComScanDirection { decrement: true },
88 Command::SetComPins {
89 alternative: true,
90 enable_com: false,
91 },
92 Command::SetContrast { contrast: 0xcf },
93 Command::SetPrechargePeriod {
94 phase1: 0x1,
95 phase2: 0xf,
96 },
97 Command::SetVcomDeselect { level: 2 },
98 Command::EntireDisplayOn { ignore_ram: false },
99 Command::SetDisplayInvert { inverse: false },
100 Command::DeactivateScroll,
101 Command::SetDisplayOnOff { on: true },
102 ];
103
104 match self.send_sequence(&commands) {
105 Ok(()) => {
106 self.state.set(State::Init);
107 }
108 Err(_e) => {}
109 }
110 }
111
112 fn send_sequence(&self, sequence: &[Command]) -> Result<(), ErrorCode> {
113 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buffer| {
114 let mut buf_slice = SubSliceMut::new(buffer);
115
116 buf_slice[0] = 0; buf_slice.slice(1..);
121
122 for cmd in sequence.iter() {
123 cmd.encode(&mut buf_slice);
124 }
125
126 let remaining_len = buf_slice.len();
129 buf_slice.reset();
130 let tx_len = buf_slice.len() - remaining_len;
131
132 self.i2c.enable();
133 match self.i2c.write(buf_slice.take(), tx_len) {
134 Ok(()) => Ok(()),
135 Err((_e, buf)) => {
136 self.buffer.replace(buf);
137 self.i2c.disable();
138 Err(ErrorCode::INVAL)
139 }
140 }
141 })
142 }
143
144 fn write_continue(&self) -> Result<(), ErrorCode> {
145 match self.state.get() {
146 State::WriteSetPage(page_index) => {
147 self.buffer.take().map_or(Err(ErrorCode::NOMEM), |buffer| {
148 self.write_buffer.map_or(Err(ErrorCode::NOMEM), |data| {
149 let start_page_index = self.active_frame_y.get() / 8;
152 let buffer_start_index = ((page_index - start_page_index) as usize)
153 * self.active_frame_width.get() as usize;
154 let page_len = self.active_frame_width.get() as usize;
155
156 let mut buf_slice = SubSliceMut::new(buffer);
157
158 buf_slice[0] = 0x40; buf_slice.slice(1..);
164
165 for i in 0..page_len {
167 buf_slice[i] = data[buffer_start_index + i];
168 }
169
170 let tx_len = page_len + 1;
172
173 self.i2c.enable();
174 match self.i2c.write(buf_slice.take(), tx_len) {
175 Ok(()) => {
176 self.state.set(State::WritePage(page_index));
177 Ok(())
178 }
179 Err((_e, buf)) => {
180 self.buffer.replace(buf);
181 Err(ErrorCode::INVAL)
182 }
183 }
184 })
185 })
186 }
187
188 State::WritePage(page_index) => {
189 let next_page = page_index + 1;
192 let last_page = (self.active_frame_y.get() + self.active_frame_height.get()) / 8;
193
194 if next_page >= last_page {
195 self.state.set(State::Idle);
197 self.write_buffer.take().map(|buf| {
198 self.client.map(|client| client.write_complete(buf, Ok(())));
199 });
200 Ok(())
201 } else {
202 self.set_page(next_page)
204 }
205 }
206
207 _ => Err(ErrorCode::FAIL),
208 }
209 }
210
211 fn set_page(&self, page_index: u8) -> Result<(), ErrorCode> {
212 let column_start = self.active_frame_x.get() + 2;
213 let commands = [
214 Command::SetPageStartAddress {
215 address: page_index,
216 },
217 Command::SetLowerColumnStartAddress {
218 address: column_start,
219 },
220 Command::SetHigherColumnStartAddress {
221 address: column_start,
222 },
223 ];
224 match self.send_sequence(&commands) {
225 Ok(()) => {
226 self.state.set(State::WriteSetPage(page_index));
227 Ok(())
228 }
229 Err(e) => Err(e),
230 }
231 }
232}
233
234impl<'a, I: hil::i2c::I2CDevice> hil::screen::ScreenSetup<'a> for Sh1106<'a, I> {
235 fn set_client(&self, client: &'a dyn hil::screen::ScreenSetupClient) {
236 self.setup_client.set(client);
237 }
238
239 fn set_resolution(&self, _resolution: (usize, usize)) -> Result<(), ErrorCode> {
240 Err(ErrorCode::NOSUPPORT)
241 }
242
243 fn set_pixel_format(&self, _depth: hil::screen::ScreenPixelFormat) -> Result<(), ErrorCode> {
244 Err(ErrorCode::NOSUPPORT)
245 }
246
247 fn set_rotation(&self, _rotation: hil::screen::ScreenRotation) -> Result<(), ErrorCode> {
248 Err(ErrorCode::NOSUPPORT)
249 }
250
251 fn get_num_supported_resolutions(&self) -> usize {
252 1
253 }
254
255 fn get_supported_resolution(&self, index: usize) -> Option<(usize, usize)> {
256 match index {
257 0 => Some((WIDTH, HEIGHT)),
258 _ => None,
259 }
260 }
261
262 fn get_num_supported_pixel_formats(&self) -> usize {
263 1
264 }
265
266 fn get_supported_pixel_format(&self, index: usize) -> Option<hil::screen::ScreenPixelFormat> {
267 match index {
268 0 => Some(hil::screen::ScreenPixelFormat::Mono),
269 _ => None,
270 }
271 }
272}
273
274impl<'a, I: hil::i2c::I2CDevice> hil::screen::Screen<'a> for Sh1106<'a, I> {
275 fn set_client(&self, client: &'a dyn hil::screen::ScreenClient) {
276 self.client.set(client);
277 }
278
279 fn get_resolution(&self) -> (usize, usize) {
280 (WIDTH, HEIGHT)
281 }
282
283 fn get_pixel_format(&self) -> hil::screen::ScreenPixelFormat {
284 hil::screen::ScreenPixelFormat::Mono
285 }
286
287 fn get_rotation(&self) -> hil::screen::ScreenRotation {
288 hil::screen::ScreenRotation::Normal
289 }
290
291 fn set_write_frame(
292 &self,
293 x: usize,
294 y: usize,
295 width: usize,
296 height: usize,
297 ) -> Result<(), ErrorCode> {
298 self.active_frame_x.set(x as u8);
300 self.active_frame_y.set(y as u8);
301 self.active_frame_width.set(width as u8);
302 self.active_frame_height.set(height as u8);
303
304 let column_start: u8 = (x as u8) + 2;
307 let commands = [
308 Command::SetPageStartAddress {
309 address: (y / 8) as u8,
310 },
311 Command::SetLowerColumnStartAddress {
312 address: column_start,
313 },
314 Command::SetHigherColumnStartAddress {
315 address: column_start,
316 },
317 ];
318 match self.send_sequence(&commands) {
319 Ok(()) => {
320 self.state.set(State::SimpleCommand);
321 Ok(())
322 }
323 Err(e) => Err(e),
324 }
325 }
326
327 fn write(&self, data: SubSliceMut<'static, u8>, _continue: bool) -> Result<(), ErrorCode> {
328 self.write_buffer.replace(data);
329
330 self.set_page(self.active_frame_y.get() / 8)
332 }
333
334 fn set_brightness(&self, brightness: u16) -> Result<(), ErrorCode> {
335 let commands = [Command::SetContrast {
336 contrast: (brightness >> 8) as u8,
337 }];
338 match self.send_sequence(&commands) {
339 Ok(()) => {
340 self.state.set(State::SimpleCommand);
341 Ok(())
342 }
343 Err(e) => Err(e),
344 }
345 }
346
347 fn set_power(&self, enabled: bool) -> Result<(), ErrorCode> {
348 let commands = [Command::SetDisplayOnOff { on: enabled }];
349 match self.send_sequence(&commands) {
350 Ok(()) => {
351 self.state.set(State::SimpleCommand);
352 Ok(())
353 }
354 Err(e) => Err(e),
355 }
356 }
357
358 fn set_invert(&self, enabled: bool) -> Result<(), ErrorCode> {
359 let commands = [Command::SetDisplayInvert { inverse: enabled }];
360 match self.send_sequence(&commands) {
361 Ok(()) => {
362 self.state.set(State::SimpleCommand);
363 Ok(())
364 }
365 Err(e) => Err(e),
366 }
367 }
368}
369
370impl<I: hil::i2c::I2CDevice> hil::i2c::I2CClient for Sh1106<'_, I> {
371 fn command_complete(&self, buffer: &'static mut [u8], _status: Result<(), hil::i2c::Error>) {
372 self.buffer.replace(buffer);
373 self.i2c.disable();
374
375 match self.state.get() {
376 State::Init => {
377 self.state.set(State::Idle);
378 self.client.map(|client| client.screen_is_ready());
379 }
380
381 State::SimpleCommand => {
382 self.state.set(State::Idle);
383 self.client.map(|client| client.command_complete(Ok(())));
384 }
385
386 State::WritePage(_) | State::WriteSetPage(_) => {
387 let _ = self.write_continue();
388 }
389 _ => {}
390 }
391 }
392}