# TCM_ReadAnswer(): response error corrected

# TCM_Read(), TCM_Write(): new commands added


git-svn-id: https://svn.fhem.de/fhem/trunk@3883 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
klaus-schauer 2013-09-09 09:26:18 +00:00
parent d629bd50ea
commit 81e5e50232

View File

@ -57,7 +57,7 @@ TCM_Initialize($)
$hash->{AttrList}= "do_not_notify:1,0 dummy:1,0 loglevel:0,1,2,3,4,5,6 blockSenderID:own,no"; $hash->{AttrList}= "do_not_notify:1,0 dummy:1,0 loglevel:0,1,2,3,4,5,6 blockSenderID:own,no";
} }
##################################### # Define
sub sub
TCM_Define($$) TCM_Define($$)
{ {
@ -95,7 +95,7 @@ TCM_Define($$)
} }
##################################### # Write
# Input is header and data (HEX), without CRC # Input is header and data (HEX), without CRC
sub sub
TCM_Write($$$) TCM_Write($$$)
@ -152,8 +152,8 @@ TCM_Write($$$)
DevIo_SimpleWrite($hash, $bstring, 1); DevIo_SimpleWrite($hash, $bstring, 1);
} }
##################################### # ESP2 CRC
# Used in the TCM120 / ESP2 # Used in the TCM120
sub sub
TCM_CSUM($) TCM_CSUM($)
{ {
@ -169,8 +169,7 @@ TCM_CSUM($)
return sprintf("%02X", $sum & 0xFF); return sprintf("%02X", $sum & 0xFF);
} }
##################################### # ESP3 CRC-Table
# Used in the TCM310 / ESP3
my @u8CRC8Table = ( my @u8CRC8Table = (
0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24,
0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f,
@ -193,6 +192,8 @@ my @u8CRC8Table = (
0x98, 0x9f, 0x8a, 0x8D, 0x84, 0x83, 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0x98, 0x9f, 0x8a, 0x8D, 0x84, 0x83, 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc,
0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3 ); 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3 );
# ESP3 CRC
# Used in the TCM310
sub sub
TCM_CRC8($) TCM_CRC8($)
{ {
@ -208,7 +209,7 @@ TCM_CRC8($)
return sprintf("%02X", $crc); return sprintf("%02X", $crc);
} }
##################################### # Read
# called from the global loop, when the select for hash->{FD} reports data # called from the global loop, when the select for hash->{FD} reports data
sub sub
TCM_Read($) TCM_Read($)
@ -228,8 +229,8 @@ TCM_Read($)
my $data = $hash->{PARTIAL} . uc(unpack('H*', $buf)); my $data = $hash->{PARTIAL} . uc(unpack('H*', $buf));
Log $ll5, "$name/RAW: $data"; Log $ll5, "$name/RAW: $data";
#############################
if($hash->{MODEL} == 120) { if($hash->{MODEL} == 120) {
# TCM 120
while($data =~ m/^A55A(.B.{20})(..)/) { while($data =~ m/^A55A(.B.{20})(..)/) {
my ($net, $crc) = ($1, $2); my ($net, $crc) = ($1, $2);
@ -276,8 +277,8 @@ TCM_Read($)
$data = "" if($data !~ m/^A55A/); $data = "" if($data !~ m/^A55A/);
} }
############################# } else {
} else { # TCM310 / ESP3 # TCM310 / ESP3
while($data =~ m/^55(....)(..)(..)(..)/) { while($data =~ m/^55(....)(..)(..)(..)/) {
my ($l1, $l2, $packetType, $crc) = (hex($1), hex($2), hex($3), $4); my ($l1, $l2, $packetType, $crc) = (hex($1), hex($2), hex($3), $4);
@ -331,34 +332,37 @@ TCM_Read($)
# packet type RESPONSE # packet type RESPONSE
my $rc = substr($mdata, 0, 2); my $rc = substr($mdata, 0, 2);
my %codes = ( my %codes = (
"00" => "RET_OK", "00" => "OK",
"01" => "RET_ERROR", "01" => "ERROR",
"02" => "RET_NOT_SUPPORTED", "02" => "NOT_SUPPORTED",
"03" => "RET_WRONG_PARAM", "03" => "WRONG_PARAM",
"04" => "RET_OPERATION_DENIED", "04" => "OPERATION_DENIED",
"82" => "FLASH_HW_ERROR",
"90" => "BASEID_OUT_OF_RANGE",
"91" => "BASEID_MAX_REACHED",
); );
$rc = $codes{$rc} if($codes{$rc}); $rc = $codes{$rc} if($codes{$rc});
Log (($rc eq "RET_OK") ? $ll5 : $ll2, "TCM: $name RESPONSE: $rc"); Log (($rc eq "OK") ? $ll5 : $ll2, "TCM: $name RESPONSE: $rc");
} elsif($packetType == 3) { } elsif($packetType == 3) {
# packet type RADIO_SUB_TEL # packet type RADIO_SUB_TEL
Log $ll2, "TCM: $name unknown packet type $packetType: $data"; Log $ll2, "TCM: $name packet type RADIO_SUB_TEL not supported: $data";
} elsif($packetType == 4) { } elsif($packetType == 4) {
# packet type EVENT # packet type EVENT
Log $ll2, "TCM: $name unknown packet type $packetType: $data"; Log $ll2, "TCM: $name packet type EVENT not supported: $data";
} elsif($packetType == 5) { } elsif($packetType == 5) {
# packet type COMMON_COMMAND # packet type COMMON_COMMAND
Log $ll2, "TCM: $name unknown packet type $packetType: $data"; Log $ll2, "TCM: $name packet type COMMON_COMMAND not supported: $data";
} elsif($packetType == 6) { } elsif($packetType == 6) {
# packet type SMART_ACK_COMMAND # packet type SMART_ACK_COMMAND
Log $ll2, "TCM: $name unknown packet type $packetType: $data"; Log $ll2, "TCM: $name packet type SMART_ACK_COMMAND not supported: $data";
} elsif($packetType == 7) { } elsif($packetType == 7) {
# packet type REMOTE_MAN_COMMAND # packet type REMOTE_MAN_COMMAND
Log $ll2, "TCM: $name unknown packet type $packetType: $data"; Log $ll2, "TCM: $name packet type REMOTE_MAN_COMMAND not supported: $data";
} else { } else {
Log $ll2, "TCM: $name unknown packet type $packetType: $data"; Log $ll2, "TCM: $name unknown packet type $packetType: $data";
@ -377,7 +381,7 @@ TCM_Read($)
$hash->{PARTIAL} = $data; $hash->{PARTIAL} = $data;
} }
##################################### # Parse Table TCM 120
my %parsetbl120 = ( my %parsetbl120 = (
"8B08" => { msg=>"ERR_SYNTAX_H_SEQ" }, "8B08" => { msg=>"ERR_SYNTAX_H_SEQ" },
"8B09" => { msg=>"ERR_SYNTAX_LENGTH" }, "8B09" => { msg=>"ERR_SYNTAX_LENGTH" },
@ -399,6 +403,7 @@ my %parsetbl120 = (
expr=>'sprintf("%s, ID:%02x%02x", $a[2]?"on":"off", $a[3], $a[4])' }, expr=>'sprintf("%s, ID:%02x%02x", $a[2]?"on":"off", $a[3], $a[4])' },
); );
# Parse TCM 120
sub sub
TCM_Parse120($$$) TCM_Parse120($$$)
{ {
@ -435,13 +440,19 @@ TCM_Parse120($$$)
return $msg; return $msg;
} }
# Parse Table TCM 310
my %rc310 = ( my %rc310 = (
"00" => "OK",
"01" => "ERROR", "01" => "ERROR",
"02" => "NOT_SUPPORTED", "02" => "NOT_SUPPORTED",
"03" => "WRONG_PARAM", "03" => "WRONG_PARAM",
"04" => "OPERATION_DENIED", "04" => "OPERATION_DENIED",
"82" => "FLASH_HW_ERROR",
"90" => "BASEID_OUT_OF_RANGE",
"91" => "BASEID_MAX_REACHED",
); );
# Parse TCM 310
sub sub
TCM_Parse310($$$) TCM_Parse310($$$)
{ {
@ -473,7 +484,7 @@ TCM_Parse310($$$)
} }
##################################### # Ready
sub sub
TCM_Ready($) TCM_Ready($)
{ {
@ -488,6 +499,7 @@ TCM_Ready($)
return ($InBytes>0); return ($InBytes>0);
} }
# Get commands TCM 120
my %gets120 = ( my %gets120 = (
"sensitivity" => "AB48", "sensitivity" => "AB48",
"idbase" => "AB58", "idbase" => "AB58",
@ -496,24 +508,37 @@ my %gets120 = (
"sw_ver" => "AB4B", "sw_ver" => "AB4B",
); );
# Get commands TCM 310
my %gets310 = ( my %gets310 = (
"sw_ver" => {cmd => "03", "sw_ver" => {cmd => "03",
APPVersion => "1,4", APPVersion => "1,4",
APIVersion => "5,4", APIVersion => "5,4",
ChipID => "9,4", ChipID => "9,4",
ChipVersion => "13,4", ChipVersion => "13,4",
Desc => "17,16,STR",}, Desc => "17,16,STR",},
"idbase" => {cmd => "08", "version" => {cmd => "03",
BaseID => "1,4", APPVersion => "1,4",
RemainingWriteCycles => "5,1",}, APIVersion => "5,4",
"baseID" => {cmd => "08", ChipID => "9,4",
BaseID => "1,4", ChipVersion => "13,4",
RemainingWriteCycles => "5,1",}, Desc => "17,16,STR",},
"repeater" => {cmd => "10", "idbase" => {cmd => "08",
repEnable => "1,1", BaseID => "1,4",
repLevel => "2,1",}, RemainingWriteCycles => "5,1",},
"baseID" => {cmd => "08",
BaseID => "1,4",
RemainingWriteCycles => "5,1",},
"repeater" => {cmd => "0A",
repEnable => "1,1",
repLevel => "2,1",},
# "secureDev" => {cmd => "1B01",
# SLF => "1,1",
# devID => "2,4",},
"numSecureDev" => {cmd => "1D",
number => "1,1",},
); );
# Get
sub sub
TCM_Get($@) TCM_Get($@)
{ {
@ -524,8 +549,8 @@ TCM_Get($@)
my $cmd = $a[1]; my $cmd = $a[1];
my ($err, $msg); my ($err, $msg);
#################################### TCM120
if($hash->{MODEL} eq "120") { if($hash->{MODEL} eq "120") {
# TCM 120
my $rawcmd = $gets120{$cmd}; my $rawcmd = $gets120{$cmd};
return "Unknown argument $cmd, choose one of " . return "Unknown argument $cmd, choose one of " .
join(" ", sort keys %gets120) if(!defined($rawcmd)); join(" ", sort keys %gets120) if(!defined($rawcmd));
@ -536,8 +561,8 @@ TCM_Get($@)
($err, $msg) = TCM_ReadAnswer($hash, "get $cmd"); ($err, $msg) = TCM_ReadAnswer($hash, "get $cmd");
$msg = TCM_Parse120($hash, $msg, 1) if(!$err); $msg = TCM_Parse120($hash, $msg, 1) if(!$err);
#################################### TCM310
} else { } else {
# TCM 310
my $cmdhash = $gets310{$cmd}; my $cmdhash = $gets310{$cmd};
return "Unknown argument $cmd, choose one of " . return "Unknown argument $cmd, choose one of " .
join(" ", sort keys %gets310) if(!defined($cmdhash)); join(" ", sort keys %gets310) if(!defined($cmdhash));
@ -559,7 +584,7 @@ TCM_Get($@)
} }
######################## # RemovePair
sub sub
TCM_RemovePair($) TCM_RemovePair($)
{ {
@ -568,28 +593,33 @@ TCM_RemovePair($)
CommandDeleteReading(undef, "$hash->{NAME} pair"); CommandDeleteReading(undef, "$hash->{NAME} pair");
} }
# Set commands TCM 120
my %sets120 = ( # Name, Data to send to the CUL, Regexp for the answer my %sets120 = ( # Name, Data to send to the CUL, Regexp for the answer
"pairForSec" => { cmd=>"AB18", arg=>"\\d+" }, "pairForSec" => { cmd => "AB18", arg => "\\d+" },
"idbase" => { cmd=>"AB18", arg=>"FF[8-9A-F][0-9A-F]{5}" }, "idbase" => { cmd => "AB18", arg => "FF[8-9A-F][0-9A-F]{5}" },
"baseID" => { cmd=>"AB18", arg=>"FF[8-9A-F][0-9A-F]{5}" }, "baseID" => { cmd => "AB18", arg => "FF[8-9A-F][0-9A-F]{5}" },
"sensitivity" => { cmd=>"AB08", arg=>"0[01]" }, "sensitivity" => { cmd => "AB08", arg => "0[01]" },
"sleep" => { cmd=>"AB09" }, "sleep" => { cmd => "AB09" },
"wake" => { cmd=>"" }, # Special "wake" => { cmd => "" }, # Special
"reset" => { cmd=>"AB0A" }, "reset" => { cmd => "AB0A" },
"modem_on" => { cmd=>"AB28", arg=>"[0-9A-F]{4}" }, "modem_on" => { cmd => "AB28", arg => "[0-9A-F]{4}" },
"modem_off" => { cmd=>"AB2A" }, "modem_off" => { cmd => "AB2A" },
); );
# Set commands TCM 310
my %sets310 = ( my %sets310 = (
"pairForSec" => { cmd=>"AB18", arg=>"\\d+" }, "pairForSec" => { cmd => "AB18", arg=> "\\d+" },
"idbase" => { cmd=>"07", arg=>"FF[8-9A-F][0-9A-F]{5}" }, "sleep" => { cmd => "01", arg => "00[0-9A-F]{6}" },
"baseID" => { cmd=>"07", arg=>"FF[8-9A-F][0-9A-F]{5}" }, "reset" => { cmd => "02" },
# The following 3 does not seem to work / dont get an answer "bist" => { cmd => "06", BIST_Result => "1,1", },
# "sleep" => { cmd=>"01", arg=>"00[0-9A-F]{6}" }, "idbase" => { cmd => "07", arg => "FF[8-9A-F][0-9A-F]{5}" },
# "reset" => { cmd=>"02" }, "baseID" => { cmd => "07", arg => "FF[8-9A-F][0-9A-F]{5}" },
# "bist" => { cmd=>"06", BIST_Result=>"1,1", }, "repeater" => { cmd => "09", arg => "0[0-1]0[0-2]" },
"maturity" => { cmd => "10", arg => "0[0-1]" },
"subtel" => { cmd => "11", arg => "0[0-1]" },
); );
# Set
sub sub
TCM_Set($@) TCM_Set($@)
{ {
@ -622,8 +652,8 @@ TCM_Set($@)
return; return;
} }
##############################
if($hash->{MODEL} eq "120") { if($hash->{MODEL} eq "120") {
# TCM 120
if($cmdHex eq "") { # wake is very special if($cmdHex eq "") { # wake is very special
DevIo_SimpleWrite($hash, "AA", 1); DevIo_SimpleWrite($hash, "AA", 1);
return ""; return "";
@ -635,8 +665,8 @@ TCM_Set($@)
$msg = TCM_Parse120($hash, $msg, 1) $msg = TCM_Parse120($hash, $msg, 1)
if(!$err); if(!$err);
############################## } else {
} else { # TCM310 # TCM310
TCM_Write($hash, sprintf("%04X0005", length($cmdHex)/2), $cmdHex); TCM_Write($hash, sprintf("%04X0005", length($cmdHex)/2), $cmdHex);
($err, $msg) = TCM_ReadAnswer($hash, "set $cmd"); ($err, $msg) = TCM_ReadAnswer($hash, "set $cmd");
$msg = TCM_Parse310($hash, $msg, $cmdhash) $msg = TCM_Parse310($hash, $msg, $cmdhash)
@ -652,6 +682,7 @@ TCM_Set($@)
} }
# ReadAnswer
sub sub
TCM_ReadAnswer($$) TCM_ReadAnswer($$)
{ {
@ -696,6 +727,7 @@ TCM_ReadAnswer($$)
Log $ll5, "TCM/RAW (ReadAnswer): $data"; Log $ll5, "TCM/RAW (ReadAnswer): $data";
if($hash->{MODEL} eq "120") { if($hash->{MODEL} eq "120") {
# TCM 120
if(length($data) >= 28) { if(length($data) >= 28) {
return ("$arg: Bogus answer received: $data", undef) return ("$arg: Bogus answer received: $data", undef)
if($data !~ m/^A55A(.B.{20})(..)/); if($data !~ m/^A55A(.B.{20})(..)/);
@ -708,12 +740,16 @@ TCM_ReadAnswer($$)
return (undef, $net); return (undef, $net);
} }
} else { # 310 } else {
if(length($data) >= 7) { # TCM 310
if(length($data) >= 14) {
return ("$arg: Bogus answer received: $data", undef) return ("$arg: Bogus answer received: $data", undef)
if($data !~ m/^55(....)(..)(..)(..)(.*)(..)$/); if($data !~ m/^55(....)(..)(..)(..)(.*)(..)$/);
my ($dlen, $olen, $ptype, $hcrc, $data, $dcrc) = ($1,$2,$3,$4,$5,$6); my ($dlen, $olen, $ptype, $hcrc, $data, $dcrc) = ($1,$2,$3,$4,$5,$6);
next if(length($data) < hex($dlen)+hex($olen)+6); ### ???
# next if(length($data) < hex($dlen)+hex($olen)+6);
# next if(length($data) < 2 * hex($dlen) + 2 * hex($olen) + 6);
next if(length($data) < 2*hex($dlen));
my $myhcrc = TCM_CRC8("$dlen$olen$ptype"); my $myhcrc = TCM_CRC8("$dlen$olen$ptype");
return ("wrong header checksum: got $hcrc, computed $myhcrc", undef) return ("wrong header checksum: got $hcrc, computed $myhcrc", undef)
@ -730,6 +766,7 @@ TCM_ReadAnswer($$)
} }
} }
# Undef
sub sub
TCM_Undef($$) TCM_Undef($$)
{ {
@ -774,6 +811,10 @@ TCM_Undef($$)
The address range used by your transceiver module, can be found in the The address range used by your transceiver module, can be found in the
parameters BaseID and LastID. parameters BaseID and LastID.
<br><br> <br><br>
The transceiver moduls do not always support all commands. The supported range
of commands depends on the hardware and the firmware version. A firmware update
is usually not provided.
<br><br>
<a name="TCMdefine"></a> <a name="TCMdefine"></a>
<b>Define</b> <b>Define</b>
@ -796,42 +837,90 @@ TCM_Undef($$)
<br> <br>
<a name="TCMset"></a> <a name="TCMset"></a>
<b>Set </b> <b>Set</b><br>
<ul> <ul><b>TCM 120</b><br>
<li>baseID<br> <li>idbase [FF800000 ... FFFFFF80]<br>
Set the BaseID.<br> Set the BaseID.<br>
Note: The firmware executes this command only up to then times to prevent misuse. Note: The firmware executes this command only up to then times to prevent misuse.</li>
</li> <li>modem_off<br>
<li>idbase<br> Deactivates TCM modem functionality</li>
Set the BaseID.<br> <li>modem_on [0000 ... FFFF]<br>
Note: The firmware executes this command only up to then times to prevent misuse. Activates TCM modem functionality and sets the modem ID</li>
</li> <li>pairForSec &lt;t/s&gt;<br>
<li>modem_off</li> Set Fhem in teach-in mode.<br>
<li>modem_on</li> The command is only required to teach-in bidirectional actuators
<li>reset</li> e. g. EEP 4BS, RORG A5-20-01 (Battery Powered Actuator),
<li>sensitivity</li> see <a href="#pairForSec"> Bidirectional Teach-In / Teach-Out</a>.</li>
<li>sleep</li> <li>reset<br>
<li>wake</li><br> Reset the device</li>
For details see the datasheet available from <a href="http://www.enocean.com">www.enocean.com</a>. <li>sensitivity [00|01]<br>
If you do not understand it, than you probably don't need it :) Set the TCM radio sensitivity: low = 00, high = 01</li>
<li>sleep<br>
Enter the energy saving mode</li>
<li>wake<br>
Wakes up from sleep mode</li>
<br><br>
For details see the TCM 120 User Manual available from <a href="http://www.enocean.com">www.enocean.com</a>.
<br><br>
</ul>
<ul><b>TCM 310</b><br>
<li>baseID [FF800000 ... FFFFFF80]<br>
Set the BaseID.<br>
Note: The firmware executes this command only up to then times to prevent misuse.</li>
<li>bist<br>
Perform Flash BIST operation (Built-in-self-test).</li>
<li>maturity [00|01]<br>
Waiting till end of maturity time before received radio telegrams will transmit:
radio telegrams are send immediately = 00, after the maturity time is elapsed = 01</li>
<li>pairForSec &lt;t/s&gt;<br>
Set Fhem in teach-in mode.<br>
The command is only required to teach-in bidirectional actuators
e. g. EEP 4BS, RORG A5-20-01 (Battery Powered Actuator),
see <a href="#pairForSec"> Bidirectional Teach-In / Teach-Out</a>.</li>
<li>reset<br>
Reset the device</li>
<li>repeater [0000|0101|0102]<br>
Set Repeater Level: off = 0000, 1 = 0101, 2 = 0102.</li>
<li>sleep &lt;t/10 ms&gt; (Range: 00000000 ... 00FFFFFF)<br>
Enter the energy saving mode</li>
<li>subtel [00|01]<br>
Transmitting additional subtelegram info: Enable = 01, Disable = 00</li>
<br><br>
For details see the EnOcean Serial Protocol 3 (ESP3) available from
<a href="http://www.enocean.com">www.enocean.com</a>.
<br><br> <br><br>
</ul> </ul>
<a name="TCMget"></a> <a name="TCMget"></a>
<b>Get</b> <b>Get</b><br>
<ul> <ul><b>TCM 120</b><br>
<li>baseID<br>
Get the BaseID. You need this command in order to control EnOcean devices,
see the <a href="#EnOceandefine">EnOcean</a> paragraph.
</li>
<li>idbase<br> <li>idbase<br>
Get the BaseID. You need this command in order to control EnOcean devices, Get the BaseID. You need this command in order to control EnOcean devices,
see the <a href="#EnOceandefine">EnOcean</a> paragraph. see the <a href="#EnOceandefine">EnOcean</a> paragraph.
</li> </li>
<li>modem_status</li> <li>modem_status<br>
<li>sensitivity</li> Requests the current modem status.</li>
<li>sw_ver</li><br> <li>sensitivity<br>
For details see the datasheet available from <a href="http://www.enocean.com">www.enocean.com</a> Get the TCM radio sensitivity, low = 00, high = 01</li>
<li>sw_ver<br>
Read the device SW version / HW version, chip-ID, etc.</li>
<br><br>
For details see the TCM 120 User Manual available from <a href="http://www.enocean.com">www.enocean.com</a>.
<br><br>
</ul>
<ul><b>TCM 310</b><br>
<li>baseID<br>
Get the BaseID. You need this command in order to control EnOcean devices,
see the <a href="#EnOceandefine">EnOcean</a> paragraph.</li>
<li>numSecureDev<br>
Read number of teached in secure devices.</li>
<li>repeater<br>
Read Repeater Level: off = 0000, 1 = 0101, 2 = 0102.</li>
<li>version<br>
Read the device SW version / HW version, chip-ID, etc.</li>
<br><br>
For details see the EnOcean Serial Protocol 3 (ESP3) available from
<a href="http://www.enocean.com">www.enocean.com</a>.
<br><br> <br><br>
</ul> </ul>