File Coverage

blib/lib/HiPi/Interface/MonoOLED.pm
Criterion Covered Total %
statement 30 245 12.2
branch 0 76 0.0
condition 0 57 0.0
subroutine 10 48 20.8
pod 0 31 0.0
total 40 457 8.7


line stmt bran cond sub pod time code
1             #########################################################################################
2             # Package HiPi::Interface::MonoOLED
3             # Description : Control Monochrome OLEDs
4             # Copyright : Copyright (c) 2018 Mark Dootson
5             # License : This is free software; you can redistribute it and/or modify it under
6             # the same terms as the Perl 5 programming language system itself.
7             #########################################################################################
8              
9             package HiPi::Interface::MonoOLED;
10              
11             #########################################################################################
12 1     1   1417 use utf8;
  1         3  
  1         9  
13 1     1   80 use strict;
  1         3  
  1         27  
14 1     1   7 use warnings;
  1         3  
  1         47  
15 1     1   7 use parent qw( HiPi::Interface );
  1         2  
  1         7  
16 1     1   69 use HiPi qw( :i2c :rpi :spi :oled );
  1         3  
  1         512  
17 1     1   8 use Carp;
  1         2  
  1         71  
18 1     1   7 use HiPi::Graphics::BitmapFont;
  1         3  
  1         39  
19 1     1   7 use HiPi::Graphics::DrawingContext;
  1         1  
  1         30  
20 1     1   446 use HiPi::Interface::MonoOLED::DisplayBuffer;
  1         3  
  1         127  
21              
22             __PACKAGE__->create_ro_accessors( qw(
23             backend spidriver rows cols col_offset
24             reset_pin dc_pin external_power flipped type controller
25             chunk_data buffer_rows
26             ) );
27              
28             __PACKAGE__->create_accessors( qw( context gpio ) );
29              
30             our $VERSION ='0.80';
31              
32             use constant {
33 1         3190 CONTROL_CONTINUE => 0x80,
34             CONTROL_COMMAND => 0x00,
35             CONTROL_DATA => 0x40,
36            
37             TYPE_CONTROL_SSD1306 => 0x01,
38             TYPE_CONTROL_SH1106 => 0x02,
39             TYPE_COLUMNS_128 => 0x04,
40             TYPE_ROWS_64 => 0x08,
41             TYPE_ROWS_32 => 0x10,
42             TYPE_BUS_I2C => 0x20,
43             TYPE_BUS_SPI => 0x40,
44            
45             OLED_SETCONTRAST => 0x81,
46             OLED_DISPLAYALLON_RESUME => 0xA4,
47             OLED_DISPLAYALLON => 0xA5,
48             OLED_NORMALDISPLAY => 0xA6,
49             OLED_INVERTDISPLAY => 0xA7,
50             OLED_DISPLAYOFF => 0xAE,
51             OLED_DISPLAYON => 0xAF,
52              
53             OLED_SETDISPLAYOFFSET => 0xD3,
54             OLED_SETCOMPINS => 0xDA,
55              
56             OLED_SETVCOMDETECT => 0xDB,
57              
58             OLED_SETDISPLAYCLOCKDIV => 0xD5,
59             OLED_SETPRECHARGE => 0xD9,
60              
61             OLED_SETMULTIPLEX => 0xA8,
62              
63             OLED_SETSTARTLINE => 0x40,
64              
65             SSD1306_MEMORYMODE => 0x20,
66             SSD1306_COLUMNADDR => 0x21,
67            
68             SH1106_SETLOWCOLUMN => 0x00,
69             SH1106_SETHIGHCOLUMN => 0x10,
70            
71             SSD1306_PAGEADDR => 0x22,
72             SH1106_PAGEADDR => 0xB0,
73              
74             OLED_COMSCANINC => 0xC0,
75             OLED_COMSCANDEC => 0xC8,
76              
77             OLED_SEGREMAP => 0xA0,
78              
79             OLED_CHARGEPUMP => 0x8D,
80              
81             OLED_EXTERNALVCC => 0x1,
82             OLED_SWITCHCAPVCC => 0x2,
83            
84             SSD1306_ACTIVATE_SCROLL => 0x2F,
85             SSD1306_DEACTIVATE_SCROLL => 0x2E,
86             SSD1306_SET_VERTICAL_SCROLL_AREA => 0xA3,
87             SSD1306_RIGHT_HORIZONTAL_SCROLL => 0x26,
88             SSD1306_LEFT_HORIZONTAL_SCROLL => 0x27,
89             SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL => 0x29,
90             SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL => 0x2A,
91              
92             SSD1306_MEMORY_MODE_HORIZ => 0x00,
93             SSD1306_MEMORY_MODE_VERT => 0x01,
94             SSD1306_MEMORY_MODE_PAGE => 0x02,
95 1     1   8 };
  1         2  
