s7_client.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. /*=============================================================================|
  2. | PROJECT SNAP7 1.3.0 |
  3. |==============================================================================|
  4. | Copyright (C) 2013, 2015 Davide Nardella |
  5. | All rights reserved. |
  6. |==============================================================================|
  7. | SNAP7 is free software: you can redistribute it and/or modify |
  8. | it under the terms of the Lesser GNU General Public License as published by |
  9. | the Free Software Foundation, either version 3 of the License, or |
  10. | (at your option) any later version. |
  11. | |
  12. | It means that you can distribute your commercial software linked with |
  13. | SNAP7 without the requirement to distribute the source code of your |
  14. | application and without the requirement that your application be itself |
  15. | distributed under LGPL. |
  16. | |
  17. | SNAP7 is distributed in the hope that it will be useful, |
  18. | but WITHOUT ANY WARRANTY; without even the implied warranty of |
  19. | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
  20. | Lesser GNU General Public License for more details. |
  21. | |
  22. | You should have received a copy of the GNU General Public License and a |
  23. | copy of Lesser GNU General Public License along with Snap7. |
  24. | If not, see http://www.gnu.org/licenses/ |
  25. |=============================================================================*/
  26. #include "s7_client.h"
  27. //---------------------------------------------------------------------------
  28. TSnap7Client::TSnap7Client()
  29. {
  30. FThread = 0;
  31. CliCompletion = 0;
  32. EvtJob = NULL;
  33. EvtComplete = NULL;
  34. FThread=NULL;
  35. ThreadCreated = false;
  36. }
  37. //---------------------------------------------------------------------------
  38. TSnap7Client::~TSnap7Client()
  39. {
  40. Destroying=true;
  41. Disconnect();
  42. CliCompletion=NULL;
  43. if (ThreadCreated)
  44. {
  45. CloseThread();
  46. delete EvtComplete;
  47. delete EvtJob;
  48. ThreadCreated=false;
  49. }
  50. }
  51. //---------------------------------------------------------------------------
  52. void TSnap7Client::CloseThread()
  53. {
  54. int Timeout;
  55. if (FThread)
  56. {
  57. FThread->Terminate();
  58. if (Job.Pending)
  59. Timeout=3000;
  60. else
  61. Timeout=1000;
  62. EvtJob->Set();
  63. if (FThread->WaitFor(Timeout)!=WAIT_OBJECT_0)
  64. FThread->Kill();
  65. try {
  66. delete FThread;
  67. }
  68. catch (...){
  69. }
  70. FThread=0;
  71. }
  72. }
  73. //---------------------------------------------------------------------------
  74. void TSnap7Client::OpenThread()
  75. {
  76. FThread = new TClientThread(this);
  77. FThread->Start();
  78. }
  79. //---------------------------------------------------------------------------
  80. int TSnap7Client::Reset(bool DoReconnect)
  81. {
  82. bool WasConnected = Connected;
  83. if (ThreadCreated)
  84. {
  85. CloseThread();
  86. Disconnect();
  87. OpenThread();
  88. }
  89. else
  90. Disconnect();
  91. if (DoReconnect || WasConnected)
  92. return Connect();
  93. else
  94. return 0;
  95. }
  96. //---------------------------------------------------------------------------
  97. void TSnap7Client::DoCompletion()
  98. {
  99. if ((CliCompletion!=NULL) && !Destroying)
  100. {
  101. try{
  102. CliCompletion(FUsrPtr, Job.Op, Job.Result);
  103. }catch (...)
  104. {
  105. }
  106. }
  107. }
  108. //---------------------------------------------------------------------------
  109. int TSnap7Client::SetAsCallback(pfn_CliCompletion pCompletion, void * usrPtr)
  110. {
  111. CliCompletion=pCompletion;
  112. FUsrPtr=usrPtr;
  113. return 0;
  114. }
  115. //---------------------------------------------------------------------------
  116. int TSnap7Client::GetParam(int ParamNumber, void * pValue)
  117. {
  118. // Actually there are no specific client params, maybe in future...
  119. return TSnap7MicroClient::GetParam(ParamNumber, pValue);
  120. }
  121. //---------------------------------------------------------------------------
  122. int TSnap7Client::SetParam(int ParamNumber, void * pValue)
  123. {
  124. // Actually there are no specific client params, maybe in future...
  125. return TSnap7MicroClient::SetParam(ParamNumber, pValue);
  126. }
  127. //---------------------------------------------------------------------------
  128. bool TSnap7Client::CheckAsCompletion(int &opResult)
  129. {
  130. if (!Job.Pending)
  131. opResult=Job.Result;
  132. else
  133. if (!Destroying)
  134. opResult=errCliJobPending; // don't set LastError here
  135. else
  136. {
  137. opResult=errCliDestroying;
  138. return true;
  139. }
  140. return !Job.Pending;
  141. }
  142. //---------------------------------------------------------------------------
  143. int TSnap7Client::AsReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void * pUsrData)
  144. {
  145. if (!Job.Pending)
  146. {
  147. Job.Pending = true;
  148. Job.Op = s7opReadArea;
  149. Job.Area = Area;
  150. Job.Number = DBNumber;
  151. Job.Start = Start;
  152. Job.Amount = Amount;
  153. Job.WordLen = WordLen;
  154. Job.pData = pUsrData;
  155. JobStart = SysGetTick();
  156. StartAsyncJob();
  157. return 0;
  158. }
  159. else
  160. return SetError(errCliJobPending);
  161. }
  162. //---------------------------------------------------------------------------
  163. int TSnap7Client::AsWriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, void * pUsrData)
  164. {
  165. int ByteSize, TotalSize;
  166. if (!Job.Pending)
  167. {
  168. Job.Pending =true;
  169. Job.Op =s7opWriteArea;
  170. Job.Area =Area;
  171. Job.Number =DBNumber;
  172. Job.Start =Start;
  173. // Performs some check first to copy the data
  174. ByteSize=DataSizeByte(WordLen);
  175. TotalSize=ByteSize*Amount; // Total size in bytes
  176. if (ByteSize==0)
  177. return SetError(errCliInvalidWordLen);
  178. if ((TotalSize < 1) || (TotalSize > int(sizeof(opData))))
  179. return SetError(errCliInvalidParams);
  180. Job.Amount =Amount;
  181. Job.WordLen =WordLen;
  182. // Doublebuffering
  183. memcpy(&opData, pUsrData, TotalSize);
  184. Job.pData =&opData;
  185. JobStart =SysGetTick();
  186. StartAsyncJob();
  187. return 0;
  188. }
  189. else
  190. return SetError(errCliJobPending);
  191. }
  192. //---------------------------------------------------------------------------
  193. int TSnap7Client::AsListBlocksOfType(int BlockType, PS7BlocksOfType pUsrData, int & ItemsCount)
  194. {
  195. if (!Job.Pending)
  196. {
  197. Job.Pending =true;
  198. Job.Op =s7opListBlocksOfType;
  199. Job.Area =BlockType;
  200. Job.pData =pUsrData;
  201. Job.pAmount =&ItemsCount;
  202. JobStart =SysGetTick();
  203. StartAsyncJob();
  204. return 0;
  205. }
  206. else
  207. return SetError(errCliJobPending);
  208. }
  209. //---------------------------------------------------------------------------
  210. int TSnap7Client::AsReadSZL(int ID, int Index, PS7SZL pUsrData, int & Size)
  211. {
  212. if (!Job.Pending)
  213. {
  214. Job.Pending =true;
  215. Job.Op =s7opReadSZL;
  216. Job.ID =ID;
  217. Job.Index =Index;
  218. Job.pData =pUsrData;
  219. Job.pAmount =&Size;
  220. Job.Amount =Size;
  221. Job.IParam =1; // Data has to be copied into user buffer
  222. JobStart =SysGetTick();
  223. StartAsyncJob();
  224. return 0;
  225. }
  226. else
  227. return SetError(errCliJobPending);
  228. }
  229. //---------------------------------------------------------------------------
  230. int TSnap7Client::AsReadSZLList(PS7SZLList pUsrData, int &ItemsCount)
  231. {
  232. if (!Job.Pending)
  233. {
  234. Job.Pending =true;
  235. Job.Op =s7opReadSzlList;
  236. Job.pData =pUsrData;
  237. Job.pAmount =&ItemsCount;
  238. Job.Amount =ItemsCount;
  239. JobStart =SysGetTick();
  240. StartAsyncJob();
  241. return 0;
  242. }
  243. else
  244. return SetError(errCliJobPending);
  245. }
  246. //---------------------------------------------------------------------------
  247. int TSnap7Client::AsUpload(int BlockType, int BlockNum, void * pUsrData, int & Size)
  248. {
  249. if (!Job.Pending)
  250. {
  251. Job.Pending =true;
  252. Job.Op =s7opUpload;
  253. Job.Area =BlockType;
  254. Job.pData =pUsrData;
  255. Job.pAmount =&Size;
  256. Job.Amount =Size;
  257. Job.Number =BlockNum;
  258. Job.IParam =0; // not full upload, only data
  259. JobStart =SysGetTick();
  260. StartAsyncJob();
  261. return 0;
  262. }
  263. else
  264. return SetError(errCliJobPending);
  265. }
  266. //---------------------------------------------------------------------------
  267. int TSnap7Client::AsFullUpload(int BlockType, int BlockNum, void * pUsrData, int & Size)
  268. {
  269. if (!Job.Pending)
  270. {
  271. Job.Pending =true;
  272. Job.Op =s7opUpload;
  273. Job.Area =BlockType;
  274. Job.pData =pUsrData;
  275. Job.pAmount =&Size;
  276. Job.Amount =Size;
  277. Job.Number =BlockNum;
  278. Job.IParam =1; // full upload
  279. JobStart =SysGetTick();
  280. StartAsyncJob();
  281. return 0;
  282. }
  283. else
  284. return SetError(errCliJobPending);
  285. }
  286. //---------------------------------------------------------------------------
  287. int TSnap7Client::AsDownload(int BlockNum, void * pUsrData, int Size)
  288. {
  289. if (!Job.Pending)
  290. {
  291. // Checks the size : here we only need a size>0 to avoid problems during
  292. // doublebuffering, the real test of the block size will be done in
  293. // Checkblock.
  294. if (Size<1)
  295. return SetError(errCliInvalidBlockSize);
  296. Job.Pending =true;
  297. Job.Op =s7opDownload;
  298. // Doublebuffering
  299. memcpy(&opData, pUsrData, Size);
  300. Job.Number =BlockNum;
  301. Job.Amount =Size;
  302. JobStart =SysGetTick();
  303. StartAsyncJob();
  304. return 0;
  305. }
  306. else
  307. return SetError(errCliJobPending);
  308. }
  309. //---------------------------------------------------------------------------
  310. int TSnap7Client::AsCopyRamToRom(int Timeout)
  311. {
  312. if (!Job.Pending)
  313. {
  314. Job.Pending =true;
  315. Job.Op =s7opCopyRamToRom;
  316. if (Timeout>0)
  317. {
  318. Job.IParam =Timeout;
  319. JobStart =SysGetTick();
  320. StartAsyncJob();
  321. return 0;
  322. }
  323. else
  324. return SetError(errCliInvalidParams);
  325. }
  326. else
  327. return SetError(errCliJobPending);
  328. }
  329. //---------------------------------------------------------------------------
  330. int TSnap7Client::AsCompress(int Timeout)
  331. {
  332. if (!Job.Pending)
  333. {
  334. Job.Pending =true;
  335. Job.Op =s7opCompress;
  336. if (Timeout>0)
  337. {
  338. Job.IParam =Timeout;
  339. JobStart =SysGetTick();
  340. StartAsyncJob();
  341. return 0;
  342. }
  343. else
  344. return SetError(errCliInvalidParams);
  345. }
  346. else
  347. return SetError(errCliJobPending);
  348. }
  349. //---------------------------------------------------------------------------
  350. int TSnap7Client::AsDBRead(int DBNumber, int Start, int Size, void * pUsrData)
  351. {
  352. return AsReadArea(S7AreaDB, DBNumber, Start, Size, S7WLByte, pUsrData);
  353. }
  354. //---------------------------------------------------------------------------
  355. int TSnap7Client::AsDBWrite(int DBNumber, int Start, int Size, void * pUsrData)
  356. {
  357. return AsWriteArea(S7AreaDB, DBNumber, Start, Size, S7WLByte, pUsrData);
  358. }
  359. //---------------------------------------------------------------------------
  360. int TSnap7Client::AsMBRead(int Start, int Size, void * pUsrData)
  361. {
  362. return AsReadArea(S7AreaMK, 0, Start, Size, S7WLByte, pUsrData);
  363. }
  364. //---------------------------------------------------------------------------
  365. int TSnap7Client::AsMBWrite(int Start, int Size, void * pUsrData)
  366. {
  367. return AsWriteArea(S7AreaMK, 0, Start, Size, S7WLByte, pUsrData);
  368. }
  369. //---------------------------------------------------------------------------
  370. int TSnap7Client::AsEBRead(int Start, int Size, void * pUsrData)
  371. {
  372. return AsReadArea(S7AreaPE, 0, Start, Size, S7WLByte, pUsrData);
  373. }
  374. //---------------------------------------------------------------------------
  375. int TSnap7Client::AsEBWrite(int Start, int Size, void * pUsrData)
  376. {
  377. return AsWriteArea(S7AreaPE, 0, Start, Size, S7WLByte, pUsrData);
  378. }
  379. //---------------------------------------------------------------------------
  380. int TSnap7Client::AsABRead(int Start, int Size, void * pUsrData)
  381. {
  382. return AsReadArea(S7AreaPA, 0, Start, Size, S7WLByte, pUsrData);
  383. }
  384. //---------------------------------------------------------------------------
  385. int TSnap7Client::AsABWrite(int Start, int Size, void * pUsrData)
  386. {
  387. return AsWriteArea(S7AreaPA, 0, Start, Size, S7WLByte, pUsrData);
  388. }
  389. //---------------------------------------------------------------------------
  390. int TSnap7Client::AsTMRead(int Start, int Amount, void * pUsrData)
  391. {
  392. return AsReadArea(S7AreaTM, 0, Start, Amount, S7WLTimer, pUsrData);
  393. }
  394. //---------------------------------------------------------------------------
  395. int TSnap7Client::AsTMWrite(int Start, int Amount, void * pUsrData)
  396. {
  397. return AsWriteArea(S7AreaTM, 0, Start, Amount, S7WLTimer, pUsrData);
  398. }
  399. //---------------------------------------------------------------------------
  400. int TSnap7Client::AsCTRead(int Start, int Amount, void * pUsrData)
  401. {
  402. return AsReadArea(S7AreaCT, 0, Start, Amount, S7WLCounter, pUsrData);
  403. }
  404. //---------------------------------------------------------------------------
  405. int TSnap7Client::AsCTWrite(int Start, int Amount, void * pUsrData)
  406. {
  407. return AsWriteArea(S7AreaCT, 0, Start, Amount, S7WLCounter, pUsrData);
  408. }
  409. //---------------------------------------------------------------------------
  410. int TSnap7Client::AsDBGet(int DBNumber, void * pUsrData, int &Size)
  411. {
  412. if (!Job.Pending)
  413. {
  414. if (Size<=0)
  415. return SetError(errCliInvalidBlockSize);
  416. Job.Pending =true;
  417. Job.Op =s7opDBGet;
  418. Job.Number =DBNumber;
  419. Job.pData =pUsrData;
  420. Job.pAmount =&Size;
  421. Job.Amount =Size;
  422. JobStart =SysGetTick();
  423. StartAsyncJob();
  424. return 0;
  425. }
  426. else
  427. return SetError(errCliJobPending);
  428. }
  429. //---------------------------------------------------------------------------
  430. int TSnap7Client::AsDBFill(int DBNumber, int FillChar)
  431. {
  432. if (!Job.Pending)
  433. {
  434. Job.Pending =true;
  435. Job.Op =s7opDBFill;
  436. Job.Number =DBNumber;
  437. Job.IParam =FillChar;
  438. JobStart =SysGetTick();
  439. StartAsyncJob();
  440. return 0;
  441. }
  442. else
  443. return SetError(errCliJobPending);
  444. }
  445. //---------------------------------------------------------------------------
  446. void TSnap7Client::StartAsyncJob()
  447. {
  448. ClrError();
  449. if (!ThreadCreated)
  450. {
  451. EvtJob = new TSnapEvent(false);
  452. EvtComplete = new TSnapEvent(false);
  453. OpenThread();
  454. ThreadCreated=true;
  455. }
  456. EvtComplete->Reset(); // reset if previously was not called WaitAsCompletion
  457. EvtJob->Set();
  458. }
  459. //---------------------------------------------------------------------------
  460. int TSnap7Client::WaitAsCompletion(unsigned long Timeout)
  461. {
  462. if (Job.Pending)
  463. {
  464. if (ThreadCreated)
  465. {
  466. if (EvtComplete->WaitFor(Timeout)==WAIT_OBJECT_0)
  467. return Job.Result;
  468. else
  469. {
  470. if (Destroying)
  471. return errCliDestroying;
  472. else
  473. return SetError(errCliJobTimeout);
  474. }
  475. }
  476. else
  477. return SetError(errCliJobTimeout);
  478. }
  479. else
  480. return Job.Result;
  481. }
  482. //---------------------------------------------------------------------------
  483. void TClientThread::Execute()
  484. {
  485. while (!Terminated)
  486. {
  487. FClient->EvtJob->WaitForever();
  488. if (!Terminated)
  489. {
  490. FClient->PerformOperation();
  491. FClient->EvtComplete->Set();
  492. // Notify the caller the end of job (if callback is set)
  493. FClient->DoCompletion();
  494. }
  495. };
  496. }