mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-25 16:05:19 +00:00
00_KNXIO.pm: code improvements, (Forum #127792)
git-svn-id: https://svn.fhem.de/fhem/trunk@27366 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
487c060d47
commit
717eb0cbf7
@ -43,9 +43,11 @@
|
|||||||
# change internal PhyAddr to reabable format + range checking on define.
|
# change internal PhyAddr to reabable format + range checking on define.
|
||||||
# 19/12/2022 cleanup
|
# 19/12/2022 cleanup
|
||||||
# 23/01/2023 cleanup, simplify _openDev
|
# 23/01/2023 cleanup, simplify _openDev
|
||||||
# xx/02/2023 PBP changes
|
# 13/03/2023 PBP changes
|
||||||
# replace cascading if..elsif with given
|
# replace cascading if..elsif with given
|
||||||
# replace GP_Import: Devio,Tcpserver,HttpUtils with use stmts
|
# replace GP_Import: Devio,Tcpserver,HttpUtils with use stmts
|
||||||
|
# 28/03/2023 cleanup
|
||||||
|
# rework Logging, duplicate msg detection
|
||||||
|
|
||||||
|
|
||||||
package KNXIO; ## no critic 'package'
|
package KNXIO; ## no critic 'package'
|
||||||
@ -56,7 +58,8 @@ use IO::Socket;
|
|||||||
use English qw(-no_match_vars);
|
use English qw(-no_match_vars);
|
||||||
use Time::HiRes qw(gettimeofday);
|
use Time::HiRes qw(gettimeofday);
|
||||||
use DevIo qw(DevIo_OpenDev DevIo_SimpleWrite DevIo_SimpleRead DevIo_CloseDev DevIo_Disconnected DevIo_IsOpen);
|
use DevIo qw(DevIo_OpenDev DevIo_SimpleWrite DevIo_SimpleRead DevIo_CloseDev DevIo_Disconnected DevIo_IsOpen);
|
||||||
use TcpServerUtils qw(TcpServer_Open TcpServer_SetLoopbackMode TcpServer_MCastAdd TcpServer_MCastRemove TcpServer_MCastSend TcpServer_MCastRecv TcpServer_Close);
|
use TcpServerUtils qw(TcpServer_Open TcpServer_SetLoopbackMode TcpServer_MCastAdd TcpServer_MCastRemove
|
||||||
|
TcpServer_MCastSend TcpServer_MCastRecv TcpServer_Close);
|
||||||
use HttpUtils qw(HttpUtils_gethostbyname HttpUtils_gethostbyname ip2str);
|
use HttpUtils qw(HttpUtils_gethostbyname HttpUtils_gethostbyname ip2str);
|
||||||
use feature qw(switch);
|
use feature qw(switch);
|
||||||
no if $] >= 5.017011, warnings => 'experimental';
|
no if $] >= 5.017011, warnings => 'experimental';
|
||||||
@ -73,9 +76,6 @@ use GPUtils qw(GP_Import GP_Export); # Package Helper Fn
|
|||||||
|
|
||||||
### import FHEM functions / global vars
|
### import FHEM functions / global vars
|
||||||
### run before package compilation
|
### run before package compilation
|
||||||
#DevIo_OpenDev DevIo_SimpleWrite DevIo_SimpleRead DevIo_CloseDev DevIo_Disconnected DevIo_IsOpen
|
|
||||||
#TcpServer_Open TcpServer_SetLoopbackMode TcpServer_MCastAdd TcpServer_MCastRemove TcpServer_MCastSend TcpServer_MCastRecv TcpServer_Close
|
|
||||||
#HttpUtils_gethostbyname ip2str
|
|
||||||
BEGIN {
|
BEGIN {
|
||||||
# Import from main context
|
# Import from main context
|
||||||
GP_Import(
|
GP_Import(
|
||||||
@ -189,7 +189,10 @@ sub KNXIO_Define {
|
|||||||
my $phytemp = KNXIO_hex2addr($phyaddr);
|
my $phytemp = KNXIO_hex2addr($phyaddr);
|
||||||
$hash->{PhyAddr} = KNXIO_addr2hex($phytemp,2); #convert 2 times for correcting input!
|
$hash->{PhyAddr} = KNXIO_addr2hex($phytemp,2); #convert 2 times for correcting input!
|
||||||
|
|
||||||
KNXIO_closeDev($hash) if ($init_done || exists($hash->{OLDDEF})); # modify definition....
|
KNXIO_closeDev($hash) if ($init_done && exists($hash->{OLDDEF})); # modify definition....
|
||||||
|
|
||||||
|
$hash->{devioLoglevel} = 4; #032023
|
||||||
|
$hash->{devioNoSTATE} = 1;
|
||||||
|
|
||||||
$hash->{PARTIAL} = q{};
|
$hash->{PARTIAL} = q{};
|
||||||
# define helpers
|
# define helpers
|
||||||
@ -203,7 +206,7 @@ sub KNXIO_Define {
|
|||||||
delete $hash->{NEXT_OPEN};
|
delete $hash->{NEXT_OPEN};
|
||||||
RemoveInternalTimer($hash);
|
RemoveInternalTimer($hash);
|
||||||
|
|
||||||
Log3 ($name, 3, qq{KNXIO_define ($name): opening device mode=$mode});
|
KNXIO_Log ($name, 3, qq{opening mode=$mode});
|
||||||
|
|
||||||
return InternalTimer(gettimeofday() + 0.2,\&KNXIO_openDev,$hash) if (! $init_done);
|
return InternalTimer(gettimeofday() + 0.2,\&KNXIO_openDev,$hash) if (! $init_done);
|
||||||
return KNXIO_openDev($hash);
|
return KNXIO_openDev($hash);
|
||||||
@ -240,12 +243,12 @@ sub KNXIO_Read {
|
|||||||
$buf = ::DevIo_SimpleRead($hash);
|
$buf = ::DevIo_SimpleRead($hash);
|
||||||
}
|
}
|
||||||
if (!defined($buf) || length($buf) == 0) {
|
if (!defined($buf) || length($buf) == 0) {
|
||||||
Log3 ($name, 1, 'KNXIO_Read: no data - disconnect');
|
KNXIO_Log ($name, 1, q{no data - disconnect});
|
||||||
KNXIO_disconnect($hash);
|
KNXIO_disconnect($hash);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log3 ($name, 5, 'KNXIO_Read: buf= ' . unpack('H*',$buf));
|
KNXIO_Log ($name, 5, 'buf=' . unpack('H*',$buf));
|
||||||
|
|
||||||
### process in indiv. subs
|
### process in indiv. subs
|
||||||
my $readmodes = {
|
my $readmodes = {
|
||||||
@ -260,7 +263,7 @@ sub KNXIO_Read {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log3 ($name, 2, qq{KNXIO_Read failed - invalid mode $mode specified});
|
KNXIO_Log ($name, 2, qq{failed - invalid mode $mode specified});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,17 +312,17 @@ sub KNXIO_ReadM {
|
|||||||
# header format: 0x06 - header size / 0x10 - KNXNET-IPVersion / 0x0530 - Routing Indicator / 0xYYYY - Header size + size of cEMIFrame
|
# header format: 0x06 - header size / 0x10 - KNXNET-IPVersion / 0x0530 - Routing Indicator / 0xYYYY - Header size + size of cEMIFrame
|
||||||
my ($header, $header_routing, $total_length) = unpack('nnn',$buf);
|
my ($header, $header_routing, $total_length) = unpack('nnn',$buf);
|
||||||
|
|
||||||
Log3 ($name, 5, 'KNXIO_ReadM: header=' . sprintf('%04x',$header) . ' routing=' . sprintf('%04x',$header_routing) .
|
KNXIO_Log ($name, 5, 'header=' . sprintf('%04x',$header) . ' routing=' . sprintf('%04x',$header_routing) .
|
||||||
qq{ TotalLength= $total_length (dezimal)});
|
qq{ TotalLength= $total_length (dezimal)});
|
||||||
|
|
||||||
if ($header != 0x0610 ) {
|
if ($header != 0x0610 ) {
|
||||||
Log3 ($name, 1, 'KNXIO_ReadM: invalid header size or version');
|
KNXIO_Log ($name, 1, 'invalid header size or version');
|
||||||
$hash->{PARTIAL} = undef; # delete all we have so far
|
$hash->{PARTIAL} = undef; # delete all we have so far
|
||||||
# KNXIO_disconnect($hash); #?
|
# KNXIO_disconnect($hash); #?
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (length($buf) < $total_length) { # 6 Byte header + min 11 Byte data
|
if (length($buf) < $total_length) { # 6 Byte header + min 11 Byte data
|
||||||
Log3 ($name,4, 'KNXIO_ReadM: still waiting for complete packet (short packet length)');
|
KNXIO_Log ($name,4, 'still waiting for complete packet (short packet length)');
|
||||||
$hash->{PARTIAL} = $buf; # still not enough
|
$hash->{PARTIAL} = $buf; # still not enough
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -337,14 +340,14 @@ sub KNXIO_ReadM {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
elsif ($header_routing == 0x0531) { # routing Lost Message
|
elsif ($header_routing == 0x0531) { # routing Lost Message
|
||||||
Log3 ($name, 3, 'KNXIO_ReadM: a routing-lost packet was received !!! - Problems with bus or KNX-router ???');
|
KNXIO_Log ($name, 3, 'a routing-lost packet was received !!! - Problems with bus or KNX-router ???');
|
||||||
}
|
}
|
||||||
elsif ($header_routing == 0x0201) { # search request
|
elsif ($header_routing == 0x0201) { # search request
|
||||||
Log3 ($name, 4, 'KNXIO_ReadM: a search-request packet was received');
|
KNXIO_Log ($name, 4, 'a search-request packet was received');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log3 ($name, 4, q{KNXIO_ReadM: a packet with unsupported service type } .
|
KNXIO_Log ($name, 4, q{a packet with unsupported service type } .
|
||||||
sprintf('%04x',$header_routing) . q{ was received. - discarded});
|
sprintf('%04x',$header_routing) . q{ was received. - discarded});
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} # /multicast
|
} # /multicast
|
||||||
@ -361,7 +364,7 @@ sub KNXIO_ReadH {
|
|||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
if ( unpack('n',$buf) != 0x0610) {
|
if ( unpack('n',$buf) != 0x0610) {
|
||||||
Log3 ($name, 3, 'KNXIO_ReadH: invalid Frame Header received - discarded');
|
KNXIO_Log ($name, 3, 'invalid Frame Header received - discarded');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,26 +375,25 @@ sub KNXIO_ReadH {
|
|||||||
my $errcode = 0;
|
my $errcode = 0;
|
||||||
my $responseID = unpack('x2n',$buf);
|
my $responseID = unpack('x2n',$buf);
|
||||||
|
|
||||||
given ($responseID) { ##
|
given ($responseID) {
|
||||||
# handle most frequent id's first
|
# handle most frequent id's first
|
||||||
## if ( $responseID == 0x0420) { # Tunnel request
|
|
||||||
when (0x0420) { # Tunnel request
|
when (0x0420) { # Tunnel request
|
||||||
($ccid,$rxseqcntr) = unpack('x7CC',$buf);
|
($ccid,$rxseqcntr) = unpack('x7CC',$buf);
|
||||||
|
|
||||||
my $discardFrame = undef;
|
my $discardFrame = undef;
|
||||||
if ($rxseqcntr == ($hash->{KNXIOhelper}->{SEQUENCECNTR} - 1)) {
|
if ($rxseqcntr == ($hash->{KNXIOhelper}->{SEQUENCECNTR} - 1)) {
|
||||||
Log3 ($name, 3, q{KNXIO_ReadH: TunnelRequest received: duplicate message received } .
|
KNXIO_Log ($name, 3, q{TunnelRequest received: duplicate message received } .
|
||||||
qq{(seqcntr= $rxseqcntr ) - ack it});
|
qq{(seqcntr= $rxseqcntr ) - ack it});
|
||||||
$hash->{KNXIOhelper}->{SEQUENCECNTR}--; # one packet duplicate... we ack it but do not process
|
$hash->{KNXIOhelper}->{SEQUENCECNTR}--; # one packet duplicate... we ack it but do not process
|
||||||
$discardFrame = 1;
|
$discardFrame = 1;
|
||||||
}
|
}
|
||||||
if ($rxseqcntr != $hash->{KNXIOhelper}->{SEQUENCECNTR}) { # really out of sequence
|
if ($rxseqcntr != $hash->{KNXIOhelper}->{SEQUENCECNTR}) { # really out of sequence
|
||||||
Log3 ($name, 3, q{KNXIO_ReadH: TunnelRequest received: out of sequence, } .
|
KNXIO_Log ($name, 3, q{TunnelRequest received: out of sequence, } .
|
||||||
qq{(seqcntrRx= $rxseqcntr seqcntrTx= $hash->{KNXIOhelper}->{SEQUENCECNTR} ) - no ack & discard});
|
qq{(seqcntrRx= $rxseqcntr seqcntrTx= $hash->{KNXIOhelper}->{SEQUENCECNTR} ) - no ack & discard});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log3 ($name, 4, q{KNXIO_ReadH: TunnelRequest received - send Ack and decode. } .
|
KNXIO_Log ($name, 4, q{TunnelRequest received - send Ack and decode. } .
|
||||||
qq{seqcntrRx= $hash->{KNXIOhelper}->{SEQUENCECNTR}} ) if (! defined($discardFrame));
|
qq{seqcntrRx= $hash->{KNXIOhelper}->{SEQUENCECNTR}} ) if (! defined($discardFrame));
|
||||||
my $tacksend = pack('nnnCCCC',0x0610,0x0421,10,4,$ccid,$hash->{KNXIOhelper}->{SEQUENCECNTR},0); # send ack
|
my $tacksend = pack('nnnCCCC',0x0610,0x0421,10,4,$ccid,$hash->{KNXIOhelper}->{SEQUENCECNTR},0); # send ack
|
||||||
$hash->{KNXIOhelper}->{SEQUENCECNTR}++;
|
$hash->{KNXIOhelper}->{SEQUENCECNTR}++;
|
||||||
$hash->{KNXIOhelper}->{SEQUENCECNTR} = 0 if ($hash->{KNXIOhelper}->{SEQUENCECNTR} > 255);
|
$hash->{KNXIOhelper}->{SEQUENCECNTR} = 0 if ($hash->{KNXIOhelper}->{SEQUENCECNTR} > 255);
|
||||||
@ -404,38 +406,31 @@ sub KNXIO_ReadH {
|
|||||||
return if (! defined($cemiRes));
|
return if (! defined($cemiRes));
|
||||||
return KNXIO_dispatch($hash,$cemiRes);
|
return KNXIO_dispatch($hash,$cemiRes);
|
||||||
}
|
}
|
||||||
## elsif ( $responseID == 0x0421) { # Tunneling Ack
|
|
||||||
when (0x0421) { # Tunneling Ack
|
when (0x0421) { # Tunneling Ack
|
||||||
($ccid,$txseqcntr,$errcode) = unpack('x7CCC',$buf);
|
($ccid,$txseqcntr,$errcode) = unpack('x7CCC',$buf);
|
||||||
if ($errcode > 0) {
|
if ($errcode > 0) {
|
||||||
Log3 ($name, 3, qq{KNXIO_ReadH: Tunneling Ack received CCID= $ccid txseq= $txseqcntr Status= } . KNXIO_errCodes($errcode));
|
KNXIO_Log ($name, 3, qq{Tunneling Ack received CCID= $ccid txseq= $txseqcntr Status= } . KNXIO_errCodes($errcode));
|
||||||
#what next ?
|
#what next ?
|
||||||
}
|
}
|
||||||
$hash->{KNXIOhelper}->{SEQUENCECNTR_W}++;
|
$hash->{KNXIOhelper}->{SEQUENCECNTR_W}++;
|
||||||
$hash->{KNXIOhelper}->{SEQUENCECNTR_W} = 0 if ($hash->{KNXIOhelper}->{SEQUENCECNTR_W} > 255);
|
$hash->{KNXIOhelper}->{SEQUENCECNTR_W} = 0 if ($hash->{KNXIOhelper}->{SEQUENCECNTR_W} > 255);
|
||||||
return RemoveInternalTimer($hash,\&KNXIO_TunnelRequestTO); # all ok, stop timer
|
return RemoveInternalTimer($hash,\&KNXIO_TunnelRequestTO); # all ok, stop timer
|
||||||
# RemoveInternalTimer($hash,\&KNXIO_TunnelRequestTO); # all ok, stop timer
|
|
||||||
}
|
}
|
||||||
## if ( $responseID == 0x0202) { # Search response
|
|
||||||
when (0x0202) { # Search response
|
when (0x0202) { # Search response
|
||||||
# elsif ( $responseID == 0x0202) { # Search response
|
KNXIO_Log ($name, 4, 'SearchResponse received');
|
||||||
Log3 ($name, 4, 'KNXIO_ReadH: SearchResponse received');
|
|
||||||
my (@contolpointIp, $controlpointPort) = unpack('x6CCCn',$buf);
|
my (@contolpointIp, $controlpointPort) = unpack('x6CCCn',$buf);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
## elsif ( $responseID == 0x0204) { # Decription response
|
|
||||||
when (0x0204) { # Decription response
|
when (0x0204) { # Decription response
|
||||||
Log3 ($name, 4, 'KNXIO_ReadH: DescriptionResponse received');
|
KNXIO_Log ($name, 4, 'DescriptionResponse received');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
## if ( $responseID == 0x0206) { # Connection response
|
|
||||||
when (0x0206) { # Connection response
|
when (0x0206) { # Connection response
|
||||||
# elsif ( $responseID == 0x0206) { # Connection response
|
|
||||||
($hash->{KNXIOhelper}->{CCID},$errcode) = unpack('x6CC',$buf); # save Comm Channel ID,errcode
|
($hash->{KNXIOhelper}->{CCID},$errcode) = unpack('x6CC',$buf); # save Comm Channel ID,errcode
|
||||||
RemoveInternalTimer($hash,\&KNXIO_keepAlive);
|
RemoveInternalTimer($hash,\&KNXIO_keepAlive);
|
||||||
if ($errcode > 0) {
|
if ($errcode > 0) {
|
||||||
Log3 ($name, 3, q{KNXIO_ReadH: ConnectionResponse received } .
|
KNXIO_Log ($name, 3, q{ConnectionResponse received } .
|
||||||
qq{CCID= $hash->{KNXIOhelper}->{CCID} Status=} . KNXIO_errCodes($errcode));
|
qq{CCID= $hash->{KNXIOhelper}->{CCID} Status=} . KNXIO_errCodes($errcode));
|
||||||
KNXIO_disconnect($hash);
|
KNXIO_disconnect($hash);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -443,40 +438,35 @@ sub KNXIO_ReadH {
|
|||||||
$hash->{PhyAddr} = KNXIO_addr2hex($phyaddr,2); # correct Phyaddr.
|
$hash->{PhyAddr} = KNXIO_addr2hex($phyaddr,2); # correct Phyaddr.
|
||||||
# DoTrigger($name, 'CONNECTED');
|
# DoTrigger($name, 'CONNECTED');
|
||||||
readingsSingleUpdate($hash, 'state', 'connected', 1);
|
readingsSingleUpdate($hash, 'state', 'connected', 1);
|
||||||
Log3 ($name, 3, qq{KNXIO $name connected});
|
KNXIO_Log ($name, 3, qq{$name connected});
|
||||||
$hash->{KNXIOhelper}->{SEQUENCECNTR} = 0;
|
$hash->{KNXIOhelper}->{SEQUENCECNTR} = 0;
|
||||||
return InternalTimer(gettimeofday() + 60, \&KNXIO_keepAlive, $hash); # start keepalive
|
return InternalTimer(gettimeofday() + 60, \&KNXIO_keepAlive, $hash); # start keepalive
|
||||||
}
|
}
|
||||||
## elsif ( $responseID == 0x0208) { # ConnectionState response
|
|
||||||
when (0x0208) { # ConnectionState response
|
when (0x0208) { # ConnectionState response
|
||||||
($hash->{KNXIOhelper}->{CCID}, $errcode) = unpack('x6CC',$buf);
|
($hash->{KNXIOhelper}->{CCID}, $errcode) = unpack('x6CC',$buf);
|
||||||
RemoveInternalTimer($hash,\&KNXIO_keepAlive);
|
RemoveInternalTimer($hash,\&KNXIO_keepAlive);
|
||||||
RemoveInternalTimer($hash,\&KNXIO_keepAliveTO); # reset timeout timer
|
RemoveInternalTimer($hash,\&KNXIO_keepAliveTO); # reset timeout timer
|
||||||
if ($errcode > 0) {
|
if ($errcode > 0) {
|
||||||
Log3 ($name, 3, q{KNXIO_ReadH: ConnectionStateResponse received } .
|
KNXIO_Log ($name, 3, q{ConnectionStateResponse received } .
|
||||||
qq{CCID= $hash->{KNXIOhelper}->{CCID} Status= } . KNXIO_errCodes($errcode));
|
qq{CCID= $hash->{KNXIOhelper}->{CCID} Status= } . KNXIO_errCodes($errcode));
|
||||||
KNXIO_disconnect($hash);
|
KNXIO_disconnect($hash);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return InternalTimer(gettimeofday() + 60, \&KNXIO_keepAlive, $hash);
|
return InternalTimer(gettimeofday() + 60, \&KNXIO_keepAlive, $hash);
|
||||||
}
|
}
|
||||||
## if ( $responseID == 0x0209) { # Disconnect request
|
|
||||||
when (0x0209) { # Disconnect request
|
when (0x0209) { # Disconnect request
|
||||||
# elsif ( $responseID == 0x0209) { # Disconnect request
|
KNXIO_Log ($name, 4, ' DisconnectRequest received, restarting connection');
|
||||||
Log3 ($name, 4, 'KNXIO_ReadH: DisconnectRequest received, restarting connenction');
|
|
||||||
$ccid = unpack('x6C',$buf);
|
$ccid = unpack('x6C',$buf);
|
||||||
$msg = pack('nnnCC',(0x0610,0x020A,8,$ccid,0));
|
$msg = pack('nnnCC',(0x0610,0x020A,8,$ccid,0));
|
||||||
::DevIo_SimpleWrite($hash,$msg,0); # send disco response
|
::DevIo_SimpleWrite($hash,$msg,0); # send disco response
|
||||||
$msg = KNXIO_prepareConnRequ($hash);
|
$msg = KNXIO_prepareConnRequ($hash);
|
||||||
}
|
}
|
||||||
## elsif ( $responseID == 0x020A) { # Disconnect response
|
|
||||||
when (0x020A) { # Disconnect response
|
when (0x020A) { # Disconnect response
|
||||||
Log3 ($name, 4, 'KNXIO_ReadH: DisconnectResponse received - sending connrequ');
|
KNXIO_Log ($name, 4, 'DisconnectResponse received - sending connrequ');
|
||||||
$msg = KNXIO_prepareConnRequ($hash);
|
$msg = KNXIO_prepareConnRequ($hash);
|
||||||
}
|
}
|
||||||
## else {
|
|
||||||
default {
|
default {
|
||||||
Log3 ($name, 3, 'KNXIO_ReadH: invalid response received: ' . unpack('H*',$buf));
|
KNXIO_Log ($name, 3, 'invalid response received: ' . unpack('H*',$buf));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -504,14 +494,14 @@ sub KNXIO_Write {
|
|||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
my $mode = $hash->{model};
|
my $mode = $hash->{model};
|
||||||
|
|
||||||
Log3 ($name, 5, 'KNXIO_write: started');
|
KNXIO_Log ($name, 5, 'started');
|
||||||
return if(!defined($fn) && $fn ne $TULID);
|
return if(!defined($fn) && $fn ne $TULID);
|
||||||
if (ReadingsVal($name, 'state', 'disconnected') ne 'connected') {
|
if (ReadingsVal($name, 'state', 'disconnected') ne 'connected') {
|
||||||
Log3 ($name, 3, qq{KNXIO_write called while not connected! Msg: $msg lost});
|
KNXIO_Log ($name, 3, qq{called while not connected! Msg: $msg lost});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log3 ($name, 5, qq{KNXIO_write: sending $msg});
|
KNXIO_Log ($name, 5, qq{sending $msg});
|
||||||
|
|
||||||
my $acpivalues = {r => 0x00, p => 0x01, w => 0x02};
|
my $acpivalues = {r => 0x00, p => 0x01, w => 0x02};
|
||||||
|
|
||||||
@ -534,9 +524,9 @@ sub KNXIO_Write {
|
|||||||
$data[0] = $acpi;
|
$data[0] = $acpi;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log3 ($name, 5, q{KNXIO_Write: data=} . sprintf('%02x' x scalar(@data), @data) .
|
KNXIO_Log ($name, 5, q{data=} . sprintf('%02x' x scalar(@data), @data) .
|
||||||
sprintf(' size=%02x acpi=%02x', $datasize, $acpi) .
|
sprintf(' size=%02x acpi=%02x', $datasize, $acpi) .
|
||||||
q{ src=} . KNXIO_addr2hex($src,2) . q{ dst=} . KNXIO_addr2hex($dst,3));
|
q{ src=} . KNXIO_addr2hex($src,2) . q{ dst=} . KNXIO_addr2hex($dst,3));
|
||||||
my $completemsg = q{};
|
my $completemsg = q{};
|
||||||
my $ret = 0;
|
my $ret = 0;
|
||||||
|
|
||||||
@ -558,10 +548,10 @@ sub KNXIO_Write {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$ret = ::DevIo_SimpleWrite($hash,$completemsg,0) if ($mode ne 'M');
|
$ret = ::DevIo_SimpleWrite($hash,$completemsg,0) if ($mode ne 'M');
|
||||||
Log3 ($name, 4, qq{KNXIO_Write: Mode= $mode buf=} . unpack('H*',$completemsg) . qq{ rc= $ret});
|
KNXIO_Log ($name, 4, qq{Mode= $mode buf=} . unpack('H*',$completemsg) . qq{ rc= $ret});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log3 ($name, 2, qq{KNXIO_write: Could not send message $msg});
|
KNXIO_Log ($name, 2, qq{Could not send message $msg});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,10 +564,10 @@ sub KNXIO_Rename {
|
|||||||
my $oldname = shift;
|
my $oldname = shift;
|
||||||
|
|
||||||
if (! IsDevice($newname,'KNXIO')) {
|
if (! IsDevice($newname,'KNXIO')) {
|
||||||
Log3 (undef, 1, qq{KNXIO_Rename: $newname is not a KNXIO device!});
|
KNXIO_Log ($oldname, 1, qq{$newname is not a KNXIO device!});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log3 (undef, 3, qq{KNXIO_Rename: device $oldname renamed to $newname});
|
KNXIO_Log ($oldname, 3, qq{device $oldname renamed to $newname});
|
||||||
|
|
||||||
#check if any reading IODev has still the old KNXIO name...
|
#check if any reading IODev has still the old KNXIO name...
|
||||||
my @KNXdevs = devspec2array('TYPE=KNX:FILTER=r:IODev=' . $oldname);
|
my @KNXdevs = devspec2array('TYPE=KNX:FILTER=r:IODev=' . $oldname);
|
||||||
@ -589,7 +579,7 @@ sub KNXIO_Rename {
|
|||||||
delete ($attr{$KNXdev}->{IODev});
|
delete ($attr{$KNXdev}->{IODev});
|
||||||
$logtxt .= qq{, attr IODev -> deleted!};
|
$logtxt .= qq{, attr IODev -> deleted!};
|
||||||
}
|
}
|
||||||
Log3 (undef, 3, qq{KNXIO_Rename: device $KNXdev change: } . $logtxt);
|
KNXIO_Log ($KNXdev, 3, qq{device change: $logtxt});
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -619,7 +609,7 @@ sub KNXIO_callback {
|
|||||||
|
|
||||||
$hash->{nextOpenDelay} = $reconnectTO;
|
$hash->{nextOpenDelay} = $reconnectTO;
|
||||||
if (defined($err)) {
|
if (defined($err)) {
|
||||||
Log3 ($hash, 2, qq{KNXIO_callback: device open $hash->{NAME} failed with: $err}) if ($err);
|
KNXIO_Log ($hash, 2, qq{device open $hash->{NAME} failed with: $err}) if ($err);
|
||||||
$hash->{NEXT_OPEN} = gettimeofday() + $hash->{nextOpenDelay};
|
$hash->{NEXT_OPEN} = gettimeofday() + $hash->{nextOpenDelay};
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -642,11 +632,11 @@ sub KNXIO_gethostbyname_Cb {
|
|||||||
if ($error) {
|
if ($error) {
|
||||||
delete $hash->{DeviceName};
|
delete $hash->{DeviceName};
|
||||||
delete $hash->{PORT};
|
delete $hash->{PORT};
|
||||||
Log3 ($name, 1, qq{KNXIO_define ($name): hostname could not be resolved: $error});
|
KNXIO_Log ($name, 1, qq{hostname could not be resolved: $error});
|
||||||
return qq{KNXIO-define: hostname could not be resolved: $error};
|
return qq{KNXIO-define: hostname could not be resolved: $error};
|
||||||
}
|
}
|
||||||
my $host = ::ip2str($dhost);
|
my $host = ::ip2str($dhost);
|
||||||
Log3 ($name, 3, qq{KNXIO_define ($name): DNS query result= $host});
|
KNXIO_Log ($name, 3, qq{DNS query result= $host});
|
||||||
$hash->{DeviceName} = $host . q{:} . $hash->{PORT};
|
$hash->{DeviceName} = $host . q{:} . $hash->{PORT};
|
||||||
delete $hash->{PORT};
|
delete $hash->{PORT};
|
||||||
return;
|
return;
|
||||||
@ -679,11 +669,11 @@ sub KNXIO_openDev {
|
|||||||
if (exists $hash->{DNSWAIT}) {
|
if (exists $hash->{DNSWAIT}) {
|
||||||
$hash->{DNSWAIT} += 1;
|
$hash->{DNSWAIT} += 1;
|
||||||
if ($hash->{DNSWAIT} > 5) {
|
if ($hash->{DNSWAIT} > 5) {
|
||||||
Log3 ($name, 2, qq{KNXIO_openDev ($name): DNS failed, check ip/hostname});
|
KNXIO_Log ($name, 2, qq{DNS failed, check ip/hostname});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
InternalTimer(gettimeofday() + 1,\&KNXIO_openDev,$hash);
|
InternalTimer(gettimeofday() + 1,\&KNXIO_openDev,$hash);
|
||||||
Log3 ($name, 2, qq{KNXIO_openDev ($name): waiting for DNS});
|
KNXIO_Log ($name, 2, q{waiting for DNS});
|
||||||
return; # waiting for DNS
|
return; # waiting for DNS
|
||||||
}
|
}
|
||||||
return if (! exists($hash->{DeviceName})); # DNS failed !
|
return if (! exists($hash->{DeviceName})); # DNS failed !
|
||||||
@ -692,7 +682,7 @@ sub KNXIO_openDev {
|
|||||||
my $param = $hash->{DeviceName}; # ip:port or UNIX:STREAM:<socket param>
|
my $param = $hash->{DeviceName}; # ip:port or UNIX:STREAM:<socket param>
|
||||||
my ($host, $port) = split(/[:]/ixms,$param);
|
my ($host, $port) = split(/[:]/ixms,$param);
|
||||||
|
|
||||||
Log3 ($name, 5, qq{KNXIO_openDev ($name): $mode , $host , $port , reopen= $reopen});
|
KNXIO_Log ($name, 5, qq{$mode , $host , $port , reopen= $reopen});
|
||||||
|
|
||||||
my $ret = undef; # result
|
my $ret = undef; # result
|
||||||
|
|
||||||
@ -701,12 +691,12 @@ sub KNXIO_openDev {
|
|||||||
delete $hash->{TCPDev}; # devio ?
|
delete $hash->{TCPDev}; # devio ?
|
||||||
$ret = ::TcpServer_Open($hash, $port, $host, 1);
|
$ret = ::TcpServer_Open($hash, $port, $host, 1);
|
||||||
if (defined($ret)) { # error
|
if (defined($ret)) { # error
|
||||||
Log3 ($name, 2, qq{KNXIO_openDev ($name): can't connect: $ret}) if(!$reopen);
|
KNXIO_Log ($name, 2, qq{can't connect: $ret}) if(!$reopen);
|
||||||
return qq{KNXIO_openDev ($name): can't connect: $ret};
|
return qq{KNXIO_openDev ($name): can't connect: $ret};
|
||||||
}
|
}
|
||||||
$ret = ::TcpServer_MCastAdd($hash,$host);
|
$ret = ::TcpServer_MCastAdd($hash,$host);
|
||||||
if (defined($ret)) { # error
|
if (defined($ret)) { # error
|
||||||
Log3 ($name, 2, qq{KNXIO_openDev ($name): MC add failed: $ret}) if(!$reopen);
|
KNXIO_Log ($name, 2, qq{MC add failed: $ret}) if(!$reopen);
|
||||||
return qq{KNXIO_openDev ($name): MC add failed: $ret};
|
return qq{KNXIO_openDev ($name): MC add failed: $ret};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -721,7 +711,7 @@ sub KNXIO_openDev {
|
|||||||
elsif ($mode eq 'S') {
|
elsif ($mode eq 'S') {
|
||||||
$host = (split(/[:]/ixms,$param))[2]; # UNIX:STREAM:<socket path>
|
$host = (split(/[:]/ixms,$param))[2]; # UNIX:STREAM:<socket path>
|
||||||
if (!(-S -r -w $host) && $init_done) {
|
if (!(-S -r -w $host) && $init_done) {
|
||||||
Log3 ($name, 2, q{KNXIO_openDev ($name): Socket not available - (knxd running?)});
|
KNXIO_Log ($name, 2, q{Socket not available - (knxd running?)});
|
||||||
return qq{KNXIO_openDev ($name): Socket not available - (knxd running?)};
|
return qq{KNXIO_openDev ($name): Socket not available - (knxd running?)};
|
||||||
}
|
}
|
||||||
$ret = ::DevIo_OpenDev($hash,$reopen,\&KNXIO_init); # no callback
|
$ret = ::DevIo_OpenDev($hash,$reopen,\&KNXIO_init); # no callback
|
||||||
@ -732,7 +722,7 @@ sub KNXIO_openDev {
|
|||||||
my $conn = 0;
|
my $conn = 0;
|
||||||
$conn = IO::Socket::INET->new(PeerAddr => "$host:$port", Type => SOCK_DGRAM, Proto => 'udp', Reuse => 1);
|
$conn = IO::Socket::INET->new(PeerAddr => "$host:$port", Type => SOCK_DGRAM, Proto => 'udp', Reuse => 1);
|
||||||
if (!($conn)) {
|
if (!($conn)) {
|
||||||
Log3 ($name, 2, qq{KNXIO_openDev ($name): can't connect: $ERRNO}) if(!$reopen);
|
KNXIO_Log ($name, 2, qq{can't connect: $ERRNO}) if(!$reopen);
|
||||||
$readyfnlist{"$name.$param"} = $hash;
|
$readyfnlist{"$name.$param"} = $hash;
|
||||||
readingsSingleUpdate($hash, 'state', 'disconnected', 1);
|
readingsSingleUpdate($hash, 'state', 'disconnected', 1);
|
||||||
$hash->{NEXT_OPEN} = gettimeofday() + $reconnectTO;
|
$hash->{NEXT_OPEN} = gettimeofday() + $reconnectTO;
|
||||||
@ -747,7 +737,7 @@ sub KNXIO_openDev {
|
|||||||
$selectlist{"$name.$param"} = $hash;
|
$selectlist{"$name.$param"} = $hash;
|
||||||
|
|
||||||
my $retxt = ($reopen)?'reappeared':'opened';
|
my $retxt = ($reopen)?'reappeared':'opened';
|
||||||
Log3 ($name, 3, qq{KNXIO_openDev ($name): device $retxt});
|
KNXIO_Log ($name, 3, qq{device $retxt});
|
||||||
$ret = KNXIO_init($hash);
|
$ret = KNXIO_init($hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -757,7 +747,7 @@ sub KNXIO_openDev {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(defined($ret) && $ret) {
|
if(defined($ret) && $ret) {
|
||||||
Log3 ($name, 1, qq{KNXIO_openDev ($name): Cannot open KNXIO-Device - ignoring it});
|
KNXIO_Log ($name, 1, q{Cannot open KNXIO-Device - ignoring it});
|
||||||
KNXIO_closeDev($hash);
|
KNXIO_closeDev($hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -784,7 +774,7 @@ sub KNXIO_init {
|
|||||||
else {
|
else {
|
||||||
# DoTrigger($name, 'CONNECTED');
|
# DoTrigger($name, 'CONNECTED');
|
||||||
readingsSingleUpdate($hash, 'state', 'connected', 1);
|
readingsSingleUpdate($hash, 'state', 'connected', 1);
|
||||||
Log3 ($name, 3, qq{KNXIO $name connected});
|
KNXIO_Log ($name, 3, qq{connected});
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -854,30 +844,31 @@ sub KNXIO_processFIFO {
|
|||||||
RemoveInternalTimer($hash,'KNXIO::KNXIO_processFIFO');
|
RemoveInternalTimer($hash,'KNXIO::KNXIO_processFIFO');
|
||||||
|
|
||||||
if ($hash->{KNXIOhelper}->{FIFOTIMER} != 0) { # dispatch still running, do a wait loop
|
if ($hash->{KNXIOhelper}->{FIFOTIMER} != 0) { # dispatch still running, do a wait loop
|
||||||
Log3 ($name, 5, qq{KNXIO_processFIFO ($name): dispatch not complete, waiting});
|
KNXIO_Log ($name, 5, q{dispatch not complete, waiting});
|
||||||
InternalTimer(gettimeofday() + 0.1, 'KNXIO::KNXIO_processFIFO', $hash);
|
InternalTimer(gettimeofday() + 0.1, 'KNXIO::KNXIO_processFIFO', $hash);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
my @que = @{$hash->{KNXIOhelper}->{FIFO}};
|
my @que = @{$hash->{KNXIOhelper}->{FIFO}};
|
||||||
if (scalar(@que) > 1) { # delete any duplicates
|
my $queentries = scalar(@que);
|
||||||
my $queentriesOld = scalar(@que);
|
if ($queentries > 1) { # delete any duplicates
|
||||||
|
my $queentriesOld = $queentries;
|
||||||
@que = KNXIO_deldupes(@que);
|
@que = KNXIO_deldupes(@que);
|
||||||
Log3 ($name, 5, qq{KNXIO_processFIFO ($name): deleted } . ($queentriesOld - scalar(@que)) .
|
$queentries = scalar(@que);
|
||||||
q{ duplicate msg from queue, } . scalar(@que) . q{ remain});
|
KNXIO_Log ($name, 5, q{deleted } . ($queentriesOld - $queentries) .
|
||||||
|
qq{ duplicate msgs from queue, $queentries remain});
|
||||||
}
|
}
|
||||||
|
|
||||||
my $queentries = scalar(@que);
|
|
||||||
if ($queentries > 0) { # process timer is not running & fifo not empty
|
if ($queentries > 0) { # process timer is not running & fifo not empty
|
||||||
$hash->{KNXIOhelper}->{FIFOMSG} = shift (@que);
|
$hash->{KNXIOhelper}->{FIFOMSG} = shift (@que);
|
||||||
@{$hash->{KNXIOhelper}->{FIFO}} = @que;
|
@{$hash->{KNXIOhelper}->{FIFO}} = @que;
|
||||||
$hash->{KNXIOhelper}->{FIFOTIMER} = 1;
|
$hash->{KNXIOhelper}->{FIFOTIMER} = 1;
|
||||||
Log3 ($name, 4, qq{KNXIO_processFIFO ($name): buf= $hash->{KNXIOhelper}->{FIFOMSG} Nr_msgs= $queentries});
|
KNXIO_Log ($name, 4, qq{buf=$hash->{KNXIOhelper}->{FIFOMSG} Nr_msgs=$queentries});
|
||||||
# InternalTimer(gettimeofday() + 1.0, \&KNXIO_dispatch2, $hash); # testing delay
|
# InternalTimer(gettimeofday() + 1.0, \&KNXIO_dispatch2, $hash); # testing delay
|
||||||
InternalTimer(gettimeofday() + 0.05, 'KNXIO::KNXIO_dispatch2', $hash); # allow time for duplicate msgs to be read
|
InternalTimer(gettimeofday() + 0.05, 'KNXIO::KNXIO_dispatch2', $hash); # allow time for duplicate msgs to be read
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log3 ($name, 5, qq{KNXIO_processFIFO ($name): finished});
|
KNXIO_Log ($name, 5, q{finished});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -888,7 +879,8 @@ sub KNXIO_deldupes {
|
|||||||
my @arr = @_;
|
my @arr = @_;
|
||||||
|
|
||||||
my %seen;
|
my %seen;
|
||||||
return grep { !$seen{$_}++ } @arr;
|
# return grep { !$seen{$_}++ } @arr;
|
||||||
|
return grep { !$seen{substr($_,6) }++ } @arr; # ignore C<src-addr>
|
||||||
}
|
}
|
||||||
|
|
||||||
###
|
###
|
||||||
@ -899,7 +891,7 @@ sub KNXIO_disconnect {
|
|||||||
|
|
||||||
::DevIo_Disconnected($hash);
|
::DevIo_Disconnected($hash);
|
||||||
|
|
||||||
Log3 ($name, 1, qq{KNXIO_disconnect ($name): device disconnected, waiting to reappear});
|
KNXIO_Log ($name, 1, qq{disconnected, waiting to reappear});
|
||||||
|
|
||||||
$readyfnlist{"$name.$param"} = $hash; # Start polling
|
$readyfnlist{"$name.$param"} = $hash; # Start polling
|
||||||
$hash->{NEXT_OPEN} = gettimeofday() + $reconnectTO;
|
$hash->{NEXT_OPEN} = gettimeofday() + $reconnectTO;
|
||||||
@ -931,7 +923,7 @@ sub KNXIO_closeDev {
|
|||||||
|
|
||||||
RemoveInternalTimer($hash);
|
RemoveInternalTimer($hash);
|
||||||
|
|
||||||
Log3 ($name, 3, qq{KNXIO_closeDev ($name): device closed}) if ($init_done);;
|
KNXIO_Log ($name, 3, q{closed}) if ($init_done);;
|
||||||
|
|
||||||
readingsSingleUpdate($hash, 'state', 'disconnected', 1);
|
readingsSingleUpdate($hash, 'state', 'disconnected', 1);
|
||||||
DoTrigger($name, 'DISCONNECTED');
|
DoTrigger($name, 'DISCONNECTED');
|
||||||
@ -955,24 +947,24 @@ sub KNXIO_decodeEMI {
|
|||||||
|
|
||||||
my ($len, $id, $src, $dst, $acpi, @data) = unpack('nnnnCC*',$buf);
|
my ($len, $id, $src, $dst, $acpi, @data) = unpack('nnnnCC*',$buf);
|
||||||
if (($len + 2) != length($buf)) {
|
if (($len + 2) != length($buf)) {
|
||||||
Log3 ($name, 4, qq{KNXIO_decodeEMI: buffer length mismatch $len } . length($buf) - 2);
|
KNXIO_Log ($name, 4, qq{buffer length mismatch $len } . length($buf) - 2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($id != 0x0027) {
|
if ($id != 0x0027) {
|
||||||
if ($id == 0x0026) {
|
if ($id == 0x0026) {
|
||||||
Log3 ($name, 4, 'KNXIO_decodeEMI: OpenGrpCon response received');
|
KNXIO_Log ($name, 4, 'OpenGrpCon response received');
|
||||||
# DoTrigger($name, 'CONNECTED');
|
# DoTrigger($name, 'CONNECTED');
|
||||||
readingsSingleUpdate($hash, 'state', 'connected', 1);
|
readingsSingleUpdate($hash, 'state', 'connected', 1);
|
||||||
Log3 ($name, 3, qq{KNXIO $name connected});
|
KNXIO_Log ($name, 3, qq{connected});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log3 ($name, 3, 'KNXIO_decodeEMI: invalid message code ' . sprintf('%04x',$id));
|
KNXIO_Log ($name, 3, 'invalid message code ' . sprintf('%04x',$id));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log3 ($name, 4, q{KNXIO_decodeEMI: src=} . KNXIO_addr2hex($src,2) . q{ - dst=} . KNXIO_addr2hex($dst,3) . q{ - leng=} . scalar(@data) .
|
KNXIO_Log ($name, 4, q{src=} . KNXIO_addr2hex($src,2) . q{ - dst=} . KNXIO_addr2hex($dst,3) . q{ - leng=} .
|
||||||
q{ - data=} . sprintf('%02x' x scalar(@data),@data));
|
scalar(@data) . q{ - data=} . sprintf('%02x' x scalar(@data),@data));
|
||||||
|
|
||||||
$src = KNXIO_addr2hex($src,0); # always a phy-address
|
$src = KNXIO_addr2hex($src,0); # always a phy-address
|
||||||
$dst = KNXIO_addr2hex($dst,1); # always a Group addr
|
$dst = KNXIO_addr2hex($dst,1); # always a Group addr
|
||||||
@ -982,9 +974,9 @@ sub KNXIO_decodeEMI {
|
|||||||
my @acpicodes = qw(read preply write invalid);
|
my @acpicodes = qw(read preply write invalid);
|
||||||
my $rwp = $acpicodes[$acpi];
|
my $rwp = $acpicodes[$acpi];
|
||||||
if (! defined($rwp) || ($rwp eq 'invalid')) {
|
if (! defined($rwp) || ($rwp eq 'invalid')) {
|
||||||
Log3 ($name, 3, 'KNXIO_decodeEMI: no valid acpi-code (read/reply/write) received, discard packet');
|
KNXIO_Log ($name, 3, 'no valid acpi-code (read/reply/write) received, discard packet');
|
||||||
Log3 ($name, 4, qq{discarded packet: src=$src dst=$dst acpi=} . sprintf('%02x',$acpi) .
|
KNXIO_Log ($name, 4, qq{discarded packet: src=$src dst=$dst acpi=} . sprintf('%02x',$acpi) .
|
||||||
' leng=' . scalar(@data) . ' data=' . sprintf('%02x' x scalar(@data),@data));
|
q{ length=} . scalar(@data) . q{ data=} . sprintf('%02x' x scalar(@data),@data));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -992,7 +984,7 @@ sub KNXIO_decodeEMI {
|
|||||||
shift @data if (scalar(@data) > 1 ); # byte 0 is ununsed if length > 1
|
shift @data if (scalar(@data) > 1 ); # byte 0 is ununsed if length > 1
|
||||||
|
|
||||||
my $outbuf = $TULID . $src . substr($rwp,0,1) . $dst . sprintf('%02x' x scalar(@data),@data);
|
my $outbuf = $TULID . $src . substr($rwp,0,1) . $dst . sprintf('%02x' x scalar(@data),@data);
|
||||||
Log3 ($name, 5, qq{KNXIO_decodeEMI: $outbuf});
|
KNXIO_Log ($name, 5, qq{outbuf=$outbuf});
|
||||||
|
|
||||||
return $outbuf;
|
return $outbuf;
|
||||||
}
|
}
|
||||||
@ -1008,7 +1000,7 @@ sub KNXIO_decodeCEMI {
|
|||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
my ($mc, $addlen) = unpack('CC',$buf);
|
my ($mc, $addlen) = unpack('CC',$buf);
|
||||||
if ($mc != 0x29 && $mc != 0x2e) {
|
if ($mc != 0x29 && $mc != 0x2e) {
|
||||||
Log3 ($name, 4, 'KNXIO_decodeCEMI: wrong MessageCode ' . sprintf("%02x",$mc) . ', discard packet');
|
KNXIO_Log ($name, 4, 'wrong MessageCode ' . sprintf("%02x",$mc) . ', discard packet');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1016,7 +1008,7 @@ sub KNXIO_decodeCEMI {
|
|||||||
my ($ctrlbyte1, $ctrlbyte2, $src, $dst, $tcf, $acpi, @data) = unpack('x' . $addlen . 'CCnnCCC*',$buf);
|
my ($ctrlbyte1, $ctrlbyte2, $src, $dst, $tcf, $acpi, @data) = unpack('x' . $addlen . 'CCnnCCC*',$buf);
|
||||||
|
|
||||||
if (($ctrlbyte1 & 0xF0) != 0xB0) { # standard frame/no repeat/broadcast - see 03_06_03 EMI_IMI specs
|
if (($ctrlbyte1 & 0xF0) != 0xB0) { # standard frame/no repeat/broadcast - see 03_06_03 EMI_IMI specs
|
||||||
Log3 ($name, 4, 'KNXIO_decodeCEMI: wrong ctrlbyte1 ' . sprintf("%02x",$ctrlbyte1) . ', discard packet');
|
KNXIO_Log ($name, 4, 'wrong ctrlbyte1 ' . sprintf("%02x",$ctrlbyte1) . ', discard packet');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
my $prio = ($ctrlbyte1 & 0x0C) >>2; # priority
|
my $prio = ($ctrlbyte1 & 0x0C) >>2; # priority
|
||||||
@ -1024,23 +1016,23 @@ sub KNXIO_decodeCEMI {
|
|||||||
my $hop_count = ($ctrlbyte2 & 0x70) >> 4; # bits 6-4
|
my $hop_count = ($ctrlbyte2 & 0x70) >> 4; # bits 6-4
|
||||||
|
|
||||||
if ($tcf != scalar(@data)) { # $tcf: number of NPDU octets, TPCI octet not included!
|
if ($tcf != scalar(@data)) { # $tcf: number of NPDU octets, TPCI octet not included!
|
||||||
Log3 ($name, 4, 'KNXIO_decodeCEMI: Datalength not consistent');
|
KNXIO_Log ($name, 4, 'Datalength not consistent');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $srcd = KNXIO_addr2hex($src,2); # always a phy-address
|
my $srcd = KNXIO_addr2hex($src,2); # always a phy-address
|
||||||
my $dstd = KNXIO_addr2hex($dst,$dest_addrType + 2);
|
my $dstd = KNXIO_addr2hex($dst,$dest_addrType + 2);
|
||||||
|
|
||||||
Log3 ($name, 4, qq{KNXIO_decodeCEMI: src=$srcd dst=$dstd destaddrType=$dest_addrType prio=$prio hop_count=$hop_count leng=} .
|
KNXIO_Log ($name, 4, qq{src=$srcd dst=$dstd destaddrType=$dest_addrType prio=$prio hop_count=$hop_count } .
|
||||||
scalar(@data) . ' data=' . sprintf('%02x' x scalar(@data),@data));
|
q{length=} . scalar(@data) . q{ data=} . sprintf('%02x' x scalar(@data),@data));
|
||||||
|
|
||||||
$acpi = ((($acpi & 0x03) << 2) | (($data[0] & 0xC0) >> 6));
|
$acpi = ((($acpi & 0x03) << 2) | (($data[0] & 0xC0) >> 6));
|
||||||
my @acpicodes = qw(read preply write invalid);
|
my @acpicodes = qw(read preply write invalid);
|
||||||
my $rwp = $acpicodes[$acpi];
|
my $rwp = $acpicodes[$acpi];
|
||||||
if (! defined($rwp) || ($rwp eq 'invalid')) { # not a groupvalue-read/write/reply
|
if (! defined($rwp) || ($rwp eq 'invalid')) { # not a groupvalue-read/write/reply
|
||||||
Log3 ($name, 3, 'KNXIO_decodeCEMI: no valid acpi-code (read/reply/write) received - discard packet');
|
KNXIO_Log ($name, 3, 'no valid acpi-code (read/reply/write) received - discard packet');
|
||||||
Log3 ($name, 4, qq{discarded packet: src=$srcd dst=$dstd destaddrType=$dest_addrType prio=$prio hop_count=$hop_count} .
|
KNXIO_Log ($name, 4, qq{discarded packet: src=$srcd dst=$dstd destaddrType=$dest_addrType prio=$prio hop_count=$hop_count} .
|
||||||
' leng=' . scalar(@data) . ' data=' . sprintf('%02x' x scalar(@data),@data));
|
q{ length=} . scalar(@data) . q{ data=} . sprintf('%02x' x scalar(@data),@data));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1051,7 +1043,7 @@ sub KNXIO_decodeCEMI {
|
|||||||
shift @data if (scalar(@data) > 1 ); # byte 0 is ununsed if length > 1
|
shift @data if (scalar(@data) > 1 ); # byte 0 is ununsed if length > 1
|
||||||
|
|
||||||
my $outbuf = $TULID . $src . substr($rwp,0,1) . $dst . sprintf('%02x' x scalar(@data),@data);
|
my $outbuf = $TULID . $src . substr($rwp,0,1) . $dst . sprintf('%02x' x scalar(@data),@data);
|
||||||
Log3 ($name, 5, qq{KNXIO_decodeCEMI: buf=$outbuf});
|
KNXIO_Log ($name, 5, qq{outbuf=$outbuf});
|
||||||
|
|
||||||
return $outbuf;
|
return $outbuf;
|
||||||
}
|
}
|
||||||
@ -1088,7 +1080,7 @@ sub KNXIO_keepAlive {
|
|||||||
my $hash = shift;
|
my $hash = shift;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
Log3 ($name, 4, 'KNXIO_keepalive - expect ConnectionStateResponse');
|
KNXIO_Log ($name, 4, 'expect ConnectionStateResponse');
|
||||||
|
|
||||||
my $msg = pack('nnnCCnnnn',(0x0610,0x0207,16,$hash->{KNXIOhelper}->{CCID},0, 0x0801,0,0,0));
|
my $msg = pack('nnnCCnnnn',(0x0610,0x0207,16,$hash->{KNXIOhelper}->{CCID},0, 0x0801,0,0,0));
|
||||||
RemoveInternalTimer($hash,\&KNXIO_keepAlive);
|
RemoveInternalTimer($hash,\&KNXIO_keepAlive);
|
||||||
@ -1102,7 +1094,7 @@ sub KNXIO_keepAliveTO {
|
|||||||
my $hash = shift;
|
my $hash = shift;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
Log3 ($name, 3, 'KNXIO_keepAlive timeout - retry');
|
KNXIO_Log ($name, 3, 'timeout - retry');
|
||||||
|
|
||||||
return KNXIO_keepAlive($hash);
|
return KNXIO_keepAlive($hash);
|
||||||
}
|
}
|
||||||
@ -1115,7 +1107,7 @@ sub KNXIO_TunnelRequestTO {
|
|||||||
RemoveInternalTimer($hash,\&KNXIO_TunnelRequestTO);
|
RemoveInternalTimer($hash,\&KNXIO_TunnelRequestTO);
|
||||||
# try resend...but only once
|
# try resend...but only once
|
||||||
if (exists($hash->{KNXIOhelper}->{LASTSENTMSG})) {
|
if (exists($hash->{KNXIOhelper}->{LASTSENTMSG})) {
|
||||||
Log3 ($name, 3, 'KNXIO_TunnelRequestTO hit - attempt resend');
|
KNXIO_Log ($name, 3, 'timeout - attempt resend');
|
||||||
my $msg = $hash->{KNXIOhelper}->{LASTSENTMSG};
|
my $msg = $hash->{KNXIOhelper}->{LASTSENTMSG};
|
||||||
::DevIo_SimpleWrite($hash,$msg,0);
|
::DevIo_SimpleWrite($hash,$msg,0);
|
||||||
delete $hash->{KNXIOhelper}->{LASTSENTMSG};
|
delete $hash->{KNXIOhelper}->{LASTSENTMSG};
|
||||||
@ -1123,7 +1115,7 @@ sub KNXIO_TunnelRequestTO {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log3 ($name, 3, 'KNXIO_TunnelRequestTO hit - sending disconnect request');
|
KNXIO_Log ($name, 3, 'timeout - sending disconnect request');
|
||||||
|
|
||||||
# send disco request
|
# send disco request
|
||||||
my $hpai = pack('nCCCCn',(0x0801,0,0,0,0,0));
|
my $hpai = pack('nCCCCn',(0x0801,0,0,0,0,0));
|
||||||
@ -1132,6 +1124,24 @@ sub KNXIO_TunnelRequestTO {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
### unified Log handling
|
||||||
|
### calling param: same as Log3: hash/name/undef, loglevel, logtext
|
||||||
|
### prependes device, subroutine, linenr. to Log msg
|
||||||
|
### return undef
|
||||||
|
sub KNXIO_Log {
|
||||||
|
my $dev = shift || 'global';
|
||||||
|
my $loglvl = shift;
|
||||||
|
my $logtxt = shift;
|
||||||
|
|
||||||
|
my $sub = (caller(1))[3] || 'main';
|
||||||
|
my $line = (caller(0))[2];
|
||||||
|
my $name = ( ref($dev) eq "HASH" ) ? $dev->{NAME} : $dev;
|
||||||
|
$sub =~ s/.+[:]+//xms;
|
||||||
|
|
||||||
|
Log3 ($name, $loglvl, qq{$name [$sub $line]: $logtxt});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
### translate Error-codes to text
|
### translate Error-codes to text
|
||||||
### copied from 03_08_01 & 03_08_02_Core document
|
### copied from 03_08_01 & 03_08_02_Core document
|
||||||
### all i know...
|
### all i know...
|
||||||
@ -1185,7 +1195,8 @@ sub KNXIO_errCodes {
|
|||||||
<a id="KNXIO-define"></a>
|
<a id="KNXIO-define"></a>
|
||||||
<p><strong>Define</strong></p>
|
<p><strong>Define</strong></p>
|
||||||
<p><code>define <name> KNXIO (H|M|T) <(ip-address|hostname):port> <phy-adress></code> <br/>or<br/>
|
<p><code>define <name> KNXIO (H|M|T) <(ip-address|hostname):port> <phy-adress></code> <br/>or<br/>
|
||||||
<code>define <name> KNXIO S <UNIX socket-path> <phy-adress></code></p>
|
<code>define <name> KNXIO S <UNIX socket-path> <phy-adress></code> <br/>or<br/>
|
||||||
|
<code>define <name> KNXIO X</code></p>
|
||||||
<ul>
|
<ul>
|
||||||
<b>Connection Types (mode)</b> (first parameter):
|
<b>Connection Types (mode)</b> (first parameter):
|
||||||
<ul>
|
<ul>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user