mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-04-21 01:46:08 +00:00
44_S7: Siemens S5 is now supported (via serial interface)
git-svn-id: https://svn.fhem.de/fhem/trunk@12776 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
a9d9c60b6a
commit
cad5d3506f
1849
fhem/FHEM/44_S7.pm
1849
fhem/FHEM/44_S7.pm
File diff suppressed because it is too large
Load Diff
@ -180,25 +180,25 @@ sub S7_ARead_Parse($$) {
|
|||||||
my $myI;
|
my $myI;
|
||||||
|
|
||||||
if ( $h->{DATATYPE} eq "u8" ) {
|
if ( $h->{DATATYPE} eq "u8" ) {
|
||||||
$myI = $hash->{S7TCPClient}->ByteAt( \@Writebuffer, $s );
|
$myI = $hash->{S7PLCClient}->ByteAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "s8" ) {
|
elsif ( $h->{DATATYPE} eq "s8" ) {
|
||||||
$myI = $hash->{S7TCPClient}->ShortAt( \@Writebuffer, $s );
|
$myI = $hash->{S7PLCClient}->ShortAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "u16" ) {
|
elsif ( $h->{DATATYPE} eq "u16" ) {
|
||||||
$myI = $hash->{S7TCPClient}->WordAt( \@Writebuffer, $s );
|
$myI = $hash->{S7PLCClient}->WordAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "s16" ) {
|
elsif ( $h->{DATATYPE} eq "s16" ) {
|
||||||
$myI = $hash->{S7TCPClient}->IntegerAt( \@Writebuffer, $s );
|
$myI = $hash->{S7PLCClient}->IntegerAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "u32" ) {
|
elsif ( $h->{DATATYPE} eq "u32" ) {
|
||||||
$myI = $hash->{S7TCPClient}->DWordAt( \@Writebuffer, $s );
|
$myI = $hash->{S7PLCClient}->DWordAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "s32" ) {
|
elsif ( $h->{DATATYPE} eq "s32" ) {
|
||||||
$myI = $hash->{S7TCPClient}->DintAt( \@Writebuffer, $s );
|
$myI = $hash->{S7PLCClient}->DintAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "float" ) {
|
elsif ( $h->{DATATYPE} eq "float" ) {
|
||||||
$myI = $hash->{S7TCPClient}->FloatAt( \@Writebuffer, $s );
|
$myI = $hash->{S7PLCClient}->FloatAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log3 $name, 3,
|
Log3 $name, 3,
|
||||||
@ -256,34 +256,34 @@ sub S7_ARead_Parse($$) {
|
|||||||
|
|
||||||
if ( $h->{DATATYPE} eq "u8" ) {
|
if ( $h->{DATATYPE} eq "u8" ) {
|
||||||
$myI =
|
$myI =
|
||||||
$hash->{S7TCPClient}->ByteAt( \@Writebuffer, $s );
|
$hash->{S7PLCClient}->ByteAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "s8" ) {
|
elsif ( $h->{DATATYPE} eq "s8" ) {
|
||||||
$myI =
|
$myI =
|
||||||
$hash->{S7TCPClient}
|
$hash->{S7PLCClient}
|
||||||
->ShortAt( \@Writebuffer, $s );
|
->ShortAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "u16" ) {
|
elsif ( $h->{DATATYPE} eq "u16" ) {
|
||||||
$myI =
|
$myI =
|
||||||
$hash->{S7TCPClient}->WordAt( \@Writebuffer, $s );
|
$hash->{S7PLCClient}->WordAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "s16" ) {
|
elsif ( $h->{DATATYPE} eq "s16" ) {
|
||||||
$myI =
|
$myI =
|
||||||
$hash->{S7TCPClient}
|
$hash->{S7PLCClient}
|
||||||
->IntegerAt( \@Writebuffer, $s );
|
->IntegerAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "u32" ) {
|
elsif ( $h->{DATATYPE} eq "u32" ) {
|
||||||
$myI =
|
$myI =
|
||||||
$hash->{S7TCPClient}
|
$hash->{S7PLCClient}
|
||||||
->DWordAt( \@Writebuffer, $s );
|
->DWordAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "s32" ) {
|
elsif ( $h->{DATATYPE} eq "s32" ) {
|
||||||
$myI =
|
$myI =
|
||||||
$hash->{S7TCPClient}->DintAt( \@Writebuffer, $s );
|
$hash->{S7PLCClient}->DintAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "float" ) {
|
elsif ( $h->{DATATYPE} eq "float" ) {
|
||||||
$myI =
|
$myI =
|
||||||
$hash->{S7TCPClient}
|
$hash->{S7PLCClient}
|
||||||
->FloatAt( \@Writebuffer, $s );
|
->FloatAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -364,43 +364,45 @@ sub S7_ARead_Attr(@) {
|
|||||||
1;
|
1;
|
||||||
|
|
||||||
=pod
|
=pod
|
||||||
|
=item summary logical device for a analog reading from a S7/S5
|
||||||
|
=item summary_DE logisches Device für einen analogen Nur Lese Datenpunkt von einer S5 / S7
|
||||||
=begin html
|
=begin html
|
||||||
|
|
||||||
<a name="S7_ARead"></a>
|
<a name="S7_ARead"></a>
|
||||||
<h3>S7_ARead</h3>
|
<h3>S7_ARead</h3>
|
||||||
<ul>
|
<ul>
|
||||||
This module is a logical module of the physical module S7.<br />
|
|
||||||
This module provides analog data (signed / unsigned integer Values).<br />
|
This module is a logical module of the physical module S7. <br>
|
||||||
Note: you have to configure a PLC reading at the physical module (S7) first.<br />
|
This module provides analog data (signed / unsigned integer Values).<br>
|
||||||
<br />
|
Note: you have to configure a PLC reading at the physical module (S7) first.<br>
|
||||||
<br />
|
<br><br>
|
||||||
<b>Define</b><br />
|
<b>Define</b><br>
|
||||||
<code>define <name> S7_ARead {inputs|outputs|flags|db} <DB> <start> {u8|s8|u16|s16|u32|s32}</code><br />
|
<code>define <name> S7_ARead {inputs|outputs|flags|db} <DB> <start> {u8|s8|u16|s16|u32|s32}</code>
|
||||||
|
<br><br>
|
||||||
<ul>
|
<ul>
|
||||||
<li>inputs|outputs|flags|db … defines where to read.</li>
|
<li>inputs|outputs|flags|db … defines where to read.</li>
|
||||||
<li>DB … Number of the DB</li>
|
<li>DB … Number of the DB</li>
|
||||||
<li>start … start byte of the reading</li>
|
<li>start … start byte of the reading</li>
|
||||||
<li>{u8|s8|u16|s16|u32|s32} … defines the datatype:
|
<li>{u8|s8|u16|s16|u32|s32} … defines the datatype: </li>
|
||||||
<ul>
|
<ul>
|
||||||
<li>u8 …. unsigned 8 Bit integer</li>
|
<li>u8 …. unsigned 8 Bit integer</li>
|
||||||
<li>s8 …. signed 8 Bit integer</li>
|
<li>s8 …. signed 8 Bit integer</li>
|
||||||
<li>u16 …. unsigned 16 Bit integer</li>
|
<li>u16 …. unsigned 16 Bit integer</li>
|
||||||
<li>s16 …. signed 16 Bit integer</li>
|
<li>s16 …. signed 16 Bit integer</li>
|
||||||
<li>u32 …. unsigned 32 Bit integer</li>
|
<li>u32 …. unsigned 32 Bit integer</li>
|
||||||
<li>s32 …. signed 32 Bit integer</li>
|
<li>s32 …. signed 32 Bit integer</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
Note: the required memory area (start – start + datatypelength) need to be with in the configured PLC reading of the physical module.
|
||||||
<li>Note: the required memory area (start – start + datatypelength) need to be with in the configured PLC reading of the physical module.</li>
|
</ul>
|
||||||
</ul>
|
<br>
|
||||||
<br />
|
<b>Attr</b><br>
|
||||||
<b>Attr</b><br />
|
The following parameters are used to scale every reading<br>
|
||||||
The following parameters are used to scale every reading
|
<ul>
|
||||||
<ul>
|
<li>multiplicator</li>
|
||||||
<li>multiplicator</li>
|
<li>offset</li>
|
||||||
<li>offset</li>
|
</ul>
|
||||||
</ul>
|
|
||||||
newValue = <multiplicator> * Value + <offset>
|
newValue = <multiplicator> * Value + <offset>
|
||||||
</ul>
|
</ul>
|
||||||
=end html
|
=end html
|
||||||
|
|
||||||
@ -409,40 +411,38 @@ sub S7_ARead_Attr(@) {
|
|||||||
<a name="S7_ARead"></a>
|
<a name="S7_ARead"></a>
|
||||||
<h3>S7_ARead</h3>
|
<h3>S7_ARead</h3>
|
||||||
<ul>
|
<ul>
|
||||||
This module is a logical module of the physical module S7.<br />
|
|
||||||
This module provides analog data (signed / unsigned integer Values).<br />
|
This module is a logical module of the physical module S7. <br>
|
||||||
Note: you have to configure a PLC reading at the physical module (S7) first.<br />
|
This module provides analog data (signed / unsigned integer Values).<br>
|
||||||
<br />
|
Note: you have to configure a PLC reading at the physical module (S7) first.<br>
|
||||||
<br />
|
<br><br>
|
||||||
<b>Define</b><br />
|
<b>Define</b><br>
|
||||||
<code>define <name> S7_ARead {inputs|outputs|flags|db} <DB> <start> {u8|s8|u16|s16|u32|s32}</code><br />
|
<code>define <name> S7_ARead {inputs|outputs|flags|db} <DB> <start> {u8|s8|u16|s16|u32|s32}</code>
|
||||||
|
<br><br>
|
||||||
<ul>
|
<ul>
|
||||||
<li>inputs|outputs|flags|db … defines where to read.</li>
|
<li>inputs|outputs|flags|db … defines where to read.</li>
|
||||||
<li>DB … Number of the DB</li>
|
<li>DB … Number of the DB</li>
|
||||||
<li>start … start byte of the reading</li>
|
<li>start … start byte of the reading</li>
|
||||||
<li>{u8|s8|u16|s16|u32|s32} … defines the datatype:
|
<li>{u8|s8|u16|s16|u32|s32} … defines the datatype: </li>
|
||||||
<ul>
|
<ul>
|
||||||
<li>u8 …. unsigned 8 Bit integer</li>
|
<li>u8 …. unsigned 8 Bit integer</li>
|
||||||
<li>s8 …. signed 8 Bit integer</li>
|
<li>s8 …. signed 8 Bit integer</li>
|
||||||
<li>u16 …. unsigned 16 Bit integer</li>
|
<li>u16 …. unsigned 16 Bit integer</li>
|
||||||
<li>s16 …. signed 16 Bit integer</li>
|
<li>s16 …. signed 16 Bit integer</li>
|
||||||
<li>u32 …. unsigned 32 Bit integer</li>
|
<li>u32 …. unsigned 32 Bit integer</li>
|
||||||
<li>s32 …. signed 32 Bit integer</li>
|
<li>s32 …. signed 32 Bit integer</li>
|
||||||
<li>float …. 4 byte float</li>
|
<li>float …. 4 byte float </li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
Note: the required memory area (start – start + datatypelength) need to be with in the configured PLC reading of the physical module.
|
||||||
<li>Note: the required memory area (start – start + datatypelength) need to be with in the configured PLC reading of the physical module.</li>
|
</ul>
|
||||||
</ul>
|
<b>Attr</b>
|
||||||
<b>Attr</b><br />
|
The following parameters are used to scale every reading
|
||||||
The following parameters are used to scale every reading
|
<ul>
|
||||||
<ul>
|
<li>multiplicator</li>
|
||||||
<li>multiplicator</li>
|
<li>offset</li>
|
||||||
<li>offset</li>
|
</ul>
|
||||||
</ul>
|
newValue = <multiplicator> * Value + <offset>
|
||||||
newValue = <multiplicator> * Value + <offset>
|
|
||||||
</ul>
|
</ul>
|
||||||
=end html_DE
|
=end html_DE
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
|
@ -210,7 +210,7 @@ sub S7_AWrite_Set($@) {
|
|||||||
my $dbNR = $hash->{DB};
|
my $dbNR = $hash->{DB};
|
||||||
my $shash = $defs{$sname};
|
my $shash = $defs{$sname};
|
||||||
|
|
||||||
if ( !defined( $shash->{S7TCPClient} ) ) {
|
if ( !defined( $shash->{S7PLCClient} ) ) {
|
||||||
my $err = "$name S7_AWrite_Set: not connected to PLC ";
|
my $err = "$name S7_AWrite_Set: not connected to PLC ";
|
||||||
Log3 $name, 3, $err;
|
Log3 $name, 3, $err;
|
||||||
return $err;
|
return $err;
|
||||||
@ -227,32 +227,40 @@ sub S7_AWrite_Set($@) {
|
|||||||
my $WordLen;
|
my $WordLen;
|
||||||
|
|
||||||
if ( $datatype eq "u8" ) {
|
if ( $datatype eq "u8" ) {
|
||||||
$b = $shash->{S7TCPClient}->setByteAt( "X", 0, $newValue );
|
$b = $shash->{S7PLCClient}->setByteAt( "X", 0, $newValue );
|
||||||
$WordLen = &S7Client::S7WLByte;
|
$WordLen = &S7Client::S7WLByte;
|
||||||
}
|
}
|
||||||
elsif ( $datatype eq "s8" ) {
|
elsif ( $datatype eq "s8" ) {
|
||||||
$b = $shash->{S7TCPClient}->setShortAt( "X", 0, $newValue );
|
$b = $shash->{S7PLCClient}->setShortAt( "X", 0, $newValue );
|
||||||
$WordLen = &S7Client::S7WLByte;
|
$WordLen = &S7Client::S7WLByte;
|
||||||
}
|
}
|
||||||
elsif ( $datatype eq "u16" ) {
|
elsif ( $datatype eq "u16" ) {
|
||||||
$b = $shash->{S7TCPClient}->setWordAt( "XX", 0, $newValue );
|
$b = $shash->{S7PLCClient}->setWordAt( "XX", 0, $newValue );
|
||||||
$WordLen = &S7Client::S7WLByte;
|
$WordLen = &S7Client::S7WLInt;
|
||||||
|
|
||||||
|
# $WordLen = &S7Client::S7WLWord;
|
||||||
}
|
}
|
||||||
elsif ( $datatype eq "s16" ) {
|
elsif ( $datatype eq "s16" ) {
|
||||||
$b = $shash->{S7TCPClient}->setIntegerAt( "XX", 0, $newValue );
|
$b = $shash->{S7PLCClient}->setIntegerAt( "XX", 0, $newValue );
|
||||||
$WordLen = &S7Client::S7WLByte;
|
$WordLen = &S7Client::S7WLInt;
|
||||||
|
|
||||||
|
# $WordLen = &S7Client::S7WLWord;
|
||||||
}
|
}
|
||||||
elsif ( $datatype eq "u32" ) {
|
elsif ( $datatype eq "u32" ) {
|
||||||
$b = $shash->{S7TCPClient}->setDWordAt( "XXXX", 0, $newValue );
|
$b = $shash->{S7PLCClient}->setDWordAt( "XXXX", 0, $newValue );
|
||||||
$WordLen = &S7Client::S7WLByte;
|
$WordLen = &S7Client::S7WLDInt;
|
||||||
|
|
||||||
|
# $WordLen = &S7Client::S7WLDWord;
|
||||||
}
|
}
|
||||||
elsif ( $datatype eq "s32" ) {
|
elsif ( $datatype eq "s32" ) {
|
||||||
$b = $shash->{S7TCPClient}->setDintAt( "XXXX", 0, $newValue );
|
$b = $shash->{S7PLCClient}->setDintAt( "XXXX", 0, $newValue );
|
||||||
$WordLen = &S7Client::S7WLByte;
|
$WordLen = &S7Client::S7WLDInt;
|
||||||
|
|
||||||
|
# $WordLen = &S7Client::S7WLDWord;
|
||||||
}
|
}
|
||||||
elsif ( $datatype eq "float" ) {
|
elsif ( $datatype eq "float" ) {
|
||||||
$b = $shash->{S7TCPClient}->setFloatAt( "XXXX", 0, $newValue );
|
$b = $shash->{S7PLCClient}->setFloatAt( "XXXX", 0, $newValue );
|
||||||
$WordLen = &S7Client::S7WLByte;
|
$WordLen = &S7Client::S7WLReal;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
my $err = "$name S7_AWrite: Parse unknown type : (" . $datatype . ")";
|
my $err = "$name S7_AWrite: Parse unknown type : (" . $datatype . ")";
|
||||||
@ -304,7 +312,7 @@ sub S7_AWrite_Parse($$) {
|
|||||||
|
|
||||||
my $ID = "$area $DB";
|
my $ID = "$area $DB";
|
||||||
|
|
||||||
Log3 $name, 6, "$name S7_AWrite_Parse $rmsg";
|
Log3 $name, 5, "$name S7_AWrite_Parse $rmsg";
|
||||||
my @clientList = split( ",", $clientNames );
|
my @clientList = split( ",", $clientNames );
|
||||||
|
|
||||||
if ( int(@clientList) > 0 ) {
|
if ( int(@clientList) > 0 ) {
|
||||||
@ -330,25 +338,25 @@ sub S7_AWrite_Parse($$) {
|
|||||||
my $myI;
|
my $myI;
|
||||||
|
|
||||||
if ( $h->{DATATYPE} eq "u8" ) {
|
if ( $h->{DATATYPE} eq "u8" ) {
|
||||||
$myI = $hash->{S7TCPClient}->ByteAt( \@Writebuffer, $s );
|
$myI = $hash->{S7PLCClient}->ByteAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "s8" ) {
|
elsif ( $h->{DATATYPE} eq "s8" ) {
|
||||||
$myI = $hash->{S7TCPClient}->ShortAt( \@Writebuffer, $s );
|
$myI = $hash->{S7PLCClient}->ShortAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "u16" ) {
|
elsif ( $h->{DATATYPE} eq "u16" ) {
|
||||||
$myI = $hash->{S7TCPClient}->WordAt( \@Writebuffer, $s );
|
$myI = $hash->{S7PLCClient}->WordAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "s16" ) {
|
elsif ( $h->{DATATYPE} eq "s16" ) {
|
||||||
$myI = $hash->{S7TCPClient}->IntegerAt( \@Writebuffer, $s );
|
$myI = $hash->{S7PLCClient}->IntegerAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "u32" ) {
|
elsif ( $h->{DATATYPE} eq "u32" ) {
|
||||||
$myI = $hash->{S7TCPClient}->DWordAt( \@Writebuffer, $s );
|
$myI = $hash->{S7PLCClient}->DWordAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "s32" ) {
|
elsif ( $h->{DATATYPE} eq "s32" ) {
|
||||||
$myI = $hash->{S7TCPClient}->DintAt( \@Writebuffer, $s );
|
$myI = $hash->{S7PLCClient}->DintAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "float" ) {
|
elsif ( $h->{DATATYPE} eq "float" ) {
|
||||||
$myI = $hash->{S7TCPClient}->FloatAt( \@Writebuffer, $s );
|
$myI = $hash->{S7PLCClient}->FloatAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log3 $name, 3, "$name S7_AWrite: Parse unknown type : ("
|
Log3 $name, 3, "$name S7_AWrite: Parse unknown type : ("
|
||||||
@ -387,34 +395,34 @@ sub S7_AWrite_Parse($$) {
|
|||||||
|
|
||||||
if ( $h->{DATATYPE} eq "u8" ) {
|
if ( $h->{DATATYPE} eq "u8" ) {
|
||||||
$myI =
|
$myI =
|
||||||
$hash->{S7TCPClient}->ByteAt( \@Writebuffer, $s );
|
$hash->{S7PLCClient}->ByteAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "s8" ) {
|
elsif ( $h->{DATATYPE} eq "s8" ) {
|
||||||
$myI =
|
$myI =
|
||||||
$hash->{S7TCPClient}
|
$hash->{S7PLCClient}
|
||||||
->ShortAt( \@Writebuffer, $s );
|
->ShortAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "u16" ) {
|
elsif ( $h->{DATATYPE} eq "u16" ) {
|
||||||
$myI =
|
$myI =
|
||||||
$hash->{S7TCPClient}->WordAt( \@Writebuffer, $s );
|
$hash->{S7PLCClient}->WordAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "s16" ) {
|
elsif ( $h->{DATATYPE} eq "s16" ) {
|
||||||
$myI =
|
$myI =
|
||||||
$hash->{S7TCPClient}
|
$hash->{S7PLCClient}
|
||||||
->IntegerAt( \@Writebuffer, $s );
|
->IntegerAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "u32" ) {
|
elsif ( $h->{DATATYPE} eq "u32" ) {
|
||||||
$myI =
|
$myI =
|
||||||
$hash->{S7TCPClient}
|
$hash->{S7PLCClient}
|
||||||
->DWordAt( \@Writebuffer, $s );
|
->DWordAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "s32" ) {
|
elsif ( $h->{DATATYPE} eq "s32" ) {
|
||||||
$myI =
|
$myI =
|
||||||
$hash->{S7TCPClient}->DintAt( \@Writebuffer, $s );
|
$hash->{S7PLCClient}->DintAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
elsif ( $h->{DATATYPE} eq "float" ) {
|
elsif ( $h->{DATATYPE} eq "float" ) {
|
||||||
$myI =
|
$myI =
|
||||||
$hash->{S7TCPClient}
|
$hash->{S7PLCClient}
|
||||||
->FloatAt( \@Writebuffer, $s );
|
->FloatAt( \@Writebuffer, $s );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -431,7 +439,7 @@ sub S7_AWrite_Parse($$) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( int(@list) == 0 ) {
|
if ( int(@list) == 0 ) {
|
||||||
Log3 $name, 6, "S7_AWrite: Parse no client found ($name) ...";
|
Log3 $name, 5, "S7_AWrite: Parse no client found ($name) ...";
|
||||||
push( @list, "" );
|
push( @list, "" );
|
||||||
|
|
||||||
# return undef;
|
# return undef;
|
||||||
@ -468,96 +476,96 @@ sub S7_AWrite_Parse($$) {
|
|||||||
1;
|
1;
|
||||||
|
|
||||||
=pod
|
=pod
|
||||||
|
=item summary logical device for a analog writing to a S7/S5
|
||||||
|
=item summary_DE logisches Device für einen analogen Lese/Schreib Datenpunkt zu einer S5 / S7
|
||||||
|
|
||||||
=begin html
|
=begin html
|
||||||
|
|
||||||
<a name="S7_AWrite"></a>
|
<p><a name="S7_AWrite"></a></p>
|
||||||
<h3>S7_AWrite</h3>
|
<h3>S7_AWrite</h3>
|
||||||
<ul>
|
<ul>
|
||||||
This module is a logical module of the physical module S7.<br />
|
<ul>This module is a logical module of the physical module S7.</ul>
|
||||||
This module provides sending analog data (unsigned integer Values) to the PLC.<br />
|
</ul>
|
||||||
Note: you have to configure a PLC writing at the physical modul (S7) first.<br />
|
<ul>
|
||||||
<br />
|
<ul>This module provides sending analog data (unsigned integer Values) to the PLC.</ul>
|
||||||
<b>Define</b>
|
</ul>
|
||||||
|
<ul>
|
||||||
<ul>
|
<ul>Note: you have to configure a PLC writing at the physical modul (S7) first.</ul>
|
||||||
<li><code>define <name> S7_AWrite {inputs|outputs|flags|db} <DB> <start> {u8|s8|u16|s16|u32|s32|float}</code><br />
|
</ul>
|
||||||
|
<p><br /><br /><strong>Define</strong><br /><code>define <name> S7_AWrite {inputs|outputs|flags|db} <DB> <start> {u8|s8|u16|s16|u32|s32|float}</code><br /><br /></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>db … defines where to read. Note currently only writing in to DB are supported.</li>
|
<ul>
|
||||||
<li>DB … Number of the DB</li>
|
<ul>
|
||||||
<li>start … start byte of the reading</li>
|
<ul>
|
||||||
<li>{u8|s8|u16|s16|u32|s32} … defines the datatype:
|
<li>db … defines where to read. Note currently only writing in to DB are supported.</li>
|
||||||
<ul>
|
<li>DB … Number of the DB</li>
|
||||||
<li>u8 …. unsigned 8 Bit integer</li>
|
<li>start … start byte of the reading</li>
|
||||||
<li>s8 …. signed 8 Bit integer</li>
|
<li>{u8|s8|u16|s16|u32|s32} … defines the datatype:</li>
|
||||||
<li>u16 …. unsigned 16 Bit integer</li>
|
<ul>
|
||||||
<li>s16 …. signed 16 Bit integer</li>
|
<li>u8 …. unsigned 8 Bit integer</li>
|
||||||
<li>u32 …. unsigned 32 Bit integer</li>
|
<li>s8 …. signed 8 Bit integer</li>
|
||||||
<li>s32 …. signed 32 Bit integer</li>
|
<li>u16 …. unsigned 16 Bit integer</li>
|
||||||
<li>float …. 4 byte float</li>
|
<li>s16 …. signed 16 Bit integer</li>
|
||||||
</ul>
|
<li>u32 …. unsigned 32 Bit integer</li>
|
||||||
</li>
|
<li>s32 …. signed 32 Bit integer</li>
|
||||||
</ul>
|
<li>float …. 4 byte float</li>
|
||||||
Note: the required memory area (start – start + datatypelength) need to be with in the configured PLC writing of the physical module.</li>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
<b>Set</b><br />
|
Note: the required memory area (start – start + datatypelength) need to be with in the configured PLC writing of the physical module.</ul>
|
||||||
|
</ul>
|
||||||
<ul>
|
</ul>
|
||||||
<li><code>set <name> S7_AWrite <value></code>
|
<p><strong>Set</strong><br /><br /><code>set <name> S7_AWrite <value></code></p>
|
||||||
|
<ul>
|
||||||
<ul>
|
<ul>
|
||||||
<li>value … an numeric value</li>
|
<ul>
|
||||||
</ul>
|
<li>value … an numeric value</li>
|
||||||
</li>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
=end html
|
=end html
|
||||||
|
|
||||||
=begin html_DE
|
=begin html_DE
|
||||||
|
|
||||||
<a name="S7_AWrite"></a>
|
<p><a name="S7_AWrite"></a></p>
|
||||||
<h3>S7_AWrite</h3>
|
<h3>S7_AWrite</h3>
|
||||||
<ul>
|
<ul>
|
||||||
This module is a logical module of the physical module S7.<br />
|
<ul>This module is a logical module of the physical module S7.</ul>
|
||||||
This module provides sending analog data (unsigned integer Values) to the PLC.<br />
|
|
||||||
Note: you have to configure a PLC writing at the physical modul (S7) first.<br />
|
|
||||||
<br />
|
|
||||||
<b>Define</b>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><code>define <name> S7_AWrite {inputs|outputs|flags|db} <DB> <start> {u8|s8|u16|s16|u32|s32|float}</code><br />
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>db … defines where to read. Note currently only writing in to DB are supported.</li>
|
|
||||||
<li>DB … Number of the DB</li>
|
|
||||||
<li>start … start byte of the reading</li>
|
|
||||||
<li>{u8|s8|u16|s16|u32|s32} … defines the datatype:
|
|
||||||
<ul>
|
|
||||||
<li>u8 …. unsigned 8 Bit integer</li>
|
|
||||||
<li>s8 …. signed 8 Bit integer</li>
|
|
||||||
<li>u16 …. unsigned 16 Bit integer</li>
|
|
||||||
<li>s16 …. signed 16 Bit integer</li>
|
|
||||||
<li>u32 …. unsigned 32 Bit integer</li>
|
|
||||||
<li>s32 …. signed 32 Bit integer</li>
|
|
||||||
<li>float …. 4 byte float</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
Note: the required memory area (start – start + datatypelength) need to be with in the configured PLC writing of the physical module.</li>
|
|
||||||
</ul>
|
|
||||||
<b>Set</b><br />
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><code>set <name> S7_AWrite <value></code>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>value … an numeric value</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
<ul>
|
||||||
=end html_DE
|
<ul>This module provides sending analog data (unsigned integer Values) to the PLC.</ul>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<ul>Note: you have to configure a PLC writing at the physical modul (S7) first.</ul>
|
||||||
|
</ul>
|
||||||
|
<p><br /><br /><strong>Define</strong><br /><code>define <name> S7_AWrite {inputs|outputs|flags|db} <DB> <start> {u8|s8|u16|s16|u32|s32|float}</code><br /><br /></p>
|
||||||
|
<ul>
|
||||||
|
<ul>
|
||||||
|
<ul>
|
||||||
|
<ul>
|
||||||
|
<li>db … defines where to read. Note currently only writing in to DB are supported.</li>
|
||||||
|
<li>DB … Number of the DB</li>
|
||||||
|
<li>start … start byte of the reading</li>
|
||||||
|
<li>{u8|s8|u16|s16|u32|s32} … defines the datatype:</li>
|
||||||
|
<ul>
|
||||||
|
<li>u8 …. unsigned 8 Bit integer</li>
|
||||||
|
<li>s8 …. signed 8 Bit integer</li>
|
||||||
|
<li>u16 …. unsigned 16 Bit integer</li>
|
||||||
|
<li>s16 …. signed 16 Bit integer</li>
|
||||||
|
<li>u32 …. unsigned 32 Bit integer</li>
|
||||||
|
<li>s32 …. signed 32 Bit integer</li>
|
||||||
|
<li>float …. 4 byte float</li>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
Note: the required memory area (start – start + datatypelength) need to be with in the configured PLC writing of the physical module.</ul>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
<p><strong>Set</strong><br /><br /><code>set <name> S7_AWrite <value></code></p>
|
||||||
|
<ul>
|
||||||
|
<ul>
|
||||||
|
<ul>
|
||||||
|
<li>value … an numeric value</li>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
</ul>=end html_DE
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -56,10 +56,11 @@ sub S7_DRead_Define($$) {
|
|||||||
|
|
||||||
if ( uc $a[2] =~ m/^Q(\d*)/ ) {
|
if ( uc $a[2] =~ m/^Q(\d*)/ ) {
|
||||||
$startposition = 1;
|
$startposition = 1;
|
||||||
if ( $hash->{IODev}{S7TYPE} eq "LOGO7" ) {
|
|
||||||
|
if ( defined($hash->{IODev}{S7TYPE}) && $hash->{IODev}{S7TYPE} eq "LOGO7" ) {
|
||||||
$Offset = 942;
|
$Offset = 942;
|
||||||
}
|
}
|
||||||
elsif ( $hash->{IODev}{S7TYPE} eq "LOGO8" ) {
|
elsif ( defined($hash->{IODev}{S7TYPE}) && $hash->{IODev}{S7TYPE} eq "LOGO8" ) {
|
||||||
$Offset = 1064;
|
$Offset = 1064;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -263,7 +264,7 @@ sub S7_DRead_Parse_new($$) {
|
|||||||
#aktualisierung des wertes
|
#aktualisierung des wertes
|
||||||
|
|
||||||
my $s = int( $h->{POSITION} / 8 ) - $start;
|
my $s = int( $h->{POSITION} / 8 ) - $start;
|
||||||
my $myI = $hash->{S7TCPClient}->ByteAt( \@Writebuffer, $s );
|
my $myI = $hash->{S7PLCClient}->ByteAt( \@Writebuffer, $s );
|
||||||
|
|
||||||
Log3 $name, 6, "$name S7_DRead_Parse update $n ";
|
Log3 $name, 6, "$name S7_DRead_Parse update $n ";
|
||||||
|
|
||||||
@ -346,7 +347,7 @@ sub S7_DRead_Parse($$) {
|
|||||||
#aktualisierung des wertes
|
#aktualisierung des wertes
|
||||||
my $s = int( $h->{POSITION} / 8 ) - $start;
|
my $s = int( $h->{POSITION} / 8 ) - $start;
|
||||||
|
|
||||||
my $myI = $hash->{S7TCPClient}->ByteAt( \@Writebuffer, $s );
|
my $myI = $hash->{S7PLCClient}->ByteAt( \@Writebuffer, $s );
|
||||||
|
|
||||||
Log3 $name, 6, "$name S7_DRead_Parse update $clientName ";
|
Log3 $name, 6, "$name S7_DRead_Parse update $clientName ";
|
||||||
|
|
||||||
@ -390,7 +391,7 @@ sub S7_DRead_Parse($$) {
|
|||||||
#my $b = pack( "C" x $length, @Writebuffer );
|
#my $b = pack( "C" x $length, @Writebuffer );
|
||||||
|
|
||||||
my $myI =
|
my $myI =
|
||||||
$hash->{S7TCPClient}->ByteAt( \@Writebuffer, $s );
|
$hash->{S7PLCClient}->ByteAt( \@Writebuffer, $s );
|
||||||
|
|
||||||
Log3 $name, 6, "$name S7_DRead_Parse update $n ";
|
Log3 $name, 6, "$name S7_DRead_Parse update $n ";
|
||||||
|
|
||||||
@ -452,30 +453,30 @@ sub S7_DRead_Attr(@) {
|
|||||||
1;
|
1;
|
||||||
|
|
||||||
=pod
|
=pod
|
||||||
|
=item summary logical device for a digital reading from a S7/S5
|
||||||
|
=item summary_DE logisches Device für einen binären Nur Lese Datenpunkt von einer S5 / S7
|
||||||
=begin html
|
=begin html
|
||||||
|
|
||||||
<a name="S7_DRead"></a>
|
<a name="S7_DRead"></a>
|
||||||
<h3>S7_DRead</h3>
|
<h3>S7_DRead</h3>
|
||||||
<ul>
|
<ul>
|
||||||
This module is a logical module of the physical module S7.<br />
|
This module is a logical module of the physical module S7. <br>
|
||||||
This module provides digital data (ON/OFF).<br />
|
This module provides digital data (ON/OFF).<br>
|
||||||
Note: you have to configure a PLC reading at the physical modul (S7) first.<br />
|
Note: you have to configure a PLC reading at the physical modul (S7) first.<br>
|
||||||
<br />
|
<br><br>
|
||||||
<br />
|
<b>Define</b>
|
||||||
<b>Define</b>
|
<ul>
|
||||||
|
<code>define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address></code>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address></code>
|
<li>inputs|outputs|flags|db … defines where to read.</li>
|
||||||
|
<li>DB … Number of the DB</li>
|
||||||
<ul>
|
<li>address … address you want to read. bit number to read. Example: 10.3</li>
|
||||||
<li>inputs|outputs|flags|db … defines where to read.</li>
|
</ul>
|
||||||
<li>DB … Number of the DB</li>
|
Note: the required memory area need to be with in the configured PLC reading of the physical module.
|
||||||
<li>address … address you want to read. bit number to read. Example: 10.3</li>
|
|
||||||
</ul>
|
|
||||||
Note: the required memory area need to be with in the configured PLC reading of the physical module.</li>
|
|
||||||
</ul>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
</ul>
|
||||||
=end html
|
=end html
|
||||||
|
|
||||||
=begin html_DE
|
=begin html_DE
|
||||||
@ -483,26 +484,23 @@ sub S7_DRead_Attr(@) {
|
|||||||
<a name="S7_DRead"></a>
|
<a name="S7_DRead"></a>
|
||||||
<h3>S7_DRead</h3>
|
<h3>S7_DRead</h3>
|
||||||
<ul>
|
<ul>
|
||||||
This module is a logical module of the physical module S7.<br />
|
|
||||||
This module provides digital data (ON/OFF).<br />
|
|
||||||
Note: you have to configure a PLC reading at the physical modul (S7) first.<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<b>Define</b>
|
|
||||||
|
|
||||||
<ul>
|
This module is a logical module of the physical module S7. <br>
|
||||||
<li><code>define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address></code>
|
This module provides digital data (ON/OFF).<br>
|
||||||
|
Note: you have to configure a PLC reading at the physical modul (S7) first.<br>
|
||||||
|
<br><br>
|
||||||
|
<b>Define</b>
|
||||||
|
<ul>
|
||||||
|
<code>define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address></code>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>inputs|outputs|flags|db … defines where to read.</li>
|
<li>inputs|outputs|flags|db … defines where to read.</li>
|
||||||
<li>DB … Number of the DB</li>
|
<li>DB … Number of the DB</li>
|
||||||
<li>address … address you want to read. bit number to read. Example: 10.3</li>
|
<li>address … address you want to read. bit number to read. Example: 10.3</li>
|
||||||
</ul>
|
</ul>
|
||||||
Note: the required memory area need to be with in the configured PLC reading of the physical module.</li>
|
Note: the required memory area need to be with in the configured PLC reading of the physical module.
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
=end html_DE
|
=end html_DE
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
|
@ -196,6 +196,7 @@ sub S7_DWrite_Define($$) {
|
|||||||
}
|
}
|
||||||
$position = ( $byte * 8 ) + $bit;
|
$position = ( $byte * 8 ) + $bit;
|
||||||
}
|
}
|
||||||
|
Log3 $name, 5, "S7_DWrite_Define called2";
|
||||||
|
|
||||||
$hash->{ADDRESS} = "$byte.$bit";
|
$hash->{ADDRESS} = "$byte.$bit";
|
||||||
|
|
||||||
@ -243,303 +244,347 @@ sub S7_DWrite_setABit($$) {
|
|||||||
return $writeAreaIndex if ( $writeAreaIndex ne int($writeAreaIndex) );
|
return $writeAreaIndex if ( $writeAreaIndex ne int($writeAreaIndex) );
|
||||||
|
|
||||||
my $b = 0;
|
my $b = 0;
|
||||||
|
my $res;
|
||||||
|
|
||||||
if ( $newValue eq "on" || $newValue eq "trigger" ) {
|
if ( $newValue eq "on" || $newValue eq "trigger" ) {
|
||||||
$b = 1;
|
$b = 1;
|
||||||
}
|
}
|
||||||
|
if ( $shash->{S7TYPE} eq "S5" ) {
|
||||||
|
|
||||||
my $res = S7_WriteBitToPLC( $shash, $writeAreaIndex, $dbNR, $position, $b );
|
#S5
|
||||||
|
#lesen wir das aktuelle byte
|
||||||
|
my $byte = int( $position / 8 );
|
||||||
|
my $bit = int( $position % 8 );
|
||||||
|
my $readbuffer;
|
||||||
|
( $res, $readbuffer ) =
|
||||||
|
S7_ReadBlockFromPLC( $shash, $writeAreaIndex, $dbNR, $byte, 1 );
|
||||||
|
|
||||||
if ( $res == 0 ) {
|
if ( $res == 0 && length($readbuffer) == 1 ) { #reading was OK
|
||||||
main::readingsSingleUpdate( $hash, "state", $newValue, 1 );
|
#setzen/löschen wir das gewünsche bit
|
||||||
}
|
|
||||||
else {
|
|
||||||
main::readingsSingleUpdate( $hash, "state", "", 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $newValue eq "trigger" ) {
|
my $tbuffer = join( ", ", unpack( "H2 " x length($readbuffer), $readbuffer ) );
|
||||||
|
Log3( undef, 5, "S5 Read old Value <-- " . $tbuffer ." now changing bitNr: ".$bit );
|
||||||
|
|
||||||
my $triggerLength = 1;
|
|
||||||
if ( defined( $main::attr{$name}{trigger_length} ) ) {
|
|
||||||
$triggerLength = $main::attr{$name}{trigger_length};
|
|
||||||
}
|
|
||||||
|
|
||||||
InternalTimer( gettimeofday() + $triggerLength,
|
my @cbuffer = unpack( "C" x length($readbuffer), $readbuffer);
|
||||||
"S7_DWrite_SwitchOff", $hash, 1 );
|
if ($b == 1) {
|
||||||
}
|
$cbuffer[0] |= (1 << $bit);
|
||||||
|
} else {
|
||||||
return undef;
|
$cbuffer[0] &= (~(1 << $bit)) & 0xFF;
|
||||||
|
}
|
||||||
}
|
|
||||||
|
$readbuffer = pack( "C" x 1, @cbuffer);
|
||||||
#####################################
|
|
||||||
|
|
||||||
sub S7_DWrite_Set(@) {
|
#schreiben wir das byte
|
||||||
my ( $hash, @a ) = @_;
|
$tbuffer = join( ", ", unpack( "H2 " x length($readbuffer), $readbuffer ) );
|
||||||
|
Log3( undef, 5, "S5 Write new Value <-- " . $tbuffer );
|
||||||
return "Need at least one parameter" if ( int(@a) < 2 );
|
$res = S7_WriteToPLC( $shash, $writeAreaIndex, $dbNR, $byte, &S7Client::S7WLByte , $readbuffer );
|
||||||
return S7_DWrite_setABit( $hash, $a[1] );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#####################################
|
if ( $res != 0 ) {
|
||||||
|
my $error = $shash->{S7PLCClient}->getErrorStr($res);
|
||||||
sub S7_DWrite_SwitchOff($) {
|
my $msg =
|
||||||
my ($hash) = @_;
|
"$name S7_DWrite_setABit -S5- S7_WriteToPLC error: $res=$error";
|
||||||
my $name = $hash->{NAME};
|
Log3( $name, 3, $msg );
|
||||||
Log3 $name, 4, "S7_DWrite: GetUpdate called ...";
|
}
|
||||||
|
|
||||||
return S7_DWrite_setABit( $hash, "off" );
|
|
||||||
|
} else {
|
||||||
}
|
|
||||||
|
my $error = $shash->{S7PLCClient}->getErrorStr($res);
|
||||||
#####################################
|
my $msg =
|
||||||
|
"$name S7_DWrite_setABit -S5- ReadArea error: $res=$error";
|
||||||
sub S7_DWrite_Parse($$) {
|
Log3( $name, 3, $msg );
|
||||||
my ( $hash, $rmsg ) = @_;
|
|
||||||
my $name;
|
S7_reconnect($shash); #lets try a reconnect
|
||||||
|
return ( -2, $msg );
|
||||||
if ( defined( $hash->{NAME} ) ) {
|
|
||||||
$name = $hash->{NAME};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$name = "dummy";
|
|
||||||
Log3 undef, 2, "S7_DWrite_Parse: Error ...";
|
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
my @a = split( "[ \t][ \t]*", $rmsg );
|
|
||||||
my @list;
|
|
||||||
|
|
||||||
my ( $area, $DB, $start, $length, $datatype, $s7name, $hexbuffer,
|
|
||||||
$clientNames );
|
|
||||||
|
|
||||||
$area = lc $a[1];
|
|
||||||
$DB = $a[2];
|
|
||||||
$start = $a[3];
|
|
||||||
$length = $a[4];
|
|
||||||
$s7name = $a[5];
|
|
||||||
$hexbuffer = $a[6];
|
|
||||||
$clientNames = $a[7];
|
|
||||||
|
|
||||||
my $ID = "$area $DB";
|
|
||||||
|
|
||||||
Log3 $name, 6, "$name S7_DWrite_Parse $rmsg";
|
|
||||||
my @clientList = split( ",", $clientNames );
|
|
||||||
|
|
||||||
if ( int(@clientList) > 0 ) {
|
|
||||||
my @Writebuffer = unpack( "C" x $length,
|
|
||||||
pack( "H2" x $length, split( ",", $hexbuffer ) ) );
|
|
||||||
# my $b = pack( "C" x $length, @Writebuffer );
|
|
||||||
foreach my $clientName (@clientList) {
|
|
||||||
|
|
||||||
my $h = $defs{$clientName};
|
|
||||||
|
|
||||||
# if ( defined( $main::attr{ $h->{NAME} }{IODev} )
|
|
||||||
# && $main::attr{ $h->{NAME} }{IODev} eq $name )
|
|
||||||
# {
|
|
||||||
|
|
||||||
if ( $h->{TYPE} eq "S7_DWrite"
|
|
||||||
&& $start <= int( $h->{POSITION} / 8 )
|
|
||||||
&& $start + $length >= int( $h->{POSITION} / 8 ) )
|
|
||||||
{
|
|
||||||
push( @list, $clientName )
|
|
||||||
; #damit die werte im client gesetzt werden!
|
|
||||||
|
|
||||||
#aktualisierung des wertes
|
|
||||||
my $s = int( $h->{POSITION} / 8 ) - $start;
|
|
||||||
|
|
||||||
my $myI = $hash->{S7TCPClient}->ByteAt( \@Writebuffer, $s );
|
|
||||||
|
|
||||||
Log3 $name, 5, "$name S7_DWrite_Parse update $clientName ";
|
|
||||||
|
|
||||||
if ( ( int($myI) & ( 1 << ( $h->{POSITION} % 8 ) ) ) > 0 ) {
|
|
||||||
|
|
||||||
main::readingsSingleUpdate( $h, "state", "on", 1 );
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
main::readingsSingleUpdate( $h, "state", "off", 1 );
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# }
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
#S7
|
||||||
|
$res =
|
||||||
|
S7_WriteBitToPLC( $shash, $writeAreaIndex, $dbNR, $position, $b );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $res == 0 ) {
|
||||||
|
main::readingsSingleUpdate( $hash, "state", $newValue, 1 );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
main::readingsSingleUpdate( $hash, "state", "", 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $newValue eq "trigger" ) {
|
||||||
|
|
||||||
|
my $triggerLength = 1;
|
||||||
|
if ( defined( $main::attr{$name}{trigger_length} ) ) {
|
||||||
|
$triggerLength = $main::attr{$name}{trigger_length};
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalTimer( gettimeofday() + $triggerLength,
|
||||||
|
"S7_DWrite_SwitchOff", $hash, 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
Log3 $name, 3, "$name S7_DWrite_Parse going the save way ";
|
|
||||||
|
|
||||||
if ( defined( $modules{S7_DWrite}{defptr}{$ID} ) ) {
|
#####################################
|
||||||
|
|
||||||
foreach my $h ( @{ $modules{S7_DWrite}{defptr}{$ID} } ) {
|
sub S7_DWrite_Set(@) {
|
||||||
if ( defined( $main::attr{ $h->{NAME} }{IODev} )
|
my ( $hash, @a ) = @_;
|
||||||
&& $main::attr{ $h->{NAME} }{IODev} eq $name )
|
|
||||||
|
return "Need at least one parameter" if ( int(@a) < 2 );
|
||||||
|
return S7_DWrite_setABit( $hash, $a[1] );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
|
||||||
|
sub S7_DWrite_SwitchOff($) {
|
||||||
|
my ($hash) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
Log3 $name, 4, "S7_DWrite: GetUpdate called ...";
|
||||||
|
|
||||||
|
return S7_DWrite_setABit( $hash, "off" );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
|
||||||
|
sub S7_DWrite_Parse($$) {
|
||||||
|
my ( $hash, $rmsg ) = @_;
|
||||||
|
my $name;
|
||||||
|
|
||||||
|
if ( defined( $hash->{NAME} ) ) {
|
||||||
|
$name = $hash->{NAME};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$name = "dummy";
|
||||||
|
Log3 undef, 2, "S7_DWrite_Parse: Error ...";
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
my @a = split( "[ \t][ \t]*", $rmsg );
|
||||||
|
my @list;
|
||||||
|
|
||||||
|
my ( $area, $DB, $start, $length, $datatype, $s7name, $hexbuffer,
|
||||||
|
$clientNames );
|
||||||
|
|
||||||
|
$area = lc $a[1];
|
||||||
|
$DB = $a[2];
|
||||||
|
$start = $a[3];
|
||||||
|
$length = $a[4];
|
||||||
|
$s7name = $a[5];
|
||||||
|
$hexbuffer = $a[6];
|
||||||
|
$clientNames = $a[7];
|
||||||
|
|
||||||
|
my $ID = "$area $DB";
|
||||||
|
|
||||||
|
Log3 $name, 6, "$name S7_DWrite_Parse $rmsg";
|
||||||
|
my @clientList = split( ",", $clientNames );
|
||||||
|
|
||||||
|
if ( int(@clientList) > 0 ) {
|
||||||
|
my @Writebuffer = unpack( "C" x $length,
|
||||||
|
pack( "H2" x $length, split( ",", $hexbuffer ) ) );
|
||||||
|
foreach my $clientName (@clientList) {
|
||||||
|
|
||||||
|
my $h = $defs{$clientName};
|
||||||
|
|
||||||
|
if ( $h->{TYPE} eq "S7_DWrite"
|
||||||
|
&& $start <= int( $h->{POSITION} / 8 )
|
||||||
|
&& $start + $length >= int( $h->{POSITION} / 8 ) )
|
||||||
{
|
{
|
||||||
if ( $start <= int( $h->{POSITION} / 8 )
|
push( @list, $clientName )
|
||||||
&& $start + $length >= int( $h->{POSITION} / 8 ) )
|
; #damit die werte im client gesetzt werden!
|
||||||
{
|
|
||||||
|
|
||||||
my $n =
|
#aktualisierung des wertes
|
||||||
$h->{NAME}; #damit die werte im client gesetzt werden!
|
my $s = int( $h->{POSITION} / 8 ) - $start;
|
||||||
push( @list, $n );
|
|
||||||
|
|
||||||
#aktualisierung des wertes
|
my $myI = $hash->{S7PLCClient}->ByteAt( \@Writebuffer, $s );
|
||||||
my @Writebuffer = unpack( "C" x $length,
|
|
||||||
pack( "H2" x $length, split( ",", $hexbuffer ) ) );
|
|
||||||
my $s = int( $h->{POSITION} / 8 ) - $start;
|
|
||||||
# my $b = pack( "C" x $length, @Writebuffer );
|
|
||||||
|
|
||||||
my $myI = $hash->{S7TCPClient}->ByteAt(\@Writebuffer, $s );
|
Log3 $name, 5, "$name S7_DWrite_Parse update $clientName ";
|
||||||
|
|
||||||
Log3 $name, 6, "$name S7_DWrite_Parse update $n ";
|
if ( ( int($myI) & ( 1 << ( $h->{POSITION} % 8 ) ) ) > 0 ) {
|
||||||
|
|
||||||
if ( ( int($myI) & ( 1 << ( $h->{POSITION} % 8 ) ) ) >
|
main::readingsSingleUpdate( $h, "state", "on", 1 );
|
||||||
0 )
|
|
||||||
{
|
|
||||||
|
|
||||||
main::readingsSingleUpdate( $h, "state", "on", 1 );
|
}
|
||||||
|
else {
|
||||||
|
main::readingsSingleUpdate( $h, "state", "off", 1 );
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
main::readingsSingleUpdate( $h, "state", "off", 1 );
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
Log3 $name, 3, "$name S7_DWrite_Parse going the save way ";
|
||||||
|
|
||||||
|
if ( defined( $modules{S7_DWrite}{defptr}{$ID} ) ) {
|
||||||
|
|
||||||
|
foreach my $h ( @{ $modules{S7_DWrite}{defptr}{$ID} } ) {
|
||||||
|
if ( defined( $main::attr{ $h->{NAME} }{IODev} )
|
||||||
|
&& $main::attr{ $h->{NAME} }{IODev} eq $name )
|
||||||
|
{
|
||||||
|
if ( $start <= int( $h->{POSITION} / 8 )
|
||||||
|
&& $start + $length >= int( $h->{POSITION} / 8 ) )
|
||||||
|
{
|
||||||
|
|
||||||
|
my $n = $h
|
||||||
|
->{NAME}; #damit die werte im client gesetzt werden!
|
||||||
|
push( @list, $n );
|
||||||
|
|
||||||
|
#aktualisierung des wertes
|
||||||
|
my @Writebuffer = unpack(
|
||||||
|
"C" x $length,
|
||||||
|
pack(
|
||||||
|
"H2" x $length, split( ",", $hexbuffer )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
my $s = int( $h->{POSITION} / 8 ) - $start;
|
||||||
|
|
||||||
|
# my $b = pack( "C" x $length, @Writebuffer );
|
||||||
|
|
||||||
|
my $myI =
|
||||||
|
$hash->{S7PLCClient}->ByteAt( \@Writebuffer, $s );
|
||||||
|
|
||||||
|
Log3 $name, 6, "$name S7_DWrite_Parse update $n ";
|
||||||
|
|
||||||
|
if ( ( int($myI) & ( 1 << ( $h->{POSITION} % 8 ) ) )
|
||||||
|
> 0 )
|
||||||
|
{
|
||||||
|
|
||||||
|
main::readingsSingleUpdate( $h, "state", "on",
|
||||||
|
1 );
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
main::readingsSingleUpdate( $h, "state", "off",
|
||||||
|
1 );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( int(@list) == 0 ) {
|
||||||
|
Log3 $name, 6, "S7_DWrite: Parse no client found ($name) ...";
|
||||||
|
push( @list, "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return @list;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( int(@list) == 0 ) {
|
|
||||||
Log3 $name, 6, "S7_DWrite: Parse no client found ($name) ...";
|
|
||||||
push( @list, "" );
|
|
||||||
}
|
|
||||||
|
|
||||||
return @list;
|
|
||||||
|
|
||||||
}
|
|
||||||
#####################################
|
#####################################
|
||||||
|
|
||||||
sub S7_DWrite_Attr(@) {
|
sub S7_DWrite_Attr(@) {
|
||||||
my ( $cmd, $name, $aName, $aVal ) = @_;
|
my ( $cmd, $name, $aName, $aVal ) = @_;
|
||||||
|
|
||||||
# $cmd can be "del" or "set"
|
# $cmd can be "del" or "set"
|
||||||
# $name is device name
|
# $name is device name
|
||||||
# aName and aVal are Attribute name and value
|
# aName and aVal are Attribute name and value
|
||||||
my $hash = $defs{$name};
|
my $hash = $defs{$name};
|
||||||
if ( $cmd eq "set" ) {
|
if ( $cmd eq "set" ) {
|
||||||
if ( $aName eq "trigger_length" ) {
|
if ( $aName eq "trigger_length" ) {
|
||||||
if ( $aVal ne int($aVal) ) {
|
if ( $aVal ne int($aVal) ) {
|
||||||
Log3 $name, 3,
|
Log3 $name, 3,
|
||||||
"S7_DWrite: Invalid $aName in attr $name $aName ($aVal is not a number): $@";
|
"S7_DWrite: Invalid $aName in attr $name $aName ($aVal is not a number): $@";
|
||||||
return "Invalid $aName : $aVal is not a number";
|
return "Invalid $aName : $aVal is not a number";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
elsif ( $aName eq "IODev" ) {
|
||||||
|
Log3 $name, 4, "S7_DWrite: IODev for $name is $aVal";
|
||||||
|
$hash->{IODev}{dirty} = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
elsif ( $aName eq "IODev" ) {
|
return undef;
|
||||||
Log3 $name, 4, "S7_DWrite: IODev for $name is $aVal";
|
|
||||||
$hash->{IODev}{dirty} = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
=pod
|
=pod
|
||||||
|
=item summary logical device for a digital writing to a S7/S5
|
||||||
|
=item summary_DE logisches Device für einen binären Lese/Schreib Datenpunkt zu einer S5 / S7
|
||||||
=begin html
|
=begin html
|
||||||
|
|
||||||
<a name="S7_DWrite"></a>
|
<p><a name="S7_DWrite"></a></p>
|
||||||
<h3>S7_DWrite</h3>
|
<h3>S7_DWrite</h3>
|
||||||
<ul>
|
<ul>
|
||||||
This module is a logical module of the physical module S7.<br />
|
<ul>This module is a logical module of the physical module S7.</ul>
|
||||||
This module is used to set/unset a Bit in ad DB of the PLC.<br />
|
</ul>
|
||||||
Note: you have to configure a PLC writing at the physical modul (S7) first.<br />
|
<ul>
|
||||||
<br />
|
<ul>This module is used to set/unset a Bit in ad DB of the PLC.</ul>
|
||||||
<b>Define</b>
|
</ul>
|
||||||
|
<ul>
|
||||||
<ul>
|
<ul>Note: you have to configure a PLC writing at the physical modul (S7) first.</ul>
|
||||||
<li><code>define <name> S7_DWrite {db} <DB> <address></code>
|
</ul>
|
||||||
|
<p><br /><br /><br /><strong>Define</strong><code>define <name> S7_DWrite {db} <DB> <address></code></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>db … defines where to read. Note currently only writing in to DB are supported.</li>
|
<ul>
|
||||||
<li>DB … Number of the DB</li>
|
<ul>
|
||||||
<li>address … address you want to write. bit number to read. Example: 10.6</li>
|
<ul>
|
||||||
</ul>
|
<li>db … defines where to read. Note currently only writing in to DB are supported.</li>
|
||||||
Note: the required memory area need to be with in the configured PLC reading of the physical module. <b>Set</b>
|
<li>DB … Number of the DB</li>
|
||||||
|
<li>address … address you want to write. bit number to read. Example: 10.6</li>
|
||||||
<ul>
|
</ul>
|
||||||
<li><code>set <name> S7_AWrite {ON|OFF|TRIGGER};</code></li>
|
Note: the required memory area need to be with in the configured PLC reading of the physical module.</ul>
|
||||||
<br />
|
</ul>
|
||||||
|
</ul>
|
||||||
<li> </li>
|
<p><strong>Set</strong><code>set <name> S7_AWrite {ON|OFF|TRIGGER};</code></p>
|
||||||
<li> </li>
|
<ul>
|
||||||
</ul>
|
<ul>Note: TRIGGER sets the bit for 1s to ON than it will set to OFF.</ul>
|
||||||
Note: TRIGGER sets the bit for 1s to ON than it will set to OFF.</li>
|
</ul>
|
||||||
</ul>
|
<p><strong>Attr</strong><br /> The following parameters are used to scale every reading</p>
|
||||||
|
<ul>
|
||||||
<p><b>Attr</b><br />
|
<li>trigger_length ... sets the on-time of a trigger</li>
|
||||||
The following parameters are used to scale every reading</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<ul>
|
|
||||||
<li>trigger_length ... sets the on-time of a trigger</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
=end html
|
=end html
|
||||||
|
|
||||||
=begin html_DE
|
=begin html_DE
|
||||||
|
|
||||||
<a name="S7_DWrite"></a>
|
<p><a name="S7_DWrite"></a></p>
|
||||||
<h3>S7_DWrite</h3>
|
<h3>S7_DWrite</h3>
|
||||||
<ul>
|
<ul>
|
||||||
This module is a logical module of the physical module S7.<br />
|
<ul>This module is a logical module of the physical module S7.</ul>
|
||||||
This module is used to set/unset a Bit in ad DB of the PLC.<br />
|
</ul>
|
||||||
Note: you have to configure a PLC writing at the physical modul (S7) first.<br />
|
<ul>
|
||||||
<br />
|
<ul>This module is used to set/unset a Bit in ad DB of the PLC.</ul>
|
||||||
<br />
|
</ul>
|
||||||
<b>Define</b>
|
<ul>
|
||||||
|
<ul>Note: you have to configure a PLC writing at the physical modul (S7) first.</ul>
|
||||||
<ul>
|
</ul>
|
||||||
<li><code>define <name> S7_DWrite {db} <DB> <position></code>
|
<p><br /><br /><br /><strong>Define</strong><code>define <name> S7_DWrite {db} <DB> <position></code></p>
|
||||||
|
<ul>
|
||||||
<ul>
|
<ul>
|
||||||
<li>db … defines where to read. Note currently only writing in to DB are supported.</li>
|
<ul>
|
||||||
<li>DB … Number of the DB</li>
|
<ul>
|
||||||
<li>address … address you want to write. bit number to read. Example: 10.6</li>
|
<li>db … defines where to read. Note currently only writing in to DB are supported.</li>
|
||||||
</ul>
|
<li>DB … Number of the DB</li>
|
||||||
Note: the required memory area need to be with in the configured PLC reading of the physical module.</li>
|
<li>address … address you want to write. bit number to read. Example: 10.6</li>
|
||||||
<br />
|
</ul>
|
||||||
<br />
|
Note: the required memory area need to be with in the configured PLC reading of the physical module.</ul>
|
||||||
<br />
|
</ul>
|
||||||
|
</ul>
|
||||||
<li> </li>
|
<p><br /><strong>Set</strong><code>set <name> S7_AWrite {ON|OFF|TRIGGER};</code></p>
|
||||||
</ul>
|
<ul>
|
||||||
<b>Set</b>
|
<ul>Note: TRIGGER sets the bit for 1s to ON than it will set to OFF.</ul>
|
||||||
|
</ul>
|
||||||
<ul>
|
<p><strong>Attr</strong><br /> The following parameters are used to scale every reading</p>
|
||||||
<li><code>set <name> S7_AWrite {ON|OFF|TRIGGER};</code><br />
|
<ul>
|
||||||
Note: TRIGGER sets the bit for 1s to ON than it will set to OFF.</li>
|
<li>trigger_length ... sets the on-time of a trigger</li>
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p><b>Attr</b><br />
|
|
||||||
The following parameters are used to scale every reading</p>
|
|
||||||
|
|
||||||
<p> </p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>trigger_length ... sets the on-time of a trigger</li>
|
|
||||||
</ul>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
=end html_DE
|
=end html_DE
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
840
fhem/FHEM/44_S7_S5Client.pm
Normal file
840
fhem/FHEM/44_S7_S5Client.pm
Normal file
@ -0,0 +1,840 @@
|
|||||||
|
# $Id$
|
||||||
|
##############################################
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
require Exporter;
|
||||||
|
use Config;
|
||||||
|
use AutoLoader;
|
||||||
|
|
||||||
|
require "44_S7_Client.pm";
|
||||||
|
|
||||||
|
#if ( OS_Linux() ) {
|
||||||
|
use Device::SerialPort;
|
||||||
|
|
||||||
|
#}
|
||||||
|
#else {
|
||||||
|
# use Win32::SerialPort;
|
||||||
|
#}
|
||||||
|
|
||||||
|
package S5Client;
|
||||||
|
|
||||||
|
#use S7ClientBase;
|
||||||
|
our @ISA = qw(S7ClientBase); # inherits from Person
|
||||||
|
|
||||||
|
#---------------------- constants for communication
|
||||||
|
|
||||||
|
use constant DLE => 0x10;
|
||||||
|
use constant ETX => 0x03;
|
||||||
|
use constant STX => 0x02;
|
||||||
|
use constant SYN => 0x16;
|
||||||
|
use constant NAK => 0x15;
|
||||||
|
use constant EOT => 0x04; # for S5
|
||||||
|
use constant ACK => 0x06; # for S5
|
||||||
|
|
||||||
|
use constant daveS5BlockType_DB => 0x01;
|
||||||
|
use constant maxSysinfoLen => 87;
|
||||||
|
use constant daveMaxRawLen => 2048;
|
||||||
|
|
||||||
|
use constant MaxPduSize =>
|
||||||
|
240;
|
||||||
|
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my $class = shift;
|
||||||
|
|
||||||
|
my $self = $class->SUPER::new();
|
||||||
|
|
||||||
|
$self->{S5PAEAddress} = 0;
|
||||||
|
$self->{S5PAAAddress} = 0;
|
||||||
|
$self->{S5flagsAddress} = 0;
|
||||||
|
$self->{S5timerAddress} = 0;
|
||||||
|
$self->{S5counterAddress} = 0;
|
||||||
|
|
||||||
|
$self->{__davet1006} = [ &DLE, &ACK ];
|
||||||
|
$self->{__daveT161003} = [ 0x16, &DLE, &ETX ];
|
||||||
|
$self->{__davet121003} = [ 0x12, &DLE, &ETX ];
|
||||||
|
|
||||||
|
$self->{PDULength} = &MaxPduSize;
|
||||||
|
|
||||||
|
|
||||||
|
#my @__davet1006 = ( &DLE, &ACK );
|
||||||
|
#my @__daveT161003 = ( 0x16, &DLE, &ETX );
|
||||||
|
#my @{$self->{__davet121003}} = ( 0x12, &DLE, &ETX );
|
||||||
|
|
||||||
|
return bless $self, $class;
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------- compare arrays
|
||||||
|
|
||||||
|
sub compare {
|
||||||
|
my ( $self, $a_ref, $b_ref ) = @_;
|
||||||
|
my @a = @{$a_ref}; # dereferencing and copying each array
|
||||||
|
my @b = @{$b_ref};
|
||||||
|
|
||||||
|
if ( @a != @b ) {
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
foreach ( my $i = 0 ; $i < @a ; $i++ ) {
|
||||||
|
|
||||||
|
# Ideally, check for undef/value comparison here as well
|
||||||
|
if ( $a[$i] != $b[$i] )
|
||||||
|
{ # use "ne" if elements are strings, not numbers
|
||||||
|
# Or you can use generic sub comparing 2 values
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# ----------- This writes a single chracter to the serial interface
|
||||||
|
#
|
||||||
|
|
||||||
|
sub S5SendSingle($$) {
|
||||||
|
my ( $self, $c ) = @_;
|
||||||
|
my $buffer = pack( 'C*', $c );
|
||||||
|
|
||||||
|
my $tbuffer = join( ", ", unpack( "H2 " x length($buffer), $buffer ) );
|
||||||
|
main::Log3( undef, 5, "S5Client S5SendSingle <-- " . $tbuffer );
|
||||||
|
|
||||||
|
$self->{serial}->write($buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#---------------------------------------------------reqest transaction with PLC
|
||||||
|
|
||||||
|
sub S5ReqTrans($$) {
|
||||||
|
my ( $self, $trN ) = @_;
|
||||||
|
my $buffer;
|
||||||
|
my $count;
|
||||||
|
my $tbuffer;
|
||||||
|
|
||||||
|
$self->S5SendSingle(&STX); #start trasmission
|
||||||
|
#expected S5 awnswer DLE,ACK
|
||||||
|
|
||||||
|
( $count, $buffer ) = $self->{serial}->read(2);
|
||||||
|
my @cbuffer = unpack( "C" x $count, $buffer );
|
||||||
|
|
||||||
|
if ( $main::attr{global}{verbose} >= 5 ) {
|
||||||
|
$tbuffer = join( ", ", unpack( "H2 " x $count, $buffer ) );
|
||||||
|
main::Log3( undef, 5, "S5Client S5ReqTrans $tbuffer -->" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $self->compare( \@cbuffer, \@{ $self->{__davet1006} } ) == 0 ) {
|
||||||
|
main::Log3( undef, 3, "S5Client S5ReqTrans: no DLE,ACK before send" );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
$self->S5SendSingle($trN);
|
||||||
|
( $count, $buffer ) = $self->{serial}->read(1);
|
||||||
|
|
||||||
|
if ( $main::attr{global}{verbose} >= 5 ) {
|
||||||
|
$tbuffer = join( ", ", unpack( "H2 " x $count, $buffer ) );
|
||||||
|
main::Log3( undef, 5, "S5Client S5ReqTrans $tbuffer -->" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $count != 1 ) {
|
||||||
|
|
||||||
|
#error awnser is too short
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
@cbuffer = unpack( "C" x $count, $buffer );
|
||||||
|
|
||||||
|
if ( $cbuffer[0] ne &STX ) {
|
||||||
|
main::Log3( undef, 3, "S5Client S5ReqTrans: no STX before send" );
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->S5SendDLEACK();
|
||||||
|
( $count, $buffer ) = $self->{serial}->read(3);
|
||||||
|
|
||||||
|
if ( $main::attr{global}{verbose} >= 5 ) {
|
||||||
|
$tbuffer = join( ", ", unpack( "H2 " x $count, $buffer ) );
|
||||||
|
main::Log3( undef, 5, "S5Client S5ReqTrans $tbuffer -->" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@cbuffer = unpack( "C" x $count, $buffer );
|
||||||
|
if ( $self->compare( \@cbuffer, \@{ $self->{__daveT161003} } ) == 0 ) {
|
||||||
|
main::Log3( undef, 3, "S5Client S5ReqTrans: no accept0 from plc" );
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->S5SendDLEACK();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub S5SendDLEACK($) {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
my $buffer = pack( 'C2', @{ $self->{__davet1006} } );
|
||||||
|
|
||||||
|
if ( $main::attr{global}{verbose} >= 5 ) {
|
||||||
|
my $tbuffer = join( ", ", unpack( "H2 " x 2, $buffer ) );
|
||||||
|
main::Log3( undef, 5, "S5Client S5SendDLEACK <-- $tbuffer" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $self->{serial}->write($buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#---------------------------------------------- S5 Exchange data
|
||||||
|
|
||||||
|
sub S5ExchangeAS511($$$$$) {
|
||||||
|
my ( $self, $b, $len, $maxlen, $trN ) = @_;
|
||||||
|
|
||||||
|
my ( $res, $i, $b1, $count );
|
||||||
|
my @cbuffer;
|
||||||
|
my $msgIn = "";
|
||||||
|
my $tbuffer;
|
||||||
|
|
||||||
|
$res = $self->S5ReqTrans($trN);
|
||||||
|
if ( $res < 0 ) {
|
||||||
|
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ExchangeAS511: Error in Exchange.ReqTrans request" );
|
||||||
|
return ( $res - 10, "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $trN == 8 ) { #Block write functions have advanced syntax
|
||||||
|
#LOG1("trN 8\n");
|
||||||
|
$self->S5SendWithDLEDup( $b, 4 );
|
||||||
|
|
||||||
|
#LOG1("trN 8 done\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
#LOG3("trN %d len %d\n",trN,len);
|
||||||
|
$self->S5SendWithDLEDup( $b, $len );
|
||||||
|
|
||||||
|
#LOG2("trN %d done\n",trN);
|
||||||
|
}
|
||||||
|
|
||||||
|
( $count, $b1 ) = $self->{serial}->read(2);
|
||||||
|
|
||||||
|
# if ( $main::attr{global}{verbose} >= 5 ) {
|
||||||
|
$tbuffer = join( ", ", unpack( "H2 " x $count, $b1 ) );
|
||||||
|
main::Log3( undef, 5, "S5Client S5ExchangeAS511 $tbuffer -->" );
|
||||||
|
# }
|
||||||
|
|
||||||
|
@cbuffer = unpack( "C" x $count, $b1 );
|
||||||
|
if ( $self->compare( \@cbuffer, \@{ $self->{__davet1006} } ) == 0 ) {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ExchangeAS511: no DLE,ACK in Exchange request" );
|
||||||
|
return ( -1, "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ( $trN != 3 ) && ( $trN != 7 ) && ( $trN != 9 ) ) {
|
||||||
|
|
||||||
|
#write bytes, compress & delblk
|
||||||
|
if ( !$self->S5ReadSingle() eq &STX ) {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ExchangeAS511: no STX in Exchange request" );
|
||||||
|
return ( -2, "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->S5SendDLEACK();
|
||||||
|
$res = 0;
|
||||||
|
@cbuffer = ();
|
||||||
|
my $buffer = "";
|
||||||
|
do {
|
||||||
|
|
||||||
|
( $i, $b1 ) = $self->{serial}->read(1);
|
||||||
|
|
||||||
|
$res += $i;
|
||||||
|
push( @cbuffer, unpack( "C" x $i, $b1 ) ) if ( $i > 0 );
|
||||||
|
|
||||||
|
} while (
|
||||||
|
( $i > 0 )
|
||||||
|
&& ( ( $cbuffer[ $res - 2 ] != &DLE )
|
||||||
|
|| ( $cbuffer[ $res - 1 ] != &ETX ) )
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( $main::attr{global}{verbose} >= 5 ) {
|
||||||
|
$tbuffer =
|
||||||
|
join( ", ", unpack( "H2 " x @cbuffer, pack( "C*", @cbuffer ) ) );
|
||||||
|
main::Log3( undef, 5, "S5Client S5ExchangeAS511 $tbuffer -->" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#LOG3( "%s *** got %d bytes.\n", dc->iface->name, res );
|
||||||
|
|
||||||
|
if ( $res < 0 ) {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ExchangeAS511: Error in Exchange.ReadChars request"
|
||||||
|
);
|
||||||
|
|
||||||
|
return ( $res - 20, "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ( $cbuffer[ $res - 2 ] != &DLE )
|
||||||
|
|| ( $cbuffer[ $res - 1 ] != &ETX ) )
|
||||||
|
{
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ExchangeAS511: No DLE,ETX in Exchange data." );
|
||||||
|
return ( -4, "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
( $res, $msgIn ) = $self->S5DLEDeDup( \@cbuffer );
|
||||||
|
if ( $res < 0 ) {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ExchangeAS511: Error in Exchange rawdata." );
|
||||||
|
return ( -3, "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->S5SendDLEACK();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $trN == 8 ) { # Write requests have more differences from others
|
||||||
|
@cbuffer = unpack( "C" x length($msgIn), $msgIn );
|
||||||
|
|
||||||
|
if ( $cbuffer[0] != 9 ) { #todo fix
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ExchangeAS511 No 0x09 in special Exchange request."
|
||||||
|
);
|
||||||
|
return ( -5, "" );
|
||||||
|
}
|
||||||
|
$self->S5SendSingle(&STX);
|
||||||
|
|
||||||
|
( $count, $b1 ) = $self->{serial}->read(2);
|
||||||
|
|
||||||
|
if ( $main::attr{global}{verbose} >= 5 ) {
|
||||||
|
$tbuffer = $tbuffer = join( ", ", unpack( "H2 " x $count, $b1 ) );
|
||||||
|
main::Log3( undef, 5, "S5Client S5ExchangeAS511 $tbuffer -->" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@cbuffer = unpack( "C" x $count, $b1 );
|
||||||
|
if ( $self->compare( \@cbuffer, \@{ $self->{__davet1006} } ) == 0 ) {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ExchangeAS511 no DLE,ACK in special Exchange request"
|
||||||
|
);
|
||||||
|
return ( -6, "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
my $b2 = substr( $b, 4 );
|
||||||
|
$self->S5SendWithDLEDup( $b2, $len ); # todo need testing !!!
|
||||||
|
#$self->S5SendWithDLEDup(dc->iface,b+4,len); #
|
||||||
|
|
||||||
|
( $count, $b1 ) = $self->{serial}->read(2);
|
||||||
|
|
||||||
|
if ( $main::attr{global}{verbose} >= 5 ) {
|
||||||
|
$tbuffer = join( ", ", unpack( "H2 " x $count, $b1 ) );
|
||||||
|
main::Log3( undef, 5, "S5Client S5ExchangeAS511 $tbuffer -->" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@cbuffer = unpack( "C" x $count, $b1 );
|
||||||
|
if ( $self->compare( \@cbuffer, \@{ $self->{__davet1006} } ) == 0 ) {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ExchangeAS511 no DLE,ACK after transfer in Exchange."
|
||||||
|
);
|
||||||
|
return ( -7, "" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $trN == 7 ) {
|
||||||
|
}
|
||||||
|
$res = $self->S5EndTrans();
|
||||||
|
if ( $res < 0 ) {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ExchangeAS511 Error in Exchange.EndTrans request." );
|
||||||
|
return ( $res - 30, "" );
|
||||||
|
}
|
||||||
|
return ( 0, $msgIn );
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Sends a sequence of characters after doubling DLEs and adding DLE,EOT.
|
||||||
|
#
|
||||||
|
sub S5SendWithDLEDup($$$) {
|
||||||
|
my ( $self, $b, $size ) = @_;
|
||||||
|
|
||||||
|
# uc target[&daveMaxRawLen];
|
||||||
|
my @target;
|
||||||
|
my $res;
|
||||||
|
my $i; #preload
|
||||||
|
|
||||||
|
my @cbuffer = unpack( "C" x $size, $b );
|
||||||
|
|
||||||
|
#LOG1("SendWithDLEDup: \n");
|
||||||
|
#_daveDump("I send",b,size);
|
||||||
|
|
||||||
|
for ( $i = 0 ; $i < $size ; $i++ ) {
|
||||||
|
push( @target, $cbuffer[$i] );
|
||||||
|
|
||||||
|
if ( $cbuffer[$i] == &DLE ) {
|
||||||
|
push( @target, &DLE );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
push( @target, &DLE );
|
||||||
|
push( @target, &EOT );
|
||||||
|
|
||||||
|
#LOGx_daveDump("I send", target, targetSize);
|
||||||
|
|
||||||
|
my $buffer = pack( 'C*', @target );
|
||||||
|
|
||||||
|
$res = $self->{serial}->write($buffer);
|
||||||
|
|
||||||
|
if ( $main::attr{global}{verbose} >= 5 ) {
|
||||||
|
my $tbuffer = join( ", ", unpack( "H2 " x length($buffer), $buffer ) );
|
||||||
|
main::Log3( undef, 5, "S5Client S5SendWithDLEDup <-- $tbuffer" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#if(daveDebug & daveDebugExchange)
|
||||||
|
#LOG2("send: res:%d\n",res);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Remove the DLE doubling:
|
||||||
|
#
|
||||||
|
|
||||||
|
sub S5DLEDeDup($$) {
|
||||||
|
|
||||||
|
my ( $self, $b ) = @_;
|
||||||
|
my @rawBuf = @{$b};
|
||||||
|
|
||||||
|
my @msg = ();
|
||||||
|
|
||||||
|
my $j = 0;
|
||||||
|
my $k;
|
||||||
|
for ( $k = 0 ; $k < @rawBuf - 2 ; $k++ ) {
|
||||||
|
push( @msg, $rawBuf[$k] );
|
||||||
|
|
||||||
|
if ( DLE == $rawBuf[$k] ) {
|
||||||
|
if ( DLE != $rawBuf[ $k + 1 ] ) {
|
||||||
|
return ( -1, "" ); #Bad doubling found
|
||||||
|
}
|
||||||
|
$k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
push( @msg, $rawBuf[$k] );
|
||||||
|
$k++;
|
||||||
|
push( @msg, $rawBuf[$k] );
|
||||||
|
|
||||||
|
$b = pack( 'C*', @msg );
|
||||||
|
|
||||||
|
return ( 0, $b );
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Executes part of the dialog required to terminate transaction:
|
||||||
|
#
|
||||||
|
|
||||||
|
sub S5EndTrans($) {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
#LOG2("%s daveEndTrans\n", dc->iface->name);
|
||||||
|
if ( $self->S5ReadSingle() ne &STX ) {
|
||||||
|
|
||||||
|
#LOG2("%s daveEndTrans *** no STX at eot sequense.\n", dc->iface->name);
|
||||||
|
#return -1;
|
||||||
|
}
|
||||||
|
$self->S5SendDLEACK();
|
||||||
|
|
||||||
|
my ( $res, $b1 ) = $self->{serial}->read(3);
|
||||||
|
|
||||||
|
if ( $main::attr{global}{verbose} >= 5 ) {
|
||||||
|
my $tbuffer = join( ", ", unpack( "H2 " x $res, $b1 ) );
|
||||||
|
main::Log3( undef, 5, "S5Client S5EndTrans $tbuffer -->" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#_daveDump("3got",b1, res);
|
||||||
|
|
||||||
|
my @cbuffer = unpack( "C" x $res, $b1 );
|
||||||
|
if ( $self->compare( \@cbuffer, \@{ $self->{__davet121003} } ) == 0 ) {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5EndTransno accept of eot/ETX from plc." );
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->S5SendDLEACK();
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# This reads a single chracter from the serial interface:
|
||||||
|
|
||||||
|
sub S5ReadSingle ($) {
|
||||||
|
my ($self) = @_;
|
||||||
|
my ( $res, $i );
|
||||||
|
|
||||||
|
( $i, $res ) = $self->{serial}->read(1);
|
||||||
|
if ( $main::attr{global}{verbose} >= 5 ) {
|
||||||
|
my $tbuffer = join( ", ", unpack( "H2 " x $i, $res ) );
|
||||||
|
main::Log3( undef, 5, "S5Client S5ReadSingle $tbuffer -->" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ((daveDebug & daveDebugSpecialChars)!=0)
|
||||||
|
# LOG3("readSingle %d chars. 1st %02X\n",i,res);
|
||||||
|
if ( $i == 1 ) {
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------------------
|
||||||
|
# Connect to S5 CPU
|
||||||
|
#
|
||||||
|
|
||||||
|
sub S5ConnectPLCAS511($$) {
|
||||||
|
my ( $self, $portName ) = @_;
|
||||||
|
my $b1 = "";
|
||||||
|
my $ttyPort;
|
||||||
|
|
||||||
|
#if ( OS_Linux() ) {
|
||||||
|
$self->{serial} = new Device::SerialPort($portName);
|
||||||
|
|
||||||
|
#}
|
||||||
|
#else {
|
||||||
|
# $ttyPort = new Win32::SerialPort( $portName );
|
||||||
|
#}
|
||||||
|
|
||||||
|
main::Log3( undef, 3, "Can't open serial port $portName" )
|
||||||
|
unless ( $self->{serial} );
|
||||||
|
die unless ( $self->{serial} );
|
||||||
|
|
||||||
|
$self->{serial}->baudrate(9600);
|
||||||
|
$self->{serial}->databits(8);
|
||||||
|
$self->{serial}->parity('even');
|
||||||
|
$self->{serial}->stopbits(1);
|
||||||
|
|
||||||
|
$self->{serial}->read_const_time(500); # 500 milliseconds = 0.5 seconds
|
||||||
|
$self->{serial}->read_char_time(10); # avg time between read char
|
||||||
|
|
||||||
|
#$ttyPort->handshake('none');
|
||||||
|
#$ttyPort->stty_icrnl(1);
|
||||||
|
#$ttyPort->stty_ocrnl(1);
|
||||||
|
#$ttyPort->stty_onlcr(1);
|
||||||
|
#$ttyPort->stty_opost(1)
|
||||||
|
|
||||||
|
$self->{serial}->write_settings();
|
||||||
|
|
||||||
|
$b1 = pack( "C*", 0, 0 );
|
||||||
|
my ( $res, $msgIn ) =
|
||||||
|
$self->S5ExchangeAS511( $b1, 2, &maxSysinfoLen, 0x18 );
|
||||||
|
|
||||||
|
if ( $res < 0 ) {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ConnectPLCAS511 ImageAddr.Exchange sequence" );
|
||||||
|
return $res - 10;
|
||||||
|
}
|
||||||
|
if ( length($msgIn) < 47 ) {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ConnectPLCAS511 Too few chars in ImageAddr data" );
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#_daveDump("connect:",dc->msgIn, 47);
|
||||||
|
|
||||||
|
my @cbuffer = unpack( "C" x length($msgIn), $msgIn );
|
||||||
|
$self->{S5PAEAddress} =
|
||||||
|
$self->WordAt( \@cbuffer, 5 ); # start of inputs;
|
||||||
|
$self->{S5PAAAddress} = $self->WordAt( \@cbuffer, 7 ); # start of outputs
|
||||||
|
$self->{S5flagsAddress} =
|
||||||
|
$self->WordAt( \@cbuffer, 9 ); # start of flag (marker) memory;
|
||||||
|
$self->{S5timerAddress} =
|
||||||
|
$self->WordAt( \@cbuffer, 11 ); #start of timer memory;
|
||||||
|
$self->{S5counterAddress} =
|
||||||
|
$self->WordAt( \@cbuffer, 13 ); #start of counter memory
|
||||||
|
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client ->S5ConnectPLCAS511 start of inputs in memory "
|
||||||
|
. $self->{S5PAEAddress} );
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client ->S5ConnectPLCAS511 start of outputs in memory "
|
||||||
|
. $self->{S5PAAAddress} );
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client ->S5ConnectPLCAS511 start of flags in memory "
|
||||||
|
. $self->{S5flagsAddress} );
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client ->S5ConnectPLCAS511 start of timers in memory "
|
||||||
|
. $self->{S5timerAddress} );
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client ->S5ConnectPLCAS511 start of counters in memory "
|
||||||
|
. $self->{S5counterAddress} );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Reads <count> bytes from area <BlockN> with offset <offset>,
|
||||||
|
# that can be readed with daveGetInteger etc. You can read bytes from
|
||||||
|
# PBs & FBs too, but use daveReadBlock for this:
|
||||||
|
#
|
||||||
|
|
||||||
|
sub S5ReadS5Bytes($$$$$) {
|
||||||
|
my ( $self, $area, $BlockN, $offset, $count ) = @_;
|
||||||
|
my ( $res, $dataend, $datastart, $b1, $msgIn );
|
||||||
|
|
||||||
|
if ( $area == &S7ClientBase::S7AreaDB ) { #DB
|
||||||
|
( $res, $datastart ) = $self->S5ReadS5BlockAddress( $area, $BlockN );
|
||||||
|
if ( $res < 0 ) {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ReadS5Bytes Error in ReadS5Bytes.BlockAddr request"
|
||||||
|
);
|
||||||
|
return ( $res - 50, "" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elsif ( $area == &S7ClientBase::S7AreaPE ) { #inputs
|
||||||
|
|
||||||
|
$datastart =
|
||||||
|
$self->{S5PAEAddress}; #need to get this information from a property
|
||||||
|
|
||||||
|
}
|
||||||
|
elsif ( $area == &S7ClientBase::S7AreaPA ) { #outputs
|
||||||
|
|
||||||
|
$datastart =
|
||||||
|
$self->{S5PAAAddress}; #need to get this information from a property
|
||||||
|
|
||||||
|
}
|
||||||
|
elsif ( $area == &S7ClientBase::S7AreaMK ) { #flags
|
||||||
|
|
||||||
|
$datastart =
|
||||||
|
$self->{S5flagsAddress}; #need to get this information from a property
|
||||||
|
|
||||||
|
}
|
||||||
|
elsif ( $area == &S7ClientBase::S7AreaTM ) { #timers
|
||||||
|
|
||||||
|
$datastart =
|
||||||
|
$self->{S5timerAddress}; #need to get this information from a property
|
||||||
|
|
||||||
|
}
|
||||||
|
elsif ( $area == &S7ClientBase::S7AreaCT ) { #counters
|
||||||
|
|
||||||
|
$datastart = $self
|
||||||
|
->{S5counterAddress}; #need to get this information from a property
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ReadS5Bytes Unknown area in ReadS5Bytes request" );
|
||||||
|
return ( -1, "" );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $count > &daveMaxRawLen ) {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ReadS5Bytes: Requested data is out-of-range" );
|
||||||
|
return ( -1, "" );
|
||||||
|
}
|
||||||
|
$datastart += $offset;
|
||||||
|
$dataend = $datastart + $count - 1;
|
||||||
|
|
||||||
|
$b1 = pack( "C*",
|
||||||
|
$datastart / 256,
|
||||||
|
$datastart % 256,
|
||||||
|
$dataend / 256,
|
||||||
|
$dataend % 256 );
|
||||||
|
|
||||||
|
( $res, $msgIn ) = $self->S5ExchangeAS511( $b1, 4, 2 * $count + 7, 0x04 );
|
||||||
|
|
||||||
|
if ( $res < 0 ) {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ReadS5Bytes Error in ReadS5Bytes.Exchange sequence" );
|
||||||
|
return ( $res - 10, "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (dc->AnswLen<count+7) { #todo implement this check
|
||||||
|
# LOG3("%s *** Too few chars (%d) in ReadS5Bytes data.\n", dc->iface->name,dc->AnswLen);
|
||||||
|
#return (-5,"");
|
||||||
|
#}
|
||||||
|
|
||||||
|
my @cbuffer = unpack( "C" x length($msgIn), $msgIn );
|
||||||
|
|
||||||
|
if ( ( $cbuffer[0] != 0 )
|
||||||
|
|| ( $cbuffer[1] != 0 )
|
||||||
|
|| ( $cbuffer[2] != 0 )
|
||||||
|
|| ( $cbuffer[3] != 0 )
|
||||||
|
|| ( $cbuffer[4] != 0 ) )
|
||||||
|
{
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ReadS5Bytes Wrong ReadS5Bytes data signature" );
|
||||||
|
return ( -6, "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
$msgIn = substr( $msgIn, 5, -2 );
|
||||||
|
return ( 0, $msgIn );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Requests physical addresses and lengths of blocks in PLC memory and writes
|
||||||
|
# them to ai structure:
|
||||||
|
#
|
||||||
|
|
||||||
|
sub S5ReadS5BlockAddress($$$) {
|
||||||
|
my ( $self, $area, $BlockN ) = @_;
|
||||||
|
my ( $res, $msgIn, $dbaddr, $dblen, $ai );
|
||||||
|
|
||||||
|
my $b1 = pack( "C*", &daveS5BlockType_DB, $BlockN )
|
||||||
|
; #note we only support DB, no PB,FB,SB
|
||||||
|
|
||||||
|
( $res, $msgIn ) = $self->S5ExchangeAS511( $b1, 2, 24, 0x1A );
|
||||||
|
|
||||||
|
if ( $res < 0 ) {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client >S5ReadS5BlockAddress Error in BlockAddr.Exchange sequense"
|
||||||
|
);
|
||||||
|
return ( $res - 10, 0, 0 );
|
||||||
|
}
|
||||||
|
if ( length($msgIn) < 15 ) {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ReadS5BlockAddress Too few chars in BlockAddr data." );
|
||||||
|
return ( -2, 0, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
my @cbuffer = unpack( "C" x length($msgIn), $msgIn );
|
||||||
|
|
||||||
|
if ( ( $cbuffer[0] != 0 )
|
||||||
|
|| ( $cbuffer[3] != 0x70 )
|
||||||
|
|| ( $cbuffer[4] != 0x70 )
|
||||||
|
|| ( $cbuffer[5] != 0x40 + &daveS5BlockType_DB )
|
||||||
|
|| ( $cbuffer[6] != $BlockN ) )
|
||||||
|
{
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5ReadS5BlockAddress Wrong BlockAddr data signature." );
|
||||||
|
|
||||||
|
return ( -3, 0, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
$dbaddr = $cbuffer[1];
|
||||||
|
$dbaddr =
|
||||||
|
$dbaddr * 256 +
|
||||||
|
$cbuffer[2]; #Let make shift operations to compiler's optimizer
|
||||||
|
|
||||||
|
$dblen = $cbuffer[11];
|
||||||
|
$dblen =
|
||||||
|
( $dblen * 256 + $cbuffer[12] - 5 ) *
|
||||||
|
2; #PLC returns dblen in words including
|
||||||
|
#5 word header (but returnes the
|
||||||
|
#start address after the header) so
|
||||||
|
#dblen is length of block body
|
||||||
|
return ( 0, $dbaddr, $dblen );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Writes <count> bytes from area <BlockN> with offset <offset> from buf.
|
||||||
|
# You can't write data to the program blocks because you can't syncronize
|
||||||
|
# with PLC cycle. For this purposes use daveWriteBlock:
|
||||||
|
#
|
||||||
|
|
||||||
|
sub S5WriteS5Bytes($$$$$$) {
|
||||||
|
my ( $self, $area, $BlockN, $offset, $count, $buf ) = @_;
|
||||||
|
my ( $res, $datastart, $dblen, $b1, $msgIn );
|
||||||
|
|
||||||
|
if ( $area == &S7ClientBase::S7AreaDB ) { #DB
|
||||||
|
( $res, $datastart, $dblen ) =
|
||||||
|
$self->S5ReadS5BlockAddress( $area, $BlockN );
|
||||||
|
if ( $res < 0 ) {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5WriteS5Bytes Error in ReadS5Bytes.BlockAddr request."
|
||||||
|
);
|
||||||
|
return $res - 50;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elsif ( $area == &S7ClientBase::S7AreaPE ) { #inputs
|
||||||
|
|
||||||
|
$datastart =
|
||||||
|
$self->{S5PAEAddress}; #need to get this information from a property
|
||||||
|
|
||||||
|
$dblen = 128;
|
||||||
|
|
||||||
|
}
|
||||||
|
elsif ( $area == &S7ClientBase::S7AreaPA ) { #outputs
|
||||||
|
|
||||||
|
$datastart =
|
||||||
|
$self->{S5PAAAddress}; #need to get this information from a property
|
||||||
|
|
||||||
|
$dblen = 128;
|
||||||
|
|
||||||
|
}
|
||||||
|
elsif ( $area == &S7ClientBase::S7AreaMK ) { #flags
|
||||||
|
|
||||||
|
$datastart =
|
||||||
|
$self->{S5flagsAddress}; #need to get this information from a property
|
||||||
|
|
||||||
|
#$dblen = 128; # S5-90U
|
||||||
|
$dblen = 256; # S5-95U
|
||||||
|
|
||||||
|
}
|
||||||
|
elsif ( $area == &S7ClientBase::S7AreaTM ) { #timers
|
||||||
|
|
||||||
|
$datastart =
|
||||||
|
$self->{S5timerAddress}; #need to get this information from a property
|
||||||
|
|
||||||
|
#$dblen = 32 *2; # S5-90U
|
||||||
|
$dblen = 128 *2; # S5-95U
|
||||||
|
|
||||||
|
}
|
||||||
|
elsif ( $area == &S7ClientBase::S7AreaCT ) { #counters
|
||||||
|
|
||||||
|
$datastart = $self
|
||||||
|
->{S5counterAddress}; #need to get this information from a property
|
||||||
|
|
||||||
|
#$dblen = 32 *2; # S5-90U
|
||||||
|
$dblen = 128 * 2; # S5-95U
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5WriteS5Bytes Unknown area in WriteS5Bytes request." );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if ( ( $count > &daveMaxRawLen ) || ( $offset + $count > $dblen ) ) {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5WriteS5Bytes Requested data is out-of-range." );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#LOG2("area start is %04x, ",datastart);
|
||||||
|
$datastart += $offset;
|
||||||
|
|
||||||
|
#LOG2("data start is %04x\n",datastart);
|
||||||
|
|
||||||
|
$b1 = pack( "C*", $datastart / 256, $datastart % 256 );
|
||||||
|
|
||||||
|
$b1 = $b1 . $buf;
|
||||||
|
|
||||||
|
( $res, $msgIn ) = $self->S5ExchangeAS511( $b1, 2 + $count, 0, 0x03 );
|
||||||
|
if ( $res < 0 ) {
|
||||||
|
main::Log3( undef, 3,
|
||||||
|
"S5Client S5WriteS5Bytes Error in WriteS5Bytes.Exchange sequense."
|
||||||
|
);
|
||||||
|
return $res - 10;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
1;
|
||||||
|
=pod
|
||||||
|
=item summary low level interface to S5
|
||||||
|
=item summary_DE low level interface to S5
|
||||||
|
|
||||||
|
=begin html
|
||||||
|
|
||||||
|
<p><a name="S7_S5Client"></a></p>
|
||||||
|
<h3>S7_S5Client</h3>
|
||||||
|
<ul>
|
||||||
|
<ul>low level interface to S5</ul>
|
||||||
|
</ul>
|
||||||
|
=end html
|
||||||
|
=begin html_DE
|
||||||
|
|
||||||
|
<p><a name="S7_S5Client"></a></p>
|
||||||
|
<h3>S7_S5Client</h3>
|
||||||
|
<ul>
|
||||||
|
<ul>low level interface to S5</ul>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
=end html_DE
|
||||||
|
|
||||||
|
=cut
|
1337
fhem/FHEM/44_S7_S7Client.pm
Normal file
1337
fhem/FHEM/44_S7_S7Client.pm
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user