line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Uniden::BC75XLT; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
$VERSION = "0.0.4"; |
4
|
0
|
|
|
0
|
0
|
|
sub Version { $VERSION; } |
5
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
1036
|
use strict; |
|
1
|
|
|
1
|
|
3
|
|
|
1
|
|
|
|
|
36
|
|
|
1
|
|
|
|
|
2409
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
39
|
|
7
|
1
|
|
|
1
|
|
1307
|
use Device::SerialPort; |
|
1
|
|
|
1
|
|
72332
|
|
|
1
|
|
|
|
|
8922
|
|
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
10315
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
my %priMode = (0 => 'OFF', 1 => 'ON', 2 => 'PLUS ON', 3 => 'DND'); |
10
|
|
|
|
|
|
|
my %keyState = (0 => 'OFF', 1 => 'ON'); |
11
|
|
|
|
|
|
|
my %bandPlan = (0 => 'USA', 1 => 'CANADA'); |
12
|
|
|
|
|
|
|
my %scanGroup = (1 => 'OFF', 0 => 'ON'); |
13
|
|
|
|
|
|
|
my %chDLY = (0 => 'OFF', 1 => 'ON'); |
14
|
|
|
|
|
|
|
my %chPRI = (0 => 'OFF', 1 => 'ON'); |
15
|
|
|
|
|
|
|
my %chLOUT = (0 => 'UNLOCKED', 1 => 'LOCKOUT'); |
16
|
|
|
|
|
|
|
my %srchDirection = (0 => 'UP', 1 => 'DOWN'); |
17
|
|
|
|
|
|
|
my %ccAlarm = (0 => 'OFF', 1 => 'ON'); |
18
|
|
|
|
|
|
|
my %ccMode = (0 => 'OFF', 1 => 'PRIORITY', 2 => 'DND'); |
19
|
|
|
|
|
|
|
my %ccBand = (0 => 'VHF_LOW', 1 => 'AIR', 2 => 'VHF_HIGH', 4 => 'UHF'); |
20
|
|
|
|
|
|
|
my %ssBand = ( |
21
|
|
|
|
|
|
|
1 => 'WX', 2 => 'POLICE', 3 => 'FIRE', 4 => 'MARINE', |
22
|
|
|
|
|
|
|
5 => 'RACE', 6 => 'AIR', 7 => 'HAM', 8 => 'RAIL', 9 => 'CB', 10 => 'OTHER' |
23
|
|
|
|
|
|
|
); |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub new |
26
|
|
|
|
|
|
|
{ |
27
|
0
|
|
|
0
|
1
|
|
my $class = shift; |
28
|
0
|
|
|
|
|
|
my $device = shift; |
29
|
0
|
|
|
|
|
|
my %opts = @_; |
30
|
|
|
|
|
|
|
|
31
|
0
|
|
0
|
|
|
|
my $baudrate = $opts{baudrate} || 57600; |
32
|
|
|
|
|
|
|
|
33
|
0
|
|
0
|
|
|
|
my $port = Device::SerialPort->new($device) || return undef; |
34
|
0
|
|
0
|
|
|
|
$port->databits($opts{databits} || 8); |
35
|
0
|
|
0
|
|
|
|
$port->baudrate($opts{baudrate} || 57600); |
36
|
0
|
|
0
|
|
|
|
$port->parity($opts{parity} || "none"); |
37
|
0
|
|
0
|
|
|
|
$port->stopbits($opts{stopbits} || 1); |
38
|
0
|
|
0
|
|
|
|
$port->handshake($opts{handshake} || "none"); |
39
|
0
|
|
0
|
|
|
|
$port->read_const_time($opts{read_cost_time} || 1); |
40
|
|
|
|
|
|
|
|
41
|
0
|
|
0
|
|
|
|
my %o = ( |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
42
|
|
|
|
|
|
|
_port => $port, |
43
|
|
|
|
|
|
|
fatal => ($opts{fatal} || 0), |
44
|
|
|
|
|
|
|
echo => ($opts{echo} || 0), |
45
|
|
|
|
|
|
|
timeout => ($opts{timeout} || 999), |
46
|
|
|
|
|
|
|
); |
47
|
|
|
|
|
|
|
|
48
|
0
|
|
|
|
|
|
bless \%o, $class; |
49
|
|
|
|
|
|
|
} |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
### public ### |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
sub getModelName |
54
|
|
|
|
|
|
|
{ |
55
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
56
|
0
|
|
|
|
|
|
return $self->_simpleGetCommand('MDL'); |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub getFirmwareVersion |
60
|
|
|
|
|
|
|
{ |
61
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
62
|
0
|
|
|
|
|
|
return $self->_simpleGetCommand('VER'); |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
sub getVolume |
66
|
|
|
|
|
|
|
{ |
67
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
68
|
0
|
|
|
|
|
|
return $self->_simpleGetCommand('VOL'); |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
sub setVolume |
72
|
|
|
|
|
|
|
{ |
73
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
74
|
0
|
|
|
|
|
|
my $value = shift; |
75
|
|
|
|
|
|
|
|
76
|
0
|
|
|
|
|
|
return $self->_simpleSetCommand('VOL', $value); |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub getSql |
80
|
|
|
|
|
|
|
{ |
81
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
82
|
0
|
|
|
|
|
|
return $self->_simpleGetCommand('SQL'); |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
sub setSql |
86
|
|
|
|
|
|
|
{ |
87
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
88
|
0
|
|
|
|
|
|
my $value = shift; |
89
|
|
|
|
|
|
|
|
90
|
0
|
|
|
|
|
|
return $self->_simpleSetCommand('SQL', $value); |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
sub setProgramMode |
94
|
|
|
|
|
|
|
{ |
95
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
96
|
|
|
|
|
|
|
|
97
|
0
|
0
|
|
|
|
|
return if $self->{_pgm}; |
98
|
0
|
|
|
|
|
|
my $res = $self->_simpleGetCommand('PRG'); |
99
|
0
|
0
|
|
|
|
|
if($res eq 'OK') |
100
|
|
|
|
|
|
|
{ |
101
|
0
|
|
|
|
|
|
$self->{_pgm} = 1; |
102
|
0
|
|
|
|
|
|
return 1; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
else |
105
|
|
|
|
|
|
|
{ |
106
|
0
|
|
|
|
|
|
print STDERR "NO $res\n"; |
107
|
|
|
|
|
|
|
} |
108
|
0
|
|
|
|
|
|
return 0; |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
sub quitProgramMode |
112
|
|
|
|
|
|
|
{ |
113
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
114
|
|
|
|
|
|
|
|
115
|
0
|
0
|
|
|
|
|
return unless $self->{_pgm}; |
116
|
0
|
|
|
|
|
|
my $res = $self->_simpleGetCommand('EPG'); |
117
|
0
|
0
|
|
|
|
|
if($res eq 'OK') |
118
|
|
|
|
|
|
|
{ |
119
|
0
|
|
|
|
|
|
$self->{_pgm} = 0; |
120
|
0
|
|
|
|
|
|
return 1; |
121
|
|
|
|
|
|
|
} |
122
|
0
|
|
|
|
|
|
return 0; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
sub getBandPlan |
126
|
|
|
|
|
|
|
{ |
127
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
128
|
|
|
|
|
|
|
|
129
|
0
|
|
|
|
|
|
return $self->_simpleGetCommand('BPL', pgm => 1); |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
sub getBandPlanName |
133
|
|
|
|
|
|
|
{ |
134
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
135
|
|
|
|
|
|
|
|
136
|
0
|
|
|
|
|
|
my $code = $self->getBandPlan(); |
137
|
0
|
|
|
|
|
|
return $self->_getName($code, \%bandPlan); |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub setBandPlan |
141
|
|
|
|
|
|
|
{ |
142
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
143
|
0
|
|
|
|
|
|
my $value = $self->_fromName(shift, \%bandPlan); |
144
|
|
|
|
|
|
|
|
145
|
0
|
|
|
|
|
|
return $self->_simpleSetCommand('BPL', $value, 1); |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
sub getKeyLockState |
149
|
|
|
|
|
|
|
{ |
150
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
151
|
0
|
|
|
|
|
|
return $self->_simpleGetCommand('KBP', pgm => 1, index => 1); |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
sub getKeyLockStateName |
155
|
|
|
|
|
|
|
{ |
156
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
157
|
|
|
|
|
|
|
|
158
|
0
|
|
|
|
|
|
my $code = $self->getKeyLockState(); |
159
|
0
|
|
|
|
|
|
return $self->_getName($code, \%keyState); |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
sub setKeyLockState |
163
|
|
|
|
|
|
|
{ |
164
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
165
|
0
|
|
|
|
|
|
my $state = $self->_fromName(shift, \%keyState); |
166
|
|
|
|
|
|
|
|
167
|
0
|
|
|
|
|
|
return $self->_simpleSetCommand('KBP', [ '', $state ], 1); |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub getPriorityMode |
171
|
|
|
|
|
|
|
{ |
172
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
173
|
|
|
|
|
|
|
|
174
|
0
|
|
|
|
|
|
return $self->_simpleGetCommand('PRI', pgm => 1); |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
sub getPriorityModeName |
178
|
|
|
|
|
|
|
{ |
179
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
180
|
|
|
|
|
|
|
|
181
|
0
|
|
|
|
|
|
my $code = $self->getPriorityMode(); |
182
|
0
|
|
|
|
|
|
return $self->_getName($code, \%priMode); |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
sub setPriorityMode |
186
|
|
|
|
|
|
|
{ |
187
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
188
|
0
|
|
|
|
|
|
my $value = $self->_fromName(shift, \%priMode); |
189
|
|
|
|
|
|
|
|
190
|
0
|
|
|
|
|
|
return $self->_simpleSetCommand('PRI', $value, 1); |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
sub getScanChannelGroup |
194
|
|
|
|
|
|
|
{ |
195
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
196
|
|
|
|
|
|
|
|
197
|
0
|
|
|
|
|
|
my $value = $self->_simpleGetCommand('SCG', pgm => 1); |
198
|
|
|
|
|
|
|
|
199
|
0
|
0
|
|
|
|
|
if($value) |
200
|
|
|
|
|
|
|
{ |
201
|
0
|
|
|
|
|
|
my @group; |
202
|
0
|
|
|
|
|
|
foreach my $one (split('', $value)) |
203
|
|
|
|
|
|
|
{ |
204
|
0
|
|
|
|
|
|
push @group, $self->_getName($one, \%scanGroup); |
205
|
|
|
|
|
|
|
} |
206
|
0
|
|
|
|
|
|
return \@group; |
207
|
|
|
|
|
|
|
} |
208
|
0
|
|
|
|
|
|
return; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
sub setScanChannelGroup |
212
|
|
|
|
|
|
|
{ |
213
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
214
|
0
|
|
|
|
|
|
my $gdata = shift; |
215
|
|
|
|
|
|
|
|
216
|
0
|
|
|
|
|
|
my $str = ''; |
217
|
0
|
0
|
|
|
|
|
if(ref($gdata) eq 'ARRAY') |
|
|
0
|
|
|
|
|
|
218
|
|
|
|
|
|
|
{ |
219
|
0
|
|
|
|
|
|
foreach my $i (0..9) |
220
|
|
|
|
|
|
|
{ |
221
|
0
|
|
|
|
|
|
my $code = $self->_fromName($gdata->[$i], \%scanGroup); |
222
|
0
|
0
|
|
|
|
|
$code = 1 unless defined($code); |
223
|
0
|
|
|
|
|
|
$str .= $code; |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
elsif(ref($gdata) eq 'HASH') |
227
|
|
|
|
|
|
|
{ |
228
|
0
|
|
|
|
|
|
foreach my $i (1..10) |
229
|
|
|
|
|
|
|
{ |
230
|
0
|
|
|
|
|
|
my $code; |
231
|
0
|
0
|
|
|
|
|
if(exists($gdata->{$i})) |
232
|
|
|
|
|
|
|
{ |
233
|
0
|
|
|
|
|
|
$code = $self->_fromName($gdata->{$i}, \%scanGroup); |
234
|
|
|
|
|
|
|
} |
235
|
0
|
0
|
|
|
|
|
$code = 1 unless defined($code); |
236
|
0
|
|
|
|
|
|
$str .= $code; |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
else |
240
|
|
|
|
|
|
|
{ |
241
|
0
|
|
|
|
|
|
$str = $gdata; |
242
|
|
|
|
|
|
|
} |
243
|
0
|
|
|
|
|
|
return $self->_simpleSetCommand('SCG', $str, 1); |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
sub setValidScanChannels |
247
|
|
|
|
|
|
|
{ |
248
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
249
|
0
|
|
|
|
|
|
my $channels = shift; |
250
|
|
|
|
|
|
|
|
251
|
0
|
|
|
|
|
|
my %on = map { $_ => 1 } @$channels; |
|
0
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
|
253
|
0
|
0
|
|
|
|
|
my @group = map { $on{$_} ? 0: 1 } (1..10); |
|
0
|
|
|
|
|
|
|
254
|
0
|
|
|
|
|
|
$self->setScanChannelGroup(\@group); |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
sub getChannelInfo |
258
|
|
|
|
|
|
|
{ |
259
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
260
|
0
|
|
|
|
|
|
my $index = shift; |
261
|
|
|
|
|
|
|
|
262
|
0
|
0
|
0
|
|
|
|
if($index < 1 || $index > 300) |
263
|
|
|
|
|
|
|
{ |
264
|
0
|
|
|
|
|
|
return $self->error("Invalid channel index: $index"); |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
0
|
|
|
|
|
|
my $value = $self->_simpleGetCommand('CIN', args => [ $index ], pgm => 1, array => 1); |
268
|
0
|
0
|
|
|
|
|
return undef unless $value; |
269
|
0
|
|
|
|
|
|
my $freq = $value->[2]; |
270
|
0
|
0
|
|
|
|
|
if($freq eq '00000000') |
271
|
|
|
|
|
|
|
{ |
272
|
0
|
|
|
|
|
|
return { state => 'UNSET' , index => $value->[0] }; |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
|
275
|
0
|
|
|
|
|
|
my %info = ( |
276
|
|
|
|
|
|
|
state => 'SET', |
277
|
|
|
|
|
|
|
index => $value->[0], |
278
|
|
|
|
|
|
|
freq_code => $value->[2], |
279
|
|
|
|
|
|
|
freq => $self->_freq_human($value->[2]), |
280
|
|
|
|
|
|
|
delay => $self->_getName($value->[5], \%chDLY), |
281
|
|
|
|
|
|
|
delay_code => $value->[5], |
282
|
|
|
|
|
|
|
lockout => $self->_getName($value->[6], \%chLOUT), |
283
|
|
|
|
|
|
|
lockout_code => $value->[6], |
284
|
|
|
|
|
|
|
priority => $self->_getName($value->[7], \%chPRI), |
285
|
|
|
|
|
|
|
priority_code => $value->[7], |
286
|
|
|
|
|
|
|
); |
287
|
|
|
|
|
|
|
|
288
|
0
|
|
|
|
|
|
return \%info; |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
sub getChannelsInfo |
292
|
|
|
|
|
|
|
{ |
293
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
294
|
0
|
|
|
|
|
|
my %opts = @_; |
295
|
|
|
|
|
|
|
|
296
|
0
|
|
0
|
|
|
|
my $start = $opts{start} || 1; |
297
|
0
|
|
0
|
|
|
|
my $stop = $opts{stop} || 300; |
298
|
0
|
|
|
|
|
|
my $state = $opts{state}; |
299
|
|
|
|
|
|
|
|
300
|
0
|
0
|
0
|
|
|
|
$start = 1 if($start < 1 || $start > 300); |
301
|
0
|
0
|
0
|
|
|
|
$stop = 300 if($stop < 1 || $stop > 300); |
302
|
0
|
0
|
|
|
|
|
if($start > $stop) |
303
|
|
|
|
|
|
|
{ |
304
|
0
|
|
|
|
|
|
$start = $stop; |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
0
|
|
|
|
|
|
my @result; |
308
|
0
|
|
|
|
|
|
$self->setProgramMode(); |
309
|
0
|
|
|
|
|
|
foreach my $n ($start..$stop) |
310
|
|
|
|
|
|
|
{ |
311
|
0
|
|
|
|
|
|
my $info = $self->getChannelInfo($n); |
312
|
0
|
0
|
|
|
|
|
if($state) |
313
|
|
|
|
|
|
|
{ |
314
|
0
|
0
|
|
|
|
|
if($state eq $info->{state}) |
315
|
|
|
|
|
|
|
{ |
316
|
0
|
|
|
|
|
|
push @result, $info; |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
else |
320
|
|
|
|
|
|
|
{ |
321
|
0
|
|
|
|
|
|
push @result, $info; |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
} |
324
|
0
|
|
|
|
|
|
$self->quitProgramMode(); |
325
|
|
|
|
|
|
|
|
326
|
0
|
|
|
|
|
|
return \@result; |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
sub getBankChannelsInfo |
330
|
|
|
|
|
|
|
{ |
331
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
332
|
0
|
|
|
|
|
|
my $bank = shift; |
333
|
0
|
|
|
|
|
|
my $state = shift; |
334
|
|
|
|
|
|
|
|
335
|
0
|
0
|
0
|
|
|
|
if($bank < 1 || $bank > 10) |
336
|
|
|
|
|
|
|
{ |
337
|
0
|
|
|
|
|
|
return $self->error("wrong bank number: $bank, valid - 1..10"); |
338
|
|
|
|
|
|
|
} |
339
|
0
|
|
|
|
|
|
my $start = (($bank-1) * 30)+ 1; |
340
|
0
|
|
|
|
|
|
my $stop = $start+29; |
341
|
|
|
|
|
|
|
|
342
|
0
|
|
|
|
|
|
my %opts = (start => $start, stop => $stop); |
343
|
0
|
0
|
|
|
|
|
if($state) |
344
|
|
|
|
|
|
|
{ |
345
|
0
|
|
|
|
|
|
$opts{state} = uc($state); |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
|
348
|
0
|
|
|
|
|
|
return $self->getChannelsInfo(%opts); |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
sub setChannelInfo |
352
|
|
|
|
|
|
|
{ |
353
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
354
|
0
|
|
|
|
|
|
my $index = shift; |
355
|
0
|
|
|
|
|
|
my $data = shift; |
356
|
|
|
|
|
|
|
|
357
|
0
|
0
|
0
|
|
|
|
if($index < 1 || $index > 300) |
358
|
|
|
|
|
|
|
{ |
359
|
0
|
|
|
|
|
|
return $self->error("Invalid channel index: $index"); |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
0
|
|
|
|
|
|
my $freq = $self->_from_human_freq($data->{freq}); |
363
|
0
|
|
0
|
|
|
|
my $dly = $data->{delay_code} || $self->_fromName($data->{delay}, \%chDLY); |
364
|
0
|
0
|
|
|
|
|
$dly = 1 unless defined $dly; |
365
|
0
|
|
0
|
|
|
|
my $pri = $data->{priority_code} || $self->_fromName($data->{priority}, \%chPRI) || 0; |
366
|
0
|
|
0
|
|
|
|
my $lout = $data->{lockout_code} || $self->_fromName($data->{lockout}, \%chLOUT) || 0; |
367
|
|
|
|
|
|
|
|
368
|
0
|
|
|
|
|
|
return $self->_simpleSetCommand('CIN', [ $index, '', $freq, '','', $dly, $lout, $pri ], 1); |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
sub eraseChannel |
372
|
|
|
|
|
|
|
{ |
373
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
374
|
0
|
|
|
|
|
|
my $index = shift; |
375
|
|
|
|
|
|
|
|
376
|
0
|
0
|
0
|
|
|
|
if($index < 1 || $index > 300) |
377
|
|
|
|
|
|
|
{ |
378
|
0
|
|
|
|
|
|
return $self->error("Invalid channel index: $index"); |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
|
381
|
0
|
|
|
|
|
|
$self->setChannelInfo($index, { freq => '0.0' }); |
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
sub getSearchCloseCallSettings |
385
|
|
|
|
|
|
|
{ |
386
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
387
|
|
|
|
|
|
|
|
388
|
0
|
|
|
|
|
|
my $value = $self->_simpleGetCommand('SCO', pgm => 1, array => 1); |
389
|
|
|
|
|
|
|
|
390
|
0
|
0
|
|
|
|
|
if($value) |
391
|
|
|
|
|
|
|
{ |
392
|
0
|
|
|
|
|
|
my $dly = $value->[0]; |
393
|
0
|
|
|
|
|
|
my $dir = $value->[2]; |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
return { |
396
|
0
|
|
|
|
|
|
direction_code => $dir, |
397
|
|
|
|
|
|
|
direction => $self->_getName($dir, \%srchDirection), |
398
|
|
|
|
|
|
|
delay_code => $dly, |
399
|
|
|
|
|
|
|
delay => $self->_getName($dly, \%chDLY), |
400
|
|
|
|
|
|
|
}; |
401
|
|
|
|
|
|
|
} |
402
|
0
|
|
|
|
|
|
return undef; |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
sub setSearchCloseCallSettings |
406
|
|
|
|
|
|
|
{ |
407
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
408
|
0
|
|
|
|
|
|
my %data = @_; |
409
|
|
|
|
|
|
|
|
410
|
0
|
|
|
|
|
|
my $dir = $self->_fromName($data{direction}, \%srchDirection); |
411
|
0
|
|
|
|
|
|
my $dly = $self->_fromName($data{delay}, \%chDLY); |
412
|
0
|
0
|
|
|
|
|
$dir = 1 unless defined $dir;; |
413
|
0
|
0
|
|
|
|
|
$dly = 1 unless defined $dir;; |
414
|
|
|
|
|
|
|
|
415
|
0
|
|
|
|
|
|
$self->_simpleSetCommand('SCO', [ $dly, '', $dir ], 1); |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
sub getGlobalLockoutFreqs |
419
|
|
|
|
|
|
|
{ |
420
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
421
|
|
|
|
|
|
|
|
422
|
0
|
|
|
|
|
|
my @freqs = (); |
423
|
|
|
|
|
|
|
|
424
|
0
|
|
|
|
|
|
my $i = 300; |
425
|
0
|
|
|
|
|
|
$self->setProgramMode(); |
426
|
0
|
|
|
|
|
|
while($i-- > 0) |
427
|
|
|
|
|
|
|
{ |
428
|
0
|
|
|
|
|
|
my $value = $self->_simpleGetCommand('GLF', pgm => 1); |
429
|
0
|
0
|
|
|
|
|
return unless defined($value); |
430
|
|
|
|
|
|
|
|
431
|
0
|
0
|
0
|
|
|
|
if($value == -1 || $value eq 'OK') |
432
|
|
|
|
|
|
|
{ |
433
|
0
|
|
|
|
|
|
last; |
434
|
|
|
|
|
|
|
} |
435
|
|
|
|
|
|
|
else |
436
|
|
|
|
|
|
|
{ |
437
|
0
|
|
|
|
|
|
push @freqs, $self->_freq_human($value); |
438
|
|
|
|
|
|
|
} |
439
|
|
|
|
|
|
|
} |
440
|
0
|
|
|
|
|
|
$self->quitProgramMode(); |
441
|
|
|
|
|
|
|
|
442
|
0
|
|
|
|
|
|
return \@freqs; |
443
|
|
|
|
|
|
|
} |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
sub lockGlobalFrequency |
446
|
|
|
|
|
|
|
{ |
447
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
448
|
0
|
|
|
|
|
|
my $freq = shift; |
449
|
|
|
|
|
|
|
|
450
|
0
|
|
|
|
|
|
$self->_simpleSetCommand('LOF', $self->_from_human_freq($freq), 1); |
451
|
|
|
|
|
|
|
} |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
sub unlockGlobalFrequency |
454
|
|
|
|
|
|
|
{ |
455
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
456
|
0
|
|
|
|
|
|
my $freq = shift; |
457
|
|
|
|
|
|
|
|
458
|
0
|
|
|
|
|
|
$self->_simpleSetCommand('ULF', $self->_from_human_freq($freq), 1); |
459
|
|
|
|
|
|
|
} |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
sub getCloseCallSettings |
462
|
|
|
|
|
|
|
{ |
463
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
464
|
|
|
|
|
|
|
|
465
|
0
|
|
|
|
|
|
my $val = $self->_simpleGetCommand('CLC', pgm => 1, array => 1); |
466
|
0
|
0
|
|
|
|
|
return unless $val; |
467
|
|
|
|
|
|
|
|
468
|
0
|
|
|
|
|
|
my $mode = $val->[0]; |
469
|
0
|
|
|
|
|
|
my $al_beep = $val->[1]; |
470
|
0
|
|
|
|
|
|
my $al_light = $val->[2]; |
471
|
0
|
|
|
|
|
|
my $band_str = $val->[3]; |
472
|
|
|
|
|
|
|
|
473
|
0
|
|
|
|
|
|
my %info = ( |
474
|
|
|
|
|
|
|
mode_code => $mode, |
475
|
|
|
|
|
|
|
mode => $self->_getName($mode, \%ccMode), |
476
|
|
|
|
|
|
|
alert_beep_code => $al_beep, |
477
|
|
|
|
|
|
|
alert_beep => $self->_getName($al_beep, \%ccAlarm), |
478
|
|
|
|
|
|
|
alert_light_code => $al_beep, |
479
|
|
|
|
|
|
|
alert_light => $self->_getName($al_light, \%ccAlarm), |
480
|
|
|
|
|
|
|
); |
481
|
|
|
|
|
|
|
|
482
|
0
|
|
|
|
|
|
my %bands = (); |
483
|
0
|
|
|
|
|
|
for(my $i = 0 ; $i < 5; $i++) |
484
|
|
|
|
|
|
|
{ |
485
|
0
|
0
|
|
|
|
|
next unless $ccBand{$i}; |
486
|
0
|
0
|
|
|
|
|
$bands{$ccBand{$i}} = substr($band_str, $i, 1) eq '1' ? 'ON': 'OFF'; |
487
|
|
|
|
|
|
|
} |
488
|
0
|
|
|
|
|
|
$info{bands} = \%bands; |
489
|
|
|
|
|
|
|
|
490
|
0
|
|
|
|
|
|
return \%info; |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
sub setCloseCallSettings |
494
|
|
|
|
|
|
|
{ |
495
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
496
|
0
|
|
|
|
|
|
my %data = @_; |
497
|
|
|
|
|
|
|
|
498
|
0
|
|
|
|
|
|
my $mode = $self->_fromName($data{mode}, \%ccMode); |
499
|
0
|
|
|
|
|
|
my $al_beep = $self->_fromName($data{alert_beep},\%ccAlarm); |
500
|
0
|
|
|
|
|
|
my $al_light = $self->_fromName($data{alert_light},\%ccAlarm); |
501
|
0
|
0
|
|
|
|
|
$mode = 2 unless defined $mode; |
502
|
0
|
0
|
|
|
|
|
$al_beep = 0 unless defined $al_beep; |
503
|
0
|
0
|
|
|
|
|
$al_light = 0 unless defined $al_light; |
504
|
|
|
|
|
|
|
|
505
|
0
|
|
|
|
|
|
my $bands = '11101'; |
506
|
0
|
0
|
0
|
|
|
|
if($data{bands} && ref($data{bands}) eq 'ARRAY' && scalar(@{$data{bands}})) |
|
0
|
|
0
|
|
|
|
|
507
|
|
|
|
|
|
|
{ |
508
|
0
|
|
|
|
|
|
my @B = ( 0, 0, 0, 0, 0 ); |
509
|
0
|
|
|
|
|
|
foreach my $name (@{$data{bands}}) |
|
0
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
{ |
511
|
0
|
|
|
|
|
|
my $code = $self->_fromName($name, \%ccBand); |
512
|
0
|
0
|
|
|
|
|
if(defined($code)) |
513
|
|
|
|
|
|
|
{ |
514
|
0
|
|
|
|
|
|
$B[$code] = 1; |
515
|
|
|
|
|
|
|
} |
516
|
|
|
|
|
|
|
} |
517
|
0
|
|
|
|
|
|
$bands = join('', @B); |
518
|
0
|
|
|
|
|
|
print STDERR "BANDS: $bands\n"; |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
|
521
|
0
|
|
|
|
|
|
$self->_simpleSetCommand('CLC', [ $mode, $al_beep, $al_light, $bands, '' ], 1); |
522
|
|
|
|
|
|
|
} |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
sub getServiceSearchSettings |
525
|
|
|
|
|
|
|
{ |
526
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
527
|
0
|
|
|
|
|
|
my $band = shift; |
528
|
|
|
|
|
|
|
|
529
|
0
|
0
|
|
|
|
|
return $self->error("There is no band") unless $band; |
530
|
0
|
|
|
|
|
|
my $index = $self->_fromName($band, \%ssBand); |
531
|
0
|
0
|
0
|
|
|
|
if($index < 1 || $index > 10) |
532
|
|
|
|
|
|
|
{ |
533
|
0
|
|
|
|
|
|
return $self->error("Band is out of range: $index. (1..10)"); |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
|
536
|
0
|
|
|
|
|
|
my $value = $self->_simpleGetCommand('SSP', args => [ $index ], pgm => 1, array => 1); |
537
|
0
|
0
|
|
|
|
|
return unless $value; |
538
|
|
|
|
|
|
|
|
539
|
0
|
|
|
|
|
|
my %data = ( |
540
|
|
|
|
|
|
|
index => $index, |
541
|
|
|
|
|
|
|
band => $self->_getName($index, \%ssBand), |
542
|
|
|
|
|
|
|
delay => $self->_getName($value->[1], \%chDLY), |
543
|
|
|
|
|
|
|
delay_code => $value->[1], |
544
|
|
|
|
|
|
|
direction => $self->_getName($value->[2], \%srchDirection), |
545
|
|
|
|
|
|
|
direction_code => $value->[2], |
546
|
|
|
|
|
|
|
); |
547
|
|
|
|
|
|
|
|
548
|
0
|
|
|
|
|
|
return \%data; |
549
|
|
|
|
|
|
|
} |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
sub setServiceSearchSettings |
552
|
|
|
|
|
|
|
{ |
553
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
554
|
0
|
|
|
|
|
|
my $band = shift; |
555
|
0
|
|
|
|
|
|
my $delay = shift; |
556
|
0
|
|
|
|
|
|
my $dir = shift; |
557
|
|
|
|
|
|
|
|
558
|
0
|
0
|
|
|
|
|
return $self->error("There is no band") unless $band; |
559
|
0
|
|
|
|
|
|
my $index = $self->_fromName($band, \%ssBand); |
560
|
0
|
0
|
0
|
|
|
|
if($index < 1 || $index > 10) |
561
|
|
|
|
|
|
|
{ |
562
|
0
|
|
|
|
|
|
return $self->error("Band is out of range: $index. (1..10)"); |
563
|
|
|
|
|
|
|
} |
564
|
|
|
|
|
|
|
|
565
|
0
|
0
|
|
|
|
|
$delay = 1 unless defined $delay; |
566
|
0
|
0
|
|
|
|
|
$dir = 1 unless defined $dir; |
567
|
|
|
|
|
|
|
|
568
|
0
|
|
|
|
|
|
my @args = ( |
569
|
|
|
|
|
|
|
$index, |
570
|
|
|
|
|
|
|
$self->_fromName($delay, \%chDLY), |
571
|
|
|
|
|
|
|
$self->_fromName($dir, \%srchDirection), |
572
|
|
|
|
|
|
|
); |
573
|
|
|
|
|
|
|
|
574
|
0
|
|
|
|
|
|
$self->_simpleSetCommand('SSP', \@args, 1); |
575
|
|
|
|
|
|
|
} |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
sub getCustomSearchGroup |
578
|
|
|
|
|
|
|
{ |
579
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
580
|
|
|
|
|
|
|
|
581
|
0
|
|
|
|
|
|
my $value = $self->_simpleGetCommand('CSG', pgm => 1, array => 1); |
582
|
|
|
|
|
|
|
|
583
|
0
|
0
|
|
|
|
|
return unless $value; |
584
|
|
|
|
|
|
|
|
585
|
0
|
|
|
|
|
|
my @group; |
586
|
0
|
|
|
|
|
|
foreach my $one (split('', $value->[0])) |
587
|
|
|
|
|
|
|
{ |
588
|
0
|
|
|
|
|
|
push @group, $self->_getName($one, \%scanGroup); |
589
|
|
|
|
|
|
|
} |
590
|
|
|
|
|
|
|
|
591
|
0
|
|
|
|
|
|
my %data = ( |
592
|
|
|
|
|
|
|
group => \@group, |
593
|
|
|
|
|
|
|
delay => $self->_getName($value->[1], \%chDLY), |
594
|
|
|
|
|
|
|
delay_code => $value->[1], |
595
|
|
|
|
|
|
|
direction => $self->_getName($value->[2], \%srchDirection), |
596
|
|
|
|
|
|
|
direction_code => $value->[2], |
597
|
|
|
|
|
|
|
); |
598
|
|
|
|
|
|
|
|
599
|
0
|
|
|
|
|
|
return \%data; |
600
|
|
|
|
|
|
|
} |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
sub setCustomSearchGroup |
603
|
|
|
|
|
|
|
{ |
604
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
605
|
0
|
|
|
|
|
|
my $gdata = shift; |
606
|
0
|
|
|
|
|
|
my $delay =shift; |
607
|
0
|
|
|
|
|
|
my $dir = shift; |
608
|
|
|
|
|
|
|
|
609
|
0
|
0
|
|
|
|
|
$delay = 1 unless defined $delay; |
610
|
0
|
0
|
|
|
|
|
$dir = 0 unless defined $dir; |
611
|
|
|
|
|
|
|
|
612
|
0
|
|
|
|
|
|
my $str = ''; |
613
|
0
|
0
|
|
|
|
|
if(ref($gdata) eq 'ARRAY') |
|
|
0
|
|
|
|
|
|
614
|
|
|
|
|
|
|
{ |
615
|
0
|
|
|
|
|
|
foreach my $i (0..9) |
616
|
|
|
|
|
|
|
{ |
617
|
0
|
|
|
|
|
|
my $code = $self->_fromName($gdata->[$i], \%scanGroup); |
618
|
0
|
0
|
|
|
|
|
$code = 1 unless defined($code); |
619
|
0
|
|
|
|
|
|
$str .= $code; |
620
|
|
|
|
|
|
|
} |
621
|
|
|
|
|
|
|
} |
622
|
|
|
|
|
|
|
elsif(ref($gdata) eq 'HASH') |
623
|
|
|
|
|
|
|
{ |
624
|
0
|
|
|
|
|
|
foreach my $i (1..10) |
625
|
|
|
|
|
|
|
{ |
626
|
0
|
|
|
|
|
|
my $code; |
627
|
0
|
0
|
|
|
|
|
if(exists($gdata->{$i})) |
628
|
|
|
|
|
|
|
{ |
629
|
0
|
|
|
|
|
|
$code = $self->_fromName($gdata->{$i}, \%scanGroup); |
630
|
|
|
|
|
|
|
} |
631
|
0
|
0
|
|
|
|
|
$code = 1 unless defined($code); |
632
|
0
|
|
|
|
|
|
$str .= $code; |
633
|
|
|
|
|
|
|
} |
634
|
|
|
|
|
|
|
} |
635
|
|
|
|
|
|
|
else |
636
|
|
|
|
|
|
|
{ |
637
|
0
|
|
|
|
|
|
$str = $gdata; |
638
|
|
|
|
|
|
|
} |
639
|
0
|
|
|
|
|
|
my @args = ( |
640
|
|
|
|
|
|
|
$str, |
641
|
|
|
|
|
|
|
$self->_fromName($delay, \%chDLY), |
642
|
|
|
|
|
|
|
$self->_fromName($dir, \%srchDirection), |
643
|
|
|
|
|
|
|
); |
644
|
0
|
|
|
|
|
|
return $self->_simpleSetCommand('CSG', \@args, 1); |
645
|
|
|
|
|
|
|
} |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
sub getCustomSearchRange |
648
|
|
|
|
|
|
|
{ |
649
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
650
|
0
|
|
|
|
|
|
my $idx = shift; |
651
|
|
|
|
|
|
|
|
652
|
0
|
0
|
|
|
|
|
return $self->error("No search index") unless $idx; |
653
|
0
|
0
|
0
|
|
|
|
if($idx < 1 || $idx > 10) |
654
|
|
|
|
|
|
|
{ |
655
|
0
|
|
|
|
|
|
$self->error("Search index is out of range: $idx (1..10)"); |
656
|
|
|
|
|
|
|
} |
657
|
0
|
|
|
|
|
|
my $value = $self->_simpleGetCommand('CSP', args => [ $idx], pgm => 1, array => 1); |
658
|
0
|
0
|
|
|
|
|
return unless $value; |
659
|
|
|
|
|
|
|
|
660
|
0
|
|
|
|
|
|
return [ $self->_freq_human($value->[1]), $self->_freq_human($value->[2]) ]; |
661
|
|
|
|
|
|
|
} |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
sub getAllCustomSearchRanges |
664
|
|
|
|
|
|
|
{ |
665
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
666
|
|
|
|
|
|
|
|
667
|
0
|
|
|
|
|
|
$self->setProgramMode(); |
668
|
0
|
|
|
|
|
|
my @data; |
669
|
0
|
|
|
|
|
|
foreach my $n (1..10) |
670
|
|
|
|
|
|
|
{ |
671
|
0
|
|
|
|
|
|
push @data, $self->getCustomSearchRange($n); |
672
|
|
|
|
|
|
|
} |
673
|
0
|
|
|
|
|
|
$self->quitProgramMode(); |
674
|
|
|
|
|
|
|
|
675
|
0
|
|
|
|
|
|
return \@data; |
676
|
|
|
|
|
|
|
} |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
sub setCustomSearchRange |
679
|
|
|
|
|
|
|
{ |
680
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
681
|
0
|
|
|
|
|
|
my $idx = shift; |
682
|
0
|
|
|
|
|
|
my $left = shift; |
683
|
0
|
|
|
|
|
|
my $right = shift; |
684
|
|
|
|
|
|
|
|
685
|
0
|
0
|
|
|
|
|
return $self->error("No search index") unless $idx; |
686
|
0
|
0
|
0
|
|
|
|
if($idx < 1 || $idx > 10) |
687
|
|
|
|
|
|
|
{ |
688
|
0
|
|
|
|
|
|
$self->error("Search index is out of range: $idx (1..10)"); |
689
|
|
|
|
|
|
|
} |
690
|
0
|
0
|
|
|
|
|
return $self->error("No left bound frequency") unless $left; |
691
|
0
|
0
|
|
|
|
|
return $self->error("No right bound frequency") unless $right; |
692
|
|
|
|
|
|
|
|
693
|
0
|
|
|
|
|
|
my @args = ( $idx, $self->_from_human_freq($left), $self->_from_human_freq($right) ); |
694
|
|
|
|
|
|
|
|
695
|
0
|
|
|
|
|
|
return $self->_simpleSetCommand('CSP', \@args, 1); |
696
|
|
|
|
|
|
|
} |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
sub clearMemory |
699
|
|
|
|
|
|
|
{ |
700
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
701
|
|
|
|
|
|
|
|
702
|
0
|
|
|
|
|
|
my $val = $self->_simpleGetCommand('CLR', prm => 1); |
703
|
|
|
|
|
|
|
|
704
|
0
|
0
|
|
|
|
|
return $val eq 'OK' ? 1: 0; |
705
|
|
|
|
|
|
|
} |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
### main method ### |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
sub command |
710
|
|
|
|
|
|
|
{ |
711
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
712
|
0
|
|
|
|
|
|
my $cmdName = uc(shift); |
713
|
0
|
|
|
|
|
|
my $args = shift; |
714
|
|
|
|
|
|
|
|
715
|
0
|
|
|
|
|
|
my $str = $cmdName; |
716
|
0
|
0
|
0
|
|
|
|
if($args && ref($args) eq 'ARRAY' && scalar(@$args) > 0) |
|
|
|
0
|
|
|
|
|
717
|
|
|
|
|
|
|
{ |
718
|
0
|
0
|
|
|
|
|
$str .= ",".join(',', map { defined($_) ? $_: '' } @$args); |
|
0
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
} |
720
|
0
|
0
|
|
|
|
|
if($self->_write($str)) |
721
|
|
|
|
|
|
|
{ |
722
|
0
|
|
|
|
|
|
my $resp = $self->_readstr(); |
723
|
0
|
0
|
|
|
|
|
unless($resp) |
724
|
|
|
|
|
|
|
{ |
725
|
0
|
|
|
|
|
|
return { status => 'ERROR', desc => 'Zero read from port' }; |
726
|
|
|
|
|
|
|
} |
727
|
0
|
|
|
|
|
|
my @out = split(',', $resp); |
728
|
0
|
|
|
|
|
|
my $first = shift @out; |
729
|
0
|
0
|
|
|
|
|
if($first eq $cmdName) |
|
|
0
|
|
|
|
|
|
730
|
|
|
|
|
|
|
{ |
731
|
0
|
0
|
0
|
|
|
|
if(scalar(@out) && $out[0] eq 'ERR') |
732
|
|
|
|
|
|
|
{ |
733
|
0
|
|
|
|
|
|
shift @out; |
734
|
0
|
|
|
|
|
|
my $desc = 'Radio returned error'; |
735
|
0
|
0
|
|
|
|
|
if(scalar(@out)) |
736
|
|
|
|
|
|
|
{ |
737
|
0
|
|
|
|
|
|
$desc .= ' ('.join(',', @out).')'; |
738
|
|
|
|
|
|
|
} |
739
|
0
|
|
|
|
|
|
return { status => 'ERROR', desc => $desc }; |
740
|
|
|
|
|
|
|
} |
741
|
0
|
|
|
|
|
|
return { status => 'OK', data => \@out }; |
742
|
|
|
|
|
|
|
} |
743
|
|
|
|
|
|
|
elsif($first eq 'ERR') |
744
|
|
|
|
|
|
|
{ |
745
|
0
|
|
|
|
|
|
return { status => 'ERROR', desc => join(',', @out) }; |
746
|
|
|
|
|
|
|
} |
747
|
|
|
|
|
|
|
else |
748
|
|
|
|
|
|
|
{ |
749
|
0
|
|
|
|
|
|
return { status => 'ERROR', desc => "Wrong response: $resp" }; |
750
|
|
|
|
|
|
|
} |
751
|
|
|
|
|
|
|
} |
752
|
0
|
|
|
|
|
|
return { status => 'ERROR', desc => 'Write failed' }; |
753
|
|
|
|
|
|
|
} |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
### internals ### |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
sub port |
758
|
|
|
|
|
|
|
{ |
759
|
0
|
|
|
0
|
0
|
|
shift->{_port}; |
760
|
|
|
|
|
|
|
} |
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
sub error |
763
|
|
|
|
|
|
|
{ |
764
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
765
|
|
|
|
|
|
|
|
766
|
0
|
0
|
|
|
|
|
if($self->{fatal}) |
767
|
|
|
|
|
|
|
{ |
768
|
0
|
|
|
|
|
|
die "ERROR: ", @_; |
769
|
|
|
|
|
|
|
} |
770
|
|
|
|
|
|
|
else |
771
|
|
|
|
|
|
|
{ |
772
|
0
|
|
|
|
|
|
print STDERR "ERROR: ", @_; |
773
|
|
|
|
|
|
|
} |
774
|
|
|
|
|
|
|
} |
775
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
sub _echo |
777
|
|
|
|
|
|
|
{ |
778
|
0
|
|
|
0
|
|
|
my $self = shift; |
779
|
0
|
|
|
|
|
|
my $str = shift; |
780
|
|
|
|
|
|
|
|
781
|
0
|
0
|
|
|
|
|
return unless $self->{echo}; |
782
|
0
|
|
|
|
|
|
print $str."\n"; |
783
|
|
|
|
|
|
|
} |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
sub _write |
786
|
|
|
|
|
|
|
{ |
787
|
0
|
|
|
0
|
|
|
my $self = shift; |
788
|
0
|
|
|
|
|
|
my $str = shift; |
789
|
|
|
|
|
|
|
|
790
|
0
|
|
|
|
|
|
$self->_echo("-> $str"); |
791
|
0
|
|
|
|
|
|
my $n = $self->port->write("$str\015\012"); |
792
|
0
|
0
|
|
|
|
|
if($n) |
793
|
|
|
|
|
|
|
{ |
794
|
0
|
|
|
|
|
|
return $n; |
795
|
|
|
|
|
|
|
} |
796
|
|
|
|
|
|
|
else |
797
|
|
|
|
|
|
|
{ |
798
|
0
|
|
|
|
|
|
$self->error("Write failed\n"); |
799
|
|
|
|
|
|
|
} |
800
|
0
|
|
|
|
|
|
return; |
801
|
|
|
|
|
|
|
} |
802
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
sub _readstr |
804
|
|
|
|
|
|
|
{ |
805
|
0
|
|
|
0
|
|
|
my $self = shift; |
806
|
|
|
|
|
|
|
|
807
|
0
|
|
|
|
|
|
my $port = $self->port; |
808
|
|
|
|
|
|
|
|
809
|
0
|
|
|
|
|
|
my $timeout = $self->{timeout}; |
810
|
0
|
|
|
|
|
|
my $buffer = ""; |
811
|
0
|
|
|
|
|
|
while ($timeout>0) |
812
|
|
|
|
|
|
|
{ |
813
|
0
|
|
|
|
|
|
my ($count,$saw)=$port->read(255); |
814
|
0
|
0
|
|
|
|
|
if ($count > 0) |
815
|
|
|
|
|
|
|
{ |
816
|
0
|
|
|
|
|
|
$buffer .= $saw; |
817
|
0
|
0
|
|
|
|
|
if($buffer =~ /\015$/) |
818
|
|
|
|
|
|
|
{ |
819
|
0
|
|
|
|
|
|
last; |
820
|
|
|
|
|
|
|
} |
821
|
|
|
|
|
|
|
} |
822
|
|
|
|
|
|
|
else |
823
|
|
|
|
|
|
|
{ |
824
|
0
|
|
|
|
|
|
$timeout--; |
825
|
|
|
|
|
|
|
} |
826
|
|
|
|
|
|
|
} |
827
|
|
|
|
|
|
|
|
828
|
0
|
0
|
|
|
|
|
if($timeout == 0) |
829
|
|
|
|
|
|
|
{ |
830
|
0
|
|
|
|
|
|
print STDERR "*** Timeout ***\n"; |
831
|
|
|
|
|
|
|
} |
832
|
|
|
|
|
|
|
else |
833
|
|
|
|
|
|
|
{ |
834
|
0
|
|
|
|
|
|
$self->_echo("<- $buffer"); |
835
|
|
|
|
|
|
|
} |
836
|
0
|
|
|
|
|
|
$buffer =~ s/\015$//; |
837
|
0
|
|
|
|
|
|
return $buffer; |
838
|
|
|
|
|
|
|
} |
839
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
sub _simpleGetCommand |
841
|
|
|
|
|
|
|
{ |
842
|
0
|
|
|
0
|
|
|
my $self = shift; |
843
|
0
|
|
|
|
|
|
my $cmd = shift; |
844
|
0
|
|
|
|
|
|
my %opts = @_; |
845
|
|
|
|
|
|
|
|
846
|
0
|
|
|
|
|
|
my $pgm = $opts{pgm}; |
847
|
0
|
|
|
|
|
|
my $qp = 0; |
848
|
0
|
0
|
0
|
|
|
|
if($pgm && !($self->{_pgm})) |
849
|
|
|
|
|
|
|
{ |
850
|
0
|
|
|
|
|
|
$self->setProgramMode(); |
851
|
0
|
|
|
|
|
|
$qp = 1; |
852
|
|
|
|
|
|
|
} |
853
|
0
|
|
|
|
|
|
my @ARGS = ($cmd); |
854
|
0
|
0
|
|
|
|
|
if($opts{args}) |
855
|
|
|
|
|
|
|
{ |
856
|
0
|
|
|
|
|
|
push @ARGS, $opts{args}; |
857
|
|
|
|
|
|
|
} |
858
|
0
|
|
|
|
|
|
my $res = $self->command(@ARGS); |
859
|
|
|
|
|
|
|
|
860
|
0
|
|
|
|
|
|
my $out; |
861
|
0
|
0
|
|
|
|
|
if($res->{status} eq 'OK') |
862
|
|
|
|
|
|
|
{ |
863
|
0
|
0
|
|
|
|
|
if($opts{array}) |
864
|
|
|
|
|
|
|
{ |
865
|
0
|
|
|
|
|
|
$out = $res->{data}; |
866
|
|
|
|
|
|
|
} |
867
|
|
|
|
|
|
|
else |
868
|
|
|
|
|
|
|
{ |
869
|
0
|
|
0
|
|
|
|
my $idx = $opts{index} || 0; |
870
|
0
|
|
|
|
|
|
$out = $res->{data}->[$idx]; |
871
|
|
|
|
|
|
|
} |
872
|
|
|
|
|
|
|
} |
873
|
|
|
|
|
|
|
else |
874
|
|
|
|
|
|
|
{ |
875
|
0
|
|
|
|
|
|
print STDERR "ERROR: $res->{desc}\n"; |
876
|
|
|
|
|
|
|
} |
877
|
0
|
0
|
|
|
|
|
$self->quitProgramMode() if($qp); |
878
|
0
|
|
|
|
|
|
return $out; |
879
|
|
|
|
|
|
|
} |
880
|
|
|
|
|
|
|
|
881
|
|
|
|
|
|
|
sub _simpleSetCommand |
882
|
|
|
|
|
|
|
{ |
883
|
0
|
|
|
0
|
|
|
my $self = shift; |
884
|
0
|
|
|
|
|
|
my $cmd = shift; |
885
|
0
|
|
|
|
|
|
my $value = shift; |
886
|
0
|
|
|
|
|
|
my $pgm = shift; |
887
|
|
|
|
|
|
|
|
888
|
0
|
|
|
|
|
|
my $qp = 0; |
889
|
0
|
0
|
0
|
|
|
|
if($pgm && !($self->{_pgm})) |
890
|
|
|
|
|
|
|
{ |
891
|
0
|
|
|
|
|
|
$self->setProgramMode(); |
892
|
0
|
|
|
|
|
|
$qp = 1; |
893
|
|
|
|
|
|
|
} |
894
|
0
|
|
|
|
|
|
my $out = 0; |
895
|
0
|
0
|
|
|
|
|
my $res = $self->command($cmd, (ref($value) eq 'ARRAY' ? $value : [ $value ])); |
896
|
0
|
0
|
|
|
|
|
if($res->{status} eq 'OK') |
897
|
|
|
|
|
|
|
{ |
898
|
0
|
0
|
0
|
|
|
|
if($res->{data} && $res->{data}->[0] eq 'NG') |
899
|
|
|
|
|
|
|
{ |
900
|
0
|
|
|
|
|
|
$out = -1; |
901
|
|
|
|
|
|
|
} |
902
|
|
|
|
|
|
|
else |
903
|
|
|
|
|
|
|
{ |
904
|
0
|
|
|
|
|
|
$out = 1; |
905
|
|
|
|
|
|
|
} |
906
|
|
|
|
|
|
|
} |
907
|
|
|
|
|
|
|
else |
908
|
|
|
|
|
|
|
{ |
909
|
0
|
|
|
|
|
|
print STDERR "ERROR: $res->{desc}\n"; |
910
|
|
|
|
|
|
|
} |
911
|
0
|
0
|
|
|
|
|
$self->quitProgramMode() if($qp); |
912
|
0
|
|
|
|
|
|
return $out; |
913
|
|
|
|
|
|
|
} |
914
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
sub _getName |
917
|
|
|
|
|
|
|
{ |
918
|
0
|
|
|
0
|
|
|
my $self = shift; |
919
|
0
|
|
|
|
|
|
my $code = shift; |
920
|
0
|
|
|
|
|
|
my $src = shift; |
921
|
|
|
|
|
|
|
|
922
|
0
|
0
|
|
|
|
|
return unless defined($code); |
923
|
0
|
0
|
|
|
|
|
return $src->{$code} if $src->{$code}; |
924
|
0
|
|
|
|
|
|
return 'UNKNOWN'; |
925
|
|
|
|
|
|
|
} |
926
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
sub _fromName |
928
|
|
|
|
|
|
|
{ |
929
|
0
|
|
|
0
|
|
|
my $self = shift; |
930
|
0
|
|
|
|
|
|
my $name = shift; |
931
|
0
|
|
|
|
|
|
my $src = shift; |
932
|
|
|
|
|
|
|
|
933
|
0
|
0
|
|
|
|
|
return $name if($name =~ /^\d+$/); |
934
|
|
|
|
|
|
|
|
935
|
0
|
|
|
|
|
|
my %reverse = map { $src->{$_} => $_ } keys %$src; |
|
0
|
|
|
|
|
|
|
936
|
0
|
|
|
|
|
|
my $NAME = uc($name); |
937
|
|
|
|
|
|
|
|
938
|
0
|
0
|
|
|
|
|
return $reverse{$NAME} if exists $reverse{$NAME}; |
939
|
0
|
|
|
|
|
|
return $name; |
940
|
|
|
|
|
|
|
} |
941
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
sub _freq_human |
943
|
|
|
|
|
|
|
{ |
944
|
0
|
|
|
0
|
|
|
my $self = shift; |
945
|
0
|
|
|
|
|
|
my $f = shift; |
946
|
|
|
|
|
|
|
|
947
|
0
|
0
|
|
|
|
|
return undef if length($f) != 8; |
948
|
|
|
|
|
|
|
|
949
|
0
|
|
|
|
|
|
my $A = substr($f, 0, 4) + 0; |
950
|
0
|
|
|
|
|
|
my $B = substr($f, 4); |
951
|
|
|
|
|
|
|
|
952
|
0
|
|
|
|
|
|
return "$A.$B"; |
953
|
|
|
|
|
|
|
} |
954
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
sub _from_human_freq |
956
|
|
|
|
|
|
|
{ |
957
|
0
|
|
|
0
|
|
|
my $self = shift; |
958
|
0
|
|
|
|
|
|
my $value = shift; |
959
|
|
|
|
|
|
|
|
960
|
0
|
0
|
|
|
|
|
if($value =~ /^(\d+)\.(\d+)$/) |
|
|
0
|
|
|
|
|
|
961
|
|
|
|
|
|
|
{ |
962
|
0
|
|
|
|
|
|
my $out = sprintf("%04d%-04s", $1, $2); |
963
|
0
|
|
|
|
|
|
$out =~ s/ /0/g; |
964
|
0
|
|
|
|
|
|
return $out; |
965
|
|
|
|
|
|
|
|
966
|
|
|
|
|
|
|
} |
967
|
|
|
|
|
|
|
elsif($value =~ /^\d+$/) |
968
|
|
|
|
|
|
|
{ |
969
|
0
|
|
|
|
|
|
return sprintf("%04d0000", $value); |
970
|
|
|
|
|
|
|
} |
971
|
0
|
|
|
|
|
|
return $value; |
972
|
|
|
|
|
|
|
} |
973
|
|
|
|
|
|
|
|
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
1; |