123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503 |
- /*=============================================================================|
- | 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_client.h"
- //---------------------------------------------------------------------------
- TSnap7Client::TSnap7Client()
- {
- FThread = 0;
- CliCompletion = 0;
- EvtJob = NULL;
- EvtComplete = NULL;
- FThread=NULL;
- ThreadCreated = false;
- }
- //---------------------------------------------------------------------------
- TSnap7Client::~TSnap7Client()
- {
- Destroying=true;
- Disconnect();
- CliCompletion=NULL;
- if (ThreadCreated)
- {
- CloseThread();
- delete EvtComplete;
- delete EvtJob;
- ThreadCreated=false;
- }
- }
- //---------------------------------------------------------------------------
- void TSnap7Client::CloseThread()
- {
- int Timeout;
- if (FThread)
- {
- FThread->Terminate();
- if (Job.Pending)
- Timeout=3000;
- else
- Timeout=1000;
- EvtJob->Set();
- if (FThread->WaitFor(Timeout)!=WAIT_OBJECT_0)
- FThread->Kill();
- try {
- delete FThread;
- }
- catch (...){
- }
- FThread=0;
- }
- }
- //---------------------------------------------------------------------------
- void TSnap7Client::OpenThread()
- {
- FThread = new TClientThread(this);
- FThread->Start();
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::Reset(bool DoReconnect)
- {
- bool WasConnected = Connected;
- if (ThreadCreated)
- {
- CloseThread();
- Disconnect();
- OpenThread();
- }
- else
- Disconnect();
-
- if (DoReconnect || WasConnected)
- return Connect();
- else
- return 0;
- }
- //---------------------------------------------------------------------------
- void TSnap7Client::DoCompletion()
- {
- if ((CliCompletion!=NULL) && !Destroying)
- {
- try{
- CliCompletion(FUsrPtr, Job.Op, Job.Result);
- }catch (...)
- {
- }
- }
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::SetAsCallback(pfn_CliCompletion pCompletion, void * usrPtr)
- {
- CliCompletion=pCompletion;
- FUsrPtr=usrPtr;
- return 0;
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::GetParam(int ParamNumber, void * pValue)
- {
- // Actually there are no specific client params, maybe in future...
- return TSnap7MicroClient::GetParam(ParamNumber, pValue);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::SetParam(int ParamNumber, void * pValue)
- {
- // Actually there are no specific client params, maybe in future...
- return TSnap7MicroClient::SetParam(ParamNumber, pValue);
- }
- //---------------------------------------------------------------------------
- bool TSnap7Client::CheckAsCompletion(int &opResult)
- {
- if (!Job.Pending)
- opResult=Job.Result;
- else
- if (!Destroying)
- opResult=errCliJobPending; // don't set LastError here
- else
- {
- opResult=errCliDestroying;
- return true;
- }
- return !Job.Pending;
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsReadArea(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();
- StartAsyncJob();
- return 0;
- }
- else
- return SetError(errCliJobPending);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsWriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void * pUsrData)
- {
- int ByteSize, TotalSize;
- if (!Job.Pending)
- {
- Job.Pending =true;
- Job.Op =s7opWriteArea;
- Job.Area =Area;
- Job.Number =DBNumber;
- Job.Start =Start;
- // Performs some check first to copy the data
- ByteSize=DataSizeByte(WordLen);
- TotalSize=ByteSize*Amount; // Total size in bytes
- if (ByteSize==0)
- return SetError(errCliInvalidWordLen);
- if ((TotalSize < 1) || (TotalSize > int(sizeof(opData))))
- return SetError(errCliInvalidParams);
- Job.Amount =Amount;
- Job.WordLen =WordLen;
- // Doublebuffering
- memcpy(&opData, pUsrData, TotalSize);
- Job.pData =&opData;
- JobStart =SysGetTick();
- StartAsyncJob();
- return 0;
- }
- else
- return SetError(errCliJobPending);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsListBlocksOfType(int BlockType, PS7BlocksOfType pUsrData, int & ItemsCount)
- {
- if (!Job.Pending)
- {
- Job.Pending =true;
- Job.Op =s7opListBlocksOfType;
- Job.Area =BlockType;
- Job.pData =pUsrData;
- Job.pAmount =&ItemsCount;
- JobStart =SysGetTick();
- StartAsyncJob();
- return 0;
- }
- else
- return SetError(errCliJobPending);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsReadSZL(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();
- StartAsyncJob();
- return 0;
- }
- else
- return SetError(errCliJobPending);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsReadSZLList(PS7SZLList pUsrData, int &ItemsCount)
- {
- if (!Job.Pending)
- {
- Job.Pending =true;
- Job.Op =s7opReadSzlList;
- Job.pData =pUsrData;
- Job.pAmount =&ItemsCount;
- Job.Amount =ItemsCount;
- JobStart =SysGetTick();
- StartAsyncJob();
- return 0;
- }
- else
- return SetError(errCliJobPending);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsUpload(int BlockType, int BlockNum, void * pUsrData, int & Size)
- {
- if (!Job.Pending)
- {
- 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();
- StartAsyncJob();
- return 0;
- }
- else
- return SetError(errCliJobPending);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsFullUpload(int BlockType, int BlockNum, void * pUsrData, int & Size)
- {
- if (!Job.Pending)
- {
- Job.Pending =true;
- Job.Op =s7opUpload;
- Job.Area =BlockType;
- Job.pData =pUsrData;
- Job.pAmount =&Size;
- Job.Amount =Size;
- Job.Number =BlockNum;
- Job.IParam =1; // full upload
- JobStart =SysGetTick();
- StartAsyncJob();
- return 0;
- }
- else
- return SetError(errCliJobPending);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsDownload(int BlockNum, void * pUsrData, int Size)
- {
- if (!Job.Pending)
- {
- // Checks the size : here we only need a size>0 to avoid problems during
- // doublebuffering, the real test of the block size will be done in
- // Checkblock.
- if (Size<1)
- return SetError(errCliInvalidBlockSize);
- Job.Pending =true;
- Job.Op =s7opDownload;
- // Doublebuffering
- memcpy(&opData, pUsrData, Size);
- Job.Number =BlockNum;
- Job.Amount =Size;
- JobStart =SysGetTick();
- StartAsyncJob();
- return 0;
- }
- else
- return SetError(errCliJobPending);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsCopyRamToRom(int Timeout)
- {
- if (!Job.Pending)
- {
- Job.Pending =true;
- Job.Op =s7opCopyRamToRom;
- if (Timeout>0)
- {
- Job.IParam =Timeout;
- JobStart =SysGetTick();
- StartAsyncJob();
- return 0;
- }
- else
- return SetError(errCliInvalidParams);
- }
- else
- return SetError(errCliJobPending);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsCompress(int Timeout)
- {
- if (!Job.Pending)
- {
- Job.Pending =true;
- Job.Op =s7opCompress;
- if (Timeout>0)
- {
- Job.IParam =Timeout;
- JobStart =SysGetTick();
- StartAsyncJob();
- return 0;
- }
- else
- return SetError(errCliInvalidParams);
- }
- else
- return SetError(errCliJobPending);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsDBRead(int DBNumber, int Start, int Size, void * pUsrData)
- {
- return AsReadArea(S7AreaDB, DBNumber, Start, Size, S7WLByte, pUsrData);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsDBWrite(int DBNumber, int Start, int Size, void * pUsrData)
- {
- return AsWriteArea(S7AreaDB, DBNumber, Start, Size, S7WLByte, pUsrData);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsMBRead(int Start, int Size, void * pUsrData)
- {
- return AsReadArea(S7AreaMK, 0, Start, Size, S7WLByte, pUsrData);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsMBWrite(int Start, int Size, void * pUsrData)
- {
- return AsWriteArea(S7AreaMK, 0, Start, Size, S7WLByte, pUsrData);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsEBRead(int Start, int Size, void * pUsrData)
- {
- return AsReadArea(S7AreaPE, 0, Start, Size, S7WLByte, pUsrData);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsEBWrite(int Start, int Size, void * pUsrData)
- {
- return AsWriteArea(S7AreaPE, 0, Start, Size, S7WLByte, pUsrData);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsABRead(int Start, int Size, void * pUsrData)
- {
- return AsReadArea(S7AreaPA, 0, Start, Size, S7WLByte, pUsrData);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsABWrite(int Start, int Size, void * pUsrData)
- {
- return AsWriteArea(S7AreaPA, 0, Start, Size, S7WLByte, pUsrData);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsTMRead(int Start, int Amount, void * pUsrData)
- {
- return AsReadArea(S7AreaTM, 0, Start, Amount, S7WLTimer, pUsrData);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsTMWrite(int Start, int Amount, void * pUsrData)
- {
- return AsWriteArea(S7AreaTM, 0, Start, Amount, S7WLTimer, pUsrData);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsCTRead(int Start, int Amount, void * pUsrData)
- {
- return AsReadArea(S7AreaCT, 0, Start, Amount, S7WLCounter, pUsrData);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsCTWrite(int Start, int Amount, void * pUsrData)
- {
- return AsWriteArea(S7AreaCT, 0, Start, Amount, S7WLCounter, pUsrData);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsDBGet(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();
- StartAsyncJob();
- return 0;
- }
- else
- return SetError(errCliJobPending);
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::AsDBFill(int DBNumber, int FillChar)
- {
- if (!Job.Pending)
- {
- Job.Pending =true;
- Job.Op =s7opDBFill;
- Job.Number =DBNumber;
- Job.IParam =FillChar;
- JobStart =SysGetTick();
- StartAsyncJob();
- return 0;
- }
- else
- return SetError(errCliJobPending);
- }
- //---------------------------------------------------------------------------
- void TSnap7Client::StartAsyncJob()
- {
- ClrError();
- if (!ThreadCreated)
- {
- EvtJob = new TSnapEvent(false);
- EvtComplete = new TSnapEvent(false);
- OpenThread();
- ThreadCreated=true;
- }
- EvtComplete->Reset(); // reset if previously was not called WaitAsCompletion
- EvtJob->Set();
- }
- //---------------------------------------------------------------------------
- int TSnap7Client::WaitAsCompletion(unsigned long Timeout)
- {
- if (Job.Pending)
- {
- if (ThreadCreated)
- {
- if (EvtComplete->WaitFor(Timeout)==WAIT_OBJECT_0)
- return Job.Result;
- else
- {
- if (Destroying)
- return errCliDestroying;
- else
- return SetError(errCliJobTimeout);
- }
- }
- else
- return SetError(errCliJobTimeout);
- }
- else
- return Job.Result;
- }
- //---------------------------------------------------------------------------
- void TClientThread::Execute()
- {
- while (!Terminated)
- {
- FClient->EvtJob->WaitForever();
- if (!Terminated)
- {
- FClient->PerformOperation();
- FClient->EvtComplete->Set();
- // Notify the caller the end of job (if callback is set)
- FClient->DoCompletion();
- }
- };
- }
|