Sharp7.cs 125 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619
  1. /*=============================================================================|
  2. | PROJECT Sharp7 1.0.0 |
  3. |==============================================================================|
  4. | Copyright (C) 2016 Davide Nardella |
  5. | All rights reserved. |
  6. |==============================================================================|
  7. | Sharp7 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 which includes |
  13. | Sharp7 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. | Sharp7 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 Sharp7. |
  24. | If not, see http://www.gnu.org/licenses/ |
  25. |=============================================================================*/
  26. using System;
  27. using System.Runtime.InteropServices;
  28. using System.Text;
  29. using System.Threading;
  30. //------------------------------------------------------------------------------
  31. // If you are compiling for UWP verify that WINDOWS_UWP or NETFX_CORE are
  32. // defined into Project Properties->Build->Conditional compilation symbols
  33. //------------------------------------------------------------------------------
  34. #if WINDOWS_UWP || NETFX_CORE
  35. using System.Threading.Tasks;
  36. using Windows.Networking;
  37. using Windows.Networking.Sockets;
  38. using Windows.Storage.Streams;
  39. #else // <-- Including MONO
  40. using System.Net.Sockets;
  41. #endif
  42. namespace Sharp7
  43. {
  44. #region [Async Sockets UWP(W10,IoT,Phone)/Windows 8/Windows 8 Phone]
  45. #if WINDOWS_UWP || NETFX_CORE
  46. class MsgSocket
  47. {
  48. private DataReader Reader = null;
  49. private DataWriter Writer = null;
  50. private StreamSocket TCPSocket;
  51. private bool _Connected;
  52. private int _ReadTimeout = 2000;
  53. private int _WriteTimeout = 2000;
  54. private int _ConnectTimeout = 1000;
  55. public static int LastError = 0;
  56. private void CreateSocket()
  57. {
  58. TCPSocket = new StreamSocket();
  59. TCPSocket.Control.NoDelay = true;
  60. _Connected = false;
  61. }
  62. public MsgSocket()
  63. {
  64. }
  65. public void Close()
  66. {
  67. if (Reader != null)
  68. {
  69. Reader.Dispose();
  70. Reader = null;
  71. }
  72. if (Writer != null)
  73. {
  74. Writer.Dispose();
  75. Writer = null;
  76. }
  77. if (TCPSocket != null)
  78. {
  79. TCPSocket.Dispose();
  80. TCPSocket = null;
  81. }
  82. _Connected = false;
  83. }
  84. private async Task AsConnect(string Host, string port, CancellationTokenSource cts)
  85. {
  86. HostName ServerHost = new HostName(Host);
  87. try
  88. {
  89. await TCPSocket.ConnectAsync(ServerHost, port).AsTask(cts.Token);
  90. _Connected = true;
  91. }
  92. catch (TaskCanceledException)
  93. {
  94. LastError = S7Consts.errTCPConnectionTimeout;
  95. }
  96. catch
  97. {
  98. LastError = S7Consts.errTCPConnectionFailed; // Maybe unreachable peer
  99. }
  100. }
  101. public int Connect(string Host, int Port)
  102. {
  103. LastError = 0;
  104. if (!Connected)
  105. {
  106. CreateSocket();
  107. CancellationTokenSource cts = new CancellationTokenSource();
  108. try
  109. {
  110. try
  111. {
  112. cts.CancelAfter(_ConnectTimeout);
  113. Task.WaitAny(Task.Run(async () => await AsConnect(Host, Port.ToString(), cts)));
  114. }
  115. catch
  116. {
  117. LastError = S7Consts.errTCPConnectionFailed;
  118. }
  119. }
  120. finally
  121. {
  122. if (cts != null)
  123. {
  124. try
  125. {
  126. cts.Cancel();
  127. cts.Dispose();
  128. cts = null;
  129. }
  130. catch { }
  131. }
  132. }
  133. if (LastError == 0)
  134. {
  135. Reader = new DataReader(TCPSocket.InputStream);
  136. Reader.InputStreamOptions = InputStreamOptions.Partial;
  137. Writer = new DataWriter(TCPSocket.OutputStream);
  138. _Connected = true;
  139. }
  140. else
  141. Close();
  142. }
  143. return LastError;
  144. }
  145. private async Task AsReadBuffer(byte[] Buffer, int Size, CancellationTokenSource cts)
  146. {
  147. try
  148. {
  149. await Reader.LoadAsync((uint)Size).AsTask(cts.Token);
  150. Reader.ReadBytes(Buffer);
  151. }
  152. catch
  153. {
  154. LastError = S7Consts.errTCPDataReceive;
  155. }
  156. }
  157. public int Receive(byte[] Buffer, int Start, int Size)
  158. {
  159. byte[] InBuffer = new byte[Size];
  160. CancellationTokenSource cts = new CancellationTokenSource();
  161. LastError = 0;
  162. try
  163. {
  164. try
  165. {
  166. cts.CancelAfter(_ReadTimeout);
  167. Task.WaitAny(Task.Run(async () => await AsReadBuffer(InBuffer, Size, cts)));
  168. }
  169. catch
  170. {
  171. LastError = S7Consts.errTCPDataReceive;
  172. }
  173. }
  174. finally
  175. {
  176. if (cts != null)
  177. {
  178. try
  179. {
  180. cts.Cancel();
  181. cts.Dispose();
  182. cts = null;
  183. }
  184. catch { }
  185. }
  186. }
  187. if (LastError == 0)
  188. Array.Copy(InBuffer, 0, Buffer, Start, Size);
  189. else
  190. Close();
  191. return LastError;
  192. }
  193. private async Task WriteBuffer(byte[] Buffer, CancellationTokenSource cts)
  194. {
  195. try
  196. {
  197. Writer.WriteBytes(Buffer);
  198. await Writer.StoreAsync().AsTask(cts.Token);
  199. }
  200. catch
  201. {
  202. LastError = S7Consts.errTCPDataSend;
  203. }
  204. }
  205. public int Send(byte[] Buffer, int Size)
  206. {
  207. byte[] OutBuffer = new byte[Size];
  208. CancellationTokenSource cts = new CancellationTokenSource();
  209. Array.Copy(Buffer, 0, OutBuffer, 0, Size);
  210. LastError = 0;
  211. try
  212. {
  213. try
  214. {
  215. cts.CancelAfter(_WriteTimeout);
  216. Task.WaitAny(Task.Run(async () => await WriteBuffer(OutBuffer, cts)));
  217. }
  218. catch
  219. {
  220. LastError = S7Consts.errTCPDataSend;
  221. }
  222. }
  223. finally
  224. {
  225. if (cts != null)
  226. {
  227. try
  228. {
  229. cts.Cancel();
  230. cts.Dispose();
  231. cts = null;
  232. }
  233. catch { }
  234. }
  235. }
  236. if (LastError != 0)
  237. Close();
  238. return LastError;
  239. }
  240. ~MsgSocket()
  241. {
  242. Close();
  243. }
  244. public bool Connected
  245. {
  246. get
  247. {
  248. return (TCPSocket != null) && _Connected;
  249. }
  250. }
  251. public int ReadTimeout
  252. {
  253. get
  254. {
  255. return _ReadTimeout;
  256. }
  257. set
  258. {
  259. _ReadTimeout = value;
  260. }
  261. }
  262. public int WriteTimeout
  263. {
  264. get
  265. {
  266. return _WriteTimeout;
  267. }
  268. set
  269. {
  270. _WriteTimeout = value;
  271. }
  272. }
  273. public int ConnectTimeout
  274. {
  275. get
  276. {
  277. return _ConnectTimeout;
  278. }
  279. set
  280. {
  281. _ConnectTimeout = value;
  282. }
  283. }
  284. }
  285. #endif
  286. #endregion
  287. #region [Sync Sockets Win32/Win64 Desktop Application]
  288. #if !WINDOWS_UWP && !NETFX_CORE
  289. class MsgSocket
  290. {
  291. private Socket TCPSocket;
  292. private int _ReadTimeout = 2000;
  293. private int _WriteTimeout = 2000;
  294. private int _ConnectTimeout = 1000;
  295. public int LastError = 0;
  296. public MsgSocket()
  297. {
  298. }
  299. ~MsgSocket()
  300. {
  301. Close();
  302. }
  303. public void Close()
  304. {
  305. if (TCPSocket != null)
  306. {
  307. TCPSocket.Dispose();
  308. TCPSocket = null;
  309. }
  310. }
  311. private void CreateSocket()
  312. {
  313. TCPSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  314. TCPSocket.NoDelay = true;
  315. }
  316. private void TCPPing(string Host, int Port)
  317. {
  318. // To Ping the PLC an Asynchronous socket is used rather then an ICMP packet.
  319. // This allows the use also across Internet and Firewalls (obviously the port must be opened)
  320. LastError = 0;
  321. Socket PingSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  322. try
  323. {
  324. IAsyncResult result = PingSocket.BeginConnect(Host, Port, null, null);
  325. bool success = result.AsyncWaitHandle.WaitOne(_ConnectTimeout, true);
  326. if (!success)
  327. {
  328. LastError = S7Consts.errTCPConnectionFailed;
  329. }
  330. }
  331. catch
  332. {
  333. LastError = S7Consts.errTCPConnectionFailed;
  334. };
  335. PingSocket.Close();
  336. }
  337. public int Connect(string Host, int Port)
  338. {
  339. LastError = 0;
  340. if (!Connected)
  341. {
  342. TCPPing(Host, Port);
  343. if (LastError == 0)
  344. try
  345. {
  346. CreateSocket();
  347. TCPSocket.Connect(Host, Port);
  348. }
  349. catch
  350. {
  351. LastError = S7Consts.errTCPConnectionFailed;
  352. }
  353. }
  354. return LastError;
  355. }
  356. private int WaitForData(int Size, int Timeout)
  357. {
  358. bool Expired = false;
  359. int SizeAvail;
  360. int Elapsed = Environment.TickCount;
  361. LastError = 0;
  362. try
  363. {
  364. SizeAvail = TCPSocket.Available;
  365. while ((SizeAvail < Size) && (!Expired))
  366. {
  367. Thread.Sleep(2);
  368. SizeAvail = TCPSocket.Available;
  369. Expired = Environment.TickCount - Elapsed > Timeout;
  370. // If timeout we clean the buffer
  371. if (Expired && (SizeAvail > 0))
  372. try
  373. {
  374. byte[] Flush = new byte[SizeAvail];
  375. TCPSocket.Receive(Flush, 0, SizeAvail, SocketFlags.None);
  376. }
  377. catch { }
  378. }
  379. }
  380. catch
  381. {
  382. LastError = S7Consts.errTCPDataReceive;
  383. }
  384. if (Expired)
  385. {
  386. LastError = S7Consts.errTCPDataReceive;
  387. }
  388. return LastError;
  389. }
  390. public int Receive(byte[] Buffer, int Start, int Size)
  391. {
  392. int BytesRead = 0;
  393. LastError = WaitForData(Size, _ReadTimeout);
  394. if (LastError == 0)
  395. {
  396. try
  397. {
  398. BytesRead = TCPSocket.Receive(Buffer, Start, Size, SocketFlags.None);
  399. }
  400. catch
  401. {
  402. LastError = S7Consts.errTCPDataReceive;
  403. }
  404. if (BytesRead == 0) // Connection Reset by the peer
  405. {
  406. LastError = S7Consts.errTCPDataReceive;
  407. Close();
  408. }
  409. }
  410. return LastError;
  411. }
  412. public int Send(byte[] Buffer, int Size)
  413. {
  414. LastError = 0;
  415. try
  416. {
  417. int BytesSent = TCPSocket.Send(Buffer, Size, SocketFlags.None);
  418. }
  419. catch
  420. {
  421. LastError = S7Consts.errTCPDataSend;
  422. Close();
  423. }
  424. return LastError;
  425. }
  426. public bool Connected
  427. {
  428. get
  429. {
  430. return (TCPSocket != null) && (TCPSocket.Connected);
  431. }
  432. }
  433. public int ReadTimeout
  434. {
  435. get
  436. {
  437. return _ReadTimeout;
  438. }
  439. set
  440. {
  441. _ReadTimeout = value;
  442. }
  443. }
  444. public int WriteTimeout
  445. {
  446. get
  447. {
  448. return _WriteTimeout;
  449. }
  450. set
  451. {
  452. _WriteTimeout = value;
  453. }
  454. }
  455. public int ConnectTimeout
  456. {
  457. get
  458. {
  459. return _ConnectTimeout;
  460. }
  461. set
  462. {
  463. _ConnectTimeout = value;
  464. }
  465. }
  466. }
  467. #endif
  468. #endregion
  469. public static class S7Consts
  470. {
  471. #region [Exported Consts]
  472. // Error codes
  473. //------------------------------------------------------------------------------
  474. // ERRORS
  475. //------------------------------------------------------------------------------
  476. public const int errTCPSocketCreation = 0x00000001;
  477. public const int errTCPConnectionTimeout = 0x00000002;
  478. public const int errTCPConnectionFailed = 0x00000003;
  479. public const int errTCPReceiveTimeout = 0x00000004;
  480. public const int errTCPDataReceive = 0x00000005;
  481. public const int errTCPSendTimeout = 0x00000006;
  482. public const int errTCPDataSend = 0x00000007;
  483. public const int errTCPConnectionReset = 0x00000008;
  484. public const int errTCPNotConnected = 0x00000009;
  485. public const int errTCPUnreachableHost = 0x00002751;
  486. public const int errIsoConnect = 0x00010000; // Connection error
  487. public const int errIsoInvalidPDU = 0x00030000; // Bad format
  488. public const int errIsoInvalidDataSize = 0x00040000; // Bad Datasize passed to send/recv : buffer is invalid
  489. public const int errCliNegotiatingPDU = 0x00100000;
  490. public const int errCliInvalidParams = 0x00200000;
  491. public const int errCliJobPending = 0x00300000;
  492. public const int errCliTooManyItems = 0x00400000;
  493. public const int errCliInvalidWordLen = 0x00500000;
  494. public const int errCliPartialDataWritten = 0x00600000;
  495. public const int errCliSizeOverPDU = 0x00700000;
  496. public const int errCliInvalidPlcAnswer = 0x00800000;
  497. public const int errCliAddressOutOfRange = 0x00900000;
  498. public const int errCliInvalidTransportSize = 0x00A00000;
  499. public const int errCliWriteDataSizeMismatch = 0x00B00000;
  500. public const int errCliItemNotAvailable = 0x00C00000;
  501. public const int errCliInvalidValue = 0x00D00000;
  502. public const int errCliCannotStartPLC = 0x00E00000;
  503. public const int errCliAlreadyRun = 0x00F00000;
  504. public const int errCliCannotStopPLC = 0x01000000;
  505. public const int errCliCannotCopyRamToRom = 0x01100000;
  506. public const int errCliCannotCompress = 0x01200000;
  507. public const int errCliAlreadyStop = 0x01300000;
  508. public const int errCliFunNotAvailable = 0x01400000;
  509. public const int errCliUploadSequenceFailed = 0x01500000;
  510. public const int errCliInvalidDataSizeRecvd = 0x01600000;
  511. public const int errCliInvalidBlockType = 0x01700000;
  512. public const int errCliInvalidBlockNumber = 0x01800000;
  513. public const int errCliInvalidBlockSize = 0x01900000;
  514. public const int errCliNeedPassword = 0x01D00000;
  515. public const int errCliInvalidPassword = 0x01E00000;
  516. public const int errCliNoPasswordToSetOrClear = 0x01F00000;
  517. public const int errCliJobTimeout = 0x02000000;
  518. public const int errCliPartialDataRead = 0x02100000;
  519. public const int errCliBufferTooSmall = 0x02200000;
  520. public const int errCliFunctionRefused = 0x02300000;
  521. public const int errCliDestroying = 0x02400000;
  522. public const int errCliInvalidParamNumber = 0x02500000;
  523. public const int errCliCannotChangeParam = 0x02600000;
  524. public const int errCliFunctionNotImplemented = 0x02700000;
  525. //------------------------------------------------------------------------------
  526. // PARAMS LIST FOR COMPATIBILITY WITH Snap7.net.cs
  527. //------------------------------------------------------------------------------
  528. public const Int32 p_u16_LocalPort = 1; // Not applicable here
  529. public const Int32 p_u16_RemotePort = 2;
  530. public const Int32 p_i32_PingTimeout = 3;
  531. public const Int32 p_i32_SendTimeout = 4;
  532. public const Int32 p_i32_RecvTimeout = 5;
  533. public const Int32 p_i32_WorkInterval = 6; // Not applicable here
  534. public const Int32 p_u16_SrcRef = 7; // Not applicable here
  535. public const Int32 p_u16_DstRef = 8; // Not applicable here
  536. public const Int32 p_u16_SrcTSap = 9; // Not applicable here
  537. public const Int32 p_i32_PDURequest = 10;
  538. public const Int32 p_i32_MaxClients = 11; // Not applicable here
  539. public const Int32 p_i32_BSendTimeout = 12; // Not applicable here
  540. public const Int32 p_i32_BRecvTimeout = 13; // Not applicable here
  541. public const Int32 p_u32_RecoveryTime = 14; // Not applicable here
  542. public const Int32 p_u32_KeepAliveTime = 15; // Not applicable here
  543. // Area ID
  544. public const byte S7AreaPE = 0x81;
  545. public const byte S7AreaPA = 0x82;
  546. public const byte S7AreaMK = 0x83;
  547. public const byte S7AreaDB = 0x84;
  548. public const byte S7AreaCT = 0x1C;
  549. public const byte S7AreaTM = 0x1D;
  550. // Word Length
  551. public const int S7WLBit = 0x01;
  552. public const int S7WLByte = 0x02;
  553. public const int S7WLChar = 0x03;
  554. public const int S7WLWord = 0x04;
  555. public const int S7WLInt = 0x05;
  556. public const int S7WLDWord = 0x06;
  557. public const int S7WLDInt = 0x07;
  558. public const int S7WLReal = 0x08;
  559. public const int S7WLCounter = 0x1C;
  560. public const int S7WLTimer = 0x1D;
  561. // PLC Status
  562. public const int S7CpuStatusUnknown = 0x00;
  563. public const int S7CpuStatusRun = 0x08;
  564. public const int S7CpuStatusStop = 0x04;
  565. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  566. public struct S7Tag
  567. {
  568. public Int32 Area;
  569. public Int32 DBNumber;
  570. public Int32 Start;
  571. public Int32 Elements;
  572. public Int32 WordLen;
  573. }
  574. #endregion
  575. }
  576. public static class S7
  577. {
  578. #region [Help Functions]
  579. private static Int64 bias = 621355968000000000; // "decimicros" between 0001-01-01 00:00:00 and 1970-01-01 00:00:00
  580. private static int BCDtoByte(byte B)
  581. {
  582. return ((B >> 4) * 10) + (B & 0x0F);
  583. }
  584. private static byte ByteToBCD(int Value)
  585. {
  586. return (byte)(((Value / 10) << 4) | (Value % 10));
  587. }
  588. private static byte[] CopyFrom(byte[] Buffer, int Pos, int Size)
  589. {
  590. byte[] Result=new byte[Size];
  591. Array.Copy(Buffer, Pos, Result, 0, Size);
  592. return Result;
  593. }
  594. public static int DataSizeByte(int WordLength)
  595. {
  596. switch (WordLength)
  597. {
  598. case S7Consts.S7WLBit: return 1; // S7 sends 1 byte per bit
  599. case S7Consts.S7WLByte: return 1;
  600. case S7Consts.S7WLChar: return 1;
  601. case S7Consts.S7WLWord: return 2;
  602. case S7Consts.S7WLDWord: return 4;
  603. case S7Consts.S7WLInt: return 2;
  604. case S7Consts.S7WLDInt: return 4;
  605. case S7Consts.S7WLReal: return 4;
  606. case S7Consts.S7WLCounter: return 2;
  607. case S7Consts.S7WLTimer: return 2;
  608. default: return 0;
  609. }
  610. }
  611. #region Get/Set the bit at Pos.Bit
  612. public static bool GetBitAt(byte[] Buffer, int Pos, int Bit)
  613. {
  614. byte[] Mask = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
  615. if (Bit < 0) Bit = 0;
  616. if (Bit > 7) Bit = 7;
  617. return (Buffer[Pos] & Mask[Bit]) != 0;
  618. }
  619. public static void SetBitAt(ref byte[] Buffer, int Pos, int Bit, bool Value)
  620. {
  621. byte[] Mask = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
  622. if (Bit < 0) Bit = 0;
  623. if (Bit > 7) Bit = 7;
  624. if (Value)
  625. Buffer[Pos] = (byte)(Buffer[Pos] | Mask[Bit]);
  626. else
  627. Buffer[Pos] = (byte)(Buffer[Pos] & ~Mask[Bit]);
  628. }
  629. #endregion
  630. #region Get/Set 8 bit signed value (S7 SInt) -128..127
  631. public static int GetSIntAt(byte[] Buffer, int Pos)
  632. {
  633. int Value = Buffer[Pos];
  634. if (Value < 128)
  635. return Value;
  636. else
  637. return (int) (Value - 256);
  638. }
  639. public static void SetSIntAt(byte[] Buffer, int Pos, int Value)
  640. {
  641. if (Value < -128) Value = -128;
  642. if (Value > 127) Value = 127;
  643. Buffer[Pos] = (byte)Value;
  644. }
  645. #endregion
  646. #region Get/Set 16 bit signed value (S7 int) -32768..32767
  647. public static int GetIntAt(byte[] Buffer, int Pos)
  648. {
  649. return (int)((Buffer[Pos] << 8) | Buffer[Pos + 1]);
  650. }
  651. public static void SetIntAt(byte[] Buffer, int Pos, Int16 Value)
  652. {
  653. Buffer[Pos] = (byte)(Value >> 8);
  654. Buffer[Pos + 1] = (byte)(Value & 0x00FF);
  655. }
  656. #endregion
  657. #region Get/Set 32 bit signed value (S7 DInt) -2147483648..2147483647
  658. public static int GetDIntAt(byte[] Buffer, int Pos)
  659. {
  660. int Result;
  661. Result = Buffer[Pos]; Result <<= 8;
  662. Result += Buffer[Pos + 1]; Result <<= 8;
  663. Result += Buffer[Pos + 2]; Result <<= 8;
  664. Result += Buffer[Pos + 3];
  665. return Result;
  666. }
  667. public static void SetDIntAt(byte[] Buffer, int Pos, int Value)
  668. {
  669. Buffer[Pos + 3] = (byte)(Value & 0xFF);
  670. Buffer[Pos + 2] = (byte)((Value >> 8) & 0xFF);
  671. Buffer[Pos + 1] = (byte)((Value >> 16) & 0xFF);
  672. Buffer[Pos] = (byte)((Value >> 24) & 0xFF);
  673. }
  674. #endregion
  675. #region Get/Set 64 bit signed value (S7 LInt) -9223372036854775808..9223372036854775807
  676. public static Int64 GetLIntAt(byte[] Buffer, int Pos)
  677. {
  678. Int64 Result;
  679. Result = Buffer[Pos]; Result <<= 8;
  680. Result += Buffer[Pos + 1]; Result <<= 8;
  681. Result += Buffer[Pos + 2]; Result <<= 8;
  682. Result += Buffer[Pos + 3]; Result <<= 8;
  683. Result += Buffer[Pos + 4]; Result <<= 8;
  684. Result += Buffer[Pos + 5]; Result <<= 8;
  685. Result += Buffer[Pos + 6]; Result <<= 8;
  686. Result += Buffer[Pos + 7];
  687. return Result;
  688. }
  689. public static void SetLIntAt(byte[] Buffer, int Pos, Int64 Value)
  690. {
  691. Buffer[Pos + 7] = (byte)(Value & 0xFF);
  692. Buffer[Pos + 6] = (byte)((Value >> 8) & 0xFF);
  693. Buffer[Pos + 5] = (byte)((Value >> 16) & 0xFF);
  694. Buffer[Pos + 4] = (byte)((Value >> 24) & 0xFF);
  695. Buffer[Pos + 3] = (byte)((Value >> 32) & 0xFF);
  696. Buffer[Pos + 2] = (byte)((Value >> 40) & 0xFF);
  697. Buffer[Pos + 1] = (byte)((Value >> 48) & 0xFF);
  698. Buffer[Pos] = (byte)((Value >> 56) & 0xFF);
  699. }
  700. #endregion
  701. #region Get/Set 8 bit unsigned value (S7 USInt) 0..255
  702. public static byte GetUSIntAt(byte[] Buffer, int Pos)
  703. {
  704. return Buffer[Pos];
  705. }
  706. public static void SetUSIntAt(byte[] Buffer, int Pos, byte Value)
  707. {
  708. Buffer[Pos] = Value;
  709. }
  710. #endregion
  711. #region Get/Set 16 bit unsigned value (S7 UInt) 0..65535
  712. public static UInt16 GetUIntAt(byte[] Buffer, int Pos)
  713. {
  714. return (UInt16)((Buffer[Pos] << 8) | Buffer[Pos + 1]);
  715. }
  716. public static void SetUIntAt(byte[] Buffer, int Pos, UInt16 Value)
  717. {
  718. Buffer[Pos] = (byte)(Value >> 8);
  719. Buffer[Pos + 1] = (byte)(Value & 0x00FF);
  720. }
  721. #endregion
  722. #region Get/Set 32 bit unsigned value (S7 UDInt) 0..4294967296
  723. public static UInt32 GetUDIntAt(byte[] Buffer, int Pos)
  724. {
  725. UInt32 Result;
  726. Result = Buffer[Pos]; Result <<= 8;
  727. Result |= Buffer[Pos + 1]; Result <<= 8;
  728. Result |= Buffer[Pos + 2]; Result <<= 8;
  729. Result |= Buffer[Pos + 3];
  730. return Result;
  731. }
  732. public static void SetUDIntAt(byte[] Buffer, int Pos, UInt32 Value)
  733. {
  734. Buffer[Pos + 3] = (byte)(Value & 0xFF);
  735. Buffer[Pos + 2] = (byte)((Value >> 8) & 0xFF);
  736. Buffer[Pos + 1] = (byte)((Value >> 16) & 0xFF);
  737. Buffer[Pos] = (byte)((Value >> 24) & 0xFF);
  738. }
  739. #endregion
  740. #region Get/Set 64 bit unsigned value (S7 ULint) 0..18446744073709551616
  741. public static UInt64 GetULIntAt(byte[] Buffer, int Pos)
  742. {
  743. UInt64 Result;
  744. Result = Buffer[Pos]; Result <<= 8;
  745. Result |= Buffer[Pos + 1]; Result <<= 8;
  746. Result |= Buffer[Pos + 2]; Result <<= 8;
  747. Result |= Buffer[Pos + 3]; Result <<= 8;
  748. Result |= Buffer[Pos + 4]; Result <<= 8;
  749. Result |= Buffer[Pos + 5]; Result <<= 8;
  750. Result |= Buffer[Pos + 6]; Result <<= 8;
  751. Result |= Buffer[Pos + 7];
  752. return Result;
  753. }
  754. public static void SetULintAt(byte[] Buffer, int Pos, UInt64 Value)
  755. {
  756. Buffer[Pos + 7] = (byte)(Value & 0xFF);
  757. Buffer[Pos + 6] = (byte)((Value >> 8) & 0xFF);
  758. Buffer[Pos + 5] = (byte)((Value >> 16) & 0xFF);
  759. Buffer[Pos + 4] = (byte)((Value >> 24) & 0xFF);
  760. Buffer[Pos + 3] = (byte)((Value >> 32) & 0xFF);
  761. Buffer[Pos + 2] = (byte)((Value >> 40) & 0xFF);
  762. Buffer[Pos + 1] = (byte)((Value >> 48) & 0xFF);
  763. Buffer[Pos] = (byte)((Value >> 56) & 0xFF);
  764. }
  765. #endregion
  766. #region Get/Set 8 bit word (S7 Byte) 16#00..16#FF
  767. public static byte GetByteAt(byte[] Buffer, int Pos)
  768. {
  769. return Buffer[Pos];
  770. }
  771. public static void SetByteAt(byte[] Buffer, int Pos, byte Value)
  772. {
  773. Buffer[Pos] = Value;
  774. }
  775. #endregion
  776. #region Get/Set 16 bit word (S7 Word) 16#0000..16#FFFF
  777. public static UInt16 GetWordAt(byte[] Buffer, int Pos)
  778. {
  779. return GetUIntAt(Buffer,Pos);
  780. }
  781. public static void SetWordAt(byte[] Buffer, int Pos, UInt16 Value)
  782. {
  783. SetUIntAt(Buffer, Pos, Value);
  784. }
  785. #endregion
  786. #region Get/Set 32 bit word (S7 DWord) 16#00000000..16#FFFFFFFF
  787. public static UInt32 GetDWordAt(byte[] Buffer, int Pos)
  788. {
  789. return GetUDIntAt(Buffer, Pos);
  790. }
  791. public static void SetDWordAt(byte[] Buffer, int Pos, UInt32 Value)
  792. {
  793. SetUDIntAt(Buffer, Pos, Value);
  794. }
  795. #endregion
  796. #region Get/Set 64 bit word (S7 LWord) 16#0000000000000000..16#FFFFFFFFFFFFFFFF
  797. public static UInt64 GetLWordAt(byte[] Buffer, int Pos)
  798. {
  799. return GetULIntAt(Buffer, Pos);
  800. }
  801. public static void SetLWordAt(byte[] Buffer, int Pos, UInt64 Value)
  802. {
  803. SetULintAt(Buffer, Pos, Value);
  804. }
  805. #endregion
  806. #region Get/Set 32 bit floating point number (S7 Real) (Range of Single)
  807. public static Single GetRealAt(byte[] Buffer, int Pos)
  808. {
  809. UInt32 Value = GetUDIntAt(Buffer, Pos);
  810. byte[] bytes = BitConverter.GetBytes(Value);
  811. return BitConverter.ToSingle(bytes, 0);
  812. }
  813. public static void SetRealAt(byte[] Buffer, int Pos, Single Value)
  814. {
  815. byte[] FloatArray = BitConverter.GetBytes(Value);
  816. Buffer[Pos] = FloatArray[3];
  817. Buffer[Pos + 1] = FloatArray[2];
  818. Buffer[Pos + 2] = FloatArray[1];
  819. Buffer[Pos + 3] = FloatArray[0];
  820. }
  821. #endregion
  822. #region Get/Set 64 bit floating point number (S7 LReal) (Range of Double)
  823. public static Double GetLRealAt(byte[] Buffer, int Pos)
  824. {
  825. UInt64 Value = GetULIntAt(Buffer, Pos);
  826. byte[] bytes = BitConverter.GetBytes(Value);
  827. return BitConverter.ToDouble(bytes, 0);
  828. }
  829. public static void SetLRealAt(byte[] Buffer, int Pos, Double Value)
  830. {
  831. byte[] FloatArray = BitConverter.GetBytes(Value);
  832. Buffer[Pos] = FloatArray[7];
  833. Buffer[Pos + 1] = FloatArray[6];
  834. Buffer[Pos + 2] = FloatArray[5];
  835. Buffer[Pos + 3] = FloatArray[4];
  836. Buffer[Pos + 4] = FloatArray[3];
  837. Buffer[Pos + 5] = FloatArray[2];
  838. Buffer[Pos + 6] = FloatArray[1];
  839. Buffer[Pos + 7] = FloatArray[0];
  840. }
  841. #endregion
  842. #region Get/Set DateTime (S7 DATE_AND_TIME)
  843. public static DateTime GetDateTimeAt(byte[] Buffer, int Pos)
  844. {
  845. int Year, Month, Day, Hour, Min, Sec, MSec;
  846. Year = BCDtoByte(Buffer[Pos]);
  847. if (Year < 90)
  848. Year += 2000;
  849. else
  850. Year += 1900;
  851. Month = BCDtoByte(Buffer[Pos + 1]);
  852. Day = BCDtoByte(Buffer[Pos + 2]);
  853. Hour = BCDtoByte(Buffer[Pos + 3]);
  854. Min = BCDtoByte(Buffer[Pos + 4]);
  855. Sec = BCDtoByte(Buffer[Pos + 5]);
  856. MSec = (BCDtoByte(Buffer[Pos + 6]) * 10) + (BCDtoByte(Buffer[Pos + 7]) / 10);
  857. try
  858. {
  859. return new DateTime(Year, Month, Day, Hour, Min, Sec, MSec);
  860. }
  861. catch (System.ArgumentOutOfRangeException)
  862. {
  863. return new DateTime(0);
  864. }
  865. }
  866. public static void SetDateTimeAt(byte[] Buffer, int Pos, DateTime Value)
  867. {
  868. int Year = Value.Year;
  869. int Month = Value.Month;
  870. int Day = Value.Day;
  871. int Hour = Value.Hour;
  872. int Min = Value.Minute;
  873. int Sec = Value.Second;
  874. int Dow = (int)Value.DayOfWeek + 1;
  875. // MSecH = First two digits of miliseconds
  876. int MsecH = Value.Millisecond / 10;
  877. // MSecL = Last digit of miliseconds
  878. int MsecL = Value.Millisecond % 10;
  879. if (Year > 1999)
  880. Year -= 2000;
  881. Buffer[Pos] = ByteToBCD(Year);
  882. Buffer[Pos + 1] = ByteToBCD(Month);
  883. Buffer[Pos + 2] = ByteToBCD(Day);
  884. Buffer[Pos + 3] = ByteToBCD(Hour);
  885. Buffer[Pos + 4] = ByteToBCD(Min);
  886. Buffer[Pos + 5] = ByteToBCD(Sec);
  887. Buffer[Pos + 6] = ByteToBCD(MsecH);
  888. Buffer[Pos + 7] = ByteToBCD(MsecL * 10 + Dow);
  889. }
  890. #endregion
  891. #region Get/Set DATE (S7 DATE)
  892. public static DateTime GetDateAt(byte[] Buffer, int Pos)
  893. {
  894. try
  895. {
  896. return new DateTime(1990, 1, 1).AddDays(GetIntAt(Buffer, Pos));
  897. }
  898. catch (System.ArgumentOutOfRangeException)
  899. {
  900. return new DateTime(0);
  901. }
  902. }
  903. public static void SetDateAt(byte[] Buffer, int Pos, DateTime Value)
  904. {
  905. SetIntAt(Buffer, Pos, (Int16)(Value - new DateTime(1990, 1, 1)).Days);
  906. }
  907. #endregion
  908. #region Get/Set TOD (S7 TIME_OF_DAY)
  909. public static DateTime GetTODAt(byte[] Buffer, int Pos)
  910. {
  911. try
  912. {
  913. return new DateTime(0).AddMilliseconds(S7.GetDIntAt(Buffer, Pos));
  914. }
  915. catch (System.ArgumentOutOfRangeException)
  916. {
  917. return new DateTime(0);
  918. }
  919. }
  920. public static void SetTODAt(byte[] Buffer, int Pos, DateTime Value)
  921. {
  922. TimeSpan Time = Value.TimeOfDay;
  923. SetDIntAt(Buffer, Pos, (Int32)Math.Round(Time.TotalMilliseconds));
  924. }
  925. #endregion
  926. #region Get/Set LTOD (S7 1500 LONG TIME_OF_DAY)
  927. public static DateTime GetLTODAt(byte[] Buffer, int Pos)
  928. {
  929. // .NET Tick = 100 ns, S71500 Tick = 1 ns
  930. try
  931. {
  932. return new DateTime(Math.Abs(GetLIntAt(Buffer,Pos)/100));
  933. }
  934. catch (System.ArgumentOutOfRangeException)
  935. {
  936. return new DateTime(0);
  937. }
  938. }
  939. public static void SetLTODAt(byte[] Buffer, int Pos, DateTime Value)
  940. {
  941. TimeSpan Time = Value.TimeOfDay;
  942. SetLIntAt(Buffer, Pos, (Int64)Time.Ticks * 100);
  943. }
  944. #endregion
  945. #region GET/SET LDT (S7 1500 Long Date and Time)
  946. public static DateTime GetLDTAt(byte[] Buffer, int Pos)
  947. {
  948. try
  949. {
  950. return new DateTime((GetLIntAt(Buffer, Pos) / 100) + bias);
  951. }
  952. catch (System.ArgumentOutOfRangeException)
  953. {
  954. return new DateTime(0);
  955. }
  956. }
  957. public static void SetLDTAt(byte[] Buffer, int Pos, DateTime Value)
  958. {
  959. SetLIntAt(Buffer, Pos, (Value.Ticks-bias) * 100);
  960. }
  961. #endregion
  962. #region Get/Set DTL (S71200/1500 Date and Time)
  963. // Thanks to Johan Cardoen for GetDTLAt
  964. public static DateTime GetDTLAt(byte[] Buffer, int Pos)
  965. {
  966. int Year, Month, Day, Hour, Min, Sec, MSec;
  967. Year = Buffer[Pos] * 256 + Buffer[Pos + 1];
  968. Month = Buffer[Pos + 2];
  969. Day = Buffer[Pos + 3];
  970. Hour = Buffer[Pos + 5];
  971. Min = Buffer[Pos + 6];
  972. Sec = Buffer[Pos + 7];
  973. MSec = (int)GetUDIntAt(Buffer, Pos + 8)/1000000;
  974. try
  975. {
  976. return new DateTime(Year, Month, Day, Hour, Min, Sec, MSec);
  977. }
  978. catch (System.ArgumentOutOfRangeException)
  979. {
  980. return new DateTime(0);
  981. }
  982. }
  983. public static void SetDTLAt(byte[] Buffer, int Pos, DateTime Value)
  984. {
  985. short Year = (short)Value.Year;
  986. byte Month = (byte)Value.Month;
  987. byte Day = (byte)Value.Day;
  988. byte Hour = (byte)Value.Hour;
  989. byte Min = (byte)Value.Minute;
  990. byte Sec = (byte)Value.Second;
  991. byte Dow = (byte)(Value.DayOfWeek + 1);
  992. Int32 NanoSecs = Value.Millisecond * 1000000;
  993. var bytes_short = BitConverter.GetBytes(Year);
  994. Buffer[Pos] = bytes_short[1];
  995. Buffer[Pos + 1] = bytes_short[0];
  996. Buffer[Pos + 2] = Month;
  997. Buffer[Pos + 3] = Day;
  998. Buffer[Pos + 4] = Dow;
  999. Buffer[Pos + 5] = Hour;
  1000. Buffer[Pos + 6] = Min;
  1001. Buffer[Pos + 7] = Sec;
  1002. SetDIntAt(Buffer, Pos + 8, NanoSecs);
  1003. }
  1004. #endregion
  1005. #region Get/Set String (S7 String)
  1006. // Thanks to Pablo Agirre
  1007. public static string GetStringAt(byte[] Buffer, int Pos)
  1008. {
  1009. int size = (int)Buffer[Pos + 1];
  1010. return Encoding.UTF8.GetString(Buffer, Pos + 2, size);
  1011. }
  1012. public static void SetStringAt(byte[] Buffer, int Pos, int MaxLen, string Value)
  1013. {
  1014. int size = Value.Length;
  1015. Buffer[Pos] = (byte)MaxLen;
  1016. Buffer[Pos + 1] = (byte)size;
  1017. Encoding.UTF8.GetBytes(Value, 0, size, Buffer, Pos + 2);
  1018. }
  1019. #endregion
  1020. #region Get/Set Array of char (S7 ARRAY OF CHARS)
  1021. public static string GetCharsAt(byte[] Buffer, int Pos, int Size)
  1022. {
  1023. return Encoding.UTF8.GetString(Buffer, Pos , Size);
  1024. }
  1025. public static void SetCharsAt(byte[] Buffer, int Pos, string Value)
  1026. {
  1027. int MaxLen = Buffer.Length - Pos;
  1028. // Truncs the string if there's no room enough
  1029. if (MaxLen > Value.Length) MaxLen = Value.Length;
  1030. Encoding.UTF8.GetBytes(Value, 0, MaxLen, Buffer, Pos);
  1031. }
  1032. #endregion
  1033. #region Get/Set Counter
  1034. public static int GetCounter(ushort Value)
  1035. {
  1036. return BCDtoByte((byte)Value) * 100 + BCDtoByte((byte)(Value >> 8));
  1037. }
  1038. public static int GetCounterAt(ushort[] Buffer, int Index)
  1039. {
  1040. return GetCounter(Buffer[Index]);
  1041. }
  1042. public static ushort ToCounter(int Value)
  1043. {
  1044. return (ushort)(ByteToBCD(Value / 100) + (ByteToBCD(Value % 100) << 8));
  1045. }
  1046. public static void SetCounterAt(ushort[] Buffer, int Pos, int Value)
  1047. {
  1048. Buffer[Pos] = ToCounter(Value);
  1049. }
  1050. #endregion
  1051. #endregion [Help Functions]
  1052. }
  1053. public class S7MultiVar
  1054. {
  1055. #region [MultiRead/Write Helper]
  1056. private S7Client FClient;
  1057. private GCHandle[] Handles = new GCHandle[S7Client.MaxVars];
  1058. private int Count = 0;
  1059. private S7Client.S7DataItem[] Items = new S7Client.S7DataItem[S7Client.MaxVars];
  1060. public int[] Results = new int[S7Client.MaxVars];
  1061. private bool AdjustWordLength(int Area, ref int WordLen, ref int Amount, ref int Start)
  1062. {
  1063. // Calc Word size
  1064. int WordSize = S7.DataSizeByte(WordLen);
  1065. if (WordSize == 0)
  1066. return false;
  1067. if (Area == S7Consts.S7AreaCT)
  1068. WordLen = S7Consts.S7WLCounter;
  1069. if (Area == S7Consts.S7AreaTM)
  1070. WordLen = S7Consts.S7WLTimer;
  1071. if (WordLen == S7Consts.S7WLBit)
  1072. Amount = 1; // Only 1 bit can be transferred at time
  1073. else
  1074. {
  1075. if ((WordLen != S7Consts.S7WLCounter) && (WordLen != S7Consts.S7WLTimer))
  1076. {
  1077. Amount = Amount * WordSize;
  1078. Start = Start * 8;
  1079. WordLen = S7Consts.S7WLByte;
  1080. }
  1081. }
  1082. return true;
  1083. }
  1084. public S7MultiVar(S7Client Client)
  1085. {
  1086. FClient = Client;
  1087. for (int c = 0; c < S7Client.MaxVars; c++)
  1088. Results[c] = (int)S7Consts.errCliItemNotAvailable;
  1089. }
  1090. ~S7MultiVar()
  1091. {
  1092. Clear();
  1093. }
  1094. public bool Add<T>(S7Consts.S7Tag Tag, ref T[] Buffer, int Offset)
  1095. {
  1096. return Add(Tag.Area, Tag.WordLen, Tag.DBNumber, Tag.Start, Tag.Elements, ref Buffer, Offset);
  1097. }
  1098. public bool Add<T>(S7Consts.S7Tag Tag, ref T[] Buffer)
  1099. {
  1100. return Add(Tag.Area, Tag.WordLen, Tag.DBNumber, Tag.Start, Tag.Elements, ref Buffer);
  1101. }
  1102. public bool Add<T>(Int32 Area, Int32 WordLen, Int32 DBNumber, Int32 Start, Int32 Amount, ref T[] Buffer)
  1103. {
  1104. return Add(Area, WordLen, DBNumber, Start, Amount, ref Buffer, 0);
  1105. }
  1106. public bool Add<T>(Int32 Area, Int32 WordLen, Int32 DBNumber, Int32 Start, Int32 Amount, ref T[] Buffer, int Offset)
  1107. {
  1108. if (Count < S7Client.MaxVars)
  1109. {
  1110. if (AdjustWordLength(Area, ref WordLen, ref Amount, ref Start))
  1111. {
  1112. Items[Count].Area = Area;
  1113. Items[Count].WordLen = WordLen;
  1114. Items[Count].Result = (int)S7Consts.errCliItemNotAvailable;
  1115. Items[Count].DBNumber = DBNumber;
  1116. Items[Count].Start = Start;
  1117. Items[Count].Amount = Amount;
  1118. GCHandle handle = GCHandle.Alloc(Buffer, GCHandleType.Pinned);
  1119. #if WINDOWS_UWP || NETFX_CORE
  1120. if (IntPtr.Size == 4)
  1121. Items[Count].pData = (IntPtr)(handle.AddrOfPinnedObject().ToInt32() + Offset * Marshal.SizeOf<T>());
  1122. else
  1123. Items[Count].pData = (IntPtr)(handle.AddrOfPinnedObject().ToInt64() + Offset * Marshal.SizeOf<T>());
  1124. #else
  1125. if (IntPtr.Size == 4)
  1126. Items[Count].pData = (IntPtr)(handle.AddrOfPinnedObject().ToInt32() + Offset * Marshal.SizeOf(typeof(T)));
  1127. else
  1128. Items[Count].pData = (IntPtr)(handle.AddrOfPinnedObject().ToInt64() + Offset * Marshal.SizeOf(typeof(T)));
  1129. #endif
  1130. Handles[Count] = handle;
  1131. Count++;
  1132. return true;
  1133. }
  1134. else
  1135. return false;
  1136. }
  1137. else
  1138. return false;
  1139. }
  1140. public int Read()
  1141. {
  1142. int FunctionResult;
  1143. int GlobalResult = (int)S7Consts.errCliFunctionRefused;
  1144. try
  1145. {
  1146. if (Count > 0)
  1147. {
  1148. FunctionResult = FClient.ReadMultiVars(Items, Count);
  1149. if (FunctionResult == 0)
  1150. for (int c = 0; c < S7Client.MaxVars; c++)
  1151. Results[c] = Items[c].Result;
  1152. GlobalResult = FunctionResult;
  1153. }
  1154. else
  1155. GlobalResult = (int)S7Consts.errCliFunctionRefused;
  1156. }
  1157. finally
  1158. {
  1159. Clear(); // handles are no more needed and MUST be freed
  1160. }
  1161. return GlobalResult;
  1162. }
  1163. public int Write()
  1164. {
  1165. int FunctionResult;
  1166. int GlobalResult = (int)S7Consts.errCliFunctionRefused;
  1167. try
  1168. {
  1169. if (Count > 0)
  1170. {
  1171. FunctionResult = FClient.WriteMultiVars(Items, Count);
  1172. if (FunctionResult == 0)
  1173. for (int c = 0; c < S7Client.MaxVars; c++)
  1174. Results[c] = Items[c].Result;
  1175. GlobalResult = FunctionResult;
  1176. }
  1177. else
  1178. GlobalResult = (int)S7Consts.errCliFunctionRefused;
  1179. }
  1180. finally
  1181. {
  1182. Clear(); // handles are no more needed and MUST be freed
  1183. }
  1184. return GlobalResult;
  1185. }
  1186. public void Clear()
  1187. {
  1188. for (int c = 0; c < Count; c++)
  1189. {
  1190. if (Handles[c] != null)
  1191. Handles[c].Free();
  1192. }
  1193. Count = 0;
  1194. }
  1195. #endregion
  1196. }
  1197. public class S7Client
  1198. {
  1199. #region [Constants and TypeDefs]
  1200. // Block type
  1201. public const int Block_OB = 0x38;
  1202. public const int Block_DB = 0x41;
  1203. public const int Block_SDB = 0x42;
  1204. public const int Block_FC = 0x43;
  1205. public const int Block_SFC = 0x44;
  1206. public const int Block_FB = 0x45;
  1207. public const int Block_SFB = 0x46;
  1208. // Sub Block Type
  1209. public const byte SubBlk_OB = 0x08;
  1210. public const byte SubBlk_DB = 0x0A;
  1211. public const byte SubBlk_SDB = 0x0B;
  1212. public const byte SubBlk_FC = 0x0C;
  1213. public const byte SubBlk_SFC = 0x0D;
  1214. public const byte SubBlk_FB = 0x0E;
  1215. public const byte SubBlk_SFB = 0x0F;
  1216. // Block languages
  1217. public const byte BlockLangAWL = 0x01;
  1218. public const byte BlockLangKOP = 0x02;
  1219. public const byte BlockLangFUP = 0x03;
  1220. public const byte BlockLangSCL = 0x04;
  1221. public const byte BlockLangDB = 0x05;
  1222. public const byte BlockLangGRAPH = 0x06;
  1223. // Max number of vars (multiread/write)
  1224. public static readonly int MaxVars = 20;
  1225. // Result transport size
  1226. const byte TS_ResBit = 0x03;
  1227. const byte TS_ResByte = 0x04;
  1228. const byte TS_ResInt = 0x05;
  1229. const byte TS_ResReal = 0x07;
  1230. const byte TS_ResOctet = 0x09;
  1231. const ushort Code7Ok = 0x0000;
  1232. const ushort Code7AddressOutOfRange = 0x0005;
  1233. const ushort Code7InvalidTransportSize = 0x0006;
  1234. const ushort Code7WriteDataSizeMismatch = 0x0007;
  1235. const ushort Code7ResItemNotAvailable = 0x000A;
  1236. const ushort Code7ResItemNotAvailable1 = 0xD209;
  1237. const ushort Code7InvalidValue = 0xDC01;
  1238. const ushort Code7NeedPassword = 0xD241;
  1239. const ushort Code7InvalidPassword = 0xD602;
  1240. const ushort Code7NoPasswordToClear = 0xD604;
  1241. const ushort Code7NoPasswordToSet = 0xD605;
  1242. const ushort Code7FunNotAvailable = 0x8104;
  1243. const ushort Code7DataOverPDU = 0x8500;
  1244. // Client Connection Type
  1245. public static readonly UInt16 CONNTYPE_PG = 0x01; // Connect to the PLC as a PG
  1246. public static readonly UInt16 CONNTYPE_OP = 0x02; // Connect to the PLC as an OP
  1247. public static readonly UInt16 CONNTYPE_BASIC = 0x03; // Basic connection
  1248. public int _LastError = 0;
  1249. public struct S7DataItem
  1250. {
  1251. public int Area;
  1252. public int WordLen;
  1253. public int Result;
  1254. public int DBNumber;
  1255. public int Start;
  1256. public int Amount;
  1257. public IntPtr pData;
  1258. }
  1259. // Order Code + Version
  1260. public struct S7OrderCode
  1261. {
  1262. public string Code; // such as "6ES7 151-8AB01-0AB0"
  1263. public byte V1; // Version 1st digit
  1264. public byte V2; // Version 2nd digit
  1265. public byte V3; // Version 3th digit
  1266. };
  1267. // CPU Info
  1268. public struct S7CpuInfo
  1269. {
  1270. public string ModuleTypeName;
  1271. public string SerialNumber;
  1272. public string ASName;
  1273. public string Copyright;
  1274. public string ModuleName;
  1275. }
  1276. public struct S7CpInfo
  1277. {
  1278. public int MaxPduLength;
  1279. public int MaxConnections;
  1280. public int MaxMpiRate;
  1281. public int MaxBusRate;
  1282. };
  1283. // Block List
  1284. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  1285. public struct S7BlocksList
  1286. {
  1287. public Int32 OBCount;
  1288. public Int32 FBCount;
  1289. public Int32 FCCount;
  1290. public Int32 SFBCount;
  1291. public Int32 SFCCount;
  1292. public Int32 DBCount;
  1293. public Int32 SDBCount;
  1294. };
  1295. // Managed Block Info
  1296. public struct S7BlockInfo
  1297. {
  1298. public int BlkType;
  1299. public int BlkNumber;
  1300. public int BlkLang;
  1301. public int BlkFlags;
  1302. public int MC7Size; // The real size in bytes
  1303. public int LoadSize;
  1304. public int LocalData;
  1305. public int SBBLength;
  1306. public int CheckSum;
  1307. public int Version;
  1308. // Chars info
  1309. public string CodeDate;
  1310. public string IntfDate;
  1311. public string Author;
  1312. public string Family;
  1313. public string Header;
  1314. };
  1315. // See §33.1 of "System Software for S7-300/400 System and Standard Functions"
  1316. // and see SFC51 description too
  1317. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  1318. public struct SZL_HEADER
  1319. {
  1320. public UInt16 LENTHDR;
  1321. public UInt16 N_DR;
  1322. };
  1323. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  1324. public struct S7SZL
  1325. {
  1326. public SZL_HEADER Header;
  1327. [MarshalAs(UnmanagedType.ByValArray)]
  1328. public byte[] Data;
  1329. };
  1330. // SZL List of available SZL IDs : same as SZL but List items are big-endian adjusted
  1331. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  1332. public struct S7SZLList
  1333. {
  1334. public SZL_HEADER Header;
  1335. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x2000 - 2)]
  1336. public UInt16[] Data;
  1337. };
  1338. // S7 Protection
  1339. // See §33.19 of "System Software for S7-300/400 System and Standard Functions"
  1340. public struct S7Protection
  1341. {
  1342. public ushort sch_schal;
  1343. public ushort sch_par;
  1344. public ushort sch_rel;
  1345. public ushort bart_sch;
  1346. public ushort anl_sch;
  1347. };
  1348. #endregion
  1349. #region [S7 Telegrams]
  1350. // ISO Connection Request telegram (contains also ISO Header and COTP Header)
  1351. byte[] ISO_CR = {
  1352. // TPKT (RFC1006 Header)
  1353. 0x03, // RFC 1006 ID (3)
  1354. 0x00, // Reserved, always 0
  1355. 0x00, // High part of packet lenght (entire frame, payload and TPDU included)
  1356. 0x16, // Low part of packet lenght (entire frame, payload and TPDU included)
  1357. // COTP (ISO 8073 Header)
  1358. 0x11, // PDU Size Length
  1359. 0xE0, // CR - Connection Request ID
  1360. 0x00, // Dst Reference HI
  1361. 0x00, // Dst Reference LO
  1362. 0x00, // Src Reference HI
  1363. 0x01, // Src Reference LO
  1364. 0x00, // Class + Options Flags
  1365. 0xC0, // PDU Max Length ID
  1366. 0x01, // PDU Max Length HI
  1367. 0x0A, // PDU Max Length LO
  1368. 0xC1, // Src TSAP Identifier
  1369. 0x02, // Src TSAP Length (2 bytes)
  1370. 0x01, // Src TSAP HI (will be overwritten)
  1371. 0x00, // Src TSAP LO (will be overwritten)
  1372. 0xC2, // Dst TSAP Identifier
  1373. 0x02, // Dst TSAP Length (2 bytes)
  1374. 0x01, // Dst TSAP HI (will be overwritten)
  1375. 0x02 // Dst TSAP LO (will be overwritten)
  1376. };
  1377. // TPKT + ISO COTP Header (Connection Oriented Transport Protocol)
  1378. byte[] TPKT_ISO = { // 7 bytes
  1379. 0x03,0x00,
  1380. 0x00,0x1f, // Telegram Length (Data Size + 31 or 35)
  1381. 0x02,0xf0,0x80 // COTP (see above for info)
  1382. };
  1383. // S7 PDU Negotiation Telegram (contains also ISO Header and COTP Header)
  1384. byte[] S7_PN = {
  1385. 0x03, 0x00, 0x00, 0x19,
  1386. 0x02, 0xf0, 0x80, // TPKT + COTP (see above for info)
  1387. 0x32, 0x01, 0x00, 0x00,
  1388. 0x04, 0x00, 0x00, 0x08,
  1389. 0x00, 0x00, 0xf0, 0x00,
  1390. 0x00, 0x01, 0x00, 0x01,
  1391. 0x00, 0x1e // PDU Length Requested = HI-LO Here Default 480 bytes
  1392. };
  1393. // S7 Read/Write Request Header (contains also ISO Header and COTP Header)
  1394. byte[] S7_RW = { // 31-35 bytes
  1395. 0x03,0x00,
  1396. 0x00,0x1f, // Telegram Length (Data Size + 31 or 35)
  1397. 0x02,0xf0, 0x80, // COTP (see above for info)
  1398. 0x32, // S7 Protocol ID
  1399. 0x01, // Job Type
  1400. 0x00,0x00, // Redundancy identification
  1401. 0x05,0x00, // PDU Reference
  1402. 0x00,0x0e, // Parameters Length
  1403. 0x00,0x00, // Data Length = Size(bytes) + 4
  1404. 0x04, // Function 4 Read Var, 5 Write Var
  1405. 0x01, // Items count
  1406. 0x12, // Var spec.
  1407. 0x0a, // Length of remaining bytes
  1408. 0x10, // Syntax ID
  1409. (byte)S7Consts.S7WLByte, // Transport Size idx=22
  1410. 0x00,0x00, // Num Elements
  1411. 0x00,0x00, // DB Number (if any, else 0)
  1412. 0x84, // Area Type
  1413. 0x00,0x00,0x00, // Area Offset
  1414. // WR area
  1415. 0x00, // Reserved
  1416. 0x04, // Transport size
  1417. 0x00,0x00, // Data Length * 8 (if not bit or timer or counter)
  1418. };
  1419. private static int Size_RD = 31; // Header Size when Reading
  1420. private static int Size_WR = 35; // Header Size when Writing
  1421. // S7 Variable MultiRead Header
  1422. byte[] S7_MRD_HEADER = {
  1423. 0x03,0x00,
  1424. 0x00,0x1f, // Telegram Length
  1425. 0x02,0xf0, 0x80, // COTP (see above for info)
  1426. 0x32, // S7 Protocol ID
  1427. 0x01, // Job Type
  1428. 0x00,0x00, // Redundancy identification
  1429. 0x05,0x00, // PDU Reference
  1430. 0x00,0x0e, // Parameters Length
  1431. 0x00,0x00, // Data Length = Size(bytes) + 4
  1432. 0x04, // Function 4 Read Var, 5 Write Var
  1433. 0x01 // Items count (idx 18)
  1434. };
  1435. // S7 Variable MultiRead Item
  1436. byte[] S7_MRD_ITEM = {
  1437. 0x12, // Var spec.
  1438. 0x0a, // Length of remaining bytes
  1439. 0x10, // Syntax ID
  1440. (byte)S7Consts.S7WLByte, // Transport Size idx=3
  1441. 0x00,0x00, // Num Elements
  1442. 0x00,0x00, // DB Number (if any, else 0)
  1443. 0x84, // Area Type
  1444. 0x00,0x00,0x00 // Area Offset
  1445. };
  1446. // S7 Variable MultiWrite Header
  1447. byte[] S7_MWR_HEADER = {
  1448. 0x03,0x00,
  1449. 0x00,0x1f, // Telegram Length
  1450. 0x02,0xf0, 0x80, // COTP (see above for info)
  1451. 0x32, // S7 Protocol ID
  1452. 0x01, // Job Type
  1453. 0x00,0x00, // Redundancy identification
  1454. 0x05,0x00, // PDU Reference
  1455. 0x00,0x0e, // Parameters Length (idx 13)
  1456. 0x00,0x00, // Data Length = Size(bytes) + 4 (idx 15)
  1457. 0x05, // Function 5 Write Var
  1458. 0x01 // Items count (idx 18)
  1459. };
  1460. // S7 Variable MultiWrite Item (Param)
  1461. byte[] S7_MWR_PARAM = {
  1462. 0x12, // Var spec.
  1463. 0x0a, // Length of remaining bytes
  1464. 0x10, // Syntax ID
  1465. (byte)S7Consts.S7WLByte, // Transport Size idx=3
  1466. 0x00,0x00, // Num Elements
  1467. 0x00,0x00, // DB Number (if any, else 0)
  1468. 0x84, // Area Type
  1469. 0x00,0x00,0x00, // Area Offset
  1470. };
  1471. // SZL First telegram request
  1472. byte[] S7_SZL_FIRST = {
  1473. 0x03, 0x00, 0x00, 0x21,
  1474. 0x02, 0xf0, 0x80, 0x32,
  1475. 0x07, 0x00, 0x00,
  1476. 0x05, 0x00, // Sequence out
  1477. 0x00, 0x08, 0x00,
  1478. 0x08, 0x00, 0x01, 0x12,
  1479. 0x04, 0x11, 0x44, 0x01,
  1480. 0x00, 0xff, 0x09, 0x00,
  1481. 0x04,
  1482. 0x00, 0x00, // ID (29)
  1483. 0x00, 0x00 // Index (31)
  1484. };
  1485. // SZL Next telegram request
  1486. byte[] S7_SZL_NEXT = {
  1487. 0x03, 0x00, 0x00, 0x21,
  1488. 0x02, 0xf0, 0x80, 0x32,
  1489. 0x07, 0x00, 0x00, 0x06,
  1490. 0x00, 0x00, 0x0c, 0x00,
  1491. 0x04, 0x00, 0x01, 0x12,
  1492. 0x08, 0x12, 0x44, 0x01,
  1493. 0x01, // Sequence
  1494. 0x00, 0x00, 0x00, 0x00,
  1495. 0x0a, 0x00, 0x00, 0x00
  1496. };
  1497. // Get Date/Time request
  1498. byte[] S7_GET_DT = {
  1499. 0x03, 0x00, 0x00, 0x1d,
  1500. 0x02, 0xf0, 0x80, 0x32,
  1501. 0x07, 0x00, 0x00, 0x38,
  1502. 0x00, 0x00, 0x08, 0x00,
  1503. 0x04, 0x00, 0x01, 0x12,
  1504. 0x04, 0x11, 0x47, 0x01,
  1505. 0x00, 0x0a, 0x00, 0x00,
  1506. 0x00
  1507. };
  1508. // Set Date/Time command
  1509. byte[] S7_SET_DT = {
  1510. 0x03, 0x00, 0x00, 0x27,
  1511. 0x02, 0xf0, 0x80, 0x32,
  1512. 0x07, 0x00, 0x00, 0x89,
  1513. 0x03, 0x00, 0x08, 0x00,
  1514. 0x0e, 0x00, 0x01, 0x12,
  1515. 0x04, 0x11, 0x47, 0x02,
  1516. 0x00, 0xff, 0x09, 0x00,
  1517. 0x0a, 0x00,
  1518. 0x19, // Hi part of Year (idx=30)
  1519. 0x13, // Lo part of Year
  1520. 0x12, // Month
  1521. 0x06, // Day
  1522. 0x17, // Hour
  1523. 0x37, // Min
  1524. 0x13, // Sec
  1525. 0x00, 0x01 // ms + Day of week
  1526. };
  1527. // S7 Set Session Password
  1528. byte[] S7_SET_PWD = {
  1529. 0x03, 0x00, 0x00, 0x25,
  1530. 0x02, 0xf0, 0x80, 0x32,
  1531. 0x07, 0x00, 0x00, 0x27,
  1532. 0x00, 0x00, 0x08, 0x00,
  1533. 0x0c, 0x00, 0x01, 0x12,
  1534. 0x04, 0x11, 0x45, 0x01,
  1535. 0x00, 0xff, 0x09, 0x00,
  1536. 0x08,
  1537. // 8 Char Encoded Password
  1538. 0x00, 0x00, 0x00, 0x00,
  1539. 0x00, 0x00, 0x00, 0x00
  1540. };
  1541. // S7 Clear Session Password
  1542. byte[] S7_CLR_PWD = {
  1543. 0x03, 0x00, 0x00, 0x1d,
  1544. 0x02, 0xf0, 0x80, 0x32,
  1545. 0x07, 0x00, 0x00, 0x29,
  1546. 0x00, 0x00, 0x08, 0x00,
  1547. 0x04, 0x00, 0x01, 0x12,
  1548. 0x04, 0x11, 0x45, 0x02,
  1549. 0x00, 0x0a, 0x00, 0x00,
  1550. 0x00
  1551. };
  1552. // S7 STOP request
  1553. byte[] S7_STOP = {
  1554. 0x03, 0x00, 0x00, 0x21,
  1555. 0x02, 0xf0, 0x80, 0x32,
  1556. 0x01, 0x00, 0x00, 0x0e,
  1557. 0x00, 0x00, 0x10, 0x00,
  1558. 0x00, 0x29, 0x00, 0x00,
  1559. 0x00, 0x00, 0x00, 0x09,
  1560. 0x50, 0x5f, 0x50, 0x52,
  1561. 0x4f, 0x47, 0x52, 0x41,
  1562. 0x4d
  1563. };
  1564. // S7 HOT Start request
  1565. byte[] S7_HOT_START = {
  1566. 0x03, 0x00, 0x00, 0x25,
  1567. 0x02, 0xf0, 0x80, 0x32,
  1568. 0x01, 0x00, 0x00, 0x0c,
  1569. 0x00, 0x00, 0x14, 0x00,
  1570. 0x00, 0x28, 0x00, 0x00,
  1571. 0x00, 0x00, 0x00, 0x00,
  1572. 0xfd, 0x00, 0x00, 0x09,
  1573. 0x50, 0x5f, 0x50, 0x52,
  1574. 0x4f, 0x47, 0x52, 0x41,
  1575. 0x4d
  1576. };
  1577. // S7 COLD Start request
  1578. byte[] S7_COLD_START = {
  1579. 0x03, 0x00, 0x00, 0x27,
  1580. 0x02, 0xf0, 0x80, 0x32,
  1581. 0x01, 0x00, 0x00, 0x0f,
  1582. 0x00, 0x00, 0x16, 0x00,
  1583. 0x00, 0x28, 0x00, 0x00,
  1584. 0x00, 0x00, 0x00, 0x00,
  1585. 0xfd, 0x00, 0x02, 0x43,
  1586. 0x20, 0x09, 0x50, 0x5f,
  1587. 0x50, 0x52, 0x4f, 0x47,
  1588. 0x52, 0x41, 0x4d
  1589. };
  1590. const byte pduStart = 0x28; // CPU start
  1591. const byte pduStop = 0x29; // CPU stop
  1592. const byte pduAlreadyStarted = 0x02; // CPU already in run mode
  1593. const byte pduAlreadyStopped = 0x07; // CPU already in stop mode
  1594. // S7 Get PLC Status
  1595. byte[] S7_GET_STAT = {
  1596. 0x03, 0x00, 0x00, 0x21,
  1597. 0x02, 0xf0, 0x80, 0x32,
  1598. 0x07, 0x00, 0x00, 0x2c,
  1599. 0x00, 0x00, 0x08, 0x00,
  1600. 0x08, 0x00, 0x01, 0x12,
  1601. 0x04, 0x11, 0x44, 0x01,
  1602. 0x00, 0xff, 0x09, 0x00,
  1603. 0x04, 0x04, 0x24, 0x00,
  1604. 0x00
  1605. };
  1606. // S7 Get Block Info Request Header (contains also ISO Header and COTP Header)
  1607. byte[] S7_BI = {
  1608. 0x03, 0x00, 0x00, 0x25,
  1609. 0x02, 0xf0, 0x80, 0x32,
  1610. 0x07, 0x00, 0x00, 0x05,
  1611. 0x00, 0x00, 0x08, 0x00,
  1612. 0x0c, 0x00, 0x01, 0x12,
  1613. 0x04, 0x11, 0x43, 0x03,
  1614. 0x00, 0xff, 0x09, 0x00,
  1615. 0x08, 0x30,
  1616. 0x41, // Block Type
  1617. 0x30, 0x30, 0x30, 0x30, 0x30, // ASCII Block Number
  1618. 0x41
  1619. };
  1620. #endregion
  1621. #region [Internals]
  1622. // Defaults
  1623. private static int ISOTCP = 102; // ISOTCP Port
  1624. private static int MinPduSize = 16;
  1625. private static int MinPduSizeToRequest = 240;
  1626. private static int MaxPduSizeToRequest = 960;
  1627. private static int DefaultTimeout = 2000;
  1628. private static int IsoHSize = 7; // TPKT+COTP Header Size
  1629. // Properties
  1630. private int _PDULength = 0;
  1631. private int _PduSizeRequested = 480;
  1632. private int _PLCPort = ISOTCP;
  1633. private int _RecvTimeout = DefaultTimeout;
  1634. private int _SendTimeout = DefaultTimeout;
  1635. private int _ConnTimeout = DefaultTimeout;
  1636. // Privates
  1637. private string IPAddress;
  1638. private byte LocalTSAP_HI;
  1639. private byte LocalTSAP_LO;
  1640. private byte RemoteTSAP_HI;
  1641. private byte RemoteTSAP_LO;
  1642. private byte LastPDUType;
  1643. private ushort ConnType = CONNTYPE_PG;
  1644. private byte[] PDU = new byte[2048];
  1645. private MsgSocket Socket = null;
  1646. private int Time_ms = 0;
  1647. private void CreateSocket()
  1648. {
  1649. try
  1650. {
  1651. Socket = new MsgSocket();
  1652. Socket.ConnectTimeout = _ConnTimeout;
  1653. Socket.ReadTimeout = _RecvTimeout;
  1654. Socket.WriteTimeout = _SendTimeout;
  1655. }
  1656. catch
  1657. {
  1658. }
  1659. }
  1660. private int TCPConnect()
  1661. {
  1662. if (_LastError==0)
  1663. try
  1664. {
  1665. _LastError=Socket.Connect(IPAddress, _PLCPort);
  1666. }
  1667. catch
  1668. {
  1669. _LastError = S7Consts.errTCPConnectionFailed;
  1670. }
  1671. return _LastError;
  1672. }
  1673. private void RecvPacket(byte[] Buffer, int Start, int Size)
  1674. {
  1675. if (Connected)
  1676. _LastError = Socket.Receive(Buffer, Start, Size);
  1677. else
  1678. _LastError = S7Consts.errTCPNotConnected;
  1679. }
  1680. private void SendPacket(byte[] Buffer, int Len)
  1681. {
  1682. _LastError = Socket.Send(Buffer, Len);
  1683. }
  1684. private void SendPacket(byte[] Buffer)
  1685. {
  1686. if (Connected)
  1687. SendPacket(Buffer, Buffer.Length);
  1688. else
  1689. _LastError = S7Consts.errTCPNotConnected;
  1690. }
  1691. private int RecvIsoPacket()
  1692. {
  1693. Boolean Done = false;
  1694. int Size = 0;
  1695. while ((_LastError == 0) && !Done)
  1696. {
  1697. // Get TPKT (4 bytes)
  1698. RecvPacket(PDU, 0, 4);
  1699. if (_LastError == 0)
  1700. {
  1701. Size = S7.GetWordAt(PDU, 2);
  1702. // Check 0 bytes Data Packet (only TPKT+COTP = 7 bytes)
  1703. if (Size == IsoHSize)
  1704. RecvPacket(PDU, 4, 3); // Skip remaining 3 bytes and Done is still false
  1705. else
  1706. {
  1707. if ((Size > _PduSizeRequested + IsoHSize) || (Size < MinPduSize))
  1708. _LastError = S7Consts.errIsoInvalidPDU;
  1709. else
  1710. Done = true; // a valid Length !=7 && >16 && <247
  1711. }
  1712. }
  1713. }
  1714. if (_LastError == 0)
  1715. {
  1716. RecvPacket(PDU, 4, 3); // Skip remaining 3 COTP bytes
  1717. LastPDUType = PDU[5]; // Stores PDU Type, we need it
  1718. // Receives the S7 Payload
  1719. RecvPacket(PDU, 7, Size - IsoHSize);
  1720. }
  1721. if (_LastError == 0)
  1722. return Size;
  1723. else
  1724. return 0;
  1725. }
  1726. private int ISOConnect()
  1727. {
  1728. int Size;
  1729. ISO_CR[16] = LocalTSAP_HI;
  1730. ISO_CR[17] = LocalTSAP_LO;
  1731. ISO_CR[20] = RemoteTSAP_HI;
  1732. ISO_CR[21] = RemoteTSAP_LO;
  1733. // Sends the connection request telegram
  1734. SendPacket(ISO_CR);
  1735. if (_LastError == 0)
  1736. {
  1737. // Gets the reply (if any)
  1738. Size = RecvIsoPacket();
  1739. if (_LastError == 0)
  1740. {
  1741. if (Size == 22)
  1742. {
  1743. if (LastPDUType != (byte)0xD0) // 0xD0 = CC Connection confirm
  1744. _LastError = S7Consts.errIsoConnect;
  1745. }
  1746. else
  1747. _LastError = S7Consts.errIsoInvalidPDU;
  1748. }
  1749. }
  1750. return _LastError;
  1751. }
  1752. private int NegotiatePduLength()
  1753. {
  1754. int Length;
  1755. // Set PDU Size Requested
  1756. S7.SetWordAt(S7_PN, 23, (ushort)_PduSizeRequested);
  1757. // Sends the connection request telegram
  1758. SendPacket(S7_PN);
  1759. if (_LastError == 0)
  1760. {
  1761. Length = RecvIsoPacket();
  1762. if (_LastError == 0)
  1763. {
  1764. // check S7 Error
  1765. if ((Length == 27) && (PDU[17] == 0) && (PDU[18] == 0)) // 20 = size of Negotiate Answer
  1766. {
  1767. // Get PDU Size Negotiated
  1768. _PDULength = S7.GetWordAt(PDU, 25);
  1769. if (_PDULength <= 0)
  1770. _LastError = S7Consts.errCliNegotiatingPDU;
  1771. }
  1772. else
  1773. _LastError = S7Consts.errCliNegotiatingPDU;
  1774. }
  1775. }
  1776. return _LastError;
  1777. }
  1778. private int CpuError(ushort Error)
  1779. {
  1780. switch(Error)
  1781. {
  1782. case 0 : return 0;
  1783. case Code7AddressOutOfRange : return S7Consts.errCliAddressOutOfRange;
  1784. case Code7InvalidTransportSize : return S7Consts.errCliInvalidTransportSize;
  1785. case Code7WriteDataSizeMismatch : return S7Consts.errCliWriteDataSizeMismatch;
  1786. case Code7ResItemNotAvailable :
  1787. case Code7ResItemNotAvailable1 : return S7Consts.errCliItemNotAvailable;
  1788. case Code7DataOverPDU : return S7Consts.errCliSizeOverPDU;
  1789. case Code7InvalidValue : return S7Consts.errCliInvalidValue;
  1790. case Code7FunNotAvailable : return S7Consts.errCliFunNotAvailable;
  1791. case Code7NeedPassword : return S7Consts.errCliNeedPassword;
  1792. case Code7InvalidPassword : return S7Consts.errCliInvalidPassword;
  1793. case Code7NoPasswordToSet :
  1794. case Code7NoPasswordToClear : return S7Consts.errCliNoPasswordToSetOrClear;
  1795. default:
  1796. return S7Consts.errCliFunctionRefused;
  1797. };
  1798. }
  1799. #endregion
  1800. #region [Class Control]
  1801. public S7Client()
  1802. {
  1803. CreateSocket();
  1804. }
  1805. ~S7Client()
  1806. {
  1807. Disconnect();
  1808. }
  1809. public int Connect()
  1810. {
  1811. _LastError = 0;
  1812. Time_ms = 0;
  1813. int Elapsed = Environment.TickCount;
  1814. if (!Connected)
  1815. {
  1816. TCPConnect(); // First stage : TCP Connection
  1817. if (_LastError == 0)
  1818. {
  1819. ISOConnect(); // Second stage : ISOTCP (ISO 8073) Connection
  1820. if (_LastError == 0)
  1821. {
  1822. _LastError = NegotiatePduLength(); // Third stage : S7 PDU negotiation
  1823. }
  1824. }
  1825. }
  1826. if (_LastError != 0)
  1827. Disconnect();
  1828. else
  1829. Time_ms = Environment.TickCount - Elapsed;
  1830. return _LastError;
  1831. }
  1832. public int ConnectTo(string Address, int Rack, int Slot)
  1833. {
  1834. UInt16 RemoteTSAP = (UInt16)((ConnType << 8) + (Rack * 0x20) + Slot);
  1835. SetConnectionParams(Address, 0x0100, RemoteTSAP);
  1836. return Connect();
  1837. }
  1838. public int SetConnectionParams(string Address, ushort LocalTSAP, ushort RemoteTSAP)
  1839. {
  1840. int LocTSAP = LocalTSAP & 0x0000FFFF;
  1841. int RemTSAP = RemoteTSAP & 0x0000FFFF;
  1842. IPAddress = Address;
  1843. LocalTSAP_HI = (byte)(LocTSAP >> 8);
  1844. LocalTSAP_LO = (byte)(LocTSAP & 0x00FF);
  1845. RemoteTSAP_HI = (byte)(RemTSAP >> 8);
  1846. RemoteTSAP_LO = (byte)(RemTSAP & 0x00FF);
  1847. return 0;
  1848. }
  1849. public int SetConnectionType(ushort ConnectionType)
  1850. {
  1851. ConnType = ConnectionType;
  1852. return 0;
  1853. }
  1854. public int Disconnect()
  1855. {
  1856. Socket.Close();
  1857. return 0;
  1858. }
  1859. public int GetParam(Int32 ParamNumber, ref int Value)
  1860. {
  1861. int Result = 0;
  1862. switch (ParamNumber)
  1863. {
  1864. case S7Consts.p_u16_RemotePort:
  1865. {
  1866. Value = PLCPort;
  1867. break;
  1868. }
  1869. case S7Consts.p_i32_PingTimeout:
  1870. {
  1871. Value = ConnTimeout;
  1872. break;
  1873. }
  1874. case S7Consts.p_i32_SendTimeout:
  1875. {
  1876. Value = SendTimeout;
  1877. break;
  1878. }
  1879. case S7Consts.p_i32_RecvTimeout:
  1880. {
  1881. Value = RecvTimeout;
  1882. break;
  1883. }
  1884. case S7Consts.p_i32_PDURequest:
  1885. {
  1886. Value = PduSizeRequested;
  1887. break;
  1888. }
  1889. default:
  1890. {
  1891. Result = S7Consts.errCliInvalidParamNumber;
  1892. break;
  1893. }
  1894. }
  1895. return Result;
  1896. }
  1897. // Set Properties for compatibility with Snap7.net.cs
  1898. public int SetParam(Int32 ParamNumber, ref int Value)
  1899. {
  1900. int Result = 0;
  1901. switch(ParamNumber)
  1902. {
  1903. case S7Consts.p_u16_RemotePort:
  1904. {
  1905. PLCPort = Value;
  1906. break;
  1907. }
  1908. case S7Consts.p_i32_PingTimeout:
  1909. {
  1910. ConnTimeout = Value;
  1911. break;
  1912. }
  1913. case S7Consts.p_i32_SendTimeout:
  1914. {
  1915. SendTimeout = Value;
  1916. break;
  1917. }
  1918. case S7Consts.p_i32_RecvTimeout:
  1919. {
  1920. RecvTimeout = Value;
  1921. break;
  1922. }
  1923. case S7Consts.p_i32_PDURequest:
  1924. {
  1925. PduSizeRequested = Value;
  1926. break;
  1927. }
  1928. default:
  1929. {
  1930. Result = S7Consts.errCliInvalidParamNumber;
  1931. break;
  1932. }
  1933. }
  1934. return Result;
  1935. }
  1936. public delegate void S7CliCompletion(IntPtr usrPtr, int opCode, int opResult);
  1937. public int SetAsCallBack(S7CliCompletion Completion, IntPtr usrPtr)
  1938. {
  1939. return S7Consts.errCliFunctionNotImplemented;
  1940. }
  1941. #endregion
  1942. #region [Data I/O main functions]
  1943. public int ReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, byte[] Buffer)
  1944. {
  1945. int BytesRead = 0;
  1946. return ReadArea(Area, DBNumber, Start, Amount, WordLen, Buffer, ref BytesRead);
  1947. }
  1948. public int ReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, byte[] Buffer, ref int BytesRead)
  1949. {
  1950. int Address;
  1951. int NumElements;
  1952. int MaxElements;
  1953. int TotElements;
  1954. int SizeRequested;
  1955. int Length;
  1956. int Offset = 0;
  1957. int WordSize = 1;
  1958. _LastError = 0;
  1959. Time_ms = 0;
  1960. int Elapsed = Environment.TickCount;
  1961. // Some adjustment
  1962. if (Area == S7Consts.S7AreaCT)
  1963. WordLen = S7Consts.S7WLCounter;
  1964. if (Area == S7Consts.S7AreaTM)
  1965. WordLen = S7Consts.S7WLTimer;
  1966. // Calc Word size
  1967. WordSize = S7.DataSizeByte(WordLen);
  1968. if (WordSize == 0)
  1969. return S7Consts.errCliInvalidWordLen;
  1970. if (WordLen == S7Consts.S7WLBit)
  1971. Amount = 1; // Only 1 bit can be transferred at time
  1972. else
  1973. {
  1974. if ((WordLen != S7Consts.S7WLCounter) && (WordLen != S7Consts.S7WLTimer))
  1975. {
  1976. Amount = Amount * WordSize;
  1977. WordSize = 1;
  1978. WordLen = S7Consts.S7WLByte;
  1979. }
  1980. }
  1981. MaxElements = (_PDULength - 18) / WordSize; // 18 = Reply telegram header
  1982. TotElements = Amount;
  1983. while ((TotElements > 0) && (_LastError == 0))
  1984. {
  1985. NumElements = TotElements;
  1986. if (NumElements > MaxElements)
  1987. NumElements = MaxElements;
  1988. SizeRequested = NumElements * WordSize;
  1989. // Setup the telegram
  1990. Array.Copy(S7_RW, 0, PDU, 0, Size_RD);
  1991. // Set DB Number
  1992. PDU[27] = (byte)Area;
  1993. // Set Area
  1994. if (Area == S7Consts.S7AreaDB)
  1995. S7.SetWordAt(PDU, 25, (ushort)DBNumber);
  1996. // Adjusts Start and word length
  1997. if ((WordLen == S7Consts.S7WLBit) || (WordLen == S7Consts.S7WLCounter) || (WordLen == S7Consts.S7WLTimer))
  1998. {
  1999. Address = Start;
  2000. PDU[22] = (byte)WordLen;
  2001. }
  2002. else
  2003. Address = Start << 3;
  2004. // Num elements
  2005. S7.SetWordAt(PDU, 23, (ushort)NumElements);
  2006. // Address into the PLC (only 3 bytes)
  2007. PDU[30] = (byte)(Address & 0x0FF);
  2008. Address = Address >> 8;
  2009. PDU[29] = (byte)(Address & 0x0FF);
  2010. Address = Address >> 8;
  2011. PDU[28] = (byte)(Address & 0x0FF);
  2012. SendPacket(PDU, Size_RD);
  2013. if (_LastError == 0)
  2014. {
  2015. Length = RecvIsoPacket();
  2016. if (_LastError == 0)
  2017. {
  2018. if (Length<25)
  2019. _LastError = S7Consts.errIsoInvalidDataSize;
  2020. else
  2021. {
  2022. if (PDU[21] != 0xFF)
  2023. _LastError = CpuError(PDU[21]);
  2024. else
  2025. {
  2026. Array.Copy(PDU, 25, Buffer, Offset, SizeRequested);
  2027. Offset += SizeRequested;
  2028. }
  2029. }
  2030. }
  2031. }
  2032. TotElements -= NumElements;
  2033. Start += NumElements * WordSize;
  2034. }
  2035. if (_LastError == 0)
  2036. {
  2037. BytesRead = Offset;
  2038. Time_ms = Environment.TickCount - Elapsed;
  2039. }
  2040. else
  2041. BytesRead = 0;
  2042. return _LastError;
  2043. }
  2044. public int WriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, byte[] Buffer)
  2045. {
  2046. int BytesWritten = 0;
  2047. return WriteArea(Area, DBNumber, Start, Amount, WordLen, Buffer, ref BytesWritten);
  2048. }
  2049. public int WriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, byte[] Buffer, ref int BytesWritten)
  2050. {
  2051. int Address;
  2052. int NumElements;
  2053. int MaxElements;
  2054. int TotElements;
  2055. int DataSize;
  2056. int IsoSize;
  2057. int Length;
  2058. int Offset = 0;
  2059. int WordSize = 1;
  2060. _LastError = 0;
  2061. Time_ms = 0;
  2062. int Elapsed = Environment.TickCount;
  2063. // Some adjustment
  2064. if (Area == S7Consts.S7AreaCT)
  2065. WordLen = S7Consts.S7WLCounter;
  2066. if (Area == S7Consts.S7AreaTM)
  2067. WordLen = S7Consts.S7WLTimer;
  2068. // Calc Word size
  2069. WordSize = S7.DataSizeByte(WordLen);
  2070. if (WordSize == 0)
  2071. return S7Consts.errCliInvalidWordLen;
  2072. if (WordLen == S7Consts.S7WLBit) // Only 1 bit can be transferred at time
  2073. Amount = 1;
  2074. else
  2075. {
  2076. if ((WordLen != S7Consts.S7WLCounter) && (WordLen != S7Consts.S7WLTimer))
  2077. {
  2078. Amount = Amount * WordSize;
  2079. WordSize = 1;
  2080. WordLen = S7Consts.S7WLByte;
  2081. }
  2082. }
  2083. MaxElements = (_PDULength - 35) / WordSize; // 35 = Reply telegram header
  2084. TotElements = Amount;
  2085. while ((TotElements > 0) && (_LastError == 0))
  2086. {
  2087. NumElements = TotElements;
  2088. if (NumElements > MaxElements)
  2089. NumElements = MaxElements;
  2090. DataSize = NumElements * WordSize;
  2091. IsoSize = Size_WR + DataSize;
  2092. // Setup the telegram
  2093. Array.Copy(S7_RW, 0, PDU, 0, Size_WR);
  2094. // Whole telegram Size
  2095. S7.SetWordAt(PDU, 2, (ushort)IsoSize);
  2096. // Data Length
  2097. Length = DataSize + 4;
  2098. S7.SetWordAt(PDU, 15, (ushort)Length);
  2099. // Function
  2100. PDU[17] = (byte)0x05;
  2101. // Set DB Number
  2102. PDU[27] = (byte)Area;
  2103. if (Area == S7Consts.S7AreaDB)
  2104. S7.SetWordAt(PDU, 25, (ushort)DBNumber);
  2105. // Adjusts Start and word length
  2106. if ((WordLen == S7Consts.S7WLBit) || (WordLen == S7Consts.S7WLCounter) || (WordLen == S7Consts.S7WLTimer))
  2107. {
  2108. Address = Start;
  2109. Length = DataSize;
  2110. PDU[22] = (byte)WordLen;
  2111. }
  2112. else
  2113. {
  2114. Address = Start << 3;
  2115. Length = DataSize << 3;
  2116. }
  2117. // Num elements
  2118. S7.SetWordAt(PDU, 23, (ushort)NumElements);
  2119. // Address into the PLC
  2120. PDU[30] = (byte)(Address & 0x0FF);
  2121. Address = Address >> 8;
  2122. PDU[29] = (byte)(Address & 0x0FF);
  2123. Address = Address >> 8;
  2124. PDU[28] = (byte)(Address & 0x0FF);
  2125. // Transport Size
  2126. switch (WordLen)
  2127. {
  2128. case S7Consts.S7WLBit:
  2129. PDU[32] = TS_ResBit;
  2130. break;
  2131. case S7Consts.S7WLCounter:
  2132. case S7Consts.S7WLTimer:
  2133. PDU[32] = TS_ResOctet;
  2134. break;
  2135. default:
  2136. PDU[32] = TS_ResByte; // byte/word/dword etc.
  2137. break;
  2138. };
  2139. // Length
  2140. S7.SetWordAt(PDU, 33, (ushort)Length);
  2141. // Copies the Data
  2142. Array.Copy(Buffer, Offset, PDU, 35, DataSize);
  2143. SendPacket(PDU, IsoSize);
  2144. if (_LastError == 0)
  2145. {
  2146. Length = RecvIsoPacket();
  2147. if (_LastError == 0)
  2148. {
  2149. if (Length == 22)
  2150. {
  2151. if (PDU[21] != (byte)0xFF)
  2152. _LastError = CpuError(PDU[21]);
  2153. }
  2154. else
  2155. _LastError = S7Consts.errIsoInvalidPDU;
  2156. }
  2157. }
  2158. Offset += DataSize;
  2159. TotElements -= NumElements;
  2160. Start += NumElements * WordSize;
  2161. }
  2162. if (_LastError == 0)
  2163. {
  2164. BytesWritten = Offset;
  2165. Time_ms = Environment.TickCount - Elapsed;
  2166. }
  2167. else
  2168. BytesWritten = 0;
  2169. return _LastError;
  2170. }
  2171. public int ReadMultiVars(S7DataItem[] Items, int ItemsCount)
  2172. {
  2173. int Offset;
  2174. int Length;
  2175. int ItemSize;
  2176. byte[] S7Item = new byte[12];
  2177. byte[] S7ItemRead = new byte[1024];
  2178. _LastError = 0;
  2179. Time_ms = 0;
  2180. int Elapsed = Environment.TickCount;
  2181. // Checks items
  2182. if (ItemsCount > MaxVars)
  2183. return S7Consts.errCliTooManyItems;
  2184. // Fills Header
  2185. Array.Copy(S7_MRD_HEADER, 0, PDU, 0, S7_MRD_HEADER.Length);
  2186. S7.SetWordAt(PDU, 13, (ushort)(ItemsCount * S7Item.Length + 2));
  2187. PDU[18] = (byte)ItemsCount;
  2188. // Fills the Items
  2189. Offset = 19;
  2190. for (int c = 0; c < ItemsCount; c++)
  2191. {
  2192. Array.Copy(S7_MRD_ITEM, S7Item, S7Item.Length);
  2193. S7Item[3] = (byte)Items[c].WordLen;
  2194. S7.SetWordAt(S7Item, 4, (ushort)Items[c].Amount);
  2195. if (Items[c].Area == S7Consts.S7AreaDB)
  2196. S7.SetWordAt(S7Item, 6, (ushort)Items[c].DBNumber);
  2197. S7Item[8] = (byte)Items[c].Area;
  2198. // Address into the PLC
  2199. int Address = Items[c].Start;
  2200. S7Item[11] = (byte)(Address & 0x0FF);
  2201. Address = Address >> 8;
  2202. S7Item[10] = (byte)(Address & 0x0FF);
  2203. Address = Address >> 8;
  2204. S7Item[09] = (byte)(Address & 0x0FF);
  2205. Array.Copy(S7Item, 0, PDU, Offset, S7Item.Length);
  2206. Offset += S7Item.Length;
  2207. }
  2208. if (Offset > _PDULength)
  2209. return S7Consts.errCliSizeOverPDU;
  2210. S7.SetWordAt(PDU, 2, (ushort)Offset); // Whole size
  2211. SendPacket(PDU, Offset);
  2212. if (_LastError != 0)
  2213. return _LastError;
  2214. // Get Answer
  2215. Length = RecvIsoPacket();
  2216. if (_LastError != 0)
  2217. return _LastError;
  2218. // Check ISO Length
  2219. if (Length < 22)
  2220. {
  2221. _LastError = S7Consts.errIsoInvalidPDU; // PDU too Small
  2222. return _LastError;
  2223. }
  2224. // Check Global Operation Result
  2225. _LastError = CpuError(S7.GetWordAt(PDU, 17));
  2226. if (_LastError != 0)
  2227. return _LastError;
  2228. // Get true ItemsCount
  2229. int ItemsRead = S7.GetByteAt(PDU, 20);
  2230. if ((ItemsRead != ItemsCount) || (ItemsRead>MaxVars))
  2231. {
  2232. _LastError = S7Consts.errCliInvalidPlcAnswer;
  2233. return _LastError;
  2234. }
  2235. // Get Data
  2236. Offset = 21;
  2237. for (int c = 0; c < ItemsCount; c++)
  2238. {
  2239. // Get the Item
  2240. Array.Copy(PDU, Offset, S7ItemRead, 0, Length-Offset);
  2241. if (S7ItemRead[0] == 0xff)
  2242. {
  2243. ItemSize = (int)S7.GetWordAt(S7ItemRead, 2);
  2244. if ((S7ItemRead[1] != TS_ResOctet) && (S7ItemRead[1] != TS_ResReal) && (S7ItemRead[1] != TS_ResBit))
  2245. ItemSize = ItemSize >> 3;
  2246. Marshal.Copy(S7ItemRead, 4, Items[c].pData, ItemSize);
  2247. Items[c].Result = 0;
  2248. if (ItemSize % 2 != 0)
  2249. ItemSize++; // Odd size are rounded
  2250. Offset = Offset + 4 + ItemSize;
  2251. }
  2252. else
  2253. {
  2254. Items[c].Result = CpuError(S7ItemRead[0]);
  2255. Offset += 4; // Skip the Item header
  2256. }
  2257. }
  2258. Time_ms = Environment.TickCount - Elapsed;
  2259. return _LastError;
  2260. }
  2261. public int WriteMultiVars(S7DataItem[] Items, int ItemsCount)
  2262. {
  2263. int Offset;
  2264. int ParLength;
  2265. int DataLength;
  2266. int ItemDataSize;
  2267. byte[] S7ParItem = new byte[S7_MWR_PARAM.Length];
  2268. byte[] S7DataItem = new byte[1024];
  2269. _LastError = 0;
  2270. Time_ms = 0;
  2271. int Elapsed = Environment.TickCount;
  2272. // Checks items
  2273. if (ItemsCount > MaxVars)
  2274. return S7Consts.errCliTooManyItems;
  2275. // Fills Header
  2276. Array.Copy(S7_MWR_HEADER, 0, PDU, 0, S7_MWR_HEADER.Length);
  2277. ParLength = ItemsCount * S7_MWR_PARAM.Length + 2;
  2278. S7.SetWordAt(PDU, 13, (ushort)ParLength);
  2279. PDU[18] = (byte)ItemsCount;
  2280. // Fills Params
  2281. Offset = S7_MWR_HEADER.Length;
  2282. for (int c=0; c<ItemsCount; c++)
  2283. {
  2284. Array.Copy(S7_MWR_PARAM, 0, S7ParItem, 0, S7_MWR_PARAM.Length);
  2285. S7ParItem[3] = (byte)Items[c].WordLen;
  2286. S7ParItem[8] = (byte)Items[c].Area;
  2287. S7.SetWordAt(S7ParItem, 4, (ushort)Items[c].Amount);
  2288. S7.SetWordAt(S7ParItem, 6, (ushort)Items[c].DBNumber);
  2289. // Address into the PLC
  2290. int Address = Items[c].Start;
  2291. S7ParItem[11] = (byte)(Address & 0x0FF);
  2292. Address = Address >> 8;
  2293. S7ParItem[10] = (byte)(Address & 0x0FF);
  2294. Address = Address >> 8;
  2295. S7ParItem[09] = (byte)(Address & 0x0FF);
  2296. Array.Copy(S7ParItem, 0, PDU, Offset, S7ParItem.Length);
  2297. Offset += S7_MWR_PARAM.Length;
  2298. }
  2299. // Fills Data
  2300. DataLength = 0;
  2301. for (int c = 0; c < ItemsCount; c++)
  2302. {
  2303. S7DataItem[0] = 0x00;
  2304. switch (Items[c].WordLen)
  2305. {
  2306. case S7Consts.S7WLBit:
  2307. S7DataItem[1] = TS_ResBit;
  2308. break;
  2309. case S7Consts.S7WLCounter:
  2310. case S7Consts.S7WLTimer:
  2311. S7DataItem[1] = TS_ResOctet;
  2312. break;
  2313. default:
  2314. S7DataItem[1] = TS_ResByte; // byte/word/dword etc.
  2315. break;
  2316. };
  2317. if ((Items[c].WordLen==S7Consts.S7WLTimer) || (Items[c].WordLen == S7Consts.S7WLCounter))
  2318. ItemDataSize = Items[c].Amount * 2;
  2319. else
  2320. ItemDataSize = Items[c].Amount;
  2321. if ((S7DataItem[1] != TS_ResOctet) && (S7DataItem[1] != TS_ResBit))
  2322. S7.SetWordAt(S7DataItem, 2, (ushort)(ItemDataSize*8));
  2323. else
  2324. S7.SetWordAt(S7DataItem, 2, (ushort)ItemDataSize);
  2325. Marshal.Copy(Items[c].pData, S7DataItem, 4, ItemDataSize);
  2326. if (ItemDataSize % 2 != 0)
  2327. {
  2328. S7DataItem[ItemDataSize+4] = 0x00;
  2329. ItemDataSize++;
  2330. }
  2331. Array.Copy(S7DataItem, 0, PDU, Offset, ItemDataSize+4);
  2332. Offset = Offset + ItemDataSize + 4;
  2333. DataLength = DataLength + ItemDataSize + 4;
  2334. }
  2335. // Checks the size
  2336. if (Offset > _PDULength)
  2337. return S7Consts.errCliSizeOverPDU;
  2338. S7.SetWordAt(PDU, 2, (ushort)Offset); // Whole size
  2339. S7.SetWordAt(PDU, 15, (ushort)DataLength); // Whole size
  2340. SendPacket(PDU, Offset);
  2341. RecvIsoPacket();
  2342. if (_LastError==0)
  2343. {
  2344. // Check Global Operation Result
  2345. _LastError = CpuError(S7.GetWordAt(PDU, 17));
  2346. if (_LastError != 0)
  2347. return _LastError;
  2348. // Get true ItemsCount
  2349. int ItemsWritten = S7.GetByteAt(PDU, 20);
  2350. if ((ItemsWritten != ItemsCount) || (ItemsWritten > MaxVars))
  2351. {
  2352. _LastError = S7Consts.errCliInvalidPlcAnswer;
  2353. return _LastError;
  2354. }
  2355. for (int c=0; c<ItemsCount; c++)
  2356. {
  2357. if (PDU[c + 21] == 0xFF)
  2358. Items[c].Result = 0;
  2359. else
  2360. Items[c].Result = CpuError((ushort)PDU[c + 21]);
  2361. }
  2362. Time_ms = Environment.TickCount - Elapsed;
  2363. }
  2364. return _LastError;
  2365. }
  2366. #endregion
  2367. #region [Data I/O lean functions]
  2368. public int DBRead(int DBNumber, int Start, int Size, byte[] Buffer)
  2369. {
  2370. return ReadArea(S7Consts.S7AreaDB, DBNumber, Start, Size, S7Consts.S7WLByte, Buffer);
  2371. }
  2372. public int DBWrite(int DBNumber, int Start, int Size, byte[] Buffer)
  2373. {
  2374. return WriteArea(S7Consts.S7AreaDB, DBNumber, Start, Size, S7Consts.S7WLByte, Buffer);
  2375. }
  2376. public int MBRead(int Start, int Size, byte[] Buffer)
  2377. {
  2378. return ReadArea(S7Consts.S7AreaMK, 0, Start, Size, S7Consts.S7WLByte, Buffer);
  2379. }
  2380. public int MBWrite(int Start, int Size, byte[] Buffer)
  2381. {
  2382. return WriteArea(S7Consts.S7AreaMK, 0, Start, Size, S7Consts.S7WLByte, Buffer);
  2383. }
  2384. public int EBRead(int Start, int Size, byte[] Buffer)
  2385. {
  2386. return ReadArea(S7Consts.S7AreaPE, 0, Start, Size, S7Consts.S7WLByte, Buffer);
  2387. }
  2388. public int EBWrite(int Start, int Size, byte[] Buffer)
  2389. {
  2390. return WriteArea(S7Consts.S7AreaPE, 0, Start, Size, S7Consts.S7WLByte, Buffer);
  2391. }
  2392. public int ABRead(int Start, int Size, byte[] Buffer)
  2393. {
  2394. return ReadArea(S7Consts.S7AreaPA, 0, Start, Size, S7Consts.S7WLByte, Buffer);
  2395. }
  2396. public int ABWrite(int Start, int Size, byte[] Buffer)
  2397. {
  2398. return WriteArea(S7Consts.S7AreaPA, 0, Start, Size, S7Consts.S7WLByte, Buffer);
  2399. }
  2400. public int TMRead(int Start, int Amount, ushort[] Buffer)
  2401. {
  2402. byte[] sBuffer = new byte[Amount * 2];
  2403. int Result = ReadArea(S7Consts.S7AreaTM, 0, Start, Amount, S7Consts.S7WLTimer, sBuffer);
  2404. if (Result == 0)
  2405. {
  2406. for (int c = 0; c < Amount; c++)
  2407. {
  2408. Buffer[c] = (ushort)((sBuffer[c * 2 + 1] << 8) + (sBuffer[c * 2]));
  2409. }
  2410. }
  2411. return Result;
  2412. }
  2413. public int TMWrite(int Start, int Amount, ushort[] Buffer)
  2414. {
  2415. byte[] sBuffer = new byte[Amount * 2];
  2416. for (int c = 0; c < Amount; c++)
  2417. {
  2418. sBuffer[c * 2 + 1] = (byte)((Buffer[c] & 0xFF00) >> 8);
  2419. sBuffer[c * 2] = (byte)(Buffer[c] & 0x00FF);
  2420. }
  2421. return WriteArea(S7Consts.S7AreaTM, 0, Start, Amount, S7Consts.S7WLTimer, sBuffer);
  2422. }
  2423. public int CTRead(int Start, int Amount, ushort[] Buffer)
  2424. {
  2425. byte[] sBuffer = new byte[Amount * 2];
  2426. int Result = ReadArea(S7Consts.S7AreaCT, 0, Start, Amount, S7Consts.S7WLCounter, sBuffer);
  2427. if (Result==0)
  2428. {
  2429. for (int c=0; c<Amount; c++)
  2430. {
  2431. Buffer[c] = (ushort)((sBuffer[c * 2 + 1] << 8) + (sBuffer[c * 2]));
  2432. }
  2433. }
  2434. return Result;
  2435. }
  2436. public int CTWrite(int Start, int Amount, ushort[] Buffer)
  2437. {
  2438. byte[] sBuffer = new byte[Amount * 2];
  2439. for (int c = 0; c < Amount; c++)
  2440. {
  2441. sBuffer[c * 2 + 1] = (byte)((Buffer[c] & 0xFF00)>>8);
  2442. sBuffer[c * 2]= (byte)(Buffer[c] & 0x00FF);
  2443. }
  2444. return WriteArea(S7Consts.S7AreaCT, 0, Start, Amount, S7Consts.S7WLCounter, sBuffer);
  2445. }
  2446. #endregion
  2447. #region [Directory functions]
  2448. public int ListBlocks(ref S7BlocksList List)
  2449. {
  2450. return S7Consts.errCliFunctionNotImplemented;
  2451. }
  2452. private string SiemensTimestamp(long EncodedDate)
  2453. {
  2454. DateTime DT = new DateTime(1984, 1, 1).AddSeconds(EncodedDate*86400);
  2455. #if WINDOWS_UWP || NETFX_CORE
  2456. return DT.ToString(System.Globalization.DateTimeFormatInfo.CurrentInfo.ShortDatePattern);
  2457. #else
  2458. return DT.ToShortDateString();
  2459. #endif
  2460. }
  2461. public int GetAgBlockInfo(int BlockType, int BlockNum, ref S7BlockInfo Info)
  2462. {
  2463. _LastError = 0;
  2464. Time_ms = 0;
  2465. int Elapsed = Environment.TickCount;
  2466. S7_BI[30] = (byte)BlockType;
  2467. // Block Number
  2468. S7_BI[31] = (byte)((BlockNum / 10000) + 0x30);
  2469. BlockNum = BlockNum % 10000;
  2470. S7_BI[32] = (byte)((BlockNum / 1000) + 0x30);
  2471. BlockNum = BlockNum % 1000;
  2472. S7_BI[33] = (byte)((BlockNum / 100) + 0x30);
  2473. BlockNum = BlockNum % 100;
  2474. S7_BI[34] = (byte)((BlockNum / 10) + 0x30);
  2475. BlockNum = BlockNum % 10;
  2476. S7_BI[35] = (byte)((BlockNum / 1) + 0x30);
  2477. SendPacket(S7_BI);
  2478. if (_LastError == 0)
  2479. {
  2480. int Length = RecvIsoPacket();
  2481. if (Length > 32) // the minimum expected
  2482. {
  2483. ushort Result = S7.GetWordAt(PDU, 27);
  2484. if (Result == 0)
  2485. {
  2486. Info.BlkFlags= PDU[42];
  2487. Info.BlkLang = PDU[43];
  2488. Info.BlkType = PDU[44];
  2489. Info.BlkNumber = S7.GetWordAt(PDU, 45);
  2490. Info.LoadSize = S7.GetDIntAt(PDU, 47);
  2491. Info.CodeDate = SiemensTimestamp(S7.GetWordAt(PDU, 59));
  2492. Info.IntfDate = SiemensTimestamp(S7.GetWordAt(PDU, 65));
  2493. Info.SBBLength = S7.GetWordAt(PDU, 67);
  2494. Info.LocalData = S7.GetWordAt(PDU, 71);
  2495. Info.MC7Size = S7.GetWordAt(PDU, 73);
  2496. Info.Author = S7.GetCharsAt(PDU, 75, 8).Trim(new char[]{(char)0});
  2497. Info.Family = S7.GetCharsAt(PDU, 83, 8).Trim(new char[]{(char)0});
  2498. Info.Header = S7.GetCharsAt(PDU, 91, 8).Trim(new char[]{(char)0});
  2499. Info.Version = PDU[99];
  2500. Info.CheckSum = S7.GetWordAt(PDU, 101);
  2501. }
  2502. else
  2503. _LastError = CpuError(Result);
  2504. }
  2505. else
  2506. _LastError = S7Consts.errIsoInvalidPDU;
  2507. }
  2508. if (_LastError == 0)
  2509. Time_ms = Environment.TickCount - Elapsed;
  2510. return _LastError;
  2511. }
  2512. public int GetPgBlockInfo(ref S7BlockInfo Info, byte[] Buffer, int Size)
  2513. {
  2514. return S7Consts.errCliFunctionNotImplemented;
  2515. }
  2516. public int ListBlocksOfType(int BlockType, ushort[] List, ref int ItemsCount)
  2517. {
  2518. return S7Consts.errCliFunctionNotImplemented;
  2519. }
  2520. #endregion
  2521. #region [Blocks functions]
  2522. public int Upload(int BlockType, int BlockNum, byte[] UsrData, ref int Size)
  2523. {
  2524. return S7Consts.errCliFunctionNotImplemented;
  2525. }
  2526. public int FullUpload(int BlockType, int BlockNum, byte[] UsrData, ref int Size)
  2527. {
  2528. return S7Consts.errCliFunctionNotImplemented;
  2529. }
  2530. public int Download(int BlockNum, byte[] UsrData, int Size)
  2531. {
  2532. return S7Consts.errCliFunctionNotImplemented;
  2533. }
  2534. public int Delete(int BlockType, int BlockNum)
  2535. {
  2536. return S7Consts.errCliFunctionNotImplemented;
  2537. }
  2538. public int DBGet(int DBNumber, byte[] UsrData, ref int Size)
  2539. {
  2540. S7BlockInfo BI = new S7BlockInfo();
  2541. int Elapsed = Environment.TickCount;
  2542. Time_ms = 0;
  2543. _LastError = GetAgBlockInfo(Block_DB, DBNumber, ref BI);
  2544. if (_LastError==0)
  2545. {
  2546. int DBSize = BI.MC7Size;
  2547. if (DBSize <= UsrData.Length)
  2548. {
  2549. Size = DBSize;
  2550. _LastError = DBRead(DBNumber, 0, DBSize, UsrData);
  2551. if (_LastError == 0)
  2552. Size = DBSize;
  2553. }
  2554. else
  2555. _LastError = S7Consts.errCliBufferTooSmall;
  2556. }
  2557. if (_LastError == 0)
  2558. Time_ms = Environment.TickCount - Elapsed;
  2559. return _LastError;
  2560. }
  2561. public int DBFill(int DBNumber, int FillChar)
  2562. {
  2563. S7BlockInfo BI = new S7BlockInfo();
  2564. int Elapsed = Environment.TickCount;
  2565. Time_ms = 0;
  2566. _LastError = GetAgBlockInfo(Block_DB, DBNumber, ref BI);
  2567. if (_LastError == 0)
  2568. {
  2569. byte[] Buffer = new byte[BI.MC7Size];
  2570. for (int c = 0; c < BI.MC7Size; c++)
  2571. Buffer[c] = (byte)FillChar;
  2572. _LastError = DBWrite(DBNumber, 0, BI.MC7Size, Buffer);
  2573. }
  2574. if (_LastError == 0)
  2575. Time_ms = Environment.TickCount - Elapsed;
  2576. return _LastError;
  2577. }
  2578. #endregion
  2579. #region [Date/Time functions]
  2580. public int GetPlcDateTime(ref DateTime DT)
  2581. {
  2582. int Length;
  2583. _LastError = 0;
  2584. Time_ms = 0;
  2585. int Elapsed = Environment.TickCount;
  2586. SendPacket(S7_GET_DT);
  2587. if (_LastError == 0)
  2588. {
  2589. Length = RecvIsoPacket();
  2590. if (Length > 30) // the minimum expected
  2591. {
  2592. if ((S7.GetWordAt(PDU, 27) == 0) && (PDU[29] == 0xFF))
  2593. {
  2594. DT = S7.GetDateTimeAt(PDU, 35);
  2595. }
  2596. else
  2597. _LastError = S7Consts.errCliInvalidPlcAnswer;
  2598. }
  2599. else
  2600. _LastError = S7Consts.errIsoInvalidPDU;
  2601. }
  2602. if(_LastError==0)
  2603. Time_ms = Environment.TickCount - Elapsed;
  2604. return _LastError;
  2605. }
  2606. public int SetPlcDateTime(DateTime DT)
  2607. {
  2608. int Length;
  2609. _LastError = 0;
  2610. Time_ms = 0;
  2611. int Elapsed = Environment.TickCount;
  2612. S7.SetDateTimeAt(S7_SET_DT, 31, DT);
  2613. SendPacket(S7_SET_DT);
  2614. if (_LastError == 0)
  2615. {
  2616. Length = RecvIsoPacket();
  2617. if (Length > 30) // the minimum expected
  2618. {
  2619. if (S7.GetWordAt(PDU, 27) != 0)
  2620. _LastError = S7Consts.errCliInvalidPlcAnswer;
  2621. }
  2622. else
  2623. _LastError = S7Consts.errIsoInvalidPDU;
  2624. }
  2625. if (_LastError == 0)
  2626. Time_ms = Environment.TickCount - Elapsed;
  2627. return _LastError;
  2628. }
  2629. public int SetPlcSystemDateTime()
  2630. {
  2631. return SetPlcDateTime(DateTime.Now);
  2632. }
  2633. #endregion
  2634. #region [System Info functions]
  2635. public int GetOrderCode(ref S7OrderCode Info)
  2636. {
  2637. S7SZL SZL = new S7SZL();
  2638. int Size = 1024;
  2639. SZL.Data = new byte[Size];
  2640. int Elapsed = Environment.TickCount;
  2641. _LastError = ReadSZL(0x0011, 0x000, ref SZL, ref Size);
  2642. if (_LastError == 0)
  2643. {
  2644. Info.Code = S7.GetCharsAt(SZL.Data, 2, 20);
  2645. Info.V1 = SZL.Data[Size - 3];
  2646. Info.V2 = SZL.Data[Size - 2];
  2647. Info.V3 = SZL.Data[Size - 1];
  2648. }
  2649. if (_LastError == 0)
  2650. Time_ms = Environment.TickCount - Elapsed;
  2651. return _LastError;
  2652. }
  2653. public int GetCpuInfo(ref S7CpuInfo Info)
  2654. {
  2655. S7SZL SZL = new S7SZL();
  2656. int Size = 1024;
  2657. SZL.Data = new byte[Size];
  2658. int Elapsed = Environment.TickCount;
  2659. _LastError = ReadSZL(0x001C, 0x000, ref SZL, ref Size);
  2660. if (_LastError == 0)
  2661. {
  2662. Info.ModuleTypeName = S7.GetCharsAt(SZL.Data, 172, 32);
  2663. Info.SerialNumber = S7.GetCharsAt(SZL.Data, 138, 24);
  2664. Info.ASName = S7.GetCharsAt(SZL.Data, 2, 24);
  2665. Info.Copyright = S7.GetCharsAt(SZL.Data, 104, 26);
  2666. Info.ModuleName = S7.GetCharsAt(SZL.Data, 36, 24);
  2667. }
  2668. if (_LastError == 0)
  2669. Time_ms = Environment.TickCount - Elapsed;
  2670. return _LastError;
  2671. }
  2672. public int GetCpInfo(ref S7CpInfo Info)
  2673. {
  2674. S7SZL SZL = new S7SZL();
  2675. int Size = 1024;
  2676. SZL.Data = new byte[Size];
  2677. int Elapsed = Environment.TickCount;
  2678. _LastError = ReadSZL(0x0131, 0x001, ref SZL, ref Size);
  2679. if (_LastError == 0)
  2680. {
  2681. Info.MaxPduLength = S7.GetIntAt(PDU, 2);
  2682. Info.MaxConnections = S7.GetIntAt(PDU, 4);
  2683. Info.MaxMpiRate = S7.GetDIntAt(PDU, 6);
  2684. Info.MaxBusRate = S7.GetDIntAt(PDU, 10);
  2685. }
  2686. if (_LastError == 0)
  2687. Time_ms = Environment.TickCount - Elapsed;
  2688. return _LastError;
  2689. }
  2690. public int ReadSZL(int ID, int Index, ref S7SZL SZL, ref int Size)
  2691. {
  2692. int Length;
  2693. int DataSZL;
  2694. int Offset = 0;
  2695. bool Done = false;
  2696. bool First = true;
  2697. byte Seq_in = 0x00;
  2698. ushort Seq_out = 0x0000;
  2699. _LastError = 0;
  2700. Time_ms = 0;
  2701. int Elapsed = Environment.TickCount;
  2702. SZL.Header.LENTHDR = 0;
  2703. do
  2704. {
  2705. if (First)
  2706. {
  2707. S7.SetWordAt(S7_SZL_FIRST, 11, ++Seq_out);
  2708. S7.SetWordAt(S7_SZL_FIRST, 29, (ushort)ID);
  2709. S7.SetWordAt(S7_SZL_FIRST, 31, (ushort)Index);
  2710. SendPacket(S7_SZL_FIRST);
  2711. }
  2712. else
  2713. {
  2714. S7.SetWordAt(S7_SZL_NEXT, 11, ++Seq_out);
  2715. PDU[24] = (byte)Seq_in;
  2716. SendPacket(S7_SZL_NEXT);
  2717. }
  2718. if (_LastError != 0)
  2719. return _LastError;
  2720. Length = RecvIsoPacket();
  2721. if (_LastError == 0)
  2722. {
  2723. if (First)
  2724. {
  2725. if (Length > 32) // the minimum expected
  2726. {
  2727. if ((S7.GetWordAt(PDU, 27) == 0) && (PDU[29] == (byte)0xFF))
  2728. {
  2729. // Gets Amount of this slice
  2730. DataSZL = S7.GetWordAt(PDU, 31) - 8; // Skips extra params (ID, Index ...)
  2731. Done = PDU[26] == 0x00;
  2732. Seq_in = (byte)PDU[24]; // Slice sequence
  2733. SZL.Header.LENTHDR = S7.GetWordAt(PDU, 37);
  2734. SZL.Header.N_DR = S7.GetWordAt(PDU, 39);
  2735. Array.Copy(PDU, 41, SZL.Data, Offset, DataSZL);
  2736. // SZL.Copy(PDU, 41, Offset, DataSZL);
  2737. Offset += DataSZL;
  2738. SZL.Header.LENTHDR += SZL.Header.LENTHDR;
  2739. }
  2740. else
  2741. _LastError = S7Consts.errCliInvalidPlcAnswer;
  2742. }
  2743. else
  2744. _LastError = S7Consts.errIsoInvalidPDU;
  2745. }
  2746. else
  2747. {
  2748. if (Length > 32) // the minimum expected
  2749. {
  2750. if ((S7.GetWordAt(PDU, 27) == 0) && (PDU[29] == (byte)0xFF))
  2751. {
  2752. // Gets Amount of this slice
  2753. DataSZL = S7.GetWordAt(PDU, 31);
  2754. Done = PDU[26] == 0x00;
  2755. Seq_in = (byte)PDU[24]; // Slice sequence
  2756. Array.Copy(PDU, 37, SZL.Data, Offset, DataSZL);
  2757. Offset += DataSZL;
  2758. SZL.Header.LENTHDR += SZL.Header.LENTHDR;
  2759. }
  2760. else
  2761. _LastError = S7Consts.errCliInvalidPlcAnswer;
  2762. }
  2763. else
  2764. _LastError = S7Consts.errIsoInvalidPDU;
  2765. }
  2766. }
  2767. First = false;
  2768. }
  2769. while (!Done && (_LastError == 0));
  2770. if (_LastError==0)
  2771. {
  2772. Size = SZL.Header.LENTHDR;
  2773. Time_ms = Environment.TickCount - Elapsed;
  2774. }
  2775. return _LastError;
  2776. }
  2777. public int ReadSZLList(ref S7SZLList List, ref Int32 ItemsCount)
  2778. {
  2779. return S7Consts.errCliFunctionNotImplemented;
  2780. }
  2781. #endregion
  2782. #region [Control functions]
  2783. public int PlcHotStart()
  2784. {
  2785. _LastError = 0;
  2786. int Elapsed = Environment.TickCount;
  2787. SendPacket(S7_HOT_START);
  2788. if (_LastError == 0)
  2789. {
  2790. int Length = RecvIsoPacket();
  2791. if (Length > 18) // 18 is the minimum expected
  2792. {
  2793. if (PDU[19] != pduStart)
  2794. _LastError = S7Consts.errCliCannotStartPLC;
  2795. else
  2796. {
  2797. if (PDU[20] == pduAlreadyStarted)
  2798. _LastError = S7Consts.errCliAlreadyRun;
  2799. else
  2800. _LastError = S7Consts.errCliCannotStartPLC;
  2801. }
  2802. }
  2803. else
  2804. _LastError = S7Consts.errIsoInvalidPDU;
  2805. }
  2806. if (_LastError == 0)
  2807. Time_ms = Environment.TickCount - Elapsed;
  2808. return _LastError;
  2809. }
  2810. public int PlcColdStart()
  2811. {
  2812. _LastError = 0;
  2813. int Elapsed = Environment.TickCount;
  2814. SendPacket(S7_COLD_START);
  2815. if (_LastError == 0)
  2816. {
  2817. int Length = RecvIsoPacket();
  2818. if (Length > 18) // 18 is the minimum expected
  2819. {
  2820. if (PDU[19] != pduStart)
  2821. _LastError = S7Consts.errCliCannotStartPLC;
  2822. else
  2823. {
  2824. if (PDU[20] == pduAlreadyStarted)
  2825. _LastError = S7Consts.errCliAlreadyRun;
  2826. else
  2827. _LastError = S7Consts.errCliCannotStartPLC;
  2828. }
  2829. }
  2830. else
  2831. _LastError = S7Consts.errIsoInvalidPDU;
  2832. }
  2833. if (_LastError == 0)
  2834. Time_ms = Environment.TickCount - Elapsed;
  2835. return _LastError;
  2836. }
  2837. public int PlcStop()
  2838. {
  2839. _LastError = 0;
  2840. int Elapsed = Environment.TickCount;
  2841. SendPacket(S7_STOP);
  2842. if (_LastError == 0)
  2843. {
  2844. int Length = RecvIsoPacket();
  2845. if (Length > 18) // 18 is the minimum expected
  2846. {
  2847. if (PDU[19]!=pduStop)
  2848. _LastError = S7Consts.errCliCannotStopPLC;
  2849. else
  2850. {
  2851. if (PDU[20]== pduAlreadyStopped)
  2852. _LastError = S7Consts.errCliAlreadyStop;
  2853. else
  2854. _LastError = S7Consts.errCliCannotStopPLC;
  2855. }
  2856. }
  2857. else
  2858. _LastError = S7Consts.errIsoInvalidPDU;
  2859. }
  2860. if (_LastError == 0)
  2861. Time_ms = Environment.TickCount - Elapsed;
  2862. return _LastError;
  2863. }
  2864. public int PlcCopyRamToRom(UInt32 Timeout)
  2865. {
  2866. return S7Consts.errCliFunctionNotImplemented;
  2867. }
  2868. public int PlcCompress(UInt32 Timeout)
  2869. {
  2870. return S7Consts.errCliFunctionNotImplemented;
  2871. }
  2872. public int PlcGetStatus(ref Int32 Status)
  2873. {
  2874. _LastError = 0;
  2875. int Elapsed = Environment.TickCount;
  2876. SendPacket(S7_GET_STAT);
  2877. if (_LastError == 0)
  2878. {
  2879. int Length = RecvIsoPacket();
  2880. if (Length > 30) // the minimum expected
  2881. {
  2882. ushort Result = S7.GetWordAt(PDU, 27);
  2883. if (Result == 0)
  2884. {
  2885. switch (PDU[44])
  2886. {
  2887. case S7Consts.S7CpuStatusUnknown:
  2888. case S7Consts.S7CpuStatusRun:
  2889. case S7Consts.S7CpuStatusStop:
  2890. {
  2891. Status = PDU[44];
  2892. break;
  2893. }
  2894. default:
  2895. {
  2896. // Since RUN status is always 0x08 for all CPUs and CPs, STOP status
  2897. // sometime can be coded as 0x03 (especially for old cpu...)
  2898. Status = S7Consts.S7CpuStatusStop;
  2899. break;
  2900. }
  2901. }
  2902. }
  2903. else
  2904. _LastError = CpuError(Result);
  2905. }
  2906. else
  2907. _LastError = S7Consts.errIsoInvalidPDU;
  2908. }
  2909. if (_LastError == 0)
  2910. Time_ms = Environment.TickCount - Elapsed;
  2911. return _LastError;
  2912. }
  2913. #endregion
  2914. #region [Security functions]
  2915. public int SetSessionPassword(string Password)
  2916. {
  2917. byte[] pwd = { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
  2918. int Length;
  2919. _LastError = 0;
  2920. int Elapsed = Environment.TickCount;
  2921. // Encodes the Password
  2922. S7.SetCharsAt(pwd, 0, Password);
  2923. pwd[0] = (byte)(pwd[0] ^ 0x55);
  2924. pwd[1] = (byte)(pwd[1] ^ 0x55);
  2925. for (int c = 2; c < 8; c++)
  2926. {
  2927. pwd[c] = (byte)(pwd[c] ^ 0x55 ^ pwd[c - 2]);
  2928. }
  2929. Array.Copy(pwd, 0, S7_SET_PWD, 29, 8);
  2930. // Sends the telegrem
  2931. SendPacket(S7_SET_PWD);
  2932. if (_LastError == 0)
  2933. {
  2934. Length = RecvIsoPacket();
  2935. if (Length > 32) // the minimum expected
  2936. {
  2937. ushort Result = S7.GetWordAt(PDU, 27);
  2938. if (Result != 0)
  2939. _LastError = CpuError(Result);
  2940. }
  2941. else
  2942. _LastError = S7Consts.errIsoInvalidPDU;
  2943. }
  2944. if (_LastError == 0)
  2945. Time_ms = Environment.TickCount - Elapsed;
  2946. return _LastError;
  2947. }
  2948. public int ClearSessionPassword()
  2949. {
  2950. int Length;
  2951. _LastError = 0;
  2952. int Elapsed = Environment.TickCount;
  2953. SendPacket(S7_CLR_PWD);
  2954. if (_LastError == 0)
  2955. {
  2956. Length = RecvIsoPacket();
  2957. if (Length > 30) // the minimum expected
  2958. {
  2959. ushort Result = S7.GetWordAt(PDU, 27);
  2960. if (Result != 0)
  2961. _LastError = CpuError(Result);
  2962. }
  2963. else
  2964. _LastError = S7Consts.errIsoInvalidPDU;
  2965. }
  2966. return _LastError;
  2967. }
  2968. public int GetProtection(ref S7Protection Protection)
  2969. {
  2970. S7Client.S7SZL SZL = new S7Client.S7SZL();
  2971. int Size = 256;
  2972. SZL.Data = new byte[Size];
  2973. _LastError = ReadSZL(0x0232, 0x0004, ref SZL, ref Size);
  2974. if (_LastError == 0)
  2975. {
  2976. Protection.sch_schal = S7.GetWordAt(SZL.Data, 2);
  2977. Protection.sch_par = S7.GetWordAt(SZL.Data, 4);
  2978. Protection.sch_rel = S7.GetWordAt(SZL.Data, 6);
  2979. Protection.bart_sch = S7.GetWordAt(SZL.Data, 8);
  2980. Protection.anl_sch = S7.GetWordAt(SZL.Data, 10);
  2981. }
  2982. return _LastError;
  2983. }
  2984. #endregion
  2985. #region [Low Level]
  2986. public int IsoExchangeBuffer(byte[] Buffer, ref Int32 Size)
  2987. {
  2988. _LastError = 0;
  2989. Time_ms = 0;
  2990. int Elapsed = Environment.TickCount;
  2991. Array.Copy(TPKT_ISO, 0, PDU, 0, TPKT_ISO.Length);
  2992. S7.SetWordAt(PDU, 2, (ushort)(Size + TPKT_ISO.Length));
  2993. try
  2994. {
  2995. Array.Copy(Buffer, 0, PDU, TPKT_ISO.Length, Size);
  2996. }
  2997. catch
  2998. {
  2999. return S7Consts.errIsoInvalidPDU;
  3000. }
  3001. SendPacket(PDU, TPKT_ISO.Length + Size);
  3002. if (_LastError==0)
  3003. {
  3004. int Length=RecvIsoPacket();
  3005. if (_LastError==0)
  3006. {
  3007. Array.Copy(PDU, TPKT_ISO.Length, Buffer, 0, Length - TPKT_ISO.Length);
  3008. Size = Length - TPKT_ISO.Length;
  3009. }
  3010. }
  3011. if (_LastError == 0)
  3012. Time_ms = Environment.TickCount - Elapsed;
  3013. else
  3014. Size = 0;
  3015. return _LastError;
  3016. }
  3017. #endregion
  3018. #region [Async functions (not implemented)]
  3019. public int AsReadArea(int Area, int DBNumber, int Start, int Amount, int WordLen, byte[] Buffer)
  3020. {
  3021. return S7Consts.errCliFunctionNotImplemented;
  3022. }
  3023. public int AsWriteArea(int Area, int DBNumber, int Start, int Amount, int WordLen, byte[] Buffer)
  3024. {
  3025. return S7Consts.errCliFunctionNotImplemented;
  3026. }
  3027. public int AsDBRead(int DBNumber, int Start, int Size, byte[] Buffer)
  3028. {
  3029. return S7Consts.errCliFunctionNotImplemented;
  3030. }
  3031. public int AsDBWrite(int DBNumber, int Start, int Size, byte[] Buffer)
  3032. {
  3033. return S7Consts.errCliFunctionNotImplemented;
  3034. }
  3035. public int AsMBRead(int Start, int Size, byte[] Buffer)
  3036. {
  3037. return S7Consts.errCliFunctionNotImplemented;
  3038. }
  3039. public int AsMBWrite(int Start, int Size, byte[] Buffer)
  3040. {
  3041. return S7Consts.errCliFunctionNotImplemented;
  3042. }
  3043. public int AsEBRead(int Start, int Size, byte[] Buffer)
  3044. {
  3045. return S7Consts.errCliFunctionNotImplemented;
  3046. }
  3047. public int AsEBWrite(int Start, int Size, byte[] Buffer)
  3048. {
  3049. return S7Consts.errCliFunctionNotImplemented;
  3050. }
  3051. public int AsABRead(int Start, int Size, byte[] Buffer)
  3052. {
  3053. return S7Consts.errCliFunctionNotImplemented;
  3054. }
  3055. public int AsABWrite(int Start, int Size, byte[] Buffer)
  3056. {
  3057. return S7Consts.errCliFunctionNotImplemented;
  3058. }
  3059. public int AsTMRead(int Start, int Amount, ushort[] Buffer)
  3060. {
  3061. return S7Consts.errCliFunctionNotImplemented;
  3062. }
  3063. public int AsTMWrite(int Start, int Amount, ushort[] Buffer)
  3064. {
  3065. return S7Consts.errCliFunctionNotImplemented;
  3066. }
  3067. public int AsCTRead(int Start, int Amount, ushort[] Buffer)
  3068. {
  3069. return S7Consts.errCliFunctionNotImplemented;
  3070. }
  3071. public int AsCTWrite(int Start, int Amount, ushort[] Buffer)
  3072. {
  3073. return S7Consts.errCliFunctionNotImplemented;
  3074. }
  3075. public int AsListBlocksOfType(int BlockType, ushort[] List)
  3076. {
  3077. return S7Consts.errCliFunctionNotImplemented;
  3078. }
  3079. public int AsReadSZL(int ID, int Index, ref S7SZL Data, ref Int32 Size)
  3080. {
  3081. return S7Consts.errCliFunctionNotImplemented;
  3082. }
  3083. public int AsReadSZLList(ref S7SZLList List, ref Int32 ItemsCount)
  3084. {
  3085. return S7Consts.errCliFunctionNotImplemented;
  3086. }
  3087. public int AsUpload(int BlockType, int BlockNum, byte[] UsrData, ref int Size)
  3088. {
  3089. return S7Consts.errCliFunctionNotImplemented;
  3090. }
  3091. public int AsFullUpload(int BlockType, int BlockNum, byte[] UsrData, ref int Size)
  3092. {
  3093. return S7Consts.errCliFunctionNotImplemented;
  3094. }
  3095. public int ASDownload(int BlockNum, byte[] UsrData, int Size)
  3096. {
  3097. return S7Consts.errCliFunctionNotImplemented;
  3098. }
  3099. public int AsPlcCopyRamToRom(UInt32 Timeout)
  3100. {
  3101. return S7Consts.errCliFunctionNotImplemented;
  3102. }
  3103. public int AsPlcCompress(UInt32 Timeout)
  3104. {
  3105. return S7Consts.errCliFunctionNotImplemented;
  3106. }
  3107. public int AsDBGet(int DBNumber, byte[] UsrData, ref int Size)
  3108. {
  3109. return S7Consts.errCliFunctionNotImplemented;
  3110. }
  3111. public int AsDBFill(int DBNumber, int FillChar)
  3112. {
  3113. return S7Consts.errCliFunctionNotImplemented;
  3114. }
  3115. public bool CheckAsCompletion(ref int opResult)
  3116. {
  3117. opResult = 0;
  3118. return false;
  3119. }
  3120. public int WaitAsCompletion(int Timeout)
  3121. {
  3122. return S7Consts.errCliFunctionNotImplemented;
  3123. }
  3124. #endregion
  3125. #region [Info Functions / Properties]
  3126. public string ErrorText(int Error)
  3127. {
  3128. switch (Error)
  3129. {
  3130. case 0: return "OK";
  3131. case S7Consts.errTCPSocketCreation: return "SYS : Error creating the Socket";
  3132. case S7Consts.errTCPConnectionTimeout: return "TCP : Connection Timeout";
  3133. case S7Consts.errTCPConnectionFailed: return "TCP : Connection Error";
  3134. case S7Consts.errTCPReceiveTimeout: return "TCP : Data receive Timeout";
  3135. case S7Consts.errTCPDataReceive: return "TCP : Error receiving Data";
  3136. case S7Consts.errTCPSendTimeout: return "TCP : Data send Timeout";
  3137. case S7Consts.errTCPDataSend: return "TCP : Error sending Data";
  3138. case S7Consts.errTCPConnectionReset: return "TCP : Connection reset by the Peer";
  3139. case S7Consts.errTCPNotConnected: return "CLI : Client not connected";
  3140. case S7Consts.errTCPUnreachableHost: return "TCP : Unreachable host";
  3141. case S7Consts.errIsoConnect: return "ISO : Connection Error";
  3142. case S7Consts.errIsoInvalidPDU: return "ISO : Invalid PDU received";
  3143. case S7Consts.errIsoInvalidDataSize: return "ISO : Invalid Buffer passed to Send/Receive";
  3144. case S7Consts.errCliNegotiatingPDU: return "CLI : Error in PDU negotiation";
  3145. case S7Consts.errCliInvalidParams: return "CLI : invalid param(s) supplied";
  3146. case S7Consts.errCliJobPending: return "CLI : Job pending";
  3147. case S7Consts.errCliTooManyItems: return "CLI : too may items (>20) in multi read/write";
  3148. case S7Consts.errCliInvalidWordLen: return "CLI : invalid WordLength";
  3149. case S7Consts.errCliPartialDataWritten: return "CLI : Partial data written";
  3150. case S7Consts.errCliSizeOverPDU: return "CPU : total data exceeds the PDU size";
  3151. case S7Consts.errCliInvalidPlcAnswer: return "CLI : invalid CPU answer";
  3152. case S7Consts.errCliAddressOutOfRange: return "CPU : Address out of range";
  3153. case S7Consts.errCliInvalidTransportSize: return "CPU : Invalid Transport size";
  3154. case S7Consts.errCliWriteDataSizeMismatch: return "CPU : Data size mismatch";
  3155. case S7Consts.errCliItemNotAvailable: return "CPU : Item not available";
  3156. case S7Consts.errCliInvalidValue: return "CPU : Invalid value supplied";
  3157. case S7Consts.errCliCannotStartPLC: return "CPU : Cannot start PLC";
  3158. case S7Consts.errCliAlreadyRun: return "CPU : PLC already RUN";
  3159. case S7Consts.errCliCannotStopPLC: return "CPU : Cannot stop PLC";
  3160. case S7Consts.errCliCannotCopyRamToRom: return "CPU : Cannot copy RAM to ROM";
  3161. case S7Consts.errCliCannotCompress: return "CPU : Cannot compress";
  3162. case S7Consts.errCliAlreadyStop: return "CPU : PLC already STOP";
  3163. case S7Consts.errCliFunNotAvailable: return "CPU : Function not available";
  3164. case S7Consts.errCliUploadSequenceFailed: return "CPU : Upload sequence failed";
  3165. case S7Consts.errCliInvalidDataSizeRecvd: return "CLI : Invalid data size received";
  3166. case S7Consts.errCliInvalidBlockType: return "CLI : Invalid block type";
  3167. case S7Consts.errCliInvalidBlockNumber: return "CLI : Invalid block number";
  3168. case S7Consts.errCliInvalidBlockSize: return "CLI : Invalid block size";
  3169. case S7Consts.errCliNeedPassword: return "CPU : Function not authorized for current protection level";
  3170. case S7Consts.errCliInvalidPassword: return "CPU : Invalid password";
  3171. case S7Consts.errCliNoPasswordToSetOrClear: return "CPU : No password to set or clear";
  3172. case S7Consts.errCliJobTimeout: return "CLI : Job Timeout";
  3173. case S7Consts.errCliFunctionRefused: return "CLI : function refused by CPU (Unknown error)";
  3174. case S7Consts.errCliPartialDataRead: return "CLI : Partial data read";
  3175. case S7Consts.errCliBufferTooSmall: return "CLI : The buffer supplied is too small to accomplish the operation";
  3176. case S7Consts.errCliDestroying: return "CLI : Cannot perform (destroying)";
  3177. case S7Consts.errCliInvalidParamNumber: return "CLI : Invalid Param Number";
  3178. case S7Consts.errCliCannotChangeParam: return "CLI : Cannot change this param now";
  3179. case S7Consts.errCliFunctionNotImplemented: return "CLI : Function not implemented";
  3180. default: return "CLI : Unknown error (0x" + Convert.ToString(Error, 16) + ")";
  3181. };
  3182. }
  3183. public int LastError()
  3184. {
  3185. return _LastError;
  3186. }
  3187. public int RequestedPduLength()
  3188. {
  3189. return _PduSizeRequested;
  3190. }
  3191. public int NegotiatedPduLength()
  3192. {
  3193. return _PDULength;
  3194. }
  3195. public int ExecTime()
  3196. {
  3197. return Time_ms;
  3198. }
  3199. public int ExecutionTime
  3200. {
  3201. get
  3202. {
  3203. return Time_ms;
  3204. }
  3205. }
  3206. public int PduSizeNegotiated
  3207. {
  3208. get
  3209. {
  3210. return _PDULength;
  3211. }
  3212. }
  3213. public int PduSizeRequested
  3214. {
  3215. get
  3216. {
  3217. return _PduSizeRequested;
  3218. }
  3219. set
  3220. {
  3221. if (value < MinPduSizeToRequest)
  3222. value = MinPduSizeToRequest;
  3223. if (value > MaxPduSizeToRequest)
  3224. value = MaxPduSizeToRequest;
  3225. _PduSizeRequested = value;
  3226. }
  3227. }
  3228. public int PLCPort
  3229. {
  3230. get
  3231. {
  3232. return _PLCPort;
  3233. }
  3234. set
  3235. {
  3236. _PLCPort = value;
  3237. }
  3238. }
  3239. public int ConnTimeout
  3240. {
  3241. get
  3242. {
  3243. return _ConnTimeout;
  3244. }
  3245. set
  3246. {
  3247. _ConnTimeout = value;
  3248. }
  3249. }
  3250. public int RecvTimeout
  3251. {
  3252. get
  3253. {
  3254. return _RecvTimeout;
  3255. }
  3256. set
  3257. {
  3258. _RecvTimeout = value;
  3259. }
  3260. }
  3261. public int SendTimeout
  3262. {
  3263. get
  3264. {
  3265. return _SendTimeout;
  3266. }
  3267. set
  3268. {
  3269. _SendTimeout = value;
  3270. }
  3271. }
  3272. public bool Connected
  3273. {
  3274. get
  3275. {
  3276. return (Socket != null) && (Socket.Connected);
  3277. }
  3278. }
  3279. #endregion
  3280. }
  3281. }