3332 lines
116 KiB
C++
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);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|