File Coverage

blib/lib/Ham/Device/FT950.pm
Criterion Covered Total %
statement 15 308 4.8
branch 0 138 0.0
condition 0 24 0.0
subroutine 5 43 11.6
pod 30 35 85.7
total 50 548 9.1


line stmt bran cond sub pod time code
1             package Ham::Device::FT950;
2              
3 1     1   36442 use 5.008008;
  1         5  
  1         44  
4 1     1   6 use strict;
  1         3  
  1         36  
5 1     1   40 use warnings;
  1         8  
  1         58  
6             require Exporter;
7 1     1   1421 use Device::SerialPort qw(:PARAM :STAT 0.07);
  1         41809  
  1         409  
8 1     1   14 use Carp;
  1         2  
  1         4445  
9             $|=1;
10              
11             our @ISA = qw();
12             our @EXPORT = qw();
13              
14             our @EXPORT_OK = qw();
15              
16             our $VERSION = '0.29.4 ';
17             #Version .23 starts OO work.
18              
19             my ($result, %rig_mode, %inv_rig_mode, %band, %inv_band);
20             my $port;
21              
22             # Going to talk to a Yaesu FT-950
23             # Constructor to start communicating
24             sub new {
25 0     0 0   my $invocant = shift;
26 0   0       my $class = ref($invocant) || $invocant;
27 0           my $self = {
28             portname => "/dev/ttyS0", #Defaults, can be overidden
29             databits => 8, #during construction by user.
30             baudrate => 4800,
31             parity => "none",
32             stopbits => 1,
33             handshake => "rts",
34             alias => "FT-950",
35             user_msg => "OFF",
36             lockfile => 1,
37             #configFile => "FT950.ini",
38             read_char_time => 0,
39             read_const_time => 20,
40             @_
41             };
42 0           bless($self, $class);
43 0           $self->_init;
44 0           $self->_openSerial();
45 0           return $self;
46             }
47              
48              
49             #Accessor Methods
50 0 0   0 1   sub portname { $_[0]->{portname }=$_[1] if defined $_[1]; $_[0]->{portname } }
  0            
51 0 0   0 1   sub databits { $_[0]->{databits }=$_[1] if defined $_[1]; $_[0]->{databits } }
  0            
52 0 0   0 0   sub baudrate { $_[0]->{baudrate }=$_[1] if defined $_[1]; $_[0]->{baudrate } }
  0            
53 0 0   0 1   sub parity { $_[0]->{parity }=$_[1] if defined $_[1]; $_[0]->{parity } }
  0            
54 0 0   0 1   sub stopbits { $_[0]->{stopbits }=$_[1] if defined $_[1]; $_[0]->{stopbits } }
  0            
55 0 0   0 1   sub handshake { $_[0]->{handshake }=$_[1] if defined $_[1]; $_[0]->{handshake } }
  0            
56 0 0   0 1   sub read_char_time { $_[0]->{read_char_time }=$_[1] if defined $_[1]; $_[0]->{read_char_time } }
  0            
57 0 0   0 1   sub read_const_time { $_[0]->{read_const_time }=$_[1] if defined $_[1]; $_[0]->{read_const_time } }
  0            
58 0 0   0 1   sub alias { $_[0]->{alias }=$_[1] if defined $_[1]; $_[0]->{alias } }
  0            
59 0 0   0 1   sub user_msg { $_[0]->{user_msg }=$_[1] if defined $_[1]; $_[0]->{user_msg } }
  0            
60 0 0   0 0   sub configFile { $_[0]->{configFile }=$_[1] if defined $_[1]; $_[0]->{configFile } }
  0            
61 0 0   0 1   sub lockfile { $_[0]->{lockfile }=$_[1] if defined $_[1]; $_[0]->{lockfile } }
  0            
