From 74c0685302fb49909034ba463ff0ecd5c9fd0a8e Mon Sep 17 00:00:00 2001 From: borisneubert Date: Tue, 25 Jan 2011 19:24:48 +0000 Subject: [PATCH] - 66_ECMD.pm: serial port protocols added - 67_EMCDDevice.pm: readings added git-svn-id: https://svn.fhem.de/fhem/trunk@808 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/66_ECMD.pm | 128 +++++++++++++++++++++++++++++-------- fhem/FHEM/67_ECMDDevice.pm | 31 ++++++++- 2 files changed, 129 insertions(+), 30 deletions(-) diff --git a/fhem/FHEM/66_ECMD.pm b/fhem/FHEM/66_ECMD.pm index 0bcb0dee6..31a67ee20 100644 --- a/fhem/FHEM/66_ECMD.pm +++ b/fhem/FHEM/66_ECMD.pm @@ -56,24 +56,18 @@ ECMD_Define($$) my $name = $a[0]; my $protocol = $a[2]; - my $ipaddress= $a[3]; - if(@a < 4 || @a > 4 || $protocol ne "telnet") { - my $msg = "wrong syntax: define ECMD telnet "; + if(@a < 4 || @a > 4 || (($protocol ne "telnet") && ($protocol ne "serial"))) { + my $msg = "wrong syntax: define ECMD telnet or define ECMD serial "; Log 2, $msg; return $msg; } ECMD_CloseDev($hash); - if($ipaddress eq "none") { - Log 1, "$name ip address is none, commands will be echoed only"; - $attr{$name}{dummy} = 1; - return undef; - } - $hash->{Protocol}= $protocol; - $hash->{IPAddress}= $ipaddress; + my $devicename= $a[3]; + $hash->{DeviceName} = $devicename; my $ret = ECMD_OpenDev($hash, 0); return $ret; @@ -108,18 +102,25 @@ ECMD_CloseDev($) { my ($hash) = @_; my $name = $hash->{NAME}; - my $ipaddress = $hash->{IPAddress}; + my $dev = $hash->{DeviceName}; - return if(!$ipaddress); + return if(!$dev); if($hash->{TCPDev}) { $hash->{TCPDev}->close(); delete($hash->{TCPDev}); - } - delete($selectlist{"$name.$ipaddress"}); - delete($readyfnlist{"$name.$ipaddress"}); + } elsif($hash->{USBDev}) { + $hash->{USBDev}->close() ; + delete($hash->{USBDev}); + + } + ($dev, undef) = split("@", $dev); # Remove the baudrate + delete($selectlist{"$name.$dev"}); + delete($readyfnlist{"$name.$dev"}); delete($hash->{FD}); + + } ######################## @@ -128,14 +129,17 @@ ECMD_OpenDev($$) { my ($hash, $reopen) = @_; my $protocol = $hash->{Protocol}; - my $ipaddress = $hash->{IPAddress}; my $name = $hash->{NAME}; + my $devicename = $hash->{DeviceName}; $hash->{PARTIAL} = ""; - Log 3, "ECMD opening $name (protocol $protocol, ipaddress $ipaddress)" + Log 3, "ECMD opening $name (protocol $protocol, device $devicename)" if(!$reopen); + if($hash->{Protocol} eq "telnet") { + + # This part is called every time the timeout (5sec) is expired _OR_ # somebody is communicating over another TCP connection. As the connect # for non-existent devices has a delay of 3 sec, we are sitting all the @@ -144,12 +148,13 @@ ECMD_OpenDev($$) return; } - my $conn = IO::Socket::INET->new(PeerAddr => $ipaddress); + my $conn = IO::Socket::INET->new(PeerAddr => $devicename); if($conn) { delete($hash->{NEXT_OPEN}) + } else { - Log(3, "Can't connect to $ipaddress: $!") if(!$reopen); - $readyfnlist{"$name.$ipaddress"} = $hash; + Log(3, "Can't connect to $devicename: $!") if(!$reopen); + $readyfnlist{"$name.$devicename"} = $hash; $hash->{STATE} = "disconnected"; $hash->{NEXT_OPEN} = time()+60; return ""; @@ -157,12 +162,74 @@ ECMD_OpenDev($$) $hash->{TCPDev} = $conn; $hash->{FD} = $conn->fileno(); - delete($readyfnlist{"$name.$ipaddress"}); - $selectlist{"$name.$ipaddress"} = $hash; + delete($readyfnlist{"$name.$devicename"}); + $selectlist{"$name.$devicename"} = $hash; + } else { + + my $baudrate; + ($devicename, $baudrate) = split("@", $devicename); + + my $po; + if ($^O=~/Win/) { + require Win32::SerialPort; + $po = new Win32::SerialPort ($devicename); + } else { + require Device::SerialPort; + $po = new Device::SerialPort ($devicename); + } + + if(!$po) { + return undef if($reopen); + Log(3, "Can't open $devicename: $!"); + $readyfnlist{"$name.$devicename"} = $hash; + $hash->{STATE} = "disconnected"; + return ""; + } + + $hash->{USBDev} = $po; + if( $^O =~ /Win/ ) { + $readyfnlist{"$name.$devicename"} = $hash; + } else { + $hash->{FD} = $po->FILENO; + delete($readyfnlist{"$name.$devicename"}); + $selectlist{"$name.$devicename"} = $hash; + } + + if($baudrate) { + $po->reset_error(); + Log 3, "CUL setting $name baudrate to $baudrate"; + $po->baudrate($baudrate); + $po->databits(8); + $po->parity('none'); + $po->stopbits(1); + $po->handshake('none'); + + # This part is for some Linux kernel versions whih has strange default + # settings. Device::SerialPort is nice: if the flag is not defined for your + # OS then it will be ignored. + $po->stty_icanon(0); + #$po->stty_parmrk(0); # The debian standard install does not have it + $po->stty_icrnl(0); + $po->stty_echoe(0); + $po->stty_echok(0); + $po->stty_echoctl(0); + + # Needed for some strange distros + $po->stty_echo(0); + $po->stty_icanon(0); + $po->stty_isig(0); + $po->stty_opost(0); + $po->stty_icrnl(0); + } + + $po->write_settings; + + + } if($reopen) { - Log 1, "ECMD $ipaddress reappeared ($name)"; + Log 1, "ECMD $name ($devicename) reappeared"; } else { Log 3, "ECMD device opened"; } @@ -173,7 +240,7 @@ ECMD_OpenDev($$) if($ret) { Log 1, "$ret"; ECMD_CloseDev($hash); - Log 1, "Cannot init $ipaddress, ignoring it"; + Log 1, "Cannot init $name ($devicename), ignoring it"; } DoTrigger($name, "CONNECTED") if($reopen); @@ -211,6 +278,7 @@ ECMD_SimpleWrite(@) return if(!$hash); $msg .= "\n" unless($nonl); + $hash->{USBDev}->write($msg) if($hash->{USBDev}); syswrite($hash->{TCPDev}, $msg) if($hash->{TCPDev}); select(undef, undef, undef, 0.001); @@ -222,9 +290,13 @@ ECMD_SimpleRead($) { my ($hash) = @_; + if($hash->{USBDev}) { + return $hash->{USBDev}->input(); + } + if($hash->{TCPDev}) { my $buf; - if(!defined(sysread($hash->{TCPDev}, $buf, 256))) { + if(!defined(sysread($hash->{TCPDev}, $buf, 1024))) { ECMD_Disconnected($hash); return undef; } @@ -307,14 +379,14 @@ sub ECMD_Disconnected($) { my $hash = shift; - my $ipaddress = $hash->{IPAddress}; + my $dev = $hash->{DeviceName}; my $name = $hash->{NAME}; return if(!defined($hash->{FD})); # Already deleted o - Log 1, "$ipaddress disconnected, waiting to reappear"; + Log 1, "$dev disconnected, waiting to reappear"; ECMD_CloseDev($hash); - $readyfnlist{"$name.$ipaddress"} = $hash; # Start polling + $readyfnlist{"$name.$dev"} = $hash; # Start polling $hash->{STATE} = "disconnected"; # Without the following sleep the open of the device causes a SIGSEGV, diff --git a/fhem/FHEM/67_ECMDDevice.pm b/fhem/FHEM/67_ECMDDevice.pm index f4eaf0ac0..eb8c4f910 100644 --- a/fhem/FHEM/67_ECMDDevice.pm +++ b/fhem/FHEM/67_ECMDDevice.pm @@ -71,6 +71,29 @@ ECMDDevice_DeviceParams2Specials($) return %specials; } +################################### +sub +ECMDDevice_Changed($$$) +{ + my ($hash, $cmd, $value)= @_; + + my $name= $hash->{NAME}; + my $r= $hash->{READINGS}; + my $tn = TimeNow(); + + $r->{$cmd}{TIME} = $tn; + $r->{$cmd}{VAL} = $value; + + $hash->{CHANGED}[0]= "$cmd: $value"; + + DoTrigger($name, undef) if($init_done); + + $hash->{STATE} = "$cmd: $value"; + Log GetLogLevel($name, 4), "ECMDDevice $name $cmd: $value"; + + return $hash->{STATE}; + +} ################################### sub @@ -111,7 +134,7 @@ ECMDDevice_Get($@) my $v= IOWrite($hash, $r); - return "$name $cmdname => $v" ; + return ECMDDevice_Changed($hash, $cmdname, $v); } @@ -151,7 +174,11 @@ ECMDDevice_Set($@) my $r = ECMDDevice_AnalyzeCommand($ecmd); - return IOWrite($hash, $r); + my $v= IOWrite($hash, $r); + $v= $params if($params); + + return ECMDDevice_Changed($hash, $cmdname, $v); + }