line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# |
2
|
|
|
|
|
|
|
package Device::MiniLED; |
3
|
2
|
|
|
2
|
|
67117
|
use Carp; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
169
|
|
4
|
2
|
|
|
2
|
|
14
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
69
|
|
5
|
2
|
|
|
2
|
|
10
|
use warnings; |
|
2
|
|
|
|
|
15
|
|
|
2
|
|
|
|
|
70
|
|
6
|
2
|
|
|
2
|
|
44
|
use 5.005; |
|
2
|
|
|
|
|
7
|
|
|
2
|
|
|
|
|
465
|
|
7
|
|
|
|
|
|
|
$Device::MiniLED::VERSION="1.03"; |
8
|
|
|
|
|
|
|
# |
9
|
|
|
|
|
|
|
# Shared Constants / Globals |
10
|
|
|
|
|
|
|
# |
11
|
|
|
|
|
|
|
our %EFFECTMAP = ( |
12
|
|
|
|
|
|
|
"hold" => 0x41, "scroll" => 0x42, |
13
|
|
|
|
|
|
|
"snow" => 0x43, "flash" => 0x44, |
14
|
|
|
|
|
|
|
"hold+flash" => 0x45 |
15
|
|
|
|
|
|
|
); |
16
|
|
|
|
|
|
|
# |
17
|
|
|
|
|
|
|
# Use Win32::Serial port on Windows otherwise, use Device::SerialPort |
18
|
|
|
|
|
|
|
# |
19
|
|
|
|
|
|
|
BEGIN |
20
|
|
|
|
|
|
|
{ |
21
|
2
|
50
|
33
|
2
|
|
25
|
my $IS_WINDOWS = ($^O eq "MSWin32" or $^O eq "cygwin") ? 1 : 0; |
22
|
|
|
|
|
|
|
# |
23
|
2
|
50
|
|
|
|
9
|
if ($IS_WINDOWS) { |
24
|
0
|
|
|
|
|
0
|
eval "use Win32::SerialPort 0.14"; |
25
|
0
|
0
|
|
|
|
0
|
die "$@\n" if ($@); |
26
|
|
|
|
|
|
|
} else { |
27
|
2
|
|
|
2
|
|
285
|
eval "use Device::SerialPort"; |
|
2
|
|
|
|
|
3593
|
|
|
2
|
|
|
|
|
90805
|
|
|
2
|
|
|
|
|
245
|
|
28
|
2
|
50
|
|
|
|
4078
|
die "$@\n" if ($@); |
29
|
|
|
|
|
|
|
} |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub new { |
33
|
1
|
|
|
1
|
1
|
657
|
my $that = shift; |
34
|
1
|
|
33
|
|
|
13
|
my $class = ref($that) || $that; |
35
|
1
|
|
|
|
|
25
|
my(%params) = @_; |
36
|
1
|
|
|
|
|
4
|
my $this = {}; |
37
|
1
|
|
|
|
|
3
|
bless $this, $class; |
38
|
1
|
50
|
|
|
|
6
|
if (!defined($params{devicetype})) { |
39
|
0
|
|
|
|
|
0
|
croak("Parameter [devicetype] must be present (sign or badge)"); |
40
|
0
|
|
|
|
|
0
|
return undef; |
41
|
|
|
|
|
|
|
} |
42
|
1
|
50
|
33
|
|
|
6
|
if ($params{devicetype} ne "sign" and $params{devicetype} ne "badge") { |
43
|
0
|
|
|
|
|
0
|
croak("Invalue value for [devicetype]: \"$params{devicetype}\""); |
44
|
0
|
|
|
|
|
0
|
return undef; |
45
|
|
|
|
|
|
|
} |
46
|
1
|
|
|
|
|
10
|
$this->{imagefactory}=Device::MiniLED::Factory->new( |
47
|
|
|
|
|
|
|
devicetype=> $params{devicetype} |
48
|
|
|
|
|
|
|
); |
49
|
1
|
|
|
|
|
6
|
$this->{msgfactory}=Device::MiniLED::Factory->new( |
50
|
|
|
|
|
|
|
devicetype=> $params{devicetype} |
51
|
|
|
|
|
|
|
); |
52
|
1
|
|
|
|
|
3
|
$this->{device} = $params{device}; |
53
|
1
|
|
|
|
|
13
|
$this->{devicetype} = $params{devicetype}; |
54
|
1
|
|
|
|
|
3
|
$this->{refcount}=0; |
55
|
1
|
|
|
|
|
5
|
return $this; |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
sub _msgfactory { |
58
|
14
|
|
|
14
|
|
33
|
my($this) = shift; |
59
|
14
|
|
|
|
|
84
|
return $this->{msgfactory}; |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
sub _imagefactory { |
62
|
6
|
|
|
6
|
|
11
|
my($this) = shift; |
63
|
6
|
|
|
|
|
34
|
return $this->{imagefactory}; |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
sub addPix { |
66
|
1
|
|
|
1
|
1
|
8
|
my($this) = shift; |
67
|
1
|
|
|
|
|
4
|
my(%params)=@_; |
68
|
1
|
50
|
|
|
|
5
|
if (defined($params{clipart})) { |
69
|
1
|
|
|
|
|
9
|
my $ca=Device::MiniLED::Clipart->new( |
70
|
|
|
|
|
|
|
name => $params{clipart}, |
71
|
|
|
|
|
|
|
type => "pix" |
72
|
|
|
|
|
|
|
); |
73
|
1
|
|
|
|
|
6
|
$params{data}=$ca->data(); |
74
|
1
|
|
|
|
|
4
|
$params{width}=$ca->width(); |
75
|
1
|
|
|
|
|
3
|
$params{height}=$ca->height(); |
76
|
|
|
|
|
|
|
} |
77
|
1
|
50
|
|
|
|
5
|
if (!defined($params{data})) { |
78
|
0
|
|
|
|
|
0
|
croak("Parameter [data] must be present"); |
79
|
0
|
|
|
|
|
0
|
return undef; |
80
|
|
|
|
|
|
|
} |
81
|
1
|
|
|
|
|
5
|
my $pixobj=$this->_imagefactory->pixmap( |
82
|
|
|
|
|
|
|
data => $params{data}, |
83
|
|
|
|
|
|
|
height => $params{height}, |
84
|
|
|
|
|
|
|
width => $params{width}, |
85
|
|
|
|
|
|
|
devicetype => $this->{devicetype} |
86
|
|
|
|
|
|
|
); |
87
|
1
|
|
|
|
|
4
|
my $pixtag=$pixobj->get_pixtag; |
88
|
1
|
|
|
|
|
7
|
$pixobj->loaddata; |
89
|
1
|
|
|
|
|
5
|
return $pixtag; |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
sub addIcon { |
92
|
1
|
|
|
1
|
1
|
6
|
my($this) = shift; |
93
|
1
|
|
|
|
|
3
|
my(%params)=@_; |
94
|
1
|
50
|
|
|
|
11
|
if (defined($params{clipart})) { |
95
|
1
|
|
|
|
|
9
|
my $ca=Device::MiniLED::Clipart->new( |
96
|
|
|
|
|
|
|
name => $params{clipart}, |
97
|
|
|
|
|
|
|
type => "icon" |
98
|
|
|
|
|
|
|
); |
99
|
1
|
|
|
|
|
3
|
$params{data}=$ca->data(); |
100
|
|
|
|
|
|
|
} |
101
|
1
|
50
|
|
|
|
4
|
if (!defined($params{data})) { |
102
|
0
|
|
|
|
|
0
|
croak("Parameter [data] must be present"); |
103
|
0
|
|
|
|
|
0
|
return undef; |
104
|
|
|
|
|
|
|
} |
105
|
1
|
|
|
|
|
4
|
my $iconobj=$this->_imagefactory->icon( |
106
|
|
|
|
|
|
|
data => $params{data}, |
107
|
|
|
|
|
|
|
devicetype => $this->{devicetype} |
108
|
|
|
|
|
|
|
); |
109
|
1
|
|
|
|
|
3
|
my $icontag=$iconobj->get_icontag; |
110
|
1
|
|
|
|
|
6
|
$iconobj->loaddata; |
111
|
1
|
|
|
|
|
6
|
return $icontag; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
sub addMsg { |
115
|
3
|
|
|
3
|
1
|
16
|
my($this) = shift; |
116
|
3
|
|
|
|
|
13
|
my(%params)=@_; |
117
|
3
|
50
|
|
|
|
9
|
if ($this->_msgfactory->{msgcount} >= 8) { |
118
|
0
|
|
|
|
|
0
|
carp("Maximum message count of 8 is already". |
119
|
|
|
|
|
|
|
" reached, discarding new message"); |
120
|
0
|
|
|
|
|
0
|
return undef; |
121
|
|
|
|
|
|
|
} |
122
|
3
|
50
|
|
|
|
11
|
if (!defined($params{data})) { |
123
|
0
|
|
|
|
|
0
|
croak("Parameter [data] must be present"); |
124
|
0
|
|
|
|
|
0
|
return undef; |
125
|
|
|
|
|
|
|
} |
126
|
3
|
50
|
|
|
|
7
|
if (!defined($params{speed})) { |
127
|
0
|
|
|
|
|
0
|
$params{speed}=4; |
128
|
|
|
|
|
|
|
} |
129
|
3
|
50
|
|
|
|
17
|
if ($params{speed} !~ /^[1-5]$/) { |
130
|
0
|
|
|
|
|
0
|
croak("Parameter [speed] must be between 1 (slowest) and 5 (fastest)"); |
131
|
0
|
|
|
|
|
0
|
return undef; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
# effect |
134
|
3
|
50
|
|
|
|
9
|
if (!defined($params{effect})) { |
135
|
0
|
|
|
|
|
0
|
$params{effect}="scroll"; |
136
|
|
|
|
|
|
|
} else { |
137
|
3
|
|
|
|
|
22
|
my @effects=keys(%Device::MiniLED::EFFECTMAP); |
138
|
3
|
50
|
|
|
|
80
|
if (!grep(/^$params{effect}$/,@effects)) { |
139
|
0
|
|
|
|
|
0
|
croak("Invalid effect value [$params{effect}]"); |
140
|
0
|
|
|
|
|
0
|
return undef; |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
} |
143
|
3
|
50
|
|
|
|
10
|
if (exists($params{slot})) { |
144
|
0
|
0
|
|
|
|
0
|
if ($params{slot} !~ /^[1-8]$/) { |
145
|
0
|
|
|
|
|
0
|
croak("Parameter [slot] must be a value from 1 to 8"); |
146
|
|
|
|
|
|
|
} else { |
147
|
0
|
|
|
|
|
0
|
$this->_msgfactory->slot($params{slot}); |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
} else { |
150
|
3
|
|
|
|
|
7
|
$params{slot}=$this->_msgfactory->slot; |
151
|
|
|
|
|
|
|
} |
152
|
3
|
|
|
|
|
9
|
my $mobj=$this->_msgfactory->msg( |
153
|
|
|
|
|
|
|
%params, |
154
|
|
|
|
|
|
|
devicetype => $this->{devicetype}, |
155
|
|
|
|
|
|
|
imagefactory =>$this->_imagefactory, |
156
|
|
|
|
|
|
|
); |
157
|
3
|
|
|
|
|
13
|
return $this->_msgfactory->{msgcount}; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
sub _connect { |
160
|
0
|
|
|
0
|
|
0
|
my $this=shift; |
161
|
0
|
|
|
|
|
0
|
my(%params)=@_; |
162
|
0
|
|
|
|
|
0
|
my $serial; |
163
|
0
|
|
|
|
|
0
|
my $port=$params{device}; |
164
|
0
|
|
|
|
|
0
|
my $baudrate=$params{baudrate}; |
165
|
0
|
0
|
0
|
|
|
0
|
my $IS_WINDOWS = ($^O eq "MSWin32" or $^O eq "cygwin") ? 1 : 0; |
166
|
0
|
0
|
|
|
|
0
|
if ($IS_WINDOWS) { |
167
|
0
|
|
|
|
|
0
|
$serial = new Win32::SerialPort ($port, 1); |
168
|
|
|
|
|
|
|
} else { |
169
|
0
|
|
|
|
|
0
|
$serial = new Device::SerialPort ($port, 1); |
170
|
|
|
|
|
|
|
} |
171
|
0
|
0
|
|
|
|
0
|
croak("Can't open serial port $port: $^E\n") unless ($serial); |
172
|
|
|
|
|
|
|
# set serial parameters |
173
|
0
|
|
|
|
|
0
|
$serial->baudrate($baudrate); |
174
|
0
|
|
|
|
|
0
|
$serial->parity('none'); |
175
|
0
|
|
|
|
|
0
|
$serial->databits(8); |
176
|
0
|
|
|
|
|
0
|
$serial->stopbits(1); |
177
|
0
|
|
|
|
|
0
|
$serial->handshake('none'); |
178
|
0
|
|
|
|
|
0
|
$serial->write_settings(); |
179
|
0
|
|
|
|
|
0
|
return $serial; |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
sub send { |
182
|
1
|
|
|
1
|
1
|
736
|
my $this=shift; |
183
|
1
|
|
|
|
|
6
|
my(%params)=@_; |
184
|
1
|
50
|
|
|
|
7
|
if (!defined($params{device})) { |
185
|
0
|
|
|
|
|
0
|
croak("Must supply the device name."); |
186
|
0
|
|
|
|
|
0
|
return undef; |
187
|
|
|
|
|
|
|
} |
188
|
1
|
|
|
|
|
3
|
my $baudrate; |
189
|
1
|
50
|
|
|
|
5
|
if (defined($params{baudrate})) { |
190
|
0
|
|
|
|
|
0
|
my @validrates = qw( 0 50 75 110 134 150 200 300 600 |
191
|
|
|
|
|
|
|
1200 1800 2400 4800 9600 19200 38400 57600 |
192
|
|
|
|
|
|
|
115200 230400 460800 500000 576000 921600 1000000 |
193
|
|
|
|
|
|
|
1152000 2000000 2500000 3000000 3500000 4000000 |
194
|
|
|
|
|
|
|
); |
195
|
0
|
0
|
|
|
|
0
|
if (! grep {$_ eq $params{baudrate}} @validrates) { |
|
0
|
|
|
|
|
0
|
|
196
|
0
|
|
|
|
|
0
|
croak('Invalid baudrate ['.$params{baudrate}.']'); |
197
|
|
|
|
|
|
|
} else { |
198
|
0
|
|
|
|
|
0
|
$baudrate=$params{baudrate}; |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
} else { |
201
|
1
|
|
|
|
|
3
|
$baudrate="38400"; |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
# packetdelay is the # of seconds to sleep between sending packets over |
204
|
|
|
|
|
|
|
# the serial port. Can be a floating point number. Default is 0.2 seconds |
205
|
1
|
|
|
|
|
2
|
my $packetdelay; |
206
|
1
|
50
|
|
|
|
4
|
if (defined($params{packetdelay})) { |
207
|
0
|
0
|
0
|
|
|
0
|
if ($params{packetdelay} > 0 && |
208
|
|
|
|
|
|
|
$params{packetdelay} =~ m#^\d*\.{0,1}\d*$#) { |
209
|
0
|
|
|
|
|
0
|
$packetdelay=$params{packetdelay}; |
210
|
|
|
|
|
|
|
} else { |
211
|
0
|
|
|
|
|
0
|
croak('Invalid value ['.$params{packetdelay} |
212
|
|
|
|
|
|
|
. '] for parameter packetdelay'); |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
} else { |
215
|
|
|
|
|
|
|
# anything below this seems to overrun the sign |
216
|
1
|
|
|
|
|
2
|
$packetdelay=0.20; |
217
|
|
|
|
|
|
|
} |
218
|
1
|
|
|
|
|
2
|
my $serial; |
219
|
1
|
50
|
|
|
|
14
|
if (defined $params{debug}) { |
220
|
1
|
|
|
|
|
8
|
$serial=Device::MiniLED::SerialTest->new(); |
221
|
|
|
|
|
|
|
} else { |
222
|
0
|
|
|
|
|
0
|
$serial=$this->_connect( |
223
|
|
|
|
|
|
|
device => $params{device}, |
224
|
|
|
|
|
|
|
baudrate => $baudrate |
225
|
|
|
|
|
|
|
); |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
# send an initial null, wakes up the sign |
228
|
1
|
|
|
|
|
7
|
$serial->write(pack("C",0x00)); |
229
|
|
|
|
|
|
|
# sleep a short while to avoid overrunning sign |
230
|
1
|
|
|
|
|
200540
|
select(undef,undef,undef,$packetdelay); |
231
|
1
|
|
|
|
|
14
|
my $count=0; |
232
|
1
|
|
|
|
|
4
|
foreach my $msgobj (@{$this->_msgfactory->objects}) { |
|
1
|
|
|
|
|
65
|
|
233
|
|
|
|
|
|
|
# get the data |
234
|
3
|
|
|
|
|
15
|
$count++; |
235
|
3
|
|
|
|
|
73
|
my @packets=$msgobj->encode(devicetype => $params{devicetype}); |
236
|
3
|
|
|
|
|
18
|
foreach my $data (@packets) { |
237
|
12
|
|
|
|
|
127
|
$serial->write($data); |
238
|
|
|
|
|
|
|
# logic so we don't sleep after the last packet |
239
|
12
|
|
|
|
|
2407302
|
select(undef,undef,undef,$packetdelay); |
240
|
|
|
|
|
|
|
# sleep a short while to avoid overrunning sign |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
} |
243
|
1
|
|
|
|
|
14
|
foreach my $data ($this->_imagefactory->packets()) { |
244
|
2
|
|
|
|
|
18
|
$serial->write($data); |
245
|
|
|
|
|
|
|
# sleep a short while to avoid overrunning sign |
246
|
2
|
|
|
|
|
400772
|
select(undef,undef,undef,$packetdelay); |
247
|
|
|
|
|
|
|
} |
248
|
1
|
|
|
|
|
31
|
my %BITVAL = ( |
249
|
|
|
|
|
|
|
1 => 1, 2 => 2, |
250
|
|
|
|
|
|
|
3 => 4, 4 => 8, |
251
|
|
|
|
|
|
|
5 => 16, 6 => 32, |
252
|
|
|
|
|
|
|
7 => 64, 8 => 128 |
253
|
|
|
|
|
|
|
); |
254
|
1
|
|
|
|
|
4
|
my $bits=0; |
255
|
1
|
|
|
|
|
4
|
my @slots; |
256
|
1
|
50
|
|
|
|
13
|
if (exists($params{showslots})) { |
257
|
|
|
|
|
|
|
# strip spaces |
258
|
0
|
|
|
|
|
0
|
$params{showslots} =~ s#\s##g; |
259
|
0
|
|
|
|
|
0
|
foreach my $one (split(/\,/,$params{showslots})) { |
260
|
0
|
0
|
|
|
|
0
|
if ($one !~ /^[1-8]$/) { |
261
|
0
|
|
|
|
|
0
|
croak("Invalid value [$one] in parameter [showslots]"); |
262
|
|
|
|
|
|
|
} else { |
263
|
0
|
|
|
|
|
0
|
push(@slots,$one); |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
} else { |
267
|
1
|
|
|
|
|
4
|
@slots = keys %{$this->_msgfactory->{'msgslots'}}; |
|
1
|
|
|
|
|
12
|
|
268
|
|
|
|
|
|
|
} |
269
|
1
|
|
|
|
|
6
|
foreach my $num (@slots) { |
270
|
3
|
|
|
|
|
14
|
$bits += $BITVAL{$num}; |
271
|
|
|
|
|
|
|
} |
272
|
1
|
50
|
|
|
|
12
|
if ($bits != 0) { |
273
|
1
|
|
|
|
|
11
|
my $runit=pack("C*",(0x02,0x33,$bits)); |
274
|
|
|
|
|
|
|
#select(undef,undef,undef,$packetdelay); |
275
|
1
|
|
|
|
|
10
|
$serial->write($runit); |
276
|
|
|
|
|
|
|
} |
277
|
1
|
50
|
|
|
|
43
|
if (defined $params{debug}) { |
278
|
1
|
|
|
|
|
8
|
return $serial->dump(); |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
package Device::MiniLED::Factory; |
282
|
2
|
|
|
2
|
|
26
|
use Carp; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
3106
|
|
283
|
|
|
|
|
|
|
our @CARP_NOT = qw(Device::MiniLED); |
284
|
|
|
|
|
|
|
sub new { |
285
|
2
|
|
|
2
|
|
3
|
my $that = shift; |
286
|
2
|
|
33
|
|
|
10
|
my $class = ref($that) || $that; |
287
|
2
|
|
|
|
|
6
|
my(%params) = @_; |
288
|
2
|
|
|
|
|
4
|
my $this = {}; |
289
|
2
|
|
|
|
|
4
|
bless $this, $class; |
290
|
2
|
|
|
|
|
7
|
foreach my $key (keys(%params)) { |
291
|
2
|
|
|
|
|
12
|
$this->{$key}=$params{$key}; |
292
|
|
|
|
|
|
|
} |
293
|
2
|
|
|
|
|
5
|
$this->{msgcount}=0; |
294
|
2
|
|
|
|
|
4
|
$this->{imgcount}=0; |
295
|
2
|
|
|
|
|
3
|
$this->{chunkcount}=0; |
296
|
2
|
|
|
|
|
5
|
$this->{chunkcache}={}; |
297
|
2
|
|
|
|
|
4
|
$this->{chunks}=[]; |
298
|
2
|
|
|
|
|
3
|
$this->{msgslots}=(); |
299
|
2
|
|
|
|
|
6
|
$this->{objects}=[]; |
300
|
2
|
|
|
|
|
11
|
return $this; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
sub slot { |
303
|
3
|
|
|
3
|
|
7
|
my $this=shift; |
304
|
3
|
|
|
|
|
4
|
my $slot; |
305
|
3
|
|
|
|
|
3
|
$slot=shift; |
306
|
3
|
|
|
|
|
5
|
my $return; |
307
|
3
|
50
|
|
|
|
7
|
if (!defined($slot)) { |
308
|
|
|
|
|
|
|
# a slot wasn't specified, so issue the next available |
309
|
3
|
|
|
|
|
8
|
for (1..8) { |
310
|
6
|
100
|
|
|
|
21
|
if (!exists($this->{msgslots}{$_})) { |
311
|
3
|
|
|
|
|
8
|
$this->{msgslots}->{$_}=1; |
312
|
3
|
|
|
|
|
5
|
$return=$_; |
313
|
3
|
|
|
|
|
6
|
last; |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
} else { |
317
|
0
|
0
|
|
|
|
0
|
if (exists($this->{msgslots}->{$slot})) { |
318
|
0
|
|
|
|
|
0
|
croak("Slot [$slot] already in use\n"); |
319
|
|
|
|
|
|
|
} else { |
320
|
0
|
|
|
|
|
0
|
$this->{msgslots}->{$slot}=1; |
321
|
0
|
|
|
|
|
0
|
$return=$slot; |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
} |
324
|
3
|
|
|
|
|
10
|
return $return; |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
sub msg { |
328
|
3
|
|
|
3
|
|
5
|
my $this=shift; |
329
|
3
|
|
|
|
|
13
|
my(%params) = @_; |
330
|
3
|
|
|
|
|
14
|
my $msg=Device::MiniLED::Msg->new(%params, factory => $this); |
331
|
3
|
|
|
|
|
8
|
push(@{$this->{objects}},$msg); |
|
3
|
|
|
|
|
5
|
|
332
|
3
|
|
|
|
|
7
|
$this->{msgcount}++; |
333
|
3
|
|
|
|
|
5
|
my $msgcount=$this->{msgcount}; |
334
|
3
|
|
|
|
|
8
|
$msg->{number}=$this->{msgcount}; |
335
|
3
|
|
|
|
|
11
|
return $msg; |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
sub objects { |
338
|
1
|
|
|
1
|
|
221
|
my $this=shift; |
339
|
1
|
|
|
|
|
12
|
return $this->{objects}; |
340
|
|
|
|
|
|
|
} |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
sub pixmap { |
343
|
1
|
|
|
1
|
|
2
|
my $this=shift; |
344
|
1
|
|
|
|
|
4
|
my(%params) = @_; |
345
|
1
|
|
|
|
|
11
|
my $pixmap=Device::MiniLED::Pixmap->new( |
346
|
|
|
|
|
|
|
%params, |
347
|
|
|
|
|
|
|
devicetype => $this->{devicetype}, |
348
|
|
|
|
|
|
|
factory => $this |
349
|
|
|
|
|
|
|
); |
350
|
1
|
|
|
|
|
1
|
push(@{$this->{pixobjects}},$pixmap); |
|
1
|
|
|
|
|
3
|
|
351
|
1
|
|
|
|
|
2
|
$this->{imgcount}++; |
352
|
1
|
|
|
|
|
6
|
$pixmap->{number}=$this->{imgcount}; |
353
|
1
|
|
|
|
|
8
|
return $pixmap; |
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
sub icon { |
356
|
1
|
|
|
1
|
|
2
|
my $this=shift; |
357
|
1
|
|
|
|
|
3
|
my(%params) = @_; |
358
|
1
|
|
|
|
|
9
|
my $icon=Device::MiniLED::Icon->new( |
359
|
|
|
|
|
|
|
%params, |
360
|
|
|
|
|
|
|
devicetype => $this->{devicetype}, |
361
|
|
|
|
|
|
|
factory => $this |
362
|
|
|
|
|
|
|
); |
363
|
1
|
|
|
|
|
2
|
push(@{$this->{iconobjects}},$icon); |
|
1
|
|
|
|
|
2
|
|
364
|
1
|
|
|
|
|
2
|
$this->{imgcount}++; |
365
|
1
|
|
|
|
|
2
|
$icon->{number}=$this->{imgcount}; |
366
|
1
|
|
|
|
|
3
|
return $icon; |
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
sub store_icontag { |
369
|
1
|
|
|
1
|
|
3
|
my $this=shift; |
370
|
1
|
|
|
|
|
2
|
my $icontag=shift; |
371
|
1
|
|
|
|
|
2
|
my $msgref=shift; |
372
|
1
|
|
|
|
|
8
|
$this->{icontag}{$icontag}=$msgref; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
sub icontag_data { |
375
|
1
|
|
|
1
|
|
4
|
my $this=shift; |
376
|
1
|
|
|
|
|
3
|
my $icontag=shift; |
377
|
1
|
50
|
|
|
|
9
|
if (defined($this->{icontag}{$icontag})) { |
378
|
1
|
|
|
|
|
6
|
return $this->{icontag}{$icontag}; |
379
|
|
|
|
|
|
|
} else { |
380
|
0
|
|
|
|
|
0
|
return ''; |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
sub pixobjects { |
385
|
0
|
|
|
0
|
|
0
|
my $this=shift; |
386
|
0
|
|
|
|
|
0
|
return $this->{pixobjects}; |
387
|
|
|
|
|
|
|
} |
388
|
|
|
|
|
|
|
sub iconobjects { |
389
|
0
|
|
|
0
|
|
0
|
my $this=shift; |
390
|
0
|
|
|
|
|
0
|
return $this->{iconobjects}; |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
sub add_chunk { |
393
|
2
|
|
|
2
|
|
3
|
my $this=shift; |
394
|
2
|
|
|
|
|
15
|
my %params=@_; |
395
|
2
|
|
|
|
|
4
|
my $chunk = $params{chunk}; |
396
|
2
|
|
|
|
|
3
|
my $type = $params{type}; |
397
|
2
|
|
|
|
|
4
|
my $return; |
398
|
|
|
|
|
|
|
# if we've seen a chunk like this before, pass back the existing |
399
|
|
|
|
|
|
|
# reference instead of storing a new image |
400
|
2
|
50
|
|
|
|
7
|
if (exists($this->{chunkcache}{$chunk})) { |
401
|
0
|
|
|
|
|
0
|
$return=$this->{chunkcache}{$chunk}; |
402
|
|
|
|
|
|
|
} else { |
403
|
2
|
|
|
|
|
4
|
my $sequence=0; |
404
|
2
|
|
|
|
|
3
|
foreach my $thing (@{$this->{chunks}}) { |
|
2
|
|
|
|
|
6
|
|
405
|
1
|
|
|
|
|
2
|
my $len=length($thing); |
406
|
1
|
50
|
|
|
|
6
|
if ($len > 32) { |
407
|
0
|
|
|
|
|
0
|
$sequence+=2; |
408
|
|
|
|
|
|
|
} else { |
409
|
1
|
|
|
|
|
4
|
$sequence+=1; |
410
|
|
|
|
|
|
|
} |
411
|
|
|
|
|
|
|
} |
412
|
2
|
|
|
|
|
4
|
push(@{$this->{chunks}},$chunk); |
|
2
|
|
|
|
|
6
|
|
413
|
2
|
|
|
|
|
3
|
my $msgref; |
414
|
2
|
100
|
|
|
|
9
|
if ($type eq "pixmap") { |
|
|
50
|
|
|
|
|
|
415
|
1
|
|
|
|
|
2
|
$msgref=0x8000+$sequence; |
416
|
|
|
|
|
|
|
} elsif ($type eq "icon") { |
417
|
1
|
|
|
|
|
3
|
$msgref=0xc000+$sequence; |
418
|
|
|
|
|
|
|
} else { |
419
|
0
|
|
|
|
|
0
|
die("argh!\n"); |
420
|
|
|
|
|
|
|
} |
421
|
2
|
|
|
|
|
6
|
$return=pack("n",$msgref); |
422
|
2
|
|
|
|
|
8
|
$this->{chunkcache}{$chunk}=$return; |
423
|
|
|
|
|
|
|
} |
424
|
2
|
|
|
|
|
11
|
return($return); |
425
|
|
|
|
|
|
|
} |
426
|
|
|
|
|
|
|
sub packets { |
427
|
1
|
|
|
1
|
|
5
|
my $this=shift; |
428
|
1
|
|
|
|
|
3
|
my $blob=join('',@{$this->{chunks}}); |
|
1
|
|
|
|
|
7
|
|
429
|
1
|
|
|
|
|
4
|
my $length=length($blob); |
430
|
|
|
|
|
|
|
# pad out to an even multiple of 64 bytes |
431
|
1
|
50
|
|
|
|
9
|
if ($length % 64) { |
432
|
1
|
|
|
|
|
5
|
my $paddedsize=$length+64-($length % 64); |
433
|
1
|
|
|
|
|
10
|
$blob=pack("a$paddedsize",$blob); |
434
|
|
|
|
|
|
|
} |
435
|
1
|
|
|
|
|
3
|
my $new=length($blob); |
436
|
|
|
|
|
|
|
# now split into 64 byte pieces, each one it's own packet |
437
|
1
|
|
|
|
|
2
|
my $i; |
438
|
|
|
|
|
|
|
my @packets; |
439
|
1
|
|
|
|
|
3
|
my $count=0x0E00; |
440
|
1
|
|
|
|
|
9
|
foreach my $chunk (unpack("(a64)*",$blob)) { |
441
|
2
|
|
|
|
|
5
|
my $len=length($chunk); |
442
|
2
|
|
|
|
|
3
|
my @tosend; |
443
|
2
|
|
|
|
|
4
|
push(@tosend,0x02,0x31); |
444
|
2
|
|
|
|
|
12
|
my $hcount=sprintf("%04x",$count); |
445
|
2
|
|
|
|
|
211
|
my($start,$end)=(unpack("(a2)*",sprintf("%04x",$count))); |
446
|
2
|
|
|
|
|
6
|
$start=hex($start); $end=hex($end); |
|
2
|
|
|
|
|
4
|
|
447
|
2
|
|
|
|
|
6
|
push(@tosend,$start,$end); |
448
|
2
|
|
|
|
|
23
|
foreach my $char (split(//,$chunk)) { |
449
|
128
|
|
|
|
|
178
|
push(@tosend,ord($char)); |
450
|
|
|
|
|
|
|
} |
451
|
2
|
|
|
|
|
30
|
my @slice=@tosend[1..$#tosend]; |
452
|
2
|
|
|
|
|
8
|
my $total; |
453
|
2
|
|
|
|
|
4
|
foreach my $one (@slice) { |
454
|
134
|
|
|
|
|
164
|
$total+=$one; |
455
|
|
|
|
|
|
|
# my $hextotal = sprintf("0x%x",$total); |
456
|
|
|
|
|
|
|
} |
457
|
2
|
|
|
|
|
5
|
my $mod=$total % 256; |
458
|
2
|
|
|
|
|
3
|
push(@tosend,$mod); |
459
|
2
|
|
|
|
|
9
|
my $packed=pack("C*",@tosend); |
460
|
2
|
|
|
|
|
5
|
push(@packets,$packed); |
461
|
2
|
|
|
|
|
12
|
$count+=64; |
462
|
|
|
|
|
|
|
} |
463
|
1
|
|
|
|
|
5
|
return @packets; |
464
|
|
|
|
|
|
|
} |
465
|
|
|
|
|
|
|
sub store_pixtag { |
466
|
1
|
|
|
1
|
|
3
|
my $this=shift; |
467
|
1
|
|
|
|
|
2
|
my $pixtag=shift; |
468
|
1
|
|
|
|
|
2
|
my $msgref=shift; |
469
|
1
|
|
|
|
|
7
|
$this->{pixtag}{$pixtag}=$msgref; |
470
|
|
|
|
|
|
|
} |
471
|
|
|
|
|
|
|
sub pixtag_data { |
472
|
1
|
|
|
1
|
|
6
|
my $this=shift; |
473
|
1
|
|
|
|
|
3
|
my $pixtag=shift; |
474
|
1
|
50
|
|
|
|
26
|
if (defined($this->{pixtag}{$pixtag})) { |
475
|
1
|
|
|
|
|
10
|
return $this->{pixtag}{$pixtag}; |
476
|
|
|
|
|
|
|
} else { |
477
|
0
|
|
|
|
|
0
|
return ''; |
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
} |
480
|
|
|
|
|
|
|
# |
481
|
|
|
|
|
|
|
# object to hold a message and it's associated data and parameters |
482
|
|
|
|
|
|
|
# |
483
|
|
|
|
|
|
|
package Device::MiniLED::Msg; |
484
|
2
|
|
|
2
|
|
15
|
use Carp; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
1991
|
|
485
|
|
|
|
|
|
|
our @CARP_NOT = qw(Device::MiniLED); |
486
|
|
|
|
|
|
|
sub new { |
487
|
3
|
|
|
3
|
|
5
|
my $that = shift; |
488
|
3
|
|
33
|
|
|
31
|
my $class = ref($that) || $that; |
489
|
3
|
|
|
|
|
24
|
my(%params) = @_; |
490
|
3
|
|
|
|
|
6
|
my $this = {}; |
491
|
3
|
|
|
|
|
7
|
bless $this, $class; |
492
|
3
|
|
|
|
|
10
|
foreach my $key (keys(%params)) { |
493
|
21
|
|
|
|
|
47
|
$this->{$key}=$params{$key}; |
494
|
|
|
|
|
|
|
} |
495
|
3
|
|
|
|
|
11
|
return $this; |
496
|
|
|
|
|
|
|
} |
497
|
|
|
|
|
|
|
sub factory { |
498
|
0
|
|
|
0
|
|
0
|
my $this = shift; |
499
|
0
|
|
|
|
|
0
|
return $this->{factory}; |
500
|
|
|
|
|
|
|
} |
501
|
|
|
|
|
|
|
sub processTags { |
502
|
3
|
|
|
3
|
|
9
|
my $this = shift; |
503
|
3
|
|
|
|
|
11
|
my $type=$this->{devicetype}; |
504
|
3
|
|
|
|
|
13
|
my $msgdata=$this->{data}; |
505
|
|
|
|
|
|
|
# font tags |
506
|
|
|
|
|
|
|
|
507
|
3
|
|
|
|
|
17
|
my ($normal,$flash); |
508
|
3
|
50
|
|
|
|
25
|
if ($type eq "badge") { |
509
|
0
|
|
|
|
|
0
|
$normal=pack("C*",0xff,0x80); |
510
|
0
|
|
|
|
|
0
|
$flash=pack("C*",0xff,0x81); |
511
|
|
|
|
|
|
|
} else { |
512
|
3
|
|
|
|
|
12
|
$normal=pack("C*",0xff,0x8f); |
513
|
3
|
|
|
|
|
9
|
$flash=pack("C*",0xff,0x8f); |
514
|
|
|
|
|
|
|
} |
515
|
3
|
|
|
|
|
24
|
$msgdata =~ s//$normal/g; |
516
|
3
|
|
|
|
|
9
|
$msgdata =~ s//$flash/g; |
517
|
|
|
|
|
|
|
# icon tags |
518
|
3
|
|
|
|
|
9
|
my $factory=$this->{imagefactory}; |
519
|
3
|
|
|
|
|
41
|
while ($msgdata =~ /()/g) { |
520
|
1
|
|
|
|
|
8
|
my $icontag=$1; |
521
|
1
|
|
|
|
|
10
|
my $substitute=$factory->icontag_data($icontag); |
522
|
1
|
|
|
|
|
37
|
$msgdata=~s/$icontag/$substitute/g; |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
# pix tags |
525
|
3
|
|
|
|
|
31
|
while ($msgdata =~ /()/g) { |
526
|
1
|
|
|
|
|
9
|
my $pixtag=$1; |
527
|
1
|
|
|
|
|
8
|
my $substitute=$factory->pixtag_data($pixtag); |
528
|
1
|
|
|
|
|
39
|
$msgdata=~s/$pixtag/$substitute/g; |
529
|
|
|
|
|
|
|
} |
530
|
3
|
|
|
|
|
16
|
$this->{data}=$msgdata; |
531
|
3
|
|
|
|
|
303
|
return $msgdata; |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
sub encode { |
534
|
3
|
|
|
3
|
|
13
|
my $this = shift; |
535
|
3
|
|
|
|
|
35
|
my(%params)=@_; |
536
|
3
|
|
|
|
|
19
|
my $number=$this->{number}; |
537
|
3
|
|
|
|
|
20
|
my $msgdata=$this->processTags(); |
538
|
3
|
|
|
|
|
36
|
my %SPMAP = ( |
539
|
|
|
|
|
|
|
1 => 0x31, 2 => 0x32, 3 => 0x33, |
540
|
|
|
|
|
|
|
4 => 0x34, 5 => 0x35 |
541
|
|
|
|
|
|
|
); |
542
|
3
|
|
|
|
|
17
|
my $effect=$Device::MiniLED::EFFECTMAP{$this->{effect}}; |
543
|
|
|
|
|
|
|
|
544
|
3
|
50
|
|
|
|
15
|
if (! $effect ) { |
545
|
0
|
|
|
|
|
0
|
$effect=0x35; |
546
|
|
|
|
|
|
|
} |
547
|
3
|
|
|
|
|
12
|
my $speed=$SPMAP{$this->{speed}}; |
548
|
3
|
50
|
|
|
|
15
|
if (! $speed ) { |
549
|
0
|
|
|
|
|
0
|
$speed=0x35; |
550
|
|
|
|
|
|
|
} |
551
|
3
|
|
|
|
|
9
|
my $alength=length($msgdata); |
552
|
3
|
|
|
|
|
27
|
$msgdata=pack("Z255",$msgdata); |
553
|
3
|
|
|
|
|
9
|
my @encoded; |
554
|
|
|
|
|
|
|
my $end; |
555
|
3
|
|
|
|
|
21
|
my @endmem=(0x00,0x40,0x80,0xc0); |
556
|
3
|
|
|
|
|
13
|
my $slot=$this->{slot}; |
557
|
3
|
|
|
|
|
15
|
foreach my $i (0..3) { |
558
|
12
|
|
|
|
|
36
|
my $start=0x06+($slot-1); |
559
|
|
|
|
|
|
|
#my $start=0x06+($number-1); |
560
|
12
|
|
|
|
|
17
|
my $chunk; |
561
|
12
|
100
|
|
|
|
37
|
if ($i == 0) { |
562
|
3
|
|
|
|
|
17
|
$chunk=substr($msgdata,0,60); |
563
|
|
|
|
|
|
|
} else { |
564
|
9
|
|
|
|
|
36
|
my $offset=60+(64*($i-1)); |
565
|
9
|
|
|
|
|
29
|
$chunk=substr($msgdata,$offset,64); |
566
|
|
|
|
|
|
|
} |
567
|
12
|
|
|
|
|
28
|
$end=$endmem[$i]; |
568
|
12
|
|
|
|
|
27
|
my $csize=length($chunk)+2; |
569
|
12
|
|
|
|
|
33
|
my(@tosend)=(0x02,0x31,$start,$end); |
570
|
12
|
100
|
|
|
|
40
|
if ($i == 0) { |
571
|
3
|
|
|
|
|
11
|
push(@tosend,($speed,0x31,$effect,$alength)); |
572
|
|
|
|
|
|
|
} |
573
|
12
|
|
|
|
|
193
|
foreach my $char (split(//,$chunk)) { |
574
|
756
|
|
|
|
|
2297
|
push(@tosend,ord($char)); |
575
|
|
|
|
|
|
|
} |
576
|
12
|
|
|
|
|
102
|
my $aend=$#tosend; |
577
|
12
|
|
|
|
|
165
|
my @slice=@tosend[1..$#tosend]; |
578
|
12
|
|
|
|
|
43
|
my $total; |
579
|
12
|
|
|
|
|
83
|
foreach my $one (@slice) { |
580
|
804
|
|
|
|
|
1721
|
$total+=$one; |
581
|
804
|
|
|
|
|
2430
|
my $hextotal = sprintf("0x%x",$total); |
582
|
|
|
|
|
|
|
} |
583
|
12
|
|
|
|
|
35
|
my $mod=$total % 256; |
584
|
12
|
|
|
|
|
31
|
my $hmod=sprintf("0x%x",$mod); |
585
|
|
|
|
|
|
|
|
586
|
12
|
|
|
|
|
24
|
push(@tosend,$mod); |
587
|
12
|
|
|
|
|
61
|
my $packed=pack("C*",@tosend); |
588
|
12
|
|
|
|
|
98
|
push(@encoded,$packed); |
589
|
|
|
|
|
|
|
} |
590
|
3
|
|
|
|
|
203
|
return @encoded; |
591
|
|
|
|
|
|
|
} |
592
|
|
|
|
|
|
|
# |
593
|
|
|
|
|
|
|
# parent object for Pixmap and Icon to derive from |
594
|
|
|
|
|
|
|
# |
595
|
|
|
|
|
|
|
# |
596
|
|
|
|
|
|
|
package Device::MiniLED::Image; |
597
|
2
|
|
|
2
|
|
15
|
use Carp; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
177
|
|
598
|
2
|
|
|
2
|
|
14
|
use POSIX qw (ceil); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
22
|
|
599
|
|
|
|
|
|
|
sub new { |
600
|
2
|
|
|
2
|
|
4
|
my $that = shift; |
601
|
2
|
|
33
|
|
|
7
|
my $class = ref($that) || $that; |
602
|
2
|
|
|
|
|
5
|
my(%params) = @_; |
603
|
2
|
|
|
|
|
3
|
my $this = {}; |
604
|
2
|
|
|
|
|
4
|
bless $this, $class; |
605
|
2
|
|
|
|
|
5
|
foreach my $key (keys(%params)) { |
606
|
8
|
|
|
|
|
18
|
$this->{$key}=$params{$key}; |
607
|
|
|
|
|
|
|
} |
608
|
2
|
|
|
|
|
7
|
return $this; |
609
|
|
|
|
|
|
|
} |
610
|
|
|
|
|
|
|
sub factory { |
611
|
2
|
|
|
2
|
|
3
|
my $this = shift; |
612
|
2
|
|
|
|
|
5
|
return $this->{factory}; |
613
|
|
|
|
|
|
|
} |
614
|
|
|
|
|
|
|
sub loaddata { |
615
|
2
|
|
|
2
|
|
3
|
my $this=shift(); |
616
|
2
|
|
|
|
|
3
|
my $devicetype=$this->{devicetype}; |
617
|
2
|
|
|
|
|
4
|
my $data=$this->{data}; |
618
|
2
|
|
|
|
|
15
|
$data=~s/[^01]//g; |
619
|
|
|
|
|
|
|
# set tilesize, width, and height |
620
|
2
|
|
|
|
|
2
|
my $tilesize;my $width;my $height; |
|
0
|
|
|
|
|
0
|
|
621
|
2
|
100
|
|
|
|
14
|
if ($this->{objtype} eq "pixmap") { |
|
|
50
|
|
|
|
|
|
622
|
1
|
|
|
|
|
2
|
$width=$this->{width}; |
623
|
1
|
|
|
|
|
2
|
$height=$this->{height}; |
624
|
1
|
50
|
|
|
|
3
|
if ($devicetype eq "sign") { |
|
|
0
|
|
|
|
|
|
625
|
1
|
|
|
|
|
2
|
$tilesize=16; |
626
|
1
|
|
|
|
|
3
|
$this->{packformat}="a32" |
627
|
|
|
|
|
|
|
} elsif ($devicetype eq "badge") { |
628
|
0
|
|
|
|
|
0
|
$tilesize=12; |
629
|
0
|
|
|
|
|
0
|
$this->{packformat}="a24" |
630
|
|
|
|
|
|
|
} |
631
|
|
|
|
|
|
|
} elsif ($this->{objtype} eq "icon") { |
632
|
1
|
50
|
|
|
|
4
|
if ($devicetype eq "sign") { |
|
|
0
|
|
|
|
|
|
633
|
1
|
|
|
|
|
2
|
$tilesize=16;$width=32;$height=16; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
2
|
|
634
|
1
|
|
|
|
|
2
|
$this->{packformat}="a64" |
635
|
|
|
|
|
|
|
} elsif ($devicetype eq "badge") { |
636
|
0
|
|
|
|
|
0
|
$tilesize=12;$width=24;$height=12; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
637
|
0
|
|
|
|
|
0
|
$this->{packformat}="a48" |
638
|
|
|
|
|
|
|
} |
639
|
|
|
|
|
|
|
} |
640
|
2
|
|
|
|
|
3
|
my $length=length($data); |
641
|
2
|
|
|
|
|
4
|
my $expected=$width*$height; |
642
|
2
|
50
|
|
|
|
4
|
if ($length < $width * $height) { |
643
|
0
|
|
|
|
|
0
|
carp("Expected [$expected] bits, got [$length] bits...padding ". |
644
|
|
|
|
|
|
|
"data with zeros"); |
645
|
0
|
|
|
|
|
0
|
$data.="0"x($expected-$length); |
646
|
|
|
|
|
|
|
} |
647
|
2
|
50
|
|
|
|
7
|
my $padding=$width%$tilesize?$tilesize-($width % $tilesize):0; |
648
|
2
|
|
|
|
|
2
|
my $newwidth=$width+$padding; |
649
|
|
|
|
|
|
|
# pad the image width to an equal multiple of the tilesize |
650
|
2
|
|
|
|
|
52
|
my $tiles=ceil($width/$tilesize); |
651
|
2
|
|
|
|
|
5
|
my $final; |
652
|
2
|
|
|
|
|
6
|
foreach my $tile (1..$tiles) { |
653
|
3
|
|
|
|
|
5
|
foreach my $row (1..$tilesize) { |
654
|
48
|
|
|
|
|
55
|
my $rowstart=($row-1)*($width); |
655
|
48
|
|
|
|
|
54
|
my $offset=$rowstart+(($tile-1)*$tilesize); |
656
|
48
|
|
|
|
|
40
|
my $chunk; |
657
|
48
|
|
|
|
|
48
|
my $chunkstart=(($tile-1) * $tilesize); |
658
|
48
|
|
|
|
|
47
|
my $chunkend=$chunkstart+($tilesize); |
659
|
48
|
50
|
|
|
|
66
|
if ($row <= $height) { |
660
|
48
|
50
|
|
|
|
65
|
if ($chunkend <= $width) { |
661
|
48
|
|
|
|
|
68
|
$chunk=substr($data,$offset,$tilesize); |
662
|
|
|
|
|
|
|
} else { |
663
|
0
|
|
|
|
|
0
|
$chunk=substr($data,$offset,$width-$chunkstart); |
664
|
0
|
|
|
|
|
0
|
$chunk.="0"x($tilesize-length($chunk)); |
665
|
|
|
|
|
|
|
} |
666
|
|
|
|
|
|
|
} else { |
667
|
0
|
|
|
|
|
0
|
$chunk="0"x($tilesize); |
668
|
|
|
|
|
|
|
} |
669
|
|
|
|
|
|
|
#print "chunk [$chunk]\n"; |
670
|
48
|
|
|
|
|
117
|
$final.=pack("B16",$chunk); |
671
|
|
|
|
|
|
|
} |
672
|
|
|
|
|
|
|
} |
673
|
2
|
|
|
|
|
17
|
$this->setmsg(data => $final); |
674
|
|
|
|
|
|
|
} |
675
|
|
|
|
|
|
|
sub setmsg { |
676
|
2
|
|
|
2
|
|
4
|
my $this = shift; |
677
|
2
|
|
|
|
|
6
|
my %params = @_; |
678
|
2
|
|
|
|
|
5
|
my $data=$params{data}; |
679
|
2
|
|
|
|
|
5
|
my $devicetype=$this->{devicetype}; |
680
|
2
|
|
|
|
|
4
|
my $objtype=$this->{objtype}; |
681
|
2
|
|
|
|
|
4
|
my $msgref; |
682
|
2
|
|
|
|
|
58
|
my $factory=$this->factory; |
683
|
2
|
|
|
|
|
7
|
my $format=$this->{packformat}; |
684
|
2
|
|
|
|
|
10
|
foreach my $chunk (unpack("($format)*",$data)) { |
685
|
2
|
|
|
|
|
8
|
$msgref.=$factory->add_chunk(chunk => $chunk, type => $objtype); |
686
|
|
|
|
|
|
|
} |
687
|
2
|
100
|
|
|
|
10
|
if ($objtype eq "pixmap") { |
|
|
50
|
|
|
|
|
|
688
|
1
|
|
|
|
|
4
|
$factory->store_pixtag($this->get_pixtag,$msgref); |
689
|
|
|
|
|
|
|
} elsif ($objtype eq "icon") { |
690
|
1
|
|
|
|
|
4
|
$factory->store_icontag($this->get_icontag,$msgref); |
691
|
|
|
|
|
|
|
} |
692
|
|
|
|
|
|
|
} |
693
|
|
|
|
|
|
|
# |
694
|
|
|
|
|
|
|
# object to hold a pixmap and it's associated data and parameters |
695
|
|
|
|
|
|
|
# |
696
|
|
|
|
|
|
|
package Device::MiniLED::Pixmap; |
697
|
2
|
|
|
2
|
|
2197
|
use Carp; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
207
|
|
698
|
|
|
|
|
|
|
our @ISA= qw (Device::MiniLED::Image); |
699
|
|
|
|
|
|
|
our @CARP_NOT = qw(Device::MiniLED); |
700
|
2
|
|
|
2
|
|
14
|
use Carp; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
1290
|
|
701
|
|
|
|
|
|
|
sub new { |
702
|
1
|
|
|
1
|
|
2
|
my $that = shift; |
703
|
1
|
|
33
|
|
|
5
|
my $class = ref($that) || $that; |
704
|
1
|
|
|
|
|
4
|
my %params=@_; |
705
|
1
|
|
|
|
|
15
|
my $this = Device::MiniLED::Image->new(%params); |
706
|
1
|
|
|
|
|
3
|
$this->{'objtype'}='pixmap'; |
707
|
|
|
|
|
|
|
# fix - my(%params) = @_; |
708
|
1
|
|
|
|
|
2
|
foreach my $key (keys(%params)) { |
709
|
5
|
|
|
|
|
8
|
$this->{$key}=$params{$key}; |
710
|
|
|
|
|
|
|
} |
711
|
1
|
50
|
|
|
|
4
|
if (!defined($this->{height})) { |
712
|
0
|
|
|
|
|
0
|
croak("Height must exist,and be 1 or greater"); |
713
|
0
|
|
|
|
|
0
|
return undef; |
714
|
|
|
|
|
|
|
} |
715
|
1
|
50
|
33
|
|
|
10
|
if (defined($this->{height}) && $this->{height} < 1 ) { |
716
|
0
|
|
|
|
|
0
|
croak("Height must be greater than 1"); |
717
|
0
|
|
|
|
|
0
|
return undef; |
718
|
|
|
|
|
|
|
} |
719
|
1
|
50
|
|
|
|
3
|
if (!defined($this->{width})) { |
720
|
0
|
|
|
|
|
0
|
croak("Width must exist,and be between 1 and 256"); |
721
|
0
|
|
|
|
|
0
|
return undef; |
722
|
|
|
|
|
|
|
} |
723
|
1
|
50
|
33
|
|
|
8
|
if (defined($this->{width}) && ( $this->{width} < 1 or $this->{width} > 256)) { |
|
|
|
33
|
|
|
|
|
724
|
0
|
|
|
|
|
0
|
croak("Width must be between 1 and 256"); |
725
|
0
|
|
|
|
|
0
|
return undef; |
726
|
|
|
|
|
|
|
} |
727
|
1
|
50
|
|
|
|
4
|
if (!defined($this->{data})) { |
728
|
0
|
|
|
|
|
0
|
croak("Parameter [data] must be present"); |
729
|
0
|
|
|
|
|
0
|
return undef; |
730
|
|
|
|
|
|
|
} |
731
|
1
|
50
|
|
|
|
4
|
if (!defined($this->{devicetype})) { |
732
|
0
|
|
|
|
|
0
|
croak("Parameter [devicetype] must be present"); |
733
|
0
|
|
|
|
|
0
|
return undef; |
734
|
|
|
|
|
|
|
} |
735
|
1
|
|
|
|
|
5
|
return (bless($this,$class)); |
736
|
|
|
|
|
|
|
} |
737
|
|
|
|
|
|
|
sub get_pixtag { |
738
|
2
|
|
|
2
|
|
4
|
my $this=shift; |
739
|
2
|
|
|
|
|
3
|
my $number=$this->{number}; |
740
|
2
|
|
|
|
|
8
|
return ""; |
741
|
|
|
|
|
|
|
} |
742
|
|
|
|
|
|
|
# |
743
|
|
|
|
|
|
|
# object to hold a icon and it's associated data and parameters |
744
|
|
|
|
|
|
|
# |
745
|
|
|
|
|
|
|
package Device::MiniLED::Icon; |
746
|
2
|
|
|
2
|
|
15
|
use Carp; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
588
|
|
747
|
|
|
|
|
|
|
our @ISA= qw (Device::MiniLED::Image); |
748
|
|
|
|
|
|
|
our @CARP_NOT = qw(Device::MiniLED); |
749
|
|
|
|
|
|
|
sub new { |
750
|
1
|
|
|
1
|
|
2
|
my $that = shift; |
751
|
1
|
|
33
|
|
|
6
|
my $class = ref($that) || $that; |
752
|
1
|
|
|
|
|
4
|
my (%params)=@_; |
753
|
1
|
|
|
|
|
4
|
my $this = Device::MiniLED::Image->new(%params); |
754
|
1
|
|
|
|
|
3
|
$this->{'objtype'}='icon'; |
755
|
1
|
|
|
|
|
2
|
bless $this, $class; |
756
|
1
|
50
|
|
|
|
8
|
if (!defined($this->{data})) { |
757
|
0
|
|
|
|
|
0
|
croak("Parameter [data] must be present"); |
758
|
0
|
|
|
|
|
0
|
return undef; |
759
|
|
|
|
|
|
|
} |
760
|
1
|
50
|
|
|
|
3
|
if (!defined($this->{devicetype})) { |
761
|
0
|
|
|
|
|
0
|
croak("Parameter [devicetype] must be present"); |
762
|
0
|
|
|
|
|
0
|
return undef; |
763
|
|
|
|
|
|
|
} |
764
|
1
|
|
|
|
|
4
|
return (bless($this,$class)); |
765
|
|
|
|
|
|
|
} |
766
|
|
|
|
|
|
|
sub get_icontag { |
767
|
2
|
|
|
2
|
|
3
|
my $this=shift; |
768
|
2
|
|
|
|
|
4
|
my $number=$this->{number}; |
769
|
2
|
|
|
|
|
9
|
return ""; |
770
|
|
|
|
|
|
|
} |
771
|
|
|
|
|
|
|
package Device::MiniLED::Clipart; |
772
|
2
|
|
|
2
|
|
12
|
use Carp; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
2632
|
|
773
|
|
|
|
|
|
|
our @CARP_NOT = qw(Device::MiniLED); |
774
|
|
|
|
|
|
|
sub new { |
775
|
3
|
|
|
3
|
|
12089
|
my $that = shift; |
776
|
3
|
|
33
|
|
|
18
|
my $class = ref($that) || $that; |
777
|
3
|
|
|
|
|
10
|
my(%params) = @_; |
778
|
3
|
|
|
|
|
5
|
my $this = {}; |
779
|
3
|
|
|
|
|
9
|
bless $this, $class; |
780
|
3
|
50
|
|
|
|
16
|
if (!defined($params{type})) { |
781
|
0
|
|
|
|
|
0
|
croak("Parameter [type] must be supplied, valid values are [pix] or [icon]"); |
782
|
0
|
|
|
|
|
0
|
return undef; |
783
|
|
|
|
|
|
|
} |
784
|
3
|
50
|
66
|
|
|
15
|
if ($params{type} ne "pix" and $params{type} ne "icon") { |
785
|
0
|
|
|
|
|
0
|
croak("Parameter [type] invalid, valid values are [pix] or [icon]"); |
786
|
0
|
|
|
|
|
0
|
return undef; |
787
|
|
|
|
|
|
|
} |
788
|
3
|
|
|
|
|
11
|
$this->{type}=$params{type}; |
789
|
3
|
100
|
|
|
|
10
|
if (defined($params{name})) { |
790
|
2
|
|
|
|
|
3
|
$this->{name}=$params{name}; |
791
|
2
|
50
|
|
|
|
12
|
if ( $this->{hashref}=$this->set(name => $params{name}) ) { |
792
|
2
|
|
|
|
|
6
|
return $this; |
793
|
|
|
|
|
|
|
} else { |
794
|
0
|
|
|
|
|
0
|
croak("No clipart named [$params{name}] exists"); |
795
|
0
|
|
|
|
|
0
|
return undef; |
796
|
|
|
|
|
|
|
} |
797
|
|
|
|
|
|
|
} else { |
798
|
1
|
|
|
|
|
5
|
return $this; |
799
|
|
|
|
|
|
|
} |
800
|
|
|
|
|
|
|
} |
801
|
|
|
|
|
|
|
sub data { |
802
|
3
|
|
|
3
|
|
9
|
my $this=shift; |
803
|
3
|
|
|
|
|
5
|
my $hashref=$this->{hashref}; |
804
|
3
|
|
|
|
|
8
|
my $data=$$hashref{'data'}; |
805
|
3
|
|
|
|
|
3
|
my $bits; |
806
|
3
|
|
|
|
|
44
|
foreach my $one (unpack("(A2)*",$data)) { |
807
|
128
|
|
|
|
|
276
|
$bits.=unpack("B8",pack("C",hex($one))); |
808
|
|
|
|
|
|
|
} |
809
|
3
|
|
|
|
|
15
|
my $len=length($bits); |
810
|
3
|
|
|
|
|
14
|
return $bits; |
811
|
|
|
|
|
|
|
} |
812
|
|
|
|
|
|
|
sub width { |
813
|
1
|
|
|
1
|
|
2
|
my $this=shift; |
814
|
1
|
|
|
|
|
2
|
my $hashref=$this->{hashref}; |
815
|
1
|
|
|
|
|
3
|
return $$hashref{'width'}; |
816
|
|
|
|
|
|
|
} |
817
|
|
|
|
|
|
|
sub height { |
818
|
1
|
|
|
1
|
|
2
|
my $this=shift; |
819
|
1
|
|
|
|
|
2
|
my $hashref=$this->{hashref}; |
820
|
1
|
|
|
|
|
11
|
return $$hashref{'height'}; |
821
|
|
|
|
|
|
|
} |
822
|
|
|
|
|
|
|
sub hash { |
823
|
3
|
|
|
3
|
|
6
|
my $this=shift; |
824
|
3
|
|
|
|
|
6
|
my %params=@_; |
825
|
3
|
|
|
|
|
5
|
my $name=$params{name}; |
826
|
3
|
|
|
|
|
163
|
my %CLIPART_PIX = ( |
827
|
|
|
|
|
|
|
zen16 => { |
828
|
|
|
|
|
|
|
width => 16, |
829
|
|
|
|
|
|
|
height => 16, |
830
|
|
|
|
|
|
|
data => |
831
|
|
|
|
|
|
|
'07e00830100820045c067e02733273327f027f863ffc1ff80ff007e000000000' |
832
|
|
|
|
|
|
|
}, |
833
|
|
|
|
|
|
|
zen12 => { |
834
|
|
|
|
|
|
|
width => 12, |
835
|
|
|
|
|
|
|
height => 12, |
836
|
|
|
|
|
|
|
data => |
837
|
|
|
|
|
|
|
'0e00318040404040f120f860dfe07fc07fc03f800e000000' |
838
|
|
|
|
|
|
|
}, |
839
|
|
|
|
|
|
|
cross16 => { |
840
|
|
|
|
|
|
|
width => 16, |
841
|
|
|
|
|
|
|
height => 16, |
842
|
|
|
|
|
|
|
data => |
843
|
|
|
|
|
|
|
'0100010001000100010002800440f83e04400280010001000100010001000100' |
844
|
|
|
|
|
|
|
}, |
845
|
|
|
|
|
|
|
circle16 => { |
846
|
|
|
|
|
|
|
width => 16, |
847
|
|
|
|
|
|
|
height => 16, |
848
|
|
|
|
|
|
|
data => |
849
|
|
|
|
|
|
|
'07e00ff01ff83ffc7ffe7ffe7ffe7ffe7ffe7ffe3ffc1ff80ff007e000000000' |
850
|
|
|
|
|
|
|
}, |
851
|
|
|
|
|
|
|
questionmark12 => { |
852
|
|
|
|
|
|
|
width => 12, |
853
|
|
|
|
|
|
|
height => 12, |
854
|
|
|
|
|
|
|
data => |
855
|
|
|
|
|
|
|
'1f003f8060c060c061800300060006000600000006000600' |
856
|
|
|
|
|
|
|
}, |
857
|
|
|
|
|
|
|
smile12 => { |
858
|
|
|
|
|
|
|
width => 12, |
859
|
|
|
|
|
|
|
height => 12, |
860
|
|
|
|
|
|
|
data => |
861
|
|
|
|
|
|
|
'0e003180404051408020802091204e40404031800e000000' |
862
|
|
|
|
|
|
|
}, |
863
|
|
|
|
|
|
|
phone16 => { |
864
|
|
|
|
|
|
|
width => 16, |
865
|
|
|
|
|
|
|
height => 16, |
866
|
|
|
|
|
|
|
data => |
867
|
|
|
|
|
|
|
'000000003ff8fffee00ee44ee44e0fe0183017d017d037d8600c7ffc00000000' |
868
|
|
|
|
|
|
|
}, |
869
|
|
|
|
|
|
|
rightarrow12 => { |
870
|
|
|
|
|
|
|
width => 12, |
871
|
|
|
|
|
|
|
height => 12, |
872
|
|
|
|
|
|
|
data => |
873
|
|
|
|
|
|
|
'000000000000010001807fc07fe07fc00180010000000000' |
874
|
|
|
|
|
|
|
}, |
875
|
|
|
|
|
|
|
heart12 => { |
876
|
|
|
|
|
|
|
width => 12, |
877
|
|
|
|
|
|
|
height => 12, |
878
|
|
|
|
|
|
|
data => |
879
|
|
|
|
|
|
|
'000071c08a208420802080204040208011000a0004000000' |
880
|
|
|
|
|
|
|
}, |
881
|
|
|
|
|
|
|
heart16 => { |
882
|
|
|
|
|
|
|
width => 16, |
883
|
|
|
|
|
|
|
height => 16, |
884
|
|
|
|
|
|
|
data => |
885
|
|
|
|
|
|
|
'00000000000000000c6012902108202820081010101008200440028001000000' |
886
|
|
|
|
|
|
|
}, |
887
|
|
|
|
|
|
|
square12 => { |
888
|
|
|
|
|
|
|
width => 12, |
889
|
|
|
|
|
|
|
height => 12, |
890
|
|
|
|
|
|
|
data => |
891
|
|
|
|
|
|
|
'fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0' |
892
|
|
|
|
|
|
|
}, |
893
|
|
|
|
|
|
|
handset16 => { |
894
|
|
|
|
|
|
|
width => 16, |
895
|
|
|
|
|
|
|
height => 16, |
896
|
|
|
|
|
|
|
data => |
897
|
|
|
|
|
|
|
'00003c003c003e0006000600060c065006a0075006503e603c003c0000000000' |
898
|
|
|
|
|
|
|
}, |
899
|
|
|
|
|
|
|
leftarrow16 => { |
900
|
|
|
|
|
|
|
width => 16, |
901
|
|
|
|
|
|
|
height => 16, |
902
|
|
|
|
|
|
|
data => |
903
|
|
|
|
|
|
|
'00000000000004000c001c003ff87ff83ff81c000c0004000000000000000000' |
904
|
|
|
|
|
|
|
}, |
905
|
|
|
|
|
|
|
circle12 => { |
906
|
|
|
|
|
|
|
width => 12, |
907
|
|
|
|
|
|
|
height => 12, |
908
|
|
|
|
|
|
|
data => |
909
|
|
|
|
|
|
|
'0e003f807fc07fc0ffe0ffe0ffe07fc07fc03f800e000000' |
910
|
|
|
|
|
|
|
}, |
911
|
|
|
|
|
|
|
questionmark16 => { |
912
|
|
|
|
|
|
|
width => 16, |
913
|
|
|
|
|
|
|
height => 16, |
914
|
|
|
|
|
|
|
data => |
915
|
|
|
|
|
|
|
'000000000fc01fe0303030303030006000c00180030003000000030003000000' |
916
|
|
|
|
|
|
|
}, |
917
|
|
|
|
|
|
|
smile16 => { |
918
|
|
|
|
|
|
|
width => 16, |
919
|
|
|
|
|
|
|
height => 16, |
920
|
|
|
|
|
|
|
data => |
921
|
|
|
|
|
|
|
'07c01830200840044c648c62800280028002882247c440042008183007c00000' |
922
|
|
|
|
|
|
|
}, |
923
|
|
|
|
|
|
|
leftarrow12 => { |
924
|
|
|
|
|
|
|
width => 12, |
925
|
|
|
|
|
|
|
height => 12, |
926
|
|
|
|
|
|
|
data => |
927
|
|
|
|
|
|
|
'000000000000080018003fe07fe03fe01800080000000000' |
928
|
|
|
|
|
|
|
}, |
929
|
|
|
|
|
|
|
rightarrow16 => { |
930
|
|
|
|
|
|
|
width => 16, |
931
|
|
|
|
|
|
|
height => 16, |
932
|
|
|
|
|
|
|
data => |
933
|
|
|
|
|
|
|
'000000000000008000c000e07ff07ff87ff000e000c000800000000000000000' |
934
|
|
|
|
|
|
|
}, |
935
|
|
|
|
|
|
|
music16 => { |
936
|
|
|
|
|
|
|
width => 16, |
937
|
|
|
|
|
|
|
height => 16, |
938
|
|
|
|
|
|
|
data => |
939
|
|
|
|
|
|
|
'000001000180014001200110011001200100010007000f000f000e0000000000' |
940
|
|
|
|
|
|
|
}, |
941
|
|
|
|
|
|
|
phone12 => { |
942
|
|
|
|
|
|
|
width => 12, |
943
|
|
|
|
|
|
|
height => 12, |
944
|
|
|
|
|
|
|
data => |
945
|
|
|
|
|
|
|
'00007fc0ffe0c060c060ca601f0031802e806ec0c060ffe0' |
946
|
|
|
|
|
|
|
}, |
947
|
|
|
|
|
|
|
music12 => { |
948
|
|
|
|
|
|
|
width => 12, |
949
|
|
|
|
|
|
|
height => 12, |
950
|
|
|
|
|
|
|
data => |
951
|
|
|
|
|
|
|
'000008000c000a0009000880088039007800780070000000' |
952
|
|
|
|
|
|
|
}, |
953
|
|
|
|
|
|
|
cross12 => { |
954
|
|
|
|
|
|
|
width => 12, |
955
|
|
|
|
|
|
|
height => 12, |
956
|
|
|
|
|
|
|
data => |
957
|
|
|
|
|
|
|
'04000400040004000a00f1e00a0004000400040004000000' |
958
|
|
|
|
|
|
|
}, |
959
|
|
|
|
|
|
|
handset12 => { |
960
|
|
|
|
|
|
|
width => 12, |
961
|
|
|
|
|
|
|
height => 12, |
962
|
|
|
|
|
|
|
data => |
963
|
|
|
|
|
|
|
'f000f80018001800180018201b401c801940f880f0000000' |
964
|
|
|
|
|
|
|
}, |
965
|
|
|
|
|
|
|
square16 => { |
966
|
|
|
|
|
|
|
width => 16, |
967
|
|
|
|
|
|
|
height => 16, |
968
|
|
|
|
|
|
|
data => |
969
|
|
|
|
|
|
|
'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' |
970
|
|
|
|
|
|
|
}, |
971
|
|
|
|
|
|
|
); |
972
|
3
|
|
|
|
|
170
|
my %CLIPART_ICONS=( |
973
|
|
|
|
|
|
|
cross16 => { |
974
|
|
|
|
|
|
|
width => 32, |
975
|
|
|
|
|
|
|
height => 16, |
976
|
|
|
|
|
|
|
data => |
977
|
|
|
|
|
|
|
'01000100010001000100010001000100010002800280044004400820F83EF01E'. |
978
|
|
|
|
|
|
|
'0440082002800440010002800100010001000100010001000100010001000100' |
979
|
|
|
|
|
|
|
}, |
980
|
|
|
|
|
|
|
heart16 => { |
981
|
|
|
|
|
|
|
width => 32, |
982
|
|
|
|
|
|
|
height => 16, |
983
|
|
|
|
|
|
|
data => |
984
|
|
|
|
|
|
|
'000000000000000000001C70000022880C604104129040242108402420284004'. |
985
|
|
|
|
|
|
|
'2008200810102008101010100820082004400440028002800100010000000000' |
986
|
|
|
|
|
|
|
}, |
987
|
|
|
|
|
|
|
leftarrow16 => { |
988
|
|
|
|
|
|
|
width => 32, |
989
|
|
|
|
|
|
|
height => 16, |
990
|
|
|
|
|
|
|
data => |
991
|
|
|
|
|
|
|
'000000000000000000000000040000000C0004001C000C003FF81C007FF83FF8'. |
992
|
|
|
|
|
|
|
'3FF87FF81C003FF80C001C0004000C0000000400000000000000000000000000' |
993
|
|
|
|
|
|
|
}, |
994
|
|
|
|
|
|
|
rightarrow16 => { |
995
|
|
|
|
|
|
|
width => 32, |
996
|
|
|
|
|
|
|
height => 16, |
997
|
|
|
|
|
|
|
data => |
998
|
|
|
|
|
|
|
'0000000000000000000000000080000000C0008000E000C07FF000E07FF87FF0'. |
999
|
|
|
|
|
|
|
'7FF07FF800E07FF000C000E0008000C000000080000000000000000000000000' |
1000
|
|
|
|
|
|
|
}, |
1001
|
|
|
|
|
|
|
handset16 => { |
1002
|
|
|
|
|
|
|
width => 32, |
1003
|
|
|
|
|
|
|
height => 16, |
1004
|
|
|
|
|
|
|
data => |
1005
|
|
|
|
|
|
|
'000000003C003C003C003C003E003E000600060006000600060C06000650064C'. |
1006
|
|
|
|
|
|
|
'06A006B007500748065006503E603E203C003C003C003C000000000000000000' |
1007
|
|
|
|
|
|
|
}, |
1008
|
|
|
|
|
|
|
phone16 => { |
1009
|
|
|
|
|
|
|
width => 32, |
1010
|
|
|
|
|
|
|
height => 16, |
1011
|
|
|
|
|
|
|
data => |
1012
|
|
|
|
|
|
|
'0000000000003FF83FF8FFFEFFFEE00EE00EE00EE44EE44EE44E04400FE00FE0'. |
1013
|
|
|
|
|
|
|
'1830183017D017D017D017D037D837D8600C600C7FFC7FFC0000000000000000' |
1014
|
|
|
|
|
|
|
}, |
1015
|
|
|
|
|
|
|
smile16 => { |
1016
|
|
|
|
|
|
|
width => 32, |
1017
|
|
|
|
|
|
|
height => 16, |
1018
|
|
|
|
|
|
|
data => |
1019
|
|
|
|
|
|
|
'07C007C01830183020082008400440044C644C648C628C628002800280028002'. |
1020
|
|
|
|
|
|
|
'800290128822983247C44C64400447C4200820081830183007C007C000000000' |
1021
|
|
|
|
|
|
|
}, |
1022
|
|
|
|
|
|
|
circle16 => { |
1023
|
|
|
|
|
|
|
width => 32, |
1024
|
|
|
|
|
|
|
height => 16, |
1025
|
|
|
|
|
|
|
data => |
1026
|
|
|
|
|
|
|
'07E000000FF007E01FF80FF03FFC1FF87FFE3FFC7FFE3FFC7FFE3FFC7FFE3FFC'. |
1027
|
|
|
|
|
|
|
'7FFE3FFC7FFE3FFC3FFC1FF81FF80FF00FF007E007E000000000000000000000' |
1028
|
|
|
|
|
|
|
}, |
1029
|
|
|
|
|
|
|
zen16 => { |
1030
|
|
|
|
|
|
|
width => 32, |
1031
|
|
|
|
|
|
|
height => 16, |
1032
|
|
|
|
|
|
|
data => |
1033
|
|
|
|
|
|
|
'07E00000083007E010080830200410085C0620047E025C0673327E0273327332'. |
1034
|
|
|
|
|
|
|
'7F0273327F867F023FFC7F861FF83FFC0FF01FF807E00FF0000007E000000000' |
1035
|
|
|
|
|
|
|
}, |
1036
|
|
|
|
|
|
|
music16 => { |
1037
|
|
|
|
|
|
|
width => 32, |
1038
|
|
|
|
|
|
|
height => 16, |
1039
|
|
|
|
|
|
|
data => |
1040
|
|
|
|
|
|
|
'0000000001000000018001000140018001200140011001200110011001200110'. |
1041
|
|
|
|
|
|
|
'0100012001000100070007000F000F000F000F000E000E000000000000000000' |
1042
|
|
|
|
|
|
|
}, |
1043
|
|
|
|
|
|
|
questionmark16 => { |
1044
|
|
|
|
|
|
|
width => 32, |
1045
|
|
|
|
|
|
|
height => 16, |
1046
|
|
|
|
|
|
|
data => |
1047
|
|
|
|
|
|
|
'00000000000000000FC000001FE00FC030301FE0303030303030303000600060'. |
1048
|
|
|
|
|
|
|
'00C000C001800180030003000300030000000000030003000300030000000000' |
1049
|
|
|
|
|
|
|
}, |
1050
|
|
|
|
|
|
|
square16 => { |
1051
|
|
|
|
|
|
|
width => 32, |
1052
|
|
|
|
|
|
|
height => 16, |
1053
|
|
|
|
|
|
|
data => |
1054
|
|
|
|
|
|
|
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'. |
1055
|
|
|
|
|
|
|
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' |
1056
|
|
|
|
|
|
|
}, |
1057
|
|
|
|
|
|
|
cross12 => { |
1058
|
|
|
|
|
|
|
width => 24, |
1059
|
|
|
|
|
|
|
height => 12, |
1060
|
|
|
|
|
|
|
data => |
1061
|
|
|
|
|
|
|
'0400400400400400400400a00a0110f1ee0e'. |
1062
|
|
|
|
|
|
|
'0a01100400a0040040040040040040000000' |
1063
|
|
|
|
|
|
|
}, |
1064
|
|
|
|
|
|
|
heart12 => { |
1065
|
|
|
|
|
|
|
width => 24, |
1066
|
|
|
|
|
|
|
height => 12, |
1067
|
|
|
|
|
|
|
data => |
1068
|
|
|
|
|
|
|
'00000071c0008a200084271c8028a2802842'. |
1069
|
|
|
|
|
|
|
'4044042082081101100a00a0040040000000' |
1070
|
|
|
|
|
|
|
}, |
1071
|
|
|
|
|
|
|
leftarrow12 => { |
1072
|
|
|
|
|
|
|
width => 24, |
1073
|
|
|
|
|
|
|
height => 12, |
1074
|
|
|
|
|
|
|
data => |
1075
|
|
|
|
|
|
|
'0000000000000001000803001807fc3feffc'. |
1076
|
|
|
|
|
|
|
'7fe7fc3fe300180100080000000000000000' |
1077
|
|
|
|
|
|
|
}, |
1078
|
|
|
|
|
|
|
rightarrow12 => { |
1079
|
|
|
|
|
|
|
width => 24, |
1080
|
|
|
|
|
|
|
height => 12, |
1081
|
|
|
|
|
|
|
data => |
1082
|
|
|
|
|
|
|
'000000000000000020010030018ff87fcffc'. |
1083
|
|
|
|
|
|
|
'7feff87fc030018020010000000000000000' |
1084
|
|
|
|
|
|
|
}, |
1085
|
|
|
|
|
|
|
handset12 => { |
1086
|
|
|
|
|
|
|
width => 24, |
1087
|
|
|
|
|
|
|
height => 12, |
1088
|
|
|
|
|
|
|
data => |
1089
|
|
|
|
|
|
|
'f00f00f80f80180180180180180182182194'. |
1090
|
|
|
|
|
|
|
'1b41a81c81d4194188f88f80f00f00000000' |
1091
|
|
|
|
|
|
|
}, |
1092
|
|
|
|
|
|
|
phone12 => { |
1093
|
|
|
|
|
|
|
width => 24, |
1094
|
|
|
|
|
|
|
height => 12, |
1095
|
|
|
|
|
|
|
data => |
1096
|
|
|
|
|
|
|
'0000007fc000ffe7fcc06ffec06c06ca6ca6'. |
1097
|
|
|
|
|
|
|
'1f01f03183182e82e86ec6ecc06c06ffeffe' |
1098
|
|
|
|
|
|
|
}, |
1099
|
|
|
|
|
|
|
smile12 => { |
1100
|
|
|
|
|
|
|
width => 24, |
1101
|
|
|
|
|
|
|
height => 12, |
1102
|
|
|
|
|
|
|
data => |
1103
|
|
|
|
|
|
|
'0e00e0318318404404514514802802802802'. |
1104
|
|
|
|
|
|
|
'9129b24e44444044043183180e00e0000000' |
1105
|
|
|
|
|
|
|
}, |
1106
|
|
|
|
|
|
|
circle12 => { |
1107
|
|
|
|
|
|
|
width => 24, |
1108
|
|
|
|
|
|
|
height => 12, |
1109
|
|
|
|
|
|
|
data => |
1110
|
|
|
|
|
|
|
'0e00003f80e07fc3f87fc3f8ffe7fcffe7fc'. |
1111
|
|
|
|
|
|
|
'ffe7fc7fc3f87fc3f83f80e00e0000000000' |
1112
|
|
|
|
|
|
|
}, |
1113
|
|
|
|
|
|
|
zen12 => { |
1114
|
|
|
|
|
|
|
width => 24, |
1115
|
|
|
|
|
|
|
height => 12, |
1116
|
|
|
|
|
|
|
data => |
1117
|
|
|
|
|
|
|
'0e00003180e0404318404404f12404f86f12'. |
1118
|
|
|
|
|
|
|
'dfef867fcdfe7fc7fc3f87fc0e03f80000e0' |
1119
|
|
|
|
|
|
|
}, |
1120
|
|
|
|
|
|
|
music12 => { |
1121
|
|
|
|
|
|
|
width => 24, |
1122
|
|
|
|
|
|
|
height => 12, |
1123
|
|
|
|
|
|
|
data => |
1124
|
|
|
|
|
|
|
'0000000801000c01800a0140090120088120'. |
1125
|
|
|
|
|
|
|
'088120390740780f00780f00700e00000000' |
1126
|
|
|
|
|
|
|
}, |
1127
|
|
|
|
|
|
|
questionmark12 => { |
1128
|
|
|
|
|
|
|
width => 24, |
1129
|
|
|
|
|
|
|
height => 12, |
1130
|
|
|
|
|
|
|
data => |
1131
|
|
|
|
|
|
|
'1f00003f81e060c3f060c618618618030630'. |
1132
|
|
|
|
|
|
|
'0600600600c00600c00000000600c00600c0' |
1133
|
|
|
|
|
|
|
}, |
1134
|
|
|
|
|
|
|
square12 => { |
1135
|
|
|
|
|
|
|
width => 24, |
1136
|
|
|
|
|
|
|
height => 12, |
1137
|
|
|
|
|
|
|
data => |
1138
|
|
|
|
|
|
|
'ffffffffffffffffffffffffffffffffffff'. |
1139
|
|
|
|
|
|
|
'ffffffffffffffffffffffffffffffffffff' |
1140
|
|
|
|
|
|
|
} |
1141
|
|
|
|
|
|
|
|
1142
|
|
|
|
|
|
|
); |
1143
|
3
|
100
|
|
|
|
20
|
if ($this->{type} eq "icon") { |
|
|
50
|
|
|
|
|
|
1144
|
1
|
|
|
|
|
19
|
return %CLIPART_ICONS; |
1145
|
|
|
|
|
|
|
} elsif ($this->{type} eq "pix") { |
1146
|
2
|
|
|
|
|
53
|
return %CLIPART_PIX; |
1147
|
|
|
|
|
|
|
} |
1148
|
|
|
|
|
|
|
} |
1149
|
|
|
|
|
|
|
sub list { |
1150
|
0
|
|
|
0
|
|
0
|
my $this=shift; |
1151
|
0
|
|
|
|
|
0
|
my %HASH=$this->hash; |
1152
|
0
|
|
|
|
|
0
|
return keys(%HASH); |
1153
|
|
|
|
|
|
|
} |
1154
|
|
|
|
|
|
|
sub set { |
1155
|
3
|
|
|
3
|
|
9
|
my $this=shift; |
1156
|
3
|
|
|
|
|
6
|
my %params=@_; |
1157
|
3
|
|
|
|
|
5
|
my $name=$params{name}; |
1158
|
3
|
|
|
|
|
5
|
my $type=$this->{type}; |
1159
|
3
|
|
|
|
|
10
|
my %HASH=$this->hash; |
1160
|
3
|
50
|
|
|
|
25
|
if (exists($HASH{$name})) { |
1161
|
3
|
|
|
|
|
44
|
$this->{hashref}=$HASH{$name}; |
1162
|
|
|
|
|
|
|
} |
1163
|
|
|
|
|
|
|
} |
1164
|
|
|
|
|
|
|
|
1165
|
|
|
|
|
|
|
package Device::MiniLED::SerialTest; |
1166
|
2
|
|
|
2
|
|
17
|
use Carp; |
|
2
|
|
|
|
|
12
|
|
|
2
|
|
|
|
|
759
|
|
1167
|
|
|
|
|
|
|
sub new { |
1168
|
1
|
|
|
1
|
|
3
|
my $that = shift; |
1169
|
1
|
|
33
|
|
|
7
|
my $class = ref($that) || $that; |
1170
|
1
|
|
|
|
|
3
|
my(%params) = @_; |
1171
|
1
|
|
|
|
|
2
|
my $this = {}; |
1172
|
1
|
|
|
|
|
2
|
bless $this, $class; |
1173
|
1
|
|
|
|
|
9
|
$this->{data}=''; |
1174
|
1
|
|
|
|
|
4
|
return $this; |
1175
|
|
|
|
|
|
|
} |
1176
|
|
|
|
|
|
|
sub connect { |
1177
|
0
|
|
|
0
|
|
0
|
my $this=shift; |
1178
|
0
|
|
|
|
|
0
|
$this->{data}=''; |
1179
|
|
|
|
|
|
|
} |
1180
|
|
|
|
|
|
|
sub write { |
1181
|
16
|
|
|
16
|
|
60
|
my $this=shift; |
1182
|
16
|
|
|
|
|
79
|
for (@_) { |
1183
|
16
|
|
|
|
|
182
|
$this->{data}.=$_; |
1184
|
|
|
|
|
|
|
} |
1185
|
|
|
|
|
|
|
} |
1186
|
|
|
|
|
|
|
sub dump { |
1187
|
1
|
|
|
1
|
|
5
|
my $this=shift; |
1188
|
1
|
|
|
|
|
36
|
return $this->{data}; |
1189
|
|
|
|
|
|
|
} |
1190
|
|
|
|
|
|
|
|
1191
|
|
|
|
|
|
|
1; |
1192
|
|
|
|
|
|
|
|
1193
|
|
|
|
|
|
|
=head1 NAME |
1194
|
|
|
|
|
|
|
|
1195
|
|
|
|
|
|
|
Device::MiniLED - send text and graphics to small LED badges and signs |
1196
|
|
|
|
|
|
|
|
1197
|
|
|
|
|
|
|
=head1 VERSION |
1198
|
|
|
|
|
|
|
|
1199
|
|
|
|
|
|
|
Version 1.03 |
1200
|
|
|
|
|
|
|
|
1201
|
|
|
|
|
|
|
=head1 SYNOPSIS |
1202
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
use Device::MiniLED; |
1204
|
|
|
|
|
|
|
my $sign=Device::MiniLED->new(devicetype => "sign"); |
1205
|
|
|
|
|
|
|
# |
1206
|
|
|
|
|
|
|
# add a text only message |
1207
|
|
|
|
|
|
|
# |
1208
|
|
|
|
|
|
|
$sign->addMsg( |
1209
|
|
|
|
|
|
|
data => "Just a normal test message", |
1210
|
|
|
|
|
|
|
effect => "scroll", |
1211
|
|
|
|
|
|
|
speed => 4 |
1212
|
|
|
|
|
|
|
); |
1213
|
|
|
|
|
|
|
# |
1214
|
|
|
|
|
|
|
# create a picture and an icon from built-in clipart |
1215
|
|
|
|
|
|
|
# |
1216
|
|
|
|
|
|
|
my $pic=$sign->addPix(clipart => "zen16"); |
1217
|
|
|
|
|
|
|
my $icon=$sign->addIcon(clipart => "heart16"); |
1218
|
|
|
|
|
|
|
# |
1219
|
|
|
|
|
|
|
# add a message with the picture and animated icon we just created |
1220
|
|
|
|
|
|
|
# |
1221
|
|
|
|
|
|
|
$sign->addMsg( |
1222
|
|
|
|
|
|
|
data => "Message 2 with a picture: $pic and an icon: $icon", |
1223
|
|
|
|
|
|
|
effect => "scroll", |
1224
|
|
|
|
|
|
|
speed => 3 |
1225
|
|
|
|
|
|
|
); |
1226
|
|
|
|
|
|
|
$sign->send(device => "COM3"); |
1227
|
|
|
|
|
|
|
|
1228
|
|
|
|
|
|
|
=head1 DESCRIPTION |
1229
|
|
|
|
|
|
|
|
1230
|
|
|
|
|
|
|
Device::MiniLED is used to send text and graphics via RS232 to our smaller set of LED Signs and badges. |
1231
|
|
|
|
|
|
|
|
1232
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
1233
|
|
|
|
|
|
|
|
1234
|
|
|
|
|
|
|
=head2 new |
1235
|
|
|
|
|
|
|
|
1236
|
|
|
|
|
|
|
my $sign=Device::MiniLED->new( |
1237
|
|
|
|
|
|
|
devicetype => $devicetype |
1238
|
|
|
|
|
|
|
); |
1239
|
|
|
|
|
|
|
# $devicetype can be either: |
1240
|
|
|
|
|
|
|
# sign - denoting a device with a 16 pixel high display |
1241
|
|
|
|
|
|
|
# badge - denoting a device with a 12 pixel high display |
1242
|
|
|
|
|
|
|
|
1243
|
|
|
|
|
|
|
=head1 METHODS |
1244
|
|
|
|
|
|
|
|
1245
|
|
|
|
|
|
|
=head2 $sign->addMsg |
1246
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
This family of devices support a maximum of 8 messages that can be sent to the sign. These messages can consist of three different types of content, which can be mixed together in the same message..plain text, pixmap images, and 2-frame anmiated icons. |
1248
|
|
|
|
|
|
|
|
1249
|
|
|
|
|
|
|
The $sign->addMsg method has one required argument, data, It also has three optional arguments: effect, speed, and slot. |
1250
|
|
|
|
|
|
|
|
1251
|
|
|
|
|
|
|
=over 4 |
1252
|
|
|
|
|
|
|
|
1253
|
|
|
|
|
|
|
=item |
1254
|
|
|
|
|
|
|
B: (required) The data to be sent to the sign. Plain text, optionally with tags for fonts and $variables that reference pixmap images or animated icons. |
1255
|
|
|
|
|
|
|
|
1256
|
|
|
|
|
|
|
=over |
1257
|
|
|
|
|
|
|
|
1258
|
|
|
|
|
|
|
=item |
1259
|
|
|
|
|
|
|
B: You can insert a font tag to create flashing text. The supported tags are <f:normal> and <f:flash>. On the badges, these tags work as expected. On the signs, either flag is actually just a toggle back and forth from flashing to normal. If you use them in the right order, you won't notice. For example: |
1260
|
|
|
|
|
|
|
$sign->addMsg( |
1261
|
|
|
|
|
|
|
data => "Some flashing text. Neat, right?" |
1262
|
|
|
|
|
|
|
); |
1263
|
|
|
|
|
|
|
|
1264
|
|
|
|
|
|
|
=back |
1265
|
|
|
|
|
|
|
|
1266
|
|
|
|
|
|
|
=item |
1267
|
|
|
|
|
|
|
B: (optional, defaults to "scroll") One of "hold", "scroll", "snow", "flash" or "hold+flash" |
1268
|
|
|
|
|
|
|
|
1269
|
|
|
|
|
|
|
=item |
1270
|
|
|
|
|
|
|
B: (optional, defaults to "4") An integer from 1 to 5, where 1 is the slowest and 5 is the fastest |
1271
|
|
|
|
|
|
|
|
1272
|
|
|
|
|
|
|
=item |
1273
|
|
|
|
|
|
|
B: (optional) An integer from 1 to 8, representing the message slots in the sign. If you don't supply this, it will assign slot numbers automatically, in ascending order. |
1274
|
|
|
|
|
|
|
|
1275
|
|
|
|
|
|
|
=back |
1276
|
|
|
|
|
|
|
|
1277
|
|
|
|
|
|
|
The addMsg method returns a number that indicates how many messages have been created. This may be helpful to ensure you don't try to add a 9th message, which will fail: |
1278
|
|
|
|
|
|
|
|
1279
|
|
|
|
|
|
|
my $sign=Device::MiniLED->new(devicetype => "sign"); |
1280
|
|
|
|
|
|
|
for (1..9) { |
1281
|
|
|
|
|
|
|
my $number=$sign->addMsg( |
1282
|
|
|
|
|
|
|
data => "Message number $_", |
1283
|
|
|
|
|
|
|
effect => "scroll", |
1284
|
|
|
|
|
|
|
speed => 5 |
1285
|
|
|
|
|
|
|
); |
1286
|
|
|
|
|
|
|
# on the ninth loop, $number will be undef, and a warning will be |
1287
|
|
|
|
|
|
|
# generated |
1288
|
|
|
|
|
|
|
} |
1289
|
|
|
|
|
|
|
|
1290
|
|
|
|
|
|
|
Assigning slots manually |
1291
|
|
|
|
|
|
|
|
1292
|
|
|
|
|
|
|
my $sign=Device::MiniLED->new(devicetype => "sign"); |
1293
|
|
|
|
|
|
|
$sign->addMsg( |
1294
|
|
|
|
|
|
|
data => "A msg in slot 3", |
1295
|
|
|
|
|
|
|
slot => 3 |
1296
|
|
|
|
|
|
|
); |
1297
|
|
|
|
|
|
|
$sign->addMsg( |
1298
|
|
|
|
|
|
|
data => "A msg in slot 1", |
1299
|
|
|
|
|
|
|
slot => 1 |
1300
|
|
|
|
|
|
|
); |
1301
|
|
|
|
|
|
|
$sign->addMsg( |
1302
|
|
|
|
|
|
|
data => "A msg in slot 5", |
1303
|
|
|
|
|
|
|
slot => 5 |
1304
|
|
|
|
|
|
|
); |
1305
|
|
|
|
|
|
|
# even though we loaded a message in slot 3, the use of "showslots" |
1306
|
|
|
|
|
|
|
# below means that only the messages in slots 1 and 5 will be displayed |
1307
|
|
|
|
|
|
|
$sign->send( |
1308
|
|
|
|
|
|
|
device => "/dev/ttyUSB0", |
1309
|
|
|
|
|
|
|
showslots => "1,5" |
1310
|
|
|
|
|
|
|
); |
1311
|
|
|
|
|
|
|
# sleep for a minute... |
1312
|
|
|
|
|
|
|
sleep(60); |
1313
|
|
|
|
|
|
|
# now we'll have the sign show just what's in slot number 3. |
1314
|
|
|
|
|
|
|
$sign->send( |
1315
|
|
|
|
|
|
|
device => "/dev/ttyUSB0", |
1316
|
|
|
|
|
|
|
showslots => "3" |
1317
|
|
|
|
|
|
|
); |
1318
|
|
|
|
|
|
|
# |
1319
|
|
|
|
|
|
|
# note: if the sign already has messages in a slot, you can have a script |
1320
|
|
|
|
|
|
|
# that does nothing other than $sign->send (with the showslots parameter) |
1321
|
|
|
|
|
|
|
# to select which of them to display on the sign. |
1322
|
|
|
|
|
|
|
# |
1323
|
|
|
|
|
|
|
# for example, you could preload messages in slots 1 through 7, with message |
1324
|
|
|
|
|
|
|
# 1 being "Happy Monday", 2 being "Happy Tuesday", and so forth. |
1325
|
|
|
|
|
|
|
# Then, on monday morning, your script could send: |
1326
|
|
|
|
|
|
|
# run $sign->send(device => 'COM1', showslots => "1"), and just the monday |
1327
|
|
|
|
|
|
|
# message would display on the sign |
1328
|
|
|
|
|
|
|
# |
1329
|
|
|
|
|
|
|
# For unknown reasons, however, the message slot selection buttons on the |
1330
|
|
|
|
|
|
|
# sign itself won't show stored messages. They are there, and will be |
1331
|
|
|
|
|
|
|
# displayed if you use the showslots parameter in $sign->send. |
1332
|
|
|
|
|
|
|
# |
1333
|
|
|
|
|
|
|
|
1334
|
|
|
|
|
|
|
=head2 $sign->addPix |
1335
|
|
|
|
|
|
|
|
1336
|
|
|
|
|
|
|
The addPix method allow you to create simple, single color pixmaps that can be inserted into a message. There are two ways to create a picture. |
1337
|
|
|
|
|
|
|
|
1338
|
|
|
|
|
|
|
B |
1339
|
|
|
|
|
|
|
|
1340
|
|
|
|
|
|
|
# |
1341
|
|
|
|
|
|
|
# load the built-in piece of clipart named phone16 |
1342
|
|
|
|
|
|
|
# the "16" is hinting that it's 16 pixels high, and thus better suited to |
1343
|
|
|
|
|
|
|
# a 16 pixel high device, and not a 12 pixel high device |
1344
|
|
|
|
|
|
|
# |
1345
|
|
|
|
|
|
|
my $pic=$sign->addPix( |
1346
|
|
|
|
|
|
|
clipart => "phone16" |
1347
|
|
|
|
|
|
|
); |
1348
|
|
|
|
|
|
|
# now use that in a message |
1349
|
|
|
|
|
|
|
$sign->addMsg( |
1350
|
|
|
|
|
|
|
data => "here is a phone: $pic", |
1351
|
|
|
|
|
|
|
); |
1352
|
|
|
|
|
|
|
|
1353
|
|
|
|
|
|
|
B |
1354
|
|
|
|
|
|
|
|
1355
|
|
|
|
|
|
|
To supply your own pictures, you need to supply 3 arguments: |
1356
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
B: height of the picture in pixels |
1358
|
|
|
|
|
|
|
|
1359
|
|
|
|
|
|
|
B: width of the picture in pixels (max is 256) |
1360
|
|
|
|
|
|
|
|
1361
|
|
|
|
|
|
|
B : a string of 1's and 0's, where the 1 will light up the pixel and |
1362
|
|
|
|
|
|
|
a 0 won't. You might find Image::Pbm and it's $image->as_bitstring method |
1363
|
|
|
|
|
|
|
helpful in generating these strings. |
1364
|
|
|
|
|
|
|
|
1365
|
|
|
|
|
|
|
# make a 5x5 pixel outlined box |
1366
|
|
|
|
|
|
|
my $pic=$sign->addPix( |
1367
|
|
|
|
|
|
|
height => 5, |
1368
|
|
|
|
|
|
|
width => 5, |
1369
|
|
|
|
|
|
|
data => |
1370
|
|
|
|
|
|
|
"11111". |
1371
|
|
|
|
|
|
|
"10001". |
1372
|
|
|
|
|
|
|
"10001". |
1373
|
|
|
|
|
|
|
"10001". |
1374
|
|
|
|
|
|
|
"11111" |
1375
|
|
|
|
|
|
|
); |
1376
|
|
|
|
|
|
|
# now use that in a message |
1377
|
|
|
|
|
|
|
$sign->addMsg( |
1378
|
|
|
|
|
|
|
data => "here is a 5 pixel box outline: $pic", |
1379
|
|
|
|
|
|
|
); |
1380
|
|
|
|
|
|
|
|
1381
|
|
|
|
|
|
|
|
1382
|
|
|
|
|
|
|
=head2 $sign->addIcon |
1383
|
|
|
|
|
|
|
|
1384
|
|
|
|
|
|
|
The $sign->addIcon method is almost identical to the $sign->addPix method. |
1385
|
|
|
|
|
|
|
The addIcon method accepts either a 16x32 pixel image (for signs), or a |
1386
|
|
|
|
|
|
|
12x24 pixel image (for badges). It internally splits the image down the middle |
1387
|
|
|
|
|
|
|
into a left and right halves, each one being 16x16 (or 12x12) pixels. |
1388
|
|
|
|
|
|
|
|
1389
|
|
|
|
|
|
|
Then, when displayed on the sign, it alternates between the two, in place, |
1390
|
|
|
|
|
|
|
creating a simple animation. |
1391
|
|
|
|
|
|
|
|
1392
|
|
|
|
|
|
|
# make an icon using the built-in heart16 clipart |
1393
|
|
|
|
|
|
|
my $icon=$sign->addIcon( |
1394
|
|
|
|
|
|
|
clipart => "heart16" |
1395
|
|
|
|
|
|
|
); |
1396
|
|
|
|
|
|
|
# now use that in a message |
1397
|
|
|
|
|
|
|
$sign->addMsg( |
1398
|
|
|
|
|
|
|
data => "Animated heart icon: $icon", |
1399
|
|
|
|
|
|
|
); |
1400
|
|
|
|
|
|
|
|
1401
|
|
|
|
|
|
|
You can "roll your own" icons as well. |
1402
|
|
|
|
|
|
|
|
1403
|
|
|
|
|
|
|
# make an animated icon that alternates between a big box and a small box |
1404
|
|
|
|
|
|
|
my $sign=Device::MiniLED->new(devicetype => "sign"); |
1405
|
|
|
|
|
|
|
my $icon16x32= |
1406
|
|
|
|
|
|
|
"XXXXXXXXXXXXXXXX" . "----------------" . |
1407
|
|
|
|
|
|
|
"X--------------X" . "----------------" . |
1408
|
|
|
|
|
|
|
"X--------------X" . "--XXXXXXXXXXX---" . |
1409
|
|
|
|
|
|
|
"X--------------X" . "--X---------X---" . |
1410
|
|
|
|
|
|
|
"X--------------X" . "--X---------X---" . |
1411
|
|
|
|
|
|
|
"X--------------X" . "--X---------X---" . |
1412
|
|
|
|
|
|
|
"X--------------X" . "--X---------X---" . |
1413
|
|
|
|
|
|
|
"X--------------X" . "--X---------X---" . |
1414
|
|
|
|
|
|
|
"X--------------X" . "--X---------X---" . |
1415
|
|
|
|
|
|
|
"X--------------X" . "--X---------X---" . |
1416
|
|
|
|
|
|
|
"X--------------X" . "--X---------X---" . |
1417
|
|
|
|
|
|
|
"X--------------X" . "--X---------X---" . |
1418
|
|
|
|
|
|
|
"X--------------X" . "--X---------X---" . |
1419
|
|
|
|
|
|
|
"X--------------X" . "--XXXXXXXXXXX---" . |
1420
|
|
|
|
|
|
|
"X--------------X" . "----------------" . |
1421
|
|
|
|
|
|
|
"XXXXXXXXXXXXXXXX" . "----------------"; |
1422
|
|
|
|
|
|
|
# translate X to 1, and - to 0 |
1423
|
|
|
|
|
|
|
$icon16x32=~tr/X-/10/; |
1424
|
|
|
|
|
|
|
# no need to specify width or height, as |
1425
|
|
|
|
|
|
|
# it assumes 16x32 if $sign is devicetype "sign", |
1426
|
|
|
|
|
|
|
# and assumes 12x24 if $sign |
1427
|
|
|
|
|
|
|
my $icon=$sign->addIcon( |
1428
|
|
|
|
|
|
|
data => $icon16x32 |
1429
|
|
|
|
|
|
|
); |
1430
|
|
|
|
|
|
|
$sign->addMsg( |
1431
|
|
|
|
|
|
|
data => "Flashing Icon: [$icon]" |
1432
|
|
|
|
|
|
|
); |
1433
|
|
|
|
|
|
|
|
1434
|
|
|
|
|
|
|
=head2 $sign->send |
1435
|
|
|
|
|
|
|
|
1436
|
|
|
|
|
|
|
The send method connects to the sign over RS232 and sends all the data accumulated from prior use of the $sign->addMsg method. The only mandatory argument is 'device', denoting which serial device to send to. |
1437
|
|
|
|
|
|
|
|
1438
|
|
|
|
|
|
|
It supports three optional arguments, showslots, baudrate and packetdelay: |
1439
|
|
|
|
|
|
|
|
1440
|
|
|
|
|
|
|
=over 4 |
1441
|
|
|
|
|
|
|
|
1442
|
|
|
|
|
|
|
=item |
1443
|
|
|
|
|
|
|
B: |
1444
|
|
|
|
|
|
|
A string that is a comma separated list of the slot numbers that you want to display on the sign. If you omit this, it will display the messages you just added with addMsg. If you supply a null string, then the sign will continue to display whatever slots it is currently displaying. |
1445
|
|
|
|
|
|
|
|
1446
|
|
|
|
|
|
|
=item |
1447
|
|
|
|
|
|
|
B: |
1448
|
|
|
|
|
|
|
defaults to 38400, no real reason to use something other than the default, but it's there if you feel the need. Must be a value that Device::Serialport or Win32::Serialport thinks is valid |
1449
|
|
|
|
|
|
|
|
1450
|
|
|
|
|
|
|
=item |
1451
|
|
|
|
|
|
|
B: An amount of time, in seconds, to wait, between sending packets to the sign. The default is 0.20. If you see "XX" displayed on your sign while sending data, increasing this value may help. Must be greater than zero. |
1452
|
|
|
|
|
|
|
|
1453
|
|
|
|
|
|
|
=over |
1454
|
|
|
|
|
|
|
|
1455
|
|
|
|
|
|
|
=item |
1456
|
|
|
|
|
|
|
B: For reference, each text message generates 3 packets, and each 16x32 portion of an image sends one packet. There's also an additional, short, packet sent after all message and image packets are delivered. So, if you make packetdelay a large number...and have lots of text and/or images, you may be waiting a while to send all the data. Similarly, you may get some milage out of using a number smaller than the default, provided you don't see 'XX' displayed on the sign while sending. |
1457
|
|
|
|
|
|
|
|
1458
|
|
|
|
|
|
|
=back |
1459
|
|
|
|
|
|
|
|
1460
|
|
|
|
|
|
|
=back |
1461
|
|
|
|
|
|
|
|
1462
|
|
|
|
|
|
|
Examples of using $sign->send |
1463
|
|
|
|
|
|
|
|
1464
|
|
|
|
|
|
|
# typical use on a windows machine |
1465
|
|
|
|
|
|
|
$sign->send( |
1466
|
|
|
|
|
|
|
device => "COM4" |
1467
|
|
|
|
|
|
|
); |
1468
|
|
|
|
|
|
|
# typical use on a unix/linux machine |
1469
|
|
|
|
|
|
|
$sign->send( |
1470
|
|
|
|
|
|
|
device => "/dev/ttyUSB0" |
1471
|
|
|
|
|
|
|
); |
1472
|
|
|
|
|
|
|
# using optional arguments, set baudrate to 9600, and sleep 1/2 a second |
1473
|
|
|
|
|
|
|
# between sending packets. |
1474
|
|
|
|
|
|
|
$sign->send( |
1475
|
|
|
|
|
|
|
device => "COM8", |
1476
|
|
|
|
|
|
|
baudrate => "9600", |
1477
|
|
|
|
|
|
|
packetdelay => 0.5 |
1478
|
|
|
|
|
|
|
); |
1479
|
|
|
|
|
|
|
|
1480
|
|
|
|
|
|
|
Note that if you have multiple connected signs, you can send to them without creating a new object: |
1481
|
|
|
|
|
|
|
|
1482
|
|
|
|
|
|
|
# send to the first sign |
1483
|
|
|
|
|
|
|
$sign->send(device => "COM4"); |
1484
|
|
|
|
|
|
|
# send to another sign |
1485
|
|
|
|
|
|
|
$sign->send(device => "COM6"); |
1486
|
|
|
|
|
|
|
# send to a badge connected on COM7 |
1487
|
|
|
|
|
|
|
# this works fine for plain text, but won't work well for |
1488
|
|
|
|
|
|
|
# pictures and icons...you'll have to create a new |
1489
|
|
|
|
|
|
|
# sign object with devicetype "badge" for them to render correctly |
1490
|
|
|
|
|
|
|
$sign->send(device => "COM7"); |
1491
|
|
|
|
|
|
|
|
1492
|
|
|
|
|
|
|
Using the showslots parameter. Also see the "slot" parameter under L<< /"$sign->addMsg" >>. |
1493
|
|
|
|
|
|
|
|
1494
|
|
|
|
|
|
|
|
1495
|
|
|
|
|
|
|
# |
1496
|
|
|
|
|
|
|
# showslots is a string, with the numbers of the messages you want |
1497
|
|
|
|
|
|
|
# displayed separated by commas |
1498
|
|
|
|
|
|
|
# |
1499
|
|
|
|
|
|
|
$sign->send(device => "/dev/ttyUSB0", |
1500
|
|
|
|
|
|
|
showslots => "1,5,7" |
1501
|
|
|
|
|
|
|
); |
1502
|
|
|
|
|
|
|
|
1503
|
|
|
|
|
|
|
=head1 AUTHOR |
1504
|
|
|
|
|
|
|
|
1505
|
|
|
|
|
|
|
Kerry Schwab, C<< >> |
1506
|
|
|
|
|
|
|
|
1507
|
|
|
|
|
|
|
=head1 SUPPORT |
1508
|
|
|
|
|
|
|
|
1509
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
1510
|
|
|
|
|
|
|
|
1511
|
|
|
|
|
|
|
perldoc Device::MiniSign |
1512
|
|
|
|
|
|
|
|
1513
|
|
|
|
|
|
|
Other links that may be helpful: |
1514
|
|
|
|
|
|
|
|
1515
|
|
|
|
|
|
|
=over |
1516
|
|
|
|
|
|
|
|
1517
|
|
|
|
|
|
|
=item * |
1518
|
|
|
|
|
|
|
Our website: L |
1519
|
|
|
|
|
|
|
|
1520
|
|
|
|
|
|
|
=item * |
1521
|
|
|
|
|
|
|
Our L |
1522
|
|
|
|
|
|
|
|
1523
|
|
|
|
|
|
|
=item * |
1524
|
|
|
|
|
|
|
The signs that work with this api are L. They are the first three shown, the badge, the "micro sign" and the "mini sign". |
1525
|
|
|
|
|
|
|
|
1526
|
|
|
|
|
|
|
=back |
1527
|
|
|
|
|
|
|
|
1528
|
|
|
|
|
|
|
=head1 BUGS |
1529
|
|
|
|
|
|
|
|
1530
|
|
|
|
|
|
|
Please report any bugs or feature requests to |
1531
|
|
|
|
|
|
|
C, or through the web interface at |
1532
|
|
|
|
|
|
|
L. I will be notified, and then you'll automatically be |
1533
|
|
|
|
|
|
|
notified of progress on your bug as I make changes. |
1534
|
|
|
|
|
|
|
|
1535
|
|
|
|
|
|
|
=head1 TODO |
1536
|
|
|
|
|
|
|
|
1537
|
|
|
|
|
|
|
=over |
1538
|
|
|
|
|
|
|
|
1539
|
|
|
|
|
|
|
=item |
1540
|
|
|
|
|
|
|
B: The signs only natively support one line of text, but they do support uploading and replacing the native font. The native font that comes with the sign is 12 pixels tall, I suppose to allow for the effect that outlines the text in a box. A 15 or 16 pixel font, however, would be much more visible. |
1541
|
|
|
|
|
|
|
|
1542
|
|
|
|
|
|
|
=item |
1543
|
|
|
|
|
|
|
B: If we provided a way to render smaller fonts, like a standard 5x7 LED font, into a pixmap, you could present two lines of text on the sign, abeit, only as a picture via addPix. |
1544
|
|
|
|
|
|
|
|
1545
|
|
|
|
|
|
|
=item |
1546
|
|
|
|
|
|
|
B: Need a better module structure that supports other models of LED signs that use a different protocol. Like LEDSign::Mini LEDSign:OtherModel, etc. |
1547
|
|
|
|
|
|
|
|
1548
|
|
|
|
|
|
|
=item |
1549
|
|
|
|
|
|
|
B: I'm much better with Perl, but it's not as popular as it used to be. Porting to python might open up a wider user base for the signs. |
1550
|
|
|
|
|
|
|
|
1551
|
|
|
|
|
|
|
=back |
1552
|
|
|
|
|
|
|
|
1553
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
1554
|
|
|
|
|
|
|
|
1555
|
|
|
|
|
|
|
I was able to leverage some existing work I found, though none of these examples reverse engineered the protocol to the same degree that we've done in this API. Here's what I found: |
1556
|
|
|
|
|
|
|
|
1557
|
|
|
|
|
|
|
=over 4 |
1558
|
|
|
|
|
|
|
|
1559
|
|
|
|
|
|
|
=item * L - Some code samples for different types of LED badges. The last one, "Badge Three", uses the same protocol we're targeting here. |
1560
|
|
|
|
|
|
|
|
1561
|
|
|
|
|
|
|
=item * L - Ruby library that appears to be targeting led badges with a very similar protocol. |
1562
|
|
|
|
|
|
|
|
1563
|
|
|
|
|
|
|
=item * L - A game, written in C#, that uses LED badges. Also has some protocol information and C# code. Targeting the same type of signs/badges. |
1564
|
|
|
|
|
|
|
|
1565
|
|
|
|
|
|
|
=item * L - Python code, again, using the same protocol. |
1566
|
|
|
|
|
|
|
|
1567
|
|
|
|
|
|
|
=back |
1568
|
|
|
|
|
|
|
|
1569
|
|
|
|
|
|
|
Other Cpan modules related to Led Signs |
1570
|
|
|
|
|
|
|
|
1571
|
|
|
|
|
|
|
=over |
1572
|
|
|
|
|
|
|
|
1573
|
|
|
|
|
|
|
=item * L - The only other CPAN perl module I could find that does something similar, albeit for a different type of sign. |
1574
|
|
|
|
|
|
|
|
1575
|
|
|
|
|
|
|
=back |
1576
|
|
|
|
|
|
|
|
1577
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
1578
|
|
|
|
|
|
|
|
1579
|
|
|
|
|
|
|
Copyright 2013 Kerry Schwab. |
1580
|
|
|
|
|
|
|
|
1581
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
1582
|
|
|
|
|
|
|
under the terms of the the Artistic License (2.0). You may obtain a |
1583
|
|
|
|
|
|
|
copy of the full license at: |
1584
|
|
|
|
|
|
|
|
1585
|
|
|
|
|
|
|
L |
1586
|
|
|
|
|
|
|
|
1587
|
|
|
|
|
|
|
Aggregation of this Package with a commercial distribution is always |
1588
|
|
|
|
|
|
|
permitted provided that the use of this Package is embedded; that is, |
1589
|
|
|
|
|
|
|
when no overt attempt is made to make this Package's interfaces visible |
1590
|
|
|
|
|
|
|
to the end user of the commercial distribution. Such use shall not be |
1591
|
|
|
|
|
|
|
construed as a distribution of this Package. |
1592
|
|
|
|
|
|
|
|
1593
|
|
|
|
|
|
|
The name of the Copyright Holder may not be used to endorse or promote |
1594
|
|
|
|
|
|
|
products derived from this software without specific prior written |
1595
|
|
|
|
|
|
|
permission. |
1596
|
|
|
|
|
|
|
|
1597
|
|
|
|
|
|
|
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED |
1598
|
|
|
|
|
|
|
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
1599
|
|
|
|
|
|
|
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
1600
|
|
|
|
|
|
|
|
1601
|
|
|
|
|
|
|
|
1602
|
|
|
|
|
|
|
=cut |