File Coverage

blib/lib/Device/PCD8544.pm
Criterion Covered Total %
statement 105 105 100.0
branch 1 2 50.0
condition n/a
subroutine 22 22 100.0
pod 8 8 100.0
total 136 137 99.2


line stmt bran cond sub pod time code
1             # Copyright (c) 2015 Timm Murray
2             # All rights reserved.
3             #
4             # Redistribution and use in source and binary forms, with or without
5             # modification, are permitted provided that the following conditions are met:
6             #
7             # * Redistributions of source code must retain the above copyright notice,
8             # this list of conditions and the following disclaimer.
9             # * Redistributions in binary form must reproduce the above copyright
10             # notice, this list of conditions and the following disclaimer in the
11             # documentation and/or other materials provided with the distribution.
12             #
13             # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14             # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15             # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16             # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
17             # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18             # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19             # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20             # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21             # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22             # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
23             # POSSIBILITY OF SUCH DAMAGE.
24             #
25             #
26             # Some of this code is based on Adafruit Industries' Python library, which is
27             # covered by:
28             #
29             #
30             # Copyright (c) 2014 Adafruit Industries
31             # Author: Tony DiCola
32             #
33             # Permission is hereby granted, free of charge, to any person obtaining a copy
34             # of this software and associated documentation files (the "Software"), to deal
35             # in the Software without restriction, including without limitation the rights
36             # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
37             # copies of the Software, and to permit persons to whom the Software is
38             # furnished to do so, subject to the following conditions:
39             #
40             # The above copyright notice and this permission notice shall be included in
41             # all copies or substantial portions of the Software.
42             #
43             # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
44             # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
45             # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
46             # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
47             # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
48             # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
49             # THE SOFTWARE.
50             #
51             package Device::PCD8544;
52             $Device::PCD8544::VERSION = '0.0268329147520525';
53             # ABSTRACT: Driver for the PCD8544 LCD controller (aka Nokia 5110)
54 2     2   16594 use v5.14;
  2         7  
  2         127  
55 2     2   10 use warnings;
  2         2  
  2         99  
56 2     2   1022 use Moo;
  2         25945  
  2         9  
57 2     2   3325 use namespace::clean;
  2         21192  
  2         13  
58 2     2   1710 use Device::WebIO::Device::DigitalOutput;
  2         18211  
  2         55  
59 2     2   854 use Device::WebIO::Device::SPI;
  2         1560  
  2         44  
60 2     2   1864 use Time::HiRes ();
  2         2387  
  2         50  
61              
62 2     2   11 use constant DEBUG => 0;
  2         2  
  2         165  
63              
64             use constant {
65 2         199 BIAS_1_100 => 0b000,
66             BIAS_1_80 => 0b001,
67             BIAS_1_65 => 0b010,
68             BIAS_1_48 => 0b011,
69             BIAS_1_40 => 0b100,
70             BIAS_1_24 => 0b101,
71             BIAS_1_18 => 0b110,
72             BIAS_1_10 => 0b111,
73 2     2   8 };
  2         11  
74             use constant {
75 2         129 SPEED_1MHZ => 1_000_000,
76             SPEED_2MHZ => 2_000_000,
77             SPEED_4MHZ => 4_000_000,
78 2     2   9 };
  2         2  
79             use constant {
80 2         2330 POWERDOWN => 0x04,
81             ENTRYMODE => 0x02,
82             EXTENDED_INSTRUCTION => 0x01,
83             DISPLAY_BLANK => 0x00,
84             DISPLAY_NORMAL => 0x04,
85             DISPLAY_ALL_ON => 0x01,
86             DISPLAY_INVERTED => 0x05,
87             FUNCTIONSET => 0x20,
88             DISPLAY_CONTROL => 0x08,
89             SETYADDR => 0x40,
90             SETXADDR => 0x80,
91             SETTEMP => 0x04,
92             SETBIAS => 0x10,
93             SETVOP => 0x80,
94 2     2   7 };
  2         2  
