/*=============================================================================| | 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 = localtime (&TheDate); if (timeinfo!=NULL) { 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 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(RemoteAddress, 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 (&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((char*)&opData,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); } //---------------------------------------------------------------------------