Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Settimino.cpp
- Committer:
- il_mix
- Date:
- 2016-11-16
- Revision:
- 0:90ad5ee1ff15
- Child:
- 1:2f8bf824ec67
File content as of revision 0:90ad5ee1ff15:
/*=============================================================================|
| PROJECT SETTIMINO 1.0.0 |
|==============================================================================|
| Copyright (C) 2013, Davide Nardella |
| All rights reserved. |
|==============================================================================|
| SETTIMINO is free software: you can redistribute it and/or modify |
| it under the terms of the Lesser GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| It means that you can distribute your commercial software linked with |
| SETTIMINO without the requirement to distribute the source code of your |
| application and without the requirement that your application be itself |
| distributed under LGPL. |
| |
| SETTIMINO is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| Lesser GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License and a |
| copy of Lesser GNU General Public License along with Snap7. |
| If not, see http://www.gnu.org/licenses/ |
|=============================================================================*/
#include "Settimino.h"
// For further informations about structures (the byte arrays and they meanins)
// see http://snap7.sourceforge.net project.
/*
Arduino has not a multithread environment and all Client functions are
fully synchronous, so to save memory we can define telegrams and I/O
data areas as globals, since only one client at time will use them.
*/
// ISO Connection Request telegram (contains also ISO Header and COTP Header)
byte ISO_CR[] = {
// TPKT (RFC1006 Header)
0x03, // RFC 1006 ID (3)
0x00, // Reserved, always 0
0x00, // High part of packet lenght (entire frame, payload and TPDU included)
0x16, // Low part of packet lenght (entire frame, payload and TPDU included)
// COTP (ISO 8073 Header)
0x11, // PDU Size Length
0xE0, // CR - Connection Request ID
0x00, // Dst Reference HI
0x00, // Dst Reference LO
0x00, // Src Reference HI
0x01, // Src Reference LO
0x00, // Class + Options Flags
0xC0, // PDU Max Length ID
0x01, // PDU Max Length HI
0x0A, // PDU Max Length LO
0xC1, // Src TSAP Identifier
0x02, // Src TSAP Length (2 bytes)
0x01, // Src TSAP HI (will be overwritten by ISOConnect())
0x00, // Src TSAP LO (will be overwritten by ISOConnect())
0xC2, // Dst TSAP Identifier
0x02, // Dst TSAP Length (2 bytes)
0x01, // Dst TSAP HI (will be overwritten by ISOConnect())
0x02 // Dst TSAP LO (will be overwritten by ISOConnect())
};
// S7 PDU Negotiation Telegram (contains also ISO Header and COTP Header)
byte S7_PN[] = {
0x03, 0x00, 0x00, 0x19, 0x02, 0xf0, 0x80, // TPKT + COTP (see above for info)
0x32, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x08, 0x00,
0x00, 0xf0, 0x00, 0x00, 0x01, 0x00, 0x01,
0x00, 0xf0 // PDU Length Requested = HI-LO 240 bytes
};
// S7 Read/Write Request Header (contains also ISO Header and COTP Header)
byte S7_RW[] = { // 31-35 bytes
0x03, 0x00,
0x00, 0x1f, // Telegram Length (Data Size + 31 or 35)
0x02, 0xf0, 0x80, // COTP (see above for info)
0x32, // S7 Protocol ID
0x01, // Job Type
0x00, 0x00, // Redundancy identification
0x05, 0x00, // PDU Reference
0x00, 0x0e, // Parameters Length
0x00, 0x00, // Data Length = Size(bytes) + 4
0x04, // Function 4 Read Var, 5 Write Var
0x01, // Items count
0x12, // Var spec.
0x0a, // Length of remaining bytes
0x10, // Syntax ID
S7WLByte, // Transport Size
0x00,0x00, // Num Elements
0x00,0x00, // DB Number (if any, else 0)
0x84, // Area Type
0x00, 0x00, 0x00, // Area Offset
// WR area
0x00, // Reserved
0x04, // Transport size
0x00, 0x00, // Data Length * 8 (if not timer or counter)
};
#ifdef _EXTENDED
// S7 Get Block Info Request Header (contains also ISO Header and COTP Header)
byte S7_BI[] = {
0x03, 0x00, 0x00, 0x25, 0x02, 0xf0, 0x80, 0x32,
0x07, 0x00, 0x00, 0x05, 0x00, 0x00, 0x08, 0x00,
0x0c, 0x00, 0x01, 0x12, 0x04, 0x11, 0x43, 0x03,
0x00, 0xff, 0x09, 0x00, 0x08, 0x30, 0x41,
0x30, 0x30, 0x30, 0x30, 0x30, // ASCII DB Number
0x41
};
// S7 Put PLC in STOP state Request Header (contains also ISO Header and COTP Header)
byte S7_STOP[] = {
0x03, 0x00, 0x00, 0x21, 0x02, 0xf0, 0x80, 0x32,
0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x10, 0x00,
0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
0x50, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x41,
0x4d
};
// S7 Put PLC in RUN state Request Header (contains also ISO Header and COTP Header)
byte S7_START[] = {
0x03, 0x00, 0x00, 0x25, 0x02, 0xf0, 0x80, 0x32,
0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x14, 0x00,
0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfd, 0x00, 0x00, 0x09, 0x50, 0x5f, 0x50, 0x52,
0x4f, 0x47, 0x52, 0x41, 0x4d
};
// S7 Get PLC Status Request Header (contains also ISO Header and COTP Header)
byte S7_PLCGETS[] = {
0x03, 0x00, 0x00, 0x21, 0x02, 0xf0, 0x80, 0x32,
0x07, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x08, 0x00,
0x08, 0x00, 0x01, 0x12, 0x04, 0x11, 0x44, 0x01,
0x00, 0xff, 0x09, 0x00, 0x04, 0x04, 0x24, 0x00,
0x00
};
#endif // _EXTENDED
TPDU PDU;
#ifdef _S7HELPER
S7Helper S7;
//-----------------------------------------------------------------------------
bool S7Helper::BitAt(void *Buffer, int ByteIndex, byte BitIndex)
{
byte mask[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
pbyte Pointer = pbyte(Buffer) + ByteIndex;
if (BitIndex>7)
return false;
else
return (*Pointer & mask[BitIndex]);
}
//-----------------------------------------------------------------------------
bool S7Helper::BitAt(int ByteIndex, int BitIndex)
{
return BitAt(&PDU.DATA[0], ByteIndex, BitIndex);
}
//-----------------------------------------------------------------------------
byte S7Helper::ByteAt(void *Buffer, int index)
{
pbyte Pointer = pbyte(Buffer) + index;
return *Pointer;
}
//-----------------------------------------------------------------------------
byte S7Helper::ByteAt(int index)
{
return ByteAt(&PDU.DATA, index);
}
//-----------------------------------------------------------------------------
word S7Helper::WordAt(void *Buffer, int index)
{
word hi=(*(pbyte(Buffer) + index))<<8;
return hi+*(pbyte(Buffer) + index+1);
}
//-----------------------------------------------------------------------------
word S7Helper::WordAt(int index)
{
return WordAt(&PDU.DATA, index);
}
//-----------------------------------------------------------------------------
dword S7Helper::DWordAt(void *Buffer, int index)
{
pbyte pb;
dword dw1;
pb=pbyte(Buffer) + index;
dw1=*pb;dw1<<=8;
pb=pbyte(Buffer) + index + 1;
dw1+=*pb;dw1<<=8;
pb=pbyte(Buffer) + index + 2;
dw1+=*pb;dw1<<=8;
pb=pbyte(Buffer) + index + 3;
dw1+=*pb;
return dw1;
}
//-----------------------------------------------------------------------------
dword S7Helper::DWordAt(int index)
{
return DWordAt(&PDU.DATA, index);
}
//-----------------------------------------------------------------------------
float S7Helper::FloatAt(void *Buffer, int index)
{
dword dw = DWordAt(Buffer, index);
return *(pfloat(&dw));
}
//-----------------------------------------------------------------------------
float S7Helper::FloatAt(int index)
{
return FloatAt(&PDU.DATA, index);
}
//-----------------------------------------------------------------------------
integer S7Helper::IntegerAt(void *Buffer, int index)
{
word w = WordAt(Buffer, index);
return *(pinteger(&w));
}
//-----------------------------------------------------------------------------
integer S7Helper::IntegerAt(int index)
{
return IntegerAt(&PDU.DATA, index);
}
//-----------------------------------------------------------------------------
long S7Helper::DintAt(void *Buffer, int index)
{
dword dw = DWordAt(Buffer, index);
return *(pdint(&dw));
}
//-----------------------------------------------------------------------------
long S7Helper::DintAt(int index)
{
return DintAt(&PDU.DATA, index);
}
#endif // _S7HELPER
//-----------------------------------------------------------------------------
S7Client::S7Client()
{
// Default TSAP values for connectiong as S7_Basic to a S7300 (Rack 0, Slot 2)
LocalTSAP_HI = 0x01;
LocalTSAP_LO = 0x00;
RemoteTSAP_HI= 0x01;
RemoteTSAP_LO= 0x02;
ConnType = S7_Basic;
Connected = false;
LastError = 0;
PDULength = 0;
RecvTimeout = 500; // 500 ms
}
//-----------------------------------------------------------------------------
S7Client::~S7Client()
{
Disconnect();
}
//-----------------------------------------------------------------------------
int S7Client::SetLastError(int Error)
{
LastError=Error;
return Error;
}
//-----------------------------------------------------------------------------
void S7Client::FlushSocket()
{
char buffer[32];
while(TCPClient.receive_all(buffer, sizeof(buffer)) > 0)
{}
}
//-----------------------------------------------------------------------------
int S7Client::IsoPduSize()
{
uint16_t Size = PDU.H[2];
return (Size<<8) + PDU.H[3];
}
//-----------------------------------------------------------------------------
int S7Client::RecvPacket(char *buf, uint16_t Size)
{
TCPClient.set_blocking(true, RecvTimeout);
int ret = TCPClient.receive(buf, Size);
TCPClient.set_blocking(false);
if(ret == 0)
return SetLastError(errTCPConnectionReset);
return SetLastError(0);
}
//-----------------------------------------------------------------------------
void S7Client::SetConnectionParams(const char* Address, uint16_t LocalTSAP, uint16_t RemoteTSAP)
{
sprintf(Peer, "%s", Address);
LocalTSAP_HI = LocalTSAP>>8;
LocalTSAP_LO = LocalTSAP & 0x00FF;
RemoteTSAP_HI = RemoteTSAP>>8;
RemoteTSAP_LO = RemoteTSAP & 0x00FF;
}
//-----------------------------------------------------------------------------
void S7Client::SetConnectionType(uint16_t ConnectionType)
{
ConnType = ConnectionType;
}
//-----------------------------------------------------------------------------
int S7Client::ConnectTo(const char* Address, uint16_t Rack, uint16_t Slot)
{
SetConnectionParams(Address, 0x0100, (ConnType<<8)+(Rack * 0x20) + Slot);
return Connect();
}
//-----------------------------------------------------------------------------
int S7Client::Connect()
{
LastError = 0;
if (!Connected)
{
TCPConnect();
if (LastError==0) // First stage : TCP Connection
{
ISOConnect();
if (LastError==0) // Second stage : ISOTCP (ISO 8073) Connection
{
LastError=NegotiatePduLength(); // Third stage : S7 PDU negotiation
}
}
}
Connected=LastError==0;
return LastError;
}
//-----------------------------------------------------------------------------
void S7Client::Disconnect()
{
if (Connected)
{
TCPClient.close();
Connected = false;
PDULength = 0;
LastError = 0;
}
}
//-----------------------------------------------------------------------------
int S7Client::TCPConnect()
{
if (TCPClient.connect(Peer, isotcp))
return SetLastError(0);
else
return SetLastError(errTCPConnectionFailed);
}
//-----------------------------------------------------------------------------
int S7Client::RecvISOPacket(uint16_t *Size)
{
bool Done = false;
pbyte Target = pbyte(&PDU.H[0])+Shift;
LastError=0;
while ((LastError==0) && !Done)
{
// Get TPKT (4 bytes)
RecvPacket(PDU.H, 4);
if (LastError==0)
{
*Size = IsoPduSize();
// Check 0 bytes Data Packet (only TPKT+COTP - 7 bytes)
if (*Size==7)
RecvPacket(PDU.H, 3); // Skip remaining 3 bytes and Done is still false
else
{
if ((*Size>MaxPduSize) || (*Size<MinPduSize))
LastError=errISOInvalidPDU;
else
Done = true; // a valid Length !=7 && >16 && <247
}
}
}
if (LastError==0)
{
RecvPacket(PDU.H, 3); // Skip remaining 3 COTP bytes
LastPDUType=PDU.H[1]; // Stores PDU Type, we need it
*Size-=ISOSize;
// We need to align with PDU.DATA
RecvPacket(Target, *Size);
}
if (LastError!=0)
FlushSocket();
return LastError;
}
//-----------------------------------------------------------------------------
int S7Client::ISOConnect()
{
uint16_t Length;
// Setup TSAPs
ISO_CR[16]=LocalTSAP_HI;
ISO_CR[17]=LocalTSAP_LO;
ISO_CR[20]=RemoteTSAP_HI;
ISO_CR[21]=RemoteTSAP_LO;
if (TCPClient.send(ISO_CR, sizeof(ISO_CR))==sizeof(ISO_CR))
{
RecvISOPacket(&Length);
if ((LastError==0) && (Length==15)) // 15 = 22 (sizeof CC telegram) - 7 (sizeof Header)
{
if (LastPDUType==CC) // Connection confirm
return 0;
else
return SetLastError(errISOInvalidPDU);
}
else
return LastError;
}
else
return SetLastError(errISOConnectionFailed);
}
//-----------------------------------------------------------------------------
int S7Client::NegotiatePduLength()
{
uint16_t Length;
if (TCPClient.send(S7_PN, sizeof(S7_PN))==sizeof(S7_PN))
{
RecvISOPacket(&Length);
if (LastError==0)
{
// check S7 Error
if ((Length==20) && (PDU.H[27]==0) && (PDU.H[28]==0)) // 20 = size of Negotiate Answer
{
PDULength = PDU.H[35];
PDULength = (PDULength<<8) + PDU.H[36]; // Value negotiated
if (PDULength>0)
return 0;
else
return SetLastError(errISONegotiatingPDU);
}
else
return SetLastError(errISONegotiatingPDU);
}
else
return LastError;
}
else
return SetLastError(errISONegotiatingPDU);
}
//-----------------------------------------------------------------------------
int S7Client::ReadArea(int Area, uint16_t DBNumber, uint16_t Start, uint16_t Amount, void *ptrData)
{
unsigned long Address;
uint16_t NumElements;
uint16_t MaxElements;
uint16_t TotElements;
uint16_t SizeRequested;
uint16_t Length;
pbyte Target;
uintptr_t Offset = 0;
int WordSize = 1;
LastError=0;
// If we are addressing Timers or counters the element size is 2
if ((Area==S7AreaCT) || (Area==S7AreaTM))
WordSize = 2;
MaxElements=(PDULength-18) / WordSize; // 18 = Reply telegram header
TotElements=Amount;
// If we use the internal buffer only, we cannot exced the PDU limit
if (ptrData==NULL)
{
if (TotElements>MaxElements)
TotElements=MaxElements;
}
while ((TotElements>0) && (LastError==0))
{
NumElements=TotElements;
if (NumElements>MaxElements)
NumElements=MaxElements;
SizeRequested =NumElements * WordSize;
Target=pbyte(ptrData)+Offset;
// Setup the telegram
memcpy(&PDU.H, S7_RW, Size_RD);
// Set DB Number
PDU.H[27] = Area;
if (Area==S7AreaDB)
{
PDU.H[25] = DBNumber>>8;
PDU.H[26] = DBNumber & 0x00FF;
}
// Adjusts Start and word length
if ((Area==S7AreaCT) || (Area==S7AreaTM))
{
Address = Start;
if (Area==S7AreaCT)
PDU.H[22]=S7WLCounter;
else
PDU.H[22]=S7WLTimer;
}
else
Address = Start<<3;
// Num elements
PDU.H[23]=NumElements<<8;
PDU.H[24]=NumElements;
// Address into the PLC
PDU.H[30] = Address & 0x000000FF;
Address = Address >> 8;
PDU.H[29] = Address & 0x000000FF;
Address = Address >> 8;
PDU.H[28] = Address & 0x000000FF;
if (TCPClient.send(PDU.H, Size_RD)==Size_RD)
{
RecvISOPacket(&Length);
if (LastError==0)
{
if (Length>=18)
{
if ((Length-18==SizeRequested) && (PDU.H[31]==0xFF))
{
if (ptrData!=NULL)
memcpy(Target, &PDU.DATA[0], SizeRequested); // Copies in the user's buffer
Offset+=SizeRequested;
}
else
LastError = errS7DataRead;
}
else
LastError = errS7InvalidPDU;
}
}
else
LastError = errTCPDataSend;
TotElements -= NumElements;
Start += NumElements*WordSize;
}
return LastError;
}
//-----------------------------------------------------------------------------
int S7Client::WriteArea(int Area, uint16_t DBNumber, uint16_t Start, uint16_t Amount, void *ptrData)
{
unsigned long Address;
uint16_t NumElements;
uint16_t MaxElements;
uint16_t TotElements;
uint16_t DataSize;
uint16_t IsoSize;
uint16_t Length;
pbyte Source;
uintptr_t Offset = 0;
int WordSize = 1;
LastError=0;
// If we are addressing Timers or counters the element size is 2
if ((Area==S7AreaCT) || (Area==S7AreaTM))
WordSize = 2;
MaxElements=(PDULength-35) / WordSize; // 35 = Write telegram header
TotElements=Amount;
if (ptrData==NULL)
{
if (TotElements>MaxElements)
TotElements=MaxElements;
}
while ((TotElements>0) && (LastError==0))
{
NumElements=TotElements;
if (NumElements>MaxElements)
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
memcpy(&PDU.H, S7_RW, Size_WR);
// Whole telegram Size
PDU.H[2]=IsoSize>>8;
PDU.H[3]=IsoSize & 0x00FF;
// Data Length
Length=DataSize+4;
PDU.H[15]=Length>>8;
PDU.H[16]=Length & 0x00FF;
// Function
PDU.H[17]=0x05;
// Set DB Number
PDU.H[27] = Area;
if (Area==S7AreaDB)
{
PDU.H[25] = DBNumber>>8;
PDU.H[26] = DBNumber & 0x00FF;
}
// Adjusts Start and word length
if ((Area==S7AreaCT) || (Area==S7AreaTM))
{
Address = Start;
Length = DataSize;
if (Area==S7AreaCT)
PDU.H[22]=S7WLCounter;
else
PDU.H[22]=S7WLTimer;
}
else
{
Address = Start<<3;
Length = DataSize<<3;
}
// Num elements
PDU.H[23]=NumElements<<8;
PDU.H[24]=NumElements;
// Address into the PLC
PDU.H[30] = Address & 0x000000FF;
Address = Address >> 8;
PDU.H[29] = Address & 0x000000FF;
Address = Address >> 8;
PDU.H[28] = Address & 0x000000FF;
// Length
PDU.H[33]=Length>>8;
PDU.H[34]=Length & 0x00FF;
// Copy data
Source=pbyte(ptrData)+Offset;
if (ptrData!=NULL)
memcpy(&PDU.H[35], Source, DataSize);
if (TCPClient.send(PDU.H, IsoSize)==IsoSize)
{
RecvISOPacket(&Length);
if (LastError==0)
{
if (Length==15)
{
if ((PDU.H[27]!=0x00) || (PDU.H[28]!=0x00) || (PDU.H[31]!=0xFF))
LastError = errS7DataWrite;
}
else
LastError = errS7InvalidPDU;
}
}
else
LastError = errTCPDataSend;
Offset+=DataSize;
TotElements -= NumElements;
Start += NumElements*WordSize;
}
return LastError;
}
//-----------------------------------------------------------------------------
#ifdef _EXTENDED
int S7Client::GetDBSize(uint16_t DBNumber, uint16_t *Size)
{
uint16_t Length;
LastError=0;
*Size=0;
// Setup the telegram
memcpy(&PDU.H, S7_BI, sizeof(S7_BI));
// Set DB Number
PDU.H[31]=(DBNumber / 10000)+0x30;
DBNumber=DBNumber % 10000;
PDU.H[32]=(DBNumber / 1000)+0x30;
DBNumber=DBNumber % 1000;
PDU.H[33]=(DBNumber / 100)+0x30;
DBNumber=DBNumber % 100;
PDU.H[34]=(DBNumber / 10)+0x30;
DBNumber=DBNumber % 10;
PDU.H[35]=(DBNumber / 1)+0x30;
if (TCPClient.send(PDU.H, sizeof(S7_BI))==sizeof(S7_BI))
{
RecvISOPacket(&Length);
if (LastError==0)
{
if (Length>25) // 26 is the minimum expected
{
if ((PDU.H[37]==0x00) && (PDU.H[38]==0x00) && (PDU.H[39]==0xFF))
{
*Size=PDU.H[83];
*Size=(*Size<<8)+PDU.H[84];
}
else
LastError = errS7Function;
}
else
LastError = errS7InvalidPDU;
}
}
else
LastError = errTCPDataSend;
return LastError;
}
//-----------------------------------------------------------------------------
int S7Client::DBGet(uint16_t DBNumber, void *ptrData, uint16_t *Size)
{
uint16_t Length;
int Result;
Result=GetDBSize(DBNumber, &Length);
if (Result==0)
{
if (Length<=*Size) // Check if the buffer supplied is big enough
{
Result=ReadArea(S7AreaDB, DBNumber, 0, Length, ptrData);
if (Result==0)
*Size=Length;
}
else
Result=errBufferTooSmall;
}
return Result;
}
//-----------------------------------------------------------------------------
int S7Client::PlcStop()
{
uint16_t Length;
LastError=0;
// Setup the telegram
memcpy(&PDU.H, S7_STOP, sizeof(S7_STOP));
if (TCPClient.send(PDU.H, sizeof(S7_STOP))==sizeof(S7_STOP))
{
RecvISOPacket(&Length);
if (LastError==0)
{
if (Length>12) // 13 is the minimum expected
{
if ((PDU.H[27]!=0x00) || (PDU.H[28]!=0x00))
LastError = errS7Function;
}
else
LastError = errS7InvalidPDU;
}
}
else
LastError = errTCPDataSend;
return LastError;
}
//-----------------------------------------------------------------------------
int S7Client::PlcStart()
{
uint16_t Length;
LastError=0;
// Setup the telegram
memcpy(&PDU.H, S7_START, sizeof(S7_START));
if (TCPClient.send(PDU.H, sizeof(S7_START))==sizeof(S7_START))
{
RecvISOPacket(&Length);
if (LastError==0)
{
if (Length>12) // 13 is the minimum expected
{
if ((PDU.H[27]!=0x00) || (PDU.H[28]!=0x00))
LastError = errS7Function;
}
else
LastError = errS7InvalidPDU;
}
}
else
LastError = errTCPDataSend;
return LastError;
}
//-----------------------------------------------------------------------------
int S7Client::GetPlcStatus(int *Status)
{
uint16_t Length;
LastError=0;
// Setup the telegram
memcpy(&PDU.H, S7_PLCGETS, sizeof(S7_PLCGETS));
if (TCPClient.send(PDU.H, sizeof(S7_PLCGETS))==sizeof(S7_PLCGETS))
{
RecvISOPacket(&Length);
if (LastError==0)
{
if (Length>53) // 54 is the minimum expected
{
switch (PDU.H[54])
{
case S7CpuStatusUnknown :
case S7CpuStatusRun :
case S7CpuStatusStop : *Status=PDU.H[54];
break;
default :
// Since RUN status is always 0x08 for all CPUs and CPs, STOP status
// sometime can be coded as 0x03 (especially for old cpu...)
*Status=S7CpuStatusStop;
}
}
else
LastError = errS7InvalidPDU;
}
}
else
LastError = errTCPDataSend;
return LastError;
}
//-----------------------------------------------------------------------------
int S7Client::IsoExchangeBuffer(uint16_t *Size)
{
LastError=0;
if (TCPClient.send(PDU.H, int(Size))==*Size)
RecvISOPacket(Size);
else
LastError = errTCPDataSend;
return LastError;
}
//-----------------------------------------------------------------------------
void S7Client::ErrorText(int Error, char *Text, int TextLen)
{
}
#endif // _EXTENDED
//-----------------------------------------------------------------------------