| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
######################################################################################### |
|
2
|
|
|
|
|
|
|
# Package HiPi::Interface::EPaper |
|
3
|
|
|
|
|
|
|
# Description : Control Monochrome EPaper displays |
|
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::DisplayBuffer; |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
######################################################################################### |
|
12
|
|
|
|
|
|
|
|
|
13
|
1
|
|
|
1
|
|
9
|
use strict; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
35
|
|
|
14
|
1
|
|
|
1
|
|
8
|
use warnings; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
32
|
|
|
15
|
1
|
|
|
1
|
|
5
|
use parent qw( HiPi::Graphics::DrawingContext ); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
5
|
|
|
16
|
1
|
|
|
1
|
|
108
|
use Carp; |
|
|
1
|
|
|
|
|
9
|
|
|
|
1
|
|
|
|
|
71
|
|
|
17
|
1
|
|
|
1
|
|
8
|
use HiPi qw( :epaper ); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
194
|
|
|
18
|
1
|
|
|
1
|
|
7
|
use Try::Tiny; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
1236
|
|
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
__PACKAGE__->create_ro_accessors( qw( |
|
21
|
|
|
|
|
|
|
device_height device_width buffers buffer_bytes |
|
22
|
|
|
|
|
|
|
frame_1_bpp frame_2_bpp |
|
23
|
|
|
|
|
|
|
frame_1_type frame_2_type |
|
24
|
|
|
|
|
|
|
frame_invert |
|
25
|
|
|
|
|
|
|
invert_draw offsetx |
|
26
|
|
|
|
|
|
|
colour_frame black_frame |
|
27
|
|
|
|
|
|
|
) ); |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
__PACKAGE__->create_accessors( qw( pen rotation ) ); |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
our $VERSION ='0.81'; |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
sub new { |
|
34
|
0
|
|
|
0
|
0
|
|
my( $class, %params) = @_; |
|
35
|
0
|
|
0
|
|
|
|
$params{pen} //= EPD_BLACK_PEN; |
|
36
|
0
|
|
0
|
|
|
|
$params{rotation} //= EPD_BLACK_PEN; |
|
37
|
0
|
|
|
|
|
|
$params{frame_invert} = [ $params{frame_1_invert}, $params{frame_2_invert} ]; |
|
38
|
0
|
|
|
|
|
|
my $bytecount = $params{device_height} * ( $params{device_width} + $params{offsetx} ); |
|
39
|
0
|
|
|
|
|
|
$bytecount >>= 3; |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
|
|
42
|
0
|
|
|
|
|
|
$params{buffers} = [ [], [] ]; |
|
43
|
|
|
|
|
|
|
|
|
44
|
0
|
0
|
|
|
|
|
if( $params{frame_1_type} != EPD_FRAME_TYPE_UNUSED ) { |
|
45
|
0
|
0
|
|
|
|
|
my $mask = ( $params{frame_1_invert} ) ? 0 : 0xFF; |
|
46
|
0
|
|
|
|
|
|
my @data = ( $mask ) x $bytecount; |
|
47
|
0
|
|
|
|
|
|
$params{buffers}->[0] = \@data; |
|
48
|
|
|
|
|
|
|
} |
|
49
|
|
|
|
|
|
|
|
|
50
|
0
|
0
|
|
|
|
|
if( $params{frame_2_type} != EPD_FRAME_TYPE_UNUSED ) { |
|
51
|
0
|
0
|
|
|
|
|
my $mask = ( $params{frame_2_invert} ) ? 0 : 0xFF; |
|
52
|
0
|
|
|
|
|
|
my @data = ( $mask ) x $bytecount; |
|
53
|
0
|
|
|
|
|
|
$params{buffers}->[1] = \@data; |
|
54
|
|
|
|
|
|
|
} |
|
55
|
|
|
|
|
|
|
|
|
56
|
0
|
|
|
|
|
|
$params{buffer_bytes} = $bytecount; |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
# colour frame & black frame |
|
59
|
0
|
|
|
|
|
|
$params{black_frame} = 0; |
|
60
|
0
|
|
|
|
|
|
$params{colour_frame} = 0; |
|
61
|
|
|
|
|
|
|
|
|
62
|
0
|
0
|
|
|
|
|
if( $params{frame_1_type} == EPD_FRAME_TYPE_COLOUR ) { |
|
|
|
0
|
|
|
|
|
|
|
63
|
0
|
|
|
|
|
|
$params{colour_frame} = 1; |
|
64
|
|
|
|
|
|
|
} elsif($params{frame_2_type} == EPD_FRAME_TYPE_COLOUR ) { |
|
65
|
0
|
|
|
|
|
|
$params{colour_frame} = 2; |
|
66
|
|
|
|
|
|
|
} |
|
67
|
|
|
|
|
|
|
|
|
68
|
0
|
0
|
|
|
|
|
if( $params{frame_1_type} == EPD_FRAME_TYPE_BLACK ) { |
|
|
|
0
|
|
|
|
|
|
|
69
|
0
|
|
|
|
|
|
$params{black_frame} = 1; |
|
70
|
|
|
|
|
|
|
} elsif($params{frame_2_type} == EPD_FRAME_TYPE_BLACK ) { |
|
71
|
0
|
|
|
|
|
|
$params{black_frame} = 2; |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
|
|
74
|
0
|
|
0
|
|
|
|
$params{colour_frame} ||= $params{black_frame}; |
|
75
|
|
|
|
|
|
|
|
|
76
|
0
|
|
|
|
|
|
my $self = $class->SUPER::new( %params ); |
|
77
|
0
|
|
|
|
|
|
return $self; |
|
78
|
|
|
|
|
|
|
} |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
sub clear_buffer { |
|
81
|
0
|
|
|
0
|
0
|
|
my ($self, $frame) = @_; |
|
82
|
|
|
|
|
|
|
|
|
83
|
0
|
0
|
|
|
|
|
if( $frame ) { |
|
84
|
0
|
0
|
|
|
|
|
my $mask = ( $self->frame_invert->[$frame] ) ? 0 : 0xFF; |
|
85
|
0
|
|
|
|
|
|
for (my $i = 0; $i < @{ $self->buffers->[$frame] }; $i ++) { |
|
|
0
|
|
|
|
|
|
|
|
86
|
0
|
|
|
|
|
|
$self->buffers->[$frame]->[$i] = $mask; |
|
87
|
|
|
|
|
|
|
} |
|
88
|
|
|
|
|
|
|
} else { |
|
89
|
0
|
|
|
|
|
|
for my $frameno ( (0, 1) ) { |
|
90
|
0
|
|
|
|
|
|
my $buffer = $self->buffers->[$frameno]; |
|
91
|
0
|
0
|
|
|
|
|
my $mask = ( $self->frame_invert->[$frameno] ) ? 0 : 0xFF; |
|
92
|
0
|
|
|
|
|
|
for (my $i = 0; $i < @$buffer; $i ++) { |
|
93
|
0
|
|
|
|
|
|
$buffer->[$i] = $mask; |
|
94
|
|
|
|
|
|
|
} |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
} |
|
97
|
0
|
|
|
|
|
|
return; |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
sub draw_pixel { |
|
101
|
0
|
|
|
0
|
0
|
|
my($self, $x, $y ) = @_; |
|
102
|
|
|
|
|
|
|
|
|
103
|
0
|
|
|
|
|
|
my $frametype = 0; |
|
104
|
0
|
0
|
|
|
|
|
if( $self->pen == EPD_COLOUR_PEN ) { |
|
105
|
0
|
|
|
|
|
|
$frametype = $self->colour_frame; |
|
106
|
|
|
|
|
|
|
} else { |
|
107
|
0
|
|
|
|
|
|
$frametype = $self->black_frame; |
|
108
|
|
|
|
|
|
|
} |
|
109
|
0
|
0
|
|
|
|
|
return unless $frametype; |
|
110
|
|
|
|
|
|
|
|
|
111
|
0
|
|
|
|
|
|
my $frame = $frametype - 1; |
|
112
|
|
|
|
|
|
|
|
|
113
|
0
|
|
|
|
|
|
my $inverted = $self->frame_invert->[$frame]; |
|
114
|
|
|
|
|
|
|
|
|
115
|
0
|
|
|
|
|
|
my $maxX = $self->device_width + $self->offsetx; |
|
116
|
0
|
|
|
|
|
|
my $adjH = $self->device_height -1; |
|
117
|
0
|
|
|
|
|
|
my $adjW = $self->device_width -1; |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
# rotate and check for bounds |
|
120
|
0
|
0
|
|
|
|
|
if ($self->rotation == EPD_ROTATION_0 ) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
121
|
0
|
0
|
0
|
|
|
|
if($x < 0 || $x >= $self->device_width || $y < 0 || $y >= $self->device_height) { |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
122
|
0
|
|
|
|
|
|
return; |
|
123
|
|
|
|
|
|
|
} |
|
124
|
|
|
|
|
|
|
} elsif ($self->rotation == EPD_ROTATION_90) { |
|
125
|
0
|
0
|
0
|
|
|
|
if($x < 0 || $x >= $self->device_height || $y < 0 || $y >= $self->device_width) { |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
126
|
0
|
|
|
|
|
|
return; |
|
127
|
|
|
|
|
|
|
} |
|
128
|
0
|
|
|
|
|
|
my $swap = $x; |
|
129
|
0
|
|
|
|
|
|
$x = $adjW - $y; |
|
130
|
0
|
|
|
|
|
|
$y = $swap; |
|
131
|
|
|
|
|
|
|
} elsif ($self->rotation == EPD_ROTATION_180) { |
|
132
|
0
|
0
|
0
|
|
|
|
if($x < 0 || $x >= $self->device_width || $y < 0 || $y >= $self->device_height) { |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
133
|
0
|
|
|
|
|
|
return; |
|
134
|
|
|
|
|
|
|
} |
|
135
|
0
|
|
|
|
|
|
$x = $adjW - $x; |
|
136
|
0
|
|
|
|
|
|
$y = $adjH - $y; |
|
137
|
|
|
|
|
|
|
} elsif ($self->rotation == EPD_ROTATION_270) { |
|
138
|
0
|
0
|
0
|
|
|
|
if($x < 0 || $x >= $self->device_height || $y < 0 || $y >= $self->device_width) { |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
139
|
0
|
|
|
|
|
|
return; |
|
140
|
|
|
|
|
|
|
} |
|
141
|
0
|
|
|
|
|
|
my $swap = $x; |
|
142
|
0
|
|
|
|
|
|
$x = $y; |
|
143
|
0
|
|
|
|
|
|
$y = $adjH - $swap; |
|
144
|
|
|
|
|
|
|
} |
|
145
|
|
|
|
|
|
|
|
|
146
|
0
|
|
|
|
|
|
my $index = ($x + $y * $maxX) >> 3; |
|
147
|
0
|
|
|
|
|
|
my $shiftbits = $x % 8; |
|
148
|
0
|
|
|
|
|
|
my $buffer = $self->buffers->[$frame]; |
|
149
|
|
|
|
|
|
|
|
|
150
|
0
|
0
|
|
|
|
|
my $on = ( $self->pen ) ? 1 : 0; |
|
151
|
|
|
|
|
|
|
|
|
152
|
0
|
0
|
|
|
|
|
if($self->pen_inverted) { |
|
153
|
0
|
0
|
|
|
|
|
$on = ( $on ) ? 0 : 1; |
|
154
|
|
|
|
|
|
|
} |
|
155
|
|
|
|
|
|
|
|
|
156
|
0
|
0
|
|
|
|
|
if( $inverted ) { |
|
157
|
0
|
0
|
|
|
|
|
if ($on) { |
|
158
|
0
|
|
|
|
|
|
$buffer->[$index] |= 0x80 >> $shiftbits; |
|
159
|
|
|
|
|
|
|
} else { |
|
160
|
0
|
|
|
|
|
|
$buffer->[$index] &= ~(0x80 >> $shiftbits); |
|
161
|
|
|
|
|
|
|
} |
|
162
|
|
|
|
|
|
|
} else { |
|
163
|
0
|
0
|
|
|
|
|
if ($on) { |
|
164
|
0
|
|
|
|
|
|
$buffer->[$index] &= ~(0x80 >> $shiftbits); |
|
165
|
|
|
|
|
|
|
} else { |
|
166
|
0
|
|
|
|
|
|
$buffer->[$index] |= 0x80 >> $shiftbits; |
|
167
|
|
|
|
|
|
|
} |
|
168
|
|
|
|
|
|
|
} |
|
169
|
|
|
|
|
|
|
|
|
170
|
0
|
|
|
|
|
|
return; |
|
171
|
|
|
|
|
|
|
} |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
sub set_pen { |
|
174
|
0
|
|
|
0
|
0
|
|
my($self, $newpen) = @_; |
|
175
|
0
|
|
|
|
|
|
my $oldpen = $self->pen; |
|
176
|
0
|
|
|
|
|
|
$self->pen( $newpen ); |
|
177
|
0
|
|
|
|
|
|
return $oldpen; |
|
178
|
|
|
|
|
|
|
} |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
sub logical_width { |
|
181
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
182
|
0
|
0
|
0
|
|
|
|
if( $self->rotation == EPD_ROTATION_90 || $self->rotation == EPD_ROTATION_270 ) { |
|
183
|
0
|
|
|
|
|
|
return $self->device_height; |
|
184
|
|
|
|
|
|
|
} else { |
|
185
|
0
|
|
|
|
|
|
return $self->device_width; |
|
186
|
|
|
|
|
|
|
} |
|
187
|
|
|
|
|
|
|
} |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
sub logical_height { |
|
190
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
191
|
0
|
0
|
0
|
|
|
|
if( $self->rotation == EPD_ROTATION_90 || $self->rotation == EPD_ROTATION_270 ) { |
|
192
|
0
|
|
|
|
|
|
return $self->device_width; |
|
193
|
|
|
|
|
|
|
} else { |
|
194
|
0
|
|
|
|
|
|
return $self->device_height; |
|
195
|
|
|
|
|
|
|
} |
|
196
|
|
|
|
|
|
|
} |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
# noops for buffer contexts |
|
199
|
|
|
|
|
|
|
|
|
200
|
0
|
|
|
0
|
0
|
|
sub rotate { carp q(you cannot call 'rotate' on a display context); } |
|
201
|
|
|
|
|
|
|
|
|
202
|
0
|
|
|
0
|
0
|
|
sub rotated_text { carp q(you cannot call 'rotate_text' on a display context); } |
|
203
|
|
|
|
|
|
|
|
|
204
|
0
|
|
|
0
|
0
|
|
sub clear_context { carp q(you cannot call 'clear_context' on a display context); } |
|
205
|
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
######################################################################################### |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
package HiPi::Interface::EPaper::PartialContext; |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
######################################################################################### |
|
212
|
|
|
|
|
|
|
|
|
213
|
1
|
|
|
1
|
|
16
|
use base qw( HiPi::Interface::EPaper::DisplayBuffer ); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
276
|
|
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
sub new { |
|
216
|
0
|
|
|
0
|
|
|
my($class, %params) = @_; |
|
217
|
0
|
|
|
|
|
|
my $self = $class->SUPER::new( %params ); |
|
218
|
0
|
|
|
|
|
|
return $self; |
|
219
|
|
|
|
|
|
|
} |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
1; |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
__END__ |