62             #Blank Accessor
63             #sub { $_[0]->{ }=$_[1] if defined $_[1]; $_[0]->{ } }
64             sub _init {
65 0     0     my $self = shift;
66             #So far we don't have anything to do.
67             }
68              
69             sub _openSerial {
70            
71 0     0     my $self = shift;
72 0           my $quite = 0;
73 0           my $lockfile = $self->portname;
74 0 0         if ($self->lockfile) { #looking for 1 or 0, 1=use lockfile, 0=no lockfile
75 0           chomp($lockfile);
76 0           $lockfile =~ /(tty.+$)/;
77 0           $lockfile = "/var/lock/LCK..".$1;
78             } else {
79 0           $lockfile = "";
80             }
81             #print "Lockfile is $lockfile \n";
82 0 0         unless ($port = Device::SerialPort -> new($self->portname, $quite, $lockfile)) { croak "Unable to open " . $self->portname . ": $^E\n"; }
  0            
83 0           $port->alias($self->alias);
84 0           $port->user_msg($self->user_msg);
85 0           $port->databits($self->databits);
86 0           $port->baudrate($self->baudrate);
87 0           $port->parity($self->parity);
88 0           $port->stopbits($self->stopbits);
89 0           $port->handshake($self->handshake);
90 0           $port->read_char_time($self->read_char_time);
91 0           $port->read_const_time($self->read_const_time);
92             #$port->save($self->configFile);
93             }
94              
95             sub DESTROY {
96 0     0     my $self = shift;
97 0           undef $port;
98             }
99              
100             #This is the original way to set serial port.
101             #my $portName = "/dev/ttyUSB0";
102             #my $port = Device::SerialPort -> new($portName) || croak "Unable to open $portName: $^E\n";
103             # $port-> alias("FT-950");
104             # $port-> user_msg("OFF");
105             # $port-> databits(8);
106             # $port-> baudrate(9600);
107             # $port-> parity("none");
108             # $port-> stopbits(1);
109             # $port-> handshake("rts");
110            
111             # $port-> write_settings;
112             # $port-> save($configFile) || warn "Unable to write config file\n";
113              
114             #$port->read_char_time(0); # don't wait for each character
115             #$port->read_const_time(20); # 1 second per unfulfilled "read" call
116              
117              
118             ###############################
119             # Set up a hash with rig modes
120             %rig_mode = qw( 1 LSB 2 USB 3 CW 4 FM 5 AM 6 FSK 7 CW-R 8 PKT-L 9 FSK-R A PKT-FM B FM-N C PKT-U D AM-N);
121             %inv_rig_mode = reverse %rig_mode;
122             ############################
123             ##############################
124             # Set up a band hash
125             %band = qw(00 1.8 01 3.5 03 7 04 10 05 14 06 18 07 21 08 24.5 09 28 10 50 11 GEN);
126             %inv_band = reverse %band;
127             ##############################
128              
129              
130              
131             #####################################
132             #
133             # sub closePort
134             # clean up serial connection
135             #
136             #sub closePort {
137             #
138             # $port->close || warn "Serial port did not close proper!\n";
139             # undef $port;
140             #}
141              
142             # print "All Closed up\n";
143             #####################################
144             #
145             # sub writeOpt
146             # Write FT-950 Options to file
147             # Writes options to "FT950-options" to
148             # current directory.
149             # return undef on fail, 1 on success
150             #
151             sub writeOpt {
152 0     0 1   my $self = shift;
153 0           my $filename = shift;
154 0 0         unless ($filename) { $filename = "FT950-options" }
  0            
155 0           my ($option,$p);
156 0 0         if (!open OUTFILE, ">$filename") {
157 0           warn "Unable to open file to write options!\n";
158 0           return undef;
159             }
160 0           for ($option = 1; $option <= 118; $option++) {
161 0           $p = sprintf "%03d", "$option";
162 0           print OUTFILE "$option ".$self->readOpt($p)."\n";
163             }
164 0           close OUTFILE;
165 0           return 1;
166             }
167             #####################################
168             #
169             # readOpt()
170             # Sent the option number 001-118
171             # and return the result
172             #
173             sub readOpt {
174 0     0 1   my $self = shift;
175 0           my $opt = shift;
176 0           my $count;
177 0 0 0       if ($opt lt "001" || $opt gt "118") {
178 0           print "Option must be 001-118\n";
179 0           return undef;
180             }
181 0 0         unless ($count = $self->writeCmd('EX'.$opt.';')) { return undef; }
  0            
182 0           my $result = $self->readResult();
183 0           $result =~ /EX\d{3}([+-]?\d+)\;/;
184 0           my $r = $1;
185             #print "Result from readReslt = $result, from \$r = $r\n";
186 0           return $r;
187            
188             }
189             #####################################
190             #
191             # sub playBack
192             # Plays back the Digital Voice Keyer
193             # send it string 01-05 for channels 1-5
194             #
195             sub playBack {
196 0     0 1   my $self = shift;
197 0           my $channel = shift;
198 0           my $count;
199 0 0 0       if ($channel lt "01" || $channel gt "05") {
200 0           print "Channel must be 01-05\n";
201 0           return undef;
202             }
203 0 0         unless ($count = $self->writeCmd('pb'.$channel.';')) { return undef; }
  0            
204 0           return $count;
205             }
206            
207             #####################################
208             #
209             # sub setPower
210             # set the rig power output
211             # sent it 005-100
212             #
213             sub setPower {
214 0     0 1   my $self = shift;
215 0           my $power = shift;
216 0           my $count;
217 0 0 0       if (!($power ge "005" && $power le "100")) {
218 0           print "Power must be 005 to 100\n";
219             return undef
220 0           }
221 0 0         unless ($count = $self->writeCmd('pc'.$power.';')) { return undef; }
  0            
222 0           return $count;
223             }
224             ####################################
225             #
226             # sub getPower
227             # returns power in watts
228             # value between 5-100
229             #
230             sub getPower {
231 0     0 1   my $self = shift;
232 0           my $power;
233 0 0         unless ($power = $self->writeCmd('pc;')) { return undef; }
  0            
234 0           my $result = $self->readResult();
235 0           $result =~ /PC(\d+)\;/;
236 0           my $p = $1;
237 0           $p = sprintf "%d", "$p";
238 0           return $p;
239             }
240              
241             #####################################
242             #
243             # sub swapVfo
244             # exchanges vfo freqs, B into A, A into B
245             # Return num of chars sent or undef
246             #
247             sub swapVfo {
248 0     0 1   my $self = shift;
249 0           my $swap;
250 0 0         unless ($swap = $self->writeCmd('SV;')) { return undef; }
  0            
251 0           return $swap;
252             }
253              
254             #####################################
255             #
256             # sub vfoSelect
257             # select VFO A or B
258             # 0=A, 1=B
259             # return num chars sent or undef
260             # if you select the same vfo twice it will mute
261             #
262             sub vfoSelect {
263 0     0 1   my $self = shift;
264 0           my $vfo = shift;
265 0           my $result;
266 0           $vfo = uc($vfo);
267 0 0         if ($vfo eq 'A') {
    0          
268 0 0         unless ($result = $self->writeCmd('VS'."0".';')) { return undef; }
  0            
269 0           return $result;
270             } elsif ($vfo eq 'B') {
271 0 0         unless ($result = $self->writeCmd('VS'."1".';')) { return undef; }
  0            
272 0           return $result;
273             } else {
274 0           print "vfo must be A or B\n";
275 0           return undef;
276             }
277             }
278             #####################################
279             #
280             # sub getActVfo
281             # Returns active vfo (receiving) A or B
282             # return undef on error
283             #
284             sub getActVfo {
285 0     0 1   my $self = shift;
286 0           my $vfo;
287             my $result;
288 0 0         unless ($result = $self->writeCmd('VS;')) { return undef; }
  0            
289 0           $vfo = $self->readResult();
290 0           $vfo =~ /VS(\d)\;/;
291 0           my $v = $1;
292 0 0         if ($v == 0) {
    0          
293 0           return "A";
294             } elsif ($v == 1) {
295 0           return "B";
296             }
297 0           return undef;
298             }
299              
300             #####################################
301             #
302             # sub bandSelect
303             # Sets the band
304             # Expects to receive the band in Mhz. It converts
305             # to the special numbers that the 950 needs:
306             # 00=1.8 01=3.5 02=? 03=7 04=10 05=14
307             # 06=18 07=21 08=28.5 09=28 10=50 11=GEN
308             #
309             # No way to query the band so guess we just
310             # trust it happens!
311             # Return undef if no bytes transmitted else
312             # return number of bytes sent.
313             #
314              
315             sub bandSelect {
316 0     0 1   my $self = shift;
317 0           my $band = shift;
318 0           my $numchars;
319 0 0         if (!$inv_band{$band}) {
320 0           carp "Invalid band!\n";
321 0           return undef;
322             }
323 0           my $b = $inv_band{$band};
324 0 0         unless ($numchars = $self->writeCmd('BS'.$b.';')) { return undef; }
  0            
325 0           return $numchars;
326             }
327              
328             #####################################
329             #
330             # sub getFreq
331             #
332             # Send getFreq VFO "A" or "B"
333             # Return the 950 frequency in Mhz
334             # Return undef on failure.
335              
336             sub getFreq {
337 0     0 1   my $self = shift; #if called $obj->getFreq("a"), this is obj reference
338 0           my $vfo = shift; #this is the argument we want.
339 0           my $result;
340 0           $vfo = uc($vfo);
341 0 0 0       if ($vfo ne "A" && $vfo ne "B") {
342 0           carp "VFO must be A or B!\n";
343 0           return undef;
344             }
345 0           $self->writeCmd('f'.$vfo.';');
346 0 0         unless ($result = $self->readResult()) { return undef }
  0            
347 0           $result =~ /(F[A-B])(\d+)\;/; # So if we receive fa14000000;
348 0           my $f = $2; # $2 has the numeric portion of the string
349 0           $f = $f / 1000000;
350 0           $f = sprintf "%2.6f", "$f";
351 0           return $f;
352             }
353              
354             ###########################################
355             #
356             # setFreq
357             # Send the FT-950 VFO and Freq and it will
358             # Set. Freq is verified.
359             # Freq must be sent in Mhz
360             #
361             sub setFreq {
362 0     0 1   my $self = shift;
363 0           my ($vfo, $freq) = @_; # Pass VFO and Freq
364             #print "We got VFO:$vfo and Freq:$freq .\n";
365 0           my $result = '';
366 0           $vfo = uc($vfo); # Make VFO upper case
367 0           $freq = $freq * 1000000; # Change freq to hertz
368             #print "The freq after math: $freq\n";
369 0 0 0       if ($freq < 30000 || $freq > 56000000) {
370 0           carp "Frequency out of range!\n";
371 0           return undef;
372             }
373 0           $freq = sprintf("%08d", $freq); #make sure the freq is padded
374             #7200000 needs to be 07200000
375             #print "The Freq after sprintf: $freq\n";
376 0 0 0       if ($vfo ne "A" && $vfo ne "B") {
377 0           carp "VFO must be A or B!\n";
378 0           return undef;
379             }
380 0 0         if ($vfo eq "A") {
    0          
381 0           $self->writeCmd('fa'.$freq.';');
382 0           $result = $self->getFreq('A');
383             } elsif
384             ($vfo eq "B") {
385 0           $self->writeCmd('fb'.$freq.';');
386 0           $result = $self->getFreq('B');
387             }
388 0           return $result;
389             }
390            
391              
392             ############################
393             #
394             # Sub writeCmd
395             # Send a scaler command (ie, "FA;")
396             # to FT-950. Must be correctly formatted.
397             # Returns number of chars successfully sent to rig
398             # or undef on failure.
399             #
400             eval {
401             sub writeCmd {
402 0     0 0   my $self = shift;
403 0           my $cmd = shift;
404 0           my $count;
405 0 0         unless ($count = $port->write($cmd)) { return undef; }
  0            
406 0           return $count;
407             }
408             };
409             ###############################
410             #
411             # Sub setMode
412             # Sets the rig mode, must sent the actual mode
413             # We take care of the numbers.
414             # Options are 1=LSB, 2=USB, 3=CW, 4=FM, 5=AM, 6=FSK-L
415             # 7=CW-R, 8=PKT-L, 9=FSK-R, A=PKT-FM, B=FM-N, C=PKT-U
416             # D=AM-N
417             # uses has $inv_rig_mode
418             sub setMode {
419 0     0 1   my $self = shift;
420 0           my $mode = shift;
421 0           $mode = uc($mode);
422 0 0         if ((!$inv_rig_mode{$mode})) {
423 0           print "Mode $mode is invalid\n";
424 0           return undef;
425             }
426 0           my $m = $inv_rig_mode{$mode};
427 0           $self->writeCmd('md0'.$m.';');
428 0           my $result = $self->getMode();
429 0           return $result;
430            
431             }
432             ##############################
433             #
434             # Sub getMode
435             # Returns the mode of the rig
436             # uses hash $rig_mode
437             #
438             eval {
439             sub getMode {
440 0     0 1   my $self = shift;
441 0           $self->writeCmd('md0;');
442 0   0       my $mode = $self->readResult() || croak "Unable to read Rig Mode!\n";
443             #print "getMode:result of command: $mode\n";
444 0           $mode =~ /MD0([0-9A-D])\;/;
445 0           my $m = $rig_mode{$1};
446             #print "getMode:Value returned: $m\n";
447 0           return $m;
448            
449             }
450             };
451              
452             ###########################################
453             #
454             # Sub readSMeter
455             #
456             # Reads the S-Meter
457             # Send a "RM1;
458             # receive a string back RM1XXX; where
459             # XXX = 000-255
460             # Sub return a value 000-255 or undef
461             #
462             sub readSMeter {
463 0     0 1   my $self = shift;
464 0           my $meter;
465 0           $self->writeCmd('RM1;');
466 0 0         unless ($meter = $self->readResult()) {return undef }
  0            
467 0           $meter =~ /RM1(\d+)\;/;
468 0           my $r = $1;
469 0           return $r
470             }
471              
472             ###########################################
473             #
474             # Sub statBSY
475             #
476             # Retrieves status of BUSY light on
477             # front of Rig.
478             # Returns 1 if ON
479             # Returns 0 if OFF
480             # Return undef is error or don't know
481             eval {
482             sub statBSY {
483 0     0 1   my $self = shift;
484 0           my ($busy, $result);
485 0 0         unless ($result = $self->writeCmd('BY;')) { return undef; }
  0            
486 0           $busy = $self->readResult();
487 0           $busy =~ /BY(\d+)\;/;
488 0           my $b = $1;
489 0 0         if ($b == 10) { return 1;
  0            
490 0           } else { return 0; }
491             }
492             };
493              
494             ###########################################
495             #
496             # Sub setMOX
497             #
498             # Sets and unsets the MOX (Manual Operated Xmit)
499             # Send a 1 to set, 0 to unset and 2 to status
500             # Status result:
501             # Returns 1 if ON
502             # Returns 0 if OFF
503             # Return undef is error or don't know
504             #
505             eval {
506             sub setMOX {
507 0     0 1   my $self = shift;
508 0           my $mox = shift;
509 0           my ($m, $result, $r);
510 0 0         if ($mox == 1) {
    0          
    0          
511 0 0         unless ($result = $self->writeCmd('MX1;')) { return undef; }
  0            
512             } elsif ($mox == 0) {
513 0 0         unless ($result = $self->writeCmd('MX0;')) { return undef; }
  0            
514             } elsif ($mox == 2) {
515 0 0         unless ($result = $self->writeCmd('MX;')) { return undef; }
  0            
516 0           $r = $self->readResult();
517 0           $r =~ /MX(\d)\;/;
518 0           return $1;
519             }
520             } #end sub
521             }; #end eval
522              
523             ###########################################
524             #
525             # Sub setVOX
526             #
527             # Sets and unsets the MOX (Voice Operated Xmit)
528             # Send a 1 to set, 0 to unset and 2 to status
529             # Status result:
530             # Returns 1 if ON
531             # Returns 0 if OFF
532             # Return undef is error or don't know
533             #
534             eval {
535             sub setVOX {
536 0     0 1   my $self = shift;
537 0           my ($vox, $m, $result, $r);
538 0           $vox = shift;
539 0 0         if ($vox == 1) {
    0          
    0          
540 0 0         unless ($result = $self->writeCmd('VX1;')) { return undef; }
  0            
541             } elsif ($vox == 0) {
542 0 0         unless ($result = $self->writeCmd('VX0;')) { return undef; }
  0            
543             } elsif ($vox == 2) {
544 0 0         unless ($result = $self->writeCmd('VX;')) { return undef; }
  0            
545 0           $r = $self->readResult();
546 0           $r =~ /VX(\d)\;/;
547 0           return $1;
548             }
549             } #end sub
550             }; #end eval
551              
552             ###########################################
553             #
554             # Sub statTX
555             #
556             # Retrieves TX status of Rig
557             # Returns 0 if Radio TX Off CAT TX OFF
558             # Returns 1 if Radio TX Off CAT TX ON
559             # Returns 2 if Radio TX ON CAT TX OFF
560             # Return undef is error or don't know
561             eval {
562             sub statTX {
563 0     0 1   my $self = shift;
564 0           my ($busy, $result);
565 0 0         unless ($result = $self->writeCmd('TX;')) { return undef; }
  0            
566 0           $busy = $self->readResult();
567 0           $busy =~ /TX(\d)\;/;
568 0           my $b = $1;
569 0 0         if ($b == 0) {
    0          
    0          
570 0           return 1;
571             } elsif ($b == 1) {
572 0           return 1;
573             } elsif ($b == 2) {
574 0           return 2;
575 0           } else { return undef; }
576             }
577             };
578              
579             ###########################################
580             #
581             # Sub statFastStep
582             #
583             # Retrieves status of "Fast Step" Button
584             # Returns 0 for Off
585             # Returns 1 for ON
586             # Return undef is error or don't know
587             eval {
588             sub statFastStep {
589 0     0 1   my $self = shift;
590 0           my ($busy, $result);
591 0 0         unless ($result = $self->writeCmd('FS;')) { return undef; }
  0            
592 0           $busy = $self->readResult();
593 0           $busy =~ /FS(\d)\;/;
594 0           my $b = $1;
595 0 0         if ($b == 0) {
    0          
596 0           return 0;
597             } elsif ($b == 1) {
598 0           return 1;
599             } else {
600 0           return undef;
601             }
602             }
603             };
604              
605             ###########################################
606             #
607             # Sub setFastStep
608             #
609             # Sets the fast step mode
610             # Send 0 for Off
611             # Send 1 for ON
612             # Returns number of chars transmitted or
613             # undef on error
614             eval {
615             sub setFastStep {
616 0     0 1   my $self = shift;
617 0           my ($cmd, $result);
618 0           $cmd = shift;
619 0 0         if ($cmd == 0) {
    0          
620 0 0         unless ($result = $self->writeCmd('FS0;')) { return undef; }
  0            
621 0           return $result;
622             } elsif ($cmd == 1) {
623 0 0         unless ($result = $self->writeCmd('FS1;')) { return undef; }
  0            
624 0           return $result;
625 0           } else { return undef;}
626            
627             }
628             };
629             ###########################################
630             #
631             # Sub readResult
632             #
633             # Returns the result from a command to FT-950
634             # Remember this only works right after a
635             # read command.
636             #
637              
638             sub readResult {
639 0     0 0   my $self = shift;
640 0           my $STALL_DEFAULT = 10; # how many seconds to wait for new input
641 0           my $timeout = $STALL_DEFAULT;
642 0           my $timeout_msg = "FT-950 timeout\n";
643 0           my $chars=0;
644 0           my $buffer="";
645              
646 0           while ($timeout>0) {
647 0           my ($count,$saw)=$port->read(255); # will read _up to_ 255 chars
648 0 0         if ($count > 0) {
649 0           $chars+=$count;
650 0           $buffer.=$saw;
651 0 0         if ($saw =~ /;/) {
652 0           return $buffer; # ; is end of data for FT-950
653 0           last;
654             }
655             # Check here to see if what we want is in the $buffer
656             # say "last" if we find it
657            
658             }
659             else {
660 0           $timeout--;
661             }
662             }
663 0           return $timeout_msg;
664             #if ($timeout==0) {
665             # die "Waited $STALL_DEFAULT seconds and never saw what I wanted\n";
666             #}
667             }
668             1;
669             __END__