client.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. /*=============================================================================|
  2. | PROJECT SNAP7 1.4.0 |
  3. |==============================================================================|
  4. | Copyright (C) 2013, 2014 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. | |
  27. | Client Example |
  28. | |
  29. |=============================================================================*/
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include "snap7.h"
  33. #ifdef OS_WINDOWS
  34. # define WIN32_LEAN_AND_MEAN
  35. # include <windows.h>
  36. #endif
  37. TS7Client *Client;
  38. byte Buffer[65536]; // 64 K buffer
  39. int SampleDBNum = 1000;
  40. char *Address; // PLC IP Address
  41. int Rack=0,Slot=2; // Default Rack and Slot
  42. int ok = 0; // Number of test pass
  43. int ko = 0; // Number of test failure
  44. bool JobDone=false;
  45. int JobResult=0;
  46. //------------------------------------------------------------------------------
  47. // Async completion callback
  48. //------------------------------------------------------------------------------
  49. // This is a simply text demo, we use callback only to set an internal flag...
  50. void S7API CliCompletion(void *usrPtr, int opCode, int opResult)
  51. {
  52. JobResult=opResult;
  53. JobDone = true;
  54. }
  55. //------------------------------------------------------------------------------
  56. // SysSleep (copied from snap_sysutils.cpp) multiplatform millisec sleep
  57. //------------------------------------------------------------------------------
  58. void SysSleep(longword Delay_ms)
  59. {
  60. #ifdef OS_WINDOWS
  61. Sleep(Delay_ms);
  62. #else
  63. struct timespec ts;
  64. ts.tv_sec = (time_t)(Delay_ms / 1000);
  65. ts.tv_nsec =(long)((Delay_ms - ts.tv_sec) * 1000000);
  66. nanosleep(&ts, (struct timespec *)0);
  67. #endif
  68. }
  69. //------------------------------------------------------------------------------
  70. // Usage Syntax
  71. //------------------------------------------------------------------------------
  72. void Usage()
  73. {
  74. printf("Usage\n");
  75. printf(" client <IP> [Rack=0 Slot=2]\n");
  76. printf("Example\n");
  77. printf(" client 192.168.1.101 0 2\n");
  78. printf("or\n");
  79. printf(" client 192.168.1.101\n");
  80. getchar();
  81. }
  82. //------------------------------------------------------------------------------
  83. // hexdump, a very nice function, it's not mine.
  84. // I found it on the net somewhere some time ago... thanks to the author ;-)
  85. //------------------------------------------------------------------------------
  86. #ifndef HEXDUMP_COLS
  87. #define HEXDUMP_COLS 16
  88. #endif
  89. void hexdump(void *mem, unsigned int len)
  90. {
  91. unsigned int i, j;
  92. for(i = 0; i < len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0); i++)
  93. {
  94. /* print offset */
  95. if(i % HEXDUMP_COLS == 0)
  96. {
  97. printf("0x%04x: ", i);
  98. }
  99. /* print hex data */
  100. if(i < len)
  101. {
  102. printf("%02x ", 0xFF & ((char*)mem)[i]);
  103. }
  104. else /* end of block, just aligning for ASCII dump */
  105. {
  106. printf(" ");
  107. }
  108. /* print ASCII dump */
  109. if(i % HEXDUMP_COLS == (HEXDUMP_COLS - 1))
  110. {
  111. for(j = i - (HEXDUMP_COLS - 1); j <= i; j++)
  112. {
  113. if(j >= len) /* end of block, not really printing */
  114. {
  115. putchar(' ');
  116. }
  117. else if(isprint((((char*)mem)[j] & 0x7F))) /* printable char */
  118. {
  119. putchar(0xFF & ((char*)mem)[j]);
  120. }
  121. else /* other char */
  122. {
  123. putchar('.');
  124. }
  125. }
  126. putchar('\n');
  127. }
  128. }
  129. }
  130. //------------------------------------------------------------------------------
  131. // Check error
  132. //------------------------------------------------------------------------------
  133. bool Check(int Result, const char * function)
  134. {
  135. printf("\n");
  136. printf("+-----------------------------------------------------\n");
  137. printf("| %s\n",function);
  138. printf("+-----------------------------------------------------\n");
  139. if (Result==0) {
  140. printf("| Result : OK\n");
  141. printf("| Execution time : %d ms\n",Client->ExecTime());
  142. printf("+-----------------------------------------------------\n");
  143. ok++;
  144. }
  145. else {
  146. printf("| ERROR !!! \n");
  147. if (Result<0)
  148. printf("| Library Error (-1)\n");
  149. else
  150. printf("| %s\n",CliErrorText(Result).c_str());
  151. printf("+-----------------------------------------------------\n");
  152. ko++;
  153. }
  154. return Result==0;
  155. }
  156. //------------------------------------------------------------------------------
  157. // Multi Read
  158. //------------------------------------------------------------------------------
  159. void MultiRead()
  160. {
  161. // Multiread buffers
  162. byte MB[16]; // 16 Merker bytes
  163. byte EB[16]; // 16 Digital Input bytes
  164. byte AB[16]; // 16 Digital Output bytes
  165. word TM[8]; // 8 timers
  166. word CT[8]; // 8 counters
  167. // Prepare struct
  168. TS7DataItem Items[5];
  169. // NOTE : *AMOUNT IS NOT SIZE* , it's the number of items
  170. // Merkers
  171. Items[0].Area =S7AreaMK;
  172. Items[0].WordLen =S7WLByte;
  173. Items[0].DBNumber =0; // Don't need DB
  174. Items[0].Start =0; // Starting from 0
  175. Items[0].Amount =16; // 16 Items (bytes)
  176. Items[0].pdata =&MB;
  177. // Digital Input bytes
  178. Items[1].Area =S7AreaPE;
  179. Items[1].WordLen =S7WLByte;
  180. Items[1].DBNumber =0; // Don't need DB
  181. Items[1].Start =0; // Starting from 0
  182. Items[1].Amount =16; // 16 Items (bytes)
  183. Items[1].pdata =&EB;
  184. // Digital Output bytes
  185. Items[2].Area =S7AreaPA;
  186. Items[2].WordLen =S7WLByte;
  187. Items[2].DBNumber =0; // Don't need DB
  188. Items[2].Start =0; // Starting from 0
  189. Items[2].Amount =16; // 16 Items (bytes)
  190. Items[2].pdata =&AB;
  191. // Timers
  192. Items[3].Area =S7AreaTM;
  193. Items[3].WordLen =S7WLTimer;
  194. Items[3].DBNumber =0; // Don't need DB
  195. Items[3].Start =0; // Starting from 0
  196. Items[3].Amount =8; // 8 Timers
  197. Items[3].pdata =&TM;
  198. // Counters
  199. Items[4].Area =S7AreaCT;
  200. Items[4].WordLen =S7WLCounter;
  201. Items[4].DBNumber =0; // Don't need DB
  202. Items[4].Start =0; // Starting from 0
  203. Items[4].Amount =8; // 8 Counters
  204. Items[4].pdata =&CT;
  205. int res=Client->ReadMultiVars(&Items[0],5);
  206. if (Check(res,"Multiread Vars"))
  207. {
  208. // Result of Client->ReadMultivars is the "global result" of
  209. // the function, it's OK if something was exchanged.
  210. // But we need to check single Var results.
  211. // Let shall suppose that we ask for 5 vars, 4 of them are ok but
  212. // the 5th is inexistent, we will have 4 results ok and 1 not ok.
  213. printf("Dump MB0..MB15 - Var Result : %d\n",Items[0].Result);
  214. if (Items[0].Result==0)
  215. hexdump(&MB,16);
  216. printf("Dump EB0..EB15 - Var Result : %d\n",Items[1].Result);
  217. if (Items[1].Result==0)
  218. hexdump(&EB,16);
  219. printf("Dump AB0..AB15 - Var Result : %d\n",Items[2].Result);
  220. if (Items[2].Result==0)
  221. hexdump(&AB,16);
  222. printf("Dump T0..T7 - Var Result : %d\n",Items[3].Result);
  223. if (Items[3].Result==0)
  224. hexdump(&TM,16); // 8 Timers -> 16 bytes
  225. printf("Dump Z0..Z7 - Var Result : %d\n",Items[4].Result);
  226. if (Items[4].Result==0)
  227. hexdump(&CT,16); // 8 Counters -> 16 bytes
  228. };
  229. }
  230. //------------------------------------------------------------------------------
  231. // List blocks in AG
  232. //------------------------------------------------------------------------------
  233. void ListBlocks()
  234. {
  235. TS7BlocksList List;
  236. int res=Client->ListBlocks(&List);
  237. if (Check(res,"List Blocks in AG"))
  238. {
  239. printf(" OBCount : %d\n",List.OBCount);
  240. printf(" FBCount : %d\n",List.FBCount);
  241. printf(" FCCount : %d\n",List.FCCount);
  242. printf(" SFBCount : %d\n",List.SFBCount);
  243. printf(" SFCCount : %d\n",List.SFCCount);
  244. printf(" DBCount : %d\n",List.DBCount);
  245. printf(" SDBCount : %d\n",List.SDBCount);
  246. };
  247. }
  248. //------------------------------------------------------------------------------
  249. // CPU Info : catalog
  250. //------------------------------------------------------------------------------
  251. void OrderCode()
  252. {
  253. TS7OrderCode Info;
  254. int res=Client->GetOrderCode(&Info);
  255. if (Check(res,"Catalog"))
  256. {
  257. printf(" Order Code : %s\n",Info.Code);
  258. printf(" Version : %d.%d.%d\n",Info.V1,Info.V2,Info.V3);
  259. };
  260. }
  261. //------------------------------------------------------------------------------
  262. // CPU Info : unit info
  263. //------------------------------------------------------------------------------
  264. void CpuInfo()
  265. {
  266. TS7CpuInfo Info;
  267. int res=Client->GetCpuInfo(&Info);
  268. if (Check(res,"Unit Info"))
  269. {
  270. printf(" Module Type Name : %s\n",Info.ModuleTypeName);
  271. printf(" Serial Number : %s\n",Info.SerialNumber);
  272. printf(" AS Name : %s\n",Info.ASName);
  273. printf(" Module Name : %s\n",Info.ModuleName);
  274. };
  275. }
  276. //------------------------------------------------------------------------------
  277. // CP Info
  278. //------------------------------------------------------------------------------
  279. void CpInfo()
  280. {
  281. TS7CpInfo Info;
  282. int res=Client->GetCpInfo(&Info);
  283. if (Check(res,"Communication processor Info"))
  284. {
  285. printf(" Max PDU Length : %d bytes\n",Info.MaxPduLengt);
  286. printf(" Max Connections : %d \n",Info.MaxConnections);
  287. printf(" Max MPI Rate : %d bps\n",Info.MaxMpiRate);
  288. printf(" Max Bus Rate : %d bps\n",Info.MaxBusRate);
  289. };
  290. }
  291. //------------------------------------------------------------------------------
  292. // PLC Status
  293. //------------------------------------------------------------------------------
  294. void UnitStatus()
  295. {
  296. int res=0;
  297. int Status=Client->PlcStatus();
  298. if (Check(res,"CPU Status"))
  299. {
  300. switch (Status)
  301. {
  302. case S7CpuStatusRun : printf(" RUN\n"); break;
  303. case S7CpuStatusStop: printf(" STOP\n"); break;
  304. default : printf(" UNKNOWN\n"); break;
  305. }
  306. };
  307. }
  308. //------------------------------------------------------------------------------
  309. // Upload DB0 (surely exists in AG)
  310. //------------------------------------------------------------------------------
  311. void UploadDB0()
  312. {
  313. int Size = sizeof(Buffer); // Size is IN/OUT par
  314. // In input it tells the client the size available
  315. // In output it tells us how many bytes were uploaded.
  316. int res=Client->Upload(Block_SDB, 0, &Buffer, &Size);
  317. if (Check(res,"Block Upload (SDB 0)"))
  318. {
  319. printf("Dump (%d bytes) :\n",Size);
  320. hexdump(&Buffer,Size);
  321. }
  322. }
  323. //------------------------------------------------------------------------------
  324. // Async Upload DB0 (using callback as completion trigger)
  325. //------------------------------------------------------------------------------
  326. void AsCBUploadDB0()
  327. {
  328. int Size = sizeof(Buffer); // Size is IN/OUT par
  329. // In input it tells the client the size available
  330. // In output it tells us how many bytes were uploaded.
  331. JobDone=false;
  332. int res=Client->AsUpload(Block_SDB, 0, &Buffer, &Size);
  333. if (res==0)
  334. {
  335. while (!JobDone)
  336. {
  337. SysSleep(100);
  338. }
  339. res=JobResult;
  340. }
  341. if (Check(res,"Async (callback) Block Upload (SDB 0)"))
  342. {
  343. printf("Dump (%d bytes) :\n",Size);
  344. hexdump(&Buffer,Size);
  345. }
  346. }
  347. //------------------------------------------------------------------------------
  348. // Async Upload DB0 (using event wait as completion trigger)
  349. //------------------------------------------------------------------------------
  350. void AsEWUploadDB0()
  351. {
  352. int Size = sizeof(Buffer); // Size is IN/OUT par
  353. // In input it tells the client the size available
  354. // In output it tells us how many bytes were uploaded.
  355. JobDone=false;
  356. int res=Client->AsUpload(Block_SDB, 0, &Buffer, &Size);
  357. if (res==0)
  358. {
  359. res=Client->WaitAsCompletion(3000);
  360. }
  361. if (Check(res,"Async (Wait event) Block Upload (SDB 0)"))
  362. {
  363. printf("Dump (%d bytes) :\n",Size);
  364. hexdump(&Buffer,Size);
  365. }
  366. }
  367. //------------------------------------------------------------------------------
  368. // Async Upload DB0 (using polling as completion trigger)
  369. //------------------------------------------------------------------------------
  370. void AsPOUploadDB0()
  371. {
  372. int Size = sizeof(Buffer); // Size is IN/OUT par
  373. // In input it tells the client the size available
  374. // In output it tells us how many bytes were uploaded.
  375. JobDone=false;
  376. int res=Client->AsUpload(Block_SDB, 0, &Buffer, &Size);
  377. if (res==0)
  378. {
  379. while (!Client->CheckAsCompletion(&res))
  380. {
  381. SysSleep(100);
  382. };
  383. }
  384. if (Check(res,"Async (polling) Block Upload (SDB 0)"))
  385. {
  386. printf("Dump (%d bytes) :\n",Size);
  387. hexdump(&Buffer,Size);
  388. }
  389. }
  390. //------------------------------------------------------------------------------
  391. // Read a sample SZL Block
  392. //------------------------------------------------------------------------------
  393. void ReadSzl_0011_0000()
  394. {
  395. PS7SZL SZL = PS7SZL(&Buffer); // use our buffer casted as TS7SZL
  396. int Size = sizeof(Buffer);
  397. // Block ID 0x0011 IDX 0x0000 normally exists in every CPU
  398. int res=Client->ReadSZL(0x0011, 0x0000, SZL, &Size);
  399. if (Check(res,"Read SZL - ID : 0x0011, IDX 0x0000"))
  400. {
  401. printf(" LENTHDR : %d\n",SZL->Header.LENTHDR);
  402. printf(" N_DR : %d\n",SZL->Header.N_DR);
  403. printf("Dump (%d bytes) :\n",Size);
  404. hexdump(&Buffer,Size);
  405. }
  406. }
  407. //------------------------------------------------------------------------------
  408. // Unit Connection
  409. //------------------------------------------------------------------------------
  410. bool CliConnect()
  411. {
  412. int res = Client->ConnectTo(Address,Rack,Slot);
  413. if (Check(res,"UNIT Connection")) {
  414. printf(" Connected to : %s (Rack=%d, Slot=%d)\n",Address,Rack,Slot);
  415. printf(" PDU Requested : %d bytes\n",Client->PDURequested());
  416. printf(" PDU Negotiated : %d bytes\n",Client->PDULength());
  417. };
  418. return res==0;
  419. }
  420. //------------------------------------------------------------------------------
  421. // Unit Disconnection
  422. //------------------------------------------------------------------------------
  423. void CliDisconnect()
  424. {
  425. Client->Disconnect();
  426. }
  427. //------------------------------------------------------------------------------
  428. // Perform readonly tests, no cpu status modification
  429. //------------------------------------------------------------------------------
  430. void PerformTests()
  431. {
  432. OrderCode();
  433. CpuInfo();
  434. CpInfo();
  435. UnitStatus();
  436. ReadSzl_0011_0000();
  437. UploadDB0();
  438. AsCBUploadDB0();
  439. AsEWUploadDB0();
  440. AsPOUploadDB0();
  441. MultiRead();
  442. }
  443. //------------------------------------------------------------------------------
  444. // Tests Summary
  445. //------------------------------------------------------------------------------
  446. void Summary()
  447. {
  448. printf("\n");
  449. printf("+-----------------------------------------------------\n");
  450. printf("| Test Summary \n");
  451. printf("+-----------------------------------------------------\n");
  452. printf("| Performed : %d\n",(ok+ko));
  453. printf("| Passed : %d\n",ok);
  454. printf("| Failed : %d\n",ko);
  455. printf("+----------------------------------------[press a key]\n");
  456. getchar();
  457. }
  458. //------------------------------------------------------------------------------
  459. // Main
  460. //------------------------------------------------------------------------------
  461. int main(int argc, char* argv[])
  462. {
  463. // Get Progran args (we need the client address and optionally Rack and Slot)
  464. if (argc!=2 && argc!=4)
  465. {
  466. Usage();
  467. return 1;
  468. }
  469. Address=argv[1];
  470. if (argc==4)
  471. {
  472. Rack=atoi(argv[2]);
  473. Slot=atoi(argv[3]);
  474. }
  475. // Client Creation
  476. Client= new TS7Client();
  477. Client->SetAsCallback(CliCompletion,NULL);
  478. // Connection
  479. if (CliConnect())
  480. {
  481. PerformTests();
  482. CliDisconnect();
  483. };
  484. // Deletion
  485. delete Client;
  486. Summary();
  487. return 0;
  488. }