GrpcPrint/PrintS/Communication/Snap7/s7_micro_client.cpp
2024-03-19 17:45:12 +08:00

3332 lines
116 KiB
C++

/*=============================================================================|
| PROJECT SNAP7 1.3.0 |
|==============================================================================|
| Copyright (C) 2013, 2015 Davide Nardella |
| All rights reserved. |
|==============================================================================|
| SNAP7 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 |
| SNAP7 without the requirement to distribute the source code of your |
| application and without the requirement that your application be itself |
| distributed under LGPL. |
| |
| SNAP7 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 "s7_micro_client.h"
//---------------------------------------------------------------------------
TSnap7MicroClient::TSnap7MicroClient()
{
SrcRef =0x0100; // RFC0983 states that SrcRef and DetRef should be 0
// and, in any case, they are ignored.
// S7 instead requires a number != 0
// Libnodave uses 0x0100
// S7Manager uses 0x0D00
// TIA Portal V12 uses 0x1D00
// WinCC uses 0x0300
// Seems that every non zero value is good enough...
DstRef =0x0000;
SrcTSap =0x0100;
DstTSap =0x0000; // It's filled by connection functions
ConnectionType = CONNTYPE_PG; // Default connection type
memset(&Job,0,sizeof(TSnap7Job));
}
//---------------------------------------------------------------------------
TSnap7MicroClient::~TSnap7MicroClient()
{
Destroying = true;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opReadArea()
{
PReqFunReadParams ReqParams;
PResFunReadParams ResParams;
PS7ResHeader23 Answer;
PResFunReadItem ResData;
word RPSize; // ReqParams size
int WordSize;
uintptr_t Offset;
pbyte Target;
int Address;
int IsoSize;
int Start;
int MaxElements; // Max elements that we can transfer in a PDU
word NumElements; // Num of elements that we are asking for this telegram
int TotElements; // Total elements requested
int Size;
int Result;
WordSize=DataSizeByte(Job.WordLen); // The size in bytes of an element that we are asking for
if (WordSize==0)
return errCliInvalidWordLen;
// First check : params bounds
if ((Job.Number<0) || (Job.Number>65535) || (Job.Start<0) || (Job.Amount<1))
return errCliInvalidParams;
// Second check : transport size
if ((Job.WordLen==S7WLBit) && (Job.Amount>1))
return errCliInvalidTransportSize;
// Request Params size
RPSize =sizeof(TReqFunReadItem)+2; // 1 item + FunRead + ItemsCount
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams =PReqFunReadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams =PResFunReadParams(pbyte(Answer)+ResHeaderSize23);
ResData =PResFunReadItem(pbyte(ResParams)+sizeof(TResFunReadParams));
// Each packet cannot exceed the PDU length (in bytes) negotiated, and moreover
// we must ensure to transfer a "finite" number of item per PDU
MaxElements=(PDULength-sizeof(TS7ResHeader23)-sizeof(TResFunReadParams)-4) / WordSize;
TotElements=Job.Amount;
Start =Job.Start;
Offset =0;
Result =0;
while ((TotElements>0) && (Result==0))
{
NumElements=TotElements;
if (NumElements>MaxElements)
NumElements=MaxElements;
Target=pbyte(Job.pData)+Offset;
//----------------------------------------------- Read next slice-----
PDUH_out->P = 0x32; // Always 0x32
PDUH_out->PDUType = PduType_request; // 0x01
PDUH_out->AB_EX = 0x0000; // Always 0x0000
PDUH_out->Sequence = GetNextWord(); // AutoInc
PDUH_out->ParLen = SwapWord(RPSize); // 14 bytes params
PDUH_out->DataLen = 0x0000; // No data
ReqParams->FunRead = pduFuncRead; // 0x04
ReqParams->ItemsCount = 1;
ReqParams->Items[0].ItemHead[0] = 0x12;
ReqParams->Items[0].ItemHead[1] = 0x0A;
ReqParams->Items[0].ItemHead[2] = 0x10;
ReqParams->Items[0].TransportSize = Job.WordLen;
ReqParams->Items[0].Length = SwapWord(NumElements);
ReqParams->Items[0].Area = Job.Area;
if (Job.Area==S7AreaDB)
ReqParams->Items[0].DBNumber = SwapWord(Job.Number);
else
ReqParams->Items[0].DBNumber = 0x0000;
// Adjusts the offset
if ((Job.WordLen==S7WLBit) || (Job.WordLen==S7WLCounter) || (Job.WordLen==S7WLTimer))
Address = Start;
else
Address = Start*8;
ReqParams->Items[0].Address[2] = Address & 0x000000FF;
Address = Address >> 8;
ReqParams->Items[0].Address[1] = Address & 0x000000FF;
Address = Address >> 8;
ReqParams->Items[0].Address[0] = Address & 0x000000FF;
IsoSize = sizeof(TS7ReqHeader)+RPSize;
Result = isoExchangeBuffer(0,IsoSize);
// Get Data
if (Result==0) // 1St level Iso
{
Size = 0;
// Item level error
if (ResData->ReturnCode==0xFF) // <-- 0xFF means Result OK
{
// Calcs data size in bytes
Size = SwapWord(ResData->DataLength);
// Adjust Size in accord of TransportSize
if ((ResData->TransportSize != TS_ResOctet) && (ResData->TransportSize != TS_ResReal) && (ResData->TransportSize != TS_ResBit))
Size = Size >> 3;
memcpy(Target, &ResData->Data[0], Size);
}
else
Result = CpuError(ResData->ReturnCode);
Offset+=Size;
};
//--------------------------------------------------------------------
TotElements -= NumElements;
Start += NumElements*WordSize;
}
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opWriteArea()
{
PReqFunWriteParams ReqParams;
PReqFunWriteDataItem ReqData; // only 1 item for WriteArea Function
PResFunWrite ResParams;
PS7ResHeader23 Answer;
word RPSize; // ReqParams size
word RHSize; // Request headers size
bool First = true;
pbyte Source;
pbyte Target;
int Address;
int IsoSize;
int WordSize;
word Size;
uintptr_t Offset = 0;
int Start; // where we are starting from for this telegram
int MaxElements; // Max elements that we can transfer in a PDU
word NumElements; // Num of elements that we are asking for this telegram
int TotElements; // Total elements requested
int Result = 0;
WordSize=DataSizeByte(Job.WordLen); // The size in bytes of an element that we are pushing
if (WordSize==0)
return errCliInvalidWordLen;
// First check : params bounds
if ((Job.Number<0) || (Job.Number>65535) || (Job.Start<0) || (Job.Amount<1))
return errCliInvalidParams;
// Second check : transport size
if ((Job.WordLen==S7WLBit) && (Job.Amount>1))
return errCliInvalidTransportSize;
RHSize =sizeof(TS7ReqHeader)+ // Request header
2+ // FunWrite+ItemCount (of TReqFunWriteParams)
sizeof(TReqFunWriteItem)+// 1 item reference
4; // ReturnCode+TransportSize+DataLength
RPSize =sizeof(TReqFunWriteItem)+2;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunWriteParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ReqData =PReqFunWriteDataItem(pbyte(ReqParams)+sizeof(TReqFunWriteItem)+2); // 2 = FunWrite+ItemsCount
Target =pbyte(ReqData)+4; // 4 = ReturnCode+TransportSize+DataLength
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResFunWrite(pbyte(Answer)+ResHeaderSize23);
// Each packet cannot exceed the PDU length (in bytes) negotiated, and moreover
// we must ensure to transfer a "finite" number of item per PDU
MaxElements=(PDULength-RHSize) / WordSize;
TotElements=Job.Amount;
Start =Job.Start;
while ((TotElements>0) && (Result==0))
{
NumElements=TotElements;
if (NumElements>MaxElements)
NumElements=MaxElements;
Source=pbyte(Job.pData)+Offset;
Size=NumElements * WordSize;
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen =SwapWord(RPSize); // 14 bytes params
PDUH_out->DataLen =SwapWord(Size+4);
ReqParams->FunWrite=pduFuncWrite; // 0x05
ReqParams->ItemsCount=1;
ReqParams->Items[0].ItemHead[0]=0x12;
ReqParams->Items[0].ItemHead[1]=0x0A;
ReqParams->Items[0].ItemHead[2]=0x10;
ReqParams->Items[0].TransportSize=Job.WordLen;
ReqParams->Items[0].Length=SwapWord(NumElements);
ReqParams->Items[0].Area=Job.Area;
if (Job.Area==S7AreaDB)
ReqParams->Items[0].DBNumber=SwapWord(Job.Number);
else
ReqParams->Items[0].DBNumber=0x0000;
// Adjusts the offset
if ((Job.WordLen==S7WLBit) || (Job.WordLen==S7WLCounter) || (Job.WordLen==S7WLTimer))
Address=Start;
else
Address=Start*8;
ReqParams->Items[0].Address[2]=Address & 0x000000FF;
Address=Address >> 8;
ReqParams->Items[0].Address[1]=Address & 0x000000FF;
Address=Address >> 8;
ReqParams->Items[0].Address[0]=Address & 0x000000FF;
ReqData->ReturnCode=0x00;
switch(Job.WordLen)
{
case S7WLBit:
ReqData->TransportSize=TS_ResBit;
break;
case S7WLInt:
case S7WLDInt:
ReqData->TransportSize=TS_ResInt;
break;
case S7WLReal:
ReqData->TransportSize=TS_ResReal;
break;
case S7WLChar :
case S7WLCounter:
case S7WLTimer:
ReqData->TransportSize=TS_ResOctet;
break;
default:
ReqData->TransportSize=TS_ResByte;
break;
};
if ((ReqData->TransportSize!=TS_ResOctet) && (ReqData->TransportSize!=TS_ResReal) && (ReqData->TransportSize!=TS_ResBit))
ReqData->DataLength=SwapWord(Size*8);
else
ReqData->DataLength=SwapWord(Size);
memcpy(Target, Source, Size);
IsoSize=RHSize + Size;
Result=isoExchangeBuffer(0,IsoSize);
if (Result==0) // 1St check : Iso result
{
Result=CpuError(SwapWord(Answer->Error)); // 2nd level global error
if (Result==0)
{ // 2th check : item error
if (ResParams->Data[0] == 0xFF) // <-- 0xFF means Result OK
Result=0;
else
// Now we check the error : if it's the first part we report the cpu error
// otherwise we warn that the function failed but some data were written
if (First)
Result=CpuError(ResParams->Data[0]);
else
Result=errCliPartialDataWritten;
};
Offset+=Size;
};
First=false;
TotElements-=NumElements;
Start+=(NumElements*WordSize);
}
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opReadMultiVars()
{
PS7DataItem Item;
PReqFunReadParams ReqParams;
PS7ResHeader23 Answer;
PResFunReadParams ResParams;
TResFunReadData ResData;
word RPSize; // ReqParams size
uintptr_t Offset =0 ;
word Slice;
longword Address;
int IsoSize;
pbyte P;
int ItemsCount, c, Result;
Item = PS7DataItem(Job.pData);
ItemsCount = Job.Amount;
// Some useful initial check to detail the errors (Since S7 CPU always answers
// with $05 if (something is wrong in params)
if (ItemsCount>MaxVars)
return errCliTooManyItems;
// Adjusts Word Length in case of timers and counters and clears results
for (c = 0; c < ItemsCount; c++)
{
Item->Result=0;
if (Item->Area==S7AreaCT)
Item->WordLen=S7WLCounter;
if (Item->Area==S7AreaTM)
Item->WordLen=S7WLTimer;
Item++;
};
// Let's build the PDU
RPSize = word(2 + ItemsCount * sizeof(TReqFunReadItem));
ReqParams = PReqFunReadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer = PS7ResHeader23(&PDU.Payload);
ResParams = PResFunReadParams(pbyte(Answer)+ResHeaderSize23);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(RPSize); // Request params size
PDUH_out->DataLen=0x0000; // No data in output
// Fill Params
ReqParams->FunRead=pduFuncRead; // 0x04
ReqParams->ItemsCount=ItemsCount;
Item = PS7DataItem(Job.pData);
for (c = 0; c < ItemsCount; c++)
{
ReqParams->Items[c].ItemHead[0]=0x12;
ReqParams->Items[c].ItemHead[1]=0x0A;
ReqParams->Items[c].ItemHead[2]=0x10;
ReqParams->Items[c].TransportSize=Item->WordLen;
ReqParams->Items[c].Length=SwapWord(Item->Amount);
ReqParams->Items[c].Area=Item->Area;
// Automatically drops DBNumber if (Area is not DB
if (Item->Area==S7AreaDB)
ReqParams->Items[c].DBNumber=SwapWord(Item->DBNumber);
else
ReqParams->Items[c].DBNumber=0x0000;
// Adjusts the offset
if ((Item->WordLen==S7WLBit) || (Item->WordLen==S7WLCounter) || (Item->WordLen==S7WLTimer))
Address=Item->Start;
else
Address=Item->Start*8;
// Builds the offset
ReqParams->Items[c].Address[2]=Address & 0x000000FF;
Address=Address >> 8;
ReqParams->Items[c].Address[1]=Address & 0x000000FF;
Address=Address >> 8;
ReqParams->Items[c].Address[0]=Address & 0x000000FF;
Item++;
};
IsoSize=RPSize+sizeof(TS7ReqHeader);
if (IsoSize>PDULength)
return errCliSizeOverPDU;
Result=isoExchangeBuffer(0,IsoSize);
if (Result!=0)
return Result;
// Function level error
if (Answer->Error!=0)
return CpuError(SwapWord(Answer->Error));
if (ResParams->ItemCount!=ItemsCount)
return errCliInvalidPlcAnswer;
P=pbyte(ResParams)+sizeof(TResFunReadParams);
Item = PS7DataItem(Job.pData);
for (c = 0; c < ItemsCount; c++)
{
ResData[c] =PResFunReadItem(pbyte(P)+Offset);
Slice=0;
// Item level error
if (ResData[c]->ReturnCode==0xFF) // <-- 0xFF means Result OK
{
// Calcs data size in bytes
Slice=SwapWord(ResData[c]->DataLength);
// Adjust Size in accord of TransportSize
if ((ResData[c]->TransportSize != TS_ResOctet) && (ResData[c]->TransportSize != TS_ResReal) && (ResData[c]->TransportSize != TS_ResBit))
Slice=Slice >> 3;
memcpy(Item->pdata, ResData[c]->Data, Slice);
Item->Result=0;
}
else
Item->Result=CpuError(ResData[c]->ReturnCode);
if ((Slice % 2)!=0)
Slice++; // Skip fill byte for Odd frame
Offset+=(4+Slice);
Item++;
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opWriteMultiVars()
{
PS7DataItem Item;
PReqFunWriteParams ReqParams;
PResFunWrite ResParams;
TReqFunWriteData ReqData;
PS7ResHeader23 Answer;
pbyte P;
uintptr_t Offset;
longword Address;
int ItemsCount, c, IsoSize;
word RPSize; // ReqParams size
word Size; // Write data size
int WordSize, Result;
Item = PS7DataItem(Job.pData);
ItemsCount = Job.Amount;
// Some useful initial check to detail the errors (Since S7 CPU always answers
// with $05 if (something is wrong in params)
if (ItemsCount>MaxVars)
return errCliTooManyItems;
// Adjusts Word Length in case of timers and counters and clears results
for (c = 0; c < ItemsCount; c++)
{
Item->Result=0;
if (Item->Area==S7AreaCT)
Item->WordLen=S7WLCounter;
if (Item->Area==S7AreaTM)
Item->WordLen=S7WLTimer;
Item++;
};
// Let's build the PDU : setup pointers
RPSize = word(2 + ItemsCount * sizeof(TReqFunWriteItem));
ReqParams = PReqFunWriteParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer = PS7ResHeader23(&PDU.Payload);
ResParams = PResFunWrite(pbyte(Answer)+ResHeaderSize23);
P=pbyte(ReqParams)+RPSize;
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(RPSize); // Request params size
// Fill Params
ReqParams->FunWrite=pduFuncWrite; // 0x05
ReqParams->ItemsCount=ItemsCount;
Offset=0;
Item = PS7DataItem(Job.pData);
for (c = 0; c < ItemsCount; c++)
{
// Items Params
ReqParams->Items[c].ItemHead[0]=0x12;
ReqParams->Items[c].ItemHead[1]=0x0A;
ReqParams->Items[c].ItemHead[2]=0x10;
ReqParams->Items[c].TransportSize=Item->WordLen;
ReqParams->Items[c].Length=SwapWord(Item->Amount);
ReqParams->Items[c].Area=Item->Area;
if (Item->Area==S7AreaDB)
ReqParams->Items[c].DBNumber=SwapWord(Item->DBNumber);
else
ReqParams->Items[c].DBNumber=0x0000;
// Adjusts the offset
if ((Item->WordLen==S7WLBit) || (Item->WordLen==S7WLCounter) || (Item->WordLen==S7WLTimer))
Address=Item->Start;
else
Address=Item->Start*8;
// Builds the offset
ReqParams->Items[c].Address[2]=Address & 0x000000FF;
Address=Address >> 8;
ReqParams->Items[c].Address[1]=Address & 0x000000FF;
Address=Address >> 8;
ReqParams->Items[c].Address[0]=Address & 0x000000FF;
// Items Data
ReqData[c]=PReqFunWriteDataItem(pbyte(P)+Offset);
ReqData[c]->ReturnCode=0x00;
switch (Item->WordLen)
{
case S7WLBit :
ReqData[c]->TransportSize=TS_ResBit;
break;
case S7WLInt :
case S7WLDInt :
ReqData[c]->TransportSize=TS_ResInt;
break;
case S7WLReal :
ReqData[c]->TransportSize=TS_ResReal;
break;
case S7WLChar :
case S7WLCounter :
case S7WLTimer : ReqData[c]->TransportSize=TS_ResOctet;
break;
default :
ReqData[c]->TransportSize=TS_ResByte; // byte/word/dword etc.
break;
};
WordSize=DataSizeByte(Item->WordLen);
Size=Item->Amount * WordSize;
if ((ReqData[c]->TransportSize!=TS_ResOctet) && (ReqData[c]->TransportSize!=TS_ResReal) && (ReqData[c]->TransportSize!=TS_ResBit))
ReqData[c]->DataLength=SwapWord(Size*8);
else
ReqData[c]->DataLength=SwapWord(Size);
memcpy(ReqData[c]->Data, Item->pdata, Size);
if ((Size % 2) != 0 && (ItemsCount - c != 1))
Size++; // Skip fill byte for Odd frame (except for the last one)
Offset+=(4+Size); // next item
Item++;
};
PDUH_out->DataLen=SwapWord(word(Offset));
IsoSize=RPSize+sizeof(TS7ReqHeader)+int(Offset);
if (IsoSize>PDULength)
return errCliSizeOverPDU;
Result=isoExchangeBuffer(0,IsoSize);
if (Result!=0)
return Result;
// Function level error
if (Answer->Error!=0)
return CpuError(SwapWord(Answer->Error));
if (ResParams->ItemCount!=ItemsCount)
return errCliInvalidPlcAnswer;
Item = PS7DataItem(Job.pData);
for (c = 0; c < ItemsCount; c++)
{
// Item level error
if (ResParams->Data[c]==0xFF) // <-- 0xFF means Result OK
Item->Result=0;
else
Item->Result=CpuError(ResParams->Data[c]);
Item++;
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opListBlocks()
{
PReqFunGetBlockInfo ReqParams;
PReqDataFunBlocks ReqData;
PResFunGetBlockInfo ResParams;
PDataFunListAll ResData;
PS7ResHeader17 Answer;
PS7BlocksList List;
int IsoSize, Result;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunGetBlockInfo(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ReqData =PReqDataFunBlocks(pbyte(ReqParams)+sizeof(TReqFunGetBlockInfo));
Answer =PS7ResHeader17(&PDU.Payload);
ResParams=PResFunGetBlockInfo(pbyte(Answer)+ResHeaderSize17);
ResData =PDataFunListAll(pbyte(ResParams)+sizeof(TResFunGetBlockInfo));
List =PS7BlocksList(Job.pData);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 0x07
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunGetBlockInfo)); // 8 bytes params
PDUH_out->DataLen=SwapWord(sizeof(TReqDataFunBlocks)); // 4 bytes data
// Fill params (mostly constants)
ReqParams->Head[0]=0x00;
ReqParams->Head[1]=0x01;
ReqParams->Head[2]=0x12;
ReqParams->Plen =0x04;
ReqParams->Uk =0x11;
ReqParams->Tg =grBlocksInfo;
ReqParams->SubFun =SFun_ListAll;
ReqParams->Seq =0x00;
// Fill data
ReqData[0] =0x0A;
ReqData[1] =0x00;
ReqData[2] =0x00;
ReqData[3] =0x00;
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunGetBlockInfo)+sizeof(TReqDataFunBlocks);
Result=isoExchangeBuffer(0,IsoSize);
// Get Data
if (Result==0)
{
if (ResParams->ErrNo==0)
{
if (SwapWord(ResData->Length)!=28)
return errCliInvalidPlcAnswer;
for (int c = 0; c < 7; c++)
{
switch (ResData->Blocks[c].BType)
{
case Block_OB:
List->OBCount=SwapWord(ResData->Blocks[c].BCount);
break;
case Block_DB:
List->DBCount=SwapWord(ResData->Blocks[c].BCount);
break;
case Block_SDB:
List->SDBCount=SwapWord(ResData->Blocks[c].BCount);
break;
case Block_FC:
List->FCCount=SwapWord(ResData->Blocks[c].BCount);
break;
case Block_SFC:
List->SFCCount=SwapWord(ResData->Blocks[c].BCount);
break;
case Block_FB:
List->FBCount=SwapWord(ResData->Blocks[c].BCount);
break;
case Block_SFB:
List->SFBCount=SwapWord(ResData->Blocks[c].BCount);
break;
}
}
}
else
Result=CpuError(SwapWord(ResParams->ErrNo));
}
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opListBlocksOfType()
{
PReqFunGetBlockInfo ReqParams;
PReqDataBlockOfType ReqData;
PS7ResHeader17 Answer;
PResFunGetBlockInfo ResParams;
PDataFunGetBot ResData;
longword *PadData;
word *List;
bool First;
bool Done = false;
byte BlockType, In_Seq;
int Count, Last, IsoSize, Result;
int c, CThis;
word DataLength;
bool RoomError = false;
BlockType=Job.Area;
List=(word*)(&opData);
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunGetBlockInfo(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader17(&PDU.Payload);
ResParams=PResFunGetBlockInfo(pbyte(Answer)+ResHeaderSize17);
ResData =PDataFunGetBot(pbyte(ResParams)+sizeof(TResFunGetBlockInfo));
// Get Data
First =true;
In_Seq=0x00; // first group sequence, next will come from PLC
Count =0;
Last =0;
do
{
//<--------------------------------------------------------- Get next slice
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 0x07
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
if (First)
{
PDUH_out->ParLen=SwapWord(8); // 8 bytes params
PDUH_out->DataLen=SwapWord(6); // 6 bytes data
DataLength=14;
}
else
{
PDUH_out->ParLen=SwapWord(12); // 12 bytes params
PDUH_out->DataLen=SwapWord(4); // 4 bytes data
DataLength=16;
}
// Fill params (mostly constants)
ReqParams->Head[0]=0x00;
ReqParams->Head[1]=0x01;
ReqParams->Head[2]=0x12;
if (First)
ReqParams->Plen =0x04;
else
ReqParams->Plen =0x08;
if (First)
ReqParams->Uk = 0x11;
else
ReqParams->Uk = 0x12;
ReqParams->Tg =grBlocksInfo;
ReqParams->SubFun =SFun_ListBoT;
ReqParams->Seq =In_Seq;
// Fill data
if (First)
{
// overlap resvd and error to avoid another struct...
ReqData =PReqDataBlockOfType(pbyte(ReqParams)+sizeof(TReqFunGetBlockInfo));
ReqData->RetVal =0xFF;
ReqData->TSize =TS_ResOctet;
ReqData->Length =SwapWord(0x0002);
ReqData->Zero =0x30; // zero ascii '0'
ReqData->BlkType =BlockType;
}
else
{
PadData =(longword*)(pbyte(ReqParams)+sizeof(TReqFunGetBlockInfo));
ReqData =PReqDataBlockOfType(pbyte(ReqParams)+sizeof(TReqFunGetBlockInfo)+4);
*PadData =0x00000000;
ReqData->RetVal =0x0A;
ReqData->TSize =0x00;
ReqData->Length =0x0000;
ReqData->Zero =0x00;
ReqData->BlkType =0x00;
};
IsoSize=sizeof(TS7ReqHeader)+DataLength;
Result=isoExchangeBuffer(0,IsoSize);
if (Result==0)
{
if (ResParams->ErrNo==0)
{
if (ResData->RetVal==0xFF)
{
Done=((ResParams->Rsvd & 0xFF00) == 0); // Low order byte = 0x00 => the sequence is done
In_Seq=ResParams->Seq; // every next telegram must have this number
CThis=((SwapWord(ResData->DataLen) - 4 ) / 4) + 1; // Partial counter
for (c=0; c < CThis+1; c++)
{
*List=SwapWord(ResData->Items[c].BlockNum);
Last++;
List++;
if (Last==0x8000)
{
Done=true;
break;
};
};
Count+=CThis; // Total counter
List--;
}
else
Result=errCliItemNotAvailable;
}
else
Result=errCliItemNotAvailable;
};
First=false;
//---------------------------------------------------------> Get next slice
}
while ((!Done) && (Result==0));
*Job.pAmount=0;
if (Result==0)
{
if (Count>Job.Amount)
{
Count=Job.Amount;
RoomError=true;
}
memcpy(Job.pData, &opData, Count*2);
*Job.pAmount=Count;
if (RoomError) // Result==0 -> override if romerror
Result=errCliPartialDataRead;
};
return Result;
}
//---------------------------------------------------------------------------
void TSnap7MicroClient::FillTime(word SiemensTime, char *PTime)
{
// SiemensTime -> number of seconds after 1/1/1984
// This is not S7 date and time but is used only internally for block info
time_t TheDate = (SiemensTime * 86400)+ DeltaSecs;
struct tm timeinfo;
if (localtime_s(&timeinfo,&TheDate)==0) {
strftime(PTime,11,"%Y/%m/%d",&timeinfo);
}
else
*PTime='\0';
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opAgBlockInfo()
{
PS7BlockInfo BlockInfo;
PReqFunGetBlockInfo ReqParams;
PReqDataBlockInfo ReqData;
PS7ResHeader17 Answer;
PResFunGetBlockInfo ResParams;
PResDataBlockInfo ResData;
byte BlockType;
int BlockNum, IsoSize, Result;
BlockType=Job.Area;
BlockNum =Job.Number;
BlockInfo=PS7BlockInfo(Job.pData);
memset(BlockInfo,0,sizeof(TS7BlockInfo));
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunGetBlockInfo(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ReqData =PReqDataBlockInfo(pbyte(ReqParams)+sizeof(TReqFunGetBlockInfo));
Answer =PS7ResHeader17(&PDU.Payload);
ResParams=PResFunGetBlockInfo(pbyte(Answer)+ResHeaderSize17);
ResData =PResDataBlockInfo(pbyte(ResParams)+sizeof(TResFunGetBlockInfo));
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 0x07
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunGetBlockInfo)); // 8 bytes params
PDUH_out->DataLen=SwapWord(sizeof(TReqDataBlockInfo)); // 4 bytes data
// Fill params (mostly constants)
ReqParams->Head[0]=0x00;
ReqParams->Head[1]=0x01;
ReqParams->Head[2]=0x12;
ReqParams->Plen =0x04;
ReqParams->Uk =0x11;
ReqParams->Tg =grBlocksInfo;
ReqParams->SubFun =SFun_BlkInfo;
ReqParams->Seq =0x00;
// Fill data
ReqData->RetVal =0xFF;
ReqData->TSize =TS_ResOctet;
ReqData->DataLen =SwapWord(0x0008);
ReqData->BlkPrfx =0x30;
ReqData->BlkType =BlockType;
ReqData->A =0x41;
ReqData->AsciiBlk[0]=(BlockNum / 10000)+0x30;
BlockNum=BlockNum % 10000;
ReqData->AsciiBlk[1]=(BlockNum / 1000)+0x30;
BlockNum=BlockNum % 1000;
ReqData->AsciiBlk[2]=(BlockNum / 100)+0x30;
BlockNum=BlockNum % 100;
ReqData->AsciiBlk[3]=(BlockNum / 10)+0x30;
BlockNum=BlockNum % 10;
ReqData->AsciiBlk[4]=(BlockNum / 1)+0x30;
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunGetBlockInfo)+sizeof(TReqDataBlockInfo);
Result=isoExchangeBuffer(0,IsoSize);
// Get Data
if (Result==0)
{
if (ResParams->ErrNo==0)
{
if (SwapWord(ResData->Length)<40) // 78
return errCliInvalidPlcAnswer;
if (ResData->RetVal==0xFF) // <-- 0xFF means Result OK
{
//<----------------------------------------------Fill block info
BlockInfo->BlkType=ResData->SubBlkType;
BlockInfo->BlkNumber=SwapWord(ResData->BlkNumber);
BlockInfo->BlkLang=ResData->BlkLang;
BlockInfo->BlkFlags=ResData->BlkFlags;
BlockInfo->MC7Size=SwapWord(ResData->MC7Len);
BlockInfo->LoadSize=SwapDWord(ResData->LenLoadMem);
BlockInfo->LocalData=SwapWord(ResData->LocDataLen);
BlockInfo->SBBLength=SwapWord(ResData->SbbLen);
BlockInfo->CheckSum=SwapWord(ResData->BlkChksum);
BlockInfo->Version=ResData->Version;
memcpy(BlockInfo->Author, ResData->Author, 8);
memcpy(BlockInfo->Family,ResData->Family,8);
memcpy(BlockInfo->Header,ResData->Header,8);
FillTime(SwapWord(ResData->CodeTime_dy),BlockInfo->CodeDate);
FillTime(SwapWord(ResData->IntfTime_dy),BlockInfo->IntfDate);
//---------------------------------------------->Fill block info
}
else
Result=CpuError(ResData->RetVal);
}
else
Result=CpuError(SwapWord(ResParams->ErrNo));
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opDBGet()
{
TS7BlockInfo BI;
void * usrPData;
int * usrPSize;
int Result, Room;
bool RoomError = false;
// Stores user pointer
usrPData=Job.pData;
usrPSize=Job.pAmount;
Room =Job.Amount;
// 1 Pass : Get block info
Job.Area=Block_DB;
Job.pData=&BI;
Result=opAgBlockInfo();
// 2 Pass : Read the whole (MC7Size bytes) DB.
if (Result==0)
{
// Check user space
if (BI.MC7Size>Room)
{
Job.Amount=Room;
RoomError=true;
}
else
Job.Amount =BI.MC7Size;
// The data is read even if the buffer is small (the error is reported).
// Imagine that we want to read only a small amount of data at the
// beginning of a DB regardless it's size....
Job.Area =S7AreaDB;
Job.WordLen=S7WLByte;
Job.Start =0;
Job.pData =usrPData;
Result =opReadArea();
if (Result==0)
*usrPSize=Job.Amount;
}
if ((Result==0) && RoomError)
return errCliBufferTooSmall;
else
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opDBFill()
{
TS7BlockInfo BI;
int Result;
// new op : get block info
Job.Op =s7opAgBlockInfo;
Job.Area =Block_DB;
Job.pData=&BI;
Result =opAgBlockInfo();
// Restore original op
Job.Op =s7opDBFill;
// Fill internal buffer then write it
if (Result==0)
{
Job.Amount =BI.MC7Size;
Job.Area =S7AreaDB;
Job.WordLen=S7WLByte;
Job.Start =0;
memset(&opData, byte(Job.IParam), Job.Amount);
Job.pData =&opData;
Result =opWriteArea();
}
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opUpload()
{
PS7ResHeader23 Answer;
int IsoSize;
byte Upload_ID = 0; // not strictly needed, only to avoid warning
byte BlockType;
int BlockNum, BlockLength, Result;
bool Done, Full; // if full==true, the data will be compatible to full download function
uintptr_t Offset;
bool RoomError = false;
BlockType=Job.Area;
BlockNum =Job.Number;
Full =Job.IParam==1;
// Setup Answer (is the same for all Upload pdus)
Answer= PS7ResHeader23(&PDU.Payload);
// Init sequence
Done =false;
Offset=0;
//<-------------------------------------------------------------StartUpload
PReqFunStartUploadParams ReqParams;
PResFunStartUploadParams ResParams;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunStartUploadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ResParams=PResFunStartUploadParams(pbyte(Answer)+ResHeaderSize23);
// Init Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunStartUploadParams));// params size
PDUH_out->DataLen=0x0000; // No data
// Init Params
ReqParams->FunSUpld=pduStartUpload;
ReqParams->Uk6[0]=0x00;
ReqParams->Uk6[1]=0x00;
ReqParams->Uk6[2]=0x00;
ReqParams->Uk6[3]=0x00;
ReqParams->Uk6[4]=0x00;
ReqParams->Uk6[5]=0x00;
ReqParams->Upload_ID=Upload_ID; // At begining is 0) we will put upload id incoming from plc
ReqParams->Len_1 =0x09; // 9 bytes from here
ReqParams->Prefix=0x5F;
ReqParams->BlkPrfx=0x30; // '0'
ReqParams->BlkType=BlockType;
// Block number
ReqParams->AsciiBlk[0]=(BlockNum / 10000)+0x30;
BlockNum=BlockNum % 10000;
ReqParams->AsciiBlk[1]=(BlockNum / 1000)+0x30;
BlockNum=BlockNum % 1000;
ReqParams->AsciiBlk[2]=(BlockNum / 100)+0x30;
BlockNum=BlockNum % 100;
ReqParams->AsciiBlk[3]=(BlockNum / 10)+0x30;
BlockNum=BlockNum % 10;
ReqParams->AsciiBlk[4]=(BlockNum / 1)+0x30;
ReqParams->A=0x41; // 'A'
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunStartUploadParams);
Result=isoExchangeBuffer(0,IsoSize);
// Get Upload Infos (only ID now)
if (Result==0)
{
if (Answer->Error==0)
Upload_ID=ResParams->Upload_ID;
else
Result=CpuError(SwapWord(Answer->Error));
};
//------------------------------------------------------------->StartUpload
if (Result==0)
{
//<--------------------------------------------------------FirstUpload
PReqFunUploadParams ReqParams;
PResFunUploadParams ResParams;
PResFunUploadDataHeaderFirst ResDataHeader;
pbyte Source;
pbyte Target;
int Size;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunUploadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
// First upload pdu consists of params, block info header, data.
ResParams=PResFunUploadParams(pbyte(Answer)+ResHeaderSize23);
ResDataHeader=PResFunUploadDataHeaderFirst(pbyte(ResParams)+sizeof(TResFunUploadParams));
if (Full)
Source=pbyte(ResDataHeader)+4; // skip only the mini header
else
Source=pbyte(ResDataHeader)+sizeof(TResFunUploadDataHeaderFirst); // not full : skip the data header
// Init Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunUploadParams));// params size
PDUH_out->DataLen=0x0000; // No data
// Init Params
ReqParams->FunUpld=pduUpload;
ReqParams->Uk6[0]=0x00;
ReqParams->Uk6[1]=0x00;
ReqParams->Uk6[2]=0x00;
ReqParams->Uk6[3]=0x00;
ReqParams->Uk6[4]=0x00;
ReqParams->Uk6[5]=0x00;
ReqParams->Upload_ID=Upload_ID; // At begining is 0) we will put upload id incoming from plc
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunUploadParams);
Result=isoExchangeBuffer(0,IsoSize);
// Get Upload Infos (only ID now)
if (Result==0)
{
if (Answer->Error==0)
{
Done=ResParams->EoU==0;
if (Full)
Size=SwapWord(Answer->DataLen)-4; // Full data Size
else
Size=SwapWord(Answer->DataLen)-sizeof(TResFunUploadDataHeaderFirst); // Size of this data slice
BlockLength=SwapWord(ResDataHeader->MC7Len); // Full block size in byte
Target=pbyte(&opData)+Offset;
memcpy(Target, Source, Size);
Offset+=Size;
}
else
Result=errCliUploadSequenceFailed;
};
//-------------------------------------------------------->FirstUpload
while (!Done && (Result==0))
{
//<----------------------------------------------------NextUpload
PReqFunUploadParams ReqParams;
PResFunUploadParams ResParams;
PResFunUploadDataHeaderNext ResDataHeader;
pbyte Source;
pbyte Target;
int Size;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunUploadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
// Next upload pdu consists of params, small info header, data.
ResParams=PResFunUploadParams(pbyte(Answer)+ResHeaderSize23);
ResDataHeader=PResFunUploadDataHeaderNext(pbyte(ResParams)+sizeof(TResFunUploadParams));
Source=pbyte(ResDataHeader)+sizeof(TResFunUploadDataHeaderNext);
// Init Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunUploadParams));// params size
PDUH_out->DataLen=0x0000; // No data
// Init Params
ReqParams->FunUpld=pduUpload;
ReqParams->Uk6[0]=0x00;
ReqParams->Uk6[1]=0x00;
ReqParams->Uk6[2]=0x00;
ReqParams->Uk6[3]=0x00;
ReqParams->Uk6[4]=0x00;
ReqParams->Uk6[5]=0x00;
ReqParams->Upload_ID=Upload_ID; // At begining is 0) we will put upload id incoming from plc
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunUploadParams);
Result=isoExchangeBuffer(0,IsoSize);
// Get Upload Infos (only ID now)
if (Result==0)
{
if (Answer->Error==0)
{
Done=ResParams->EoU==0;
Size=SwapWord(Answer->DataLen)-sizeof(TResFunUploadDataHeaderNext); // Size of this data slice
Target=pbyte(&opData)+Offset;
memcpy(Target, Source, Size);
Offset+=Size;
}
else
Result=errCliUploadSequenceFailed;
};
//---------------------------------------------------->NextUpload
}
if (Result==0)
{
//<----------------------------------------------------EndUpload;
PReqFunEndUploadParams ReqParams;
PResFunEndUploadParams ResParams;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunEndUploadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ResParams=PResFunEndUploadParams(pbyte(Answer)+ResHeaderSize23);
// Init Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunEndUploadParams));// params size
PDUH_out->DataLen=0x0000; // No data
// Init Params
ReqParams->FunEUpld=pduEndUpload;
ReqParams->Uk6[0]=0x00;
ReqParams->Uk6[1]=0x00;
ReqParams->Uk6[2]=0x00;
ReqParams->Uk6[3]=0x00;
ReqParams->Uk6[4]=0x00;
ReqParams->Uk6[5]=0x00;
ReqParams->Upload_ID=Upload_ID; // At begining is 0) we will put upload id incoming from plc
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunEndUploadParams);
Result=isoExchangeBuffer(0,IsoSize);
// Get EndUpload Result
if (Result==0)
{
if ((Answer->Error!=0) || (ResParams->FunEUpld!=pduEndUpload))
Result=errCliUploadSequenceFailed;
};
//---------------------------------------------------->EndUpload;
}
};
*Job.pAmount=0;
if (Result==0)
{
if (Full)
{
opSize=int(Offset);
if (opSize<78)
Result=errCliInvalidDataSizeRecvd;
}
else
{
opSize=BlockLength;
if (opSize<1)
Result=errCliInvalidDataSizeRecvd;
};
if (Result==0)
{
// Checks user space
if (Job.Amount<opSize) {
opSize=Job.Amount;
RoomError = true;
};
memcpy(Job.pData, &opData, opSize);
*Job.pAmount=opSize;
if (RoomError) // Result==0 -> override if romerror
Result=errCliPartialDataRead;
};
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opDownload()
{
PS7CompactBlockInfo Info;
PS7BlockFooter Footer;
int BlockNum, StoreBlockNum, BlockAmount;
int BlockSize, BlockSizeLd;
int BlockType, Remainder;
int Result, IsoSize;
bool Done = false;
uintptr_t Offset;
BlockAmount=Job.Amount;
BlockNum =Job.Number;
Result=CheckBlock(-1,-1,&opData,BlockAmount);
if (Result==0)
{
Info=PS7CompactBlockInfo(&opData);
// Gets blocktype
BlockType=SubBlockToBlock(Info->SubBlkType);
if (BlockNum>=0)
Info->BlkNum=SwapWord(BlockNum); // change the number
else
BlockNum=SwapWord(Info->BlkNum); // use the header's number
BlockSizeLd=BlockAmount; // load mem needed for this block
BlockSize =SwapWord(Info->MC7Len); // net size
Footer=PS7BlockFooter(pbyte(&opData)+BlockSizeLd-sizeof(TS7BlockFooter));
Footer->Chksum=0x0000;
Offset=0;
Remainder=BlockAmount;
//<---------------------------------------------- Start Download request
PReqStartDownloadParams ReqParams;
PResStartDownloadParams ResParams;
PS7ResHeader23 Answer;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqStartDownloadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResStartDownloadParams(pbyte(Answer)+ResHeaderSize23);
// Init Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqStartDownloadParams));
PDUH_out->DataLen=0x0000; // No data
// Init Params
ReqParams->FunSDwnld = pduReqDownload;
ReqParams->Uk6[0]=0x00;
ReqParams->Uk6[1]=0x01;
ReqParams->Uk6[2]=0x00;
ReqParams->Uk6[3]=0x00;
ReqParams->Uk6[4]=0x00;
ReqParams->Uk6[5]=0x00;
ReqParams->Dwnld_ID=0x00;
ReqParams->Len_1 =0x09;
ReqParams->Prefix=0x5F;
ReqParams->BlkPrfx=0x30;
ReqParams->BlkType=BlockType;
StoreBlockNum=BlockNum;
ReqParams->AsciiBlk[0]=(BlockNum / 10000)+0x30;
BlockNum=BlockNum % 10000;
ReqParams->AsciiBlk[1]=(BlockNum / 1000)+0x30;
BlockNum=BlockNum % 1000;
ReqParams->AsciiBlk[2]=(BlockNum / 100)+0x30;
BlockNum=BlockNum % 100;
ReqParams->AsciiBlk[3]=(BlockNum / 10)+0x30;
BlockNum=BlockNum % 10;
ReqParams->AsciiBlk[4]=(BlockNum / 1)+0x30;
ReqParams->P =0x50;
ReqParams->Len_2=0x0D;
ReqParams->Uk1 =0x31; // '1'
BlockNum=StoreBlockNum;
// Load memory
ReqParams->AsciiLoad[0]=(BlockSizeLd / 100000)+0x30;
BlockSizeLd=BlockSizeLd % 100000;
ReqParams->AsciiLoad[1]=(BlockSizeLd / 10000)+0x30;
BlockSizeLd=BlockSizeLd % 10000;
ReqParams->AsciiLoad[2]=(BlockSizeLd / 1000)+0x30;
BlockSizeLd=BlockSizeLd % 1000;
ReqParams->AsciiLoad[3]=(BlockSizeLd / 100)+0x30;
BlockSizeLd=BlockSizeLd % 100;
ReqParams->AsciiLoad[4]=(BlockSizeLd / 10)+0x30;
BlockSizeLd=BlockSizeLd % 10;
ReqParams->AsciiLoad[5]=(BlockSizeLd / 1)+0x30;
// MC7 memory
ReqParams->AsciiMC7[0]=(BlockSize / 100000)+0x30;
BlockSize=BlockSize % 100000;
ReqParams->AsciiMC7[1]=(BlockSize / 10000)+0x30;
BlockSize=BlockSize % 10000;
ReqParams->AsciiMC7[2]=(BlockSize / 1000)+0x30;
BlockSize=BlockSize % 1000;
ReqParams->AsciiMC7[3]=(BlockSize / 100)+0x30;
BlockSize=BlockSize % 100;
ReqParams->AsciiMC7[4]=(BlockSize / 10)+0x30;
BlockSize=BlockSize % 10;
ReqParams->AsciiMC7[5]=(BlockSize / 1)+0x30;
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqStartDownloadParams);
Result=isoExchangeBuffer(0,IsoSize);
// Get Result
if (Result==0)
{
if (SwapWord(Answer->Error)!=Code7NeedPassword)
{
if ((Answer->Error!=0) || (*ResParams!=pduReqDownload))
Result=errCliDownloadSequenceFailed;
}
else
Result=errCliNeedPassword;
}
//----------------------------------------------> Start Download request
if (Result==0)
{
do
{
//<-------------------------------- Download sequence (PLC requests)
PReqDownloadParams ReqParams;
PS7ResHeader23 Answer;
PResDownloadParams ResParams;
PResDownloadDataHeader ResData;
int Slice, Size, MaxSlice;
word Sequence;
pbyte Source;
pbyte Target;
ReqParams=PReqDownloadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResDownloadParams(pbyte(Answer)+ResHeaderSize23);
ResData =PResDownloadDataHeader(pbyte(ResParams)+sizeof(TResDownloadParams));
Target =pbyte(ResData)+sizeof(TResDownloadDataHeader);
Source =pbyte(&opData)+Offset;
Result=isoRecvBuffer(0,Size);
if (Result==0)
{
if ((u_int(Size)>sizeof(TS7ReqHeader)) && (ReqParams->Fun==pduDownload))
{
Sequence=PDUH_out->Sequence;
// Max data slice that we can fit in this pdu
MaxSlice=PDULength-ResHeaderSize23-sizeof(TResDownloadParams)-sizeof(TResDownloadDataHeader);
Slice=Remainder;
if (Slice>MaxSlice)
Slice=MaxSlice;
Remainder-=Slice;
Offset+=Slice;
Done=Remainder<=0;
// Init Answer
Answer->P=0x32;
Answer->PDUType=PduType_response;
Answer->AB_EX=0x0000;
Answer->Sequence=Sequence;
Answer->ParLen =SwapWord(sizeof(TResDownloadParams));
Answer->DataLen=SwapWord(word(sizeof(TResDownloadDataHeader))+Slice);
Answer->Error =0x0000;
// Init Params
ResParams->FunDwnld=pduDownload;
if (Remainder>0)
ResParams->EoS=0x01;
else
ResParams->EoS=0x00;
// Init Data
ResData->DataLen=SwapWord(Slice);
ResData->FB_00=0xFB00;
memcpy(Target, Source, Slice);
// Send the slice
IsoSize=ResHeaderSize23+sizeof(TResDownloadParams)+sizeof(TResDownloadDataHeader)+Slice;
Result=isoSendBuffer(0,IsoSize);
}
else
Result=errCliDownloadSequenceFailed;
};
//--------------------------------> Download sequence (PLC requests)
}
while (!Done && (Result==0));
if (Result==0)
{
//<-------------------------------------------Perform Download Ended
PReqDownloadParams ReqParams;
PS7ResHeader23 Answer;
PResEndDownloadParams ResParams;
int Size;
word Sequence;
ReqParams=PReqDownloadParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResEndDownloadParams(pbyte(Answer)+ResHeaderSize23);
Result=isoRecvBuffer(0,Size);
if (Result==0)
{
if ((u_int(Size)>sizeof(TS7ReqHeader)) && (ReqParams->Fun==pduDownloadEnded))
{
Sequence=PDUH_out->Sequence;
// Init Answer
Answer->P=0x32;
Answer->PDUType=PduType_response;
Answer->AB_EX=0x0000;
Answer->Sequence=Sequence;
Answer->ParLen =SwapWord(sizeof(TResEndDownloadParams));
Answer->DataLen=0x0000;
Answer->Error =0x0000;
// Init Params
*ResParams=pduDownloadEnded;
IsoSize=ResHeaderSize23+sizeof(TResEndDownloadParams);
Result=isoSendBuffer(0,IsoSize);
}
else
Result=errCliDownloadSequenceFailed;
};
//------------------------------------------->Perform Download Ended
if (Result==0)
{
//<----------------------------------- Insert block into the unit
PReqControlBlockParams ReqParams;
PS7ResHeader23 Answer;
pbyte ResParams;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqControlBlockParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer=PS7ResHeader23(&PDU.Payload);
ResParams=pbyte(Answer)+ResHeaderSize23;
// Init Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqControlBlockParams));
PDUH_out->DataLen=0x0000; // No data
// Init Params
ReqParams->Fun = pduControl;
ReqParams->Uk7[0]=0x00;
ReqParams->Uk7[1]=0x00;
ReqParams->Uk7[2]=0x00;
ReqParams->Uk7[3]=0x00;
ReqParams->Uk7[4]=0x00;
ReqParams->Uk7[5]=0x00;
ReqParams->Uk7[6]=0xFD;
ReqParams->Len_1 =SwapWord(0x0A);
ReqParams->NumOfBlocks=0x01;
ReqParams->ByteZero =0x00;
ReqParams->AsciiZero =0x30;
ReqParams->BlkType=BlockType;
ReqParams->AsciiBlk[0]=(BlockNum / 10000)+0x30;
BlockNum=BlockNum % 10000;
ReqParams->AsciiBlk[1]=(BlockNum / 1000)+0x30;
BlockNum=BlockNum % 1000;
ReqParams->AsciiBlk[2]=(BlockNum / 100)+0x30;
BlockNum=BlockNum % 100;
ReqParams->AsciiBlk[3]=(BlockNum / 10)+0x30;
BlockNum=BlockNum % 10;
ReqParams->AsciiBlk[4]=(BlockNum / 1)+0x30;
ReqParams->SFun =SFun_Insert;
ReqParams->Len_2=0x05;
ReqParams->Cmd[0]='_';
ReqParams->Cmd[1]='I';
ReqParams->Cmd[2]='N';
ReqParams->Cmd[3]='S';
ReqParams->Cmd[4]='E';
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqControlBlockParams);
Result=isoExchangeBuffer(0,IsoSize);
if (Result==0)
{
if ((Answer->Error!=0) || (*ResParams!=pduControl))
Result=errCliInsertRefused;
};
//-----------------------------------> Insert block into the unit
}
};
};
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opDelete()
{
PReqControlBlockParams ReqParams;
PS7ResHeader23 Answer;
pbyte ResParams;
int IsoSize, BlockType, BlockNum, Result;
BlockType=Job.Area;
BlockNum =Job.Number;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqControlBlockParams(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=pbyte(Answer)+ResHeaderSize23;
// Init Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqControlBlockParams));
PDUH_out->DataLen=0x0000; // No data
// Init Params
ReqParams->Fun = pduControl;
ReqParams->Uk7[0]=0x00;
ReqParams->Uk7[1]=0x00;
ReqParams->Uk7[2]=0x00;
ReqParams->Uk7[3]=0x00;
ReqParams->Uk7[4]=0x00;
ReqParams->Uk7[5]=0x00;
ReqParams->Uk7[6]=0xFD;
ReqParams->Len_1 =SwapWord(0x0A);
ReqParams->NumOfBlocks=0x01;
ReqParams->ByteZero =0x00;
ReqParams->AsciiZero =0x30;
ReqParams->BlkType=BlockType;
ReqParams->AsciiBlk[0]=(BlockNum / 10000)+0x30;
BlockNum=BlockNum % 10000;
ReqParams->AsciiBlk[1]=(BlockNum / 1000)+0x30;
BlockNum=BlockNum % 1000;
ReqParams->AsciiBlk[2]=(BlockNum / 100)+0x30;
BlockNum=BlockNum % 100;
ReqParams->AsciiBlk[3]=(BlockNum / 10)+0x30;
BlockNum=BlockNum % 10;
ReqParams->AsciiBlk[4]=(BlockNum / 1)+0x30;
ReqParams->SFun =SFun_Delete;
ReqParams->Len_2=0x05;
ReqParams->Cmd[0]='_';
ReqParams->Cmd[1]='D';
ReqParams->Cmd[2]='E';
ReqParams->Cmd[3]='L';
ReqParams->Cmd[4]='E';
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqControlBlockParams);
Result=isoExchangeBuffer(0,IsoSize);
if (Result==0)
{
if (SwapWord(Answer->Error)!=Code7NeedPassword)
{
if ((Answer->Error!=0) || (*ResParams!=pduControl))
Result=errCliDeleteRefused;
}
else
Result=errCliNeedPassword;
}
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opReadSZL()
{
PS7Answer17 Answer;
PReqFunReadSZLFirst ReqParamsFirst;
PReqFunReadSZLNext ReqParamsNext;
PS7ReqSZLData ReqDataFirst;
PS7ReqSZLData ReqDataNext;
PS7ResParams7 ResParams;
PS7ResSZLDataFirst ResDataFirst;
PS7ResSZLDataNext ResDataNext;
PSZL_HEADER Header;
PS7SZLList Target;
pbyte PDataFirst;
pbyte PDataNext;
word ID, Index;
int IsoSize, DataSize, DataSZL, Result;
bool First, Done;
bool NoRoom = false;
uintptr_t Offset =0;
byte Seq_in =0x00;
ID=Job.ID;
Index=Job.Index;
opSize=0;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParamsFirst=PReqFunReadSZLFirst(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ReqParamsNext =PReqFunReadSZLNext(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ReqDataFirst =PS7ReqSZLData(pbyte(ReqParamsFirst)+sizeof(TReqFunReadSZLFirst));
ReqDataNext =PS7ReqSZLData(pbyte(ReqParamsNext)+sizeof(TReqFunReadSZLNext));
Answer =PS7Answer17(&PDU.Payload);
ResParams =PS7ResParams7(pbyte(Answer)+ResHeaderSize17);
ResDataFirst =PS7ResSZLDataFirst(pbyte(ResParams)+sizeof(TS7Params7));
ResDataNext =PS7ResSZLDataNext(pbyte(ResParams)+sizeof(TS7Params7));
PDataFirst =pbyte(ResDataFirst)+8; // skip header
PDataNext =pbyte(ResDataNext)+4; // skip header
Header =PSZL_HEADER(&opData);
First=true;
Done =false;
do
{
//<------------------------------------------------------- read slices
if (First)
{
//<-------------------------------------------------- prepare first
DataSize=sizeof(TS7ReqSZLData);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 0x07
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunReadSZLFirst)); // 8 bytes params
PDUH_out->DataLen=SwapWord(DataSize); // 8/4 bytes data
// Fill Params
ReqParamsFirst->Head[0]=0x00;
ReqParamsFirst->Head[1]=0x01;
ReqParamsFirst->Head[2]=0x12;
ReqParamsFirst->Plen =0x04;
ReqParamsFirst->Uk =0x11;
ReqParamsFirst->Tg =grSZL;
ReqParamsFirst->SubFun =SFun_ReadSZL; //0x03
ReqParamsFirst->Seq =Seq_in;
// Fill Data
ReqDataFirst->Ret =0xFF;
ReqDataFirst->TS =TS_ResOctet;
ReqDataFirst->DLen =SwapWord(0x0004);
ReqDataFirst->ID =SwapWord(ID);
ReqDataFirst->Index =SwapWord(Index);
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunReadSZLFirst)+DataSize;
//--------------------------------------------------> prepare first
}
else
{
//<-------------------------------------------------- prepare next
DataSize=sizeof(TS7ReqSZLData)-4;
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 0x07
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunReadSZLNext)); // 8 bytes params
PDUH_out->DataLen=SwapWord(DataSize);// 8/4 bytes data
// Fill Params
ReqParamsNext->Head[0]=0x00;
ReqParamsNext->Head[1]=0x01;
ReqParamsNext->Head[2]=0x12;
ReqParamsNext->Plen =0x08;
ReqParamsNext->Uk =0x12;
ReqParamsNext->Tg =grSZL;
ReqParamsNext->SubFun =SFun_ReadSZL;
ReqParamsNext->Seq =Seq_in;
ReqParamsNext->Rsvd =0x0000;
ReqParamsNext->ErrNo =0x0000;
// Fill Data
ReqDataNext->Ret =0x0A;
ReqDataNext->TS =0x00;
ReqDataNext->DLen =0x0000;
ReqDataNext->ID =0x0000;
ReqDataNext->Index =0x0000;
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunReadSZLNext)+DataSize;
//--------------------------------------------------> prepare next
}
Result=isoExchangeBuffer(0,IsoSize);
// Get Data
if (Result==0)
{
if (First)
{
//<------------------------------------------ get data first
if (ResParams->Err==0)
{
if (ResDataFirst->Ret==0xFF) // <-- 0xFF means Result OK
{
// Gets Amount of this slice
DataSZL=SwapWord(ResDataFirst->DLen)-4;// Skips extra params (ID, Index ...)
// Gets end of Sequence Flag
Done=(ResParams->resvd & 0xFF00) == 0; // Low order byte = 0x00 => the sequence is done
// Gets Unit's function sequence
Seq_in=ResParams->Seq;
Target=PS7SZLList(pbyte(&opData)+Offset);
memcpy(Target, PDataFirst, DataSZL);
Offset+=DataSZL;
}
else
Result=CpuError(ResDataFirst->Ret);
}
else
Result=CpuError(ResDataFirst->Ret);
//------------------------------------------> get data first
}
else
{
//<------------------------------------------ get data next
if (ResParams->Err==0)
{
if (ResDataNext->Ret==0xFF) // <-- 0xFF means Result OK
{
// Gets Amount of this slice
DataSZL=SwapWord(ResDataNext->DLen);
// Gets end of Sequence Flag
Done=(ResParams->resvd & 0xFF00) == 0; // Low order byte = 0x00 => the sequence is done
// Gets Unit's function sequence
Seq_in=ResParams->Seq;
Target=PS7SZLList(pbyte(&opData)+Offset);
memcpy(Target, PDataNext, DataSZL);
Offset+=DataSZL;
}
else
Result=CpuError(ResDataNext->Ret);
}
else
Result=CpuError(ResDataNext->Ret);
//------------------------------------------> get data next
}
First=false;
}
//-------------------------------------------------------> read slices
}
while ((!Done) && (Result==0));
// Check errors and adjust header
if (Result==0)
{
// Adjust big endian header
Header->LENTHDR=SwapWord(Header->LENTHDR);
Header->N_DR =SwapWord(Header->N_DR);
opSize=int(Offset);
if (Job.IParam==1) // if 1 data has to be copied into user buffer
{
// Check buffer size
if (opSize>Job.Amount)
{
opSize=Job.Amount;
NoRoom=true;
}
memcpy(Job.pData, &opData, opSize);
*Job.pAmount=opSize;
};
};
if ((Result==0)&& NoRoom)
Result=errCliBufferTooSmall;
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opReadSZLList()
{
PS7SZLList usrSZLList, opDataList;
int ItemsCount, ItemsCount_in, c, Result;
bool NoRoom = false;
Job.ID =0x0000;
Job.Index =0x0000;
Job.IParam =0;
ItemsCount_in=Job.Amount; // stores the room
Job.Amount =sizeof(opData); // read into the internal buffer
Result =opReadSZL();
if (Result==0)
{
opDataList=PS7SZLList(&opData); // Source
usrSZLList=PS7SZLList(Job.pData); // Target
ItemsCount=(opSize-sizeof(SZL_HEADER)) / 2;
// Check input size
if (ItemsCount>ItemsCount_in)
{
ItemsCount=ItemsCount_in; // Trim itemscount
NoRoom=true;
}
for (c = 0; c < ItemsCount; c++)
usrSZLList->List[c]=SwapWord(opDataList->List[c]);
*Job.pAmount=ItemsCount;
}
else
*Job.pAmount=0;
if ((Result==0) && NoRoom)
Result=errCliBufferTooSmall;
return Result;
}
//---------------------------------------------------------------------------
byte TSnap7MicroClient::BCDtoByte(byte B)
{
return ((B >> 4) * 10) + (B & 0x0F);
}
//---------------------------------------------------------------------------
byte TSnap7MicroClient::WordToBCD(word Value)
{
return ((Value / 10) << 4) | (Value % 10);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opGetDateTime()
{
PTimeStruct DateTime;
PReqFunDateTime ReqParams;
PReqDataGetDateTime ReqData;
PS7ResParams7 ResParams;
PResDataGetTime ResData;
PS7ResHeader17 Answer;
int IsoSize, Result;
word AYear;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunDateTime(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ReqData =PReqDataGetDateTime(pbyte(ReqParams)+sizeof(TReqFunDateTime));
Answer =PS7ResHeader17(&PDU.Payload);
ResParams=PS7ResParams7(pbyte(Answer)+ResHeaderSize17);
ResData =PResDataGetTime(pbyte(ResParams)+sizeof(TS7Params7));
DateTime =PTimeStruct(Job.pData);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 0x07
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunDateTime)); // 8 bytes params
PDUH_out->DataLen=SwapWord(sizeof(TReqDataGetDateTime)); // 4 bytes data
// Fill params (mostly constants)
ReqParams->Head[0]=0x00;
ReqParams->Head[1]=0x01;
ReqParams->Head[2]=0x12;
ReqParams->Plen =0x04;
ReqParams->Uk =0x11;
ReqParams->Tg =grClock;
ReqParams->SubFun =SFun_ReadClock;
ReqParams->Seq =0x00;
// Fill Data
*ReqData =0x0000000A;
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunDateTime)+sizeof(TReqDataGetDateTime);
Result=isoExchangeBuffer(0,IsoSize);
// Get Data
if (Result==0)
{
if (ResParams->Err==0)
{
if (ResData->RetVal==0xFF) // <-- 0xFF means Result OK
{
// Decode Plc Date and Time
AYear=BCDtoByte(ResData->Time[0]);
if (AYear<90)
AYear=AYear+100;
DateTime->tm_year=AYear;
DateTime->tm_mon =BCDtoByte(ResData->Time[1])-1;
DateTime->tm_mday=BCDtoByte(ResData->Time[2]);
DateTime->tm_hour=BCDtoByte(ResData->Time[3]);
DateTime->tm_min =BCDtoByte(ResData->Time[4]);
DateTime->tm_sec =BCDtoByte(ResData->Time[5]);
DateTime->tm_wday=(ResData->Time[7] & 0x0F)-1;
}
else
Result=CpuError(ResData->RetVal);
}
else
Result=CpuError(ResData->RetVal);
}
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opSetDateTime()
{
PTimeStruct DateTime;
PReqFunDateTime ReqParams;
PReqDataSetTime ReqData;
PS7ResParams7 ResParams;
PS7ResHeader17 Answer;
word AYear;
int IsoSize, Result;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunDateTime(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ReqData =PReqDataSetTime(pbyte(ReqParams)+sizeof(TReqFunDateTime));
Answer =PS7ResHeader17(&PDU.Payload);
ResParams=PS7ResParams7(pbyte(Answer)+ResHeaderSize17);
DateTime =PTimeStruct(Job.pData);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 0x07
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunDateTime)); // 8 bytes params
PDUH_out->DataLen=SwapWord(sizeof(TReqDataSetTime)); // 4 bytes data
// Fill params (mostly constants)
ReqParams->Head[0]=0x00;
ReqParams->Head[1]=0x01;
ReqParams->Head[2]=0x12;
ReqParams->Plen =0x04;
ReqParams->Uk =0x11;
ReqParams->Tg =grClock;
ReqParams->SubFun =SFun_SetClock;
ReqParams->Seq =0x00;
// EncodeSiemensDateTime;
if (DateTime->tm_year<100)
AYear=DateTime->tm_year;
else
AYear=DateTime->tm_year-100;
ReqData->RetVal=0xFF;
ReqData->TSize =TS_ResOctet;
ReqData->Length=SwapWord(0x000A);
ReqData->Rsvd =0x00;
ReqData->HiYear=0x19; // *must* be 19 tough it's not the Hi part of the year...
ReqData->Time[0]=WordToBCD(AYear);
ReqData->Time[1]=WordToBCD(DateTime->tm_mon+1);
ReqData->Time[2]=WordToBCD(DateTime->tm_mday);
ReqData->Time[3]=WordToBCD(DateTime->tm_hour);
ReqData->Time[4]=WordToBCD(DateTime->tm_min);
ReqData->Time[5]=WordToBCD(DateTime->tm_sec);
ReqData->Time[6]=0;
ReqData->Time[7]=DateTime->tm_wday+1;
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunDateTime)+sizeof(TReqDataSetTime);
Result=isoExchangeBuffer(0,IsoSize);
// Get Result
if (Result==0)
{
if (ResParams->Err!=0)
Result=CpuError(SwapWord(ResParams->Err));
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opGetOrderCode()
{
PS7OrderCode OC;
int Result;
Job.ID =0x0011;
Job.Index =0x0000;
Job.IParam =0;
Result =opReadSZL();
if (Result==0)
{
OC=PS7OrderCode(Job.pData);
memset(OC,0,sizeof(TS7OrderCode));
memcpy(OC->Code,&opData[6],20);
OC->V1=opData[opSize-3];
OC->V2=opData[opSize-2];
OC->V3=opData[opSize-1];
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opGetCpuInfo()
{
PS7CpuInfo Info;
int Result;
// Store Pointer
Info=PS7CpuInfo(Job.pData);
// Clear data in order to have the end of strings (\0) correctly setted
memset(Info, 0, sizeof(TS7CpuInfo));
Job.ID =0x001C;
Job.Index =0x0000;
Job.IParam=0;
Result =opReadSZL();
if (Result==0)
{
memcpy(Info->ModuleTypeName,&opData[176],32);
memcpy(Info->SerialNumber,&opData[142],24);
memcpy(Info->ASName,&opData[6],24);
memcpy(Info->Copyright,&opData[108],26);
memcpy(Info->ModuleName,&opData[40],24);
}
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opGetCpInfo()
{
PS7CpInfo Info;
int Result;
// Store Pointer
Info=PS7CpInfo(Job.pData);
memset(Info,0,sizeof(TS7CpInfo));
Job.ID =0x0131;
Job.Index =0x0001;
Job.IParam=0;
Result =opReadSZL();
if (Result==0)
{
Info->MaxPduLengt=opData[6]*256+opData[7];
Info->MaxConnections=opData[8]*256+opData[9];
Info->MaxMpiRate=DWordAt(&opData[10]);
Info->MaxBusRate=DWordAt(&opData[14]);
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opGetPlcStatus()
{
int *Status;
int Result;
Status =(int*)Job.pData;
Job.ID =0x0424;
Job.Index =0x0000;
Job.IParam =0;
Result =opReadSZL();
if (Result==0)
{
switch (opData[7])
{
case S7CpuStatusUnknown :
case S7CpuStatusRun :
case S7CpuStatusStop : *Status=opData[7];
break;
default :
// Since RUN status is always $08 for all CPUs and CPs, STOP status
// sometime can be coded as $03 (especially for old cpu...)
*Status=S7CpuStatusStop;
}
}
else
*Status=0;
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opPlcStop()
{
PReqFunPlcStop ReqParams;
PResFunCtrl ResParams;
PS7ResHeader23 Answer;
int IsoSize, Result;
char p_program[] = {'P','_','P','R','O','G','R','A','M'};
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunPlcStop(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResFunCtrl(pbyte(Answer)+ResHeaderSize23);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunPlcStop));
PDUH_out->DataLen=0x0000; // No Data
// Fill Params
ReqParams->Fun=pduStop;
memset(ReqParams->Uk_5,0,5);
ReqParams->Len_2=0x09;
memcpy(ReqParams->Cmd,&p_program,9);
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunPlcStop);
Result=isoExchangeBuffer(0,IsoSize);
if (Result==0)
{
if (Answer->Error!=0)
{
if (ResParams->ResFun!=pduStop)
Result=errCliCannotStopPLC;
else
if (ResParams->para ==0x07)
Result=errCliAlreadyStop;
else
Result=errCliCannotStopPLC;
};
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opPlcHotStart()
{
PReqFunPlcHotStart ReqParams;
PResFunCtrl ResParams;
PS7ResHeader23 Answer;
int IsoSize, Result;
char p_program[] = {'P','_','P','R','O','G','R','A','M'};
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunPlcHotStart(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResFunCtrl(pbyte(Answer)+ResHeaderSize23);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunPlcHotStart)); // 16 bytes params
PDUH_out->DataLen=0x0000; // No Data
// Fill Params
ReqParams->Fun=pduStart;
ReqParams->Uk_7[0]=0x00;
ReqParams->Uk_7[1]=0x00;
ReqParams->Uk_7[2]=0x00;
ReqParams->Uk_7[3]=0x00;
ReqParams->Uk_7[4]=0x00;
ReqParams->Uk_7[5]=0x00;
ReqParams->Uk_7[6]=0xFD;
ReqParams->Len_1=0x0000;
ReqParams->Len_2=0x09;
memcpy(ReqParams->Cmd,&p_program,9);
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunPlcHotStart);
Result=isoExchangeBuffer(0,IsoSize);
if (Result==0)
{
if ((Answer->Error!=0))
{
if ((ResParams->ResFun!=pduStart))
Result=errCliCannotStartPLC;
else
{
if (ResParams->para==0x03)
Result=errCliAlreadyRun;
else
if (ResParams->para==0x02)
Result=errCliCannotStartPLC;
else
Result=errCliCannotStartPLC;
}
}
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opPlcColdStart()
{
PReqFunPlcColdStart ReqParams;
PResFunCtrl ResParams;
PS7ResHeader23 Answer;
int IsoSize, Result;
char p_program[] = {'P','_','P','R','O','G','R','A','M'};
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunPlcColdStart(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResFunCtrl(pbyte(Answer)+ResHeaderSize23);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunPlcColdStart)); // 22 bytes params
PDUH_out->DataLen=0x0000; // No Data
// Fill Params
ReqParams->Fun=pduStart;
ReqParams->Uk_7[0]=0x00;
ReqParams->Uk_7[1]=0x00;
ReqParams->Uk_7[2]=0x00;
ReqParams->Uk_7[3]=0x00;
ReqParams->Uk_7[4]=0x00;
ReqParams->Uk_7[5]=0x00;
ReqParams->Uk_7[6]=0xFD;
ReqParams->Len_1=SwapWord(0x0002);
ReqParams->SFun =SwapWord(0x4320); // Cold start
ReqParams->Len_2=0x09;
memcpy(ReqParams->Cmd,&p_program,9);
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunPlcColdStart);
Result=isoExchangeBuffer(0,IsoSize);
if (Result==0)
{
if ((Answer->Error!=0))
{
if ((ResParams->ResFun!=pduStart))
Result=errCliCannotStartPLC;
else
{
if (ResParams->para==0x03)
Result=errCliAlreadyRun;
else
if (ResParams->para==0x02)
Result=errCliCannotStartPLC;
else
Result=errCliCannotStartPLC;
}
}
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opCopyRamToRom()
{
PReqFunCopyRamToRom ReqParams;
PResFunCtrl ResParams;
PS7ResHeader23 Answer;
int IsoSize, CurTimeout, Result;
char _modu[] = {'_','M','O','D','U'};
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunCopyRamToRom(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResFunCtrl(pbyte(Answer)+ResHeaderSize23);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunCopyRamToRom));
PDUH_out->DataLen=0x0000; // No Data
// Fill Params
ReqParams->Fun=pduControl;
ReqParams->Uk_7[0]=0x00;
ReqParams->Uk_7[1]=0x00;
ReqParams->Uk_7[2]=0x00;
ReqParams->Uk_7[3]=0x00;
ReqParams->Uk_7[4]=0x00;
ReqParams->Uk_7[5]=0x00;
ReqParams->Uk_7[6]=0xFD;
ReqParams->Len_1=SwapWord(0x0002);
ReqParams->SFun =SwapWord(0x4550);
ReqParams->Len_2=0x05;
memcpy(ReqParams->Cmd,&_modu,5);
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunCopyRamToRom);
// Changes the timeout
CurTimeout=RecvTimeout;
RecvTimeout=Job.IParam;
Result=isoExchangeBuffer(0,IsoSize);
// Restores the timeout
RecvTimeout=CurTimeout;
if (Result==0)
{
if ((Answer->Error!=0) || (ResParams->ResFun!=pduControl))
Result=errCliCannotCopyRamToRom;
}
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opCompress()
{
PReqFunCompress ReqParams;
PResFunCtrl ResParams;
PS7ResHeader23 Answer;
int IsoSize, CurTimeout, Result;
char _garb[] = {'_','G','A','R','B'};
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunCompress(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResFunCtrl(pbyte(Answer)+ResHeaderSize23);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_request; // 0x01
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen=SwapWord(sizeof(TReqFunCompress));
PDUH_out->DataLen=0x0000; // No Data
// Fill Params
ReqParams->Fun=pduControl;
ReqParams->Uk_7[0]=0x00;
ReqParams->Uk_7[1]=0x00;
ReqParams->Uk_7[2]=0x00;
ReqParams->Uk_7[3]=0x00;
ReqParams->Uk_7[4]=0x00;
ReqParams->Uk_7[5]=0x00;
ReqParams->Uk_7[6]=0xFD;
ReqParams->Len_1=0x0000;
ReqParams->Len_2=0x05;
memcpy(ReqParams->Cmd,&_garb,5);
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunCompress);
// Changes the timeout
CurTimeout=RecvTimeout;
RecvTimeout=Job.IParam;
Result=isoExchangeBuffer(0,IsoSize);
// Restores the timeout
RecvTimeout=CurTimeout;
if (Result==0)
{
if (((Answer->Error!=0) || (ResParams->ResFun!=pduControl)))
Result=errCliCannotCompress;
}
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opGetProtection()
{
PS7Protection Info, usrInfo;
int Result;
// Store Pointer
usrInfo=PS7Protection(Job.pData);
memset(usrInfo, 0, sizeof(TS7Protection));
Job.ID =0x0232;
Job.Index =0x0004;
Job.IParam=0; // No copy in Usr Data pointed by Job.pData
Result =opReadSZL();
if (Result==0)
{
Info=PS7Protection(pbyte(&opData)+6);
usrInfo->sch_schal=SwapWord(Info->sch_schal);
usrInfo->sch_par =SwapWord(Info->sch_par);
usrInfo->sch_rel =SwapWord(Info->sch_rel);
usrInfo->bart_sch =SwapWord(Info->bart_sch);
usrInfo->anl_sch =SwapWord(Info->anl_sch);
}
return Result;
}
//******************************************************************************
// NOTE
// PASSWORD HACKING IS VERY FAR FROM THE AIM OF THIS PROJECT
// NEXT FUNCTION ONLY ENCODES THE ASCII PASSWORD TO BE DOWNLOADED IN THE PLC.
//
// MOREOVER **YOU NEED TO KNOW** THE CORRECT PASSWORD TO MEET THE CPU
// SECURITY LEVEL
//******************************************************************************
int TSnap7MicroClient::opSetPassword()
{
PReqFunSecurity ReqParams;
PReqDataSecurity ReqData;
PResParamsSecurity ResParams;
PS7ResHeader23 Answer;
int c, IsoSize, Result;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunSecurity(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ReqData =PReqDataSecurity(pbyte(ReqParams)+sizeof(TReqFunSecurity));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResParamsSecurity(pbyte(Answer)+ResHeaderSize17);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 0x07
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen =SwapWord(sizeof(TReqFunSecurity));
PDUH_out->DataLen=SwapWord(sizeof(TReqDataSecurity));
// Fill params (mostly constants)
ReqParams->Head[0]=0x00;
ReqParams->Head[1]=0x01;
ReqParams->Head[2]=0x12;
ReqParams->Plen =0x04;
ReqParams->Uk =0x11;
ReqParams->Tg =grSecurity;
ReqParams->SubFun =SFun_EnterPwd;
ReqParams->Seq =0x00;
// Fill Data
ReqData->Ret =0xFF;
ReqData->TS =TS_ResOctet;
ReqData->DLen =SwapWord(0x0008); // 8 bytes data : password
// Encode the password
ReqData->Pwd[0]=opData[0] ^ 0x55;
ReqData->Pwd[1]=opData[1] ^ 0x55;
for (c = 2; c < 8; c++){
ReqData->Pwd[c]=opData[c] ^ 0x55 ^ ReqData->Pwd[c-2];
};
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunSecurity)+sizeof(TReqDataSecurity);
Result=isoExchangeBuffer(0,IsoSize);
// Get Return
if (Result==0)
{
if (ResParams->Err!=0)
Result=CpuError(SwapWord(ResParams->Err));
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::opClearPassword()
{
PReqFunSecurity ReqParams;
PReqDataSecurity ReqData;
PResParamsSecurity ResParams;
PS7ResHeader23 Answer;
int IsoSize, Result;
// Setup pointers (note : PDUH_out and PDU.Payload are the same pointer)
ReqParams=PReqFunSecurity(pbyte(PDUH_out)+sizeof(TS7ReqHeader));
ReqData =PReqDataSecurity(pbyte(ReqParams)+sizeof(TReqFunSecurity));
Answer =PS7ResHeader23(&PDU.Payload);
ResParams=PResParamsSecurity(pbyte(Answer)+ResHeaderSize17);
// Fill Header
PDUH_out->P=0x32; // Always 0x32
PDUH_out->PDUType=PduType_userdata; // 0x07
PDUH_out->AB_EX=0x0000; // Always 0x0000
PDUH_out->Sequence=GetNextWord(); // AutoInc
PDUH_out->ParLen =SwapWord(sizeof(TReqFunSecurity));
PDUH_out->DataLen=SwapWord(0x0004); // We need only 4 bytes
// Fill params (mostly constants)
ReqParams->Head[0]=0x00;
ReqParams->Head[1]=0x01;
ReqParams->Head[2]=0x12;
ReqParams->Plen =0x04;
ReqParams->Uk =0x11;
ReqParams->Tg =grSecurity;
ReqParams->SubFun =SFun_CancelPwd;
ReqParams->Seq =0x00;
// Fill Data
ReqData->Ret =0x0A;
ReqData->TS =0x00;
ReqData->DLen =0x0000;
IsoSize=sizeof(TS7ReqHeader)+sizeof(TReqFunSecurity)+4;
Result=isoExchangeBuffer(0,IsoSize);
// Get Return
if (Result==0)
{
if (ResParams->Err!=0)
Result=CpuError(SwapWord(ResParams->Err));
};
return Result;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::CpuError(int Error)
{
switch(Error)
{
case 0 : return 0;
case Code7AddressOutOfRange : return errCliAddressOutOfRange;
case Code7InvalidTransportSize : return errCliInvalidTransportSize;
case Code7WriteDataSizeMismatch : return errCliWriteDataSizeMismatch;
case Code7ResItemNotAvailable :
case Code7ResItemNotAvailable1 : return errCliItemNotAvailable;
case Code7DataOverPDU : return errCliSizeOverPDU;
case Code7InvalidValue : return errCliInvalidValue;
case Code7FunNotAvailable : return errCliFunNotAvailable;
case Code7NeedPassword : return errCliNeedPassword;
case Code7InvalidPassword : return errCliInvalidPassword;
case Code7NoPasswordToSet :
case Code7NoPasswordToClear : return errCliNoPasswordToSetOrClear;
default:
return errCliFunctionRefused;
};
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::DataSizeByte(int WordLength)
{
switch (WordLength){
case S7WLBit : return 1; // S7 sends 1 byte per bit
case S7WLByte : return 1;
case S7WLChar : return 1;
case S7WLWord : return 2;
case S7WLDWord : return 4;
case S7WLInt : return 2;
case S7WLDInt : return 4;
case S7WLReal : return 4;
case S7WLCounter : return 2;
case S7WLTimer : return 2;
default : return 0;
}
}
//---------------------------------------------------------------------------
longword TSnap7MicroClient::DWordAt(void * P)
{
longword DW;
DW=*(longword*)P;
return SwapDWord(DW);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::CheckBlock(int BlockType, int BlockNum, void * pBlock, int Size)
{
PS7CompactBlockInfo Info = PS7CompactBlockInfo(pBlock);
if (BlockType>=0) // if (BlockType<0 the test is skipped
{
if ((BlockType!=Block_OB)&&(BlockType!=Block_DB)&&(BlockType!=Block_FB)&&
(BlockType!=Block_FC)&&(BlockType!=Block_SDB)&&(BlockType!=Block_SFC)&&
(BlockType!=Block_SFB))
return errCliInvalidBlockType;
}
if (BlockNum>=0) // if (BlockNum<0 the test is skipped
{
if (BlockNum>0xFFFF)
return errCliInvalidBlockNumber;
};
if (SwapDWord(Info->LenLoadMem)!=longword(Size))
return errCliInvalidBlockSize;
// Check the presence of the footer
if (SwapWord(Info->MC7Len)+sizeof(TS7CompactBlockInfo)>=u_int(Size))
return errCliInvalidBlockSize;
return 0;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::SubBlockToBlock(int SBB)
{
switch (SBB)
{
case SubBlk_OB : return Block_OB;
case SubBlk_DB : return Block_DB;
case SubBlk_SDB : return Block_SDB;
case SubBlk_FC : return Block_FC;
case SubBlk_SFC : return Block_SFC;
case SubBlk_FB : return Block_FB;
case SubBlk_SFB : return Block_SFB;
default : return 0;
};
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::PerformOperation()
{
ClrError();
int Operation=Job.Op;
switch(Operation)
{
case s7opNone:
Job.Result=errCliInvalidParams;
break;
case s7opReadArea:
Job.Result=opReadArea();
break;
case s7opWriteArea:
Job.Result=opWriteArea();
break;
case s7opReadMultiVars:
Job.Result=opReadMultiVars();
break;
case s7opWriteMultiVars:
Job.Result=opWriteMultiVars();
break;
case s7opDBGet:
Job.Result=opDBGet();
break;
case s7opDBFill:
Job.Result=opDBFill();
break;
case s7opUpload:
Job.Result=opUpload();
break;
case s7opDownload:
Job.Result=opDownload();
break;
case s7opDelete:
Job.Result=opDelete();
break;
case s7opListBlocks:
Job.Result=opListBlocks();
break;
case s7opAgBlockInfo:
Job.Result=opAgBlockInfo();
break;
case s7opListBlocksOfType:
Job.Result=opListBlocksOfType();
break;
case s7opReadSzlList:
Job.Result=opReadSZLList();
break;
case s7opReadSZL:
Job.Result=opReadSZL();
break;
case s7opGetDateTime:
Job.Result=opGetDateTime();
break;
case s7opSetDateTime:
Job.Result=opSetDateTime();
break;
case s7opGetOrderCode:
Job.Result=opGetOrderCode();
break;
case s7opGetCpuInfo:
Job.Result=opGetCpuInfo();
break;
case s7opGetCpInfo:
Job.Result=opGetCpInfo();
break;
case s7opGetPlcStatus:
Job.Result=opGetPlcStatus();
break;
case s7opPlcHotStart:
Job.Result=opPlcHotStart();
break;
case s7opPlcColdStart:
Job.Result=opPlcColdStart();
break;
case s7opCopyRamToRom:
Job.Result=opCopyRamToRom();
break;
case s7opCompress:
Job.Result=opCompress();
break;
case s7opPlcStop:
Job.Result=opPlcStop();
break;
case s7opGetProtection:
Job.Result=opGetProtection();
break;
case s7opSetPassword:
Job.Result=opSetPassword();
break;
case s7opClearPassword:
Job.Result=opClearPassword();
break;
}
Job.Time =SysGetTick()-JobStart;
Job.Pending=false;
return SetError(Job.Result);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::Disconnect()
{
JobStart=SysGetTick();
PeerDisconnect();
Job.Time=SysGetTick()-JobStart;
Job.Pending=false;
return 0;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::Reset(bool DoReconnect)
{
Job.Pending=false;
if (DoReconnect) {
Disconnect();
return Connect();
}
else
return 0;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::Connect()
{
int Result;
JobStart=SysGetTick();
Result =PeerConnect();
Job.Time=SysGetTick()-JobStart;
return Result;
}
//---------------------------------------------------------------------------
void TSnap7MicroClient::SetConnectionType(word ConnType)
{
ConnectionType=ConnType;
}
//---------------------------------------------------------------------------
void TSnap7MicroClient::SetConnectionParams(const char *RemAddress, word LocalTSAP, word RemoteTSAP)
{
SrcTSap = LocalTSAP;
DstTSap = RemoteTSAP;
strncpy_s(RemoteAddress, 16,RemAddress, 16);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::ConnectTo(const char *RemAddress, int Rack, int Slot)
{
word RemoteTSAP = (ConnectionType<<8)+(Rack*0x20)+Slot;
SetConnectionParams(RemAddress, SrcTSap, RemoteTSAP);
return Connect();
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::GetParam(int ParamNumber, void *pValue)
{
switch (ParamNumber)
{
case p_u16_RemotePort:
*Puint16_t(pValue)=RemotePort;
break;
case p_i32_PingTimeout:
*Pint32_t(pValue)=PingTimeout;
break;
case p_i32_SendTimeout:
*Pint32_t(pValue)=SendTimeout;
break;
case p_i32_RecvTimeout:
*Pint32_t(pValue)=RecvTimeout;
break;
case p_i32_WorkInterval:
*Pint32_t(pValue)=WorkInterval;
break;
case p_u16_SrcRef:
*Puint16_t(pValue)=SrcRef;
break;
case p_u16_DstRef:
*Puint16_t(pValue)=DstRef;
break;
case p_u16_SrcTSap:
*Puint16_t(pValue)=SrcTSap;
break;
case p_i32_PDURequest:
*Pint32_t(pValue)=PDURequest;
break;
default: return errCliInvalidParamNumber;
}
return 0;
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::SetParam(int ParamNumber, void *pValue)
{
switch (ParamNumber)
{
case p_u16_RemotePort:
if (!Connected)
RemotePort=*Puint16_t(pValue);
else
return errCliCannotChangeParam;
break;
case p_i32_PingTimeout:
PingTimeout=*Pint32_t(pValue);
break;
case p_i32_SendTimeout:
SendTimeout=*Pint32_t(pValue);
break;
case p_i32_RecvTimeout:
RecvTimeout=*Pint32_t(pValue);
break;
case p_i32_WorkInterval:
WorkInterval=*Pint32_t(pValue);
break;
case p_u16_SrcRef:
SrcRef=*Puint16_t(pValue);
break;
case p_u16_DstRef:
DstRef=*Puint16_t(pValue);
break;
case p_u16_SrcTSap:
SrcTSap=*Puint16_t(pValue);
break;
case p_i32_PDURequest:
PDURequest=*Pint32_t(pValue);
break;
default: return errCliInvalidParamNumber;
}
return 0;
}
//---------------------------------------------------------------------------
// Data I/O functions
int TSnap7MicroClient::ReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void * pUsrData)
{
if (!Job.Pending)
{
Job.Pending = true;
Job.Op = s7opReadArea;
Job.Area = Area;
Job.Number = DBNumber;
Job.Start = Start;
Job.Amount = Amount;
Job.WordLen = WordLen;
Job.pData = pUsrData;
JobStart = SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::WriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void * pUsrData)
{
if (!Job.Pending)
{
Job.Pending = true;
Job.Op = s7opWriteArea;
Job.Area = Area;
Job.Number = DBNumber;
Job.Start = Start;
Job.Amount = Amount;
Job.WordLen = WordLen;
Job.pData = pUsrData;
JobStart = SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::ReadMultiVars(PS7DataItem Item, int ItemsCount)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opReadMultiVars;
Job.Amount =ItemsCount;
Job.pData =Item;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::WriteMultiVars(PS7DataItem Item, int ItemsCount)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opWriteMultiVars;
Job.Amount =ItemsCount;
Job.pData =Item;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::DBRead(int DBNumber, int Start, int Size, void * pUsrData)
{
return ReadArea(S7AreaDB, DBNumber, Start, Size, S7WLByte, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::DBWrite(int DBNumber, int Start, int Size, void * pUsrData)
{
return WriteArea(S7AreaDB, DBNumber, Start, Size, S7WLByte, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::MBRead(int Start, int Size, void * pUsrData)
{
return ReadArea(S7AreaMK, 0, Start, Size, S7WLByte, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::MBWrite(int Start, int Size, void * pUsrData)
{
return WriteArea(S7AreaMK, 0, Start, Size, S7WLByte, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::EBRead(int Start, int Size, void * pUsrData)
{
return ReadArea(S7AreaPE, 0, Start, Size, S7WLByte, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::EBWrite(int Start, int Size, void * pUsrData)
{
return WriteArea(S7AreaPE, 0, Start, Size, S7WLByte, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::ABRead(int Start, int Size, void * pUsrData)
{
return ReadArea(S7AreaPA, 0, Start, Size, S7WLByte, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::ABWrite(int Start, int Size, void * pUsrData)
{
return WriteArea(S7AreaPA, 0, Start, Size, S7WLByte, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::TMRead(int Start, int Amount, void * pUsrData)
{
return ReadArea(S7AreaTM, 0, Start, Amount, S7WLTimer, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::TMWrite(int Start, int Amount, void * pUsrData)
{
return WriteArea(S7AreaTM, 0, Start, Amount, S7WLTimer, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::CTRead(int Start, int Amount, void * pUsrData)
{
return ReadArea(S7AreaCT, 0, Start, Amount, S7WLCounter, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::CTWrite(int Start, int Amount, void * pUsrData)
{
return WriteArea(S7AreaCT, 0, Start, Amount, S7WLCounter, pUsrData);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::ListBlocks(PS7BlocksList pUsrData)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opListBlocks;
Job.pData =pUsrData;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::GetAgBlockInfo(int BlockType, int BlockNum, PS7BlockInfo pUsrData)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opAgBlockInfo;
Job.Area =BlockType;
Job.Number =BlockNum;
Job.pData =pUsrData;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::GetPgBlockInfo(void * pBlock, PS7BlockInfo pUsrData, int Size)
{
PS7CompactBlockInfo Info;
PS7BlockFooter Footer;
int Result=CheckBlock(-1,-1,pBlock,Size);
if (Result==0)
{
Info=PS7CompactBlockInfo(pBlock);
pUsrData->BlkType =Info->SubBlkType;
pUsrData->BlkNumber=SwapWord(Info->BlkNum);
pUsrData->BlkLang =Info->BlkLang;
pUsrData->BlkFlags =Info->BlkFlags;
pUsrData->MC7Size =SwapWord(Info->MC7Len);
pUsrData->LoadSize =SwapDWord(Info->LenLoadMem);
pUsrData->LocalData=SwapDWord(Info->LocDataLen);
pUsrData->SBBLength=SwapDWord(Info->SbbLen);
pUsrData->CheckSum =0; // this info is not available
pUsrData->Version =0; // this info is not available
FillTime(SwapWord(Info->CodeTime_dy),pUsrData->CodeDate);
FillTime(SwapWord(Info->IntfTime_dy),pUsrData->IntfDate);
Footer=PS7BlockFooter(pbyte(Info)+pUsrData->LoadSize-sizeof(TS7BlockFooter));
memcpy(pUsrData->Author,Footer->Author,8);
memcpy(pUsrData->Family,Footer->Family,8);
memcpy(pUsrData->Header,Footer->Header,8);
};
return SetError(Result);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::ListBlocksOfType(int BlockType, TS7BlocksOfType *pUsrData, int &ItemsCount)
{
if (!Job.Pending)
{
if (ItemsCount<1)
return SetError(errCliInvalidBlockSize);
Job.Pending =true;
Job.Op =s7opListBlocksOfType;
Job.Area =BlockType;
Job.pData =pUsrData;
Job.pAmount =&ItemsCount;
Job.Amount =ItemsCount;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::Upload(int BlockType, int BlockNum, void * pUsrData, int & Size)
{
if (!Job.Pending)
{
if (Size<=0)
return SetError(errCliInvalidBlockSize);
Job.Pending =true;
Job.Op =s7opUpload;
Job.Area =BlockType;
Job.pData =pUsrData;
Job.pAmount =&Size;
Job.Amount =Size;
Job.Number =BlockNum;
Job.IParam =0; // not full upload, only data
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::FullUpload(int BlockType, int BlockNum, void * pUsrData, int & Size)
{
if (!Job.Pending)
{
if (Size<=0)
return SetError(errCliInvalidBlockSize);
Job.Pending =true;
Job.Op =s7opUpload;
Job.Area =BlockType;
Job.pData =pUsrData;
Job.pAmount =&Size;
Job.Amount =Size;
Job.Number =BlockNum;
Job.IParam =1; // header + data + footer
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::Download(int BlockNum, void * pUsrData, int Size)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opDownload;
memcpy(&opData, pUsrData, Size);
Job.Number =BlockNum;
Job.Amount =Size;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::Delete(int BlockType, int BlockNum)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opDelete;
Job.Area =BlockType;
Job.Number =BlockNum;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::DBGet(int DBNumber, void * pUsrData, int & Size)
{
if (!Job.Pending)
{
if (Size<=0)
return SetError(errCliInvalidBlockSize);
Job.Pending =true;
Job.Op =s7opDBGet;
Job.Number =DBNumber;
Job.pData =pUsrData;
Job.pAmount =&Size;
Job.Amount =Size;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::DBFill(int DBNumber, int FillChar)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opDBFill;
Job.Number =DBNumber;
Job.IParam =FillChar;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::GetPlcDateTime(tm &DateTime)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opGetDateTime;
Job.pData =&DateTime;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::SetPlcDateTime(tm * DateTime)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opSetDateTime;
Job.pData =DateTime;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::SetPlcSystemDateTime()
{
time_t Now;
time(&Now);
struct tm DateTime;
localtime_s (&DateTime,&Now);
return SetPlcDateTime(&DateTime);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::GetOrderCode(PS7OrderCode pUsrData)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opGetOrderCode;
Job.pData =pUsrData;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::GetCpuInfo(PS7CpuInfo pUsrData)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opGetCpuInfo;
Job.pData =pUsrData;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::GetCpInfo(PS7CpInfo pUsrData)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opGetCpInfo;
Job.pData =pUsrData;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::ReadSZL(int ID, int Index, PS7SZL pUsrData, int &Size)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opReadSZL;
Job.ID =ID;
Job.Index =Index;
Job.pData =pUsrData;
Job.pAmount =&Size;
Job.Amount =Size;
Job.IParam =1; // Data has to be copied into user buffer
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::ReadSZLList(PS7SZLList pUsrData, int &ItemsCount)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opReadSzlList;
Job.pData =pUsrData;
Job.pAmount =&ItemsCount;
Job.Amount =ItemsCount;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::PlcHotStart()
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opPlcHotStart;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::PlcColdStart()
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opPlcColdStart;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::PlcStop()
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opPlcStop;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::CopyRamToRom(int Timeout)
{
if (!Job.Pending)
{
if (Timeout>0)
{
Job.Pending =true;
Job.Op =s7opCopyRamToRom;
Job.IParam =Timeout;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliInvalidParams);
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::Compress(int Timeout)
{
if (!Job.Pending)
{
if (Timeout>0)
{
Job.Pending =true;
Job.Op =s7opCompress;
Job.IParam =Timeout;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliInvalidParams);
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::GetPlcStatus(int & Status)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opGetPlcStatus;
Job.pData =&Status;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::GetProtection(PS7Protection pUsrData)
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opGetProtection;
Job.pData =pUsrData;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::SetSessionPassword(char *Password)
{
if (!Job.Pending)
{
size_t L = strlen(Password);
// checks the len
if ((L<1) || (L>8))
return SetError(errCliInvalidParams);
Job.Pending =true;
// prepares an 8 char string filled with spaces
memset(&opData,0x20,8);
// copies
strncpy_s((char*)&opData,L,Password,L);
Job.Op =s7opSetPassword;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------
int TSnap7MicroClient::ClearSessionPassword()
{
if (!Job.Pending)
{
Job.Pending =true;
Job.Op =s7opClearPassword;
JobStart =SysGetTick();
return PerformOperation();
}
else
return SetError(errCliJobPending);
}
//---------------------------------------------------------------------------