95              
96             has dev => (
97             is => 'ro',
98             required => 1,
99             );
100             has speed => (
101             is => 'ro',
102             default => sub { SPEED_4MHZ },
103             );
104             has webio => (
105             is => 'ro',
106             isa => sub {
107             my ($obj) = @_;
108             if(! (
109             $obj->does( 'Device::WebIO::Device::DigitalOutput' )
110             && $obj->does( 'Device::WebIO::Device::SPI' )
111             )) {
112             die "The webio object must do the roles Device::WebIO::Device::DigitalOutput and Device::WebIO::Device::SPI\n";
113             }
114             },
115             required => 1,
116             );
117             has 'power' => (
118             is => 'ro',
119             required => 1,
120             );
121             has 'rst' => (
122             is => 'ro',
123             required => 1,
124             );
125             has 'dc' => (
126             is => 'ro',
127             required => 1,
128             );
129             has 'contrast' => (
130             is => 'rw',
131             default => sub { 0x3C },
132             trigger => sub {
133             my ($self, $val) = @_;
134             return 1 unless $self->_was_init_called;
135             $self->_send_extended_command( SETVOP | $val );
136             return 1;
137             },
138             );
139             has 'bias' => (
140             is => 'rw',
141             default => sub { BIAS_1_40 },
142             trigger => sub {
143             my ($self, $val) = @_;
144             return 1 unless $self->_was_init_called;
145             $self->_send_extended_command( SETBIAS | $val );
146             return 1;
147             },
148             );
149             has '_buffer' => (
150             is => 'rw',
151             default => sub {[]},
152             );
153             has '_was_init_called' => (
154             is => 'rw',
155             default => sub { 0 },
156             );
157              
158              
159             sub init
160             {
161 1     1 1 752 my ($self) = @_;
162 1 50       7 return 1 if $self->_was_init_called;
163 1         3 my $webio = $self->webio;
164              
165 1         32 foreach ($self->power, $self->rst, $self->dc ) {
166 3         8 $webio->set_as_output( $_ );
167 3         8 $webio->output_pin( $_, 1 );
168             }
169              
170 1         9 $webio->spi_set_speed( $self->dev, $self->speed );
171              
172 1         4 $self->reset;
173 1         4 $self->_was_init_called( 1 );
174 1         5 return 1;
175             }
176              
177             sub reset
178             {
179 2     2 1 3 my ($self) = @_;
180 2         5 my $webio = $self->webio;
181 2         5 my $power = $self->power;
182 2         4 my $rst = $self->rst;
183              
184             # Created using suggestions from 'Kuy' on Sparkfun product comments:
185             # https://www.sparkfun.com/products/10168
186             #
187 2         7 $webio->output_pin( $power, 1 );
188 2         5 $webio->output_pin( $rst, 1 );
189 2         10218 Time::HiRes::usleep( 5_000 );
190              
191 2         18 $webio->output_pin( $rst, 0 );
192 2         2243 Time::HiRes::usleep( 1_000 );
193              
194 2         14 $webio->output_pin( $rst, 1 );
195 2         10338 Time::HiRes::usleep( 5_000 );
196              
197 2         4 say "Setting bias (" . SETBIAS . " | " . $self->bias . ")" if DEBUG;
198 2         89 $self->_send_extended_command( SETBIAS | $self->bias );
199 2         4 say "Setting contrast (" . SETVOP . " | " . $self->contrast . ")" if DEBUG;
200 2         36 $self->_send_extended_command( SETVOP | $self->contrast );
201 2         3 say "Setting Y Addr (" . SETYADDR . ")" if DEBUG;
202 2         6 $self->_send_command( SETYADDR | 0x00 );
203 2         2 say "Setting X Addr (" . SETXADDR . ")" if DEBUG;
204 2         6 $self->_send_command( SETXADDR | 0x00 );
205              
206 2         10 return 1;
207             }
208              
209             sub set_image
210             {
211 2     2 1 5 my ($self, $img) = @_;
212 2         5 $self->_buffer( $img );
213 2         7 return 1;
214             }
215              
216             sub update
217             {
218 2     2 1 4 my ($self) = @_;
219 2         6 $self->_send_buffer;
220 2         4 return 1;
221             }
222              
223             sub display_blank
224             {
225 1     1 1 572 my ($self) = @_;
226 1         6 $self->_send_command( DISPLAY_CONTROL | DISPLAY_BLANK );
227 1         6 return 1;
228             }
229              
230             sub display_normal
231             {
232 1     1 1 3 my ($self) = @_;
233 1         3 $self->_send_command( DISPLAY_CONTROL | DISPLAY_NORMAL );
234 1         4 return 1;
235             }
236              
237             sub display_all_on
238             {
239 1     1 1 3 my ($self) = @_;
240 1         9 $self->_send_command( DISPLAY_CONTROL | DISPLAY_ALL_ON );
241 1         4 return 1;
242             }
243              
244             sub display_inverse
245             {
246 1     1 1 2 my ($self) = @_;
247 1         5 $self->_send_command( DISPLAY_CONTROL | DISPLAY_INVERTED );
248 1         5 return 1;
249             }
250              
251             sub _send_command
252             {
253 36     36   37 my ($self, $cmd) = @_;
254 36         40 say "Sending command $cmd" if DEBUG;
255              
256 36         172 my $webio = $self->webio;
257 36         86 $webio->output_pin( $self->dc, 0 );
258              
259 36         122 my $fmt_cmd = pack 'n', $cmd;
260 36         82 $webio->spi_write( $self->dev, $fmt_cmd );
261              
262 36         75 return 1;
263             }
264              
265             sub _send_extended_command
266             {
267 6     6   983 my ($self, $cmd) = @_;
268 6         7 say "Sending extended command $cmd {" if DEBUG;
269 6         14 $self->_send_command( FUNCTIONSET | EXTENDED_INSTRUCTION );
270 6         8 $self->_send_command( $cmd );
271 6         9 $self->_send_command( FUNCTIONSET );
272 6         13 $self->_send_command( DISPLAY_CONTROL | DISPLAY_NORMAL );
273 6         7 say "}" if DEBUG;
274 6         4 return 1;
275             }
276              
277             sub _send_buffer
278             {
279 2     2   4 my ($self) = @_;
280 2         5 my $buffer = $self->_buffer;
281 2         6 my $webio = $self->webio;
282              
283 2         5 $self->_send_command( SETYADDR | 0x00 );
284 2         5 $self->_send_command( SETXADDR | 0x00 );
285              
286 2         5 $webio->output_pin( $self->dc, 1 );
287              
288 2         20 my $fmt_buf = pack 'C*', @$buffer;
289 2         6 $webio->spi_write( $self->dev, $fmt_buf );
290              
291 2         5 return 1;
292             }
293              
294              
295             1;
296             __END__