96              
97              
98             sub new {
99 0     0 0   my ($class, %userparams) = @_;
100            
101 0           my %params = $class->_init_params( %userparams );
102            
103 0           my $self = $class->SUPER::new(%params);
104            
105 0           $self->context(
106             HiPi::Interface::MonoOLED::DisplayBuffer->new(
107             rows => $self->buffer_rows,
108             cols => $self->cols,
109             )
110             );
111            
112 0 0 0       $self->_set_gpio if(defined($self->dc_pin) || defined($self->reset_pin) );
113            
114 0 0         if(defined($self->dc_pin)) {
115 0 0         if( $self->gpio->get_pin_mode( $self->dc_pin ) != RPI_MODE_OUTPUT ) {
116 0           $self->gpio->set_pin_mode( $self->dc_pin, RPI_MODE_OUTPUT );
117             }
118 0           $self->gpio->set_pin_level( $self->dc_pin, RPI_LOW );
119             }
120            
121 0 0         if(defined($self->reset_pin)) {
122 0 0         if( $self->gpio->get_pin_mode( $self->reset_pin ) != RPI_MODE_OUTPUT ) {
123 0           $self->gpio->set_pin_mode( $self->reset_pin, RPI_MODE_OUTPUT );
124             }
125             }
126              
127 0 0         unless( $params{'skip_reset'} ) {
128 0           $self->display_reset;
129 0 0         unless( $params{'skip_logo'} ) {
130 0           $self->draw_logo;
131 0           $self->display_update;
132             }
133             }
134            
135 0           return $self;
136             }
137              
138             sub _init_params {
139 0     0     my( $class, %inparams ) = @_;
140 0           my $pi = HiPi::RaspberryPi->new();
141            
142 0 0         my %i2cparams = (
143             devicename => ( $pi->board_type == RPI_BOARD_TYPE_1 ) ? '/dev/i2c-0' : '/dev/i2c-1',
144             address => 0x3C,
145             device => undef,
146             reset_pin => undef,
147             chunk_data => 1,
148             );
149            
150 0           my %spiparams = (
151             devicename => '/dev/spidev0.0',
152             speed => SPI_SPEED_MHZ_1,
153             bitsperword => 8,
154             delay => 0,
155             device => undef,
156             reset_pin => undef,
157             dc_pin => undef,
158             );
159            
160 0   0       $inparams{type} //= SSD1306_128_X_64_I2C;
161 0           my $controltype = $inparams{type};
162            
163             # defaults
164 0           my %params = (
165             device => undef,
166             backend => 'i2c',
167             cols => 128,
168             rows => 64,
169             buffer_rows => 64,
170             col_offset => 0,
171             type => SSD1306_128_X_64_I2C,
172             controller => TYPE_CONTROL_SSD1306,
173             );
174            
175 0 0         $params{backend} = ( $controltype & TYPE_BUS_SPI ) ? 'spi' : 'i2c';
176             # $params{cols} = only support 128 type currently
177            
178 0 0         if( $controltype & TYPE_CONTROL_SH1106 ) {
179 0           $params{col_offset} = 2;
180 0           $params{controller} = TYPE_CONTROL_SH1106;
181             }
182            
183 0 0         $params{buffer_rows} = $params{rows} = ( $controltype & TYPE_ROWS_32 ) ? 32 : 64;
184            
185             # get user params
186 0           foreach my $key( keys (%inparams) ) {
187 0           $params{$key} = $inparams{$key};
188             }
189            
190             # fix any daft row figures
191 0 0         if( $params{rows} !~ /^32|64$/ ) {
192 0           $params{rows} = 64;
193             }
194 0 0         if( $params{buffer_rows} !~ /^32|64$/ ) {
195 0           $params{buffer_rows} = $params{rows};
196             }
197             # get backend params
198 0 0         if( $params{backend} eq 'spi' ) {
199 0           foreach my $key( keys %spiparams ) {
200 0   0       $params{$key} //= $spiparams{$key};
201             }
202             } else {
203 0           foreach my $key( keys %i2cparams ) {
204 0   0       $params{$key} //= $i2cparams{$key};
205             # set chunk_data for smbus / bcm2835
206 0 0         if($params{backend} eq 'i2c') {
207 0   0       $params{chunk_data} //= 0;
208             } else {
209 0   0       $params{chunk_data} //= 1;
210             }
211             }
212             }
213            
214 0 0         unless( defined($params{device}) ) {
215 0 0         if ( $params{backend} eq 'bcm2835' ) {
    0          
216 0           require HiPi::BCM2835::I2C;
217             $params{device} = HiPi::BCM2835::I2C->new(
218             address => $params{address},
219 0 0         peripheral => ( $params{devicename} eq '/dev/i2c-0' ) ? HiPi::BCM2835::I2C::BB_I2C_PERI_0() : HiPi::BCM2835::I2C::BB_I2C_PERI_1(),
220             );
221             } elsif( $params{backend} eq 'spi' ) {
222 0           require HiPi::Device::SPI;
223             $params{device} = HiPi::Device::SPI->new(
224             speed => $params{speed},
225             bitsperword => $params{bitsperword},
226             delay => $params{delay},
227             devicename => $params{devicename},
228 0           );
229             } else {
230 0           require HiPi::Device::I2C;
231             $params{device} = HiPi::Device::I2C->new(
232             devicename => $params{devicename},
233             address => $params{address},
234             busmode => $params{backend},
235 0           );
236             }
237             }
238            
239 0 0         $params{spidriver} = $params{device}->isa('HiPi::Device::SPI') ? 1 : 0;
240            
241 0           return %params;
242             }
243              
244             sub display_reset {
245 0     0 0   my $self = shift;
246            
247 0 0         if(defined($self->reset_pin)) {
248 0           $self->gpio->set_pin_level($self->reset_pin, RPI_LOW );
249 0           $self->delayMicroseconds(1000);
250 0           $self->gpio->set_pin_level($self->reset_pin, RPI_HIGH );
251 0           $self->delayMicroseconds(1000);
252             }
253            
254 0           $self->send_command(OLED_DISPLAYOFF);
255 0           $self->send_command(OLED_SETDISPLAYCLOCKDIV, 0x80);
256 0           $self->send_command(OLED_SETMULTIPLEX, $self->rows -1);
257 0           $self->send_command(OLED_SETDISPLAYOFFSET, 0x00);
258 0           $self->send_command(OLED_SETSTARTLINE | 0x0);
259 0 0         if ( $self->external_power ) {
260 0           $self->send_command(OLED_CHARGEPUMP, 0x10);
261             } else {
262 0           $self->send_command(OLED_CHARGEPUMP, 0x14);
263             }
264            
265 0 0         if( $self->controller == TYPE_CONTROL_SSD1306 ) {
266 0           $self->send_command( SSD1306_MEMORYMODE, SSD1306_MEMORY_MODE_HORIZ );
267             }
268            
269 0           $self->display_flip($self->flipped);
270            
271 0 0         if( $self->rows == 64 ) {
272 0           $self->send_command(OLED_SETCOMPINS, 0x12);
273             } else {
274 0           $self->send_command(OLED_SETCOMPINS, 0x02);
275             }
276            
277 0           $self->send_command(OLED_SETCONTRAST, 0x7f);
278            
279 0 0         if ( $self->external_power ) {
280 0           $self->send_command(OLED_SETPRECHARGE, 0x22);
281             } else {
282 0           $self->send_command(OLED_SETPRECHARGE, 0xF1);
283             }
284            
285 0           $self->send_command(OLED_SETVCOMDETECT, 0x40);
286 0           $self->send_command(OLED_DISPLAYALLON_RESUME);
287 0           $self->send_command(OLED_NORMALDISPLAY);
288 0 0         if( $self->controller == TYPE_CONTROL_SSD1306 ) {
289 0           $self->send_command(SSD1306_DEACTIVATE_SCROLL);
290             }
291 0           $self->clear_buffer;
292 0           $self->display_update;
293 0           $self->send_command(OLED_DISPLAYON);
294            
295 0           return;
296             }
297              
298             sub _set_gpio {
299 0     0     my $self = shift;
300 0 0 0       unless( defined( $self->gpio ) && $self->gpio->isa('HiPi::GPIO') ) {
301 0           require HiPi::GPIO;
302 0           $self->gpio( HiPi::GPIO->new );
303             }
304             }
305              
306             sub send_command {
307 0     0 0   my($self, @bytes) = @_;
308 0 0         if( $self->spidriver ) {
309 0           $self->_spi_send_command( @bytes );
310             } else {
311 0           $self->_i2c_send_command( @bytes );
312             }
313             }
314              
315             sub send_data {
316 0     0 0   my($self, @bytes) = @_;
317 0 0         if( $self->spidriver ) {
318 0           $self->_spi_send_data( @bytes );
319             } else {
320 0           $self->_i2c_send_data( @bytes );
321             }
322             }
323              
324             sub _spi_send_command {
325 0     0     my($self, @commands) = @_;
326 0           $self->gpio->set_pin_level( $self->dc_pin, RPI_LOW );
327 0           $self->delayMicroseconds(10);
328 0           $self->device->transfer( pack('C*', @commands ) );
329 0           return;
330             }
331              
332             sub _spi_send_data {
333 0     0     my($self, @data) = @_;
334 0           $self->gpio->set_pin_level( $self->dc_pin, RPI_HIGH );
335 0           $self->delayMicroseconds(10);
336 0           $self->device->transfer( pack('C*', @data ) );
337 0           return;
338             }
339              
340             sub _i2c_send_command {
341 0     0     my($self, @bytes) = @_;
342 0           my $bytecount = scalar @bytes;
343 0 0         return unless $bytecount;
344            
345 0           for ( my $i = 0; $i < $bytecount; $i ++ ) {
346 0           $self->device->bus_write( CONTROL_COMMAND, $bytes[$i] );
347             }
348             }
349              
350             sub _i2c_send_data {
351 0     0     my($self, @bytes) = @_;
352            
353             # set chunk size based on backend
354 0 0         my $chunksize = ( $self->chunk_data ) ? 16 : 0;
355              
356 0 0         if( $chunksize ) {
357            
358 0           my $numbytes = scalar @bytes;
359 0           my $chunks = int( $numbytes / $chunksize );
360 0           my $leftover = ( $numbytes % $chunksize );
361            
362 0           for (my $chunk = 0; $chunk < $chunks; $chunk ++ ) {
363 0           my $start = $chunk * $chunksize;
364 0           my $end = $start + $chunksize - 1;
365 0           $self->device->bus_write( CONTROL_DATA, @bytes[$start..$end] );
366             }
367            
368 0 0         if($leftover){
369 0           my $start = $chunks * $chunksize;
370 0           my $end = $start + $leftover - 1;
371 0           $self->device->bus_write( CONTROL_DATA, @bytes[$start..$end] );
372             }
373             } else {
374             # send it all at once
375 0           $self->device->bus_write( CONTROL_DATA, @bytes );
376             }
377            
378 0           return;
379             }
380              
381             sub clear_buffer {
382 0     0 0   my $self = shift;
383 0           $self->context->clear_buffer(0);
384             }
385              
386             sub fill_buffer {
387 0     0 0   my $self = shift;
388 0           $self->context->clear_buffer(0xFF);
389             }
390              
391             sub invert_display {
392 0     0 0   my $self = shift;
393 0           $self->send_command(OLED_INVERTDISPLAY);
394             }
395              
396             sub normal_display {
397 0     0 0   my $self = shift;
398 0           $self->send_command(OLED_NORMALDISPLAY);
399             }
400              
401             sub display_off {
402 0     0 0   my $self = shift;
403 0           $self->send_command(OLED_DISPLAYOFF);
404             }
405              
406             sub display_on {
407 0     0 0   my $self = shift;
408 0           $self->send_command(OLED_DISPLAYON);
409             }
410              
411             sub set_contrast {
412 0     0 0   my ($self, $contrast) = @_;
413 0           $self->send_command(OLED_SETCONTRAST, $contrast & 0xFF );
414             }
415              
416             sub set_start_line {
417 0     0 0   my($self, $line) = @_;
418 0 0 0       if( $line >= 0 && $line < $self->buffer_rows ) {
419 0           $self->send_command(OLED_SETSTARTLINE | $line);
420             }
421 0           return;
422             }
423              
424             sub create_context {
425 0     0 0   return HiPi::Graphics::DrawingContext->new;
426             }
427              
428             sub display_update {
429 0     0 0   my( $self ) = @_;
430 0           $self->block_update(0,0, $self->cols -1, $self->buffer_rows - 1);
431 0           return;
432             }
433              
434             sub block_update {
435 0     0 0   my ( $self, $x1, $y1, $x2, $y2 ) = @_;
436 0 0 0       if(
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
437             $x1 < 0 || $x1 >= $self->cols
438             || $x2 < 0 || $x2 >= $self->cols
439             || $y1 < 0 || $y1 >= $self->buffer_rows
440             || $y2 < 0 || $y2 >= $self->buffer_rows
441             || $y1 > $y2 || $x1 > $x2) {
442            
443 0           carp qq(block update parameters outside display bounds : $x1, $y1, $x2, $y2);
444 0           return;
445             }
446            
447 0           my $page_start = $y1 >> 3;
448 0           my $page_end = $y2 >> 3;
449 0           my $pagebytes = $self->cols;
450 0           my $colstart = $self->col_offset + $x1;
451 0           my $colend = $self->col_offset + $x2;
452 0           for (my $page = $page_start; $page <= $page_end; $page ++) {
453 0           $self->_set_ready_for_update( $page, $page, $colstart, $colend);
454 0           my $start = ($page * $pagebytes) + $x1;
455 0           my $end = $start + ( $x2 - $x1 );
456 0           $self->send_data( @{ $self->context->buffer }[$start..$end] );
  0            
457 0 0 0       if( $self->buffer_rows == 32 && $self->rows == 32 ) {
458             # repeat whole buffer
459 0           $self->_set_ready_for_update( $page + 4, $page + 4, $colstart, $colend);
460 0           $self->send_data( @{ $self->context->buffer }[$start..$end] );
  0            
461             }
462             }
463 0           return;
464             }
465              
466             sub _set_ready_for_update {
467 0     0     my($self, $page_start, $page_end, $col_start, $col_end ) = @_;
468 0 0         if( $self->controller == TYPE_CONTROL_SH1106 ) {
469 0           my $col_low = $col_start & 0x0F;
470 0           my $col_high = ($col_start >> 4) & 0x1F;
471 0           $self->send_command(SH1106_SETLOWCOLUMN | $col_low );
472 0           $self->send_command(SH1106_SETHIGHCOLUMN | $col_high );
473 0           $self->send_command(SH1106_PAGEADDR | $page_start );
474             } else {
475 0           $self->send_command(SSD1306_COLUMNADDR, $col_start, $col_end );
476 0           $self->send_command(SSD1306_PAGEADDR, $page_start, $page_end);
477             }
478 0           return;
479             }
480              
481             sub display_flip {
482 0     0 0   my($self, $flipped) = @_;
483 0   0       $flipped ||= 0;
484 0 0         if ( $flipped ) {
485 0           $self->send_command(OLED_SEGREMAP | 0x00);
486 0           $self->send_command(OLED_COMSCANINC);
487            
488             } else {
489 0           $self->send_command(OLED_SEGREMAP | 0x01);
490 0           $self->send_command(OLED_COMSCANDEC);
491             }
492 0           return;
493             }
494              
495             sub draw_logo {
496 0     0 0   my ($self, $x, $y) = @_;
497 0   0       $x ||= 0;
498 0   0       $y ||= 0;
499 0           my $raspberry = $self->get_logo;
500 0           $self->draw_rectangle( $x, $y, $x+127, $y+31);
501 0           $self->draw_text( $x+14, $y+4, 'Raspberry Pi', 'Sans12');
502 0           $self->draw_text( $x+37, $y+17, 'HiPi Perl','Sans12');
503 0           my $text = 'HiPi ' . $HiPi::VERSION;
504 0           $self->draw_text(22,40, $text, 'Sans20');
505 0           $self->draw_bit_array( $x+96, $y+4, $raspberry, 0 );
506             }
507              
508             sub get_logo {
509 0     0 0   my $raspberry = [
510             [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
511             [ 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0 ],
512             [ 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 ],
513             [ 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0 ],
514             [ 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0 ],
515            
516             [ 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 ],
517             [ 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0 ],
518             [ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ],
519             [ 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0 ],
520             [ 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0 ],
521            
522             [ 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0 ],
523             [ 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0 ],
524             [ 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0 ],
525             [ 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0 ],
526             [ 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0 ],
527            
528             [ 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0 ],
529             [ 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0 ],
530             [ 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0 ],
531             [ 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 ],
532             [ 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0 ],
533            
534             [ 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 ],
535             [ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 ],
536             [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
537             ];
538            
539 0           return $raspberry;
540             }
541              
542             #---------------------------------------------------
543             # Context Interface
544             #---------------------------------------------------
545              
546 0     0 0   sub invert_pen { shift->context->invert_pen( @_ ); }
547              
548 0     0 0   sub draw_context { shift->context->draw_context( @_ ); }
549              
550 0     0 0   sub draw_pixel { shift->context->draw_pixel( @_ ); }
551              
552 0     0 0   sub draw_text { shift->context->draw_text( @_ ); }
553              
554 0     0 0   sub get_text_extents { shift->context->get_text_extents( @_ ); }
555              
556 0     0 0   sub draw_circle { shift->context->draw_circle( @_ ); }
557              
558 0     0 0   sub draw_ellipse { shift->context->draw_ellipse( @_ ); }
559              
560 0     0 0   sub draw_arc { shift->context->draw_arc( @_ ); }
561              
562 0     0 0   sub draw_rectangle { shift->context->draw_rectangle( @_ ); }
563              
564 0     0 0   sub draw_rounded_rectangle { shift->context->draw_rounded_rectangle( @_ ); }
565              
566 0     0 0   sub draw_line { shift->context->draw_line( @_ ); }
567              
568 0     0 0   sub draw_polygon { shift->context->draw_polygon( @_ ); }
569              
570 0     0 0   sub draw_bit_array { shift->context->draw_bit_array( @_ ); }
571              
572             #---------------------------------------------------
573             # Command Aliases
574             #---------------------------------------------------
575              
576             *HiPi::Interface::MonoOLED::update_display = \&display_update;
577              
578             1;
579              
580             __END__