pyprofibus-linuxcnc-hal 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. #
  4. # PROFIBUS DP - LinuxCNC HAL module
  5. #
  6. # Copyright 2016-2023 Michael Buesch <m@bues.ch>
  7. #
  8. # This program is free software; you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation; either version 2 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License along
  19. # with this program; if not, write to the Free Software Foundation, Inc.,
  20. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. #
  22. from __future__ import division, absolute_import, print_function, unicode_literals
  23. import sys
  24. import os
  25. import time
  26. import getopt
  27. import struct
  28. from pyprofibus import ProfibusError, FdlError, DpError
  29. from pyprofibus.compat import isPy2Compat
  30. from pyprofibus.util import fileExists, FaultDebouncer
  31. from pyprofibus.dp import DpTelegram_SetPrm_Req
  32. from pyprofibus.conf import PbConf, PbConfError
  33. from pyprofibus.version import *
  34. class SigBit:
  35. def __init__(self, hal, halName, byteOffset, bitOffset):
  36. self.hal = hal
  37. self.halName = halName
  38. self.byteOffset = byteOffset
  39. self.bitOffset = bitOffset
  40. self.setMask = 1 << bitOffset
  41. self.clrMask = ~(1 << bitOffset)
  42. def fromHal(self, destBuf):
  43. if self.hal[self.halName]:
  44. destBuf[self.byteOffset] |= self.setMask
  45. else:
  46. destBuf[self.byteOffset] &= self.clrMask
  47. def toHal(self, srcBuf):
  48. self.hal[self.halName] = (srcBuf[self.byteOffset] >> self.bitOffset) & 1
  49. def __str__(self):
  50. return "profibus.%s" % self.halName
  51. class SigU8:
  52. def __init__(self, hal, halName, offset):
  53. self.hal = hal
  54. self.halName = halName
  55. self.offset = offset
  56. def fromHal(self, destBuf):
  57. destBuf[self.offset] = self.hal[self.halName] & 0xFF
  58. def toHal(self, srcBuf):
  59. self.hal[self.halName] = srcBuf[self.offset] & 0xFF
  60. def __str__(self):
  61. return "profibus.%s" % self.halName
  62. class SigU16:
  63. def __init__(self, hal, halName, offset):
  64. self.hal = hal
  65. self.halName = halName
  66. self.offset = offset
  67. def fromHal(self, destBuf):
  68. word = self.hal[self.halName] & 0xFFFF
  69. destBuf[self.offset] = (word >> 8) & 0xFF
  70. destBuf[self.offset + 1] = word & 0xFF
  71. def toHal(self, srcBuf):
  72. word = (srcBuf[self.offset] << 8) |\
  73. srcBuf[self.offset + 1]
  74. self.hal[self.halName] = word & 0xFFFF
  75. def __str__(self):
  76. return "profibus.%s" % self.halName
  77. class SigS16:
  78. def __init__(self, hal, halName, offset):
  79. self.hal = hal
  80. self.halName = halName
  81. self.offset = offset
  82. def fromHal(self, destBuf):
  83. word = self.hal[self.halName] & 0xFFFF
  84. destBuf[self.offset] = (word >> 8) & 0xFF
  85. destBuf[self.offset + 1] = word & 0xFF
  86. def toHal(self, srcBuf):
  87. word = (srcBuf[self.offset] << 8) |\
  88. srcBuf[self.offset + 1]
  89. if word & 0x8000:
  90. self.hal[self.halName] = -((~word + 1) & 0xFFFF)
  91. else:
  92. self.hal[self.halName] = word & 0xFFFF
  93. def __str__(self):
  94. return "profibus.%s" % self.halName
  95. class SigU31:
  96. def __init__(self, hal, halName, offset):
  97. self.hal = hal
  98. self.halName = halName
  99. self.offset = offset
  100. def fromHal(self, destBuf):
  101. dword = self.hal[self.halName] & 0x7FFFFFFF
  102. destBuf[self.offset] = (dword >> 24) & 0xFF
  103. destBuf[self.offset + 1] = (dword >> 16) & 0xFF
  104. destBuf[self.offset + 2] = (dword >> 8) & 0xFF
  105. destBuf[self.offset + 3] = dword & 0xFF
  106. def toHal(self, srcBuf):
  107. dword = (srcBuf[self.offset] << 24) |\
  108. (srcBuf[self.offset + 1] << 16) |\
  109. (srcBuf[self.offset + 2] << 8) |\
  110. srcBuf[self.offset + 3]
  111. self.hal[self.halName] = dword & 0x7FFFFFFF
  112. def __str__(self):
  113. return "profibus.%s" % self.halName
  114. class SigS32:
  115. def __init__(self, hal, halName, offset):
  116. self.hal = hal
  117. self.halName = halName
  118. self.offset = offset
  119. def fromHal(self, destBuf):
  120. dword = self.hal[self.halName] & 0xFFFFFFFF
  121. destBuf[self.offset] = (dword >> 24) & 0xFF
  122. destBuf[self.offset + 1] = (dword >> 16) & 0xFF
  123. destBuf[self.offset + 2] = (dword >> 8) & 0xFF
  124. destBuf[self.offset + 3] = dword & 0xFF
  125. def toHal(self, srcBuf):
  126. dword = (srcBuf[self.offset] << 24) |\
  127. (srcBuf[self.offset + 1] << 16) |\
  128. (srcBuf[self.offset + 2] << 8) |\
  129. srcBuf[self.offset + 3]
  130. if dword & 0x80000000:
  131. self.hal[self.halName] = -((~dword + 1) & 0xFFFFFFFF)
  132. else:
  133. self.hal[self.halName] = dword & 0xFFFFFFFF
  134. def __str__(self):
  135. return "profibus.%s" % self.halName
  136. class SigFloat:
  137. floatStruct = struct.Struct(str('>f'))
  138. def __init__(self, hal, halName, offset):
  139. self.hal = hal
  140. self.halName = halName
  141. self.offset = offset
  142. def fromHal(self, destBuf):
  143. buf = self.floatStruct.pack(self.hal[self.halName])
  144. if isPy2Compat:
  145. buf = [ ord(b) for b in buf ]
  146. destBuf[self.offset : self.offset + 4] = buf[0 : 4]
  147. def toHal(self, srcBuf):
  148. dword = (srcBuf[self.offset] << 24) |\
  149. (srcBuf[self.offset + 1] << 16) |\
  150. (srcBuf[self.offset + 2] << 8) |\
  151. srcBuf[self.offset + 3]
  152. if isPy2Compat:
  153. value = self.floatStruct.unpack(
  154. chr((dword >> 24) & 0xFF) +\
  155. chr((dword >> 16) & 0xFF) +\
  156. chr((dword >> 8) & 0xFF) +\
  157. chr(dword & 0xFF)
  158. )[0]
  159. else:
  160. value = self.floatStruct.unpack(
  161. bytes( ((dword >> 24) & 0xFF,
  162. (dword >> 16) & 0xFF,
  163. (dword >> 8) & 0xFF,
  164. dword & 0xFF)
  165. )
  166. )[0]
  167. self.hal[self.halName] = value
  168. def __str__(self):
  169. return "profibus.%s" % self.halName
  170. class Worker:
  171. def __init__(self, hal, master):
  172. self.__configDone = False
  173. self.hal = hal
  174. self.master = master
  175. self.slaves = master.getSlaveList()
  176. def __buildTable(self, slaveAddr, direction, size):
  177. tab = []
  178. for i in range(0, size):
  179. for bitNr in range(8):
  180. halName = "slave.%d.%s.bit.%d.%d" % (
  181. slaveAddr, direction, i, bitNr)
  182. if self.hal[halName + ".active"]:
  183. tab.append(SigBit(self.hal, halName,
  184. i, bitNr))
  185. halName = "slave.%d.%s.u8.%d" % (
  186. slaveAddr, direction, i)
  187. if self.hal[halName + ".active"]:
  188. tab.append(SigU8(self.hal, halName, i))
  189. if i % 2:
  190. continue
  191. if size - i < 2:
  192. continue
  193. halName = "slave.%d.%s.u16.%d" % (
  194. slaveAddr, direction, i)
  195. if self.hal[halName + ".active"]:
  196. tab.append(SigU16(self.hal, halName, i))
  197. halName = "slave.%d.%s.s16.%d" % (
  198. slaveAddr, direction, i)
  199. if self.hal[halName + ".active"]:
  200. tab.append(SigS16(self.hal, halName, i))
  201. if size - i < 4:
  202. continue
  203. halName = "slave.%d.%s.u31.%d" % (
  204. slaveAddr, direction, i)
  205. if self.hal[halName + ".active"]:
  206. tab.append(SigU31(self.hal, halName, i))
  207. halName = "slave.%d.%s.s32.%d" % (
  208. slaveAddr, direction, i)
  209. if self.hal[halName + ".active"]:
  210. tab.append(SigS32(self.hal, halName, i))
  211. halName = "slave.%d.%s.float.%d" % (
  212. slaveAddr, direction, i)
  213. if self.hal[halName + ".active"]:
  214. tab.append(SigFloat(self.hal, halName, i))
  215. return tab
  216. def __tryBuildConfig(self):
  217. if not self.hal["config.ready"]:
  218. return
  219. for slave in self.slaves:
  220. slaveConf = slave.slaveConf
  221. if slaveConf is None:
  222. continue
  223. activePbMasterOutputs = self.__buildTable(
  224. slave.slaveAddr, "mosi", slaveConf.inputSize)
  225. activePbMasterInputs = self.__buildTable(
  226. slave.slaveAddr, "miso", slaveConf.outputSize)
  227. slave.userData["activePbMasterInputs"] = activePbMasterInputs
  228. slave.userData["activePbMasterOutputs"] = activePbMasterOutputs
  229. printInfo("Active DP slave (addr=%d) I/O pins:" % slave.slaveAddr)
  230. for sig in activePbMasterOutputs:
  231. printInfo("DP slave input: " + str(sig))
  232. for sig in activePbMasterInputs:
  233. printInfo("DP slave output: " + str(sig))
  234. self.__configDone = True
  235. printInfo("HAL configuration done")
  236. def mainLoop(self, faultDeb):
  237. master = self.master
  238. while watchdog() and not self.__configDone:
  239. self.__tryBuildConfig()
  240. time.sleep(0.1)
  241. while watchdog():
  242. for slave in self.slaves:
  243. slaveConf = slave.slaveConf
  244. if slaveConf is not None:
  245. # Copy I/O data from HAL to PB master output.
  246. txData = bytearray(slaveConf.inputSize)
  247. for sig in slave.userData["activePbMasterOutputs"]:
  248. sig.fromHal(txData)
  249. slave.setMasterOutData(txData)
  250. slave = master.run()
  251. if slave is not None:
  252. slaveConf = slave.slaveConf
  253. if slaveConf is not None:
  254. rxData = slave.getMasterInData()
  255. halBaseName = "slave.%d" % slave.slaveAddr
  256. isConnected = slave.isConnected()
  257. if isConnected: # Slave is connected.
  258. # Copy I/O data from PB master input to HAL.
  259. if rxData is not None:
  260. assert len(rxData) == slaveConf.outputSize
  261. for sig in slave.userData["activePbMasterInputs"]:
  262. sig.toHal(rxData)
  263. self.hal[halBaseName + ".connected"] = True
  264. self.hal[halBaseName + ".connecting"] = False
  265. else: # Slave is not connected.
  266. self.hal[halBaseName + ".connecting"] = slave.isConnecting()
  267. self.hal[halBaseName + ".connected"] = False
  268. if self.hal[halBaseName + ".config.disconnect-clear-pins"]:
  269. # Clear the HAL data.
  270. rxData = bytearray(slaveConf.outputSize)
  271. for sig in slave.userData["activePbMasterInputs"]:
  272. sig.toHal(rxData)
  273. faultDeb.ok()
  274. class LinuxCNC_NotRunning(Exception):
  275. pass
  276. def printError(msg):
  277. sys.stderr.write("pyprofibus: " + msg + "\n")
  278. def printWarning(msg):
  279. sys.stderr.write("pyprofibus: " + msg + "\n")
  280. def printInfo(msg):
  281. sys.stdout.write("pyprofibus: " + msg + "\n")
  282. # Check presence of LinuxCNC.
  283. # Returns normally, if LinuxCNC is detected.
  284. # Raises LinuxCNC_NotRunning, if LinuxCNC is not detected.
  285. def watchdog():
  286. # Check whether LinuxCNC is running.
  287. if fileExists("/tmp/linuxcnc.lock"):
  288. return True
  289. if not opt_watchdog:
  290. # The check is disabled. Return success.
  291. return True
  292. printError("LinuxCNC doesn't seem to be running. "\
  293. "(Use '--watchdog off' to disable this check.)")
  294. raise LinuxCNC_NotRunning()
  295. # Create the global LinuxCNC HAL pins and params
  296. def createGlobalHalPins(hal):
  297. HAL_BIT, HAL_U32, HAL_S32, HAL_FLOAT = \
  298. LinuxCNC_HAL.HAL_BIT, LinuxCNC_HAL.HAL_U32, \
  299. LinuxCNC_HAL.HAL_S32, LinuxCNC_HAL.HAL_FLOAT
  300. HAL_IN, HAL_OUT, HAL_RO, HAL_RW = \
  301. LinuxCNC_HAL.HAL_IN, LinuxCNC_HAL.HAL_OUT, \
  302. LinuxCNC_HAL.HAL_RO, LinuxCNC_HAL.HAL_RW
  303. hal.newparam("config.ready", HAL_BIT, HAL_RW)
  304. # Create the per-slave LinuxCNC HAL pins and params
  305. def createSlaveHalPins(hal, slaveAddr, slaveOutputSize, slaveInputSize):
  306. HAL_BIT, HAL_U32, HAL_S32, HAL_FLOAT = \
  307. LinuxCNC_HAL.HAL_BIT, LinuxCNC_HAL.HAL_U32, \
  308. LinuxCNC_HAL.HAL_S32, LinuxCNC_HAL.HAL_FLOAT
  309. HAL_IN, HAL_OUT, HAL_RO, HAL_RW = \
  310. LinuxCNC_HAL.HAL_IN, LinuxCNC_HAL.HAL_OUT, \
  311. LinuxCNC_HAL.HAL_RO, LinuxCNC_HAL.HAL_RW
  312. addr = slaveAddr
  313. hal.newpin("slave.%d.connecting" % addr, HAL_BIT, HAL_OUT)
  314. hal.newpin("slave.%d.connected" % addr, HAL_BIT, HAL_OUT)
  315. printInfo("DP slave %d output (MISO): %d bytes" % (addr, slaveOutputSize))
  316. printInfo("DP slave %d input (MOSI): %d bytes" % (addr, slaveInputSize))
  317. # Create the input pins
  318. for i in range(slaveInputSize):
  319. for bit in range(8):
  320. hal.newpin("slave.%d.mosi.bit.%d.%d" % (addr, i, bit),
  321. HAL_BIT, HAL_IN)
  322. hal.newparam("slave.%d.mosi.bit.%d.%d.active" % (addr, i, bit),
  323. HAL_BIT, HAL_RW)
  324. hal.newpin("slave.%d.mosi.u8.%d" % (addr, i),
  325. HAL_U32, HAL_IN)
  326. hal.newparam("slave.%d.mosi.u8.%d.active" % (addr, i),
  327. HAL_BIT, HAL_RW)
  328. if i % 2:
  329. continue
  330. if slaveInputSize - i < 2:
  331. continue
  332. hal.newpin("slave.%d.mosi.u16.%d" % (addr, i),
  333. HAL_U32, HAL_IN)
  334. hal.newparam("slave.%d.mosi.u16.%d.active" % (addr, i),
  335. HAL_BIT, HAL_RW)
  336. hal.newpin("slave.%d.mosi.s16.%d" % (addr, i),
  337. HAL_S32, HAL_IN)
  338. hal.newparam("slave.%d.mosi.s16.%d.active" % (addr, i),
  339. HAL_BIT, HAL_RW)
  340. if slaveInputSize - i < 4:
  341. continue
  342. hal.newpin("slave.%d.mosi.u31.%d" % (addr, i),
  343. HAL_U32, HAL_IN)
  344. hal.newparam("slave.%d.mosi.u31.%d.active" % (addr, i),
  345. HAL_BIT, HAL_RW)
  346. hal.newpin("slave.%d.mosi.s32.%d" % (addr, i),
  347. HAL_S32, HAL_IN)
  348. hal.newparam("slave.%d.mosi.s32.%d.active" % (addr, i),
  349. HAL_BIT, HAL_RW)
  350. hal.newpin("slave.%d.mosi.float.%d" % (addr, i),
  351. HAL_FLOAT, HAL_IN)
  352. hal.newparam("slave.%d.mosi.float.%d.active" % (addr, i),
  353. HAL_BIT, HAL_RW)
  354. # Create the output pins
  355. for i in range(slaveOutputSize):
  356. for bit in range(8):
  357. hal.newpin("slave.%d.miso.bit.%d.%d" % (addr, i, bit),
  358. HAL_BIT, HAL_OUT)
  359. hal.newparam("slave.%d.miso.bit.%d.%d.active" % (addr, i, bit),
  360. HAL_BIT, HAL_RW)
  361. hal.newpin("slave.%d.miso.u8.%d" % (addr, i),
  362. HAL_U32, HAL_OUT)
  363. hal.newparam("slave.%d.miso.u8.%d.active" % (addr, i),
  364. HAL_BIT, HAL_RW)
  365. if i % 2:
  366. continue
  367. if slaveOutputSize < 2:
  368. continue
  369. hal.newpin("slave.%d.miso.u16.%d" % (addr, i),
  370. HAL_U32, HAL_OUT)
  371. hal.newparam("slave.%d.miso.u16.%d.active" % (addr, i),
  372. HAL_BIT, HAL_RW)
  373. hal.newpin("slave.%d.miso.s16.%d" % (addr, i),
  374. HAL_S32, HAL_OUT)
  375. hal.newparam("slave.%d.miso.s16.%d.active" % (addr, i),
  376. HAL_BIT, HAL_RW)
  377. if slaveOutputSize < 4:
  378. continue
  379. hal.newpin("slave.%d.miso.u31.%d" % (addr, i),
  380. HAL_U32, HAL_OUT)
  381. hal.newparam("slave.%d.miso.u31.%d.active" % (addr, i),
  382. HAL_BIT, HAL_RW)
  383. hal.newpin("slave.%d.miso.s32.%d" % (addr, i),
  384. HAL_S32, HAL_OUT)
  385. hal.newparam("slave.%d.miso.s32.%d.active" % (addr, i),
  386. HAL_BIT, HAL_RW)
  387. hal.newpin("slave.%d.miso.float.%d" % (addr, i),
  388. HAL_FLOAT, HAL_OUT)
  389. hal.newparam("slave.%d.miso.float.%d.active" % (addr, i),
  390. HAL_BIT, HAL_RW)
  391. hal.newparam("slave.%d.config.disconnect-clear-pins" % addr, HAL_BIT, HAL_RW)
  392. def usage():
  393. print("pyprofibus-linuxcnc-hal version %s" % VERSION_STRING)
  394. print("")
  395. print("Usage: pyprofibus-linuxcnc-hal [OPTIONS] pyprofibus.conf")
  396. print("")
  397. print("Options:")
  398. print("")
  399. print(" -L|--loglevel LVL Set the log level:")
  400. print(" 0: Log nothing")
  401. print(" 1: Log errors")
  402. print(" 2: Log errors and warnings")
  403. print(" 3: Log errors, warnings and info messages (default)")
  404. print(" 4: Verbose logging")
  405. print(" 5: Extremely verbose logging")
  406. print(" -N|--nice NICE Renice the process. -20 <= NICE <= 19.")
  407. print(" Default: Do not renice")
  408. print("")
  409. print("Debugging options:")
  410. print(" -W|--watchdog 1/0 Enable/disable LinuxCNC runtime watchdog.")
  411. print(" Default: on")
  412. print("")
  413. print("For an example LinuxCNC HAL configuration see:")
  414. print(" linuxcnc-demo.hal")
  415. def main():
  416. global LinuxCNC_HAL
  417. global opt_loglevel
  418. global opt_nice
  419. global opt_watchdog
  420. opt_loglevel = 3
  421. opt_nice = None
  422. opt_watchdog = True
  423. try:
  424. (opts, args) = getopt.getopt(sys.argv[1:],
  425. "hL:N:W:",
  426. [ "help",
  427. "loglevel=",
  428. "nice=",
  429. "watchdog=", ])
  430. except getopt.GetoptError as e:
  431. printError(str(e))
  432. usage()
  433. return 1
  434. for (o, v) in opts:
  435. if o in ("-h", "--help"):
  436. usage()
  437. return 0
  438. if o in ("-L", "--loglevel"):
  439. try:
  440. opt_loglevel = int(v)
  441. except ValueError:
  442. printError("-L|--loglevel: Invalid log level")
  443. return 1
  444. if o in ("-N", "--nice"):
  445. try:
  446. opt_nice = int(v)
  447. if opt_nice < -20 or opt_nice > 19:
  448. raise ValueError
  449. except ValueError:
  450. printError("-N|--nice: Invalid niceness level")
  451. return 1
  452. if o in ("-W", "--watchdog"):
  453. opt_watchdog = str2bool(v)
  454. if len(args) != 1:
  455. usage()
  456. return 1
  457. configFile = args[0]
  458. result = 0
  459. try:
  460. # Parse the Profibus config file
  461. config = PbConf.fromFile(configFile)
  462. if opt_loglevel >= 4 and config.debug < 1:
  463. config.debug = 1
  464. # Adjust process priority
  465. if opt_nice is not None:
  466. try:
  467. os.nice(opt_nice)
  468. except OSError as e:
  469. printError("Failed to renice process to "
  470. "%d: %s" % (opt_nice, str(e)))
  471. return 1
  472. # Try to import the LinuxCNC HAL module
  473. try:
  474. import hal as LinuxCNC_HAL
  475. except ImportError as e:
  476. printError("Failed to import LinuxCNC HAL "
  477. "module: %s" % str(e))
  478. return 1
  479. # Create the LinuxCNC HAL component.
  480. hal = LinuxCNC_HAL.component("profibus")
  481. # Create the HAL pins.
  482. createGlobalHalPins(hal=hal)
  483. for slaveConf in config.slaveConfs:
  484. createSlaveHalPins(hal=hal,
  485. slaveAddr=slaveConf.addr,
  486. slaveInputSize=slaveConf.inputSize,
  487. slaveOutputSize=slaveConf.outputSize)
  488. # Setup the PROFIBUS stack.
  489. master = config.makeDPM()
  490. for slaveConf in config.slaveConfs:
  491. slaveDesc = slaveConf.makeDpSlaveDesc()
  492. dp1PrmMask = bytearray((
  493. DpTelegram_SetPrm_Req.DPV1PRM0_FAILSAFE,
  494. DpTelegram_SetPrm_Req.DPV1PRM1_REDCFG,
  495. 0x00))
  496. dp1PrmSet = bytearray((
  497. DpTelegram_SetPrm_Req.DPV1PRM0_FAILSAFE,
  498. DpTelegram_SetPrm_Req.DPV1PRM1_REDCFG,
  499. 0x00))
  500. slaveDesc.setUserPrmData(
  501. slaveConf.gsd.getUserPrmData(dp1PrmMask=dp1PrmMask,
  502. dp1PrmSet=dp1PrmSet))
  503. master.addSlave(slaveDesc)
  504. printInfo("Running PROFIBUS-DP master...")
  505. master.initialize()
  506. worker = Worker(hal, master)
  507. hal.ready()
  508. printInfo("ready.")
  509. faultDeb = FaultDebouncer()
  510. while True:
  511. try:
  512. worker.mainLoop(faultDeb)
  513. except (LinuxCNC_NotRunning, KeyboardInterrupt) as e:
  514. raise e
  515. except Exception as e:
  516. if faultDeb.fault() >= 3:
  517. # Too many faults. Raise a fatal exception.
  518. printError("Fatal PROFIBUS fault.")
  519. raise e
  520. else:
  521. # Non-fatal fault.
  522. printError("PROFIBUS fault:\n%s" % str(e))
  523. except (LinuxCNC_NotRunning, KeyboardInterrupt) as e:
  524. result = 1
  525. except PbConfError as e:
  526. printError("Profibus configuration error:\n%s" % str(e))
  527. result = 1
  528. except ProfibusError as e:
  529. printError("Fatal PROFIBUS fault:\n%s" % str(e))
  530. result = 1
  531. printInfo("LinuxCNC HAL module shutdown.")
  532. return result
  533. if __name__ == "__main__":
  534. sys.exit(main())