File Coverage

BC75XLT.pm
Criterion Covered Total %
statement 12 437 2.7
branch 0 182 0.0
condition 0 91 0.0
subroutine 4 58 6.9
pod 42 45 93.3
total 58 813 7.1


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;