File Coverage

blib/lib/HiPi/Interface/EPaper.pm
Criterion Covered Total %
statement 24 175 13.7
branch 0 38 0.0
condition 0 18 0.0
subroutine 8 49 16.3
pod 0 39 0.0
total 32 319 10.0


line stmt bran cond sub pod time code
1             #########################################################################################
2             # Package HiPi::Interface::EPaper
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::EPaper;
10              
11             #########################################################################################
12 1     1   1049 use strict;
  1         2  
  1         29  
13 1     1   5 use warnings;
  1         2  
  1         26  
14 1     1   4 use parent qw( HiPi::Interface );
  1         3  
  1         6  
15 1     1   56 use HiPi qw( :rpi :spi :epaper );
  1         2  
  1         425  
16 1     1   8 use Carp;
  1         2  
  1         82  
17 1     1   8 use UNIVERSAL::require;
  1         3  
  1         12  
18 1     1   564 use HiPi::Graphics::DrawingContext;
  1         2  
  1         46  
19 1     1   512 use HiPi::Interface::EPaper::DisplayBuffer;
  1         3  
  1         2405  
20              
21             __PACKAGE__->create_ro_accessors( qw(
22             device_width device_height offsetx type rotation
23             frame_1_bpp frame_2_bpp
24             frame_1_type frame_2_type
25             dc_pin reset_pin busy_pin gpio
26             lut_vcom0 lut_vcom1 lut_w lut_b lut_g1 lut_g2 lut_red0 lut_red1
27             lut_full lut_partial
28             can_partial busy_state
29             frame_1_invert frame_2_invert
30             spi_chunksize
31             _in_deep_sleep is_tri_colour
32             border_control
33             ) );
34              
35             __PACKAGE__->create_accessors( qw( context lut_state ) );
36              
37             our $VERSION ='0.81';
38              
39             sub new {
40 0     0 0   my ($class, %userparams) = @_;
41            
42 0           my %params = (
43             devicename => '/dev/spidev0.0',
44             speed => SPI_SPEED_MHZ_1,
45             bitsperword => 8,
46             delay => 0,
47             device => undef,
48             reset_pin => undef,
49             dc_pin => undef,
50             busy_pin => undef,
51             type => undef,
52             gpio => undef,
53             device_width => undef,
54             device_height => undef,
55             rotation => undef,
56             can_partial => 0,
57             lut_state => EPD_UPD_MODE_FIXED,
58             invert_draw => 0,
59             busy_state => RPI_LOW,
60             offsetx => 0,
61             spi_chunksize => 4096,
62            
63             );
64            
65             # get user params
66 0           foreach my $key( keys (%userparams) ) {
67 0           $params{$key} = $userparams{$key};
68             }
69            
70 0           my $epaperclass;
71            
72 0 0         croak q(No valid 'type' parameter given) unless $params{type};
73            
74 0 0         if( $params{type} == EPD_WS_1_54_152_X_152_C ) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
75 0           $epaperclass = 'HiPi::Interface::EPaper::Waveshare::EPD152X152';
76            
77             } elsif( $params{type} == EPD_WS_1_54_200_X_200_B ) {
78 0           $epaperclass = 'HiPi::Interface::EPaper::Waveshare::EPD200X200B';
79            
80             } elsif( $params{type} == EPD_WS_1_54_200_X_200_A) {
81 0           $epaperclass = 'HiPi::Interface::EPaper::Waveshare::EPD200X200';
82            
83             } elsif( $params{type} == EPD_WS_2_13_250_X_122_A ) {
84 0           $epaperclass = 'HiPi::Interface::EPaper::Waveshare::EPD250X122';
85            
86             } elsif( $params{type} == EPD_WS_2_13_212_X_104_B ) {
87 0           $epaperclass = 'HiPi::Interface::EPaper::Waveshare::EPD212X104';
88            
89             } elsif( $params{type} == EPD_WS_2_90_296_X_128_A ) {
90 0           $epaperclass = 'HiPi::Interface::EPaper::Waveshare::EPD296X128';
91            
92             } elsif( $params{type} == EPD_WS_2_90_296_X_128_B ) {
93 0           $epaperclass = 'HiPi::Interface::EPaper::Waveshare::EPD296X128B';
94            
95             } elsif( $params{type} == EPD_PIMORONI_INKY_PHAT_V2 ) {
96 0           $epaperclass = 'HiPi::Interface::EPaper::Pimoroni::EPDInkyPHAT_V2';
97             } else {
98 0           croak q(No valid 'type' parameter given);
99             }
100            
101 0 0         $epaperclass->use or die $@;
102            
103 0           my $self = $epaperclass->_create( %params );
104            
105 0           $self->context(
106             HiPi::Interface::EPaper::DisplayBuffer->new(
107             device_width => $self->device_width,
108             device_height => $self->device_height,
109             rotation => $self->rotation,
110             frame_1_bpp => $self->frame_1_bpp,
111             frame_2_bpp => $self->frame_2_bpp,
112             frame_1_type => $self->frame_1_type,
113             frame_2_type => $self->frame_2_type,
114             frame_1_invert => $self->frame_1_invert,
115             frame_2_invert => $self->frame_2_invert,
116             offsetx => $self->offsetx,
117             )
118             );
119            
120 0 0         unless( $params{'skip_reset'} ) {
121 0           $self->display_reset;
122             #if( $params{'draw_logo'} ) {
123             # $self->draw_logo;
124             # $self->display_update;
125             #}
126             }
127            
128 0           return $self;
129             }
130              
131             sub _create {
132 0     0     my( $class, %params ) = @_;
133            
134 0 0         unless(defined($params{device})) {
135 0           require HiPi::Device::SPI;
136             $params{device} = HiPi::Device::SPI->new(
137             speed => $params{speed},
138             bitsperword => $params{bitsperword},
139             delay => $params{delay},
140             devicename => $params{devicename},
141 0           );
142             }
143            
144 0 0         unless(defined($params{gpio})) {
145 0           require HiPi::GPIO;
146 0           $params{gpio} = HiPi::GPIO->new
147             }
148            
149 0           my $self = $class->SUPER::new( %params );
150            
151             # init the GPIO settings;
152            
153 0           $self->gpio->set_pin_mode( $self->reset_pin, RPI_MODE_OUTPUT);
154 0           $self->gpio->set_pin_mode( $self->dc_pin, RPI_MODE_OUTPUT);
155 0           $self->gpio->set_pin_mode( $self->busy_pin, RPI_MODE_INPUT);
156            
157 0           return $self;
158             }
159              
160             sub reset {
161 0     0 0   my $self = shift;
162 0           $self->gpio->set_pin_level( $self->reset_pin, RPI_LOW);
163 0           $self->delay( 200 );
164 0           $self->gpio->set_pin_level( $self->reset_pin, RPI_HIGH);
165 0           $self->delay( 200 );
166             }
167              
168             sub send_command {
169 0     0 0   my( $self, $command, @data ) = @_;
170 0           $self->gpio->set_pin_level( $self->dc_pin, RPI_LOW);
171 0           $self->delayMicroseconds(10);
172 0           $self->device->transfer( pack('C*', ( $command ) ) );
173 0 0         if( @data ) {
174 0           $self->send_data( @data );
175             }
176 0           return;
177             }
178              
179             sub send_data {
180 0     0 0   my($self, @data) = @_;
181 0           $self->gpio->set_pin_level( $self->dc_pin, RPI_HIGH );
182 0           $self->delayMicroseconds(10);
183 0           $self->device->transfer( pack('C*', @data ) );
184 0           return;
185             }
186              
187             sub wait_for_idle {
188 0     0 0   my $self = shift;
189 0           while( $self->gpio->get_pin_level( $self->busy_pin ) == $self->busy_state ) {
190 0           $self->delay(100);
191             }
192 0           return;
193             }
194              
195             sub logical_width {
196 0     0 0   my $self = shift;
197 0 0 0       if( $self->rotation == EPD_ROTATION_90 || $self->rotation == EPD_ROTATION_270 ) {
198 0           return $self->device_height;
199             } else {
200 0           return $self->device_width;
201             }
202             }
203              
204             sub logical_height {
205 0     0 0   my $self = shift;
206 0 0 0       if( $self->rotation == EPD_ROTATION_90 || $self->rotation == EPD_ROTATION_270 ) {
207 0           return $self->device_width;
208             } else {
209 0           return $self->device_height;
210             }
211             }
212              
213             #----------------------------------------------------
214             # Common Type Methods
215             #----------------------------------------------------
216              
217             sub display_reset {
218 0     0 0   my $self = shift;
219 0           carp 'display_reset not supported in this class';
220             }
221              
222             sub display_update {
223 0     0 0   my $self = shift;
224 0           carp 'display_update not supported in this class';
225             }
226              
227             #----------------------------------------------------
228             # Waveshare 2 & 3 col non partial methods
229             #----------------------------------------------------
230              
231             sub set_lut_bw {
232 0     0 0   my $self = shift;
233 0           carp 'set_lut_bw not supported in this class';
234             }
235              
236             sub set_lut_colour {
237 0     0 0   my $self = shift;
238 0           carp 'set_lut_colour not supported in this class';
239             }
240              
241             #----------------------------------------------------
242             # Waveshare Partial Update Methods
243             #----------------------------------------------------
244              
245             sub create_partial_context {
246 0     0 0   my $self = shift;
247 0           carp 'create_partial_context not supported in this class';
248             }
249              
250             sub display_frame {
251 0     0 0   my $self = shift;
252 0           carp 'display_frame not supported in this class';
253             }
254              
255             sub display_sleep {
256 0     0 0   my $self = shift;
257 0           carp 'display_sleep not supported in this class';
258             }
259              
260             sub display_partial_update {
261 0     0 0   my $self = shift;
262 0           carp 'display_partial_update not supported in this class';
263             }
264              
265             sub get_partial_coordinates {
266 0     0 0   my $self = shift;
267 0           carp 'get_partial_coordinates not supported in this class';
268             }
269              
270             sub set_frame_memory {
271 0     0 0   my $self = shift;
272 0           carp 'set_frame_memory not supported in this class';
273             }
274              
275             sub set_lut_full {
276 0     0 0   my $self = shift;
277 0           carp 'set_lut_full not supported in this class';
278             }
279              
280             sub set_lut_partial {
281 0     0 0   my $self = shift;
282 0           carp 'set_lut_partial not supported in this class';
283             }
284              
285             sub set_memory_area {
286 0     0 0   my $self = shift;
287 0           carp 'set_memory_area not supported in this class';
288             }
289              
290             sub set_memory_pointer {
291 0     0 0   my $self = shift;
292 0           carp 'set_memory_pointer not supported in this class';
293             }
294              
295             sub set_update_mode {
296 0     0 0   my $self = shift;
297 0           carp 'set_update_mode not supported in this class';
298             }
299              
300             sub _send_command_if_data {
301 0     0     my($self, $command, $data ) = @_;
302 0 0 0       if( $data && ref($data) eq 'ARRAY' && @$data ) {
      0        
303 0           $self->send_command( $command, @$data );
304             }
305             }
306              
307             #----------------------------------------------------
308             # This class methods
309             #----------------------------------------------------
310              
311             sub clear_buffer {
312 0     0 0   my $self = shift;
313 0           $self->context->clear_buffer;
314             }
315              
316             sub set_pen {
317 0     0 0   my($self, $newpen) = @_;
318 0           my $oldpen = $self->context->pen;
319 0           $self->context->pen( $newpen );
320 0           return $oldpen;
321             }
322              
323             sub draw_logo {
324 0     0 0   my $self = shift;
325            
326 0           my $maxW = $self->logical_width;
327 0           my $maxH = $self->logical_height;
328            
329             # get the sizes for text
330 0           my $toptext = 'Raspberry Pi';
331 0           my $topfont = 'SansEPD102';
332 0           my $bottext = 'HiPi ' . $HiPi::VERSION;
333 0           my $botfont = 'SansEPD102';
334 0           my $maxtextheight = int($maxH / 2) - 15;
335 0           my $maxtextwidth = $maxW - 15;
336 0           for my $size ( qw( 102 76 50 38 31 28 23 19 15) ) {
337 0           $topfont = 'SansEPD' . $size;
338 0           my($tw, $th) = $self->get_text_extents( $toptext, $topfont );
339 0 0 0       last if $tw <= $maxtextwidth && $th <= $maxtextheight;
340             }
341 0           for my $size ( qw( 102 76 50 38 31 28 23 19 15) ) {
342 0           $botfont = 'SansEPD' . $size;
343 0           my($tw, $th) = $self->get_text_extents( $bottext, $botfont );
344 0 0 0       last if $tw <= $maxtextwidth - 20 && $th <= $maxtextheight;
345             }
346            
347 0           my $restorepen = $self->set_pen( EPD_BLACK_PEN );
348 0           my($w, $h) = $self->get_text_extents( $toptext, $topfont );
349 0           my $x = int( 0.5 + ($maxW - $w) / 2);
350             # for $y we want the middle of the top half of the screen
351 0           my $y = int( 0.5 + (($maxH / 2 ) - $h) / 2);
352 0           $self->draw_text($x,$y, $toptext, $topfont);
353            
354 0           $self->set_pen( EPD_COLOUR_PEN );
355            
356 0           my $rectx = $maxW - 1;
357 0           my $recty = int(0.5 + $maxH / 2);
358            
359 0           for (my $i = 0; $i < 3; $i ++) {
360 0           $self->draw_rectangle(0 + $i, 0 + $i , $rectx - $i, $recty - $i);
361             }
362            
363 0           $self->draw_rectangle(0,$recty + 1, $maxW -1, $maxH -1, 1);
364            
365 0           ($w, $h) = $self->get_text_extents( $bottext, $botfont);
366 0           $x = int( 0.5 + ($maxW - $w) / 2);
367 0           $y = int( $recty + 1 + ($recty - $h) / 2);
368 0           $self->invert_pen(1);
369 0           $self->draw_text($x, $y, $bottext, $botfont);
370 0           $self->invert_pen(0);
371            
372 0           $self->set_pen( $restorepen );
373             }
374              
375             sub create_context {
376 0     0 0   return HiPi::Graphics::DrawingContext->new;
377             }
378              
379             #---------------------------------------------------
380             # Context Interface
381             #---------------------------------------------------
382              
383              
384 0     0 0   sub invert_pen { shift->context->invert_pen( @_ ); }
385              
386 0     0 0   sub draw_context { shift->context->draw_context( @_ ); }
387              
388 0     0 0   sub draw_pixel { shift->context->draw_pixel( @_ ); }
389              
390 0     0 0   sub draw_text { shift->context->draw_text( @_ ); }
391              
392 0     0 0   sub get_text_extents { shift->context->get_text_extents( @_ ); }
393              
394 0     0 0   sub draw_circle { shift->context->draw_circle( @_ ); }
395              
396 0     0 0   sub draw_ellipse { shift->context->draw_ellipse( @_ ); }
397              
398 0     0 0   sub draw_arc { shift->context->draw_arc( @_ ); }
399              
400 0     0 0   sub draw_rectangle { shift->context->draw_rectangle( @_ ); }
401              
402 0     0 0   sub draw_rounded_rectangle { shift->context->draw_rounded_rectangle( @_ ); }
403              
404 0     0 0   sub draw_line { shift->context->draw_line( @_ ); }
405              
406 0     0 0   sub draw_polygon { shift->context->draw_polygon( @_ ); }
407              
408 0     0 0   sub draw_bit_array { shift->context->draw_bit_array( @_ ); }
409              
410              
411             1;
412              
413             __END__