client.c 19 KB

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