Skip to content

Commit 324cd95

Browse files
committed
Tweak result types and introduce new error enum for TerminalMode
1 parent 26a5aa4 commit 324cd95

File tree

2 files changed

+79
-38
lines changed

2 files changed

+79
-38
lines changed

src/mode/terminal.rs

Lines changed: 74 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use crate::displayrotation::DisplayRotation;
2727
use crate::displaysize::DisplaySize;
2828
use crate::interface::DisplayInterface;
2929
use crate::mode::displaymode::DisplayModeTrait;
30+
use crate::mode::terminal::TerminalModeError::{InterfaceError, OutOfBounds, Uninitialized};
3031
use crate::properties::DisplayProperties;
3132
use crate::Error;
3233
use core::cmp::min;
@@ -94,6 +95,36 @@ impl Cursor {
9495
}
9596
}
9697

98+
/// Errors which can occur when interacting with the terminal mode
99+
pub enum TerminalModeError<DI>
100+
where
101+
DI: DisplayInterface,
102+
{
103+
/// An error occurred in the underlying interface layer
104+
InterfaceError(DI::Error),
105+
/// The mode was used before it was initialized
106+
Uninitialized,
107+
/// A location was specified outside the bounds of the screen
108+
OutOfBounds,
109+
}
110+
111+
// Cannot use From<_> due to coherence
112+
trait IntoTerminalModeResult<DI, T>
113+
where
114+
DI: DisplayInterface,
115+
{
116+
fn terminal_err(self) -> Result<T, TerminalModeError<DI>>;
117+
}
118+
119+
impl<DI, T> IntoTerminalModeResult<DI, T> for Result<T, DI::Error>
120+
where
121+
DI: DisplayInterface,
122+
{
123+
fn terminal_err(self) -> Result<T, TerminalModeError<DI>> {
124+
self.map_err(|err| InterfaceError(err))
125+
}
126+
}
127+
97128
// TODO: Add to prelude
98129
/// Terminal mode handler
99130
pub struct TerminalMode<DI> {
@@ -124,7 +155,7 @@ where
124155
DI: DisplayInterface,
125156
{
126157
/// Clear the display and reset the cursor to the top left corner
127-
pub fn clear(&mut self) -> Result<(), DI::Error> {
158+
pub fn clear(&mut self) -> Result<(), TerminalModeError<DI>> {
128159
let display_size = self.properties.get_size();
129160

130161
let numchars = match display_size {
@@ -134,17 +165,20 @@ where
134165
};
135166

136167
// Let the chip handle line wrapping so we can fill the screen with blanks faster
137-
self.properties.change_mode(AddrMode::Horizontal)?;
168+
self.properties
169+
.change_mode(AddrMode::Horizontal)
170+
.terminal_err()?;
138171
let (display_width, display_height) = self.properties.get_dimensions();
139172
self.properties
140-
.set_draw_area((0, 0), (display_width, display_height))?;
173+
.set_draw_area((0, 0), (display_width, display_height))
174+
.terminal_err()?;
141175

142176
for _ in 0..numchars {
143-
self.properties.draw(&[0; 8])?;
177+
self.properties.draw(&[0; 8]).terminal_err()?;
144178
}
145179

146180
// But for normal operation we manage the line wrapping
147-
self.properties.change_mode(AddrMode::Page)?;
181+
self.properties.change_mode(AddrMode::Page).terminal_err()?;
148182
self.reset_pos()?;
149183

150184
Ok(())
@@ -156,9 +190,9 @@ where
156190
rst: &mut RST,
157191
delay: &mut DELAY,
158192
) -> Result<(), Error<(), PinE>>
159-
where
160-
RST: OutputPin<Error = PinE>,
161-
DELAY: DelayMs<u8>,
193+
where
194+
RST: OutputPin<Error = PinE>,
195+
DELAY: DelayMs<u8>,
162196
{
163197
rst.set_high().map_err(Error::Pin)?;
164198
delay.delay_ms(1);
@@ -168,26 +202,28 @@ where
168202
}
169203

170204
/// Write out data to display. This is a noop in terminal mode.
171-
pub fn flush(&mut self) -> Result<(), ()> {
205+
pub fn flush(&mut self) -> Result<(), TerminalModeError<DI>> {
172206
Ok(())
173207
}
174208

175209
/// Print a character to the display
176-
pub fn print_char(&mut self, c: char) -> Result<(), DI::Error> {
210+
pub fn print_char(&mut self, c: char) -> Result<(), TerminalModeError<DI>> {
177211
match c {
178212
'\n' => {
179213
let CursorWrapEvent(new_line) = self.ensure_cursor()?.advance_line();
180-
self.properties.set_column(0)?;
181-
self.properties.set_row(new_line * 8)?;
214+
self.properties.set_column(0).terminal_err()?;
215+
self.properties.set_row(new_line * 8).terminal_err()?;
182216
}
183217
'\r' => {
184-
self.properties.set_column(0)?;
218+
self.properties.set_column(0).terminal_err()?;
185219
let (_, cur_line) = self.ensure_cursor()?.get_position();
186220
self.ensure_cursor()?.set_position(0, cur_line);
187221
}
188222
_ => {
189223
// Send the pixel data to the display
190-
self.properties.draw(&Self::char_to_bitmap(c))?;
224+
self.properties
225+
.draw(&Self::char_to_bitmap(c))
226+
.terminal_err()?;
191227
// Increment character counter and potentially wrap line
192228
self.advance_cursor()?;
193229
}
@@ -199,49 +235,54 @@ where
199235
/// Initialise the display in page mode (i.e. a byte walks down a column of 8 pixels) with
200236
/// column 0 on the left and column _(display_width - 1)_ on the right, but no automatic line
201237
/// wrapping.
202-
pub fn init(&mut self) -> Result<(), DI::Error> {
203-
self.properties.init_with_mode(AddrMode::Page)?;
238+
pub fn init(&mut self) -> Result<(), TerminalModeError<DI>> {
239+
self.properties
240+
.init_with_mode(AddrMode::Page)
241+
.terminal_err()?;
204242
self.reset_pos()?;
205243
Ok(())
206244
}
207245

208246
/// Set the display rotation
209-
pub fn set_rotation(&mut self, rot: DisplayRotation) -> Result<(), DI::Error> {
247+
pub fn set_rotation(&mut self, rot: DisplayRotation) -> Result<(), TerminalModeError<DI>> {
210248
// we don't need to touch the cursor because rotating 90º or 270º currently just flips
211-
self.properties.set_rotation(rot)
249+
self.properties.set_rotation(rot).terminal_err()
212250
}
213251

214252
/// Turn the display on or off. The display can be drawn to and retains all
215253
/// of its memory even while off.
216-
pub fn display_on(&mut self, on: bool) -> Result<(), DI::Error> {
217-
self.properties.display_on(on)
254+
pub fn display_on(&mut self, on: bool) -> Result<(), TerminalModeError<DI>> {
255+
self.properties.display_on(on).terminal_err()
218256
}
219257

220258
/// Get the current cursor position, in character coordinates.
221259
/// This is the (column, row) that the next character will be written to.
222-
pub fn get_position(&self) -> Result<(u8, u8), ()> {
223-
self.cursor.as_ref().map(|c| c.get_position()).ok_or(())
260+
pub fn get_position(&self) -> Result<(u8, u8), TerminalModeError<DI>> {
261+
self.cursor
262+
.as_ref()
263+
.map(|c| c.get_position())
264+
.ok_or(Uninitialized)
224265
}
225266

226267
/// Set the cursor position, in character coordinates.
227268
/// This is the (column, row) that the next character will be written to.
228269
/// If the position is out of bounds, an Err will be returned.
229-
pub fn set_position(&mut self, column: u8, row: u8) -> Result<(), ()> {
270+
pub fn set_position(&mut self, column: u8, row: u8) -> Result<(), TerminalModeError<DI>> {
230271
let (width, height) = self.ensure_cursor()?.get_dimensions();
231272
if column >= width || row >= height {
232-
Err(())
273+
Err(OutOfBounds)
233274
} else {
234-
self.properties.set_column(column * 8)?;
235-
self.properties.set_row(row * 8)?;
275+
self.properties.set_column(column * 8).terminal_err()?;
276+
self.properties.set_row(row * 8).terminal_err()?;
236277
self.ensure_cursor()?.set_position(column, row);
237278
Ok(())
238279
}
239280
}
240281

241282
/// Reset the draw area and move pointer to the top left corner
242-
fn reset_pos(&mut self) -> Result<(), ()> {
243-
self.properties.set_column(0)?;
244-
self.properties.set_row(0)?;
283+
fn reset_pos(&mut self) -> Result<(), TerminalModeError<DI>> {
284+
self.properties.set_column(0).terminal_err()?;
285+
self.properties.set_row(0).terminal_err()?;
245286
// Initialise the counter when we know it's valid
246287
let (display_width, display_height) = self.properties.get_dimensions();
247288
self.cursor = Some(Cursor::new(display_width, display_height));
@@ -251,15 +292,15 @@ where
251292

252293
/// Advance the cursor, automatically wrapping lines and/or screens if necessary
253294
/// Takes in an already-unwrapped cursor to avoid re-unwrapping
254-
fn advance_cursor(&mut self) -> Result<(), ()> {
295+
fn advance_cursor(&mut self) -> Result<(), TerminalModeError<DI>> {
255296
if let Some(CursorWrapEvent(new_row)) = self.ensure_cursor()?.advance() {
256-
self.properties.set_row(new_row * 8)?;
297+
self.properties.set_row(new_row * 8).terminal_err()?;
257298
}
258299
Ok(())
259300
}
260301

261-
fn ensure_cursor(&mut self) -> Result<&mut Cursor, ()> {
262-
self.cursor.as_mut().ok_or(())
302+
fn ensure_cursor(&mut self) -> Result<&mut Cursor, TerminalModeError<DI>> {
303+
self.cursor.as_mut().ok_or(Uninitialized)
263304
}
264305

265306
fn char_to_bitmap(input: char) -> [u8; 8] {

src/properties.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ where
8787
/// Only works in Horizontal or Vertical addressing mode
8888
pub fn set_draw_area(&mut self, start: (u8, u8), end: (u8, u8)) -> Result<(), DI::Error> {
8989
match self.addr_mode {
90-
AddrMode::Page => Err(()),
90+
AddrMode::Page => panic!("Device cannot be in Page mode to set draw area"),
9191
_ => {
9292
Command::ColumnAddress(start.0, end.0 - 1).send(&mut self.iface)?;
9393
Command::PageAddress(start.1.into(), (end.1 - 1).into()).send(&mut self.iface)?;
@@ -99,10 +99,10 @@ where
9999
/// Set the column address in the framebuffer of the display where any sent data should be
100100
/// drawn.
101101
/// Only works in Page addressing mode.
102-
pub fn set_column(&mut self, column: u8) -> Result<(), ()> {
102+
pub fn set_column(&mut self, column: u8) -> Result<(), DI::Error> {
103103
match self.addr_mode {
104104
AddrMode::Page => Command::ColStart(column).send(&mut self.iface),
105-
_ => Err(()),
105+
_ => panic!("Device must be in Page mode to set column"),
106106
}
107107
}
108108

@@ -111,10 +111,10 @@ where
111111
/// Note that the parameter is in pixels, but the page will be set to the start of the 8px
112112
/// row which contains the passed-in row.
113113
/// Only works in Page addressing mode.
114-
pub fn set_row(&mut self, row: u8) -> Result<(), ()> {
114+
pub fn set_row(&mut self, row: u8) -> Result<(), DI::Error> {
115115
match self.addr_mode {
116116
AddrMode::Page => Command::PageStart(row.into()).send(&mut self.iface),
117-
_ => Err(()),
117+
_ => panic!("Device must be in Page mode to set row"),
118118
}
119119
}
120120

0 commit comments

Comments
 (0)