File Coverage

blib/lib/Device/MatrixOrbital/GLK.pm
Criterion Covered Total %
statement 18 183 9.8
branch 0 138 0.0
condition 0 6 0.0
subroutine 6 33 18.1
pod 23 25 92.0
total 47 385 12.2


line stmt bran cond sub pod time code
1             package Device::MatrixOrbital::GLK;
2              
3             ################
4             #
5             # Perl module for controling the Matrix Orbital graphic LCD displays
6             #
7             # Nicholas J Humfrey
8             # njh@cpan.org
9             #
10              
11 1     1   47523 use Device::SerialPort;
  1         41475  
  1         70  
12 1     1   1197 use Params::Util qw(_SCALAR _POSINT);
  1         6156  
  1         98  
13 1     1   1163 use Time::HiRes qw(sleep alarm);
  1         1974  
  1         5  
14 1     1   199 use strict;
  1         1  
  1         25  
15 1     1   5 use Carp;
  1         2  
  1         66  
16              
17 1     1   5 use vars qw/$VERSION @ISA/;
  1         2  
  1         2365  
18             @ISA = "Device::SerialPort";
19             $VERSION="0.01";
20              
21              
22              
23             sub new {
24 0     0 1   my $class = shift;
25 0   0       my $port = shift || '/dev/ttyS0';
26 0   0       my $baudrate = shift || 19200;
27 0           my $lcd_type = shift;
28            
29              
30             # Create self using super class
31 0 0         my $self = $class->SUPER::new( $port )
32             or die "Failed to create SerialPort object: $!";
33            
34             # Configure the Serial Port
35 0 0         $self->baudrate($baudrate) || die ("Failed to set baud rate");
36 0 0         $self->parity("none") || die ("Failed to set parity");
37 0 0         $self->databits(8) || die ("Failed to set data bits");
38 0 0         $self->stopbits(1) || die ("Failed to set stop bits");
39 0 0         $self->handshake("none") || die ("Failed to disable handshaking");
40 0 0         $self->write_settings || die ("Failed to write settings");
41              
42             # Check for features
43 0 0         die "status isn't available for serial port: $port"
44             unless ($self->can_status());
45 0 0         die "write_done isn't available for serial port: $port"
46             unless ($self->can_write_done());
47            
48             # Set a serial timeout default of 5 seconds
49 0           $self->{'timeout'} = 5;
50              
51              
52             # Check LCD type
53 0 0         if (defined $lcd_type) {
54 0           $self->{'lcd_type'} = $lcd_type;
55             } else {
56 0           $self->{'lcd_type'} = $self->get_lcd_type();
57             }
58            
59 0           return $self;
60             }
61              
62              
63              
64             sub backlight_on {
65 0     0 1   my $self = shift;
66 0   0       my $min = $_[0] || 0;
67 0           $self->send_command( 0x42, $min );
68             }
69              
70             sub backlight_off {
71 0     0 1   my $self = shift;
72 0           $self->send_command( 0x46 );
73             }
74              
75             sub cursor_home {
76 0     0 1   my $self = shift;
77 0           $self->send_command( 0x48 );
78             }
79              
80             sub set_contrast {
81 0     0 1   my $self = shift;
82 0           my ($value) = @_;
83 0           $self->send_command( 0x50, $value );
84             }
85              
86             sub set_and_save_contrast {
87 0     0 1   my $self = shift;
88 0           my ($value) = @_;
89 0           $self->send_command( 0x91, $value );
90             }
91              
92             sub set_brightness {
93 0     0 1   my $self = shift;
94 0           my ($value) = @_;
95 0           $self->send_command( 0x99, $value );
96             }
97              
98             sub set_and_save_brightness {
99 0     0 1   my $self = shift;
100 0           my ($value) = @_;
101 0           $self->send_command( 0x98, $value );
102             }
103              
104             sub set_autoscroll_on {
105 0     0 1   my $self = shift;
106 0           $self->send_command( 0x51 );
107             }
108              
109             sub set_autoscroll_off {
110 0     0 1   my $self = shift;
111 0           $self->send_command( 0x52 );
112             }
113              
114              
115             sub set_drawing_color {
116 0     0 1   my $self = shift;
117 0           my ($color) = @_;
118 0           $self->send_command( 0x63, $color );
119             }
120              
121             sub clear_screen {
122 0     0 1   my $self = shift;
123 0           $self->send_command( 0x58 );
124             }
125              
126             sub draw_bitmap {
127 0     0 1   my $self = shift;
128 0           my ($refid, $x, $y) = @_;
129 0           $self->send_command( 0x62, $refid, $x, $y );
130             }
131              
132             sub draw_pixel {
133 0     0 1   my $self = shift;
134 0           my ($x, $y) = @_;
135 0           $self->send_command( 0x70, $x, $y );
136             }
137              
138             sub draw_line {
139 0     0 1   my $self = shift;
140 0           my ($x1, $y1, $x2, $y2) = @_;
141 0           $self->send_command( 0x6C, $x1, $y1, $x2, $y2 );
142             }
143              
144             sub draw_line_continue {
145 0     0 1   my $self = shift;
146 0           my ($x, $y) = @_;
147 0           $self->send_command( 0x65, $x, $y );
148             }
149              
150             sub draw_rect {
151 0     0 1   my $self = shift;
152 0           my ($colour, $x1, $y1, $x2, $y2) = @_;
153 0           $self->send_command( 0x72, $colour, $x1, $y1, $x2, $y2 );
154             }
155              
156             sub draw_solid_rect {
157 0     0 1   my $self = shift;
158 0           my ($colour, $x1, $y1, $x2, $y2) = @_;
159 0           $self->send_command( 0x78, $colour, $x1, $y1, $x2, $y2 );
160             }
161              
162             sub get_lcd_type {
163 0     0 1   my $self = shift;
164 0 0         unless (defined $self->{'lcd_type'}) {
165 0           $self->send_command( 0x37 );
166              
167 0           my $value = $self->getchar();
168 0 0         unless (defined $value) {
169 0           warn "Failed to read single byte from LCD screen";
170 0           return undef;
171             }
172            
173 0 0         if ($value==0x01) { $self->{'lcd_type'}='LCD0821' }
  0 0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
174 0           elsif ($value==0x02) { $self->{'lcd_type'}='LCD2021' }
175 0           elsif ($value==0x05) { $self->{'lcd_type'}='LCD2041' }
176 0           elsif ($value==0x06) { $self->{'lcd_type'}='LCD4021' }
177 0           elsif ($value==0x07) { $self->{'lcd_type'}='LCD4041' }
178 0           elsif ($value==0x08) { $self->{'lcd_type'}='LK202-25' }
179 0           elsif ($value==0x09) { $self->{'lcd_type'}='LK204-25' }
180 0           elsif ($value==0x0A) { $self->{'lcd_type'}='LK404-55' }
181 0           elsif ($value==0x0B) { $self->{'lcd_type'}='VFD2021' }
182 0           elsif ($value==0x0C) { $self->{'lcd_type'}='VFD2041' }
183 0           elsif ($value==0x0D) { $self->{'lcd_type'}='VFD4021' }
184 0           elsif ($value==0x0E) { $self->{'lcd_type'}='VK202-25' }
185 0           elsif ($value==0x0F) { $self->{'lcd_type'}='VK204-25' }
186 0           elsif ($value==0x10) { $self->{'lcd_type'}='GLC12232' }
187 0           elsif ($value==0x13) { $self->{'lcd_type'}='GLC24064' }
188 0           elsif ($value==0x15) { $self->{'lcd_type'}='GLK24064-25' }
189 0           elsif ($value==0x22) { $self->{'lcd_type'}='GLK12232-25-WBL' }
190 0           elsif ($value==0x24) { $self->{'lcd_type'}='GLK12232-25-SM' }
191 0           elsif ($value==0x31) { $self->{'lcd_type'}='LK404-AT' }
192 0           elsif ($value==0x32) { $self->{'lcd_type'}='MOS-AV-162A' }
193 0           elsif ($value==0x33) { $self->{'lcd_type'}='LK402-12' }
194 0           elsif ($value==0x34) { $self->{'lcd_type'}='LK162-12' }
195 0           elsif ($value==0x35) { $self->{'lcd_type'}='LK204-25PC' }
196 0           elsif ($value==0x36) { $self->{'lcd_type'}='LK202-24-USB' }
197 0           elsif ($value==0x37) { $self->{'lcd_type'}='VK202-24-USB' }
198 0           elsif ($value==0x38) { $self->{'lcd_type'}='LK204-24-USB' }
199 0           elsif ($value==0x39) { $self->{'lcd_type'}='VK204-24-USB' }
200 0           elsif ($value==0x3A) { $self->{'lcd_type'}='PK162-12' }
201 0           elsif ($value==0x3B) { $self->{'lcd_type'}='VK162-12' }
202 0           elsif ($value==0x3C) { $self->{'lcd_type'}='MOS-AP-162A' }
203 0           elsif ($value==0x3D) { $self->{'lcd_type'}='PK202-25' }
204 0           elsif ($value==0x3E) { $self->{'lcd_type'}='MOS-AL-162A' }
205 0           elsif ($value==0x40) { $self->{'lcd_type'}='MOS-AV-202A' }
206 0           elsif ($value==0x41) { $self->{'lcd_type'}='MOS-AP-202A' }
207 0           elsif ($value==0x42) { $self->{'lcd_type'}='PK202-24-USB' }
208 0           elsif ($value==0x43) { $self->{'lcd_type'}='MOS-AL-082' }
209 0           elsif ($value==0x44) { $self->{'lcd_type'}='MOS-AL-204' }
210 0           elsif ($value==0x45) { $self->{'lcd_type'}='MOS-AV-204' }
211 0           elsif ($value==0x46) { $self->{'lcd_type'}='MOS-AL-402' }
212 0           elsif ($value==0x47) { $self->{'lcd_type'}='MOS-AV-402' }
213 0           elsif ($value==0x48) { $self->{'lcd_type'}='LK082-12' }
214 0           elsif ($value==0x49) { $self->{'lcd_type'}='VK402-12' }
215 0           elsif ($value==0x4A) { $self->{'lcd_type'}='VK404-55' }
216 0           elsif ($value==0x4B) { $self->{'lcd_type'}='LK402-25' }
217 0           elsif ($value==0x4C) { $self->{'lcd_type'}='VK402-25' }
218 0           else { printf STDERR ("Unknown/unsupported LCD type 0x%x", $value); }
219             }
220            
221 0           return $self->{'lcd_type'};
222             }
223              
224             sub get_lcd_dimensions {
225 0     0 1   my $self = shift;
226              
227             # We need the LCD type first
228 0           my $lcd = $self->get_lcd_type();
229              
230 0 0         if ($lcd eq 'GLC12232') { return (122,32) }
  0 0          
    0          
    0          
    0          
    0          
231 0           elsif ($lcd eq 'GLC24064') { return (240,64) }
232 0           elsif ($lcd eq 'GLK24064-25') { return (240,64) }
233 0           elsif ($lcd eq 'GLK12232-25-WBL') { return (122,32) }
234 0           elsif ($lcd eq 'GLK12232-25-SM') { return (122,32) }
235 0           elsif ($lcd eq 'GLK240128-25') { return (240,128) }
236             else {
237 0           warn "Unknown pixel dimensions for LCD: $lcd";
238 0           return undef;
239             }
240             }
241              
242             sub get_firmware_version {
243 0     0 1   my $self = shift;
244 0 0         unless (defined $self->{'firmware_version'}) {
245 0           $self->send_command( 0x36 );
246              
247 0           my $value = sprintf("%2.2x", $self->getchar() );
248 0           my ($major, $minor) = ($value =~ /(\w{1})(\w{1})/);
249 0           $self->{'firmware_version'} = "$major.$minor";
250             }
251            
252 0           return $self->{'firmware_version'};
253             }
254              
255              
256              
257             #### --------------------------------------------------------- ####
258              
259              
260              
261             ## Send a command to the display
262             sub send_command {
263 0     0 0   my $self = shift;
264 0           $self->print( pack( 'C*', 0xFE, @_ ) );
265             }
266              
267              
268             ## Send a string to the display
269             sub print {
270 0     0 1   my $self = shift;
271 0           my ($string) = @_;
272 0           my $bytes = 0;
273              
274 0           eval {
275 0     0     local $SIG{ALRM} = sub { die "Timed out."; };
  0            
276 0           alarm($self->{'timeout'});
277            
278             # Send it
279 0           $bytes = $self->write( $string );
280            
281             # Block until it is sent
282 0           while(($self->write_done(0))[0] == 0) {}
283            
284 0           alarm 0;
285             };
286            
287 0 0         if ($@) {
288 0 0         die unless $@ eq "Timed out.\n"; # propagate unexpected errors
289             # timed out
290 0           warn "Timed out while writing to serial port.\n";
291             }
292              
293 0           return $bytes;
294             }
295              
296              
297             ## Send a formatted string to the display
298             sub printf {
299 0     0 1   my $self = shift;
300            
301 0           $self->print( sprintf( @_ ) );
302             }
303              
304              
305             ## Read a single byte from the serial port and return it as an integer
306             sub getchar {
307 0     0 0   my $self = shift;
308              
309             # don't wait for each character
310 0           $self->read_char_time(0);
311            
312             # milliseconds per unfulfilled "read" call
313 0           $self->read_const_time($self->{'timeout'}*1000);
314              
315             # Read one charater
316 0           my ($count,$data) = $self->read(1);
317 0 0         return undef if ($count<1);
318 0           return unpack('C',$data);
319             }
320              
321              
322             ## Close the serial port
323             sub DESTROY {
324 0     0     my $self=shift;
325            
326 0 0         if (defined $self->{'serial'}) {
327 0 0         $self->{'serial'}->close || warn "Failed to close serial port.";
328 0           undef $self->{'serial'};
329             }
330             }
331              
332              
333             1;
334              
335             __END__