client.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. # -*- coding: utf-8 -*-
  2. #
  3. # AWL simulator - PLC core server client
  4. #
  5. # Copyright 2013-2015 Michael Buesch <m@bues.ch>
  6. #
  7. # This program is free software; you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation; either version 2 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License along
  18. # with this program; if not, write to the Free Software Foundation, Inc.,
  19. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  20. #
  21. from __future__ import division, absolute_import, print_function, unicode_literals
  22. from awlsim.common.compat import *
  23. from awlsim.common.util import *
  24. from awlsim.common.subprocess import *
  25. from awlsim.coreserver.server import *
  26. from awlsim.coreserver.messages import *
  27. from awlsim.coreserver.memarea import *
  28. import sys
  29. import socket
  30. import errno
  31. import time
  32. class AwlSimClient(object):
  33. def __init__(self):
  34. self.serverProcess = None
  35. self.serverProcessHost = None
  36. self.serverProcessPort = None
  37. self.__transceiver = None
  38. self.__defaultTimeout = 3.0
  39. def spawnServer(self,
  40. interpreter=None,
  41. serverExecutable=None,
  42. listenHost=AwlSimServer.DEFAULT_HOST,
  43. listenPort=AwlSimServer.DEFAULT_PORT):
  44. """Spawn a new AwlSim-core server process.
  45. interpreter -> The python interpreter to use. Must be either:
  46. - None: Use sys.executable as interpreter.
  47. - a string: Use the specified interpreter binary.
  48. - list of strings: Try with the interpreters in the
  49. list, until the first working one is found.
  50. serverExecutable -> The server executable to run.
  51. This has precedence over 'interpreter'.
  52. May be a list of strings.
  53. listenHost -> The hostname or IP address to listen on.
  54. listenPort -> The port to listen on.
  55. Returns the spawned process' PID."""
  56. if self.serverProcess:
  57. raise AwlSimError("Server already running")
  58. if serverExecutable:
  59. for serverExe in toList(serverExecutable):
  60. if not findExecutable(serverExe):
  61. continue
  62. self.serverProcess = AwlSimServer.start(listenHost = listenHost,
  63. listenPort = listenPort,
  64. forkServerProcess = serverExe)
  65. break
  66. else:
  67. raise AwlSimError("Unable to fork any of the supplied "
  68. "server executables: %s" %\
  69. str(toList(serverExecutable)))
  70. else:
  71. if interpreter is None:
  72. interpreter = sys.executable
  73. for interp in toList(interpreter):
  74. if not findExecutable(interp):
  75. continue
  76. self.serverProcess = AwlSimServer.start(listenHost = listenHost,
  77. listenPort = listenPort,
  78. forkInterpreter = interp)
  79. break
  80. else:
  81. raise AwlSimError("Unable to fork an awlsim core server with "
  82. "any of the supplied Python interpreters: %s\n"
  83. "No interpreter found." %\
  84. str(toList(interpreter)))
  85. self.serverProcessHost = listenHost
  86. self.serverProcessPort = listenPort
  87. if isJython:
  88. #XXX Workaround: Jython's socket module does not like connecting
  89. # to a starting server. Wait a few seconds for the server
  90. # to start listening on the socket.
  91. time.sleep(10)
  92. def killSpawnedServer(self):
  93. """Shutdown the server process started with spawnServer()."""
  94. if not self.serverProcess:
  95. return
  96. if self.__transceiver:
  97. try:
  98. msg = AwlSimMessage_SHUTDOWN()
  99. status = self.__sendAndWaitFor_REPLY(msg)
  100. if status != AwlSimMessage_REPLY.STAT_OK:
  101. printError("AwlSimClient: Failed to shut "
  102. "down server via message")
  103. except (AwlSimError, MaintenanceRequest) as e:
  104. pass
  105. self.serverProcess.terminate()
  106. self.serverProcess.wait()
  107. self.serverProcess = None
  108. self.serverProcessHost = None
  109. self.serverProcessPort = None
  110. def connectToServer(self,
  111. host=AwlSimServer.DEFAULT_HOST,
  112. port=AwlSimServer.DEFAULT_PORT,
  113. timeout=3.0):
  114. """Connect to a AwlSim-core server.
  115. host -> The hostname or IP address to connect to.
  116. port -> The port to connect to."""
  117. self.__defaultTimeout = timeout
  118. startTime = monotonic_time()
  119. readableSockaddr = host
  120. try:
  121. family, socktype, sockaddr = AwlSimServer.getaddrinfo(host, port)
  122. if family == AF_UNIX:
  123. readableSockaddr = sockaddr
  124. else:
  125. readableSockaddr = "[%s]:%d" % (sockaddr[0], sockaddr[1])
  126. printInfo("AwlSimClient: Connecting to server '%s'..." % readableSockaddr)
  127. sock = socket.socket(family, socktype)
  128. while 1:
  129. if monotonic_time() - startTime > timeout:
  130. raise AwlSimError("Timeout connecting "
  131. "to AwlSimServer %s" % readableSockaddr)
  132. try:
  133. sock.connect(sockaddr)
  134. except SocketErrors as e:
  135. if e.errno == errno.ECONNREFUSED or\
  136. e.errno == errno.ENOENT:
  137. self.sleep(0.1)
  138. continue
  139. if isJython and\
  140. e.strerror.endswith("java.nio.channels.CancelledKeyException"):
  141. # XXX Jython workaround: Ignore this exception
  142. printInfo("Warning: Jython connect workaround")
  143. continue
  144. raise
  145. break
  146. except SocketErrors as e:
  147. raise AwlSimError("Failed to connect to AwlSimServer %s: %s" %\
  148. (readableSockaddr, str(e)))
  149. printInfo("AwlSimClient: Connected.")
  150. self.__transceiver = AwlSimMessageTransceiver(sock, readableSockaddr)
  151. self.lastRxMsg = None
  152. # Ping the server
  153. try:
  154. self.__transceiver.send(AwlSimMessage_PING())
  155. msg = self.__transceiver.receive(timeout = timeout)
  156. if not msg:
  157. raise AwlSimError("AwlSimClient: Server did not "
  158. "respond to PING request.")
  159. if msg.msgId != AwlSimMessage.MSG_ID_PONG:
  160. raise AwlSimError("AwlSimClient: Server did not "
  161. "respond properly to PING request. "
  162. "(Expected ID %d, but got ID %d)" %\
  163. (AwlSimMessage.MSG_ID_PONG, msg.msgId))
  164. except TransferError as e:
  165. raise AwlSimError("AwlSimClient: PING to server failed")
  166. def shutdownTransceiver(self):
  167. """Shutdown transceiver and close the socket."""
  168. if not self.__transceiver:
  169. return
  170. self.__transceiver.shutdown()
  171. self.__transceiver = None
  172. def shutdown(self):
  173. """Shutdown all sockets and spawned processes."""
  174. self.killSpawnedServer()
  175. self.shutdownTransceiver()
  176. def __rx_NOP(self, msg):
  177. pass # Nothing
  178. def handle_EXCEPTION(self, exception):
  179. raise exception
  180. def __rx_EXCEPTION(self, msg):
  181. self.handle_EXCEPTION(msg.exception)
  182. def __rx_PING(self, msg):
  183. self.__send(AwlSimMessage_PONG())
  184. def handle_PONG(self):
  185. printInfo("AwlSimClient: Received PONG")
  186. def __rx_PONG(self, msg):
  187. self.handle_PONG()
  188. def handle_AWLSRC(self, awlSource):
  189. pass # Don't do anything by default
  190. def __rx_AWLSRC(self, msg):
  191. self.handle_AWLSRC(msg.source)
  192. def handle_SYMTABSRC(self, symTabSource):
  193. pass # Don't do anything by default
  194. def __rx_SYMTABSRC(self, msg):
  195. self.handle_SYMTABSRC(msg.source)
  196. def handle_CPUDUMP(self, dumpText):
  197. pass # Don't do anything by default
  198. def __rx_CPUDUMP(self, msg):
  199. self.handle_CPUDUMP(msg.dumpText)
  200. def __rx_MAINTREQ(self, msg):
  201. raise msg.maintRequest
  202. def handle_MEMORY(self, memAreas):
  203. pass # Don't do anything by default
  204. def __rx_MEMORY(self, msg):
  205. self.handle_MEMORY(msg.memAreas)
  206. if msg.flags & msg.FLG_SYNC:
  207. # The server should never send us a synchronous
  208. # memory image. So just output an error message.
  209. printError("Received synchronous memory request")
  210. def handle_INSNSTATE(self, msg):
  211. pass # Don't do anything by default
  212. def __rx_INSNSTATE(self, msg):
  213. self.handle_INSNSTATE(msg)
  214. def handle_IDENTS(self, msg):
  215. pass # Don't do anything by default
  216. def __rx_IDENTS(self, msg):
  217. self.handle_IDENTS(msg)
  218. def handle_BLOCKINFO(self, msg):
  219. pass # Don't do anything by default
  220. def __rx_BLOCKINFO(self, msg):
  221. self.handle_BLOCKINFO(msg)
  222. __msgRxHandlers = {
  223. AwlSimMessage.MSG_ID_REPLY : __rx_NOP,
  224. AwlSimMessage.MSG_ID_EXCEPTION : __rx_EXCEPTION,
  225. AwlSimMessage.MSG_ID_MAINTREQ : __rx_MAINTREQ,
  226. AwlSimMessage.MSG_ID_PING : __rx_PING,
  227. AwlSimMessage.MSG_ID_PONG : __rx_PONG,
  228. AwlSimMessage.MSG_ID_AWLSRC : __rx_AWLSRC,
  229. AwlSimMessage.MSG_ID_SYMTABSRC : __rx_SYMTABSRC,
  230. AwlSimMessage.MSG_ID_IDENTS : __rx_IDENTS,
  231. AwlSimMessage.MSG_ID_BLOCKINFO : __rx_BLOCKINFO,
  232. AwlSimMessage.MSG_ID_CPUSPECS : __rx_NOP,
  233. AwlSimMessage.MSG_ID_RUNSTATE : __rx_NOP,
  234. AwlSimMessage.MSG_ID_CPUDUMP : __rx_CPUDUMP,
  235. AwlSimMessage.MSG_ID_MEMORY : __rx_MEMORY,
  236. AwlSimMessage.MSG_ID_INSNSTATE : __rx_INSNSTATE,
  237. }
  238. # Main message processing
  239. # timeout: None -> Blocking. Block until packet is received.
  240. # 0 -> No timeout (= Nonblocking). Return immediately.
  241. # x -> Timeout, in seconds.
  242. def processMessages(self, timeout=None):
  243. self.lastRxMsg = None
  244. if not self.__transceiver:
  245. return False
  246. try:
  247. msg = self.__transceiver.receive(timeout)
  248. except TransferError as e:
  249. if e.reason == e.REASON_BLOCKING:
  250. return False
  251. raise AwlSimError("AwlSimClient: "
  252. "I/O error in connection to server '%s':\n"
  253. "%s (errno = %s)" %\
  254. (self.__transceiver.peerInfoString, str(e), str(e.errno)))
  255. except TransferError as e:
  256. raise AwlSimError("AwlSimClient: "
  257. "Connection to server '%s' died. "
  258. "Failed to receive message." %\
  259. self.__transceiver.peerInfoString)
  260. if not msg:
  261. return False
  262. self.lastRxMsg = msg
  263. try:
  264. handler = self.__msgRxHandlers[msg.msgId]
  265. except KeyError:
  266. raise AwlSimError("AwlSimClient: Received unsupported "
  267. "message 0x%02X" % msg.msgId)
  268. handler(self, msg)
  269. return True
  270. def sleep(self, seconds):
  271. time.sleep(seconds)
  272. def __send(self, txMsg):
  273. try:
  274. self.__transceiver.send(txMsg)
  275. except TransferError as e:
  276. raise AwlSimError("AwlSimClient: "
  277. "Send error in connection to server '%s':\n"
  278. "%s (errno = %s)" %\
  279. (self.__transceiver.peerInfoString,
  280. str(e), str(e.errno)))
  281. def __sendAndWait(self, txMsg, checkRxMsg,
  282. waitTimeout=None,
  283. ignoreMaintenanceRequests=False):
  284. self.__send(txMsg)
  285. now = monotonic_time()
  286. end = now + (self.__defaultTimeout if waitTimeout is None\
  287. else waitTimeout)
  288. while now < end:
  289. try:
  290. if self.processMessages(0.1):
  291. rxMsg = self.lastRxMsg
  292. if rxMsg is not None and\
  293. checkRxMsg(rxMsg):
  294. return rxMsg
  295. except MaintenanceRequest as e:
  296. if not ignoreMaintenanceRequests:
  297. raise e
  298. now = monotonic_time()
  299. raise AwlSimError("AwlSimClient: Timeout waiting for server reply.")
  300. def __sendAndWaitFor_REPLY(self, msg, timeout=None,
  301. ignoreMaintenanceRequests=False):
  302. def checkRxMsg(rxMsg):
  303. return rxMsg.msgId == AwlSimMessage.MSG_ID_REPLY and\
  304. rxMsg.inReplyToId == msg.msgId and\
  305. rxMsg.inReplyToSeq == msg.seq
  306. return self.__sendAndWait(msg, checkRxMsg, timeout,
  307. ignoreMaintenanceRequests).status
  308. def reset(self):
  309. if not self.__transceiver:
  310. return False
  311. msg = AwlSimMessage_RESET()
  312. status = self.__sendAndWaitFor_REPLY(msg,
  313. ignoreMaintenanceRequests = True)
  314. if status != AwlSimMessage_REPLY.STAT_OK:
  315. raise AwlSimError("AwlSimClient: Failed to reset CPU")
  316. return True
  317. def setRunState(self, run=True):
  318. if not self.__transceiver:
  319. return False
  320. if run:
  321. runState = AwlSimMessage_RUNSTATE.STATE_RUN
  322. else:
  323. runState = AwlSimMessage_RUNSTATE.STATE_STOP
  324. msg = AwlSimMessage_RUNSTATE(runState)
  325. status = self.__sendAndWaitFor_REPLY(msg,
  326. ignoreMaintenanceRequests = True)
  327. if status != AwlSimMessage_REPLY.STAT_OK:
  328. raise AwlSimError("AwlSimClient: Failed to set run state")
  329. return True
  330. def getRunState(self):
  331. if not self.__transceiver:
  332. return False
  333. msg = AwlSimMessage_GET_RUNSTATE()
  334. rxMsg = self.__sendAndWait(msg,
  335. lambda rxMsg: rxMsg.msgId == AwlSimMessage.MSG_ID_RUNSTATE)
  336. if rxMsg.runState == AwlSimMessage_RUNSTATE.STATE_RUN:
  337. return True
  338. return False
  339. def getAwlSource(self, identHash, sync=True):
  340. if not self.__transceiver:
  341. return False
  342. msg = AwlSimMessage_GET_AWLSRC(identHash)
  343. if sync:
  344. rxMsg = self.__sendAndWait(msg,
  345. lambda rxMsg: rxMsg.msgId == AwlSimMessage.MSG_ID_AWLSRC)
  346. return rxMsg.source
  347. else:
  348. self.__send(msg)
  349. return True
  350. def loadAwlSource(self, awlSource):
  351. if not self.__transceiver:
  352. return False
  353. msg = AwlSimMessage_AWLSRC(awlSource)
  354. self.__transceiver.txCork(True)
  355. try:
  356. status = self.__sendAndWaitFor_REPLY(msg, 10.0)
  357. finally:
  358. self.__transceiver.txCork(False)
  359. if status != AwlSimMessage_REPLY.STAT_OK:
  360. raise AwlSimError("AwlSimClient: Failed to AWL source")
  361. return True
  362. def getSymTabSource(self, identHash, sync=True):
  363. if not self.__transceiver:
  364. return False
  365. msg = AwlSimMessage_GET_SYMTABSRC(identHash)
  366. if sync:
  367. rxMsg = self.__sendAndWait(msg,
  368. lambda rxMsg: rxMsg.msgId == AwlSimMessage.MSG_ID_SYMTABSRC)
  369. return rxMsg.source
  370. else:
  371. self.__send(msg)
  372. return True
  373. def loadSymTabSource(self, symTabSource):
  374. if not self.__transceiver:
  375. return False
  376. msg = AwlSimMessage_SYMTABSRC(symTabSource)
  377. self.__transceiver.txCork(True)
  378. try:
  379. status = self.__sendAndWaitFor_REPLY(msg)
  380. finally:
  381. self.__transceiver.txCork(False)
  382. if status != AwlSimMessage_REPLY.STAT_OK:
  383. raise AwlSimError("AwlSimClient: Failed to load symbol table source")
  384. return True
  385. def loadLibraryBlock(self, libSelection):
  386. if not self.__transceiver:
  387. return False
  388. msg = AwlSimMessage_LIBSEL(libSelection)
  389. status = self.__sendAndWaitFor_REPLY(msg)
  390. if status != AwlSimMessage_REPLY.STAT_OK:
  391. raise AwlSimError("AwlSimClient: Failed to load library block selection")
  392. return True
  393. def loadHardwareModule(self, hwmodDesc):
  394. if not self.__transceiver:
  395. return False
  396. msg = AwlSimMessage_HWMOD(hwmodDesc)
  397. status = self.__sendAndWaitFor_REPLY(msg)
  398. if status != AwlSimMessage_REPLY.STAT_OK:
  399. raise AwlSimError("AwlSimClient: Failed to load hardware module")
  400. return True
  401. def removeSource(self, identHash):
  402. if not self.__transceiver:
  403. return False
  404. msg = AwlSimMessage_REMOVESRC(identHash)
  405. status = self.__sendAndWaitFor_REPLY(msg)
  406. if status != AwlSimMessage_REPLY.STAT_OK:
  407. raise AwlSimError("AwlSimClient: Failed to remove source")
  408. return True
  409. def removeBlock(self, blockInfo):
  410. if not self.__transceiver:
  411. return False
  412. msg = AwlSimMessage_REMOVEBLK(blockInfo)
  413. status = self.__sendAndWaitFor_REPLY(msg)
  414. if status != AwlSimMessage_REPLY.STAT_OK:
  415. raise AwlSimError("AwlSimClient: Failed to remove block")
  416. return True
  417. # Request the (source) ident hashes from the CPU.
  418. # This method is asynchronous.
  419. # The idents are returned via handle_IDENTS()
  420. def requestIdents(self, reqAwlSources = False,
  421. reqSymTabSources = False,
  422. reqHwModules = False,
  423. reqLibSelections = False):
  424. if not self.__transceiver:
  425. return False
  426. self.__send(AwlSimMessage_GET_IDENTS(
  427. (AwlSimMessage_GET_IDENTS.GET_AWLSRCS if reqAwlSources else 0) |\
  428. (AwlSimMessage_GET_IDENTS.GET_SYMTABSRCS if reqSymTabSources else 0) |\
  429. (AwlSimMessage_GET_IDENTS.GET_HWMODS if reqHwModules else 0) |\
  430. (AwlSimMessage_GET_IDENTS.GET_LIBSELS if reqLibSelections else 0)))
  431. return True
  432. # Request the compiled block info from the CPU.
  433. # This method is asynchronous.
  434. # The idents are returned via handle_BLOCKINFO()
  435. def requestBlockInfo(self, reqOBInfo = False,
  436. reqFCInfo = False,
  437. reqFBInfo = False,
  438. reqDBInfo = False):
  439. if not self.__transceiver:
  440. return False
  441. self.__send(AwlSimMessage_GET_BLOCKINFO(
  442. (AwlSimMessage_GET_BLOCKINFO.GET_OB_INFO if reqOBInfo else 0) |\
  443. (AwlSimMessage_GET_BLOCKINFO.GET_FC_INFO if reqFCInfo else 0) |\
  444. (AwlSimMessage_GET_BLOCKINFO.GET_FB_INFO if reqFBInfo else 0) |\
  445. (AwlSimMessage_GET_BLOCKINFO.GET_DB_INFO if reqDBInfo else 0)))
  446. return True
  447. def __setOption(self, name, value, sync=True):
  448. if not self.__transceiver:
  449. return False
  450. msg = AwlSimMessage_OPT(name, str(value))
  451. if sync:
  452. status = self.__sendAndWaitFor_REPLY(msg)
  453. if status != AwlSimMessage_REPLY.STAT_OK:
  454. raise AwlSimError("AwlSimClient: Failed to set option '%s'" % name)
  455. else:
  456. self.__send(msg)
  457. return True
  458. def setLoglevel(self, level=Logging.LOG_INFO):
  459. Logging.setLoglevel(level)
  460. return self.__setOption("loglevel", int(level))
  461. def enableOBTempPresets(self, enable=True):
  462. return self.__setOption("ob_temp_presets", int(bool(enable)))
  463. def enableExtendedInsns(self, enable=True):
  464. return self.__setOption("extended_insns", int(bool(enable)))
  465. def setPeriodicDumpInterval(self, interval=0):
  466. return self.__setOption("periodic_dump_int", int(interval))
  467. def setCycleTimeLimit(self, seconds=5.0):
  468. return self.__setOption("cycle_time_limit", float(seconds))
  469. def setRunTimeLimit(self, seconds=0.0):
  470. return self.__setOption("runtime_limit", float(seconds))
  471. # Set instruction state dumping.
  472. # fromLine, toLine is the range of AWL line numbers for which
  473. # dumping is enabled.
  474. def setInsnStateDump(self, enable=True,
  475. sourceId=0, fromLine=1, toLine=0x7FFFFFFF,
  476. sync=True):
  477. if not self.__transceiver:
  478. return None
  479. msg = AwlSimMessage_INSNSTATE_CONFIG(
  480. flags = 0,
  481. sourceId = sourceId,
  482. fromLine = fromLine,
  483. toLine = toLine)
  484. if enable:
  485. msg.flags |= msg.FLG_CLEAR
  486. else:
  487. msg.flags |= msg.FLG_CLEAR_ONLY
  488. if sync:
  489. msg.flags |= msg.FLG_SYNC
  490. status = self.__sendAndWaitFor_REPLY(msg)
  491. if status != AwlSimMessage_REPLY.STAT_OK:
  492. raise AwlSimError("AwlSimClient: Failed to set insn state dump")
  493. else:
  494. self.__send(msg)
  495. def getCpuSpecs(self):
  496. if not self.__transceiver:
  497. return None
  498. msg = AwlSimMessage_GET_CPUSPECS()
  499. rxMsg = self.__sendAndWait(msg,
  500. lambda rxMsg: rxMsg.msgId == AwlSimMessage.MSG_ID_CPUSPECS)
  501. return rxMsg.cpuspecs
  502. def setCpuSpecs(self, cpuspecs):
  503. if not self.__transceiver:
  504. return False
  505. msg = AwlSimMessage_CPUSPECS(cpuspecs)
  506. status = self.__sendAndWaitFor_REPLY(msg)
  507. if status != AwlSimMessage_REPLY.STAT_OK:
  508. raise AwlSimError("AwlSimClient: Failed to set cpuspecs")
  509. return True
  510. # Set the memory areas we are interested in receiving
  511. # dumps for, in the server.
  512. # memAreas is a list of MemoryArea instances.
  513. # The repetitionPeriod tells whether to
  514. # - only run the request once (repetitionneriod < 0.0)
  515. # - repeat every n'th second (repetitionFactor = n)
  516. # If sync is true, wait for a reply from the server.
  517. def setMemoryReadRequests(self, memAreas, repetitionPeriod = -1.0,
  518. sync = False):
  519. if not self.__transceiver:
  520. return False
  521. msg = AwlSimMessage_REQ_MEMORY(0, repetitionPeriod, memAreas)
  522. if sync:
  523. msg.flags |= msg.FLG_SYNC
  524. status = self.__sendAndWaitFor_REPLY(msg)
  525. if status != AwlSimMessage_REPLY.STAT_OK:
  526. raise AwlSimError("AwlSimClient: Failed to set "
  527. "memory read reqs")
  528. else:
  529. self.__send(msg)
  530. return True
  531. # Write memory areas in the server.
  532. # memAreas is a list of MemoryAreaData instances.
  533. # If sync is true, wait for a reply from the server.
  534. def writeMemory(self, memAreas, sync=False):
  535. if not self.__transceiver:
  536. return False
  537. msg = AwlSimMessage_MEMORY(0, memAreas)
  538. if sync:
  539. msg.flags |= msg.FLG_SYNC
  540. status = self.__sendAndWaitFor_REPLY(msg)
  541. if status != AwlSimMessage_REPLY.STAT_OK:
  542. raise AwlSimError("AwlSimClient: Failed to write "
  543. "to memory")
  544. else:
  545. self.__send(msg)
  546. return True