diff --git a/fhem/CHANGED b/fhem/CHANGED index fb582feb6..560680f04 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,13 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - feature: 66_ECMD, 67_ECMDDevice: + - if split is used, the strings at which the messages are split + are still part of the messages + - no default attributes for requestSeparator and responseSeparator + - input of raw data as perl-encoded string (for setting + attributes) + - be more verbose and explicit at loglevel 5 + - documentation corrected and amended - feature: 57_Calendar: BYDAY: recognizes and honors one or several weekdays with and without prefix (e.g. -1SU, 2MO) with MONTHLY - bugfix: contrib/Widgets/DateTimePicker/fhemweb_datetime.js: parameter diff --git a/fhem/FHEM/66_ECMD.pm b/fhem/FHEM/66_ECMD.pm index f960e6745..4e2d9f3d3 100644 --- a/fhem/FHEM/66_ECMD.pm +++ b/fhem/FHEM/66_ECMD.pm @@ -25,9 +25,30 @@ package main; -# -# Potential future extensions: add support for PARTIALly received datagrams -# http://forum.fhem.de/index.php/topic,24280.msg174330.html#msg174330 + +=for comment + +General rule: + +ECMD handles raw data, i.e. data that might contain control and non-printable characters. +User input for raw data, e.g. setting attributes, and display of raw data is perl-encoded. +Perl-encoded raw data in logs is not enclosed in double quotes. + +A carriage return/line feed (characters 13 and 10) is encoded as +\r\n +and logged as +\r\n (\010\012) + +Decoding is handled by dq(). Encoding is handled by cq(). + +changes as of 27 Nov 2016: +- if split is used, the strings at which the messages are split are still part of the messages +- no default attributes for requestSeparator and responseSeparator +- input of raw data as perl-encoded string (for setting attributes) +- be more verbose and explicit at loglevel 5 +- documentation corrected and amended + +=cut use strict; @@ -84,7 +105,9 @@ ECMD_Define($$) return $msg; } - $attr{$name}{"requestSeparator"}= "\000"; + $hash->{fhem}{".requestSeparator"}= undef; + $hash->{fhem}{".responseSeparator"}= undef; + $hash->{fhem}{".split"}= undef; DevIo_CloseDev($hash); @@ -136,33 +159,37 @@ ECMD_DoInit($) ##################################### sub -dq($) +oq($) { -=for comment - '\a' => "\\a", - '\e' => "\\e", - '\f' => "\\f", - '\n' => "\\n", - '\r' => "\\r", - '\t' => "\\t", - ); - - $s =~ s/\\/\\\\/g; - foreach my $regex (keys %escSequences) { - $s =~ s/$regex/$escSequences{$regex}/g; - } - $s =~ s/([\000-\037])/sprintf("\\%03o", ord($1))/eg; - - - -=cut - - my ($s)= @_; - $s= "" unless(defined($s)); - return "\"" . escapeLogLine($s) . "\""; + return join("", map { sprintf("\\%03o", ord($_)) } split("", $s)); } +sub +dq($) +{ + my ($s)= @_; + return defined($s) ? escapeLogLine($s) . " (" . oq($s) . ")" : ""; +} + +sub +cq($) +{ + my ($s)= @_; + + $s =~ s/\\(\d)(\d)(\d)/chr($1*64+$2*8+$3)/eg; + $s =~ s/\\a/\a/g; + $s =~ s/\\e/\e/g; + $s =~ s/\\f/\f/g; + $s =~ s/\\n/\n/g; + $s =~ s/\\r/\r/g; + $s =~ s/\\t/\t/g; + $s =~ s/\\\\/\\/g; + + return $s; +} + +##################################### sub ECMD_Log($$$) { @@ -170,7 +197,7 @@ ECMD_Log($$$) my $name= $hash->{NAME}; $loglevel= AttrVal($name, "logTraffic", undef) unless(defined($loglevel)); return unless(defined($loglevel)); - Log3 $hash, $loglevel , "$name: $logmsg"; + Log3 $hash, $loglevel, "$name: $logmsg"; } ##################################### @@ -498,8 +525,10 @@ ECMD_Attr($@) my @a = @_; my $hash= $defs{$a[1]}; + my $name= $hash->{NAME}; - if($a[0] eq "set" && $a[2] eq "classdefs") { + if($a[0] eq "set") { + if($a[2] eq "classdefs") { my @classdefs= split(/:/,$a[3]); delete $hash->{fhem}{classDefs}; @@ -507,6 +536,30 @@ ECMD_Attr($@) my ($classname,$filename)= split(/=/,$classdef,2); ECMD_EvalClassDef($hash, $classname, $filename); } + } elsif($a[2] eq "requestSeparator") { + my $c= cq($a[3]); + $hash->{fhem}{".requestSeparator"}= $c; + Log3 $hash, 5, "$name: requestSeparator set to " . dq($c); + } elsif($a[2] eq "responseSeparator") { + my $c= cq($a[3]); + $hash->{fhem}{".responseSeparator"}= $c; + Log3 $hash, 5, "$name: responseSeparator set to " . dq($c); + } elsif($a[2] eq "split") { + my $c= cq($a[3]); + $hash->{fhem}{".split"}= $c; + Log3 $hash, 5, "$name: split set to " . dq($c); + } + } elsif($a[0] eq "del") { + if($a[2] eq "requestSeparator") { + $hash->{fhem}{".requestSeparator"}= undef; + Log3 $hash, 5, "$name: requestSeparator deleted"; + } elsif($a[2] eq "responseSeparator") { + $hash->{fhem}{".responseSeparator"}= undef; + Log3 $hash, 5, "$name: responseSeparator deleted"; + } elsif($a[2] eq "split") { + $hash->{fhem}{".split"}= undef; + Log3 $hash, 5, "$name: split deleted"; + } } return undef; @@ -572,19 +625,19 @@ ECMD_Write($$$) my $name= $hash->{NAME}; my $answer; my $ret= ""; - my $requestSeparator= AttrVal($name, "requestSeparator", undef); - my $responseSeparator= AttrVal($name, "responseSeparator", ""); + my $requestSeparator= $hash->{fhem}{".requestSeparator"}; + my $responseSeparator= $hash->{fhem}{".responseSeparator"}; my @ecmds; if(defined($requestSeparator)) { @ecmds= split $requestSeparator, $msg; } else { push @ecmds, $msg; } - ECMD_Log $hash, 5, "command split into " . ($#ecmds+1) . " parts." if($#ecmds>0); + ECMD_Log $hash, 5, "command split into " . ($#ecmds+1) . " parts, requestSeparator is " . + dq($requestSeparator) if($#ecmds>0); foreach my $ecmd (@ecmds) { ECMD_Log $hash, 5, "sending command " . dq($ecmd); my $msg .= $ecmd; - #$msg.= "\n" unless($nonl); if(defined($expect)) { $answer= ECMD_SimpleExpect($hash, $msg, $expect); $answer= "" unless(defined($answer)); @@ -603,18 +656,21 @@ ECMD_Write($$$) 1; =pod +=item device +=item summary configurable request/response-like communication (physical device) +=item summary_DE konfigurierbare Frage/Antwort-Kommunikation (physisches Gerät) =begin html

ECMD