// function to set bit at the specific index in byte; since I do not have syshelpers unit
procedure PutBit(var Value: Byte; Index: Byte; State: Boolean);
begin
Value := (Value and not Byte(1 shl Index)) or (Byte(State) shl Index);
end;
function TS7Client.WriteBit(aArea: int16; aDBNumber: uint16;
aStart: uint16; bit_index: uint16; bit_value: Boolean): int16;
var
Address: longword;
NumElements, MaxElements, TotElements, DataSize, IsoSize, Length: uint16;
Source: byte;
Offset: uintptr = 0;
WordSize: int16;
begin
LastError := 0;
// If we are addressing Timers or counters the element size is 2
if (aArea = S7AreaCT) or (aArea = S7AreaTM) then
WordSize := 2
else
WordSize := 1; // added by Avra (it was missing)
MaxElements := (FPDULength - 35) div WordSize; // 35 = Write telegram header
TotElements := 1; // Vertnik
while (TotElements > 0) and (LastError = 0) do
begin
NumElements := TotElements;
if NumElements > MaxElements then
NumElements := MaxElements;
// If we use the internal buffer only, we cannot exced the PDU limit
DataSize := NumElements * WordSize;
IsoSize := Size_WR + DataSize;
// Setup the telegram
Move(S7_RW, PDU.H, Size_WR);
PDU.H[22] := S7WLBit; // Vertnik
// Whole telegram Size
PDU.H[2] := IsoSize shr 8;
PDU.H[3] := IsoSize and $00FF;
// Data Length
Length := DataSize+4;
PDU.H[15] := Length shr 8;
PDU.H[16] := Length and $00FF;
// Function
PDU.H[17] := $05;
// Set DB Number
PDU.H[27] := aArea;
if aArea = S7AreaDB then
begin
PDU.H[25] := aDBNumber shr 8;
PDU.H[26] := aDBNumber and $00FF;
end;
// Adjusts aStart and word length
if (aArea = S7AreaCT) or (aArea = S7AreaTM) then
begin
Address := aStart;
Length := DataSize;
if aArea = S7AreaCT then
PDU.H[22] := S7WLCounter
else
PDU.H[22] := S7WLTimer;
end
else
begin
Address := (aStart shl 3)+bit_index; // Vertnik
Length := DataSize; // Vertnik
end;
// Num elements
PDU.H[23] := NumElements shr 8; // fix by Avra, original: PDU.H[23] := NumElements shl 8
PDU.H[24] := NumElements and $00FF; ; // fix by Avra, original: PDU.H[24] := NumElements;
// Address into the PLC
PDU.H[30] := Address and $000000FF;
Address := Address shr 8;
PDU.H[29] := Address and $000000FF;
Address := Address shr 8;
PDU.H[28] := Address and $000000FF;
// Transport size
PDU.H[32] := $03; // Vertnik
// Length
PDU.H[33] := Length shr 8;
PDU.H[34] := Length and $00FF;
// Copy data
PutBit(Source,0,bit_value); // Vertnik
Move(Source, PDU.Bytes[35], DataSize); // Vertnik
//
if TCPClient.SendBuffer(@PDU.H, IsoSize) = IsoSize then
begin
RecvISOPacket(Length);
if LastError = 0 then
begin
if Length = 15 then
begin
if (PDU.H[27] <> $00) or (PDU.H[28] <> $00) or (PDU.H[31] <> $FF) then
LastError := errS7DataWrite;
end
else
LastError := errS7InvalidPDU;
end;
end
else
LastError := errTCPDataSend;
Offset := Offset + DataSize;
TotElements := TotElements - NumElements;
aStart := aStart + NumElements * WordSize;
end;
Result := LastError;
end;