1use crate::{command::*, consts::*};
4use display_interface::{DisplayError, WriteOnlyDataCommand};
5
6pub struct ST7567S<DI, MODE> {
19 pub(crate) mode: MODE,
20 pub(crate) display_interface: DI,
21}
22
23pub struct DirectWriteMode;
25
26pub struct BufferedMode {
28 buffer: [u8; BUFFER_SIZE],
29}
30
31impl BufferedMode {
32 pub(crate) fn new() -> Self {
33 BufferedMode {
34 buffer: [0; BUFFER_SIZE],
35 }
36 }
37}
38
39impl<DI: WriteOnlyDataCommand> ST7567S<DI, DirectWriteMode> {
40 pub fn new(display_interface: DI) -> Self {
45 ST7567S {
46 mode: DirectWriteMode,
47 display_interface,
48 }
49 }
50
51 pub fn into_buffered_graphics_mode(self) -> ST7567S<DI, BufferedMode> {
53 ST7567S {
54 mode: BufferedMode::new(),
55 display_interface: self.display_interface,
56 }
57 }
58}
59
60impl<DI: WriteOnlyDataCommand> ST7567S<DI, BufferedMode> {
61 pub fn clear(&mut self) {
63 self.mode.buffer = [0; BUFFER_SIZE];
64 }
65
66 pub fn set_pixel(&mut self, x: u8, y: u8, value: bool) -> Result<(), DisplayError> {
70 if x >= DISPLAY_WIDTH || y >= DISPLAY_HEIGHT {
71 return Err(DisplayError::OutOfBoundsError);
72 }
73
74 let column: usize = x as usize;
75 let page: usize = (y / 8) as usize;
76 let page_bit = y % 8;
77
78 let byte_idx = page * (DISPLAY_WIDTH as usize) + column;
79 let byte = self.mode.buffer[byte_idx];
80 let bit_value: u8 = value.into();
81 let byte = byte & !(1 << page_bit) | (bit_value << page_bit);
82
83 self.mode.buffer[byte_idx] = byte;
84
85 Ok(())
86 }
87
88 pub fn flush(&mut self) -> Result<(), DisplayError> {
90 Self::flush_buffer_chunks(
91 &mut self.display_interface,
92 self.mode.buffer.as_slice(),
93 (0, 0),
94 (DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1),
95 )
96 }
97}
98
99impl<DI: WriteOnlyDataCommand, MODE> ST7567S<DI, MODE> {
100 pub fn init(&mut self) -> Result<(), DisplayError> {
102 SetBiasCommand::Bias1_9.write(&mut self.display_interface)?;
103 SetSEGDirectionCommand::Normal.write(&mut self.display_interface)?;
104 SetCOMDirectionCommand::Reverse.write(&mut self.display_interface)?;
105 SetRegulationResistorRatioCommand::Ratio5_0.write(&mut self.display_interface)?;
106 SetElectronicVolumeCommand::new(40)
107 .unwrap()
108 .write(&mut self.display_interface)?;
109 SetPowerControlCommand::BoosterOn.write(&mut self.display_interface)?;
110 SetPowerControlCommand::VoltageRegulatorOn.write(&mut self.display_interface)?;
111 SetPowerControlCommand::VoltageFollowerOn.write(&mut self.display_interface)?;
112 SetStartLineCommand::new(0)
113 .unwrap()
114 .write(&mut self.display_interface)?;
115
116 self.draw([0; BUFFER_SIZE].as_slice())?;
117
118 DisplayOnCommand::On.write(&mut self.display_interface)?;
119
120 Ok(())
121 }
122
123 pub fn reset(&mut self) -> Result<(), DisplayError> {
126 ResetCommand.write(&mut self.display_interface)
127 }
128
129 pub fn draw(&mut self, buffer: &[u8]) -> Result<(), DisplayError> {
133 if buffer.len() != BUFFER_SIZE {
134 return Err(DisplayError::OutOfBoundsError);
135 }
136
137 Self::flush_buffer_chunks(
138 &mut self.display_interface,
139 buffer,
140 (0, 0),
141 (DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1),
142 )
143 }
144
145 pub fn bounded_draw(
152 &mut self,
153 buffer: &[u8],
154 top_left: (u8, u8),
155 bottom_right: (u8, u8),
156 ) -> Result<(), DisplayError> {
157 Self::flush_buffer_chunks(&mut self.display_interface, buffer, top_left, bottom_right)
158 }
159
160 pub(crate) fn flush_buffer_chunks(
161 display_interface: &mut DI,
162 buffer: &[u8],
163 top_left: (u8, u8),
164 bottom_right: (u8, u8),
165 ) -> Result<(), DisplayError> {
166 if top_left.0 >= DISPLAY_WIDTH || top_left.1 >= DISPLAY_HEIGHT {
167 return Err(DisplayError::OutOfBoundsError);
168 }
169 if bottom_right.0 >= DISPLAY_WIDTH || bottom_right.1 >= DISPLAY_HEIGHT {
170 return Err(DisplayError::OutOfBoundsError);
171 }
172 if top_left.0 > bottom_right.0 || top_left.1 > bottom_right.1 {
173 return Err(DisplayError::OutOfBoundsError);
174 }
175
176 let first_page: usize = (top_left.1 / 8) as usize;
177 let first_column: usize = top_left.0 as usize;
178
179 let last_page: usize = (bottom_right.1 / 8) as usize;
180 let last_column: usize = bottom_right.0 as usize;
181
182 buffer
183 .chunks(DISPLAY_WIDTH as usize)
184 .skip(first_page)
185 .take(last_page - first_page + 1)
186 .map(|page| &page[first_column..=last_column])
187 .enumerate()
188 .try_for_each(|(page_idx, page)| {
189 SetPageAddressCommand::new(first_page as u8 + page_idx as u8)
190 .unwrap()
191 .write(display_interface)?;
192 SetColumnAddressLSNibbleCommand::new(first_column as u8)
193 .unwrap()
194 .write(display_interface)?;
195 SetColumnAddressMSNibbleCommand::new(first_column as u8)
196 .unwrap()
197 .write(display_interface)?;
198
199 display_interface.send_data(display_interface::DataFormat::U8(page))
200 })
201 }
202}