############################################## # $Id$ package main; use strict; use warnings; use Device::SerialPort; my %sets = ( "cmd" => "", "freq" => "", ); ##################################### sub SCIVT_Initialize($) { my ($hash) = @_; # Consumer $hash->{DefFn} = "SCIVT_Define"; $hash->{GetFn} = "SCIVT_Get"; $hash->{SetFn} = "SCIVT_Set"; $hash->{AttrList}= "model:SCD10,SCD20,SCD30"; } ##################################### sub SCIVT_Define($$) { my ($hash, $def) = @_; my @a = split("[ \t][ \t]*", $def); return "Define the serial device as a parameter, use none for a fake device" if(@a != 3); $hash->{STATE} = "Initialized"; my $dev = $a[2]; Log3 $hash, 1, "SCIVT device is none, commands will be echoed only" if($dev eq "none"); if($dev ne "none") { Log3 $hash, 3, "SCIVT opening device $dev"; my $po = new Device::SerialPort ($dev); return "SCIVT Can't open $dev: $!" if(!$po); Log3 $hash, 2, "SCIVT opened device $dev"; $po->close(); } $hash->{DeviceName} = $dev; $hash->{Timer} = 900; # call every 15 min $hash->{Cmd} = 'F'; # get all data, min/max unchanged my $tn = TimeNow(); $hash->{READINGS}{"freq"}{TIME} = $tn; $hash->{READINGS}{"freq"}{VAL} = $hash->{Timer}; $hash->{READINGS}{"cmd"}{TIME} = $tn; $hash->{READINGS}{"cmd"}{VAL} = $hash->{Cmd}; $hash->{CHANGED}[0] = "freq: $hash->{Timer}"; $hash->{CHANGED}[1] = "cmd: $hash->{Cmd}"; # InternalTimer blocks if init_done is not true my $oid = $init_done; $init_done = 1; SCIVT_GetStatus($hash); $init_done = $oid; return undef; } ##################################### sub SCIVT_Set($@) { my ($hash, @a) = @_; return "\"set SCIVT\" needs at least two parameter" if(@a < 3); my $name = $hash->{NAME}; Log3 $name, 4, "SCIVT Set request $a[1] $a[2], old: Timer:$hash->{Timer} Cmd: $hash->{Cmd}"; return "Unknown argument $a[1], choose one of " . join(" ", sort keys %sets) if(!defined($sets{$a[1]})); $name = shift @a; my $type = shift @a; my $arg = join("", @a); my $tn = TimeNow(); if($type eq "freq") { if ($arg > 0) { $hash->{Timer} = $arg * 60; $hash->{READINGS}{$type}{TIME} = $tn; $hash->{READINGS}{$type}{VAL} = $hash->{Timer}; $hash->{CHANGED}[0] = "$type: $hash->{Timer}"; } } if($type eq "cmd") { if ($arg eq "F") { $hash->{Cmd} = 'F'; # F : get all data } if ($arg eq "L") # L : get all data and clear min-/max values { $hash->{Cmd} = 'L'; } $hash->{READINGS}{$type}{TIME} = $tn; $hash->{READINGS}{$type}{VAL} = $hash->{Cmd}; $hash->{CHANGED}[0] = "$type: $hash->{Cmd}"; } DoTrigger($name, undef) if($init_done); Log3 $name, 3, "SCIVT Set result Timer:$hash->{Timer} sec Cmd:$hash->{Cmd}"; return "SCIVT => Timer:$hash->{Timer} Cmd:$hash->{Cmd}"; } ##################################### sub SCIVT_Get($@) { my ($hash, @a) = @_; return "get for an SCIVT device needs exactly one parameter" if(@a != 2); my $name = $hash->{NAME}; my $v; if($a[1] eq "data") { $v = SCIVT_GetLine($hash->{DeviceName}, $hash->{Cmd}); if(!defined($v)) { Log3 $name, 2, "SCIVT Get $a[1] error"; return "$a[0] $a[1] => Error"; } $v =~ s/[\r\n]//g; # Delete the NewLine $hash->{READINGS}{$a[1]}{VAL} = $v; $hash->{READINGS}{$a[1]}{TIME} = TimeNow(); } else { if($a[1] eq "param") { $v = "$hash->{DeviceName} $hash->{Timer} $hash->{Cmd}"; } else { return "Unknown argument $a[1], must be data or param"; } } Log3 $name, 3, "SCIVT Get $a[1] $v"; return "$a[0] $a[1] => $v"; } ##################################### sub SCIVT_GetStatus($) { my ($hash) = @_; my $dnr = $hash->{DEVNR}; my $name = $hash->{NAME}; # Call us in n minutes again. InternalTimer(gettimeofday()+ $hash->{Timer}, "SCIVT_GetStatus", $hash,1); my %vals; my $result = SCIVT_GetLine($hash->{DeviceName}, $hash->{Cmd}); if(!defined($result)) { Log3 $name, 4, "SCIVT read error, retry $hash->{DeviceName}, $hash->{Cmd}"; $result = SCIVT_GetLine($hash->{DeviceName}, $hash->{Cmd}); } if(!defined($result)) { Log3 $name, 2, "SCIVT read error, abort $hash->{DeviceName}, $hash->{Cmd}"; $hash->{STATE} = "timeout"; return $hash->{STATE}; } if (length($result) < 10) { Log3 $name, 2, "SCIVT incomplete line ($result)"; $hash->{STATE} = "incomplete"; } else { $result =~ s/^.*R://; $result =~ s/[\r\n ]//g; Log3 $name, 3, "SCIVT $result (raw)"; $result=~ s/,/./g; my @data = split(";", $result); my @names = ("Vs", "Is", "Temp", "minV", "maxV", "minI", "maxI"); my $tn = TimeNow(); for(my $i = 0; $i < int(@names); $i++) { $hash->{CHANGED}[$i] = "$names[$i]: $data[$i]"; $hash->{READINGS}{$names[$i]}{TIME} = $tn; $hash->{READINGS}{$names[$i]}{VAL} = $data[$i]; } DoTrigger($name, undef) if($init_done); $result =~ s/;/ /g; $hash->{STATE} = "$result"; } return $hash->{STATE}; } ##################################### sub SCIVT_GetLine($$) { my $retry = 0; my ($dev,$cmd) = @_; return "R:13,66; 0,0;30;13,62;15,09;- 0,2; 2,8;\n" if($dev eq "none"); # Fake-mode my $serport = new Device::SerialPort ($dev); if(!$serport) { Log3 undef, 1, "SCIVT: Can't open $dev: $!"; return undef; } $serport->reset_error(); $serport->baudrate(1200); $serport->databits(8); $serport->parity('none'); $serport->stopbits(1); $serport->handshake('none'); my $rm = "SCIVT timeout reading the answer"; my $data=""; $serport->write($cmd); sleep(1); for(;;) { my ($rout, $rin) = ('', ''); vec($rin, $serport->FILENO, 1) = 1; my $nfound = select($rout=$rin, undef, undef, 3.0); if($nfound < 0) { $rm = "SCIVT Select error $nfound / $!"; goto DONE; } last if($nfound == 0); my $buf = $serport->input(); if(!defined($buf) || length($buf) == 0) { $rm = "SCIVT EOF on $dev"; goto DONE; } $data .= $buf; if($data =~ m/[\r\n]/) { # Newline received $serport->close(); return $data; } } DONE: $serport->close(); Log3 undef, 3, "SCIVT $rm"; return undef; } 1; =pod =begin html

SCIVT

=end html =cut