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__ |