2
0
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:
erwin 2023-03-27 18:44:00 +00:00
parent 487c060d47
commit 717eb0cbf7

View File

@ -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 &lt;name&gt; KNXIO (H|M|T) &lt;(ip-address|hostname):port&gt; &lt;phy-adress&gt;</code> <br/>or<br/> <p><code>define &lt;name&gt; KNXIO (H|M|T) &lt;(ip-address|hostname):port&gt; &lt;phy-adress&gt;</code> <br/>or<br/>
<code>define &lt;name&gt; KNXIO S &lt;UNIX socket-path&gt; &lt;phy-adress&gt;</code></p> <code>define &lt;name&gt; KNXIO S &lt;UNIX socket-path&gt; &lt;phy-adress&gt;</code> <br/>or<br/>
<code>define &lt;name&gt; KNXIO X</code></p>
<ul> <ul>
<b>Connection Types (mode)</b> (first parameter): <b>Connection Types (mode)</b> (first parameter):
<ul> <ul>