mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-04-08 19:32:42 +00:00
Adapted to DevIo
git-svn-id: https://svn.fhem.de/fhem/trunk@1013 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
71ea4d044e
commit
ad9285cd3d
@ -15,11 +15,7 @@ sub CUL_ReadAnswer($$$$);
|
||||
sub CUL_Ready($);
|
||||
sub CUL_Write($$$);
|
||||
|
||||
sub CUL_OpenDev($$);
|
||||
sub CUL_CloseDev($);
|
||||
sub CUL_SimpleWrite(@);
|
||||
sub CUL_SimpleRead($);
|
||||
sub CUL_Disconnected($);
|
||||
|
||||
my %gets = ( # Name, Data to send to the CUL, Regexp for the answer
|
||||
"ccconf" => 1,
|
||||
@ -79,6 +75,8 @@ CUL_Initialize($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
require "$attr{global}{modpath}/FHEM/DevIo.pm";
|
||||
|
||||
# Provider
|
||||
$hash->{ReadFn} = "CUL_Read";
|
||||
$hash->{WriteFn} = "CUL_Write";
|
||||
@ -96,6 +94,7 @@ CUL_Initialize($)
|
||||
"fhtsoftbuffer:1,0 sendpool addvaltrigger " .
|
||||
"rfmode:SlowRF,HomeMatic hmId hmProtocolEvents";
|
||||
$hash->{ShutdownFn} = "CUL_Shutdown";
|
||||
|
||||
}
|
||||
|
||||
#####################################
|
||||
@ -112,7 +111,7 @@ CUL_Define($$)
|
||||
return $msg;
|
||||
}
|
||||
|
||||
CUL_CloseDev($hash);
|
||||
DevIo_CloseDev($hash);
|
||||
|
||||
my $name = $a[0];
|
||||
my $dev = $a[2];
|
||||
@ -145,7 +144,7 @@ CUL_Define($$)
|
||||
}
|
||||
|
||||
$hash->{DeviceName} = $dev;
|
||||
my $ret = CUL_OpenDev($hash, 0);
|
||||
my $ret = DevIo_OpenDev($hash, 0, "CUL_DoInit");
|
||||
return $ret;
|
||||
}
|
||||
|
||||
@ -169,7 +168,7 @@ CUL_Undef($$)
|
||||
}
|
||||
|
||||
CUL_SimpleWrite($hash, "X00"); # Switch reception off, it may hang up the CUL
|
||||
CUL_CloseDev($hash);
|
||||
DevIo_CloseDev($hash);
|
||||
return undef;
|
||||
}
|
||||
|
||||
@ -450,7 +449,7 @@ READEND:
|
||||
CUL_SimpleWrite($hash, $gets{$a[1]}[0] . $arg);
|
||||
($err, $msg) = CUL_ReadAnswer($hash, $a[1], 0, $gets{$a[1]}[1]);
|
||||
if(!defined($msg)) {
|
||||
CUL_Disconnected($hash);
|
||||
DevIo_Disconnected($hash);
|
||||
$msg = "No answer";
|
||||
|
||||
} elsif($a[1] eq "uptime") { # decode it
|
||||
@ -540,7 +539,7 @@ CUL_DoInit($)
|
||||
CUL_SimpleWrite($hash, "T01" . $hash->{FHTID});
|
||||
}
|
||||
|
||||
$hash->{STATE} = "Initialized" if(!$hash->{STATE});
|
||||
$hash->{STATE} = "Initialized";
|
||||
|
||||
# Reset the counter
|
||||
delete($hash->{XMIT_TIME});
|
||||
@ -586,12 +585,12 @@ CUL_ReadAnswer($$$$)
|
||||
if($nfound < 0) {
|
||||
next if ($! == EAGAIN() || $! == EINTR() || $! == 0);
|
||||
my $err = $!;
|
||||
CUL_Disconnected($hash);
|
||||
DevIo_Disconnected($hash);
|
||||
return("CUL_ReadAnswer $arg: $err", undef);
|
||||
}
|
||||
return ("Timeout reading answer for get $arg", undef)
|
||||
if($nfound == 0);
|
||||
$buf = CUL_SimpleRead($hash);
|
||||
$buf = DevIo_SimpleRead($hash);
|
||||
return ("No data", undef) if(!defined($buf));
|
||||
|
||||
}
|
||||
@ -784,20 +783,10 @@ CUL_Read($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
my $buf = CUL_SimpleRead($hash);
|
||||
my $buf = DevIo_SimpleRead($hash);
|
||||
return "" if(!defined($buf));
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
###########
|
||||
# Lets' try again: Some drivers return len(0) on the first read...
|
||||
if(defined($buf) && length($buf) == 0) {
|
||||
$buf = CUL_SimpleRead($hash);
|
||||
}
|
||||
|
||||
if(!defined($buf) || length($buf) == 0) {
|
||||
CUL_Disconnected($hash);
|
||||
return "";
|
||||
}
|
||||
|
||||
my $culdata = $hash->{PARTIAL};
|
||||
Log 5, "CUL/RAW: $culdata/$buf";
|
||||
$culdata .= $buf;
|
||||
@ -842,8 +831,7 @@ CUL_Parse($$$$$)
|
||||
my $len = length($dmsg);
|
||||
|
||||
if($fn eq "F" && $len >= 9) { # Reformat for 10_FS20.pm
|
||||
|
||||
CUL_AddFS20Queue($iohash, ""); # Block immediate replies
|
||||
CUL_AddFS20Queue($iohash, ""); # Delay immediate replies
|
||||
$dmsg = sprintf("81%02x04xx0101a001%s00%s",
|
||||
$len/2+7, substr($dmsg,1,6), substr($dmsg,7));
|
||||
$dmsg = lc($dmsg);
|
||||
@ -922,7 +910,7 @@ CUL_Ready($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
return CUL_OpenDev($hash, 1)
|
||||
return DevIo_OpenDev($hash, 1, "CUL_DoInit")
|
||||
if($hash->{STATE} eq "disconnected");
|
||||
|
||||
# This is relevant for windows/USB only
|
||||
@ -956,221 +944,6 @@ CUL_SimpleWrite(@)
|
||||
select(undef, undef, undef, 0.001);
|
||||
}
|
||||
|
||||
########################
|
||||
sub
|
||||
CUL_SimpleRead($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
my ($buf, $res);
|
||||
|
||||
if($hash->{USBDev}) {
|
||||
$buf = $hash->{USBDev}->input();
|
||||
|
||||
} elsif($hash->{DIODev}) {
|
||||
$res = sysread($hash->{DIODev}, $buf, 256);
|
||||
$buf = undef if(!defined($res));
|
||||
|
||||
} elsif($hash->{TCPDev}) {
|
||||
$res = sysread($hash->{TCPDev}, $buf, 256);
|
||||
$buf = undef if(!defined($res));
|
||||
|
||||
}
|
||||
return $buf;
|
||||
}
|
||||
|
||||
########################
|
||||
sub
|
||||
CUL_CloseDev($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $dev = $hash->{DeviceName};
|
||||
|
||||
return if(!$dev);
|
||||
|
||||
if($hash->{TCPDev}) {
|
||||
$hash->{TCPDev}->close();
|
||||
delete($hash->{TCPDev});
|
||||
|
||||
} elsif($hash->{USBDev}) {
|
||||
$hash->{USBDev}->close() ;
|
||||
delete($hash->{USBDev});
|
||||
|
||||
} elsif($hash->{DIODev}) {
|
||||
close($hash->{DIODev});
|
||||
delete($hash->{DIODev});
|
||||
|
||||
}
|
||||
($dev, undef) = split("@", $dev); # Remove the baudrate
|
||||
delete($selectlist{"$name.$dev"});
|
||||
delete($readyfnlist{"$name.$dev"});
|
||||
delete($hash->{FD});
|
||||
}
|
||||
|
||||
########################
|
||||
sub
|
||||
CUL_OpenDev($$)
|
||||
{
|
||||
my ($hash, $reopen) = @_;
|
||||
my $dev = $hash->{DeviceName};
|
||||
my $name = $hash->{NAME};
|
||||
my $po;
|
||||
my $baudrate;
|
||||
($dev, $baudrate) = split("@", $dev);
|
||||
|
||||
|
||||
$hash->{PARTIAL} = "";
|
||||
Log 3, "CUL opening $name device $dev"
|
||||
if(!$reopen);
|
||||
|
||||
if($dev =~ m/^(.+):([0-9]+)$/) { # host:port
|
||||
|
||||
# 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
|
||||
# time in this connect. NEXT_OPEN tries to avoid this problem.
|
||||
if($hash->{NEXT_OPEN} && time() < $hash->{NEXT_OPEN}) {
|
||||
return;
|
||||
}
|
||||
|
||||
my $conn = IO::Socket::INET->new(PeerAddr => $dev);
|
||||
if($conn) {
|
||||
delete($hash->{NEXT_OPEN})
|
||||
|
||||
} else {
|
||||
Log(3, "Can't connect to $dev: $!") if(!$reopen);
|
||||
$readyfnlist{"$name.$dev"} = $hash;
|
||||
$hash->{STATE} = "disconnected";
|
||||
$hash->{NEXT_OPEN} = time()+60;
|
||||
return "";
|
||||
}
|
||||
|
||||
$hash->{TCPDev} = $conn;
|
||||
$hash->{FD} = $conn->fileno();
|
||||
delete($readyfnlist{"$name.$dev"});
|
||||
$selectlist{"$name.$dev"} = $hash;
|
||||
|
||||
} elsif($baudrate && lc($baudrate) eq "directio") { # Without Device::SerialPort
|
||||
|
||||
if(!open($po, "+<$dev")) {
|
||||
return undef if($reopen);
|
||||
Log(3, "Can't open $dev: $!");
|
||||
$readyfnlist{"$name.$dev"} = $hash;
|
||||
$hash->{STATE} = "disconnected";
|
||||
return "";
|
||||
}
|
||||
|
||||
$hash->{DIODev} = $po;
|
||||
|
||||
if( $^O =~ /Win/ ) {
|
||||
$readyfnlist{"$name.$dev"} = $hash;
|
||||
} else {
|
||||
$hash->{FD} = fileno($po);
|
||||
delete($readyfnlist{"$name.$dev"});
|
||||
$selectlist{"$name.$dev"} = $hash;
|
||||
}
|
||||
|
||||
|
||||
} else { # USB/Serial device
|
||||
|
||||
|
||||
if ($^O=~/Win/) {
|
||||
require Win32::SerialPort;
|
||||
$po = new Win32::SerialPort ($dev);
|
||||
} else {
|
||||
require Device::SerialPort;
|
||||
$po = new Device::SerialPort ($dev);
|
||||
}
|
||||
|
||||
if(!$po) {
|
||||
return undef if($reopen);
|
||||
Log(3, "Can't open $dev: $!");
|
||||
$readyfnlist{"$name.$dev"} = $hash;
|
||||
$hash->{STATE} = "disconnected";
|
||||
return "";
|
||||
}
|
||||
$hash->{USBDev} = $po;
|
||||
if( $^O =~ /Win/ ) {
|
||||
$readyfnlist{"$name.$dev"} = $hash;
|
||||
} else {
|
||||
$hash->{FD} = $po->FILENO;
|
||||
delete($readyfnlist{"$name.$dev"});
|
||||
$selectlist{"$name.$dev"} = $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, "CUL $dev reappeared ($name)";
|
||||
} else {
|
||||
Log 3, "CUL device opened";
|
||||
}
|
||||
|
||||
$hash->{STATE}=""; # Allow InitDev to set the state
|
||||
my $ret = CUL_DoInit($hash);
|
||||
|
||||
if($ret) {
|
||||
CUL_CloseDev($hash);
|
||||
Log 1, "Cannot init $dev, ignoring it";
|
||||
}
|
||||
|
||||
DoTrigger($name, "CONNECTED") if($reopen);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub
|
||||
CUL_Disconnected($)
|
||||
{
|
||||
my $hash = shift;
|
||||
my $dev = $hash->{DeviceName};
|
||||
my $name = $hash->{NAME};
|
||||
my $baudrate;
|
||||
($dev, $baudrate) = split("@", $dev);
|
||||
|
||||
return if(!defined($hash->{FD})); # Already deleted or RFR
|
||||
|
||||
Log 1, "$dev disconnected, waiting to reappear";
|
||||
CUL_CloseDev($hash);
|
||||
$readyfnlist{"$name.$dev"} = $hash; # Start polling
|
||||
$hash->{STATE} = "disconnected";
|
||||
|
||||
# Without the following sleep the open of the device causes a SIGSEGV,
|
||||
# and following opens block infinitely. Only a reboot helps.
|
||||
sleep(5);
|
||||
|
||||
DoTrigger($name, "DISCONNECTED");
|
||||
}
|
||||
|
||||
sub
|
||||
CUL_Attr(@)
|
||||
{
|
||||
|
@ -11,11 +11,7 @@ sub HMLAN_Write($$$);
|
||||
sub HMLAN_ReadAnswer($$$);
|
||||
sub HMLAN_uptime($);
|
||||
|
||||
sub HMLAN_OpenDev($$);
|
||||
sub HMLAN_CloseDev($);
|
||||
sub HMLAN_SimpleWrite(@);
|
||||
sub HMLAN_SimpleRead($);
|
||||
sub HMLAN_Disconnected($);
|
||||
|
||||
my %sets = (
|
||||
"hmPairForSec" => "HomeMatic",
|
||||
@ -27,6 +23,8 @@ HMLAN_Initialize($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
require "$attr{global}{modpath}/FHEM/DevIo.pm";
|
||||
|
||||
# Provider
|
||||
$hash->{ReadFn} = "HMLAN_Read";
|
||||
$hash->{WriteFn} = "HMLAN_Write";
|
||||
@ -58,11 +56,11 @@ HMLAN_Define($$)
|
||||
Log 2, $msg;
|
||||
return $msg;
|
||||
}
|
||||
HMLAN_CloseDev($hash);
|
||||
DevIo_CloseDev($hash);
|
||||
|
||||
my $name = $a[0];
|
||||
my $dev = $a[2];
|
||||
$dev .= ":1000" if($dev !~ m/:/);
|
||||
$dev .= ":1000" if($dev !~ m/:/ && $dev ne "none" && $dev !~ m/\@/);
|
||||
$attr{$name}{hmId} = sprintf("%06X", time() % 0xffffff); # Will be overwritten
|
||||
|
||||
if($dev eq "none") {
|
||||
@ -71,7 +69,7 @@ HMLAN_Define($$)
|
||||
return undef;
|
||||
}
|
||||
$hash->{DeviceName} = $dev;
|
||||
my $ret = HMLAN_OpenDev($hash, 0);
|
||||
my $ret = DevIo_OpenDev($hash, 0, "HMLAN_DoInit");
|
||||
return $ret;
|
||||
}
|
||||
|
||||
@ -94,7 +92,7 @@ HMLAN_Undef($$)
|
||||
}
|
||||
}
|
||||
|
||||
HMLAN_CloseDev($hash);
|
||||
DevIo_CloseDev($hash);
|
||||
return undef;
|
||||
}
|
||||
|
||||
@ -168,12 +166,12 @@ HMLAN_ReadAnswer($$$)
|
||||
if($nfound < 0) {
|
||||
next if ($! == EAGAIN() || $! == EINTR() || $! == 0);
|
||||
my $err = $!;
|
||||
HMLAN_Disconnected($hash);
|
||||
DevIo_Disconnected($hash);
|
||||
return("HMLAN_ReadAnswer $arg: $err", undef);
|
||||
}
|
||||
return ("Timeout reading answer for get $arg", undef)
|
||||
if($nfound == 0);
|
||||
$buf = HMLAN_SimpleRead($hash);
|
||||
$buf = DevIo_SimpleRead($hash);
|
||||
return ("No data", undef) if(!defined($buf));
|
||||
|
||||
if($buf) {
|
||||
@ -223,14 +221,10 @@ HMLAN_Read($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
my $buf = HMLAN_SimpleRead($hash);
|
||||
my $buf = DevIo_SimpleRead($hash);
|
||||
return "" if(!defined($buf));
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
if(!defined($buf) || length($buf) == 0) {
|
||||
HMLAN_Disconnected($hash);
|
||||
return "";
|
||||
}
|
||||
|
||||
my $hmdata = $hash->{PARTIAL};
|
||||
Log 5, "HMLAN/RAW: $hmdata/$buf";
|
||||
$hmdata .= $buf;
|
||||
@ -325,7 +319,7 @@ HMLAN_Ready($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
return HMLAN_OpenDev($hash, 1);
|
||||
return DevIo_OpenDev($hash, 1, "HMLAN_DoInit");
|
||||
}
|
||||
|
||||
########################
|
||||
@ -345,88 +339,10 @@ HMLAN_SimpleWrite(@)
|
||||
|
||||
########################
|
||||
sub
|
||||
HMLAN_SimpleRead($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
if($hash->{TCPDev}) {
|
||||
my $buf;
|
||||
if(!defined(sysread($hash->{TCPDev}, $buf, 256))) {
|
||||
HMLAN_Disconnected($hash);
|
||||
return undef;
|
||||
}
|
||||
return $buf;
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
########################
|
||||
sub
|
||||
HMLAN_CloseDev($)
|
||||
HMLAN_DoInit($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $dev = $hash->{DeviceName};
|
||||
|
||||
return if(!$dev);
|
||||
|
||||
if($hash->{TCPDev}) {
|
||||
$hash->{TCPDev}->close();
|
||||
delete($hash->{TCPDev});
|
||||
|
||||
}
|
||||
delete($selectlist{"$name.$dev"});
|
||||
delete($readyfnlist{"$name.$dev"});
|
||||
delete($hash->{FD});
|
||||
}
|
||||
|
||||
########################
|
||||
sub
|
||||
HMLAN_OpenDev($$)
|
||||
{
|
||||
my ($hash, $reopen) = @_;
|
||||
my $dev = $hash->{DeviceName};
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
$hash->{PARTIAL} = "";
|
||||
Log 3, "HMLAN opening $name device $dev"
|
||||
if(!$reopen);
|
||||
|
||||
if($dev =~ m/^.+:\d+$/) { # host:port
|
||||
|
||||
# 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
|
||||
# time in this connect. NEXT_OPEN tries to avoid this problem.
|
||||
if($hash->{NEXT_OPEN} && time() < $hash->{NEXT_OPEN}) {
|
||||
return;
|
||||
}
|
||||
|
||||
my $conn = IO::Socket::INET->new(PeerAddr => $dev);
|
||||
if($conn) {
|
||||
delete($hash->{NEXT_OPEN})
|
||||
|
||||
} else {
|
||||
Log(3, "Can't connect to $dev: $!") if(!$reopen);
|
||||
$readyfnlist{"$name.$dev"} = $hash;
|
||||
$hash->{STATE} = "disconnected";
|
||||
$hash->{NEXT_OPEN} = time()+60;
|
||||
return "";
|
||||
}
|
||||
|
||||
$hash->{TCPDev} = $conn;
|
||||
$hash->{FD} = $conn->fileno();
|
||||
delete($readyfnlist{"$name.$dev"});
|
||||
$selectlist{"$name.$dev"} = $hash;
|
||||
|
||||
InternalTimer(gettimeofday()+25, "HMLAN_KeepAlive", $hash, 0);
|
||||
}
|
||||
|
||||
if($reopen) {
|
||||
Log 1, "HMLAN $dev reappeared ($name)";
|
||||
} else {
|
||||
Log 3, "HMLAN device opened";
|
||||
}
|
||||
|
||||
my $id = AttrVal($name, "hmId", undef);
|
||||
my $key = AttrVal($name, "hmKey", ""); # 36(!) hex digits
|
||||
@ -440,10 +356,8 @@ HMLAN_OpenDev($$)
|
||||
HMLAN_SimpleWrite($hash, "Y03,00,");
|
||||
HMLAN_SimpleWrite($hash, "T$s2000,04,00,00000000");
|
||||
|
||||
$hash->{STATE}="Initialized";
|
||||
|
||||
DoTrigger($name, "CONNECTED") if($reopen);
|
||||
return "";
|
||||
InternalTimer(gettimeofday()+25, "HMLAN_KeepAlive", $hash, 0);
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
@ -456,27 +370,4 @@ HMLAN_KeepAlive($)
|
||||
InternalTimer(gettimeofday()+25, "HMLAN_KeepAlive", $hash, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub
|
||||
HMLAN_Disconnected($)
|
||||
{
|
||||
my $hash = shift;
|
||||
my $dev = $hash->{DeviceName};
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
return if(!defined($hash->{FD})); # Already deleted or RFR
|
||||
|
||||
Log 1, "$dev disconnected, waiting to reappear";
|
||||
RemoveInternalTimer($hash);
|
||||
HMLAN_CloseDev($hash);
|
||||
$readyfnlist{"$name.$dev"} = $hash; # Start polling
|
||||
$hash->{STATE} = "disconnected";
|
||||
|
||||
# Without the following sleep the open of the device causes a SIGSEGV,
|
||||
# and following opens block infinitely. Only a reboot helps.
|
||||
sleep(5);
|
||||
DoTrigger($name, "DISCONNECTED");
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -13,10 +13,6 @@ use Time::HiRes qw(gettimeofday);
|
||||
|
||||
sub KM271_Read($);
|
||||
sub KM271_Ready($);
|
||||
sub KM271_OpenDev($);
|
||||
sub KM271_CloseDev($);
|
||||
sub KM271_SimpleWrite(@);
|
||||
sub KM271_SimpleRead($);
|
||||
sub KM271_crc($);
|
||||
sub KM271_setbits($$);
|
||||
sub KM271_GetReading($$);
|
||||
@ -180,6 +176,8 @@ KM271_Initialize($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
require "$attr{global}{modpath}/FHEM/DevIo.pm";
|
||||
|
||||
$hash->{ReadFn} = "KM271_Read";
|
||||
$hash->{ReadyFn} = "KM271_Ready";
|
||||
|
||||
@ -208,7 +206,7 @@ KM271_Define($$)
|
||||
return "wrong syntax: define <name> KM271 [devicename|none]"
|
||||
if(@a != 3);
|
||||
|
||||
KM271_CloseDev($hash);
|
||||
DevIo_CloseDev($hash);
|
||||
my $name = $a[0];
|
||||
my $dev = $a[2];
|
||||
|
||||
@ -218,7 +216,7 @@ KM271_Define($$)
|
||||
}
|
||||
|
||||
$hash->{DeviceName} = $dev;
|
||||
my $ret = KM271_OpenDev($hash);
|
||||
my $ret = DevIo_OpenDev($hash, 0, "KM271_DoInit");
|
||||
return $ret;
|
||||
}
|
||||
|
||||
@ -228,7 +226,7 @@ sub
|
||||
KM271_Undef($$)
|
||||
{
|
||||
my ($hash, $arg) = @_;
|
||||
KM271_CloseDev($hash);
|
||||
DevIo_CloseDev($hash);
|
||||
return undef;
|
||||
}
|
||||
|
||||
@ -269,7 +267,7 @@ KM271_Set($@)
|
||||
my $data = ($val ? sprintf($fmt, $val) : $fmt);
|
||||
|
||||
push @{$hash->{SENDBUFFER}}, $data;
|
||||
KM271_SimpleWrite($hash, "02") if(!$hash->{WAITING});
|
||||
DevIo_SimpleWrite($hash, "02") if(!$hash->{WAITING});
|
||||
|
||||
return undef;
|
||||
}
|
||||
@ -284,45 +282,40 @@ KM271_Read($)
|
||||
my $name = $hash->{NAME};
|
||||
my ($data, $crc);
|
||||
|
||||
my $buf = KM271_SimpleRead($hash);
|
||||
Log 5, "KM271RAW: " . unpack('H*', $buf);
|
||||
|
||||
if(!defined($buf)) {
|
||||
Log 1, "$name: EOF";
|
||||
KM271_CloseDev($hash);
|
||||
return;
|
||||
}
|
||||
my $buf = DevIo_SimpleRead($hash);
|
||||
return "" if(!defined($buf));
|
||||
|
||||
$buf = unpack('H*', $buf);
|
||||
Log 5, "KM271RAW: $buf";
|
||||
|
||||
if(@{$hash->{SENDBUFFER}} || $hash->{DATASENT}) { # Send data
|
||||
|
||||
if($buf eq "02") { # KM271 Wants to send, override
|
||||
KM271_SimpleWrite($hash, "02");
|
||||
DevIo_SimpleWrite($hash, "02");
|
||||
return;
|
||||
}
|
||||
|
||||
if($buf eq "10") {
|
||||
if($hash->{DATASENT}) {
|
||||
delete($hash->{DATASENT});
|
||||
KM271_SimpleWrite($hash, "02") if(@{$hash->{SENDBUFFER}});
|
||||
DevIo_SimpleWrite($hash, "02") if(@{$hash->{SENDBUFFER}});
|
||||
return;
|
||||
}
|
||||
$data = pop @{ $hash->{SENDBUFFER} };
|
||||
$data =~ s/10/1010/g;
|
||||
$crc = KM271_crc($data);
|
||||
KM271_SimpleWrite($hash, $data."1003$crc"); # Send the data
|
||||
DevIo_SimpleWrite($hash, $data."1003$crc"); # Send the data
|
||||
}
|
||||
|
||||
if($buf eq "15") { # NACK from the KM271
|
||||
Log 1, "$name: NACK!";
|
||||
delete($hash->{DATASENT});
|
||||
KM271_SimpleWrite($hash, "02") if(@{$hash->{SENDBUFFER}});
|
||||
DevIo_SimpleWrite($hash, "02") if(@{$hash->{SENDBUFFER}});
|
||||
return;
|
||||
}
|
||||
|
||||
} elsif($buf eq "02") { # KM271 Wants to send
|
||||
KM271_SimpleWrite($hash, "10"); # We are ready
|
||||
DevIo_SimpleWrite($hash, "10"); # We are ready
|
||||
$hash->{PARTIAL} = "";
|
||||
$hash->{WAITING} = 1;
|
||||
return;
|
||||
@ -339,12 +332,12 @@ KM271_Read($)
|
||||
|
||||
if(KM271_crc($data) ne $crc) {
|
||||
Log 1, "Wrong CRC in $hash->{PARTIAL}: $crc vs. ". KM271_crc($data);
|
||||
KM271_SimpleWrite($hash, "15"); # NAK
|
||||
KM271_SimpleWrite($hash, "02") if(@{$hash->{SENDBUFFER}}); # want to send
|
||||
DevIo_SimpleWrite($hash, "15"); # NAK
|
||||
DevIo_SimpleWrite($hash, "02") if(@{$hash->{SENDBUFFER}}); # want to send
|
||||
return;
|
||||
}
|
||||
|
||||
KM271_SimpleWrite($hash, "10"); # ACK, Data received ok
|
||||
DevIo_SimpleWrite($hash, "10"); # ACK, Data received ok
|
||||
|
||||
|
||||
$data =~ s/1010/10/g;
|
||||
@ -406,97 +399,21 @@ KM271_Ready($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
return DevIo_OpenDev($hash, 1, undef)
|
||||
if($hash->{STATE} eq "disconnected");
|
||||
|
||||
# This is relevant for windows/USB only
|
||||
my $po = $hash->{Dev};
|
||||
my $po = $hash->{USBDev};
|
||||
my ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags) = $po->status;
|
||||
return ($InBytes>0);
|
||||
}
|
||||
|
||||
########################
|
||||
sub
|
||||
KM271_SimpleWrite(@)
|
||||
{
|
||||
my ($hash, $msg) = @_;
|
||||
Log 3, "KM271 SimpleWrite $msg" if(length($msg) != 2);
|
||||
$hash->{Dev}->write(pack('H*',$msg)) if($hash->{DeviceName});
|
||||
}
|
||||
|
||||
########################
|
||||
sub
|
||||
KM271_SimpleRead($)
|
||||
KM271_DoInit($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
return $hash->{Dev}->input() if($hash->{Dev});
|
||||
return undef;
|
||||
}
|
||||
|
||||
########################
|
||||
sub
|
||||
KM271_CloseDev($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $dev = $hash->{DeviceName};
|
||||
|
||||
return if(!$dev); # "none"
|
||||
|
||||
if($hash->{Dev}) {
|
||||
$hash->{Dev}->close() ;
|
||||
delete($hash->{Dev});
|
||||
|
||||
}
|
||||
delete($selectlist{"$name.$dev"});
|
||||
delete($readyfnlist{"$name.$dev"});
|
||||
delete($hash->{FD});
|
||||
delete($hash->{DeviceName});
|
||||
}
|
||||
|
||||
########################
|
||||
sub
|
||||
KM271_OpenDev($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
my $dev = $hash->{DeviceName};
|
||||
my $name = $hash->{NAME};
|
||||
my $po;
|
||||
|
||||
$hash->{PARTIAL} = "";
|
||||
Log 3, "KM271 opening $name device $dev";
|
||||
|
||||
if ($^O=~/Win/) {
|
||||
require Win32::SerialPort;
|
||||
$po = new Win32::SerialPort ($dev);
|
||||
} else {
|
||||
require Device::SerialPort;
|
||||
$po = new Device::SerialPort ($dev);
|
||||
}
|
||||
|
||||
if(!$po) {
|
||||
Log(3, "Can't open $dev: $!");
|
||||
return "";
|
||||
}
|
||||
$hash->{Dev} = $po;
|
||||
if( $^O =~ /Win/ ) {
|
||||
$readyfnlist{"$name.$dev"} = $hash;
|
||||
} else {
|
||||
$hash->{FD} = $po->FILENO;
|
||||
delete($readyfnlist{"$name.$dev"});
|
||||
$selectlist{"$name.$dev"} = $hash;
|
||||
}
|
||||
|
||||
$po->reset_error();
|
||||
$po->baudrate(2400);
|
||||
$po->databits(8);
|
||||
$po->parity('none');
|
||||
$po->stopbits(1);
|
||||
$po->handshake('none');
|
||||
|
||||
$hash->{STATE} = "Initialized";
|
||||
|
||||
push @{$hash->{SENDBUFFER}}, "EE0000";
|
||||
KM271_SimpleWrite($hash, "02"); # STX
|
||||
|
||||
Log 3, "$dev opened";
|
||||
DevIo_SimpleWrite($hash, "02"); # STX
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
@ -26,11 +26,6 @@ sub TCM_ReadAnswer($$);
|
||||
sub TCM_Ready($);
|
||||
sub TCM_Write($$$);
|
||||
|
||||
sub TCM_OpenDev($$);
|
||||
sub TCM_CloseDev($);
|
||||
sub TCM_SimpleWrite($$);
|
||||
sub TCM_SimpleRead($);
|
||||
sub TCM_Disconnected($);
|
||||
sub TCM_Parse120($$$);
|
||||
sub TCM_CRC8($);
|
||||
sub TCM_CSUM($);
|
||||
@ -40,6 +35,8 @@ TCM_Initialize($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
require "$attr{global}{modpath}/FHEM/DevIo.pm";
|
||||
|
||||
# Provider
|
||||
$hash->{ReadFn} = "TCM_Read";
|
||||
$hash->{WriteFn} = "TCM_Write";
|
||||
@ -70,7 +67,7 @@ TCM_Define($$)
|
||||
"{devicename[\@baudrate]|ip:port}"
|
||||
if(@a != 4 || $model !~ m/^(120|310)$/);
|
||||
|
||||
TCM_CloseDev($hash);
|
||||
DevIo_CloseDev($hash);
|
||||
my $dev = $a[3];
|
||||
|
||||
if($dev eq "none") {
|
||||
@ -81,7 +78,7 @@ TCM_Define($$)
|
||||
|
||||
$hash->{DeviceName} = $dev;
|
||||
$hash->{MODEL} = $model;
|
||||
my $ret = TCM_OpenDev($hash, 0);
|
||||
my $ret = DevIo_OpenDev($hash, 0, undef);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
@ -114,7 +111,7 @@ TCM_Write($$$)
|
||||
}
|
||||
Log $ll5, "$hash->{NAME} sending $bstring";
|
||||
|
||||
TCM_SimpleWrite($hash, $bstring);
|
||||
DevIo_SimpleWrite($hash, $bstring);
|
||||
}
|
||||
|
||||
#####################################
|
||||
@ -180,22 +177,13 @@ TCM_Read($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
my $buf = TCM_SimpleRead($hash);
|
||||
my $buf = DevIo_SimpleRead($hash);
|
||||
return "" if(!defined($buf));
|
||||
|
||||
my $name = $hash->{NAME};
|
||||
my $ll5 = GetLogLevel($name,5);
|
||||
my $ll2 = GetLogLevel($name,2);
|
||||
|
||||
###########
|
||||
# Lets' try again: Some drivers return len(0) on the first read...
|
||||
if(defined($buf) && length($buf) == 0) {
|
||||
$buf = TCM_SimpleRead($hash);
|
||||
}
|
||||
|
||||
if(!defined($buf) || length($buf) == 0) {
|
||||
TCM_Disconnected($hash);
|
||||
return "";
|
||||
}
|
||||
|
||||
my $data = $hash->{PARTIAL} . uc(unpack('H*', $buf));
|
||||
Log $ll5, "$name/RAW: $data";
|
||||
|
||||
@ -401,7 +389,7 @@ TCM_Ready($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
return TCM_OpenDev($hash, 1)
|
||||
return DevIo_OpenDev($hash, 1, undef)
|
||||
if($hash->{STATE} eq "disconnected");
|
||||
|
||||
# This is relevant for windows/USB only
|
||||
@ -410,193 +398,6 @@ TCM_Ready($)
|
||||
return ($InBytes>0);
|
||||
}
|
||||
|
||||
########################
|
||||
# Input is HEX, with header and CRC
|
||||
sub
|
||||
TCM_SimpleWrite($$)
|
||||
{
|
||||
my ($hash, $msg) = @_;
|
||||
return if(!$hash);
|
||||
#Log 1, "SW: $msg";
|
||||
$msg = pack('H*', $msg);
|
||||
$hash->{USBDev}->write($msg) if($hash->{USBDev});
|
||||
syswrite($hash->{TCPDev}, $msg) if($hash->{TCPDev});
|
||||
select(undef, undef, undef, 0.001);
|
||||
}
|
||||
|
||||
########################
|
||||
sub
|
||||
TCM_SimpleRead($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
my $buf;
|
||||
|
||||
$buf = $hash->{USBDev}->input() if($hash->{USBDev});
|
||||
$buf = sysread($hash->{TCPDev}, $buf, 256) if($hash->{TCPDev});
|
||||
return $buf;
|
||||
}
|
||||
|
||||
########################
|
||||
sub
|
||||
TCM_CloseDev($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $dev = $hash->{DeviceName};
|
||||
|
||||
return if(!$dev);
|
||||
|
||||
if($hash->{TCPDev}) {
|
||||
$hash->{TCPDev}->close();
|
||||
delete($hash->{TCPDev});
|
||||
|
||||
} 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});
|
||||
}
|
||||
|
||||
########################
|
||||
sub
|
||||
TCM_OpenDev($$)
|
||||
{
|
||||
my ($hash, $reopen) = @_;
|
||||
my $dev = $hash->{DeviceName};
|
||||
my $name = $hash->{NAME};
|
||||
my $po;
|
||||
my $baudrate;
|
||||
($dev, $baudrate) = split("@", $dev);
|
||||
if(!$baudrate) {
|
||||
$baudrate = 9600 if($hash->{MODEL} == 120);
|
||||
$baudrate = 57600 if($hash->{MODEL} == 310);
|
||||
}
|
||||
|
||||
|
||||
$hash->{PARTIAL} = "";
|
||||
Log 3, "TCM opening $name device $dev"
|
||||
if(!$reopen);
|
||||
|
||||
if($dev =~ m/^(.+):([0-9]+)$/) { # host:port
|
||||
|
||||
# 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
|
||||
# time in this connect. NEXT_OPEN tries to avoid this problem.
|
||||
if($hash->{NEXT_OPEN} && time() < $hash->{NEXT_OPEN}) {
|
||||
return;
|
||||
}
|
||||
|
||||
my $conn = IO::Socket::INET->new(PeerAddr => $dev);
|
||||
if($conn) {
|
||||
delete($hash->{NEXT_OPEN})
|
||||
|
||||
} else {
|
||||
Log(3, "Can't connect to $dev: $!") if(!$reopen);
|
||||
$readyfnlist{"$name.$dev"} = $hash;
|
||||
$hash->{STATE} = "disconnected";
|
||||
$hash->{NEXT_OPEN} = time()+60;
|
||||
return "";
|
||||
}
|
||||
|
||||
$hash->{TCPDev} = $conn;
|
||||
$hash->{FD} = $conn->fileno();
|
||||
delete($readyfnlist{"$name.$dev"});
|
||||
$selectlist{"$name.$dev"} = $hash;
|
||||
|
||||
} else { # USB/Serial device
|
||||
|
||||
if ($^O=~/Win/) {
|
||||
require Win32::SerialPort;
|
||||
$po = new Win32::SerialPort ($dev);
|
||||
} else {
|
||||
require Device::SerialPort;
|
||||
$po = new Device::SerialPort ($dev);
|
||||
}
|
||||
|
||||
if(!$po) {
|
||||
return undef if($reopen);
|
||||
Log(3, "Can't open $dev: $!");
|
||||
$readyfnlist{"$name.$dev"} = $hash;
|
||||
$hash->{STATE} = "disconnected";
|
||||
return "";
|
||||
}
|
||||
$hash->{USBDev} = $po;
|
||||
if( $^O =~ /Win/ ) {
|
||||
$readyfnlist{"$name.$dev"} = $hash;
|
||||
} else {
|
||||
$hash->{FD} = $po->FILENO;
|
||||
delete($readyfnlist{"$name.$dev"});
|
||||
$selectlist{"$name.$dev"} = $hash;
|
||||
}
|
||||
|
||||
$po->reset_error();
|
||||
$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, "TCM $dev reappeared ($name)";
|
||||
} else {
|
||||
Log 3, "TCM device opened";
|
||||
}
|
||||
|
||||
$hash->{STATE}="connected";
|
||||
|
||||
DoTrigger($name, "CONNECTED") if($reopen);
|
||||
return "";
|
||||
}
|
||||
|
||||
sub
|
||||
TCM_Disconnected($)
|
||||
{
|
||||
my $hash = shift;
|
||||
my $dev = $hash->{DeviceName};
|
||||
my $name = $hash->{NAME};
|
||||
my $baudrate;
|
||||
($dev, $baudrate) = split("@", $dev);
|
||||
|
||||
return if(!defined($hash->{FD})); # Already deleted or RFR
|
||||
|
||||
Log 1, "$dev disconnected, waiting to reappear";
|
||||
TCM_CloseDev($hash);
|
||||
$readyfnlist{"$name.$dev"} = $hash; # Start polling
|
||||
$hash->{STATE} = "disconnected";
|
||||
|
||||
# Without the following sleep the open of the device causes a SIGSEGV,
|
||||
# and following opens block infinitely. Only a reboot helps.
|
||||
sleep(5);
|
||||
|
||||
DoTrigger($name, "DISCONNECTED");
|
||||
}
|
||||
|
||||
my %gets120 = (
|
||||
"sensitivity" => "AB48",
|
||||
"idbase" => "AB58",
|
||||
@ -711,7 +512,7 @@ TCM_Set($@)
|
||||
##############################
|
||||
if($hash->{MODEL} eq "120") {
|
||||
if($cmdHex eq "") { # wake is very special
|
||||
TCM_SimpleWrite($hash, "AA");
|
||||
DevIo_SimpleWrite($hash, "AA");
|
||||
return "";
|
||||
}
|
||||
|
||||
@ -767,12 +568,12 @@ TCM_ReadAnswer($$)
|
||||
if($nfound < 0) {
|
||||
next if ($! == EAGAIN() || $! == EINTR() || $! == 0);
|
||||
my $err = $!;
|
||||
TCM_Disconnected($hash);
|
||||
DevIo_Disconnected($hash);
|
||||
return("TCM_ReadAnswer $err", undef);
|
||||
}
|
||||
return ("Timeout reading answer for $arg", undef)
|
||||
if($nfound == 0);
|
||||
$buf = TCM_SimpleRead($hash);
|
||||
$buf = DevIo_SimpleRead($hash);
|
||||
return ("No data", undef) if(!defined($buf));
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user