sms_client.c 21 KB

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