@@ -27,6 +27,7 @@ use crate::displayrotation::DisplayRotation;
27
27
use crate :: displaysize:: DisplaySize ;
28
28
use crate :: interface:: DisplayInterface ;
29
29
use crate :: mode:: displaymode:: DisplayModeTrait ;
30
+ use crate :: mode:: terminal:: TerminalModeError :: { InterfaceError , OutOfBounds , Uninitialized } ;
30
31
use crate :: properties:: DisplayProperties ;
31
32
use crate :: Error ;
32
33
use core:: cmp:: min;
@@ -94,6 +95,36 @@ impl Cursor {
94
95
}
95
96
}
96
97
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
+
97
128
// TODO: Add to prelude
98
129
/// Terminal mode handler
99
130
pub struct TerminalMode < DI > {
@@ -124,7 +155,7 @@ where
124
155
DI : DisplayInterface ,
125
156
{
126
157
/// 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 > > {
128
159
let display_size = self . properties . get_size ( ) ;
129
160
130
161
let numchars = match display_size {
@@ -134,17 +165,20 @@ where
134
165
} ;
135
166
136
167
// 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 ( ) ?;
138
171
let ( display_width, display_height) = self . properties . get_dimensions ( ) ;
139
172
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 ( ) ?;
141
175
142
176
for _ in 0 ..numchars {
143
- self . properties . draw ( & [ 0 ; 8 ] ) ?;
177
+ self . properties . draw ( & [ 0 ; 8 ] ) . terminal_err ( ) ?;
144
178
}
145
179
146
180
// 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 ( ) ?;
148
182
self . reset_pos ( ) ?;
149
183
150
184
Ok ( ( ) )
@@ -156,9 +190,9 @@ where
156
190
rst : & mut RST ,
157
191
delay : & mut DELAY ,
158
192
) -> 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 > ,
162
196
{
163
197
rst. set_high ( ) . map_err ( Error :: Pin ) ?;
164
198
delay. delay_ms ( 1 ) ;
@@ -168,26 +202,28 @@ where
168
202
}
169
203
170
204
/// 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 > > {
172
206
Ok ( ( ) )
173
207
}
174
208
175
209
/// 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 > > {
177
211
match c {
178
212
'\n' => {
179
213
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 ( ) ?;
182
216
}
183
217
'\r' => {
184
- self . properties . set_column ( 0 ) ?;
218
+ self . properties . set_column ( 0 ) . terminal_err ( ) ?;
185
219
let ( _, cur_line) = self . ensure_cursor ( ) ?. get_position ( ) ;
186
220
self . ensure_cursor ( ) ?. set_position ( 0 , cur_line) ;
187
221
}
188
222
_ => {
189
223
// 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 ( ) ?;
191
227
// Increment character counter and potentially wrap line
192
228
self . advance_cursor ( ) ?;
193
229
}
@@ -199,49 +235,54 @@ where
199
235
/// Initialise the display in page mode (i.e. a byte walks down a column of 8 pixels) with
200
236
/// column 0 on the left and column _(display_width - 1)_ on the right, but no automatic line
201
237
/// 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 ( ) ?;
204
242
self . reset_pos ( ) ?;
205
243
Ok ( ( ) )
206
244
}
207
245
208
246
/// 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 > > {
210
248
// 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 ( )
212
250
}
213
251
214
252
/// Turn the display on or off. The display can be drawn to and retains all
215
253
/// 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 ( )
218
256
}
219
257
220
258
/// Get the current cursor position, in character coordinates.
221
259
/// 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 )
224
265
}
225
266
226
267
/// Set the cursor position, in character coordinates.
227
268
/// This is the (column, row) that the next character will be written to.
228
269
/// 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 > > {
230
271
let ( width, height) = self . ensure_cursor ( ) ?. get_dimensions ( ) ;
231
272
if column >= width || row >= height {
232
- Err ( ( ) )
273
+ Err ( OutOfBounds )
233
274
} 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 ( ) ?;
236
277
self . ensure_cursor ( ) ?. set_position ( column, row) ;
237
278
Ok ( ( ) )
238
279
}
239
280
}
240
281
241
282
/// 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 ( ) ?;
245
286
// Initialise the counter when we know it's valid
246
287
let ( display_width, display_height) = self . properties . get_dimensions ( ) ;
247
288
self . cursor = Some ( Cursor :: new ( display_width, display_height) ) ;
@@ -251,15 +292,15 @@ where
251
292
252
293
/// Advance the cursor, automatically wrapping lines and/or screens if necessary
253
294
/// 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 > > {
255
296
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 ( ) ?;
257
298
}
258
299
Ok ( ( ) )
259
300
}
260
301
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 )
263
304
}
264
305
265
306
fn char_to_bitmap ( input : char ) -> [ u8 ; 8 ] {
0 commit comments