hls.py 183 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247
  1. '''
  2. GNU LESSER GENERAL PUBLIC LICENSE
  3. Version 3, 29 June 2007
  4. Copyright (C) 2017 - 2018 Richard.Hu <http://fsf.org/>
  5. Everyone is permitted to copy and distribute verbatim copies
  6. of this license document, but changing it is not allowed.
  7. This version of the GNU Lesser General Public License incorporates
  8. the terms and conditions of version 3 of the GNU General Public
  9. License, supplemented by the additional permissions listed below.
  10. 0. Additional Definitions.
  11. As used herein, "this License" refers to version 3 of the GNU Lesser
  12. General Public License, and the "GNU GPL" refers to version 3 of the GNU
  13. General Public License.
  14. "The Library" refers to a covered work governed by this License,
  15. other than an Application or a Combined Work as defined below.
  16. An "Application" is any work that makes use of an interface provided
  17. by the Library, but which is not otherwise based on the Library.
  18. Defining a subclass of a class defined by the Library is deemed a mode
  19. of using an interface provided by the Library.
  20. A "Combined Work" is a work produced by combining or linking an
  21. Application with the Library. The particular version of the Library
  22. with which the Combined Work was made is also called the "Linked
  23. Version".
  24. The "Minimal Corresponding Source" for a Combined Work means the
  25. Corresponding Source for the Combined Work, excluding any source code
  26. for portions of the Combined Work that, considered in isolation, are
  27. based on the Application, and not on the Linked Version.
  28. The "Corresponding Application Code" for a Combined Work means the
  29. object code and/or source code for the Application, including any data
  30. and utility programs needed for reproducing the Combined Work from the
  31. Application, but excluding the System Libraries of the Combined Work.
  32. 1. Exception to Section 3 of the GNU GPL.
  33. You may convey a covered work under sections 3 and 4 of this License
  34. without being bound by section 3 of the GNU GPL.
  35. 2. Conveying Modified Versions.
  36. If you modify a copy of the Library, and, in your modifications, a
  37. facility refers to a function or data to be supplied by an Application
  38. that uses the facility (other than as an argument passed when the
  39. facility is invoked), then you may convey a copy of the modified
  40. version:
  41. a) under this License, provided that you make a good faith effort to
  42. ensure that, in the event an Application does not supply the
  43. function or data, the facility still operates, and performs
  44. whatever part of its purpose remains meaningful, or
  45. b) under the GNU GPL, with none of the additional permissions of
  46. this License applicable to that copy.
  47. 3. Object Code Incorporating Material from Library Header Files.
  48. The object code form of an Application may incorporate material from
  49. a header file that is part of the Library. You may convey such object
  50. code under terms of your choice, provided that, if the incorporated
  51. material is not limited to numerical parameters, data structure
  52. layouts and accessors, or small macros, inline functions and templates
  53. (ten or fewer lines in length), you do both of the following:
  54. a) Give prominent notice with each copy of the object code that the
  55. Library is used in it and that the Library and its use are
  56. covered by this License.
  57. b) Accompany the object code with a copy of the GNU GPL and this license
  58. document.
  59. 4. Combined Works.
  60. You may convey a Combined Work under terms of your choice that,
  61. taken together, effectively do not restrict modification of the
  62. portions of the Library contained in the Combined Work and reverse
  63. engineering for debugging such modifications, if you also do each of
  64. the following:
  65. a) Give prominent notice with each copy of the Combined Work that
  66. the Library is used in it and that the Library and its use are
  67. covered by this License.
  68. b) Accompany the Combined Work with a copy of the GNU GPL and this license
  69. document.
  70. c) For a Combined Work that displays copyright notices during
  71. execution, include the copyright notice for the Library among
  72. these notices, as well as a reference directing the user to the
  73. copies of the GNU GPL and this license document.
  74. d) Do one of the following:
  75. 0) Convey the Minimal Corresponding Source under the terms of this
  76. License, and the Corresponding Application Code in a form
  77. suitable for, and under terms that permit, the user to
  78. recombine or relink the Application with a modified version of
  79. the Linked Version to produce a modified Combined Work, in the
  80. manner specified by section 6 of the GNU GPL for conveying
  81. Corresponding Source.
  82. 1) Use a suitable shared library mechanism for linking with the
  83. Library. A suitable mechanism is one that (a) uses at run time
  84. a copy of the Library already present on the user's computer
  85. system, and (b) will operate properly with a modified version
  86. of the Library that is interface-compatible with the Linked
  87. Version.
  88. e) Provide Installation Information, but only if you would otherwise
  89. be required to provide such information under section 6 of the
  90. GNU GPL, and only to the extent that such information is
  91. necessary to install and execute a modified version of the
  92. Combined Work produced by recombining or relinking the
  93. Application with a modified version of the Linked Version. (If
  94. you use option 4d0, the Installation Information must accompany
  95. the Minimal Corresponding Source and Corresponding Application
  96. Code. If you use option 4d1, you must provide the Installation
  97. Information in the manner specified by section 6 of the GNU GPL
  98. for conveying Corresponding Source.)
  99. 5. Combined Libraries.
  100. You may place library facilities that are a work based on the
  101. Library side by side in a single library together with other library
  102. facilities that are not Applications and are not covered by this
  103. License, and convey such a combined library under terms of your
  104. choice, if you do both of the following:
  105. a) Accompany the combined library with a copy of the same work based
  106. on the Library, uncombined with any other library facilities,
  107. conveyed under the terms of this License.
  108. b) Give prominent notice with the combined library that part of it
  109. is a work based on the Library, and explaining where to find the
  110. accompanying uncombined form of the same work.
  111. 6. Revised Versions of the GNU Lesser General Public License.
  112. The Free Software Foundation may publish revised and/or new versions
  113. of the GNU Lesser General Public License from time to time. Such new
  114. versions will be similar in spirit to the present version, but may
  115. differ in detail to address new problems or concerns.
  116. Each version is given a distinguishing version number. If the
  117. Library as you received it specifies that a certain numbered version
  118. of the GNU Lesser General Public License "or any later version"
  119. applies to it, you have the option of following the terms and
  120. conditions either of that published version or of any later version
  121. published by the Free Software Foundation. If the Library as you
  122. received it does not specify a version number of the GNU Lesser
  123. General Public License, you may choose any version of the GNU Lesser
  124. General Public License ever published by the Free Software Foundation.
  125. If the Library as you received it specifies that a proxy can decide
  126. whether future versions of the GNU Lesser General Public License shall
  127. apply, that proxy's public statement of acceptance of any version is
  128. permanent authorization for you to choose that version for the
  129. Library.
  130. '''
  131. import string
  132. import uuid
  133. import socket
  134. import struct
  135. import threading
  136. import gzip
  137. import datetime
  138. import random
  139. from time import sleep
  140. from enum import Enum
  141. class StringResources:
  142. '''系统的资源类'''
  143. @staticmethod
  144. def ConnectedFailed():
  145. return "连接失败"
  146. @staticmethod
  147. def UnknownError():
  148. return "未知错误"
  149. @staticmethod
  150. def ErrorCode():
  151. return "错误代号"
  152. @staticmethod
  153. def TextDescription():
  154. return "文本描述"
  155. @staticmethod
  156. def ExceptionMessage():
  157. return "错误信息:"
  158. @staticmethod
  159. def ExceptionStackTrace():
  160. return "错误堆栈:"
  161. @staticmethod
  162. def ExceptopnTargetSite():
  163. return "错误方法:"
  164. @staticmethod
  165. def ExceprionCustomer():
  166. return "用户自定义方法出错:"
  167. @staticmethod
  168. def TokenCheckFailed():
  169. return "令牌检查错误。"
  170. @staticmethod
  171. def SuccessText():
  172. return "Success"
  173. @staticmethod
  174. def NotSupportedDataType():
  175. return "输入的类型不支持,请重新输入"
  176. # Modbus相关
  177. @staticmethod
  178. def ModbusTcpFunctionCodeNotSupport():
  179. return "不支持的功能码"
  180. @staticmethod
  181. def ModbusTcpFunctionCodeOverBound():
  182. return "读取的数据越界"
  183. @staticmethod
  184. def ModbusTcpFunctionCodeQuantityOver():
  185. return "读取长度超过最大值"
  186. @staticmethod
  187. def ModbusTcpFunctionCodeReadWriteException():
  188. return "读写异常"
  189. @staticmethod
  190. def ModbusTcpReadCoilException():
  191. return "读取线圈异常"
  192. @staticmethod
  193. def ModbusTcpWriteCoilException():
  194. return "写入线圈异常"
  195. @staticmethod
  196. def ModbusTcpReadRegisterException():
  197. return "读取寄存器异常"
  198. @staticmethod
  199. def ModbusTcpWriteRegisterException():
  200. return "写入寄存器异常"
  201. @staticmethod
  202. def ModbusAddressMustMoreThanOne():
  203. return "地址值在起始地址为1的情况下,必须大于1"
  204. @staticmethod
  205. def MelsecPleaseReferToManulDocument():
  206. return "请查看三菱的通讯手册来查看报警的具体信息"
  207. @staticmethod
  208. def MelsecReadBitInfo():
  209. return "读取位变量数组只能针对位软元件,如果读取字软元件,请调用Read方法"
  210. @staticmethod
  211. def OmronStatus0():
  212. return "通讯正常"
  213. @staticmethod
  214. def OmronStatus1():
  215. return "消息头不是FINS"
  216. @staticmethod
  217. def OmronStatus2():
  218. return "数据长度太长"
  219. @staticmethod
  220. def OmronStatus3():
  221. return "该命令不支持"
  222. @staticmethod
  223. def OmronStatus20():
  224. return "超过连接上限"
  225. @staticmethod
  226. def OmronStatus21():
  227. return "指定的节点已经处于连接中"
  228. @staticmethod
  229. def OmronStatus22():
  230. return "尝试去连接一个受保护的网络节点,该节点还未配置到PLC中"
  231. @staticmethod
  232. def OmronStatus23():
  233. return "当前客户端的网络节点超过正常范围"
  234. @staticmethod
  235. def OmronStatus24():
  236. return "当前客户端的网络节点已经被使用"
  237. @staticmethod
  238. def OmronStatus25():
  239. return "所有的网络节点已经被使用"
  240. class OperateResult:
  241. '''结果对象类,可以携带额外的数据信息'''
  242. def __init__(self, err = 0, msg = ""):
  243. self.ErrorCode = err
  244. self.Message = msg
  245. # 是否成功的标志
  246. IsSuccess = False
  247. # 操作返回的错误消息
  248. Message = StringResources.SuccessText()
  249. # 错误码
  250. ErrorCode = 0
  251. # 返回显示的文本
  252. def ToMessageShowString( self ):
  253. '''获取错误代号及文本描述'''
  254. return StringResources.ErrorCode() + ":" + str(self.ErrorCode) + "\r\n" + StringResources.TextDescription() + ":" + self.Message
  255. def CopyErrorFromOther(self, result):
  256. '''从另一个结果类中拷贝错误信息'''
  257. if result != None:
  258. self.ErrorCode = result.ErrorCode
  259. self.Message = result.Message
  260. @staticmethod
  261. def CreateFailedResult( result ):
  262. '''创建一个失败的结果对象'''
  263. failed = OperateResult()
  264. failed.ErrorCode = result.ErrorCode
  265. failed.Message = result.Message
  266. return failed
  267. @staticmethod
  268. def CreateSuccessResult(Content1=None,Content2=None,Content3=None,Content4=None,Content5=None,Content6=None,Content7=None,Content8=None,Content9=None,Content10=None):
  269. '''创建一个成功的对象'''
  270. success = OperateResult()
  271. success.IsSuccess = True
  272. success.Message = StringResources.SuccessText()
  273. if(Content2 == None and Content3 == None and Content4 == None and Content5 == None and Content6 == None and Content7 == None and Content8 == None and Content9 == None and Content10 == None) :
  274. success.Content = Content1
  275. else:
  276. success.Content1 = Content1
  277. success.Content2 = Content2
  278. success.Content3 = Content3
  279. success.Content4 = Content4
  280. success.Content5 = Content5
  281. success.Content6 = Content6
  282. success.Content7 = Content7
  283. success.Content8 = Content8
  284. success.Content9 = Content9
  285. success.Content10 = Content10
  286. return success
  287. class SoftIncrementCount:
  288. '''一个简单的不持久化的序号自增类,采用线程安全实现,并允许指定最大数字,到达后清空从指定数开始'''
  289. start = 0
  290. current = 0
  291. maxValue = 100000000000000000000000000
  292. hybirdLock = threading.Lock()
  293. def __init__(self, maxValue, start):
  294. '''实例化一个自增信息的对象,包括最大值'''
  295. self.maxValue = maxValue
  296. self.start = start
  297. def GetCurrentValue( self ):
  298. '''获取自增信息'''
  299. value = 0
  300. self.hybirdLock.acquire()
  301. value = self.current
  302. self.current = self.current + 1
  303. if self.current > self.maxValue:
  304. self.current = 0
  305. self.hybirdLock.release()
  306. return value
  307. class INetMessage:
  308. '''数据消息的基本基类'''
  309. def ProtocolHeadBytesLength(self):
  310. '''协议头数据长度,也即是第一次接收的数据长度'''
  311. return 0
  312. def GetContentLengthByHeadBytes(self):
  313. '''二次接收的数据长度'''
  314. return 0
  315. def CheckHeadBytesLegal(self,toke):
  316. '''令牌检查是否成功'''
  317. return False
  318. def GetHeadBytesIdentity(self):
  319. '''获取头子节里的消息标识'''
  320. return 0
  321. HeadBytes = bytes(0)
  322. ContentBytes = bytes(0)
  323. SendBytes = bytes(0)
  324. class S7Message (INetMessage):
  325. '''西门子s7协议的消息接收规则'''
  326. def ProtocolHeadBytesLength(self):
  327. '''协议头数据长度,也即是第一次接收的数据长度'''
  328. return 4
  329. def GetContentLengthByHeadBytes(self):
  330. '''二次接收的数据长度'''
  331. if self.HeadBytes != None:
  332. return self.HeadBytes[2]*256 + self.HeadBytes[3]-4
  333. else:
  334. return 0
  335. def CheckHeadBytesLegal(self,token):
  336. '''令牌检查是否成功'''
  337. if self.HeadBytes != None:
  338. if self.HeadBytes[0] == 0x03 and self.HeadBytes[1] == 0x00:
  339. return True
  340. else:
  341. return False
  342. else:
  343. return False
  344. class MelsecA1EBinaryMessage(INetMessage):
  345. '''三菱的A兼容1E帧协议解析规则'''
  346. def ProtocolHeadBytesLength(self):
  347. '''协议头数据长度,也即是第一次接收的数据长度'''
  348. return 2
  349. def GetContentLengthByHeadBytes(self):
  350. '''二次接收的数据长度'''
  351. contentLength = 0
  352. if self.HeadBytes[1] == 0x5B:
  353. contentLength = 2
  354. else:
  355. length = 0
  356. if self.SendBytes[10] % 2 == 0:
  357. length = self.SendBytes[10]
  358. else:
  359. length = self.SendBytes[10] + 1
  360. if self.HeadBytes[0] == 0x80:
  361. contentLength = int(length / 2)
  362. elif self.HeadBytes[0] == 0x81:
  363. contentLength = self.SendBytes[10] * 2
  364. elif self.HeadBytes[0] == 0x82:
  365. contentLength = 0
  366. elif self.HeadBytes[0] == 0x83:
  367. contentLength = 0
  368. # 在A兼容1E协议中,写入值后,若不发生异常,只返回副标题 + 结束代码(0x00)
  369. # 这已经在协议头部读取过了,后面要读取的长度为0(contentLength=0)
  370. return contentLength
  371. def CheckHeadBytesLegal(self,token):
  372. '''令牌检查是否成功'''
  373. if self.HeadBytes != None:
  374. if self.HeadBytes[0] - self.SendBytes[0] == 0x80:
  375. return True
  376. else:
  377. return False
  378. else:
  379. return False
  380. class MelsecQnA3EBinaryMessage(INetMessage):
  381. '''三菱的Qna兼容3E帧协议解析规则'''
  382. def ProtocolHeadBytesLength(self):
  383. '''协议头数据长度,也即是第一次接收的数据长度'''
  384. return 9
  385. def GetContentLengthByHeadBytes(self):
  386. '''二次接收的数据长度'''
  387. if self.HeadBytes != None:
  388. return self.HeadBytes[8] * 256 + self.HeadBytes[7]
  389. else:
  390. return 0
  391. def CheckHeadBytesLegal(self,token):
  392. '''令牌检查是否成功'''
  393. if self.HeadBytes != None:
  394. if self.HeadBytes[0] == 0xD0 and self.HeadBytes[1] == 0x00:
  395. return True
  396. else:
  397. return False
  398. else:
  399. return False
  400. class MelsecQnA3EAsciiMessage(INetMessage):
  401. '''三菱的Qna兼容3E帧的ASCII协议解析规则'''
  402. def ProtocolHeadBytesLength(self):
  403. '''协议头数据长度,也即是第一次接收的数据长度'''
  404. return 18
  405. def GetContentLengthByHeadBytes(self):
  406. '''二次接收的数据长度'''
  407. if self.HeadBytes != None:
  408. return int(self.HeadBytes[14:18].decode('ascii'),16)
  409. else:
  410. return 0
  411. def CheckHeadBytesLegal(self,token):
  412. '''令牌检查是否成功'''
  413. if self.HeadBytes != None:
  414. if self.HeadBytes[0] == ord('D') and self.HeadBytes[1] == ord('0') and self.HeadBytes[2] == ord('0') and self.HeadBytes[3] == ord('0'):
  415. return True
  416. else:
  417. return False
  418. else:
  419. return False
  420. class ModbusTcpMessage (INetMessage):
  421. '''Modbus-Tcp协议的信息'''
  422. def ProtocolHeadBytesLength(self):
  423. '''协议头数据长度,也即是第一次接收的数据长度'''
  424. return 6
  425. def GetContentLengthByHeadBytes(self):
  426. '''二次接收的数据长度'''
  427. if self.HeadBytes != None:
  428. return self.HeadBytes[4] * 256 + self.HeadBytes[5]
  429. else:
  430. return 0
  431. def CheckHeadBytesLegal(self,token):
  432. '''令牌检查是否成功'''
  433. return True
  434. def GetHeadBytesIdentity(self):
  435. '''获取头子节里的消息标识'''
  436. return self.HeadBytes[0] * 256 + self.HeadBytes[1]
  437. class HslMessage (INetMessage):
  438. '''本组件系统使用的默认的消息规则,说明解析和反解析规则的'''
  439. def ProtocolHeadBytesLength(self):
  440. '''协议头数据长度,也即是第一次接收的数据长度'''
  441. return 32
  442. def GetContentLengthByHeadBytes(self):
  443. '''二次接收的数据长度'''
  444. if self.HeadBytes != None:
  445. buffer = bytearray(4)
  446. buffer[0:4] = self.HeadBytes[28:32]
  447. return struct.unpack('<i',buffer)[0]
  448. else:
  449. return 0
  450. def GetHeadBytesIdentity(self):
  451. '''获取头子节里的消息标识'''
  452. if self.HeadBytes != None:
  453. buffer = bytearray(4)
  454. buffer[0:4] = self.HeadBytes[4:8]
  455. return struct.unpack('<i',buffer)[0]
  456. else:
  457. return 0
  458. def CheckHeadBytesLegal(self,token):
  459. '''令牌检查是否成功'''
  460. if self.HeadBytes == None:
  461. return False
  462. else:
  463. return SoftBasic.IsTwoBytesEquel(self.HeadBytes,12,token,0,16)
  464. class DataFormat(Enum):
  465. '''应用于多字节数据的解析或是生成格式'''
  466. ABCD = 0
  467. BADC = 1
  468. CDAB = 2
  469. DCBA = 3
  470. class ByteTransform:
  471. '''数据转换类的基础,提供了一些基础的方法实现.'''
  472. DataFormat = DataFormat.DCBA
  473. def TransBool(self, buffer, index ):
  474. '''将buffer数组转化成bool对象'''
  475. return ((buffer[index] & 0x01) == 0x01)
  476. def TransBoolArray(self, buffer, index, length ):
  477. '''将buffer数组转化成bool数组对象,需要转入索引,长度'''
  478. data = bytearray(length)
  479. for i in range(length):
  480. data[i]=buffer[i+index]
  481. return SoftBasic.ByteToBoolArray( data, length * 8 )
  482. def TransByte( self, buffer, index ):
  483. '''将buffer中的字节转化成byte对象,需要传入索引'''
  484. return buffer[index]
  485. def TransByteArray( self, buffer, index, length ):
  486. '''将buffer中的字节转化成byte数组对象,需要传入索引'''
  487. data = bytearray(length)
  488. for i in range(length):
  489. data[i]=buffer[i+index]
  490. return data
  491. def TransInt16( self, buffer, index ):
  492. '''从缓存中提取short结果'''
  493. data = self.TransByteArray(buffer,index,2)
  494. return struct.unpack('<h',data)[0]
  495. def TransInt16Array( self, buffer, index, length ):
  496. '''从缓存中提取short数组结果'''
  497. tmp = []
  498. for i in range(length):
  499. tmp.append( self.TransInt16( buffer, index + 2 * i ))
  500. return tmp
  501. def TransUInt16(self, buffer, index ):
  502. '''从缓存中提取ushort结果'''
  503. data = self.TransByteArray(buffer,index,2)
  504. return struct.unpack('<H',data)[0]
  505. def TransUInt16Array(self, buffer, index, length ):
  506. '''从缓存中提取ushort数组结果'''
  507. tmp = []
  508. for i in range(length):
  509. tmp.append( self.TransUInt16( buffer, index + 2 * i ))
  510. return tmp
  511. def TransInt32(self, buffer, index ):
  512. '''从缓存中提取int结果'''
  513. data = self.ByteTransDataFormat4(self.TransByteArray(buffer,index,4))
  514. return struct.unpack('<i',data)[0]
  515. def TransInt32Array(self, buffer, index, length ):
  516. '''从缓存中提取int数组结果'''
  517. tmp = []
  518. for i in range(length):
  519. tmp.append( self.TransInt32( buffer, index + 4 * i ))
  520. return tmp
  521. def TransUInt32(self, buffer, index ):
  522. '''从缓存中提取uint结果'''
  523. data = self.ByteTransDataFormat4(self.TransByteArray(buffer,index,4))
  524. return struct.unpack('<I',data)[0]
  525. def TransUInt32Array(self, buffer, index, length ):
  526. '''从缓存中提取uint数组结果'''
  527. tmp = []
  528. for i in range(length):
  529. tmp.append( self.TransUInt32( buffer, index + 4 * i ))
  530. return tmp
  531. def TransInt64(self, buffer, index ):
  532. '''从缓存中提取long结果'''
  533. data = self.ByteTransDataFormat8(self.TransByteArray(buffer,index,8))
  534. return struct.unpack('<q',data)[0]
  535. def TransInt64Array(self, buffer, index, length):
  536. '''从缓存中提取long数组结果'''
  537. tmp = []
  538. for i in range(length):
  539. tmp.append( self.TransInt64( buffer, index + 8 * i ))
  540. return tmp
  541. def TransUInt64(self, buffer, index ):
  542. '''从缓存中提取ulong结果'''
  543. data = self.ByteTransDataFormat8(self.TransByteArray(buffer,index,8))
  544. return struct.unpack('<Q',data)[0]
  545. def TransUInt64Array(self, buffer, index, length):
  546. '''从缓存中提取ulong数组结果'''
  547. tmp = []
  548. for i in range(length):
  549. tmp.append( self.TransUInt64( buffer, index + 8 * i ))
  550. return tmp
  551. def TransSingle(self, buffer, index ):
  552. '''从缓存中提取float结果'''
  553. data = self.ByteTransDataFormat4(self.TransByteArray(buffer,index,4))
  554. return struct.unpack('<f',data)[0]
  555. def TransSingleArray(self, buffer, index, length):
  556. '''从缓存中提取float数组结果'''
  557. tmp = []
  558. for i in range(length):
  559. tmp.append( self.TransSingle( buffer, index + 4 * i ))
  560. return tmp
  561. def TransDouble(self, buffer, index ):
  562. '''从缓存中提取double结果'''
  563. data = self.ByteTransDataFormat8(self.TransByteArray(buffer,index,8))
  564. return struct.unpack('<d',data)[0]
  565. def TransDoubleArray(self, buffer, index, length):
  566. '''从缓存中提取double数组结果'''
  567. tmp = []
  568. for i in range(length):
  569. tmp.append( self.TransDouble( buffer, index + 8 * i ))
  570. return tmp
  571. def TransString( self, buffer, index, length, encoding ):
  572. '''从缓存中提取string结果,使用指定的编码'''
  573. data = self.TransByteArray(buffer,index,length)
  574. return data.decode(encoding)
  575. def BoolArrayTransByte(self, values):
  576. '''bool数组变量转化缓存数据,需要传入bool数组'''
  577. if (values == None): return None
  578. return SoftBasic.BoolArrayToByte( values )
  579. def BoolTransByte(self, value):
  580. '''bool变量转化缓存数据,需要传入bool值'''
  581. return self.BoolArrayTransByte([value])
  582. def ByteTransByte(self, value ):
  583. '''byte变量转化缓存数据,需要传入byte值'''
  584. buffer = bytearray(1)
  585. buffer[0] = value
  586. return buffer
  587. def Int16ArrayTransByte(self, values ):
  588. '''short数组变量转化缓存数据,需要传入short数组'''
  589. if (values == None) : return None
  590. buffer = bytearray(len(values) * 2)
  591. for i in range(len(values)):
  592. buffer[(i*2): (i*2+2)] = struct.pack('<h',values[i])
  593. return buffer
  594. def Int16TransByte(self, value ):
  595. '''short数组变量转化缓存数据,需要传入short值'''
  596. return self.Int16ArrayTransByte([value])
  597. def UInt16ArrayTransByte(self, values ):
  598. '''ushort数组变量转化缓存数据,需要传入ushort数组'''
  599. if (values == None) : return None
  600. buffer = bytearray(len(values) * 2)
  601. for i in range(len(values)):
  602. buffer[(i*2): (i*2+2)] = struct.pack('<H',values[i])
  603. return buffer
  604. def UInt16TransByte(self, value ):
  605. '''ushort变量转化缓存数据,需要传入ushort值'''
  606. return self.UInt16ArrayTransByte([value])
  607. def Int32ArrayTransByte(self, values ):
  608. '''int数组变量转化缓存数据,需要传入int数组'''
  609. if (values == None) : return None
  610. buffer = bytearray(len(values) * 4)
  611. for i in range(len(values)):
  612. buffer[(i*4): (i*4+4)] = self.ByteTransDataFormat4(struct.pack('<i',values[i]))
  613. return buffer
  614. def Int32TransByte(self, value ):
  615. '''int变量转化缓存数据,需要传入int值'''
  616. return self.Int32ArrayTransByte([value])
  617. def UInt32ArrayTransByte(self, values ):
  618. '''uint数组变量转化缓存数据,需要传入uint数组'''
  619. if (values == None) : return None
  620. buffer = bytearray(len(values) * 4)
  621. for i in range(len(values)):
  622. buffer[(i*4): (i*4+4)] = self.ByteTransDataFormat4(struct.pack('<I',values[i]))
  623. return buffer
  624. def UInt32TransByte(self, value ):
  625. '''uint变量转化缓存数据,需要传入uint值'''
  626. return self.UInt32ArrayTransByte([value])
  627. def Int64ArrayTransByte(self, values ):
  628. '''long数组变量转化缓存数据,需要传入long数组'''
  629. if (values == None) : return None
  630. buffer = bytearray(len(values) * 8)
  631. for i in range(len(values)):
  632. buffer[(i*8): (i*8+8)] = self.ByteTransDataFormat8(struct.pack('<q',values[i]))
  633. return buffer
  634. def Int64TransByte(self, value ):
  635. '''long变量转化缓存数据,需要传入long值'''
  636. return self.Int64ArrayTransByte([value])
  637. def UInt64ArrayTransByte(self, values ):
  638. '''ulong数组变量转化缓存数据,需要传入ulong数组'''
  639. if (values == None) : return None
  640. buffer = bytearray(len(values) * 8)
  641. for i in range(len(values)):
  642. buffer[(i*8): (i*8+8)] = self.ByteTransDataFormat8(struct.pack('<Q',values[i]))
  643. return buffer
  644. def UInt64TransByte(self, value ):
  645. '''ulong变量转化缓存数据,需要传入ulong值'''
  646. return self.UInt64ArrayTransByte([value])
  647. def FloatArrayTransByte(self, values ):
  648. '''float数组变量转化缓存数据,需要传入float数组'''
  649. if (values == None) : return None
  650. buffer = bytearray(len(values) * 4)
  651. for i in range(len(values)):
  652. buffer[(i*4): (i*4+4)] = self.ByteTransDataFormat4(struct.pack('<f',values[i]))
  653. return buffer
  654. def FloatTransByte(self, value ):
  655. '''float变量转化缓存数据,需要传入float值'''
  656. return self.FloatArrayTransByte([value])
  657. def DoubleArrayTransByte(self, values ):
  658. '''double数组变量转化缓存数据,需要传入double数组'''
  659. if (values == None) : return None
  660. buffer = bytearray(len(values) * 8)
  661. for i in range(len(values)):
  662. buffer[(i*8): (i*8+8)] = self.ByteTransDataFormat8(struct.pack('<d',values[i]))
  663. return buffer
  664. def DoubleTransByte(self, value ):
  665. '''double变量转化缓存数据,需要传入double值'''
  666. return self.DoubleArrayTransByte([value])
  667. def StringTransByte(self, value:str, encoding:str ):
  668. '''使用指定的编码字符串转化缓存数据,需要传入string值及编码信息'''
  669. return value.encode(encoding)
  670. def ByteTransDataFormat4(self, value, index = 0 ):
  671. '''反转多字节的数据信息'''
  672. buffer = bytearray(4)
  673. if self.DataFormat == DataFormat.ABCD:
  674. buffer[0] = value[index + 3]
  675. buffer[1] = value[index + 2]
  676. buffer[2] = value[index + 1]
  677. buffer[3] = value[index + 0]
  678. elif self.DataFormat == DataFormat.BADC:
  679. buffer[0] = value[index + 2]
  680. buffer[1] = value[index + 3]
  681. buffer[2] = value[index + 0]
  682. buffer[3] = value[index + 1]
  683. elif self.DataFormat == DataFormat.CDAB:
  684. buffer[0] = value[index + 1]
  685. buffer[1] = value[index + 0]
  686. buffer[2] = value[index + 3]
  687. buffer[3] = value[index + 2]
  688. elif self.DataFormat == DataFormat.DCBA:
  689. buffer[0] = value[index + 0]
  690. buffer[1] = value[index + 1]
  691. buffer[2] = value[index + 2]
  692. buffer[3] = value[index + 3]
  693. return buffer
  694. def ByteTransDataFormat8(self, value, index = 0 ):
  695. '''反转多字节的数据信息'''
  696. buffer = bytearray(8)
  697. if self.DataFormat == DataFormat.ABCD:
  698. buffer[0] = value[index + 7]
  699. buffer[1] = value[index + 6]
  700. buffer[2] = value[index + 5]
  701. buffer[3] = value[index + 4]
  702. buffer[4] = value[index + 3]
  703. buffer[5] = value[index + 2]
  704. buffer[6] = value[index + 1]
  705. buffer[7] = value[index + 0]
  706. elif self.DataFormat == DataFormat.BADC:
  707. buffer[0] = value[index + 6]
  708. buffer[1] = value[index + 7]
  709. buffer[2] = value[index + 4]
  710. buffer[3] = value[index + 5]
  711. buffer[4] = value[index + 2]
  712. buffer[5] = value[index + 3]
  713. buffer[6] = value[index + 0]
  714. buffer[7] = value[index + 1]
  715. elif self.DataFormat == DataFormat.CDAB:
  716. buffer[0] = value[index + 1]
  717. buffer[1] = value[index + 0]
  718. buffer[2] = value[index + 3]
  719. buffer[3] = value[index + 2]
  720. buffer[4] = value[index + 5]
  721. buffer[5] = value[index + 4]
  722. buffer[6] = value[index + 7]
  723. buffer[7] = value[index + 6]
  724. elif self.DataFormat == DataFormat.DCBA:
  725. buffer[0] = value[index + 0]
  726. buffer[1] = value[index + 1]
  727. buffer[2] = value[index + 2]
  728. buffer[3] = value[index + 3]
  729. buffer[4] = value[index + 4]
  730. buffer[5] = value[index + 5]
  731. buffer[6] = value[index + 6]
  732. buffer[7] = value[index + 7]
  733. return buffer
  734. class RegularByteTransform(ByteTransform):
  735. '''常规的字节转换类'''
  736. def __init__(self):
  737. return
  738. class ReverseBytesTransform(ByteTransform):
  739. '''字节倒序的转换类'''
  740. def TransInt16(self, buffer, index ):
  741. '''从缓存中提取short结果'''
  742. data = self.TransByteArray(buffer,index,2)
  743. return struct.unpack('>h',data)[0]
  744. def TransUInt16(self, buffer, index ):
  745. '''从缓存中提取ushort结果'''
  746. data = self.TransByteArray(buffer,index,2)
  747. return struct.unpack('>H',data)[0]
  748. def TransInt32(self, buffer, index ):
  749. '''从缓存中提取int结果'''
  750. data = self.TransByteArray(buffer,index,4)
  751. return struct.unpack('>i',data)[0]
  752. def TransUInt32(self, buffer, index ):
  753. '''从缓存中提取uint结果'''
  754. data = self.TransByteArray(buffer,index,4)
  755. return struct.unpack('>I',data)[0]
  756. def TransInt64(self, buffer, index ):
  757. '''从缓存中提取long结果'''
  758. data = self.TransByteArray(buffer,index,8)
  759. return struct.unpack('>q',data)[0]
  760. def TransUInt64(self, buffer, index ):
  761. '''从缓存中提取ulong结果'''
  762. data = self.TransByteArray(buffer,index,8)
  763. return struct.unpack('>Q',data)[0]
  764. def TransSingle(self, buffer, index ):
  765. '''从缓存中提取float结果'''
  766. data = self.TransByteArray(buffer,index,4)
  767. return struct.unpack('>f',data)[0]
  768. def TransDouble(self, buffer, index ):
  769. '''从缓存中提取double结果'''
  770. data = self.TransByteArray(buffer,index,8)
  771. return struct.unpack('>d',data)[0]
  772. def Int16ArrayTransByte(self, values ):
  773. '''short数组变量转化缓存数据,需要传入short数组 -> bytearray'''
  774. if (values == None) : return None
  775. buffer = bytearray(len(values) * 2)
  776. for i in range(len(values)):
  777. buffer[(i*2): (i*2+2)] = struct.pack('>h',values[i])
  778. return buffer
  779. def UInt16ArrayTransByte(self, values ):
  780. '''ushort数组变量转化缓存数据,需要传入ushort数组 -> bytearray'''
  781. if (values == None) : return None
  782. buffer = bytearray(len(values) * 2)
  783. for i in range(len(values)):
  784. buffer[(i*2): (i*2+2)] = struct.pack('>H',values[i])
  785. return buffer
  786. def Int32ArrayTransByte(self, values ):
  787. '''int数组变量转化缓存数据,需要传入int数组 -> bytearray'''
  788. if (values == None) : return None
  789. buffer = bytearray(len(values) * 4)
  790. for i in range(len(values)):
  791. buffer[(i*4): (i*4+4)] = struct.pack('>i',values[i])
  792. return buffer
  793. def UInt32ArrayTransByte(self, values ):
  794. '''uint数组变量转化缓存数据,需要传入uint数组 -> bytearray'''
  795. if (values == None) : return None
  796. buffer = bytearray(len(values) * 4)
  797. for i in range(len(values)):
  798. buffer[(i*4): (i*4+4)] = struct.pack('>I',values[i])
  799. return buffer
  800. def Int64ArrayTransByte(self, values ):
  801. '''long数组变量转化缓存数据,需要传入long数组 -> bytearray'''
  802. if (values == None) : return None
  803. buffer = bytearray(len(values) * 8)
  804. for i in range(len(values)):
  805. buffer[(i*8): (i*8+8)] = struct.pack('>q',values[i])
  806. return buffer
  807. def UInt64ArrayTransByte(self, values ):
  808. '''ulong数组变量转化缓存数据,需要传入ulong数组 -> bytearray'''
  809. if (values == None) : return None
  810. buffer = bytearray(len(values) * 8)
  811. for i in range(len(values)):
  812. buffer[(i*8): (i*8+8)] = struct.pack('>Q',values[i])
  813. return buffer
  814. def FloatArrayTransByte(self, values ):
  815. '''float数组变量转化缓存数据,需要传入float数组 -> bytearray'''
  816. if (values == None) : return None
  817. buffer = bytearray(len(values) * 4)
  818. for i in range(len(values)):
  819. buffer[(i*4): (i*4+4)] = struct.pack('>f',values[i])
  820. return buffer
  821. def DoubleArrayTransByte(self, values ):
  822. '''double数组变量转化缓存数据,需要传入double数组 -> bytearray'''
  823. if (values == None) : return None
  824. buffer = bytearray(len(values) * 8)
  825. for i in range(len(values)):
  826. buffer[(i*8): (i*8+8)] = struct.pack('>d',values[i])
  827. return buffer
  828. class ReverseWordTransform(ByteTransform):
  829. '''按照字节错位的数据转换类'''
  830. def __init__(self):
  831. '''初始化方法,重新设置DataFormat'''
  832. self.DataFormat = DataFormat.ABCD
  833. IsStringReverse = False
  834. def ReverseBytesByWord( self, buffer, index, length ):
  835. '''按照字节错位的方法 -> bytearray'''
  836. if buffer == None: return None
  837. data = self.TransByteArray(buffer,index,length)
  838. for i in range(len(data)//2):
  839. data[i*2+0],data[i*2+1]= data[i*2+1],data[i*2+0]
  840. return data
  841. def ReverseAllBytesByWord( self, buffer ):
  842. '''按照字节错位的方法 -> bytearray'''
  843. return self.ReverseBytesByWord(buffer,0,len(buffer))
  844. def TransInt16( self, buffer, index ):
  845. '''从缓存中提取short结果'''
  846. data = self.ReverseBytesByWord(buffer,index,2)
  847. return struct.unpack('<h',data)[0]
  848. def TransUInt16(self, buffer, index ):
  849. '''从缓存中提取ushort结果'''
  850. data = self.ReverseBytesByWord(buffer,index,2)
  851. return struct.unpack('<H',data)[0]
  852. def TransString( self, buffer, index, length, encoding ):
  853. '''从缓存中提取string结果,使用指定的编码'''
  854. data = self.TransByteArray(buffer,index,length)
  855. if self.IsStringReverse:
  856. return self.ReverseAllBytesByWord(data).decode(encoding)
  857. else:
  858. return data.decode(encoding)
  859. def Int16ArrayTransByte(self, values ):
  860. '''short数组变量转化缓存数据,需要传入short数组'''
  861. buffer = super().Int16ArrayTransByte(values)
  862. return self.ReverseAllBytesByWord(buffer)
  863. def UInt16ArrayTransByte(self, values ):
  864. '''ushort数组变量转化缓存数据,需要传入ushort数组'''
  865. buffer = super().UInt16ArrayTransByte(values)
  866. return self.ReverseAllBytesByWord(buffer)
  867. def StringTransByte(self, value, encoding ):
  868. '''使用指定的编码字符串转化缓存数据,需要传入string值及编码信息'''
  869. buffer = value.encode(encoding)
  870. buffer = SoftBasic.BytesArrayExpandToLengthEven(buffer)
  871. if self.IsStringReverse:
  872. return self.ReverseAllBytesByWord( buffer )
  873. else:
  874. return buffer
  875. class ByteTransformHelper:
  876. '''所有数据转换类的静态辅助方法'''
  877. @staticmethod
  878. def GetBoolResultFromBytes( result, byteTransform ):
  879. '''将指定的OperateResult类型转化'''
  880. try:
  881. if result.IsSuccess:
  882. return OperateResult.CreateSuccessResult(byteTransform.TransBool(result.Content , 0 ))
  883. else:
  884. return OperateResult.CreateFailedResult(result)
  885. except Exception as ex:
  886. return OperateResult( msg = "数据转化失败,源数据:" + SoftBasic.ByteToHexString( result.Content ) + " 消息:" + str(ex))
  887. @staticmethod
  888. def GetByteResultFromBytes( result, byteTransform ):
  889. '''将指定的OperateResult类型转化'''
  890. try:
  891. if result.IsSuccess:
  892. return OperateResult.CreateSuccessResult(byteTransform.TransByte(result.Content , 0 ))
  893. else:
  894. return OperateResult.CreateFailedResult(result)
  895. except Exception as ex:
  896. return OperateResult( msg = "数据转化失败,源数据:" + SoftBasic.ByteToHexString( result.Content ) + " 消息:" + str(ex))
  897. @staticmethod
  898. def GetInt16ResultFromBytes( result, byteTransform ):
  899. '''将指定的OperateResult类型转化'''
  900. try:
  901. if result.IsSuccess:
  902. return OperateResult.CreateSuccessResult(byteTransform.TransInt16(result.Content , 0 ))
  903. else:
  904. return OperateResult.CreateFailedResult(result)
  905. except Exception as ex:
  906. return OperateResult( msg = "数据转化失败,源数据:" + SoftBasic.ByteToHexString( result.Content ) + " 消息:" + str(ex))
  907. @staticmethod
  908. def GetUInt16ResultFromBytes( result, byteTransform ):
  909. '''将指定的OperateResult类型转化'''
  910. try:
  911. if result.IsSuccess:
  912. return OperateResult.CreateSuccessResult(byteTransform.TransUInt16(result.Content , 0 ))
  913. else:
  914. return OperateResult.CreateFailedResult(result)
  915. except Exception as ex:
  916. return OperateResult( msg = "数据转化失败,源数据:" + SoftBasic.ByteToHexString( result.Content ) + " 消息:" + str(ex))
  917. @staticmethod
  918. def GetInt32ResultFromBytes( result, byteTransform ):
  919. '''将指定的OperateResult类型转化'''
  920. try:
  921. if result.IsSuccess:
  922. return OperateResult.CreateSuccessResult(byteTransform.TransInt32(result.Content , 0 ))
  923. else:
  924. return OperateResult.CreateFailedResult(result)
  925. except Exception as ex:
  926. return OperateResult( msg = "数据转化失败,源数据:" + SoftBasic.ByteToHexString( result.Content ) + " 消息:" + str(ex))
  927. @staticmethod
  928. def GetUInt32ResultFromBytes( result, byteTransform ):
  929. '''将指定的OperateResult类型转化'''
  930. try:
  931. if result.IsSuccess:
  932. return OperateResult.CreateSuccessResult(byteTransform.TransUInt32(result.Content , 0 ))
  933. else:
  934. return OperateResult.CreateFailedResult(result)
  935. except Exception as ex:
  936. return OperateResult( msg = "数据转化失败,源数据:" + SoftBasic.ByteToHexString( result.Content ) + " 消息:" + str(ex))
  937. @staticmethod
  938. def GetInt64ResultFromBytes( result, byteTransform ):
  939. '''将指定的OperateResult类型转化'''
  940. try:
  941. if result.IsSuccess:
  942. return OperateResult.CreateSuccessResult(byteTransform.TransInt64(result.Content , 0 ))
  943. else:
  944. return OperateResult.CreateFailedResult(result)
  945. except Exception as ex:
  946. return OperateResult( msg = "数据转化失败,源数据:" + SoftBasic.ByteToHexString( result.Content ) + " 消息:" + str(ex))
  947. @staticmethod
  948. def GetUInt64ResultFromBytes( result, byteTransform ):
  949. '''将指定的OperateResult类型转化'''
  950. try:
  951. if result.IsSuccess:
  952. return OperateResult.CreateSuccessResult(byteTransform.TransUInt64(result.Content , 0 ))
  953. else:
  954. return OperateResult.CreateFailedResult(result)
  955. except Exception as ex:
  956. return OperateResult( msg = "数据转化失败,源数据:" + SoftBasic.ByteToHexString( result.Content ) + " 消息:" + str(ex))
  957. @staticmethod
  958. def GetSingleResultFromBytes( result, byteTransform ):
  959. '''将指定的OperateResult类型转化'''
  960. try:
  961. if result.IsSuccess:
  962. return OperateResult.CreateSuccessResult(byteTransform.TransSingle(result.Content , 0 ))
  963. else:
  964. return OperateResult.CreateFailedResult(result)
  965. except Exception as ex:
  966. return OperateResult( msg = "数据转化失败,源数据:" + SoftBasic.ByteToHexString( result.Content ) + " 消息:" + str(ex))
  967. @staticmethod
  968. def GetDoubleResultFromBytes( result, byteTransform ):
  969. '''将指定的OperateResult类型转化'''
  970. try:
  971. if result.IsSuccess:
  972. return OperateResult.CreateSuccessResult(byteTransform.TransDouble(result.Content , 0 ))
  973. else:
  974. return OperateResult.CreateFailedResult(result)
  975. except Exception as ex:
  976. return OperateResult( msg = "数据转化失败,源数据:" + SoftBasic.ByteToHexString( result.Content ) + " 消息:" + str(ex))
  977. @staticmethod
  978. def GetStringResultFromBytes( result, byteTransform ):
  979. '''将指定的OperateResult类型转化'''
  980. try:
  981. if result.IsSuccess:
  982. return OperateResult.CreateSuccessResult(byteTransform.TransString(result.Content , 0, len(result.Content), 'ascii' ))
  983. else:
  984. return OperateResult.CreateFailedResult(result)
  985. except Exception as ex:
  986. return OperateResult( msg = "数据转化失败,源数据:" + SoftBasic.ByteToHexString( result.Content ) + " 消息:" + str(ex))
  987. class DeviceAddressBase:
  988. '''所有设备通信类的地址基础类'''
  989. Address = 0
  990. def AnalysisAddress( self, address ):
  991. '''解析字符串的地址'''
  992. self.Address = int(address)
  993. class SoftBasic:
  994. '''系统运行的基础方法,提供了一些基本的辅助方法'''
  995. @staticmethod
  996. def GetSizeDescription(size):
  997. '''获取指定数据大小的文本描述字符串'''
  998. if size < 1000:
  999. return str(size) + " B"
  1000. elif size < (1000 * 1000):
  1001. data = float(size) / 1024
  1002. return '{:.2f}'.format(data) + " Kb"
  1003. elif size < (1000 * 1000 * 1000):
  1004. data = float(size) / 1024 / 1024
  1005. return '{:.2f}'.format(data) + " Mb"
  1006. else:
  1007. data = float(size) / 1024 / 1024 / 1024
  1008. return '{:.2f}'.format(data) + " Gb"
  1009. @staticmethod
  1010. def ByteToHexString(inBytes,segment=' '):
  1011. '''将字节数组转换成十六进制的表示形式,需要传入2个参数,数据和分隔符,该方法还存在一点问题'''
  1012. str_list = []
  1013. for byte in inBytes:
  1014. str_list.append('{:02X}'.format(byte))
  1015. if segment != None:
  1016. return segment.join(str_list)
  1017. else:
  1018. return ''.join(str_list)
  1019. @staticmethod
  1020. def ByteToBoolArray( InBytes, length ):
  1021. '''从字节数组中提取bool数组变量信息'''
  1022. if InBytes == None:
  1023. return None
  1024. if length > len(InBytes) * 8:
  1025. length = len(InBytes) * 8
  1026. buffer = []
  1027. for i in range(length):
  1028. index = i // 8
  1029. offect = i % 8
  1030. temp = 0
  1031. if offect == 0 : temp = 0x01
  1032. elif offect == 1 : temp = 0x02
  1033. elif offect == 2 : temp = 0x04
  1034. elif offect == 3 : temp = 0x08
  1035. elif offect == 4 : temp = 0x10
  1036. elif offect == 5 : temp = 0x20
  1037. elif offect == 6 : temp = 0x40
  1038. elif offect == 7 : temp = 0x80
  1039. if (InBytes[index] & temp) == temp:
  1040. buffer.append(True)
  1041. else:
  1042. buffer.append(False)
  1043. return buffer
  1044. @staticmethod
  1045. def BoolArrayToByte( array ):
  1046. '''从bool数组变量变成byte数组'''
  1047. if (array == None) : return None
  1048. length = 0
  1049. if len(array) % 8 == 0:
  1050. length = int(len(array) / 8)
  1051. else:
  1052. length = int(len(array) / 8) + 1
  1053. buffer = bytearray(length)
  1054. for i in range(len(array)):
  1055. index = i // 8
  1056. offect = i % 8
  1057. temp = 0
  1058. if offect == 0 : temp = 0x01
  1059. elif offect == 1 : temp = 0x02
  1060. elif offect == 2 : temp = 0x04
  1061. elif offect == 3 : temp = 0x08
  1062. elif offect == 4 : temp = 0x10
  1063. elif offect == 5 : temp = 0x20
  1064. elif offect == 6 : temp = 0x40
  1065. elif offect == 7 : temp = 0x80
  1066. if array[i] : buffer[index] += temp
  1067. return buffer
  1068. @staticmethod
  1069. def HexStringToBytes( hex ):
  1070. '''将hex字符串转化为byte数组'''
  1071. return bytes.fromhex(hex)
  1072. @staticmethod
  1073. def BytesArrayExpandToLengthEven(array):
  1074. '''扩充一个整型的数据长度为偶数个'''
  1075. if len(array) % 2 == 1:
  1076. array.append(0)
  1077. return array
  1078. @staticmethod
  1079. def IsTwoBytesEquel( b1, start1, b2, start2, length ):
  1080. '''判断两个字节的指定部分是否相同'''
  1081. if b1 == None or b2 == None: return False
  1082. for ii in range(length):
  1083. if b1[ii+start1] != b2[ii+start2]: return False
  1084. return True
  1085. @staticmethod
  1086. def TokenToBytes( token ):
  1087. '''将uuid的token值转化成统一的bytes数组,方便和java,C#通讯'''
  1088. buffer = bytearray(token.bytes)
  1089. buffer[0],buffer[1],buffer[2],buffer[3] = buffer[3],buffer[2],buffer[1],buffer[0]
  1090. buffer[4],buffer[5] = buffer[5],buffer[4]
  1091. buffer[6],buffer[7] = buffer[7],buffer[6]
  1092. return buffer
  1093. @staticmethod
  1094. def ArrayExpandToLength( value, length ):
  1095. '''将数组扩充到指定的长度'''
  1096. buffer = bytearray(length)
  1097. if len(value) >= length:
  1098. buffer[0:] = value[0:len(value)]
  1099. else:
  1100. buffer[0:len(value)] = value
  1101. return buffer
  1102. @staticmethod
  1103. def ArrayExpandToLengthEven( value ):
  1104. '''将数组扩充到偶数的长度'''
  1105. if len(value) % 2 == 0:
  1106. return value
  1107. else:
  1108. buffer = bytearray(len(value)+1)
  1109. buffer[0:len(value)] = value
  1110. return value
  1111. @staticmethod
  1112. def StringToUnicodeBytes( value ):
  1113. '''获取字符串的unicode编码字符'''
  1114. if value == None: return bytearray(0)
  1115. buffer = value.encode('utf-16')
  1116. if len(buffer) > 1 and buffer[0] == 255 and buffer[1] == 254:
  1117. buffer = buffer[2:len(buffer)]
  1118. return buffer
  1119. @staticmethod
  1120. def GetUniqueStringByGuidAndRandom():
  1121. '''获取一串唯一的随机字符串,长度为20,由Guid码和4位数的随机数组成,保证字符串的唯一性'''
  1122. return SoftBasic.ByteToHexString(SoftBasic.TokenToBytes(uuid.uuid1()), None) + str(random.randint(12, 20))
  1123. class HslSecurity:
  1124. @staticmethod
  1125. def ByteEncrypt( enBytes ):
  1126. '''加密方法,只对当前的程序集开放'''
  1127. if (enBytes == None) : return None
  1128. result = bytearray(len(enBytes))
  1129. for i in range(len(enBytes)):
  1130. result[i] = enBytes[i] ^ 0xB5
  1131. return result
  1132. @staticmethod
  1133. def ByteDecrypt( deBytes ):
  1134. '''解密方法,只对当前的程序集开放'''
  1135. return HslSecurity.ByteEncrypt(deBytes)
  1136. class SoftZipped:
  1137. '''一个负责压缩解压数据字节的类'''
  1138. @staticmethod
  1139. def CompressBytes( inBytes ):
  1140. '''压缩字节数据'''
  1141. if inBytes == None : return None
  1142. return gzip.compress( inBytes )
  1143. @staticmethod
  1144. def Decompress( inBytes ):
  1145. '''解压字节数据'''
  1146. if inBytes == None : return None
  1147. return gzip.decompress( inBytes )
  1148. class HslProtocol:
  1149. '''用于本程序集访问通信的暗号说明'''
  1150. @staticmethod
  1151. def HeadByteLength():
  1152. '''规定所有的网络传输指令头都为32字节'''
  1153. return 32
  1154. @staticmethod
  1155. def ProtocolBufferSize():
  1156. '''所有网络通信中的缓冲池数据信息'''
  1157. return 1024
  1158. @staticmethod
  1159. def ProtocolCheckSecends():
  1160. '''用于心跳程序的暗号信息'''
  1161. return 1
  1162. @staticmethod
  1163. def ProtocolClientQuit():
  1164. '''客户端退出消息'''
  1165. return 2
  1166. @staticmethod
  1167. def ProtocolClientRefuseLogin():
  1168. '''因为客户端达到上限而拒绝登录'''
  1169. return 3
  1170. @staticmethod
  1171. def ProtocolClientAllowLogin():
  1172. return 4
  1173. @staticmethod
  1174. def ProtocolUserString():
  1175. '''说明发送的只是文本信息'''
  1176. return 1001
  1177. @staticmethod
  1178. def ProtocolUserBytes():
  1179. '''发送的数据就是普通的字节数组'''
  1180. return 1002
  1181. @staticmethod
  1182. def ProtocolUserBitmap():
  1183. '''发送的数据就是普通的图片数据'''
  1184. return 1003
  1185. @staticmethod
  1186. def ProtocolUserException():
  1187. '''发送的数据是一条异常的数据,字符串为异常消息'''
  1188. return 1004
  1189. @staticmethod
  1190. def ProtocolFileDownload():
  1191. '''请求文件下载的暗号'''
  1192. return 2001
  1193. @staticmethod
  1194. def ProtocolFileUpload():
  1195. '''请求文件上传的暗号'''
  1196. return 2002
  1197. @staticmethod
  1198. def ProtocolFileDelete():
  1199. '''请求删除文件的暗号'''
  1200. return 2003
  1201. @staticmethod
  1202. def ProtocolFileCheckRight():
  1203. '''文件校验成功'''
  1204. return 2004
  1205. @staticmethod
  1206. def ProtocolFileCheckError():
  1207. '''文件校验失败'''
  1208. return 2005
  1209. @staticmethod
  1210. def ProtocolFileSaveError():
  1211. '''文件保存失败'''
  1212. return 2006
  1213. @staticmethod
  1214. def ProtocolFileDirectoryFiles():
  1215. '''请求文件列表的暗号'''
  1216. return 2007
  1217. @staticmethod
  1218. def ProtocolFileDirectories():
  1219. '''请求子文件的列表暗号'''
  1220. return 2008
  1221. @staticmethod
  1222. def ProtocolProgressReport():
  1223. '''进度返回暗号'''
  1224. return 2009
  1225. @staticmethod
  1226. def ProtocolNoZipped():
  1227. '''不压缩数据字节'''
  1228. return 3001
  1229. @staticmethod
  1230. def ProtocolZipped():
  1231. '''压缩数据字节'''
  1232. return 3002
  1233. @staticmethod
  1234. def CommandBytesBase( command, customer, token, data ):
  1235. '''生成终极传送指令的方法,所有的数据均通过该方法出来'''
  1236. _zipped = HslProtocol.ProtocolNoZipped()
  1237. buffer = None
  1238. _sendLength = 0
  1239. if data == None:
  1240. buffer = bytearray(HslProtocol.HeadByteLength())
  1241. else:
  1242. data = HslSecurity.ByteEncrypt( data )
  1243. if len(data) > 102400:
  1244. data = SoftZipped.CompressBytes( data )
  1245. _zipped = HslProtocol.ProtocolZipped()
  1246. buffer = bytearray( HslProtocol.HeadByteLength() + len(data) )
  1247. _sendLength = len(data)
  1248. buffer[0:4] = struct.pack( '<i', command )
  1249. buffer[4:8] = struct.pack( '<i', customer )
  1250. buffer[8:12] = struct.pack( '<i', _zipped)
  1251. buffer[12:28] = SoftBasic.TokenToBytes(token)
  1252. buffer[28:32] = struct.pack( '<i', _sendLength)
  1253. if _sendLength>0:
  1254. buffer[32:_sendLength+32]=data
  1255. return buffer
  1256. @staticmethod
  1257. def CommandAnalysis( head, content ):
  1258. '''解析接收到数据,先解压缩后进行解密'''
  1259. if content != None:
  1260. _zipped = struct.unpack('<i', head[8:12])[0]
  1261. if _zipped == HslProtocol.ProtocolZipped():
  1262. content = SoftZipped.Decompress( content )
  1263. return HslSecurity.ByteEncrypt(content)
  1264. return bytearray(0)
  1265. @staticmethod
  1266. def CommandBytes( customer, token, data ):
  1267. '''获取发送字节数据的实际数据,带指令头'''
  1268. return HslProtocol.CommandBytesBase( HslProtocol.ProtocolUserBytes(), customer, token, data )
  1269. @staticmethod
  1270. def CommandString( customer, token, data ):
  1271. '''获取发送字节数据的实际数据,带指令头'''
  1272. if data == None:
  1273. return HslProtocol.CommandBytesBase( HslProtocol.ProtocolUserString(), customer, token, None )
  1274. else:
  1275. buffer = SoftBasic.StringToUnicodeBytes(data)
  1276. return HslProtocol.CommandBytesBase( HslProtocol.ProtocolUserString(), customer, token, buffer )
  1277. class NetworkBase:
  1278. '''网络基础类的核心'''
  1279. Token = uuid.UUID('{00000000-0000-0000-0000-000000000000}')
  1280. CoreSocket = socket.socket()
  1281. def Receive(self,socket,length):
  1282. '''接收固定长度的字节数组'''
  1283. totle = 0
  1284. data = bytearray()
  1285. try:
  1286. while totle < length:
  1287. data.extend(socket.recv(length-totle))
  1288. totle += len(data)
  1289. return OperateResult.CreateSuccessResult(data)
  1290. except Exception as e:
  1291. result = OperateResult()
  1292. result.Message = str(e)
  1293. return result
  1294. def Send(self,socket,data):
  1295. '''发送消息给套接字,直到完成的时候返回'''
  1296. try:
  1297. socket.send(data)
  1298. return OperateResult.CreateSuccessResult()
  1299. except Exception as e:
  1300. return OperateResult( msg = str(e))
  1301. def CreateSocketAndConnect(self,ipAddress,port,timeout = 10000):
  1302. '''创建一个新的socket对象并连接到远程的地址,默认超时时间为10秒钟'''
  1303. try:
  1304. socketTmp = socket.socket()
  1305. socketTmp.connect((ipAddress,port))
  1306. return OperateResult.CreateSuccessResult(socketTmp)
  1307. except Exception as e:
  1308. return OperateResult( msg = str(e))
  1309. def ReceiveMessage( self, socket, timeOut, netMsg ):
  1310. '''接收一条完整的数据,使用异步接收完成,包含了指令头信息'''
  1311. result = OperateResult()
  1312. headResult = self.Receive( socket, netMsg.ProtocolHeadBytesLength() )
  1313. if headResult.IsSuccess == False:
  1314. result.CopyErrorFromOther(headResult)
  1315. return result
  1316. netMsg.HeadBytes = headResult.Content
  1317. if netMsg.CheckHeadBytesLegal( SoftBasic.TokenToBytes(self.Token) ) == False:
  1318. # 令牌校验失败
  1319. if socket != None: socket.close()
  1320. result.Message = StringResources.TokenCheckFailed()
  1321. return result
  1322. contentLength = netMsg.GetContentLengthByHeadBytes( )
  1323. if contentLength == 0:
  1324. netMsg.ContentBytes = bytearray(0)
  1325. else:
  1326. contentResult = self.Receive( socket, contentLength )
  1327. if contentResult.IsSuccess == False:
  1328. result.CopyErrorFromOther( contentResult )
  1329. return result
  1330. netMsg.ContentBytes = contentResult.Content
  1331. if netMsg.ContentBytes == None: netMsg.ContentBytes = bytearray(0)
  1332. result.Content = netMsg
  1333. result.IsSuccess = True
  1334. return result
  1335. class NetworkDoubleBase(NetworkBase):
  1336. '''支持长连接,短连接两个模式的通用客户端基类'''
  1337. byteTransform = ByteTransform()
  1338. ipAddress = "127.0.0.1"
  1339. port = 10000
  1340. isPersistentConn = False
  1341. isSocketError = False
  1342. receiveTimeOut = 10000
  1343. isUseSpecifiedSocket = False
  1344. interactiveLock = threading.Lock()
  1345. iNetMessage = INetMessage()
  1346. def SetPersistentConnection( self ):
  1347. '''在读取数据之前可以调用本方法将客户端设置为长连接模式,相当于跳过了ConnectServer的结果验证,对异形客户端无效'''
  1348. self.isPersistentConn = True
  1349. def ConnectServer( self ):
  1350. '''切换短连接模式到长连接模式,后面的每次请求都共享一个通道'''
  1351. self.isPersistentConn = True
  1352. result = OperateResult( )
  1353. # 重新连接之前,先将旧的数据进行清空
  1354. if self.CoreSocket != None:
  1355. self.CoreSocket.close()
  1356. rSocket = self.CreateSocketAndInitialication( )
  1357. if rSocket.IsSuccess == False:
  1358. self.isSocketError = True
  1359. rSocket.Content = None
  1360. result.Message = rSocket.Message
  1361. else:
  1362. self.CoreSocket = rSocket.Content
  1363. result.IsSuccess = True
  1364. return result
  1365. def ConnectClose( self ):
  1366. '''在长连接模式下,断开服务器的连接,并切换到短连接模式'''
  1367. result = OperateResult( )
  1368. self.isPersistentConn = False
  1369. self.interactiveLock.acquire()
  1370. # 额外操作
  1371. result = self.ExtraOnDisconnect( self.CoreSocket )
  1372. # 关闭信息
  1373. if self.CoreSocket != None : self.CoreSocket.close()
  1374. self.CoreSocket = None
  1375. self.interactiveLock.release( )
  1376. return result
  1377. # 初始化的信息方法和连接结束的信息方法,需要在继承类里面进行重新实现
  1378. def InitializationOnConnect( self, socket ):
  1379. '''连接上服务器后需要进行的初始化操作'''
  1380. return OperateResult.CreateSuccessResult()
  1381. def ExtraOnDisconnect( self, socket ):
  1382. '''在将要和服务器进行断开的情况下额外的操作,需要根据对应协议进行重写'''
  1383. return OperateResult.CreateSuccessResult()
  1384. def GetAvailableSocket( self ):
  1385. '''获取本次操作的可用的网络套接字'''
  1386. if self.isPersistentConn :
  1387. # 如果是异形模式
  1388. if self.isUseSpecifiedSocket :
  1389. if self.isSocketError:
  1390. return OperateResult( msg = '连接不可用' )
  1391. else:
  1392. return OperateResult.CreateSuccessResult( self.CoreSocket )
  1393. else:
  1394. # 长连接模式
  1395. if self.isSocketError or self.CoreSocket == None :
  1396. connect = self.ConnectServer( )
  1397. if connect.IsSuccess == False:
  1398. self.isSocketError = True
  1399. return OperateResult( msg = connect.Message )
  1400. else:
  1401. self.isSocketError = False
  1402. return OperateResult.CreateSuccessResult( self.CoreSocket )
  1403. else:
  1404. return OperateResult.CreateSuccessResult( self.CoreSocket )
  1405. else:
  1406. # 短连接模式
  1407. return self.CreateSocketAndInitialication( )
  1408. def CreateSocketAndInitialication( self ):
  1409. '''连接并初始化网络套接字'''
  1410. result = self.CreateSocketAndConnect( self.ipAddress, self.port, 10000 )
  1411. if result.IsSuccess:
  1412. # 初始化
  1413. initi = self.InitializationOnConnect( result.Content )
  1414. if initi.IsSuccess == False:
  1415. if result.Content !=None : result.Content.close( )
  1416. result.IsSuccess = initi.IsSuccess
  1417. result.CopyErrorFromOther( initi )
  1418. return result
  1419. def ReadFromCoreSocketServer( self, socket, send ):
  1420. '''在其他指定的套接字上,使用报文来通讯,传入需要发送的消息,返回一条完整的数据指令'''
  1421. read = self.ReadFromCoreServerBase( socket, send )
  1422. if read.IsSuccess == False: return OperateResult.CreateFailedResult( read )
  1423. # 拼接结果数据
  1424. Content = bytearray(len(read.Content1) + len(read.Content2))
  1425. if len(read.Content1) > 0 :
  1426. Content[0:len(read.Content1)] = read.Content1
  1427. if len(read.Content2) > 0 :
  1428. Content[len(read.Content1):len(Content)] = read.Content2
  1429. return OperateResult.CreateSuccessResult( Content )
  1430. def ReadFromCoreServer( self, send ):
  1431. '''使用底层的数据报文来通讯,传入需要发送的消息,返回一条完整的数据指令'''
  1432. result = OperateResult( )
  1433. self.interactiveLock.acquire()
  1434. # 获取有用的网络通道,如果没有,就建立新的连接
  1435. resultSocket = self.GetAvailableSocket( )
  1436. if resultSocket.IsSuccess == False:
  1437. self.isSocketError = True
  1438. self.interactiveLock.release()
  1439. result.CopyErrorFromOther( resultSocket )
  1440. return result
  1441. read = self.ReadFromCoreSocketServer( resultSocket.Content, send )
  1442. if read.IsSuccess :
  1443. self.isSocketError = False
  1444. result.IsSuccess = read.IsSuccess
  1445. result.Content = read.Content
  1446. result.Message = StringResources.SuccessText
  1447. # string tmp2 = BasicFramework.SoftBasic.ByteToHexString( result.Content, '-' )
  1448. else:
  1449. self.isSocketError = True
  1450. result.CopyErrorFromOther( read )
  1451. self.interactiveLock.release()
  1452. if self.isPersistentConn==False:
  1453. if resultSocket.Content != None:
  1454. resultSocket.Content.close()
  1455. return result
  1456. def ReadFromCoreServerBase( self, socket, send ):
  1457. '''使用底层的数据报文来通讯,传入需要发送的消息,返回最终的数据结果,被拆分成了头子节和内容字节信息'''
  1458. self.iNetMessage.SendBytes = send
  1459. sendResult = self.Send( socket, send )
  1460. if sendResult.IsSuccess == False:
  1461. if socket!= None : socket.close( )
  1462. return OperateResult.CreateFailedResult( sendResult )
  1463. # 接收超时时间大于0时才允许接收远程的数据
  1464. if (self.receiveTimeOut >= 0):
  1465. # 接收数据信息
  1466. resultReceive = self.ReceiveMessage(socket, 10000, self.iNetMessage)
  1467. if resultReceive.IsSuccess == False:
  1468. socket.close( )
  1469. return OperateResult( msg = "Receive data timeout: " + str(self.receiveTimeOut ) + " Msg:"+ resultReceive.Message)
  1470. return OperateResult.CreateSuccessResult( resultReceive.Content.HeadBytes, resultReceive.Content.ContentBytes )
  1471. else:
  1472. return OperateResult.CreateSuccessResult( bytearray(0), bytearray(0) )
  1473. def GetBoolResultFromBytes( self, result ):
  1474. '''将指定的OperateResult类型转化'''
  1475. return ByteTransformHelper.GetBoolResultFromBytes( result, self.byteTransform)
  1476. def GetByteResultFromBytes( self, result ):
  1477. '''将指定的OperateResult类型转化'''
  1478. return ByteTransformHelper.GetByteResultFromBytes( result, self.byteTransform)
  1479. def GetInt16ResultFromBytes( self, result ):
  1480. '''将指定的OperateResult类型转化'''
  1481. return ByteTransformHelper.GetInt16ResultFromBytes( result, self.byteTransform)
  1482. def GetUInt16ResultFromBytes( self, result ):
  1483. '''将指定的OperateResult类型转化'''
  1484. return ByteTransformHelper.GetUInt16ResultFromBytes( result, self.byteTransform)
  1485. def GetInt32ResultFromBytes( self, result ):
  1486. '''将指定的OperateResult类型转化'''
  1487. return ByteTransformHelper.GetInt32ResultFromBytes( result, self.byteTransform )
  1488. def GetUInt32ResultFromBytes( self, result ):
  1489. '''将指定的OperateResult类型转化'''
  1490. return ByteTransformHelper.GetUInt32ResultFromBytes( result, self.byteTransform )
  1491. def GetInt64ResultFromBytes( self, result ):
  1492. '''将指定的OperateResult类型转化'''
  1493. return ByteTransformHelper.GetInt64ResultFromBytes( result, self.byteTransform )
  1494. def GetUInt64ResultFromBytes( self, result ):
  1495. '''将指定的OperateResult类型转化'''
  1496. return ByteTransformHelper.GetUInt64ResultFromBytes( result, self.byteTransform )
  1497. def GetSingleResultFromBytes( self, result ):
  1498. '''将指定的OperateResult类型转化'''
  1499. return ByteTransformHelper.GetSingleResultFromBytes( result, self.byteTransform )
  1500. def GetDoubleResultFromBytes( self, result ):
  1501. '''将指定的OperateResult类型转化'''
  1502. return ByteTransformHelper.GetDoubleResultFromBytes( result, self.byteTransform )
  1503. def GetStringResultFromBytes( self, result ):
  1504. '''将指定的OperateResult类型转化'''
  1505. return ByteTransformHelper.GetStringResultFromBytes( result, self.byteTransform )
  1506. class NetworkDeviceBase(NetworkDoubleBase):
  1507. '''设备类的基类,提供了基础的字节读写方法'''
  1508. # 单个数据字节的长度,西门子为2,三菱,欧姆龙,modbusTcp就为1
  1509. WordLength = 1
  1510. def Read( self, address, length ):
  1511. '''从设备读取原始数据'''
  1512. return OperateResult( )
  1513. def Write( self, address, value ):
  1514. '''将原始数据写入设备'''
  1515. return OperateResult()
  1516. def ReadInt16( self, address, length = None ):
  1517. '''读取设备的short类型的数据'''
  1518. if(length == None):
  1519. return self.GetInt16ResultFromBytes( self.Read( address, self.WordLength ) )
  1520. else:
  1521. read = self.Read(address,length*self.WordLength)
  1522. if read.IsSuccess == False:
  1523. return OperateResult.CreateFailedResult(read)
  1524. return OperateResult.CreateSuccessResult(self.byteTransform.TransInt16Array(read.Content,0,length))
  1525. def ReadUInt16( self, address, length = None ):
  1526. '''读取设备的ushort数据类型的数据'''
  1527. if length == None:
  1528. return self.GetUInt16ResultFromBytes(self.Read(address,self.WordLength))
  1529. else:
  1530. read = self.Read(address,length*self.WordLength)
  1531. if read.IsSuccess == False:
  1532. return OperateResult.CreateFailedResult(read)
  1533. return OperateResult.CreateSuccessResult(self.byteTransform.TransUInt16Array(read.Content,0,length))
  1534. def ReadInt32( self, address, length = None ):
  1535. '''读取设备的int类型的数据'''
  1536. if length == None:
  1537. return self.GetInt32ResultFromBytes( self.Read( address, 2 * self.WordLength ) )
  1538. else:
  1539. read = self.Read(address,2*length*self.WordLength)
  1540. if read.IsSuccess == False:
  1541. return OperateResult.CreateFailedResult(read)
  1542. return OperateResult.CreateSuccessResult(self.byteTransform.TransInt32Array(read.Content,0,length))
  1543. def ReadUInt32( self, address, length = None ):
  1544. '''读取设备的uint数据类型的数据'''
  1545. if length == None:
  1546. return self.GetUInt32ResultFromBytes(self.Read(address,2 * self.WordLength))
  1547. else:
  1548. read = self.Read(address,2*length*self.WordLength)
  1549. if read.IsSuccess == False:
  1550. return OperateResult.CreateFailedResult(read)
  1551. return OperateResult.CreateSuccessResult(self.byteTransform.TransUInt32Array(read.Content,0,length))
  1552. def ReadFloat( self, address, length = None ):
  1553. '''读取设备的float类型的数据'''
  1554. if length == None:
  1555. return self.GetSingleResultFromBytes( self.Read( address, 2 * self.WordLength ) )
  1556. else:
  1557. read = self.Read(address,2*length*self.WordLength)
  1558. if read.IsSuccess == False:
  1559. return OperateResult.CreateFailedResult(read)
  1560. return OperateResult.CreateSuccessResult(self.byteTransform.TransSingleArray(read.Content,0,length))
  1561. def ReadInt64( self, address, length = None ):
  1562. '''读取设备的long类型的数组'''
  1563. if length == None:
  1564. return self.GetInt64ResultFromBytes( self.Read( address, 4 * self.WordLength) )
  1565. else:
  1566. read = self.Read(address,4*length*self.WordLength)
  1567. if read.IsSuccess == False:
  1568. return OperateResult.CreateFailedResult(read)
  1569. return OperateResult.CreateSuccessResult(self.byteTransform.TransInt64Array(read.Content,0,length))
  1570. def ReadUInt64( self, address, length = None ):
  1571. '''读取设备的long类型的数组'''
  1572. if length == None:
  1573. return self.GetUInt64ResultFromBytes( self.Read( address, 4 * self.WordLength) )
  1574. else:
  1575. read = self.Read(address,4*length*self.WordLength)
  1576. if read.IsSuccess == False:
  1577. return OperateResult.CreateFailedResult(read)
  1578. return OperateResult.CreateSuccessResult(self.byteTransform.TransUInt64Array(read.Content,0,length))
  1579. def ReadDouble( self, address, length = None ):
  1580. '''读取设备的long类型的数组'''
  1581. if length == None:
  1582. return self.GetDoubleResultFromBytes( self.Read( address, 4 * self.WordLength) )
  1583. else:
  1584. read = self.Read(address,4*length*self.WordLength)
  1585. if read.IsSuccess == False:
  1586. return OperateResult.CreateFailedResult(read)
  1587. return OperateResult.CreateSuccessResult(self.byteTransform.TransDoubleArray(read.Content,0,length))
  1588. def ReadString( self, address, length ):
  1589. return self.GetStringResultFromBytes( self.Read( address, length ) )
  1590. def WriteInt16( self, address, value ):
  1591. '''向设备中写入short数据或是数组,返回是否写入成功'''
  1592. if type(value) == list:
  1593. return self.Write( address, self.byteTransform.Int16ArrayTransByte( value ) )
  1594. else:
  1595. return self.WriteInt16( address, [value] )
  1596. def WriteUInt16( self, address, value ):
  1597. '''向设备中写入short数据或是数组,返回是否写入成功'''
  1598. if type(value) == list:
  1599. return self.Write( address, self.byteTransform.UInt16ArrayTransByte( value ) )
  1600. else:
  1601. return self.WriteUInt16( address, [value] )
  1602. def WriteInt32( self, address, value ):
  1603. '''向设备中写入int数据,返回是否写入成功'''
  1604. if type(value) == list:
  1605. return self.Write( address, self.byteTransform.Int32ArrayTransByte(value) )
  1606. else:
  1607. return self.WriteInt32( address, [value])
  1608. def WriteUInt32( self, address, value):
  1609. '''向设备中写入uint数据,返回是否写入成功'''
  1610. if type(value) == list:
  1611. return self.Write( address, self.byteTransform.UInt32ArrayTransByte(value) )
  1612. else:
  1613. return self.WriteUInt32( address, [value] )
  1614. def WriteFloat( self, address, value ):
  1615. '''向设备中写入float数据,返回是否写入成功'''
  1616. if type(value) == list:
  1617. return self.Write( address, self.byteTransform.FloatArrayTransByte(value) )
  1618. else:
  1619. return self.WriteFloat(address, [value])
  1620. def WriteInt64( self, address, value ):
  1621. '''向设备中写入long数据,返回是否写入成功'''
  1622. if type(value) == list:
  1623. return self.Write( address, self.byteTransform.Int64ArrayTransByte(value))
  1624. else:
  1625. return self.WriteInt64( address, [value] )
  1626. def WriteUInt64( self, address, value ):
  1627. '''向设备中写入ulong数据,返回是否写入成功'''
  1628. if type(value) == list:
  1629. return self.Write( address, self.byteTransform.UInt64ArrayTransByte(value))
  1630. else:
  1631. return self.WriteUInt64( address, [value] )
  1632. def WriteDouble( self, address, value ):
  1633. '''向设备中写入double数据,返回是否写入成功'''
  1634. if type(value) == list:
  1635. return self.Write( address, self.byteTransform.DoubleArrayTransByte(value) )
  1636. else:
  1637. return self.WriteDouble( address, [value] )
  1638. def WriteString( self, address, value, length = None ):
  1639. '''向设备中写入string数据,编码为ascii,返回是否写入成功'''
  1640. if length == None:
  1641. return self.Write( address, self.byteTransform.StringTransByte( value, 'ascii' ) )
  1642. else:
  1643. return self.Write( address, SoftBasic.ArrayExpandToLength(self.byteTransform.StringTransByte( value, 'ascii' ), length))
  1644. def WriteUnicodeString( self, address, value, length = None):
  1645. '''向设备中写入string数据,编码为unicode,返回是否写入成功'''
  1646. if length == None:
  1647. temp = SoftBasic.StringToUnicodeBytes(value)
  1648. return self.Write( address, temp )
  1649. else:
  1650. temp = SoftBasic.StringToUnicodeBytes(value)
  1651. temp = SoftBasic.ArrayExpandToLength( temp, length * 2 )
  1652. return self.Write( address, temp )
  1653. class ModbusInfo:
  1654. '''Modbus协议相关的一些信息'''
  1655. @staticmethod
  1656. def ReadCoil():
  1657. '''读取线圈功能码'''
  1658. return 0x01
  1659. @staticmethod
  1660. def ReadDiscrete():
  1661. '''读取寄存器功能码'''
  1662. return 0x02
  1663. @staticmethod
  1664. def ReadRegister():
  1665. '''读取寄存器功能码'''
  1666. return 0x03
  1667. @staticmethod
  1668. def ReadInputRegister():
  1669. '''读取输入寄存器'''
  1670. return 0x04
  1671. @staticmethod
  1672. def WriteOneCoil():
  1673. '''写单个寄存器'''
  1674. return 0x05
  1675. @staticmethod
  1676. def WriteOneRegister():
  1677. '''写单个寄存器'''
  1678. return 0x06
  1679. @staticmethod
  1680. def WriteCoil():
  1681. '''写多个线圈'''
  1682. return 0x0F
  1683. @staticmethod
  1684. def WriteRegister():
  1685. '''写多个寄存器'''
  1686. return 0x10
  1687. @staticmethod
  1688. def FunctionCodeNotSupport():
  1689. '''不支持该功能码'''
  1690. return 0x01
  1691. @staticmethod
  1692. def FunctionCodeOverBound():
  1693. '''该地址越界'''
  1694. return 0x02
  1695. @staticmethod
  1696. def FunctionCodeQuantityOver():
  1697. '''读取长度超过最大值'''
  1698. return 0x03
  1699. @staticmethod
  1700. def FunctionCodeReadWriteException():
  1701. '''读写异常'''
  1702. return 0x04
  1703. @staticmethod
  1704. def PackCommandToTcp( value, id ):
  1705. '''将modbus指令打包成Modbus-Tcp指令'''
  1706. buffer = bytearray( len(value) + 6)
  1707. buffer[0:2] = struct.pack('>H',id)
  1708. buffer[4:6] = struct.pack('>H',len(value))
  1709. buffer[6:len(buffer)] = value
  1710. return buffer
  1711. @staticmethod
  1712. def GetDescriptionByErrorCode( code ):
  1713. '''通过错误码来获取到对应的文本消息'''
  1714. if code == 0x01: return StringResources.ModbusTcpFunctionCodeNotSupport()
  1715. elif code == 0x02: return StringResources.ModbusTcpFunctionCodeOverBound()
  1716. elif code == 0x03: return StringResources.ModbusTcpFunctionCodeQuantityOver()
  1717. elif code == 0x04: return StringResources.ModbusTcpFunctionCodeReadWriteException()
  1718. else: return StringResources.UnknownError
  1719. @staticmethod
  1720. def AnalysisReadAddress( address, isStartWithZero ):
  1721. '''分析Modbus协议的地址信息,该地址适应于tcp及rtu模式'''
  1722. try:
  1723. mAddress = ModbusAddress(address)
  1724. if isStartWithZero == False:
  1725. if mAddress.Address < 1:
  1726. raise RuntimeError(StringResources.ModbusAddressMustMoreThanOne())
  1727. else:
  1728. mAddress.Address = mAddress.Address - 1
  1729. return OperateResult.CreateSuccessResult(mAddress)
  1730. except Exception as ex:
  1731. return OperateResult( msg = str(ex))
  1732. class ModbusAddress(DeviceAddressBase):
  1733. '''Modbus协议的地址类'''
  1734. Station = 0
  1735. Function = ModbusInfo.ReadRegister()
  1736. def __init__(self, address = "0"):
  1737. self.Station = -1
  1738. self.Function = ModbusInfo.ReadRegister()
  1739. self.Address = 0
  1740. self.AnalysisAddress(address)
  1741. def AnalysisAddress( self, address = "0" ):
  1742. '''解析Modbus的地址码'''
  1743. if address.find(';')>=0:
  1744. listAddress = address.split(";")
  1745. for index in range(len(listAddress)):
  1746. if listAddress[index][0] == 's' or listAddress[index][0] == 'S':
  1747. self.Station = int(listAddress[index][2:])
  1748. elif listAddress[index][0] == 'x' or listAddress[index][0] == 'X':
  1749. self.Function = int(listAddress[index][2:])
  1750. else:
  1751. self.Address = int(listAddress[index])
  1752. else:
  1753. self.Address = int(address)
  1754. def CreateReadCoils( self, station, length ):
  1755. '''创建一个读取线圈的字节对象'''
  1756. buffer = bytearray(6)
  1757. if self.Station < 0 :
  1758. buffer[0] = station
  1759. else:
  1760. buffer[0] = self.Station
  1761. buffer[1] = ModbusInfo.ReadCoil()
  1762. buffer[2:4] = struct.pack('>H', self.Address)
  1763. buffer[4:6] = struct.pack('>H', length)
  1764. return buffer
  1765. def CreateReadDiscrete( self, station, length ):
  1766. '''创建一个读取离散输入的字节对象'''
  1767. buffer = bytearray(6)
  1768. if self.Station < 0 :
  1769. buffer[0] = station
  1770. else:
  1771. buffer[0] = self.Station
  1772. buffer[1] = ModbusInfo.ReadDiscrete()
  1773. buffer[2:4] = struct.pack('>H', self.Address)
  1774. buffer[4:6] = struct.pack('>H', length)
  1775. return buffer
  1776. def CreateReadRegister( self, station, length ):
  1777. '''创建一个读取寄存器的字节对象'''
  1778. buffer = bytearray(6)
  1779. if self.Station < 0 :
  1780. buffer[0] = station
  1781. else:
  1782. buffer[0] = self.Station
  1783. buffer[1] = self.Function
  1784. buffer[2:4] = struct.pack('>H', self.Address)
  1785. buffer[4:6] = struct.pack('>H', length)
  1786. return buffer
  1787. def CreateReadInputRegister( self, station, length ):
  1788. '''创建一个读取寄存器的字节对象'''
  1789. buffer = bytearray(6)
  1790. if self.Station < 0 :
  1791. buffer[0] = station
  1792. else:
  1793. buffer[0] = self.Station
  1794. buffer[1] = ModbusInfo.ReadInputRegister()
  1795. buffer[2:4] = struct.pack('>H', self.Address)
  1796. buffer[4:6] = struct.pack('>H', length)
  1797. return buffer
  1798. def CreateWriteOneCoil(self, station, value):
  1799. '''创建一个写入单个线圈的指令'''
  1800. buffer = bytearray(6)
  1801. if self.Station < 0 :
  1802. buffer[0] = station
  1803. else:
  1804. buffer[0] = self.Station
  1805. buffer[1] = ModbusInfo.WriteOneCoil()
  1806. buffer[2:4] = struct.pack('>H', self.Address)
  1807. if value == True:
  1808. buffer[4] = 0xFF
  1809. return buffer
  1810. def CreateWriteOneRegister(self, station, values):
  1811. '''创建一个写入单个寄存器的指令'''
  1812. buffer = bytearray(6)
  1813. if self.Station < 0 :
  1814. buffer[0] = station
  1815. else:
  1816. buffer[0] = self.Station
  1817. buffer[1] = ModbusInfo.WriteOneRegister()
  1818. buffer[2:4] = struct.pack('>H', self.Address)
  1819. buffer[4:6] = values
  1820. return buffer
  1821. def CreateWriteCoil(self, station, values):
  1822. '''创建一个写入批量线圈的指令'''
  1823. data = SoftBasic.BoolArrayToByte( values )
  1824. buffer = bytearray(7 + len(data))
  1825. if self.Station < 0 :
  1826. buffer[0] = station
  1827. else:
  1828. buffer[0] = self.Station
  1829. buffer[1] = ModbusInfo.WriteCoil()
  1830. buffer[2:4] = struct.pack('>H', self.Address)
  1831. buffer[4:6] = struct.pack('>H', len(values))
  1832. buffer[6] = len(data)
  1833. buffer[7:len(buffer)] = data
  1834. return buffer
  1835. def CreateWriteRegister(self, station, values):
  1836. '''创建一个写入批量寄存器的指令'''
  1837. buffer = bytearray(7 + len(values))
  1838. if self.Station < 0 :
  1839. buffer[0] = station
  1840. else:
  1841. buffer[0] = self.Station
  1842. buffer[1] = ModbusInfo.WriteRegister()
  1843. buffer[2:4] = struct.pack('>H', self.Address)
  1844. buffer[4:6] = struct.pack('>H', len(values)//2)
  1845. buffer[6] = len(values)
  1846. buffer[7:len(buffer)] = values
  1847. return buffer
  1848. def AddressAdd(self, value):
  1849. '''地址新增指定的数'''
  1850. modbusAddress = ModbusAddress()
  1851. modbusAddress.Station = self.Station
  1852. modbusAddress.Function = self.Function
  1853. modbusAddress.Address = self.Address+value
  1854. return modbusAddress
  1855. class ModbusTcpNet(NetworkDeviceBase):
  1856. '''Modbus-Tcp协议的客户端通讯类,方便的和服务器进行数据交互'''
  1857. station = 1
  1858. softIncrementCount = None
  1859. isAddressStartWithZero = True
  1860. def __init__(self, ipAddress = '127.0.0.1', port = 502, station = 1):
  1861. '''实例化一个MOdbus-Tcp协议的客户端对象'''
  1862. self.WordLength = 1
  1863. self.softIncrementCount = SoftIncrementCount( 65536, 0 )
  1864. self.station = station
  1865. self.ipAddress = ipAddress
  1866. self.port = port
  1867. self.byteTransform = ReverseWordTransform()
  1868. self.iNetMessage = ModbusTcpMessage()
  1869. def SetDataFormat( self, value ):
  1870. '''多字节的数据是否高低位反转,该设置的改变会影响Int32,UInt32,float,double,Int64,UInt64类型的读写'''
  1871. self.byteTransform.DataFormat = value
  1872. def GetDataFormat( self ):
  1873. '''多字节的数据是否高低位反转,该设置的改变会影响Int32,UInt32,float,double,Int64,UInt64类型的读写'''
  1874. return self.byteTransform.DataFormat
  1875. def SetIsStringReverse( self, value ):
  1876. '''字符串数据是否按照字来反转'''
  1877. self.byteTransform.IsStringReverse = value
  1878. def GetIsStringReverse( self ):
  1879. '''字符串数据是否按照字来反转'''
  1880. return self.byteTransform.IsStringReverse
  1881. def BuildReadCoilCommand(self, address, length):
  1882. '''生成一个读取线圈的指令头'''
  1883. # 分析地址
  1884. analysis = ModbusInfo.AnalysisReadAddress( address, self.isAddressStartWithZero )
  1885. if analysis.IsSuccess == False: return OperateResult.CreateFailedResult(analysis)
  1886. # 获取消息号
  1887. messageId = self.softIncrementCount.GetCurrentValue()
  1888. #生成最终的指令
  1889. buffer = ModbusInfo.PackCommandToTcp(analysis.Content.CreateReadCoils( self.station, length ), messageId)
  1890. return OperateResult.CreateSuccessResult(buffer)
  1891. def BuildReadDiscreteCommand(self, address, length):
  1892. '''生成一个读取离散信息的指令头'''
  1893. # 分析地址
  1894. analysis = ModbusInfo.AnalysisReadAddress( address, self.isAddressStartWithZero )
  1895. if analysis.IsSuccess == False: return OperateResult.CreateFailedResult(analysis)
  1896. # 获取消息号
  1897. messageId = self.softIncrementCount.GetCurrentValue()
  1898. buffer = ModbusInfo.PackCommandToTcp(analysis.Content.CreateReadDiscrete(self.station,length), messageId)
  1899. return OperateResult.CreateSuccessResult(buffer)
  1900. def BuildReadRegisterCommand(self, address, length):
  1901. '''创建一个读取寄存器的字节对象'''
  1902. analysis = ModbusInfo.AnalysisReadAddress( address, self.isAddressStartWithZero )
  1903. if analysis.IsSuccess == False: return OperateResult.CreateFailedResult(analysis)
  1904. # 获取消息号
  1905. messageId = self.softIncrementCount.GetCurrentValue()
  1906. buffer = ModbusInfo.PackCommandToTcp(analysis.Content.CreateReadRegister(self.station,length), messageId)
  1907. return OperateResult.CreateSuccessResult(buffer)
  1908. def BuildReadInputRegisterCommand(self, address, length):
  1909. '''创建一个读取寄存器的字节对象'''
  1910. analysis = ModbusInfo.AnalysisReadAddress( address, self.isAddressStartWithZero )
  1911. if analysis.IsSuccess == False: return OperateResult.CreateFailedResult(analysis)
  1912. # 获取消息号
  1913. messageId = self.softIncrementCount.GetCurrentValue()
  1914. buffer = ModbusInfo.PackCommandToTcp(analysis.Content.CreateReadInputRegister(self.station,length), messageId)
  1915. return OperateResult.CreateSuccessResult(buffer)
  1916. def BuildWriteOneCoilCommand(self, address,value):
  1917. '''生成一个写入单线圈的指令头'''
  1918. analysis = ModbusInfo.AnalysisReadAddress( address, self.isAddressStartWithZero )
  1919. if analysis.IsSuccess == False: return OperateResult.CreateFailedResult(analysis)
  1920. # 获取消息号
  1921. messageId = self.softIncrementCount.GetCurrentValue()
  1922. buffer = ModbusInfo.PackCommandToTcp(analysis.Content.CreateWriteOneCoil(self.station,value), messageId)
  1923. return OperateResult.CreateSuccessResult(buffer)
  1924. def BuildWriteOneRegisterCommand(self, address, values):
  1925. '''生成一个写入单个寄存器的报文'''
  1926. analysis = ModbusInfo.AnalysisReadAddress( address, self.isAddressStartWithZero )
  1927. if analysis.IsSuccess == False: return OperateResult.CreateFailedResult(analysis)
  1928. # 获取消息号
  1929. messageId = self.softIncrementCount.GetCurrentValue()
  1930. buffer = ModbusInfo.PackCommandToTcp(analysis.Content.CreateWriteOneRegister(self.station,values), messageId)
  1931. return OperateResult.CreateSuccessResult(buffer)
  1932. def BuildWriteCoilCommand(self, address, values):
  1933. '''生成批量写入单个线圈的报文信息,需要传入bool数组信息'''
  1934. analysis = ModbusInfo.AnalysisReadAddress( address, self.isAddressStartWithZero )
  1935. if analysis.IsSuccess == False: return OperateResult.CreateFailedResult(analysis)
  1936. # 获取消息号
  1937. messageId = self.softIncrementCount.GetCurrentValue()
  1938. buffer = ModbusInfo.PackCommandToTcp(analysis.Content.CreateWriteCoil(self.station,values), messageId)
  1939. return OperateResult.CreateSuccessResult(buffer)
  1940. def BuildWriteRegisterCommand(self, address, values):
  1941. '''生成批量写入寄存器的报文信息,需要传入byte数组'''
  1942. analysis = ModbusInfo.AnalysisReadAddress( address, self.isAddressStartWithZero )
  1943. if analysis.IsSuccess == False: return OperateResult.CreateFailedResult(analysis)
  1944. # 获取消息号
  1945. messageId = self.softIncrementCount.GetCurrentValue()
  1946. buffer = ModbusInfo.PackCommandToTcp(analysis.Content.CreateWriteRegister(self.station,values), messageId)
  1947. return OperateResult.CreateSuccessResult(buffer)
  1948. def BuildReadModbusAddressCommand( self, address, length ):
  1949. '''生成一个读取寄存器的指令头,address->ModbusAddress'''
  1950. # 获取消息号
  1951. messageId = self.softIncrementCount.GetCurrentValue()
  1952. # 生成最终tcp指令
  1953. buffer = ModbusInfo.PackCommandToTcp( address.CreateReadRegister( self.station, length ), messageId )
  1954. #print(buffer)
  1955. return OperateResult.CreateSuccessResult( buffer )
  1956. def CheckModbusTcpResponse( self, send ):
  1957. '''检查当前的Modbus-Tcp响应是否是正确的'''
  1958. resultBytes = self.ReadFromCoreServer( send )
  1959. if resultBytes.IsSuccess == True:
  1960. if (send[7] + 0x80) == resultBytes.Content[7]:
  1961. # 发生了错误
  1962. resultBytes.IsSuccess = False
  1963. resultBytes.Message = ModbusInfo.GetDescriptionByErrorCode( resultBytes.Content[8] )
  1964. resultBytes.ErrorCode = resultBytes.Content[8]
  1965. return resultBytes
  1966. def ReadModBusBase( self, code, address, length ):
  1967. '''检查当前的Modbus-Tcp响应是否是正确的'''
  1968. command = None
  1969. if code == ModbusInfo.ReadCoil():
  1970. command = self.BuildReadCoilCommand( address, length )
  1971. elif code == ModbusInfo.ReadDiscrete():
  1972. command = self.BuildReadDiscreteCommand( address, length )
  1973. elif code == ModbusInfo.ReadRegister():
  1974. command = self.BuildReadRegisterCommand( address, length )
  1975. elif code == ModbusInfo.ReadInputRegister():
  1976. command = self.BuildReadInputRegisterCommand( address, length )
  1977. else:
  1978. command = OperateResult( msg = StringResources.ModbusTcpFunctionCodeNotSupport() )
  1979. if command.IsSuccess == False : return OperateResult.CreateFailedResult( command )
  1980. resultBytes = self.CheckModbusTcpResponse( command.Content )
  1981. if resultBytes.IsSuccess == True:
  1982. # 二次数据处理
  1983. if len(resultBytes.Content) >= 9:
  1984. buffer = bytearray(len(resultBytes.Content) - 9)
  1985. buffer[0:len(buffer)] = resultBytes.Content[9:]
  1986. resultBytes.Content = buffer
  1987. return resultBytes
  1988. def ReadModBusAddressBase( self, address, length = 1 ):
  1989. '''读取服务器的数据,需要指定不同的功能码'''
  1990. command = self.BuildReadModbusAddressCommand( address, length )
  1991. if command.IsSuccess == False: return OperateResult.CreateFailedResult(command)
  1992. resultBytes = self.CheckModbusTcpResponse( command.Content )
  1993. if resultBytes.IsSuccess == True:
  1994. # 二次数据处理
  1995. if len(resultBytes.Content) >= 9:
  1996. buffer = bytearray(len(resultBytes.Content) - 9)
  1997. buffer[0:len(buffer)] = resultBytes.Content[9:]
  1998. resultBytes.Content = buffer
  1999. return resultBytes
  2000. def ReadCoil( self, address, length = None):
  2001. '''批量的读取线圈,需要指定起始地址,读取长度可选'''
  2002. if length == None:
  2003. read = self.ReadCoil( address, 1 )
  2004. if read.IsSuccess == False : return OperateResult.CreateFailedResult( read )
  2005. return OperateResult.CreateSuccessResult( read.Content[0] )
  2006. else:
  2007. read = self.ReadModBusBase( ModbusInfo.ReadCoil(), address, length )
  2008. if read.IsSuccess == False : return OperateResult.CreateFailedResult( read )
  2009. return OperateResult.CreateSuccessResult( SoftBasic.ByteToBoolArray( read.Content, length ) )
  2010. def ReadDiscrete( self, address, length = None):
  2011. '''批量的读取输入点,需要指定起始地址,可选读取长度'''
  2012. if length == None:
  2013. read = self.ReadDiscrete( address, 1 )
  2014. if read.IsSuccess == False : return OperateResult.CreateFailedResult( read )
  2015. return OperateResult.CreateSuccessResult( read.Content[0] )
  2016. else:
  2017. read = self.ReadModBusBase( ModbusInfo.ReadDiscrete(), address, length )
  2018. if read.IsSuccess == False : return OperateResult.CreateFailedResult( read )
  2019. return OperateResult.CreateSuccessResult( SoftBasic.ByteToBoolArray( read.Content, length ) )
  2020. def Read( self, address, length ):
  2021. '''从Modbus服务器批量读取寄存器的信息,需要指定起始地址,读取长度'''
  2022. analysis = ModbusInfo.AnalysisReadAddress( address, self.isAddressStartWithZero )
  2023. if analysis.IsSuccess == False : return OperateResult.CreateFailedResult( analysis )
  2024. return self.ReadModBusAddressBase( analysis.Content, length )
  2025. def WriteOneRegister( self, address, value ):
  2026. '''写一个寄存器数据'''
  2027. if type(value) == list:
  2028. command = self.BuildWriteOneRegisterCommand( address, value )
  2029. if command.IsSuccess == False : return command
  2030. return self.CheckModbusTcpResponse( command.Content )
  2031. else:
  2032. return self.WriteOneRegister(address, struct.pack('>H', value))
  2033. def Write( self, address, value ):
  2034. '''将数据写入到Modbus的寄存器上去,需要指定起始地址和数据内容'''
  2035. command = self.BuildWriteRegisterCommand( address, value )
  2036. if command.IsSuccess == False:
  2037. return command
  2038. return self.CheckModbusTcpResponse( command.Content )
  2039. def WriteCoil( self, address, value ):
  2040. '''批量写线圈信息,指定是否通断'''
  2041. if type(value) == list:
  2042. command = self.BuildWriteCoilCommand( address, value )
  2043. if command.IsSuccess == False : return command
  2044. return self.CheckModbusTcpResponse( command.Content )
  2045. else:
  2046. command = self.BuildWriteOneCoilCommand( address, value )
  2047. if command.IsSuccess == False : return command
  2048. return self.CheckModbusTcpResponse( command.Content )
  2049. def WriteBool( self, address, values ):
  2050. '''批量写寄存器的数据内容'''
  2051. return self.Write( address, SoftBasic.BoolArrayToByte( values ) )
  2052. # 三菱的类库
  2053. class MelsecA1EDataType:
  2054. '''三菱PLC的数据类型,此处包含了几个常用的类型'''
  2055. DataCode = bytearray(2)
  2056. DataType = 0
  2057. AsciiCode = 0
  2058. FromBase = 0
  2059. def __init__(self, code0, code1, typeCode, asciiCode, fromBase):
  2060. '''如果您清楚类型代号,可以根据值进行扩展'''
  2061. self.DataCode[0] = code0
  2062. self.DataCode[1] = code1
  2063. self.AsciiCode = asciiCode
  2064. self.FromBase = fromBase
  2065. if typeCode < 2:
  2066. self.DataType = typeCode
  2067. @staticmethod
  2068. def GetX():
  2069. '''X输入寄存器'''
  2070. return MelsecA1EDataType(0x58,0x20,0x01,'X*',8)
  2071. @staticmethod
  2072. def GetY():
  2073. '''Y输出寄存器'''
  2074. return MelsecA1EDataType(0x59,0x20,0x01,'Y*',8)
  2075. @staticmethod
  2076. def GetM():
  2077. '''M中间寄存器'''
  2078. return MelsecA1EDataType(0x4D,0x20,0x01,'M*',10)
  2079. @staticmethod
  2080. def GetS():
  2081. '''S状态寄存器'''
  2082. return MelsecA1EDataType(0x53,0x20,0x01,'S*',10)
  2083. @staticmethod
  2084. def GetD():
  2085. '''D数据寄存器'''
  2086. return MelsecA1EDataType(0x44,0x20,0x00,'D*',10)
  2087. @staticmethod
  2088. def GetR():
  2089. '''R文件寄存器'''
  2090. return MelsecA1EDataType(0x52,0x20,0x00,'R*',10)
  2091. class MelsecMcDataType:
  2092. '''三菱PLC的数据类型,此处包含了几个常用的类型'''
  2093. DataCode = 0
  2094. DataType = 0
  2095. AsciiCode = 0
  2096. FromBase = 0
  2097. def __init__(self, code, typeCode, asciiCode, fromBase):
  2098. '''如果您清楚类型代号,可以根据值进行扩展'''
  2099. self.DataCode = code
  2100. self.AsciiCode = asciiCode
  2101. self.FromBase = fromBase
  2102. if typeCode < 2:
  2103. self.DataType = typeCode
  2104. @staticmethod
  2105. def GetX():
  2106. '''X输入寄存器'''
  2107. return MelsecMcDataType(0x9C,0x01,'X*',16)
  2108. @staticmethod
  2109. def GetY():
  2110. '''Y输出寄存器'''
  2111. return MelsecMcDataType(0x9D,0x01,'Y*',16)
  2112. @staticmethod
  2113. def GetM():
  2114. '''M中间寄存器'''
  2115. return MelsecMcDataType(0x90,0x01,'M*',10)
  2116. @staticmethod
  2117. def GetD():
  2118. '''D数据寄存器'''
  2119. return MelsecMcDataType(0xA8,0x00,'D*',10)
  2120. @staticmethod
  2121. def GetW():
  2122. '''W链接寄存器'''
  2123. return MelsecMcDataType(0xB4,0x00,'W*',16)
  2124. @staticmethod
  2125. def GetL():
  2126. '''L锁存继电器'''
  2127. return MelsecMcDataType(0x92,0x01,'L*',10)
  2128. @staticmethod
  2129. def GetF():
  2130. '''F报警器'''
  2131. return MelsecMcDataType(0x93,0x01,'F*',10)
  2132. @staticmethod
  2133. def GetV():
  2134. '''V边沿继电器'''
  2135. return MelsecMcDataType(0x93,0x01,'V*',10)
  2136. @staticmethod
  2137. def GetB():
  2138. '''B链接继电器'''
  2139. return MelsecMcDataType(0xA,0x01,'B*',16)
  2140. @staticmethod
  2141. def GetR():
  2142. '''R文件寄存器'''
  2143. return MelsecMcDataType(0xAF,0x00,'R*',10)
  2144. @staticmethod
  2145. def GetS():
  2146. '''S步进继电器'''
  2147. return MelsecMcDataType(0x98,0x01,'S*',10)
  2148. @staticmethod
  2149. def GetZ():
  2150. '''变址寄存器'''
  2151. return MelsecMcDataType(0xCC,0x00,'Z*',10)
  2152. @staticmethod
  2153. def GetT():
  2154. '''定时器的值'''
  2155. return MelsecMcDataType(0xC2,0x00,'TN',10)
  2156. @staticmethod
  2157. def GetC():
  2158. '''计数器的值'''
  2159. return MelsecMcDataType(0xC5,0x00,'CN',10)
  2160. class MelsecHelper:
  2161. '''所有三菱通讯类的通用辅助工具类,包含了一些通用的静态方法,可以使用本类来获取一些原始的报文信息。详细的操作参见例子'''
  2162. @staticmethod
  2163. def McA1EAnalysisAddress( address = "0" ):
  2164. result = OperateResult()
  2165. try:
  2166. if address.startswith("X") or address.startswith("x"):
  2167. result.Content1 = MelsecA1EDataType.GetX()
  2168. result.Content2 = int(address[1:], MelsecA1EDataType.GetX().FromBase)
  2169. elif address.startswith("Y") or address.startswith("y"):
  2170. result.Content1 = MelsecA1EDataType.GetY()
  2171. result.Content2 = int(address[1:], MelsecA1EDataType.GetY().FromBase)
  2172. elif address.startswith("M") or address.startswith("m"):
  2173. result.Content1 = MelsecA1EDataType.GetM()
  2174. result.Content2 = int(address[1:], MelsecA1EDataType.GetM().FromBase)
  2175. elif address.startswith("S") or address.startswith("s"):
  2176. result.Content1 = MelsecA1EDataType.GetS()
  2177. result.Content2 = int(address[1:], MelsecA1EDataType.GetS().FromBase)
  2178. elif address.startswith("D") or address.startswith("d"):
  2179. result.Content1 = MelsecA1EDataType.GetD()
  2180. result.Content2 = int(address[1:], MelsecA1EDataType.GetD().FromBase)
  2181. elif address.startswith("R") or address.startswith("r"):
  2182. result.Content1 = MelsecA1EDataType.GetR()
  2183. result.Content2 = int(address[1:], MelsecA1EDataType.GetR().FromBase)
  2184. else:
  2185. raise Exception("type not supported!")
  2186. except Exception as ex:
  2187. result.Message = str(ex)
  2188. return result
  2189. result.IsSuccess = True
  2190. result.Message = StringResources.SuccessText()
  2191. return result
  2192. @staticmethod
  2193. def McAnalysisAddress( address = "0" ):
  2194. result = OperateResult()
  2195. try:
  2196. if address.startswith("M") or address.startswith("m"):
  2197. result.Content1 = MelsecMcDataType.GetM()
  2198. result.Content2 = int(address[1:], MelsecMcDataType.GetM().FromBase)
  2199. elif address.startswith("X") or address.startswith("x"):
  2200. result.Content1 = MelsecMcDataType.GetX()
  2201. result.Content2 = int(address[1:], MelsecMcDataType.GetX().FromBase)
  2202. elif address.startswith("Y") or address.startswith("y"):
  2203. result.Content1 = MelsecMcDataType.GetY()
  2204. result.Content2 = int(address[1:], MelsecMcDataType.GetY().FromBase)
  2205. elif address.startswith("D") or address.startswith("d"):
  2206. result.Content1 = MelsecMcDataType.GetD()
  2207. result.Content2 = int(address[1:], MelsecMcDataType.GetD().FromBase)
  2208. elif address.startswith("W") or address.startswith("w"):
  2209. result.Content1 = MelsecMcDataType.GetW()
  2210. result.Content2 = int(address[1:], MelsecMcDataType.GetW().FromBase)
  2211. elif address.startswith("L") or address.startswith("l"):
  2212. result.Content1 = MelsecMcDataType.GetL()
  2213. result.Content2 = int(address[1:], MelsecMcDataType.GetL().FromBase)
  2214. elif address.startswith("F") or address.startswith("f"):
  2215. result.Content1 = MelsecMcDataType.GetF()
  2216. result.Content2 = int(address[1:], MelsecMcDataType.GetF().FromBase)
  2217. elif address.startswith("V") or address.startswith("v"):
  2218. result.Content1 = MelsecMcDataType.GetV()
  2219. result.Content2 = int(address[1:], MelsecMcDataType.GetV().FromBase)
  2220. elif address.startswith("B") or address.startswith("b"):
  2221. result.Content1 = MelsecMcDataType.GetB()
  2222. result.Content2 = int(address[1:], MelsecMcDataType.GetB().FromBase)
  2223. elif address.startswith("R") or address.startswith("r"):
  2224. result.Content1 = MelsecMcDataType.GetR()
  2225. result.Content2 = int(address[1:], MelsecMcDataType.GetR().FromBase)
  2226. elif address.startswith("S") or address.startswith("s"):
  2227. result.Content1 = MelsecMcDataType.GetS()
  2228. result.Content2 = int(address[1:], MelsecMcDataType.GetS().FromBase)
  2229. elif address.startswith("Z") or address.startswith("z"):
  2230. result.Content1 = MelsecMcDataType.GetZ()
  2231. result.Content2 = int(address[1:], MelsecMcDataType.GetZ().FromBase)
  2232. elif address.startswith("T") or address.startswith("t"):
  2233. result.Content1 = MelsecMcDataType.GetT()
  2234. result.Content2 = int(address[1:], MelsecMcDataType.GetT().FromBase)
  2235. elif address.startswith("C") or address.startswith("c"):
  2236. result.Content1 = MelsecMcDataType.GetC()
  2237. result.Content2 = int(address[1:], MelsecMcDataType.GetC().FromBase)
  2238. else:
  2239. raise Exception("type not supported!")
  2240. except Exception as ex:
  2241. result.Message = str(ex)
  2242. return result
  2243. result.IsSuccess = True
  2244. result.Message = StringResources.SuccessText()
  2245. return result
  2246. @staticmethod
  2247. def BuildBytesFromData( value, length = None ):
  2248. '''从数据构建一个ASCII格式地址字节'''
  2249. if length == None:
  2250. return ('{:02X}'.format(value)).encode('ascii')
  2251. else:
  2252. return (('{:0'+ str(length) +'X}').format(value)).encode('ascii')
  2253. @staticmethod
  2254. def BuildBytesFromAddress( address, dataType ):
  2255. '''从三菱的地址中构建MC协议的6字节的ASCII格式的地址'''
  2256. if dataType.FromBase == 10:
  2257. return ('{:06d}'.format(address)).encode('ascii')
  2258. else:
  2259. return ('{:06X}'.format(address)).encode('ascii')
  2260. @staticmethod
  2261. def FxCalculateCRC( data ):
  2262. '''计算Fx协议指令的和校验信息'''
  2263. sum = 0
  2264. index = 1
  2265. while index < (len(data) - 2):
  2266. sum += data[index]
  2267. index=index+1
  2268. return MelsecHelper.BuildBytesFromData( sum )
  2269. @staticmethod
  2270. def CheckCRC( data ):
  2271. '''检查指定的和校验是否是正确的'''
  2272. crc = MelsecHelper.FxCalculateCRC( data )
  2273. if (crc[0] != data[data.Length - 2]) : return False
  2274. if (crc[1] != data[data.Length - 1]) : return False
  2275. return True
  2276. class MelsecA1ENet(NetworkDeviceBase):
  2277. '''三菱PLC通讯协议,采用A兼容1E帧协议实现,使用二进制码通讯,请根据实际型号来进行选取'''
  2278. PLCNumber = 0xFF
  2279. def __init__(self,ipAddress= "127.0.0.1",port = 0):
  2280. '''实例化一个三菱的A兼容1E帧协议的通讯对象'''
  2281. self.iNetMessage = MelsecA1EBinaryMessage()
  2282. self.byteTransform = RegularByteTransform()
  2283. self.ipAddress = ipAddress
  2284. self.port = port
  2285. self.WordLength = 1
  2286. @staticmethod
  2287. def BuildReadCommand(address,length,plcNumber):
  2288. '''根据类型地址长度确认需要读取的指令头'''
  2289. analysis = MelsecHelper.McA1EAnalysisAddress( address )
  2290. if analysis.IsSuccess == False : return OperateResult.CreateFailedResult( analysis )
  2291. subtitle = 0
  2292. if analysis.Content1.DataType == 0x01:
  2293. subtitle = 0x00
  2294. else:
  2295. subtitle = 0x01
  2296. _PLCCommand = bytearray(12)
  2297. _PLCCommand[0] = subtitle # 副标题
  2298. _PLCCommand[1] = plcNumber # PLC编号
  2299. _PLCCommand[2] = 0x0A # CPU监视定时器(L)这里设置为0x00,0x0A,等待CPU返回的时间为10*250ms=2.5秒
  2300. _PLCCommand[3] = 0x00 # CPU监视定时器(H)
  2301. _PLCCommand[4] = analysis.Content2 % 256 # 起始软元件(开始读取的地址)
  2302. _PLCCommand[5] = analysis.Content2 // 256
  2303. _PLCCommand[6] = 0x00
  2304. _PLCCommand[7] = 0x00
  2305. _PLCCommand[8] = analysis.Content1.DataCode[1] # 软元件代码(L)
  2306. _PLCCommand[9] = analysis.Content1.DataCode[0] # 软元件代码(H)
  2307. _PLCCommand[10] = length % 256 # 软元件点数
  2308. _PLCCommand[11] = 0x00
  2309. return OperateResult.CreateSuccessResult( _PLCCommand )
  2310. @staticmethod
  2311. def BuildWriteCommand( address,value,plcNumber):
  2312. '''根据类型地址以及需要写入的数据来生成指令头'''
  2313. analysis = MelsecHelper.McA1EAnalysisAddress( address )
  2314. if analysis.IsSuccess == False : return OperateResult.CreateFailedResult( analysis )
  2315. length = -1
  2316. if analysis.Content1.DataType == 1:
  2317. # 按照位写入的操作,数据需要重新计算
  2318. length2 = len(value) // 2 + 1
  2319. if len(value) % 2 == 0 :
  2320. length2 = len(value) // 2
  2321. buffer = bytearray(length2)
  2322. for i in range(length2):
  2323. if value[i * 2 + 0] != 0x00 :
  2324. buffer[i] += 0x10
  2325. if (i * 2 + 1) < len(value) :
  2326. if value[i * 2 + 1] != 0x00 :
  2327. buffer[i] += 0x01
  2328. length = len(value)
  2329. value = buffer
  2330. subtitle = 0
  2331. if analysis.Content1.DataType == 0x01:
  2332. subtitle = 0x02
  2333. else:
  2334. subtitle = 0x03
  2335. _PLCCommand = bytearray(12 + len(value))
  2336. _PLCCommand[0] = subtitle # 副标题
  2337. _PLCCommand[1] = plcNumber # PLC编号
  2338. _PLCCommand[2] = 0x0A # CPU监视定时器(L)这里设置为0x00,0x0A,等待CPU返回的时间为10*250ms=2.5秒
  2339. _PLCCommand[3] = 0x00 # CPU监视定时器(H)
  2340. _PLCCommand[4] = analysis.Content2 % 256 # 起始软元件(开始读取的地址)
  2341. _PLCCommand[5] = analysis.Content2 // 256
  2342. _PLCCommand[6] = 0x00
  2343. _PLCCommand[7] = 0x00
  2344. _PLCCommand[8] = analysis.Content1.DataCode[1] # 软元件代码(L)
  2345. _PLCCommand[9] = analysis.Content1.DataCode[0] # 软元件代码(H)
  2346. _PLCCommand[10] = length % 256 # 软元件点数
  2347. _PLCCommand[11] = 0x00
  2348. # 判断是否进行位操作
  2349. if analysis.Content1.DataType == 1:
  2350. if length > 0:
  2351. _PLCCommand[10] = length % 256 # 软元件点数
  2352. else:
  2353. _PLCCommand[10] = len(value) * 2 % 256 # 软元件点数
  2354. else:
  2355. _PLCCommand[10] = len(value) // 2 % 256 # 软元件点数
  2356. _PLCCommand[12:] = value
  2357. return OperateResult.CreateSuccessResult( _PLCCommand )
  2358. @staticmethod
  2359. def ExtractActualData( response, isBit ):
  2360. ''' 从PLC反馈的数据中提取出实际的数据内容,需要传入反馈数据,是否位读取'''
  2361. if isBit == True:
  2362. # 位读取
  2363. Content = bytearray((len(response) - 2) * 2)
  2364. i = 2
  2365. while i < len(response):
  2366. if (response[i] & 0x10) == 0x10:
  2367. Content[(i - 2) * 2 + 0] = 0x01
  2368. if (response[i] & 0x01) == 0x01:
  2369. Content[(i - 2) * 2 + 1] = 0x01
  2370. i = i + 1
  2371. return OperateResult.CreateSuccessResult( Content )
  2372. else:
  2373. # 字读取
  2374. return OperateResult.CreateSuccessResult( response[2:] )
  2375. def Read( self, address, length ):
  2376. '''从三菱PLC中读取想要的数据,返回读取结果'''
  2377. # 获取指令
  2378. command = MelsecA1ENet.BuildReadCommand( address, length, self.PLCNumber )
  2379. if command.IsSuccess == False :
  2380. return OperateResult.CreateFailedResult( command )
  2381. # 核心交互
  2382. read = self.ReadFromCoreServer( command.Content )
  2383. if read.IsSuccess == False : return OperateResult.CreateFailedResult( read )
  2384. # 错误代码验证
  2385. errorCode = read.Content[1]
  2386. if errorCode != 0 : return OperateResult(err=errorCode, msg=StringResources.MelsecPleaseReferToManulDocument())
  2387. # 数据解析,需要传入是否使用位的参数
  2388. return MelsecA1ENet.ExtractActualData( read.Content, command.Content[0] == 0x00 )
  2389. def ReadBool( self, address, length = None ):
  2390. '''从三菱PLC中批量读取位软元件,返回读取结果'''
  2391. if length == None:
  2392. read = self.ReadBool(address,1)
  2393. if read.IsSuccess == False:
  2394. return OperateResult.CreateFailedResult(read)
  2395. else:
  2396. return OperateResult.CreateSuccessResult(read.Content[0])
  2397. else:
  2398. # 解析地址
  2399. analysis = MelsecHelper.McA1EAnalysisAddress( address )
  2400. if analysis.IsSuccess == False :
  2401. return OperateResult.CreateFailedResult( analysis )
  2402. # 位读取校验
  2403. if analysis.Content1.DataType == 0x00 :
  2404. return OperateResult( msg = StringResources.MelsecReadBitInfo() )
  2405. # 核心交互
  2406. read = self.Read( address, length )
  2407. if read.IsSuccess == False :
  2408. return OperateResult.CreateFailedResult( read )
  2409. # 转化bool数组
  2410. content = []
  2411. for i in range(length):
  2412. if read.Content[i] == 0x01:
  2413. content.append(True)
  2414. else:
  2415. content.append(False)
  2416. return OperateResult.CreateSuccessResult( content )
  2417. def Write( self, address, value ):
  2418. '''向PLC写入数据,数据格式为原始的字节类型'''
  2419. # 解析指令
  2420. command = MelsecA1ENet.BuildWriteCommand( address, value, self.PLCNumber )
  2421. if command.IsSuccess == False : return command
  2422. # 核心交互
  2423. read = self.ReadFromCoreServer( command.Content )
  2424. if read.IsSuccess == False : return read
  2425. # 错误码校验
  2426. errorCode = read.Content[1]
  2427. if errorCode != 0 : return OperateResult(err=errorCode, msg=StringResources.MelsecPleaseReferToManulDocument())
  2428. # 成功
  2429. return OperateResult.CreateSuccessResult( )
  2430. def WriteBool( self, address, values ):
  2431. '''向PLC中位软元件写入bool数组或是值,返回值说明,比如你写入M100,values[0]对应M100'''
  2432. if type(values) == list:
  2433. buffer = bytearray(len(values))
  2434. for i in range(len(values)):
  2435. if values[i] == True:
  2436. buffer[i] = 0x01
  2437. return self.Write(address, buffer)
  2438. else:
  2439. return self.Write(address,[values])
  2440. class MelsecMcNet(NetworkDeviceBase):
  2441. '''三菱PLC通讯类,采用Qna兼容3E帧协议实现,需要在PLC侧先的以太网模块先进行配置,必须为二进制通讯'''
  2442. NetworkNumber = 0
  2443. NetworkStationNumber = 0
  2444. def __init__(self,ipAddress= "127.0.0.1",port = 0):
  2445. '''实例化一个三菱的Qna兼容3E帧协议的通讯对象'''
  2446. self.iNetMessage = MelsecQnA3EBinaryMessage()
  2447. self.byteTransform = RegularByteTransform()
  2448. self.ipAddress = ipAddress
  2449. self.port = port
  2450. self.WordLength = 1
  2451. @staticmethod
  2452. def BuildReadCommand(address,length,networkNumber = 0,networkStationNumber = 0):
  2453. '''根据类型地址长度确认需要读取的指令头'''
  2454. analysis = MelsecHelper.McAnalysisAddress( address )
  2455. if analysis.IsSuccess == False : return OperateResult.CreateFailedResult( analysis )
  2456. _PLCCommand = bytearray(21)
  2457. _PLCCommand[0] = 0x50 # 副标题
  2458. _PLCCommand[1] = 0x00
  2459. _PLCCommand[2] = networkNumber # 网络号
  2460. _PLCCommand[3] = 0xFF # PLC编号
  2461. _PLCCommand[4] = 0xFF # 目标模块IO编号
  2462. _PLCCommand[5] = 0x03
  2463. _PLCCommand[6] = networkStationNumber # 目标模块站号
  2464. _PLCCommand[7] = 0x0C # 请求数据长度
  2465. _PLCCommand[8] = 0x00
  2466. _PLCCommand[9] = 0x0A # CPU监视定时器
  2467. _PLCCommand[10] = 0x00
  2468. _PLCCommand[11] = 0x01 # 批量读取数据命令
  2469. _PLCCommand[12] = 0x04
  2470. _PLCCommand[13] = analysis.Content1.DataType # 以点为单位还是字为单位成批读取
  2471. _PLCCommand[14] = 0x00
  2472. _PLCCommand[15] = analysis.Content2 % 256 # 起始地址的地位
  2473. _PLCCommand[16] = analysis.Content2 // 256
  2474. _PLCCommand[17] = 0x00
  2475. _PLCCommand[18] = analysis.Content1.DataCode # 指明读取的数据
  2476. _PLCCommand[19] = length % 256 # 软元件长度的地位
  2477. _PLCCommand[20] = length // 256
  2478. return OperateResult.CreateSuccessResult( _PLCCommand )
  2479. @staticmethod
  2480. def BuildWriteCommand( address, value, networkNumber = 0, networkStationNumber = 0 ):
  2481. '''根据类型地址以及需要写入的数据来生成指令头'''
  2482. analysis = MelsecHelper.McAnalysisAddress( address )
  2483. if analysis.IsSuccess == False : return OperateResult.CreateFailedResult( analysis )
  2484. length = -1
  2485. if analysis.Content1.DataType == 1:
  2486. # 按照位写入的操作,数据需要重新计算
  2487. length2 = len(value) // 2 + 1
  2488. if len(value) % 2 == 0 :
  2489. length2 = len(value) // 2
  2490. buffer = bytearray(length2)
  2491. for i in range(length2):
  2492. if value[i * 2 + 0] != 0x00 :
  2493. buffer[i] += 0x10
  2494. if (i * 2 + 1) < len(value) :
  2495. if value[i * 2 + 1] != 0x00 :
  2496. buffer[i] += 0x01
  2497. length = len(value)
  2498. value = buffer
  2499. _PLCCommand = bytearray(21 + len(value))
  2500. _PLCCommand[0] = 0x50 # 副标题
  2501. _PLCCommand[1] = 0x00
  2502. _PLCCommand[2] = networkNumber # 网络号
  2503. _PLCCommand[3] = 0xFF # PLC编号
  2504. _PLCCommand[4] = 0xFF # 目标模块IO编号
  2505. _PLCCommand[5] = 0x03
  2506. _PLCCommand[6] = networkStationNumber # 目标模块站号
  2507. _PLCCommand[7] = (len(_PLCCommand) - 9) % 256 # 请求数据长度
  2508. _PLCCommand[8] = (len(_PLCCommand) - 9) // 256
  2509. _PLCCommand[9] = 0x0A # CPU监视定时器
  2510. _PLCCommand[10] = 0x00
  2511. _PLCCommand[11] = 0x01 # 批量读取数据命令
  2512. _PLCCommand[12] = 0x14
  2513. _PLCCommand[13] = analysis.Content1.DataType # 以点为单位还是字为单位成批读取
  2514. _PLCCommand[14] = 0x00
  2515. _PLCCommand[15] = analysis.Content2 % 256 # 起始地址的地位
  2516. _PLCCommand[16] = analysis.Content2 // 256
  2517. _PLCCommand[17] = 0x00
  2518. _PLCCommand[18] = analysis.Content1.DataCode # 指明写入的数据
  2519. # 判断是否进行位操作
  2520. if analysis.Content1.DataType == 1:
  2521. if length > 0:
  2522. _PLCCommand[19] = length % 256 # 软元件长度的地位
  2523. _PLCCommand[20] = length // 256
  2524. else:
  2525. _PLCCommand[19] = len(value) * 2 % 256 # 软元件长度的地位
  2526. _PLCCommand[20] = len(value) * 2 // 256
  2527. else:
  2528. _PLCCommand[19] = len(value) // 2 % 256 # 软元件长度的地位
  2529. _PLCCommand[20] = len(value) // 2 // 256
  2530. _PLCCommand[21:] = value
  2531. return OperateResult.CreateSuccessResult( _PLCCommand )
  2532. @staticmethod
  2533. def ExtractActualData( response, isBit ):
  2534. ''' 从PLC反馈的数据中提取出实际的数据内容,需要传入反馈数据,是否位读取'''
  2535. if isBit == True:
  2536. # 位读取
  2537. Content = bytearray((len(response) - 11) * 2)
  2538. i = 11
  2539. while i < len(response):
  2540. if (response[i] & 0x10) == 0x10:
  2541. Content[(i - 11) * 2 + 0] = 0x01
  2542. if (response[i] & 0x01) == 0x01:
  2543. Content[(i - 11) * 2 + 1] = 0x01
  2544. i = i + 1
  2545. return OperateResult.CreateSuccessResult( Content )
  2546. else:
  2547. # 字读取
  2548. Content = bytearray(len(response) - 11)
  2549. Content[0:] = response[11:]
  2550. return OperateResult.CreateSuccessResult( Content )
  2551. def Read( self, address, length ):
  2552. '''从三菱PLC中读取想要的数据,返回读取结果'''
  2553. # 获取指令
  2554. command = MelsecMcNet.BuildReadCommand( address, length, self.NetworkNumber, self.NetworkStationNumber )
  2555. if command.IsSuccess == False :
  2556. return OperateResult.CreateFailedResult( command )
  2557. # 核心交互
  2558. read = self.ReadFromCoreServer( command.Content )
  2559. if read.IsSuccess == False : return OperateResult.CreateFailedResult( read )
  2560. # 错误代码验证
  2561. errorCode = read.Content[9] * 256 + read.Content[10]
  2562. if errorCode != 0 : return OperateResult(err=errorCode, msg=StringResources.MelsecPleaseReferToManulDocument())
  2563. # 数据解析,需要传入是否使用位的参数
  2564. return MelsecMcNet.ExtractActualData( read.Content, command.Content[13] == 1 )
  2565. def ReadBool( self, address, length = None ):
  2566. '''从三菱PLC中批量读取位软元件,返回读取结果'''
  2567. if length == None:
  2568. read = self.ReadBool(address,1)
  2569. if read.IsSuccess == False:
  2570. return OperateResult.CreateFailedResult(read)
  2571. else:
  2572. return OperateResult.CreateSuccessResult(read.Content[0])
  2573. else:
  2574. # 解析地址
  2575. analysis = MelsecHelper.McAnalysisAddress( address )
  2576. if analysis.IsSuccess == False :
  2577. return OperateResult.CreateFailedResult( analysis )
  2578. # 位读取校验
  2579. if analysis.Content1.DataType == 0x00 :
  2580. return OperateResult( msg = StringResources.MelsecReadBitInfo() )
  2581. # 核心交互
  2582. read = self.Read( address, length )
  2583. if read.IsSuccess == False :
  2584. return OperateResult.CreateFailedResult( read )
  2585. # 转化bool数组
  2586. content = []
  2587. for i in range(length):
  2588. if read.Content[i] == 0x01:
  2589. content.append(True)
  2590. else:
  2591. content.append(False)
  2592. return OperateResult.CreateSuccessResult( content )
  2593. def Write( self, address, value ):
  2594. '''向PLC写入数据,数据格式为原始的字节类型'''
  2595. # 解析指令
  2596. command = MelsecMcNet.BuildWriteCommand( address, value, self.NetworkNumber, self.NetworkStationNumber )
  2597. if command.IsSuccess == False : return command
  2598. # 核心交互
  2599. read = self.ReadFromCoreServer( command.Content )
  2600. if read.IsSuccess == False : return read
  2601. # 错误码校验
  2602. errorCode = read.Content[9] * 256 + read.Content[10]
  2603. if errorCode != 0 : return OperateResult(err=errorCode, msg=StringResources.MelsecPleaseReferToManulDocument())
  2604. # 成功
  2605. return OperateResult.CreateSuccessResult( )
  2606. def WriteBool( self, address, values ):
  2607. '''向PLC中位软元件写入bool数组或是值,返回值说明,比如你写入M100,values[0]对应M100'''
  2608. if type(values) == list:
  2609. buffer = bytearray(len(values))
  2610. for i in range(len(values)):
  2611. if values[i] == True:
  2612. buffer[i] = 0x01
  2613. return self.Write(address, buffer)
  2614. else:
  2615. return self.WriteBool(address,[values])
  2616. class MelsecMcAsciiNet(NetworkDeviceBase):
  2617. '''三菱PLC通讯类,采用Qna兼容3E帧协议实现,需要在PLC侧先的以太网模块先进行配置,必须为ASCII通讯格式'''
  2618. NetworkNumber = 0
  2619. NetworkStationNumber = 0
  2620. def __init__(self,ipAddress= "127.0.0.1",port = 0):
  2621. '''实例化一个三菱的Qna兼容3E帧协议的通讯对象'''
  2622. self.iNetMessage = MelsecQnA3EAsciiMessage()
  2623. self.byteTransform = RegularByteTransform()
  2624. self.ipAddress = ipAddress
  2625. self.port = port
  2626. self.WordLength = 1
  2627. @staticmethod
  2628. def BuildReadCommand( address, length, networkNumber = 0, networkStationNumber = 0 ):
  2629. '''根据类型地址长度确认需要读取的报文'''
  2630. analysis = MelsecHelper.McAnalysisAddress( address )
  2631. if analysis.IsSuccess == False : return OperateResult.CreateFailedResult( analysis )
  2632. # 默认信息----注意:高低字节交错
  2633. _PLCCommand = bytearray(42)
  2634. _PLCCommand[ 0] = 0x35 # 副标题
  2635. _PLCCommand[ 1] = 0x30
  2636. _PLCCommand[ 2] = 0x30
  2637. _PLCCommand[ 3] = 0x30
  2638. _PLCCommand[ 4] = MelsecHelper.BuildBytesFromData( networkNumber )[0] # 网络号
  2639. _PLCCommand[ 5] = MelsecHelper.BuildBytesFromData( networkNumber )[1]
  2640. _PLCCommand[ 6] = 0x46 # PLC编号
  2641. _PLCCommand[ 7] = 0x46
  2642. _PLCCommand[ 8] = 0x30 # 目标模块IO编号
  2643. _PLCCommand[ 9] = 0x33
  2644. _PLCCommand[10] = 0x46
  2645. _PLCCommand[11] = 0x46
  2646. _PLCCommand[12] = MelsecHelper.BuildBytesFromData( networkStationNumber )[0] # 目标模块站号
  2647. _PLCCommand[13] = MelsecHelper.BuildBytesFromData( networkStationNumber )[1]
  2648. _PLCCommand[14] = 0x30 # 请求数据长度
  2649. _PLCCommand[15] = 0x30
  2650. _PLCCommand[16] = 0x31
  2651. _PLCCommand[17] = 0x38
  2652. _PLCCommand[18] = 0x30 # CPU监视定时器
  2653. _PLCCommand[19] = 0x30
  2654. _PLCCommand[20] = 0x31
  2655. _PLCCommand[21] = 0x30
  2656. _PLCCommand[22] = 0x30 # 批量读取数据命令
  2657. _PLCCommand[23] = 0x34
  2658. _PLCCommand[24] = 0x30
  2659. _PLCCommand[25] = 0x31
  2660. _PLCCommand[26] = 0x30 # 以点为单位还是字为单位成批读取
  2661. _PLCCommand[27] = 0x30
  2662. _PLCCommand[28] = 0x30
  2663. _PLCCommand[29] = 0x30 if analysis.Content1.DataType == 0 else 0x31
  2664. _PLCCommand[30] = analysis.Content1.AsciiCode.encode('ascii')[0] # 软元件类型
  2665. _PLCCommand[31] = analysis.Content1.AsciiCode.encode('ascii')[1]
  2666. _PLCCommand[32:38] = MelsecHelper.BuildBytesFromAddress( analysis.Content2, analysis.Content1 ) # 起始地址的地位
  2667. _PLCCommand[38:42] = MelsecHelper.BuildBytesFromData( length, 4 ) # 软元件点数
  2668. return OperateResult.CreateSuccessResult( _PLCCommand )
  2669. @staticmethod
  2670. def BuildWriteCommand( address, value, networkNumber = 0, networkStationNumber = 0 ):
  2671. '''根据类型地址以及需要写入的数据来生成报文'''
  2672. analysis = MelsecHelper.McAnalysisAddress( address )
  2673. if analysis.IsSuccess == False : return OperateResult.CreateFailedResult( analysis )
  2674. # 预处理指令
  2675. if analysis.Content1.DataType == 0x01:
  2676. # 位写入
  2677. buffer = bytearray(len(value))
  2678. for i in range(len(buffer)):
  2679. buffer[i] = 0x30 if value[i] == 0x00 else 0x31
  2680. value = buffer
  2681. else:
  2682. # 字写入
  2683. buffer = bytearray(len(value) * 2)
  2684. for i in range(len(value) // 2):
  2685. tmp = value[i*2]+ value[i*2+1]*256
  2686. buffer[4*i:4*i+4] = MelsecHelper.BuildBytesFromData( tmp, 4 )
  2687. value = buffer
  2688. # 默认信息----注意:高低字节交错
  2689. _PLCCommand = bytearray(42 + len(value))
  2690. _PLCCommand[ 0] = 0x35 # 副标题
  2691. _PLCCommand[ 1] = 0x30
  2692. _PLCCommand[ 2] = 0x30
  2693. _PLCCommand[ 3] = 0x30
  2694. _PLCCommand[ 4] = MelsecHelper.BuildBytesFromData( networkNumber )[0] # 网络号
  2695. _PLCCommand[ 5] = MelsecHelper.BuildBytesFromData( networkNumber )[1]
  2696. _PLCCommand[ 6] = 0x46 # PLC编号
  2697. _PLCCommand[ 7] = 0x46
  2698. _PLCCommand[ 8] = 0x30 # 目标模块IO编号
  2699. _PLCCommand[ 9] = 0x33
  2700. _PLCCommand[10] = 0x46
  2701. _PLCCommand[11] = 0x46
  2702. _PLCCommand[12] = MelsecHelper.BuildBytesFromData( networkStationNumber )[0] # 目标模块站号
  2703. _PLCCommand[13] = MelsecHelper.BuildBytesFromData( networkStationNumber )[1]
  2704. _PLCCommand[14] = MelsecHelper.BuildBytesFromData( len(_PLCCommand) - 18, 4 )[0] # 请求数据长度
  2705. _PLCCommand[15] = MelsecHelper.BuildBytesFromData( len(_PLCCommand) - 18, 4 )[1]
  2706. _PLCCommand[16] = MelsecHelper.BuildBytesFromData( len(_PLCCommand) - 18, 4 )[2]
  2707. _PLCCommand[17] = MelsecHelper.BuildBytesFromData( len(_PLCCommand) - 18, 4 )[3]
  2708. _PLCCommand[18] = 0x30 # CPU监视定时器
  2709. _PLCCommand[19] = 0x30
  2710. _PLCCommand[20] = 0x31
  2711. _PLCCommand[21] = 0x30
  2712. _PLCCommand[22] = 0x31 # 批量写入的命令
  2713. _PLCCommand[23] = 0x34
  2714. _PLCCommand[24] = 0x30
  2715. _PLCCommand[25] = 0x31
  2716. _PLCCommand[26] = 0x30 # 子命令
  2717. _PLCCommand[27] = 0x30
  2718. _PLCCommand[28] = 0x30
  2719. _PLCCommand[29] = 0x30 if analysis.Content1.DataType == 0 else 0x31
  2720. _PLCCommand[30] = analysis.Content1.AsciiCode.encode('ascii')[0] # 软元件类型
  2721. _PLCCommand[31] = analysis.Content1.AsciiCode.encode('ascii')[1]
  2722. _PLCCommand[32] = MelsecHelper.BuildBytesFromAddress( analysis.Content2, analysis.Content1 )[0] # 起始地址的地位
  2723. _PLCCommand[33] = MelsecHelper.BuildBytesFromAddress( analysis.Content2, analysis.Content1 )[1]
  2724. _PLCCommand[34] = MelsecHelper.BuildBytesFromAddress( analysis.Content2, analysis.Content1 )[2]
  2725. _PLCCommand[35] = MelsecHelper.BuildBytesFromAddress( analysis.Content2, analysis.Content1 )[3]
  2726. _PLCCommand[36] = MelsecHelper.BuildBytesFromAddress( analysis.Content2, analysis.Content1 )[4]
  2727. _PLCCommand[37] = MelsecHelper.BuildBytesFromAddress( analysis.Content2, analysis.Content1 )[5]
  2728. # 判断是否进行位操作
  2729. if (analysis.Content1.DataType == 1):
  2730. _PLCCommand[38] = MelsecHelper.BuildBytesFromData( len(value), 4 )[0] # 软元件点数
  2731. _PLCCommand[39] = MelsecHelper.BuildBytesFromData( len(value), 4 )[1]
  2732. _PLCCommand[40] = MelsecHelper.BuildBytesFromData( len(value), 4 )[2]
  2733. _PLCCommand[41] = MelsecHelper.BuildBytesFromData( len(value), 4 )[3]
  2734. else:
  2735. _PLCCommand[38] = MelsecHelper.BuildBytesFromData( len(value) // 4, 4 )[0] # 软元件点数
  2736. _PLCCommand[39] = MelsecHelper.BuildBytesFromData( len(value) // 4, 4 )[1]
  2737. _PLCCommand[40] = MelsecHelper.BuildBytesFromData( len(value) // 4, 4 )[2]
  2738. _PLCCommand[41] = MelsecHelper.BuildBytesFromData( len(value) // 4, 4 )[3]
  2739. _PLCCommand[42:] = value
  2740. return OperateResult.CreateSuccessResult( _PLCCommand )
  2741. @staticmethod
  2742. def ExtractActualData( response, isBit ):
  2743. if isBit == True:
  2744. # 位读取
  2745. Content = bytearray(len(response) - 22)
  2746. for i in range(22,len(response)):
  2747. Content[i - 22] = 0x00 if response[i] == 0x30 else 0x01
  2748. return OperateResult.CreateSuccessResult( Content )
  2749. else:
  2750. # 字读取
  2751. Content = bytearray((len(response) - 22) // 2)
  2752. for i in range(len(Content)//2):
  2753. tmp = int(response[i * 4 + 22:i * 4 + 26].decode('ascii'),16)
  2754. Content[i * 2:i * 2+2] = struct.pack('<H',tmp)
  2755. return OperateResult.CreateSuccessResult( Content )
  2756. def Read( self, address, length ):
  2757. '''从三菱PLC中读取想要的数据,返回读取结果'''
  2758. # 获取指令
  2759. command = MelsecMcAsciiNet.BuildReadCommand( address, length, self.NetworkNumber, self.NetworkStationNumber )
  2760. if command.IsSuccess == False : return OperateResult.CreateFailedResult( command )
  2761. # 核心交互
  2762. read = self.ReadFromCoreServer( command.Content )
  2763. if read.IsSuccess == False : return OperateResult.CreateFailedResult( read )
  2764. # 错误代码验证
  2765. errorCode = int( read.Content[18:22].decode('ascii'), 16 )
  2766. if errorCode != 0 : return OperateResult( err= errorCode, msg = StringResources.MelsecPleaseReferToManulDocument() )
  2767. # 数据解析,需要传入是否使用位的参数
  2768. return MelsecMcAsciiNet.ExtractActualData( read.Content, command.Content[29] == 0x31 )
  2769. def ReadBool( self, address, length = None ):
  2770. if length == None:
  2771. read = self.ReadBool( address, 1 )
  2772. if read.IsSuccess == False : return OperateResult.CreateFailedResult( read )
  2773. return OperateResult.CreateSuccessResult( read.Content[0] )
  2774. else:
  2775. # 解析地址
  2776. analysis = MelsecHelper.McAnalysisAddress( address )
  2777. if analysis.IsSuccess == False : return OperateResult.CreateFailedResult( analysis )
  2778. # 位读取校验
  2779. if analysis.Content1.DataType == 0x00 : return OperateResult( msg = StringResources.MelsecReadBitInfo )
  2780. # 核心交互
  2781. read = self.Read( address, length )
  2782. if read.IsSuccess == False : return OperateResult.CreateFailedResult( read )
  2783. # 转化bool数组
  2784. content = []
  2785. for i in range(len(read.Content)):
  2786. if read.Content[i] == 0x01:
  2787. content.append(True)
  2788. else:
  2789. content.append(False)
  2790. return OperateResult.CreateSuccessResult( content )
  2791. def Write( self, address, value ):
  2792. '''向PLC写入数据,数据格式为原始的字节类型'''
  2793. # 解析指令
  2794. command = MelsecMcAsciiNet.BuildWriteCommand( address, value, self.NetworkNumber, self.NetworkStationNumber )
  2795. if command.IsSuccess == False : return command
  2796. # 核心交互
  2797. read = self.ReadFromCoreServer( command.Content )
  2798. if read.IsSuccess == False : return read
  2799. # 错误码验证
  2800. errorCode = int( read.Content[18:22].decode('ascii'), 16 )
  2801. if errorCode != 0 : return OperateResult( err = errorCode, msg = StringResources.MelsecPleaseReferToManulDocument() )
  2802. # 写入成功
  2803. return OperateResult.CreateSuccessResult( )
  2804. def WriteBool( self, address, values ):
  2805. '''向PLC中位软元件写入bool数组,返回值说明,比如你写入M100,values[0]对应M100'''
  2806. if type(values) == list:
  2807. buffer = bytearray(len(values))
  2808. for i in range(len(buffer)):
  2809. buffer[i] = 0x01 if values[i] == True else 0x00
  2810. return self.Write( address, buffer )
  2811. else:
  2812. return self.WriteBool( address, [values] )
  2813. # 西门子的数据类
  2814. class SiemensPLCS(Enum):
  2815. '''西门子PLC的类对象'''
  2816. S1200 = 0
  2817. S300 = 1
  2818. S1500 = 2
  2819. S200Smart = 3
  2820. class SiemensS7Net(NetworkDeviceBase):
  2821. '''一个西门子的客户端类,使用S7协议来进行数据交互'''
  2822. CurrentPlc = SiemensPLCS.S1200
  2823. plcHead1 = bytearray([0x03,0x00,0x00,0x16,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC0,0x01,0x0A,0xC1,0x02,0x01,0x02,0xC2,0x02,0x01,0x00])
  2824. plcHead2 = bytearray([0x03,0x00,0x00,0x19,0x02,0xF0,0x80,0x32,0x01,0x00,0x00,0x04,0x00,0x00,0x08,0x00,0x00,0xF0,0x00,0x00,0x01,0x00,0x01,0x01,0xE0])
  2825. plcOrderNumber = bytearray([0x03,0x00,0x00,0x21,0x02,0xF0,0x80,0x32,0x07,0x00,0x00,0x00,0x01,0x00,0x08,0x00,0x08,0x00,0x01,0x12,0x04,0x11,0x44,0x01,0x00,0xFF,0x09,0x00,0x04,0x00,0x11,0x00,0x00])
  2826. plcHead1_200smart = bytearray([0x03,0x00,0x00,0x16,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,0x02,0x10,0x00,0xC2,0x02,0x03,0x00,0xC0,0x01,0x0A])
  2827. plcHead2_200smart = bytearray([0x03,0x00,0x00,0x19,0x02,0xF0,0x80,0x32,0x01,0x00,0x00,0xCC,0xC1,0x00,0x08,0x00,0x00,0xF0,0x00,0x00,0x01,0x00,0x01,0x03,0xC0])
  2828. def __init__(self, siemens, ipAddress = "127.0.0.1",port = 102):
  2829. '''实例化一个西门子的S7协议的通讯对象并指定Ip地址'''
  2830. self.WordLength = 2
  2831. self.ipAddress = ipAddress
  2832. self.port = port
  2833. self.CurrentPlc = siemens
  2834. self.iNetMessage = S7Message()
  2835. self.byteTransform = ReverseBytesTransform()
  2836. if siemens == SiemensPLCS.S1200:
  2837. self.plcHead1[21] = 0
  2838. elif siemens == SiemensPLCS.S300:
  2839. self.plcHead1[21] = 2
  2840. elif siemens == SiemensPLCS.S1500:
  2841. self.plcHead1[21] = 0
  2842. elif siemens == SiemensPLCS.S200Smart:
  2843. self.plcHead1 = self.plcHead1_200smart
  2844. self.plcHead2 = self.plcHead2_200smart
  2845. else:
  2846. self.plcHead1[18] = 0
  2847. @staticmethod
  2848. def CalculateAddressStarted( address = "M0" ):
  2849. '''计算特殊的地址信息'''
  2850. if address.find('.') >= 0:
  2851. temp = address.split(".")
  2852. return int(temp[0]) * 8 + int(temp[1])
  2853. else:
  2854. return int( address ) * 8
  2855. @staticmethod
  2856. def AnalysisAddress( address = 'M0' ):
  2857. '''解析数据地址,解析出地址类型,起始地址,DB块的地址'''
  2858. result = OperateResult( )
  2859. try:
  2860. result.Content3 = 0
  2861. if address[0] == 'I':
  2862. result.Content1 = 0x81
  2863. result.Content2 = SiemensS7Net.CalculateAddressStarted( address[1:] )
  2864. elif address[0] == 'Q':
  2865. result.Content1 = 0x82
  2866. result.Content2 = SiemensS7Net.CalculateAddressStarted( address[1:] )
  2867. elif address[0] == 'M':
  2868. result.Content1 = 0x83
  2869. result.Content2 = SiemensS7Net.CalculateAddressStarted( address[1:] )
  2870. elif address[0] == 'D' or address[0:2] == "DB":
  2871. result.Content1 = 0x84
  2872. adds = address.split(".")
  2873. if address[1] == 'B':
  2874. result.Content3 = int( adds[0][2:] )
  2875. else:
  2876. result.Content3 = int( adds[0][1:] )
  2877. result.Content2 = SiemensS7Net.CalculateAddressStarted( address[ (address.find( '.' ) + 1):])
  2878. elif address[0] == 'T':
  2879. result.Content1 = 0x1D
  2880. result.Content2 = SiemensS7Net.CalculateAddressStarted( address[1:] )
  2881. elif address[0] == 'C':
  2882. result.Content1 = 0x1C
  2883. result.Content2 = SiemensS7Net.CalculateAddressStarted( address[1:] )
  2884. elif address[0] == 'V':
  2885. result.Content1 = 0x84
  2886. result.Content3 = 1
  2887. result.Content2 = SiemensS7Net.CalculateAddressStarted( address[1:] )
  2888. else:
  2889. result.Message = StringResources.NotSupportedDataType()
  2890. result.Content1 = 0
  2891. result.Content2 = 0
  2892. result.Content3 = 0
  2893. return result
  2894. except Exception as ex:
  2895. result.Message = str(ex)
  2896. return result
  2897. result.IsSuccess = True
  2898. return result
  2899. @staticmethod
  2900. def BuildReadCommand( address, length ):
  2901. '''生成一个读取字数据指令头的通用方法'''
  2902. if address == None : raise Exception( "address" )
  2903. if length == None : raise Exception( "count" )
  2904. if len(address) != len(length) : raise Exception( "两个参数的个数不统一" )
  2905. if len(length) > 19 : raise Exception( "读取的数组数量不允许大于19" )
  2906. readCount = len(length)
  2907. _PLCCommand = bytearray(19 + readCount * 12)
  2908. # ======================================================================================
  2909. _PLCCommand[0] = 0x03 # 报文头
  2910. _PLCCommand[1] = 0x00
  2911. _PLCCommand[2] = len(_PLCCommand) // 256 # 长度
  2912. _PLCCommand[3] = len(_PLCCommand) % 256
  2913. _PLCCommand[4] = 0x02 # 固定
  2914. _PLCCommand[5] = 0xF0
  2915. _PLCCommand[6] = 0x80
  2916. _PLCCommand[7] = 0x32 # 协议标识
  2917. _PLCCommand[8] = 0x01 # 命令:发
  2918. _PLCCommand[9] = 0x00 # redundancy identification (reserved): 0x0000;
  2919. _PLCCommand[10] = 0x00 # protocol data unit reference; it’s increased by request event;
  2920. _PLCCommand[11] = 0x00
  2921. _PLCCommand[12] = 0x01 # 参数命令数据总长度
  2922. _PLCCommand[13] = (len(_PLCCommand) - 17) // 256
  2923. _PLCCommand[14] = (len(_PLCCommand) - 17) % 256
  2924. _PLCCommand[15] = 0x00 # 读取内部数据时为00,读取CPU型号为Data数据长度
  2925. _PLCCommand[16] = 0x00
  2926. # =====================================================================================
  2927. _PLCCommand[17] = 0x04 # 读写指令,04读,05写
  2928. _PLCCommand[18] = readCount # 读取数据块个数
  2929. for ii in range(readCount):
  2930. #===========================================================================================
  2931. # 指定有效值类型
  2932. _PLCCommand[19 + ii * 12] = 0x12
  2933. # 接下来本次地址访问长度
  2934. _PLCCommand[20 + ii * 12] = 0x0A
  2935. # 语法标记,ANY
  2936. _PLCCommand[21 + ii * 12] = 0x10
  2937. # 按字为单位
  2938. _PLCCommand[22 + ii * 12] = 0x02
  2939. # 访问数据的个数
  2940. _PLCCommand[23 + ii * 12] = length[ii] // 256
  2941. _PLCCommand[24 + ii * 12] = length[ii] % 256
  2942. # DB块编号,如果访问的是DB块的话
  2943. _PLCCommand[25 + ii * 12] = address[ii].Content3 // 256
  2944. _PLCCommand[26 + ii * 12] = address[ii].Content3 % 256
  2945. # 访问数据类型
  2946. _PLCCommand[27 + ii * 12] = address[ii].Content1
  2947. # 偏移位置
  2948. _PLCCommand[28 + ii * 12] = address[ii].Content2 // 256 // 256 % 256
  2949. _PLCCommand[29 + ii * 12] = address[ii].Content2 // 256 % 256
  2950. _PLCCommand[30 + ii * 12] = address[ii].Content2 % 256
  2951. return OperateResult.CreateSuccessResult( _PLCCommand )
  2952. @staticmethod
  2953. def BuildBitReadCommand( address ):
  2954. '''生成一个位读取数据指令头的通用方法'''
  2955. analysis = SiemensS7Net.AnalysisAddress( address )
  2956. if analysis.IsSuccess == False : return OperateResult.CreateFailedResult( analysis )
  2957. _PLCCommand = bytearray(31)
  2958. # 报文头
  2959. _PLCCommand[0] = 0x03
  2960. _PLCCommand[1] = 0x00
  2961. # 长度
  2962. _PLCCommand[2] = len(_PLCCommand) // 256
  2963. _PLCCommand[3] = len(_PLCCommand) % 256
  2964. # 固定
  2965. _PLCCommand[4] = 0x02
  2966. _PLCCommand[5] = 0xF0
  2967. _PLCCommand[6] = 0x80
  2968. _PLCCommand[7] = 0x32
  2969. # 命令:发
  2970. _PLCCommand[8] = 0x01
  2971. # 标识序列号
  2972. _PLCCommand[9] = 0x00
  2973. _PLCCommand[10] = 0x00
  2974. _PLCCommand[11] = 0x00
  2975. _PLCCommand[12] = 0x01
  2976. # 命令数据总长度
  2977. _PLCCommand[13] = (len(_PLCCommand) - 17) // 256
  2978. _PLCCommand[14] = (len(_PLCCommand) - 17) % 256
  2979. _PLCCommand[15] = 0x00
  2980. _PLCCommand[16] = 0x00
  2981. # 命令起始符
  2982. _PLCCommand[17] = 0x04
  2983. # 读取数据块个数
  2984. _PLCCommand[18] = 0x01
  2985. #===========================================================================================
  2986. # 读取地址的前缀
  2987. _PLCCommand[19] = 0x12
  2988. _PLCCommand[20] = 0x0A
  2989. _PLCCommand[21] = 0x10
  2990. # 读取的数据时位
  2991. _PLCCommand[22] = 0x01
  2992. # 访问数据的个数
  2993. _PLCCommand[23] = 0x00
  2994. _PLCCommand[24] = 0x01
  2995. # DB块编号,如果访问的是DB块的话
  2996. _PLCCommand[25] = analysis.Content3 // 256
  2997. _PLCCommand[26] = analysis.Content3 % 256
  2998. # 访问数据类型
  2999. _PLCCommand[27] = analysis.Content1
  3000. # 偏移位置
  3001. _PLCCommand[28] = analysis.Content2 // 256 // 256 % 256
  3002. _PLCCommand[29] = analysis.Content2 // 256 % 256
  3003. _PLCCommand[30] = analysis.Content2 % 256
  3004. return OperateResult.CreateSuccessResult( _PLCCommand )
  3005. @staticmethod
  3006. def BuildWriteByteCommand( address, data ):
  3007. '''生成一个写入字节数据的指令'''
  3008. if data == None : data = bytearray(0)
  3009. analysis = SiemensS7Net.AnalysisAddress( address )
  3010. if analysis.IsSuccess == False : return OperateResult.CreateFailedResult(analysis)
  3011. _PLCCommand = bytearray(35 + len(data))
  3012. _PLCCommand[0] = 0x03
  3013. _PLCCommand[1] = 0x00
  3014. # 长度
  3015. _PLCCommand[2] = (35 + len(data)) // 256
  3016. _PLCCommand[3] = (35 + len(data)) % 256
  3017. # 固定
  3018. _PLCCommand[4] = 0x02
  3019. _PLCCommand[5] = 0xF0
  3020. _PLCCommand[6] = 0x80
  3021. _PLCCommand[7] = 0x32
  3022. # 命令 发
  3023. _PLCCommand[8] = 0x01
  3024. # 标识序列号
  3025. _PLCCommand[9] = 0x00
  3026. _PLCCommand[10] = 0x00
  3027. _PLCCommand[11] = 0x00
  3028. _PLCCommand[12] = 0x01
  3029. # 固定
  3030. _PLCCommand[13] = 0x00
  3031. _PLCCommand[14] = 0x0E
  3032. # 写入长度+4
  3033. _PLCCommand[15] = (4 + len(data)) // 256
  3034. _PLCCommand[16] = (4 + len(data)) % 256
  3035. # 读写指令
  3036. _PLCCommand[17] = 0x05
  3037. # 写入数据块个数
  3038. _PLCCommand[18] = 0x01
  3039. # 固定,返回数据长度
  3040. _PLCCommand[19] = 0x12
  3041. _PLCCommand[20] = 0x0A
  3042. _PLCCommand[21] = 0x10
  3043. # 写入方式,1是按位,2是按字
  3044. _PLCCommand[22] = 0x02
  3045. # 写入数据的个数
  3046. _PLCCommand[23] = len(data) // 256
  3047. _PLCCommand[24] = len(data) % 256
  3048. # DB块编号,如果访问的是DB块的话
  3049. _PLCCommand[25] = analysis.Content3 // 256
  3050. _PLCCommand[26] = analysis.Content3 % 256
  3051. # 写入数据的类型
  3052. _PLCCommand[27] = analysis.Content1
  3053. # 偏移位置
  3054. _PLCCommand[28] = analysis.Content2 // 256 // 256 % 256
  3055. _PLCCommand[29] = analysis.Content2 // 256 % 256
  3056. _PLCCommand[30] = analysis.Content2 % 256
  3057. # 按字写入
  3058. _PLCCommand[31] = 0x00
  3059. _PLCCommand[32] = 0x04
  3060. # 按位计算的长度
  3061. _PLCCommand[33] = len(data) * 8 // 256
  3062. _PLCCommand[34] = len(data) * 8 % 256
  3063. _PLCCommand[35:] = data
  3064. return OperateResult.CreateSuccessResult(_PLCCommand)
  3065. @staticmethod
  3066. def BuildWriteBitCommand( address, data ):
  3067. analysis = SiemensS7Net.AnalysisAddress( address )
  3068. if analysis.IsSuccess == False : return OperateResult.CreateFailedResult(analysis)
  3069. buffer = bytearray(1)
  3070. if data == True : buffer[0] = 0x01
  3071. _PLCCommand = bytearray(35 + len(buffer))
  3072. _PLCCommand[0] = 0x03
  3073. _PLCCommand[1] = 0x00
  3074. # 长度
  3075. _PLCCommand[2] = (35 + len(buffer)) // 256
  3076. _PLCCommand[3] = (35 + len(buffer)) % 256
  3077. # 固定
  3078. _PLCCommand[4] = 0x02
  3079. _PLCCommand[5] = 0xF0
  3080. _PLCCommand[6] = 0x80
  3081. _PLCCommand[7] = 0x32
  3082. # 命令 发
  3083. _PLCCommand[8] = 0x01
  3084. # 标识序列号
  3085. _PLCCommand[9] = 0x00
  3086. _PLCCommand[10] = 0x00
  3087. _PLCCommand[11] = 0x00
  3088. _PLCCommand[12] = 0x01
  3089. # 固定
  3090. _PLCCommand[13] = 0x00
  3091. _PLCCommand[14] = 0x0E
  3092. # 写入长度+4
  3093. _PLCCommand[15] = (4 + len(buffer)) // 256
  3094. _PLCCommand[16] = (4 + len(buffer)) % 256
  3095. # 命令起始符
  3096. _PLCCommand[17] = 0x05
  3097. # 写入数据块个数
  3098. _PLCCommand[18] = 0x01
  3099. _PLCCommand[19] = 0x12
  3100. _PLCCommand[20] = 0x0A
  3101. _PLCCommand[21] = 0x10
  3102. # 写入方式,1是按位,2是按字
  3103. _PLCCommand[22] = 0x01
  3104. # 写入数据的个数
  3105. _PLCCommand[23] = len(buffer) // 256
  3106. _PLCCommand[24] = len(buffer) % 256
  3107. # DB块编号,如果访问的是DB块的话
  3108. _PLCCommand[25] = analysis.Content3 // 256
  3109. _PLCCommand[26] = analysis.Content3 % 256
  3110. # 写入数据的类型
  3111. _PLCCommand[27] = analysis.Content1
  3112. # 偏移位置
  3113. _PLCCommand[28] = analysis.Content2 // 256 // 256
  3114. _PLCCommand[29] = analysis.Content2 // 256
  3115. _PLCCommand[30] = analysis.Content2 % 256
  3116. # 按位写入
  3117. _PLCCommand[31] = 0x00
  3118. _PLCCommand[32] = 0x03
  3119. # 按位计算的长度
  3120. _PLCCommand[33] = len(buffer) // 256
  3121. _PLCCommand[34] = len(buffer) % 256
  3122. _PLCCommand[35:] = buffer
  3123. return OperateResult.CreateSuccessResult(_PLCCommand)
  3124. def InitializationOnConnect( self, socket ):
  3125. '''连接上服务器后需要进行的二次握手操作'''
  3126. # msg = SoftBasic.ByteToHexString(self.plcHead1, ' ')
  3127. # 第一次握手
  3128. read_first = self.ReadFromCoreServerBase( socket, self.plcHead1 )
  3129. if read_first.IsSuccess == False : return read_first
  3130. # 第二次握手
  3131. read_second = self.ReadFromCoreServerBase( socket, self.plcHead2 )
  3132. if read_second.IsSuccess == False : return read_second
  3133. # 返回成功的信号
  3134. return OperateResult.CreateSuccessResult( )
  3135. def ReadOrderNumber( self ):
  3136. '''从PLC读取订货号信息'''
  3137. read = self.ReadFromCoreServer( self.plcOrderNumber )
  3138. if read.IsSuccess == False : return OperateResult.CreateFailedResult( read )
  3139. return OperateResult.CreateSuccessResult( read.Content[71:92].decode('ascii') )
  3140. def __ReadBase( self, address, length ):
  3141. '''基础的读取方法,外界不应该调用本方法'''
  3142. command = SiemensS7Net.BuildReadCommand( address, length )
  3143. if command.IsSuccess == False : return command
  3144. read = self.ReadFromCoreServer( command.Content )
  3145. if read.IsSuccess == False : return read
  3146. # 分析结果
  3147. receiveCount = 0
  3148. for i in range(len(length)):
  3149. receiveCount += length[i]
  3150. if len(read.Content) >= 21 and read.Content[20] == len(length) :
  3151. buffer = bytearray(receiveCount)
  3152. kk = 0
  3153. ll = 0
  3154. ii = 21
  3155. while ii < len(read.Content):
  3156. if ii + 1 < len(read.Content):
  3157. if read.Content[ii] == 0xFF and read.Content[ii + 1] == 0x04:
  3158. # 有数据
  3159. buffer[ll : ll + length[kk]] = read.Content[ii+4 : ii+4+length[kk]]
  3160. ii += length[kk] + 3
  3161. ll += length[kk]
  3162. kk += 1
  3163. ii += 1
  3164. return OperateResult.CreateSuccessResult( buffer )
  3165. else :
  3166. result = OperateResult()
  3167. result.ErrorCode = read.ErrorCode
  3168. result.Message = "数据块长度校验失败"
  3169. return result
  3170. def Read( self, address, length ):
  3171. '''从PLC读取数据,地址格式为I100,Q100,DB20.100,M100,T100,C100以字节为单位'''
  3172. if type(address) == list and type(length) == list:
  3173. addressResult = []
  3174. for i in range(length):
  3175. tmp = SiemensS7Net.AnalysisAddress( address[i] )
  3176. if tmp.IsSuccess == False : return OperateResult.CreateFailedResult( addressResult[i] )
  3177. addressResult.append( tmp )
  3178. return self.__ReadBase( addressResult, length )
  3179. else:
  3180. addressResult = SiemensS7Net.AnalysisAddress( address )
  3181. if addressResult.IsSuccess == False : return OperateResult.CreateFailedResult( addressResult )
  3182. bytesContent = bytearray()
  3183. alreadyFinished = 0
  3184. while alreadyFinished < length :
  3185. readLength = min( length - alreadyFinished, 200 )
  3186. read = self.__ReadBase( [ addressResult ], [ readLength ] )
  3187. if read.IsSuccess == True :
  3188. bytesContent.extend( read.Content )
  3189. else:
  3190. return read
  3191. alreadyFinished += readLength
  3192. addressResult.Content2 += readLength * 8
  3193. return OperateResult.CreateSuccessResult( bytesContent )
  3194. def __ReadBitFromPLC( self, address ):
  3195. '''从PLC读取数据,地址格式为I100,Q100,DB20.100,M100,以位为单位'''
  3196. # 指令生成
  3197. command = SiemensS7Net.BuildBitReadCommand( address )
  3198. if command.IsSuccess == False : return OperateResult.CreateFailedResult( command )
  3199. # 核心交互
  3200. read = self.ReadFromCoreServer( command.Content )
  3201. if read.IsSuccess == False : return read
  3202. # 分析结果
  3203. receiveCount = 1
  3204. if len(read.Content) >= 21 and read.Content[20] == 1 :
  3205. buffer = bytearray(receiveCount)
  3206. if 22 < len(read.Content) :
  3207. if read.Content[21] == 0xFF and read.Content[22] == 0x03:
  3208. # 有数据
  3209. buffer[0] = read.Content[25]
  3210. return OperateResult.CreateSuccessResult( buffer )
  3211. else:
  3212. result = OperateResult()
  3213. result.ErrorCode = read.ErrorCode
  3214. result.Message = "数据块长度校验失败"
  3215. return result
  3216. def ReadBool( self, address ):
  3217. '''读取指定地址的bool数据'''
  3218. return self.GetBoolResultFromBytes( self.__ReadBitFromPLC( address ) )
  3219. def ReadByte( self, address ):
  3220. '''读取指定地址的byte数据'''
  3221. return self.GetByteResultFromBytes( self.Read( address, 1 ) )
  3222. def __WriteBase( self, entireValue ):
  3223. '''基础的写入数据的操作支持'''
  3224. write = self.ReadFromCoreServer( entireValue )
  3225. if write.IsSuccess == False : return write
  3226. if write.Content[len(write.Content) - 1] != 0xFF :
  3227. # 写入异常
  3228. return OperateResult( msg = "写入数据异常", err = write.Content[write.Content.Length - 1])
  3229. else:
  3230. return OperateResult.CreateSuccessResult( )
  3231. def Write( self, address, value ):
  3232. '''将数据写入到PLC数据,地址格式为I100,Q100,DB20.100,M100,以字节为单位'''
  3233. command = self.BuildWriteByteCommand( address, value )
  3234. if command.IsSuccess == False : return command
  3235. return self.__WriteBase( command.Content )
  3236. def WriteBool( self, address, value ):
  3237. '''写入PLC的一个位,例如"M100.6","I100.7","Q100.0","DB20.100.0",如果只写了"M100"默认为"M100.0'''
  3238. # 生成指令
  3239. command = SiemensS7Net.BuildWriteBitCommand( address, value )
  3240. if command.IsSuccess == False : return command
  3241. return self.__WriteBase( command.Content )
  3242. def WriteByte( self, address, value ):
  3243. '''向PLC中写入byte数据,返回值说明'''
  3244. return self.Write( address, [value] )
  3245. class SiemensFetchWriteNet(NetworkDeviceBase):
  3246. '''使用了Fetch/Write协议来和西门子进行通讯,该种方法需要在PLC侧进行一些配置'''
  3247. def __init__( self, ipAddress = '127.0.0.1', port = 1000 ):
  3248. ''' 实例化一个西门子的Fetch/Write协议的通讯对象,可以指定ip地址及端口号'''
  3249. self.ipAddress = ipAddress
  3250. self.port = port
  3251. self.WordLength = 2
  3252. @staticmethod
  3253. def CalculateAddressStarted( address = "M100" ):
  3254. '''计算特殊的地址信息'''
  3255. if address.find( '.' ) < 0:
  3256. return int( address )
  3257. else:
  3258. temp = address.split( '.' )
  3259. return int( temp[0] )
  3260. @staticmethod
  3261. def AnalysisAddress( address = "M100" ):
  3262. '''解析数据地址,解析出地址类型,起始地址,DB块的地址'''
  3263. result = OperateResult( )
  3264. try:
  3265. result.Content3 = 0
  3266. if address[0] == 'I':
  3267. result.Content1 = 0x03
  3268. result.Content2 = SiemensFetchWriteNet.CalculateAddressStarted( address[1:] )
  3269. elif address[0] == 'Q':
  3270. result.Content1 = 0x04
  3271. result.Content2 = SiemensFetchWriteNet.CalculateAddressStarted( address[1:] )
  3272. elif address[0] == 'M':
  3273. result.Content1 = 0x02
  3274. result.Content2 = SiemensFetchWriteNet.CalculateAddressStarted( address[1:] )
  3275. elif address[0] == 'D' or address.startswith("DB"):
  3276. result.Content1 = 0x01
  3277. adds = address.split( '.' )
  3278. if address[1] == 'B':
  3279. result.Content3 = int( adds[0][2:] )
  3280. else:
  3281. result.Content3 = int( adds[0][1:] )
  3282. if result.Content3 > 255:
  3283. result.Message = "DB块数据无法大于255"
  3284. return result
  3285. result.Content2 = SiemensFetchWriteNet.CalculateAddressStarted( address[ address.find( '.' ) + 1:] )
  3286. elif address[0] == 'T':
  3287. result.Content1 = 0x07
  3288. result.Content2 = SiemensFetchWriteNet.CalculateAddressStarted( address[1:] )
  3289. elif address[0] == 'C':
  3290. result.Content1 = 0x06
  3291. result.Content2 = SiemensFetchWriteNet.CalculateAddressStarted( address[1:])
  3292. else:
  3293. result.Message = StringResources.NotSupportedDataType()
  3294. result.Content1 = 0
  3295. result.Content2 = 0
  3296. result.Content3 = 0
  3297. return result
  3298. except Exception as ex:
  3299. result.Message = str(ex)
  3300. return result
  3301. result.IsSuccess = True
  3302. return result
  3303. @staticmethod
  3304. def BuildReadCommand( address, count ):
  3305. '''生成一个读取字数据指令头的通用方法'''
  3306. result = OperateResult( )
  3307. analysis = SiemensFetchWriteNet.AnalysisAddress( address )
  3308. if analysis.IsSuccess == False :
  3309. result.CopyErrorFromOther( analysis )
  3310. return result
  3311. _PLCCommand = bytearray(16)
  3312. _PLCCommand[0] = 0x53
  3313. _PLCCommand[1] = 0x35
  3314. _PLCCommand[2] = 0x10
  3315. _PLCCommand[3] = 0x01
  3316. _PLCCommand[4] = 0x03
  3317. _PLCCommand[5] = 0x05
  3318. _PLCCommand[6] = 0x03
  3319. _PLCCommand[7] = 0x08
  3320. # 指定数据区
  3321. _PLCCommand[8] = analysis.Content1
  3322. _PLCCommand[9] = analysis.Content3
  3323. # 指定数据地址
  3324. _PLCCommand[10] =analysis.Content2 // 256
  3325. _PLCCommand[11] = analysis.Content2 % 256
  3326. if analysis.Content1 == 0x01 or analysis.Content1 == 0x06 or analysis.Content1 == 0x07:
  3327. if count % 2 != 0:
  3328. result.Message = "读取的数据长度必须为偶数"
  3329. return result
  3330. else:
  3331. # 指定数据长度
  3332. _PLCCommand[12] = count // 2 // 256
  3333. _PLCCommand[13] = count // 2 % 256
  3334. else:
  3335. # 指定数据长度
  3336. _PLCCommand[12] = count // 256
  3337. _PLCCommand[13] = count % 256
  3338. _PLCCommand[14] = 0xff
  3339. _PLCCommand[15] = 0x02
  3340. result.Content = _PLCCommand
  3341. result.IsSuccess = True
  3342. return result
  3343. @staticmethod
  3344. def BuildWriteCommand( address, data ):
  3345. '''生成一个写入字节数据的指令'''
  3346. if data == None : data = bytearray(0)
  3347. result = OperateResult( )
  3348. analysis = SiemensFetchWriteNet.AnalysisAddress( address )
  3349. if analysis.IsSuccess == False:
  3350. result.CopyErrorFromOther( analysis )
  3351. return result
  3352. _PLCCommand = bytearray(16 + len(data))
  3353. _PLCCommand[0] = 0x53
  3354. _PLCCommand[1] = 0x35
  3355. _PLCCommand[2] = 0x10
  3356. _PLCCommand[3] = 0x01
  3357. _PLCCommand[4] = 0x03
  3358. _PLCCommand[5] = 0x03
  3359. _PLCCommand[6] = 0x03
  3360. _PLCCommand[7] = 0x08
  3361. # 指定数据区
  3362. _PLCCommand[8] = analysis.Content1
  3363. _PLCCommand[9] = analysis.Content3
  3364. # 指定数据地址
  3365. _PLCCommand[10] = analysis.Content2 // 256
  3366. _PLCCommand[11] = analysis.Content2 % 256
  3367. if analysis.Content1 == 0x01 or analysis.Content1 == 0x06 or analysis.Content1 == 0x07:
  3368. if data.Length % 2 != 0:
  3369. result.Message = "写入的数据长度必须为偶数"
  3370. return result
  3371. else:
  3372. # 指定数据长度
  3373. _PLCCommand[12] = data.Length // 2 // 256
  3374. _PLCCommand[13] = data.Length // 2 % 256
  3375. else:
  3376. # 指定数据长度
  3377. _PLCCommand[12] = data.Length // 256
  3378. _PLCCommand[13] = data.Length % 256
  3379. _PLCCommand[14] = 0xff
  3380. _PLCCommand[15] = 0x02
  3381. # 放置数据
  3382. _PLCCommand[16:16+len(data)] = data
  3383. result.Content = _PLCCommand
  3384. result.IsSuccess = True
  3385. return result
  3386. def Read( self, address, length ):
  3387. '''从PLC读取数据,地址格式为I100,Q100,DB20.100,M100,T100,C100,以字节为单位'''
  3388. # 指令解析 -> Instruction parsing
  3389. command = SiemensFetchWriteNet.BuildReadCommand( address, length )
  3390. if command.IsSuccess == False : return command
  3391. # 核心交互 -> Core Interactions
  3392. read = self.ReadFromCoreServer( command.Content )
  3393. if read.IsSuccess == False : return read
  3394. # 错误码验证 -> Error code Verification
  3395. if read.Content[8] != 0x00 : return OperateResult(read.Content[8],"发生了异常,具体信息查找Fetch/Write协议文档")
  3396. # 读取正确 -> Read Right
  3397. buffer = bytearray(len(read.Content) - 16)
  3398. buffer[0:len(buffer)] = read.Content[16:16+len(buffer)]
  3399. return OperateResult.CreateSuccessResult( buffer )
  3400. def ReadByte( self, address ):
  3401. '''读取指定地址的byte数据'''
  3402. return self.GetByteResultFromBytes( self.Read( address, 1 ) )
  3403. def Write( self, address, value ):
  3404. '''将数据写入到PLC数据,地址格式为I100,Q100,DB20.100,M100,以字节为单位'''
  3405. # 指令解析 -> Instruction parsing
  3406. command = SiemensFetchWriteNet.BuildWriteCommand( address, value )
  3407. if command.IsSuccess == False : return command
  3408. # 核心交互 -> Core Interactions
  3409. write = self.ReadFromCoreServer( command.Content )
  3410. if write.IsSuccess == False : return write
  3411. # 错误码验证 -> Error code Verification
  3412. if (write.Content[8] != 0x00) : OperateResult(err = write.Content[8], msg = "西门子PLC写入失败!")
  3413. # 写入成功 -> Write Right
  3414. return OperateResult.CreateSuccessResult( )
  3415. def WriteBool( self, address, values):
  3416. '''向PLC中写入byte数据,返回是否写入成功 -> Writes byte data to the PLC and returns whether the write succeeded'''
  3417. if type(values) == list:
  3418. return self.Write( address, SoftBasic.BoolArrayToByte( values ) )
  3419. else:
  3420. return self.WriteBool( address, [ values ] )
  3421. # Omron PLC 通讯类
  3422. class OmronFinsDataType:
  3423. '''欧姆龙的Fins协议的数据类型'''
  3424. BitCode = 0
  3425. WordCode = 0
  3426. def __init__(self, bitCode = 0, wordCode = 0):
  3427. '''实例化一个Fins的数据类型'''
  3428. self.BitCode = bitCode
  3429. self.WordCode = wordCode
  3430. @staticmethod
  3431. def DM():
  3432. '''DM Area'''
  3433. return OmronFinsDataType( 0x02, 0x82 )
  3434. @staticmethod
  3435. def CIO():
  3436. '''CIO Area'''
  3437. return OmronFinsDataType( 0x30, 0xB0 )
  3438. @staticmethod
  3439. def WR():
  3440. '''Work Area'''
  3441. return OmronFinsDataType( 0x31, 0xB1 )
  3442. @staticmethod
  3443. def HR():
  3444. '''Holding Bit Area'''
  3445. return OmronFinsDataType( 0x32, 0xB2 )
  3446. @staticmethod
  3447. def AR():
  3448. '''Auxiliary Bit Area'''
  3449. return OmronFinsDataType( 0x33, 0xB3 )
  3450. class OmronFinsNet(NetworkDoubleBase):
  3451. '''欧姆龙PLC通讯类,采用Fins-Tcp通信协议实现'''
  3452. def __init__(self,ipAddress="127.0.0.1",port = 1000):
  3453. '''实例化一个欧姆龙PLC Fins帧协议的通讯对象'''
  3454. self.ipAddress = ipAddress
  3455. self.port = port
  3456. ICF = 0
  3457. RSV = 0
  3458. GCT = 0
  3459. DNA = 0
  3460. DA1 = 0
  3461. DA2 = 0
  3462. SNA = 0
  3463. SA1 = 0
  3464. SA2 = 0
  3465. SID = 0
  3466. def SetSA1(self, value):
  3467. '''设置SA1的方法'''
  3468. self.SA1 = value
  3469. self.handSingle[19] = value
  3470. handSingle = bytearray([0x46, 0x49, 0x4E, 0x53,0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01])
  3471. @staticmethod
  3472. def AnalysisAddress( address, isBit ):
  3473. result = OperateResult( )
  3474. try:
  3475. if address[0] == 'D' or address[0] == 'd':
  3476. # DM区数据
  3477. result.Content1 = OmronFinsDataType.DM
  3478. elif address[0] == 'C' or address[0] == 'c':
  3479. # CIO区数据
  3480. result.Content1 = OmronFinsDataType.CIO
  3481. elif address[0] == 'W' or address[0] == 'w':
  3482. # WR区
  3483. result.Content1 = OmronFinsDataType.WR
  3484. elif address[0] == 'H' or address[0] == 'h':
  3485. # HR区
  3486. result.Content1 = OmronFinsDataType.HR
  3487. elif address[0] == 'A' or address[0] == 'a':
  3488. # AR区
  3489. result.Content1 = OmronFinsDataType.AR
  3490. else:
  3491. raise RuntimeError( StringResources.NotSupportedDataType() )
  3492. if isBit == True:
  3493. # 位操作
  3494. splits = address[1:].split('.')
  3495. addr = int( splits[0] )
  3496. result.Content2 = bytearray(3)
  3497. result.Content2[0] = struct.pack('<H', addr )[1]
  3498. result.Content2[1] = struct.pack('<H', addr )[0]
  3499. if len(splits) > 1:
  3500. result.Content2[2] = int(splits[1])
  3501. if result.Content2[2] > 15:
  3502. raise RuntimeError( "欧姆龙位地址必须0-15之间" )
  3503. else:
  3504. # 字操作
  3505. addr = int( address[1:] )
  3506. result.Content2 = bytearray(3)
  3507. result.Content2[0] = struct.pack('<H', addr )[1]
  3508. result.Content2[1] = struct.pack('<H', addr )[0]
  3509. except Exception as ex:
  3510. result.Message = str(ex)
  3511. return result
  3512. result.IsSuccess = True
  3513. return result
  3514. @staticmethod
  3515. def ResponseValidAnalysis( response, isRead ):
  3516. # 数据有效性分析
  3517. if len(response) >= 16:
  3518. # 提取错误码
  3519. buffer = bytearray(4)
  3520. buffer[0] = response[15]
  3521. buffer[1] = response[14]
  3522. buffer[2] = response[13]
  3523. buffer[3] = response[12]
  3524. err = struct.unpack( '<i' , buffer )[0]
  3525. if err > 0 : return OperateResult( err = err, msg = OmronFinsNet.GetStatusDescription( err ) )
  3526. if response.Length >= 30:
  3527. err = response[28] * 256 + response[29]
  3528. if err > 0 : return OperateResult( err = err, msg = "欧姆龙数据接收出错" )
  3529. if isRead == False : return OperateResult.CreateSuccessResult( bytearray(0) )
  3530. # 读取操作
  3531. content = bytearray(len(response) - 30)
  3532. if len(content) > 0 :
  3533. content[0:len(content)] = response[30:]
  3534. return OperateResult.CreateSuccessResult( content )
  3535. return OperateResult( msg = "欧姆龙数据接收出错" )
  3536. @staticmethod
  3537. def GetStatusDescription( err ):
  3538. '''获取错误信息的字符串描述文本'''
  3539. if err == 0: return StringResources.OmronStatus0()
  3540. elif err == 1: return StringResources.OmronStatus1()
  3541. elif err == 2: return StringResources.OmronStatus2()
  3542. elif err == 3: return StringResources.OmronStatus3()
  3543. elif err == 20: return StringResources.OmronStatus20()
  3544. elif err == 21: return StringResources.OmronStatus21()
  3545. elif err == 22: return StringResources.OmronStatus22()
  3546. elif err == 23: return StringResources.OmronStatus23()
  3547. elif err == 24: return StringResources.OmronStatus24()
  3548. elif err == 25: return StringResources.OmronStatus25()
  3549. else: return StringResources.UnknownError()
  3550. def PackCommand( self, cmd ):
  3551. '''将普通的指令打包成完整的指令'''
  3552. buffer = bytearray(26 + len(cmd))
  3553. buffer[0:4] = self.handSingle[0:4]
  3554. tmp = struct.pack('>i', len(buffer) - 8 )
  3555. buffer[4:8] = tmp
  3556. buffer[11] = 0x02
  3557. buffer[16] = self.ICF
  3558. buffer[17] = self.RSV
  3559. buffer[18] = self.GCT
  3560. buffer[19] = self.DNA
  3561. buffer[20] = self.DA1
  3562. buffer[21] = self.DA2
  3563. buffer[22] = self.SNA
  3564. buffer[23] = self.SA1
  3565. buffer[24] = self.SA2
  3566. buffer[25] = self.SID
  3567. buffer[26:] = cmd
  3568. return buffer
  3569. def BuildReadCommand( self, address, length , isBit):
  3570. '''根据类型地址长度确认需要读取的指令头'''
  3571. analysis = OmronFinsNet.AnalysisAddress( address, isBit )
  3572. if analysis.IsSuccess == False : return OperateResult.CreateFailedResult( analysis )
  3573. _PLCCommand = bytearray(8)
  3574. _PLCCommand[0] = 0x01
  3575. _PLCCommand[1] = 0x01
  3576. if isBit == True:
  3577. _PLCCommand[2] = analysis.Content1.BitCode
  3578. else:
  3579. _PLCCommand[2] = analysis.Content1.WordCode
  3580. _PLCCommand[3:6] = analysis.Content2
  3581. _PLCCommand[6] = length / 256
  3582. _PLCCommand[7] = length % 256
  3583. return OperateResult.CreateSuccessResult( self.PackCommand( _PLCCommand ) )
  3584. def BuildWriteCommand( self, address, value, isBit ):
  3585. '''根据类型地址以及需要写入的数据来生成指令头'''
  3586. analysis = self.AnalysisAddress( address, isBit )
  3587. if analysis.IsSuccess == False : return OperateResult.CreateFailedResult( analysis )
  3588. _PLCCommand = bytearray(8 + len(value))
  3589. _PLCCommand[0] = 0x01
  3590. _PLCCommand[1] = 0x02
  3591. if isBit == True:
  3592. _PLCCommand[2] = analysis.Content1.BitCode
  3593. else:
  3594. _PLCCommand[2] = analysis.Content1.WordCode
  3595. _PLCCommand[3:6] = analysis.Content2
  3596. if isBit == True:
  3597. _PLCCommand[6] = len(value) // 256
  3598. _PLCCommand[7] = len(value) % 256
  3599. else:
  3600. _PLCCommand[6] = len(value) // 2 // 256
  3601. _PLCCommand[7] = len(value) // 2 % 256
  3602. _PLCCommand[8:] = value
  3603. return OperateResult.CreateSuccessResult( self.PackCommand( _PLCCommand ) )
  3604. def InitializationOnConnect( self, socket ):
  3605. '''在连接上欧姆龙PLC后,需要进行一步握手协议'''
  3606. # 握手信号
  3607. read = self.ReadFromCoreServerBase( socket, self.handSingle )
  3608. if read.IsSuccess == False : return read
  3609. # 检查返回的状态
  3610. buffer = bytearray(4)
  3611. buffer[0] = read.Content2[7]
  3612. buffer[1] = read.Content2[6]
  3613. buffer[2] = read.Content2[5]
  3614. buffer[3] = read.Content2[4]
  3615. status = struct.unpack( '<i',buffer )[0]
  3616. if status != 0 : return OperateResult( err = status, msg = OmronFinsNet.GetStatusDescription( status ) )
  3617. # 提取PLC的节点地址
  3618. if read.Content2.Length >= 16 : self.DA1 = read.Content2[15]
  3619. return OperateResult.CreateSuccessResult( )
  3620. def Read( self, address, length ):
  3621. '''从欧姆龙PLC中读取想要的数据,返回读取结果,读取单位为字'''
  3622. # 获取指令
  3623. command = self.BuildReadCommand( address, length, False )
  3624. if command.IsSuccess == False : return OperateResult.CreateFailedResult( command )
  3625. # 核心数据交互
  3626. read = self.ReadFromCoreServer( command.Content )
  3627. if read.IsSuccess == False : return OperateResult.CreateFailedResult( read )
  3628. # 数据有效性分析
  3629. valid = OmronFinsNet.ResponseValidAnalysis( read.Content, True )
  3630. if valid.IsSuccess == False : return OperateResult.CreateFailedResult( valid )
  3631. # 读取到了正确的数据
  3632. return OperateResult.CreateSuccessResult( valid.Content )
  3633. def ReadBool( self, address, length = None ):
  3634. '''从欧姆龙PLC中批量读取位软元件,返回读取结果'''
  3635. if length == None:
  3636. read = self.ReadBool( address, 1 )
  3637. if read.IsSuccess == False : return OperateResult.CreateFailedResult( read )
  3638. return OperateResult.CreateSuccessResult( read.Content[0] )
  3639. else:
  3640. # 获取指令
  3641. command = self.BuildReadCommand( address, length, True )
  3642. if command.IsSuccess == False : return OperateResult.CreateFailedResult( command )
  3643. # 核心数据交互
  3644. read = self.ReadFromCoreServer( command.Content )
  3645. if read.IsSuccess == False : return OperateResult.CreateFailedResult( read )
  3646. # 数据有效性分析
  3647. valid = OmronFinsNet.ResponseValidAnalysis( read.Content, True )
  3648. if valid.IsSuccess == False : return OperateResult.CreateFailedResult( valid )
  3649. # 返回正确的数据信息
  3650. content = []
  3651. for i in range(len(read.Content)):
  3652. if read.Content[i] == 0x01:
  3653. content.append(True)
  3654. else:
  3655. content.append(False)
  3656. return OperateResult.CreateSuccessResult( content )
  3657. def Write( self, address, value ):
  3658. '''向PLC中位软元件写入bool数组,返回值说明,比如你写入D100,values[0]对应D100.0'''
  3659. # 获取指令
  3660. command = self.BuildWriteCommand( address, value, False )
  3661. if command.IsSuccess == False : return command
  3662. # 核心数据交互
  3663. read = self.ReadFromCoreServer( command.Content )
  3664. if read.IsSuccess == False : return read
  3665. # 数据有效性分析
  3666. valid = OmronFinsNet.ResponseValidAnalysis( read.Content, False )
  3667. if valid.IsSuccess == False : return valid
  3668. # 成功
  3669. return OperateResult.CreateSuccessResult( )
  3670. def WriteBool( self, address, values ):
  3671. '''向PLC中位软元件写入bool数组,返回值说明,比如你写入D100,values[0]对应D100.0'''
  3672. if type(values) == list:
  3673. # 获取指令
  3674. content = bytearray(len(values))
  3675. for i in range(len(values)):
  3676. if values[i] == True:
  3677. content[i] = 0x01
  3678. else:
  3679. content[i] = 0x00
  3680. command = self.BuildWriteCommand( address, content, True )
  3681. if command.IsSuccess == False : return command
  3682. # 核心数据交互
  3683. read = self.ReadFromCoreServer( command.Content )
  3684. if read.IsSuccess == False : return read
  3685. # 数据有效性分析
  3686. valid = OmronFinsNet.ResponseValidAnalysis( read.Content, False )
  3687. if valid.IsSuccess == False : return valid
  3688. # 写入成功
  3689. return OperateResult.CreateSuccessResult( )
  3690. else:
  3691. return self.WriteBool( address, [values] )
  3692. # NetSimplifyClient类
  3693. class NetSimplifyClient(NetworkDoubleBase):
  3694. '''异步访问数据的客户端类,用于向服务器请求一些确定的数据信息'''
  3695. def __init__(self, ipAddress, port):
  3696. '''实例化一个客户端的对象,用于和服务器通信'''
  3697. self.iNetMessage = HslMessage()
  3698. self.byteTransform = RegularByteTransform()
  3699. self.ipAddress = ipAddress
  3700. self.port = port
  3701. def ReadBytesFromServer( self, customer, send = None):
  3702. '''客户端向服务器进行请求,请求字节数据'''
  3703. return self.__ReadFromServerBase( HslProtocol.CommandBytes( customer, self.Token, send))
  3704. def ReadStringFromServer( self, customer, send = None):
  3705. '''客户端向服务器进行请求,请求字符串数据'''
  3706. read = self.__ReadFromServerBase( HslProtocol.CommandString( customer, self.Token, send))
  3707. if read.IsSuccess == False:
  3708. return OperateResult.CreateFailedResult( read )
  3709. return OperateResult.CreateSuccessResult( read.Content.decode('utf-16') )
  3710. def __ReadFromServerBase( self, send):
  3711. '''需要发送的底层数据'''
  3712. read = self.ReadFromCoreServer( send )
  3713. if read.IsSuccess == False:
  3714. return read
  3715. headBytes = bytearray(HslProtocol.HeadByteLength())
  3716. contentBytes = bytearray(len(read.Content) - HslProtocol.HeadByteLength())
  3717. headBytes[0:HslProtocol.HeadByteLength()] = read.Content[0:HslProtocol.HeadByteLength()]
  3718. if len(contentBytes) > 0:
  3719. contentBytes[0:len(contentBytes)] = read.Content[HslProtocol.HeadByteLength():len(read.Content)]
  3720. contentBytes = HslProtocol.CommandAnalysis( headBytes, contentBytes )
  3721. return OperateResult.CreateSuccessResult( contentBytes )
  3722. class AppSession:
  3723. '''网络会话信息'''
  3724. IpAddress = "127.0.0.1"
  3725. Port = 12345
  3726. LoginAlias = ""
  3727. HeartTime = None
  3728. ClientType = ""
  3729. ClientUniqueID = ""
  3730. BytesHead = bytearray(32)
  3731. BytesContent = bytearray(0)
  3732. KeyGroup = ""
  3733. WorkSocket = socket.socket()
  3734. HybirdLockSend = threading.Lock()
  3735. def __init__( self ):
  3736. self.ClientUniqueID = SoftBasic.GetUniqueStringByGuidAndRandom()
  3737. self.HeartTime = datetime.datetime.now()
  3738. def Clear( self ):
  3739. self.BytesHead = bytearray(HslProtocol.HeadByteLength())
  3740. self.BytesContent = None
  3741. class NetworkXBase(NetworkBase):
  3742. '''多功能网络类的基类'''
  3743. ThreadBack = None
  3744. def __init__(self):
  3745. return
  3746. def SendBytesAsync( self, session, content ):
  3747. '''发送数据的方法'''
  3748. if content == None : return
  3749. session.HybirdLockSend.acquire()
  3750. self.Send( session.WorkSocket, content )
  3751. session.HybirdLockSend.release()
  3752. def ThreadBackground( self, session ):
  3753. while True:
  3754. if session.WorkSocket == None : break
  3755. readHeadBytes = self.Receive(session.WorkSocket,HslProtocol.HeadByteLength())
  3756. if readHeadBytes.IsSuccess == False :
  3757. self.SocketReceiveException( session )
  3758. return
  3759. length = struct.unpack( '<i', readHeadBytes.Content[28:32])[0]
  3760. readContent = self.Receive(session.WorkSocket,length)
  3761. if readContent.IsSuccess == False :
  3762. self.SocketReceiveException( session )
  3763. return
  3764. if self.CheckRemoteToken( readHeadBytes.Content ):
  3765. head = readHeadBytes.Content
  3766. content = HslProtocol.CommandAnalysis(head,readContent.Content)
  3767. protocol = struct.unpack('<i', head[0:4])[0]
  3768. customer = struct.unpack('<i', head[4:8])[0]
  3769. self.DataProcessingCenter(session,protocol,customer,content)
  3770. else:
  3771. self.AppSessionRemoteClose( session )
  3772. def BeginReceiveBackground( self, session ):
  3773. ThreadBack = threading.Thread(target=self.ThreadBackground,args=[session])
  3774. ThreadBack.start()
  3775. def DataProcessingCenter( self, session, protocol, customer, content ):
  3776. '''数据处理中心,应该继承重写'''
  3777. return
  3778. def CheckRemoteToken( self, headBytes ):
  3779. '''检查当前的头子节信息的令牌是否是正确的'''
  3780. return SoftBasic.IsTwoBytesEquel( headBytes,12, SoftBasic.TokenToBytes(self.Token), 0, 16 )
  3781. def SocketReceiveException( self, session ):
  3782. '''接收出错的时候进行处理'''
  3783. return
  3784. def AppSessionRemoteClose( self, session ):
  3785. '''当远端的客户端关闭连接时触发'''
  3786. return
  3787. def SendBaseAndCheckReceive( self, socket, headcode, customer, send ):
  3788. '''[自校验] 发送字节数据并确认对方接收完成数据,如果结果异常,则结束通讯'''
  3789. # 数据处理
  3790. send = HslProtocol.CommandBytesBase( headcode, customer, self.Token, send )
  3791. sendResult = self.Send( socket, send )
  3792. if sendResult.IsSuccess == False: return sendResult
  3793. # 检查对方接收完成
  3794. checkResult = self.ReceiveLong( socket )
  3795. if checkResult.IsSuccess == False: return checkResult
  3796. # 检查长度接收
  3797. if checkResult.Content != len(send):
  3798. self.CloseSocket(socket)
  3799. return OperateResult( msg = "接收的数据数据长度验证失败")
  3800. return checkResult
  3801. def SendBytesAndCheckReceive( self, socket, customer, send ):
  3802. '''[自校验] 发送字节数据并确认对方接收完成数据,如果结果异常,则结束通讯'''
  3803. return self.SendBaseAndCheckReceive( socket, HslProtocol.ProtocolUserBytes(), customer, send )
  3804. def SendStringAndCheckReceive( self, socket, customer, send ):
  3805. '''[自校验] 直接发送字符串数据并确认对方接收完成数据,如果结果异常,则结束通讯'''
  3806. data = SoftBasic.StringToUnicodeBytes(send)
  3807. return self.SendBaseAndCheckReceive( socket, HslProtocol.ProtocolUserString(), customer, data )
  3808. def ReceiveAndCheckBytes( self, socket, timeout ):
  3809. '''[自校验] 接收一条完整的同步数据,包含头子节和内容字节,基础的数据,如果结果异常,则结束通讯'''
  3810. # 30秒超时接收验证
  3811. # if (timeout > 0) ThreadPool.QueueUserWorkItem( new WaitCallback( ThreadPoolCheckTimeOut ), hslTimeOut );
  3812. # 接收头指令
  3813. headResult = self.Receive(socket, HslProtocol.HeadByteLength())
  3814. if headResult.IsSuccess == False:
  3815. return OperateResult.CreateFailedResult(headResult)
  3816. # 检查令牌
  3817. if self.CheckRemoteToken(headResult.Content) == False:
  3818. self.CloseSocket(socket)
  3819. return OperateResult( msg = StringResources.TokenCheckFailed() )
  3820. contentLength = struct.unpack( '<i', headResult.Content[(HslProtocol.HeadByteLength() - 4):])[0]
  3821. # 接收内容
  3822. contentResult = self.Receive(socket, contentLength)
  3823. if contentResult.IsSuccess == False:
  3824. return OperateResult.CreateFailedResult( contentResult )
  3825. # 返回成功信息
  3826. checkResult = self.SendLong(socket, HslProtocol.HeadByteLength() + contentLength)
  3827. if checkResult.IsSuccess == False:
  3828. return OperateResult.CreateFailedResult( checkResult )
  3829. head = headResult.Content
  3830. content = contentResult.Content
  3831. content = HslProtocol.CommandAnalysis(head, content)
  3832. return OperateResult.CreateSuccessResult(head, content)
  3833. def ReceiveStringContentFromSocket( self, socket ):
  3834. '''[自校验] 从网络中接收一个字符串数据,如果结果异常,则结束通讯'''
  3835. receive = self.ReceiveAndCheckBytes(socket, 10000)
  3836. if receive.IsSuccess == False: return OperateResult.CreateFailedResult(receive)
  3837. # 检查是否是字符串信息
  3838. if struct.unpack('<i',receive.Content1[0:4])[0] != HslProtocol.ProtocolUserString():
  3839. self.CloseSocket(socket)
  3840. return OperateResult( msg = "ReceiveStringContentFromSocket异常" )
  3841. if receive.Content2 == None: receive.Content2 = bytearray(0)
  3842. # 分析数据
  3843. return OperateResult.CreateSuccessResult(struct.unpack('<i', receive.Content1[4:8])[0], receive.Content2.decode('utf-16'))
  3844. def ReceiveBytesContentFromSocket( self, socket ):
  3845. '''[自校验] 从网络中接收一串字节数据,如果结果异常,则结束通讯'''
  3846. receive = self.ReceiveAndCheckBytes( socket, 10000 )
  3847. if receive.IsSuccess == False: return OperateResult.CreateFailedResult(receive)
  3848. # 检查是否是字节信息
  3849. if struct.unpack('<i', receive.Content1[0:4])[0] != HslProtocol.ProtocolUserBytes():
  3850. self.CloseSocket(socket)
  3851. return OperateResult( msg = "字节内容检查失败" )
  3852. # 分析数据
  3853. return OperateResult.CreateSuccessResult( struct.unpack('<i', receive.Content1[4:8])[0], receive.Content2 )
  3854. def ReceiveLong( self, socket ):
  3855. '''从网络中接收Long数据'''
  3856. read = self.Receive(socket, 8)
  3857. if read.IsSuccess == False: return OperateResult.CreateFailedResult(read)
  3858. return OperateResult.CreateSuccessResult(struct.unpack('<Q', read.Content)[0])
  3859. def SendLong( self, socket, value ):
  3860. '''将Long数据发送到套接字'''
  3861. return self.Send( socket, struct.pack( '<Q', value ) )
  3862. def CloseSocket(self, socket):
  3863. '''关闭网络'''
  3864. if socket != None:
  3865. socket.close()
  3866. class NetPushClient(NetworkXBase):
  3867. '''发布订阅类的客户端,使用指定的关键订阅相关的数据推送信息'''
  3868. IpAddress = "127.0.0.1"
  3869. Port = 12345
  3870. keyWord = "A"
  3871. ReConnectTime = 10
  3872. action = None
  3873. def __init__( self, ipAddress, port, key):
  3874. '''实例化一个发布订阅类的客户端,需要指定ip地址,端口,及订阅关键字'''
  3875. self.IpAddress = ipAddress
  3876. self.Port = port
  3877. self.keyWord = key
  3878. def DataProcessingCenter( self, session, protocol, customer, content ):
  3879. if protocol == HslProtocol.ProtocolUserString():
  3880. if self.action != None: self.action( self.keyWord, content.decode('utf-16') )
  3881. def SocketReceiveException( self, session ):
  3882. # 发生异常的时候需要进行重新连接
  3883. while True:
  3884. print('NetPushClient wait 10s to reconnect server')
  3885. sleep( self.ReConnectTime )
  3886. if self.CreatePush( ).IsSuccess == True:
  3887. break
  3888. def CreatePush( self, pushCallBack = None ):
  3889. '''创建数据推送服务'''
  3890. if pushCallBack == None:
  3891. if self.CoreSocket != None: self.CoreSocket.close( )
  3892. connect = self.CreateSocketAndConnect( self.IpAddress, self.Port, 5000 )
  3893. if connect.IsSuccess == False: return connect
  3894. send = self.SendStringAndCheckReceive( connect.Content, 0, self.keyWord )
  3895. if send.IsSuccess == False: return send
  3896. receive = self.ReceiveStringContentFromSocket( connect.Content )
  3897. if receive.IsSuccess == False : return receive
  3898. if receive.Content1 != 0: return OperateResult( msg = receive.Content2 )
  3899. appSession = AppSession( )
  3900. self.CoreSocket = connect.Content
  3901. appSession.WorkSocket = connect.Content
  3902. self.BeginReceiveBackground( appSession )
  3903. return OperateResult.CreateSuccessResult( )
  3904. else:
  3905. self.action = pushCallBack
  3906. return self.CreatePush( )
  3907. def ClosePush( self ):
  3908. '''关闭消息推送的界面'''
  3909. self.action = None
  3910. if self.CoreSocket != None:
  3911. self.Send(self.CoreSocket, struct.pack('<i', 100 ) )
  3912. self.CloseSocket(self.CoreSocket)