The following virtual motor operates a temperature controller via USB. This is the VM code:
#!/usr/bin/perl -w # # file name: /online_dir/vm1.pl # # This script is a template for a virtual motor. # my ($method, $value_new) = @ARGV; my $status = 1; if( $method eq "set_position") { Spectra::set_temp_tcu200( $value_new); } elsif( $method eq "get_position") { $SYM{RETURN_VALUE} = Spectra::get_temp_tcu200(1); } elsif( $method eq "get_limit_min") { $SYM{RETURN_VALUE} = 0.; } elsif( $method eq "get_limit_max") { $SYM{RETURN_VALUE} = 1000; } elsif( $method eq "exec_stop") { ; } else { Spectra::error( "vm1: failed to identify $method"); $status = 0; goto finish; } finish: $status;
The functions that speak to the device are defined in /online_dir/TkIrc.pl:
# # # package Spectra; use strict; use Fcntl; use POSIX qw( :termios_h); my $flag_tcu200_open = 0; my $flag_tcu200_debug = 0; sub open_tcu200 { my $status = 1; my $dev = "/dev/ttyUSB0"; # # the configuration # #$ stty -F /dev/ttyUSB0 -a # speed 9600 baud; rows 0; columns 0; line = 0; # intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; # susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 0; time = 0; # parenb -parodd cs7 hupcl -cstopb cread clocal -crtscts # -ignbrk brkint ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany imaxbel iutf8 # -opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 # -isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke if( -e $dev) { system( "stty -F $dev 7fffe006:4:dad:0:3:1c:7f:15:4:0:0:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0"); } else { $dev = "/dev/ttyUSB1"; if( -e $dev) { system( "stty -F $dev 7fffe006:4:dad:0:3:1c:7f:15:4:0:0:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0"); } else { print " no USB device \n"; goto finish; } } if( !sysopen(USB, $dev, O_RDWR)) { if( !sysopen(USB, $dev, O_RDWR)) { Spectra::error(" open_tcu200: failed to open USB0 and USB1 "); $status = 0; goto finish; } } finish: return $status; } sub recv_tcu200 { my ( $tmo) = @_; my $status = undef; my $flag_retry = 0; if( !$flag_tcu200_open) { open_tcu200(); if( !$flag_tcu200_open) { Spectra::error( "Failed to open USB for Tcu200 controller"); goto finish; } } retry: my $rin = my $win = my $ein = ""; vec( $rin, fileno( USB), 1) = 1; $ein = $rin | $win; # # do we have input? # my $nfd = select( $rin, $win, $ein, $tmo); if( !$nfd) { Spectra::error( "TkIrc::recv_tcu200: time-out during select(), tmp $tmo"); $status = undef; goto finish; } my $buffer = " " x 101; sysread( USB, $buffer, 100, 0); $buffer = substr( $buffer, 3); $buffer = substr( $buffer, 0, length( $buffer) - 2); if( length( $buffer) < 1) { if( !$flag_retry) { $flag_retry = 1; if( $flag_tcu200_debug) { print "recv_tcu200: received empty answer, repeating recv()\n"; } goto retry; } else { Spectra::error(" TkIRc.pl::recv_tcu200: received 2nd empty answer"); $status = undef; goto finish; } } $status = $buffer; if( $flag_tcu200_debug) { print "recv_tcu200: <<< $status"; } finish: return $status; } sub send_tcu200 { my ($buffer_in) = @_; my $status = 1; if( !$flag_tcu200_open) { open_tcu200(); if( !$flag_tcu200_open) { Spectra::error( "Failed to open usb for Tcu200 controller"); $status = 0; goto finish; } } syswrite( USB, $buffer_in, length($buffer_in), 0); if( $flag_tcu200_debug) { print "send_tcu200: >>> $buffer_in\n"; } finish: return $status; } sub set_temp_tcu200 { my ( $setpoint) = @_; my $status = 1; my $part1 = "\0040011\002"; my $part2 = sprintf( "SL%.1f\003", $setpoint); my @l = unpack("C*", $part2); my $bcc = $l[0]; for( my $i = 1; $i < length( $part2); $i++) { $bcc = $bcc ^ $l[$i]; } my $buffer_out = $part1 . $part2 . chr($bcc) . "\r\n"; if( !send_tcu200( $buffer_out)) { Spectra::error( "TkIrc::set_temp_tcu200: failed to seg 'temp'"); $status = 0; goto finish; } select undef, undef, undef, 0.05; if( $flag_tcu200_debug) { print "send_tcu200: <<< $setpoint\n"; } finish: return $status; } sub get_temp_tcu200 { my $status = 1; my $buffer = "\0040011PV\005\r\n"; if( !send_tcu200( $buffer)) { Spectra::error( "TkIrc::get_temp_tcu200: failed to get 'temp'"); $status = 0; goto finish; } # # 2 seconds time-out # select undef, undef, undef, 0.05; my $buffer = recv_tcu200( 2); if( !defined( $buffer)) { $status = Spectra::error( "TkIRc::get_temp_tcu200: failed to receive temp"); goto finish; } # # remove a leading 'V' which comes when a new temperatur is sent # $buffer =~ s/^V(.+)$/$1/; finish: return $buffer; }