ppl_shim.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972
  1. # -*- coding: utf-8 -*-
  2. #
  3. # AWL simulator - PiXtend hardware interface
  4. #
  5. # Copyright 2018 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.cython_support cimport * #@cy
  23. from awlsim.common.compat import *
  24. from awlsim.common.util import *
  25. from awlsim.common.enumeration import *
  26. from awlsim.common.exceptions import *
  27. from awlsim.common.datatypehelpers import * #+cimport
  28. __all__ = [
  29. "Relay",
  30. "DigitalOut",
  31. "DigitalIn",
  32. "GPIO",
  33. "EnvSensorBase",
  34. "TempIn",
  35. "HumIn",
  36. "AnalogIn",
  37. "AnalogOut",
  38. "PWM0Period",
  39. "PWM0",
  40. "PWM1Period",
  41. "PWM1",
  42. ]
  43. class AbstractIO(object): #+cdef
  44. """PiXtend abstract I/O handler.
  45. """
  46. setters = ()
  47. getters = ()
  48. def __init__(self, pixtend, isV2, index, bitOffset, directOnly=False, bitSize=1):
  49. """PiXtend I/O abstraction layer.
  50. pixtend: class Pixtend instance
  51. isV2: True, if 'pixtend' is V2.x.
  52. index: Index number of this I/O resource.
  53. e.g. 2 for DI2.
  54. bitOffset: The bit offset in the AWL E or A region this
  55. PiXtend resource is mapped to.
  56. directOnly: If False, then the resource is read/written in the
  57. user cycle and stored in or written to the process image
  58. region specified by bitOffset.
  59. If True, this resource is only accessible by
  60. direct PEx or PAx access only.
  61. bitSize: The size of this I/O instance, in bits.
  62. """
  63. self.pixtend = pixtend
  64. self.isV2 = isV2
  65. self.index = index
  66. self.byteOffset = bitOffset // 8
  67. self.bitOffset = bitOffset % 8
  68. self.directOnly = directOnly
  69. self.bitSize = bitSize
  70. self.byteSize = intDivRoundUp(self.bitSize, 8)
  71. def setup(self, secondaryOffset): #+cpdef
  72. self.byteOffset = max(self.byteOffset + secondaryOffset, 0)
  73. try:
  74. self.setter = self.setters[self.index]
  75. except IndexError:
  76. self.setter = None
  77. try:
  78. self.getter = self.getters[self.index]
  79. except IndexError:
  80. self.getter = None
  81. def set(self, dataBytes): #@nocy
  82. #@cy cdef set(self, bytearray dataBytes):
  83. self.setWithByteOffset(dataBytes, self.byteOffset)
  84. def setWithByteOffset(self, dataBytes, byteOffset): #@nocy
  85. #@cy cdef setWithByteOffset(self, bytearray dataBytes, uint32_t byteOffset):
  86. raise NotImplementedError
  87. def get(self, dataBytes): #@nocy
  88. #@cy cdef get(self, bytearray dataBytes):
  89. self.getWithByteOffset(dataBytes, self.byteOffset)
  90. def getWithByteOffset(self, dataBytes, byteOffset): #@nocy
  91. #@cy cdef getWithByteOffset(self, bytearray dataBytes, uint32_t byteOffset):
  92. raise NotImplementedError
  93. class AbstractBitIO(AbstractIO): #+cdef
  94. """PiXtend abstract bit I/O handler.
  95. """
  96. def __init__(self, *args, **kwargs):
  97. AbstractIO.__init__(self, *args, bitSize=1, **kwargs)
  98. def setup(self, secondaryOffset): #+cpdef
  99. AbstractIO.setup(self, secondaryOffset)
  100. self.bitMask = 1 << self.bitOffset
  101. self.invBitMask = (~self.bitMask) & 0xFF
  102. def setWithByteOffset(self, dataBytes, byteOffset): #@nocy
  103. #@cy cdef setWithByteOffset(self, bytearray dataBytes, uint32_t byteOffset):
  104. self.setter(self, (dataBytes[byteOffset] >> self.bitOffset) & 1)
  105. def getWithByteOffset(self, dataBytes, byteOffset): #@nocy
  106. #@cy cdef getWithByteOffset(self, bytearray dataBytes, uint32_t byteOffset):
  107. if self.getter(self):
  108. dataBytes[byteOffset] |= self.bitMask
  109. else:
  110. dataBytes[byteOffset] &= self.invBitMask
  111. class AbstractWordIO(AbstractIO): #+cdef
  112. """PiXtend abstract word I/O handler.
  113. """
  114. def __init__(self, *args, **kwargs):
  115. AbstractIO.__init__(self, *args, bitSize=16, **kwargs)
  116. def setWithByteOffset(self, dataBytes, byteOffset): #@nocy
  117. #@cy cdef setWithByteOffset(self, bytearray dataBytes, uint32_t byteOffset):
  118. self.setter(self,
  119. (dataBytes[byteOffset] << 8) |\
  120. (dataBytes[byteOffset + 1]))
  121. def getWithByteOffset(self, dataBytes, byteOffset): #@nocy
  122. #@cy cdef getWithByteOffset(self, bytearray dataBytes, uint32_t byteOffset):
  123. #@cy cdef uint16_t value
  124. value = self.getter(self)
  125. dataBytes[byteOffset] = (value >> 8) & 0xFF
  126. dataBytes[byteOffset + 1] = value & 0xFF
  127. class Relay(AbstractBitIO): #+cdef
  128. """PiXtend relay I/O handler.
  129. """
  130. def __setRelay0(self, state):
  131. pixtend = self.pixtend
  132. pixtend.relay0 = pixtend.ON if state else pixtend.OFF
  133. def __setRelay1(self, state):
  134. pixtend = self.pixtend
  135. pixtend.relay1 = pixtend.ON if state else pixtend.OFF
  136. def __setRelay2(self, state):
  137. pixtend = self.pixtend
  138. pixtend.relay2 = pixtend.ON if state else pixtend.OFF
  139. def __setRelay3(self, state):
  140. pixtend = self.pixtend
  141. pixtend.relay3 = pixtend.ON if state else pixtend.OFF
  142. setters = (
  143. __setRelay0,
  144. __setRelay1,
  145. __setRelay2,
  146. __setRelay3,
  147. )
  148. class DigitalOut(AbstractBitIO): #+cdef
  149. """PiXtend digital output I/O handler.
  150. """
  151. def __setDO0(self, state):
  152. pixtend = self.pixtend
  153. if self.isV2:
  154. pixtend.digital_out0 = pixtend.ON if state else pixtend.OFF
  155. else:
  156. pixtend.digital_output0 = pixtend.ON if state else pixtend.OFF
  157. def __setDO1(self, state):
  158. pixtend = self.pixtend
  159. if self.isV2:
  160. pixtend.digital_out1 = pixtend.ON if state else pixtend.OFF
  161. else:
  162. pixtend.digital_output1 = pixtend.ON if state else pixtend.OFF
  163. def __setDO2(self, state):
  164. pixtend = self.pixtend
  165. if self.isV2:
  166. pixtend.digital_out2 = pixtend.ON if state else pixtend.OFF
  167. else:
  168. pixtend.digital_output2 = pixtend.ON if state else pixtend.OFF
  169. def __setDO3(self, state):
  170. pixtend = self.pixtend
  171. if self.isV2:
  172. pixtend.digital_out3 = pixtend.ON if state else pixtend.OFF
  173. else:
  174. pixtend.digital_output3 = pixtend.ON if state else pixtend.OFF
  175. def __setDO4(self, state):
  176. pixtend = self.pixtend
  177. if self.isV2:
  178. assert(0)
  179. else:
  180. pixtend.digital_output4 = pixtend.ON if state else pixtend.OFF
  181. def __setDO5(self, state):
  182. pixtend = self.pixtend
  183. if self.isV2:
  184. assert(0)
  185. else:
  186. pixtend.digital_output5 = pixtend.ON if state else pixtend.OFF
  187. setters = (
  188. __setDO0,
  189. __setDO1,
  190. __setDO2,
  191. __setDO3,
  192. __setDO4,
  193. __setDO5,
  194. )
  195. class DigitalIn(AbstractBitIO): #+cdef
  196. """PiXtend digital input I/O handler.
  197. """
  198. def __getDI0(self):
  199. pixtend = self.pixtend
  200. if self.isV2:
  201. return 1 if pixtend.digital_in0 == pixtend.ON else 0
  202. return 1 if pixtend.digital_input0 == pixtend.ON else 0
  203. def __getDI1(self):
  204. pixtend = self.pixtend
  205. if self.isV2:
  206. return 1 if pixtend.digital_in1 == pixtend.ON else 0
  207. return 1 if pixtend.digital_input1 == pixtend.ON else 0
  208. def __getDI2(self):
  209. pixtend = self.pixtend
  210. if self.isV2:
  211. return 1 if pixtend.digital_in2 == pixtend.ON else 0
  212. return 1 if pixtend.digital_input2 == pixtend.ON else 0
  213. def __getDI3(self):
  214. pixtend = self.pixtend
  215. if self.isV2:
  216. return 1 if pixtend.digital_in3 == pixtend.ON else 0
  217. return 1 if pixtend.digital_input3 == pixtend.ON else 0
  218. def __getDI4(self):
  219. pixtend = self.pixtend
  220. if self.isV2:
  221. return 1 if pixtend.digital_in4 == pixtend.ON else 0
  222. return 1 if pixtend.digital_input4 == pixtend.ON else 0
  223. def __getDI5(self):
  224. pixtend = self.pixtend
  225. if self.isV2:
  226. return 1 if pixtend.digital_in5 == pixtend.ON else 0
  227. return 1 if pixtend.digital_input5 == pixtend.ON else 0
  228. def __getDI6(self):
  229. pixtend = self.pixtend
  230. if self.isV2:
  231. return 1 if pixtend.digital_in6 == pixtend.ON else 0
  232. return 1 if pixtend.digital_input6 == pixtend.ON else 0
  233. def __getDI7(self):
  234. pixtend = self.pixtend
  235. if self.isV2:
  236. return 1 if pixtend.digital_in7 == pixtend.ON else 0
  237. return 1 if pixtend.digital_input7 == pixtend.ON else 0
  238. getters = (
  239. __getDI0,
  240. __getDI1,
  241. __getDI2,
  242. __getDI3,
  243. __getDI4,
  244. __getDI5,
  245. __getDI6,
  246. __getDI7,
  247. )
  248. class GPIO(AbstractBitIO): #+cdef
  249. """PiXtend GPIO I/O handler.
  250. """
  251. EnumGen.start
  252. MODE_OUTPUT = EnumGen.item
  253. MODE_INPUT = EnumGen.item
  254. MODE_DHT11 = EnumGen.item
  255. MODE_DHT22 = EnumGen.item
  256. EnumGen.end
  257. def __init__(self, *args, **kwargs):
  258. AbstractBitIO.__init__(self, *args, **kwargs)
  259. self.mode = None
  260. self.pullUp = None
  261. def __getGPIO0(self):
  262. pixtend = self.pixtend
  263. return 1 if pixtend.gpio0 == pixtend.ON else 0
  264. def __getGPIO1(self):
  265. pixtend = self.pixtend
  266. return 1 if pixtend.gpio1 == pixtend.ON else 0
  267. def __getGPIO2(self):
  268. pixtend = self.pixtend
  269. return 1 if pixtend.gpio2 == pixtend.ON else 0
  270. def __getGPIO3(self):
  271. pixtend = self.pixtend
  272. return 1 if pixtend.gpio3 == pixtend.ON else 0
  273. getters = (
  274. __getGPIO0,
  275. __getGPIO1,
  276. __getGPIO2,
  277. __getGPIO3,
  278. )
  279. def __setGPIO0(self, state):
  280. pixtend = self.pixtend
  281. pixtend.gpio0 = pixtend.ON if state else pixtend.OFF
  282. def __setGPIO1(self, state):
  283. pixtend = self.pixtend
  284. pixtend.gpio1 = pixtend.ON if state else pixtend.OFF
  285. def __setGPIO2(self, state):
  286. pixtend = self.pixtend
  287. pixtend.gpio2 = pixtend.ON if state else pixtend.OFF
  288. def __setGPIO3(self, state):
  289. pixtend = self.pixtend
  290. pixtend.gpio3 = pixtend.ON if state else pixtend.OFF
  291. setters = (
  292. __setGPIO0,
  293. __setGPIO1,
  294. __setGPIO2,
  295. __setGPIO3,
  296. )
  297. def __getV2Ctrl(self, mode):
  298. pixtend = self.pixtend
  299. ctrlValue = {
  300. self.MODE_OUTPUT : pixtend.GPIO_OUTPUT,
  301. self.MODE_INPUT : pixtend.GPIO_INPUT,
  302. self.MODE_DHT11 : pixtend.GPIO_DHT11,
  303. self.MODE_DHT22 : pixtend.GPIO_DHT22,
  304. }[mode]
  305. return ctrlValue
  306. def __getV1Dir(self, mode):
  307. pixtend = self.pixtend
  308. if mode == self.MODE_OUTPUT:
  309. return pixtend.GPIO_OUTPUT
  310. return pixtend.GPIO_INPUT
  311. def __getV1DHTOn(self, mode):
  312. pixtend = self.pixtend
  313. if mode in {self.MODE_DHT11, self.MODE_DHT22}:
  314. return pixtend.ON
  315. return pixtend.OFF
  316. def __setModeGPIO0(self, mode):
  317. pixtend = self.pixtend
  318. if self.isV2:
  319. pixtend.gpio0_ctrl = self.__getV2Ctrl(mode)
  320. else:
  321. pixtend.gpio0_direction = self.__getV1Dir(mode)
  322. pixtend.dht0 = self.__getV1DHTOn(mode)
  323. def __setModeGPIO1(self, mode):
  324. pixtend = self.pixtend
  325. if self.isV2:
  326. pixtend.gpio1_ctrl = self.__getV2Ctrl(mode)
  327. else:
  328. pixtend.gpio1_direction = self.__getV1Dir(mode)
  329. pixtend.dht1 = self.__getV1DHTOn(mode)
  330. def __setModeGPIO2(self, mode):
  331. pixtend = self.pixtend
  332. if self.isV2:
  333. pixtend.gpio2_ctrl = self.__getV2Ctrl(mode)
  334. else:
  335. pixtend.gpio2_direction = self.__getV1Dir(mode)
  336. pixtend.dht2 = self.__getV1DHTOn(mode)
  337. def __setModeGPIO3(self, mode):
  338. pixtend = self.pixtend
  339. if self.isV2:
  340. pixtend.gpio3_ctrl = self.__getV2Ctrl(mode)
  341. else:
  342. pixtend.gpio3_direction = self.__getV1Dir(mode)
  343. pixtend.dht3 = self.__getV1DHTOn(mode)
  344. settersMode = (
  345. __setModeGPIO0,
  346. __setModeGPIO1,
  347. __setModeGPIO2,
  348. __setModeGPIO3,
  349. )
  350. def __setPullUp0(self, state):
  351. pixtend = self.pixtend
  352. if self.isV2:
  353. if pixtend.gpio_pullups_enable:
  354. pixtend.gpio0 = pixtend.ON if state else pixtend.OFF
  355. def __setPullUp1(self, state):
  356. pixtend = self.pixtend
  357. if self.isV2:
  358. if pixtend.gpio_pullups_enable:
  359. pixtend.gpio1 = pixtend.ON if state else pixtend.OFF
  360. def __setPullUp2(self, state):
  361. pixtend = self.pixtend
  362. if self.isV2:
  363. if pixtend.gpio_pullups_enable:
  364. pixtend.gpio2 = pixtend.ON if state else pixtend.OFF
  365. def __setPullUp3(self, state):
  366. pixtend = self.pixtend
  367. if self.isV2:
  368. if pixtend.gpio_pullups_enable:
  369. pixtend.gpio3 = pixtend.ON if state else pixtend.OFF
  370. settersPullUp = (
  371. __setPullUp0,
  372. __setPullUp1,
  373. __setPullUp2,
  374. __setPullUp3,
  375. )
  376. @staticmethod
  377. def setGlobalPullUpEnable(pixtend, isV2, pullUpEnable):
  378. if isV2:
  379. pixtend.gpio_pullups_enable = pixtend.ON if pullUpEnable else pixtend.OFF
  380. def setup(self, secondaryOffset): #+cpdef
  381. AbstractBitIO.setup(self, secondaryOffset)
  382. if self.mode is not None:
  383. setMode = self.settersMode[self.index]
  384. setMode(self, self.mode)
  385. if self.pullUp is not None:
  386. setPullUp = self.settersPullUp[self.index]
  387. setPullUp(self, self.pixtend.ON if self.pullUp
  388. else self.pixtend.OFF)
  389. class EnvSensorBase(AbstractWordIO): #+cdef
  390. """Environmental sensor base class.
  391. """
  392. EnumGen.start
  393. TYPE_DHT11 = EnumGen.item
  394. TYPE_DHT22 = EnumGen.item
  395. EnumGen.end
  396. def __init__(self, sensorType, *args, **kwargs):
  397. AbstractWordIO.__init__(self, *args, **kwargs)
  398. self.sensorType = sensorType
  399. # Create a child GPIO object.
  400. gpioMode = {
  401. self.TYPE_DHT11 : GPIO.MODE_DHT11,
  402. self.TYPE_DHT22 : GPIO.MODE_DHT22,
  403. }[self.sensorType]
  404. self.gpio = GPIO(self.pixtend, self.isV2, self.index, 0, True)
  405. self.gpio.mode = gpioMode
  406. def setup(self, secondaryOffset): #+cpdef
  407. AbstractWordIO.setup(self, secondaryOffset)
  408. # Configure the child GPIO object.
  409. self.gpio.setup(secondaryOffset)
  410. #TODO Fahrenheit
  411. class TempIn(EnvSensorBase): #+cdef
  412. """DHT11/DHT22 temperature input.
  413. """
  414. def __convert(self, temp): #@nocy
  415. #@cy cdef uint16_t __convert(self, double temp):
  416. return max(min(int(round(temp * 10.0)), 8500), -2000) & 0xFFFF
  417. def __getTemp0(self):
  418. if self.isV2:
  419. return self.__convert(self.pixtend.temp0)
  420. if self.sensorType == self.TYPE_DHT11:
  421. return self.__convert(self.pixtend.t0_dht11)
  422. return self.__convert(self.pixtend.t0_dht22)
  423. def __getTemp1(self):
  424. if self.isV2:
  425. return self.__convert(self.pixtend.temp1)
  426. if self.sensorType == self.TYPE_DHT11:
  427. return self.__convert(self.pixtend.t1_dht11)
  428. return self.__convert(self.pixtend.t1_dht22)
  429. def __getTemp2(self):
  430. if self.isV2:
  431. return self.__convert(self.pixtend.temp2)
  432. if self.sensorType == self.TYPE_DHT11:
  433. return self.__convert(self.pixtend.t2_dht11)
  434. return self.__convert(self.pixtend.t2_dht22)
  435. def __getTemp3(self):
  436. if self.isV2:
  437. return self.__convert(self.pixtend.temp3)
  438. if self.sensorType == self.TYPE_DHT11:
  439. return self.__convert(self.pixtend.t3_dht11)
  440. return self.__convert(self.pixtend.t3_dht22)
  441. getters = (
  442. __getTemp0,
  443. __getTemp1,
  444. __getTemp2,
  445. __getTemp3,
  446. )
  447. class HumIn(EnvSensorBase): #+cdef
  448. """DHT11/DHT22 humidity input.
  449. """
  450. def __convert(self, hum): #@nocy
  451. #@cy cdef uint16_t __convert(self, double hum):
  452. return max(min(int(round(hum * 10.0)), 1000), 0)
  453. def __getHum0(self):
  454. if self.isV2:
  455. return self.__convert(self.pixtend.humid0)
  456. if self.sensorType == self.TYPE_DHT11:
  457. return self.__convert(self.pixtend.h0_dht11)
  458. return self.__convert(self.pixtend.h0_dht22)
  459. def __getHum1(self):
  460. if self.isV2:
  461. return self.__convert(self.pixtend.humid1)
  462. if self.sensorType == self.TYPE_DHT11:
  463. return self.__convert(self.pixtend.h1_dht11)
  464. return self.__convert(self.pixtend.h1_dht22)
  465. def __getHum2(self):
  466. if self.isV2:
  467. return self.__convert(self.pixtend.humid2)
  468. if self.sensorType == self.TYPE_DHT11:
  469. return self.__convert(self.pixtend.h2_dht11)
  470. return self.__convert(self.pixtend.h2_dht22)
  471. def __getHum3(self):
  472. if self.isV2:
  473. return self.__convert(self.pixtend.humid3)
  474. if self.sensorType == self.TYPE_DHT11:
  475. return self.__convert(self.pixtend.h3_dht11)
  476. return self.__convert(self.pixtend.h3_dht22)
  477. getters = (
  478. __getHum0,
  479. __getHum1,
  480. __getHum2,
  481. __getHum3,
  482. )
  483. class AnalogIn(AbstractWordIO): #+cdef
  484. """PiXtend analog input I/O handler.
  485. """
  486. def __init__(self, *args, **kwargs):
  487. AbstractWordIO.__init__(self, *args, **kwargs)
  488. self.jumper10V = None
  489. self.numberOfSamples = None
  490. def __convertV(self, V): #@nocy
  491. #@cy cdef uint16_t __convertV(self, double V):
  492. return max(min(int(round(V * 2764.8)), 32767), -32768)
  493. def __convertMA(self, mA): #@nocy
  494. #@cy cdef uint16_t __convertMA(self, double mA):
  495. return max(min(int(round((mA - 4.0) * 1728.0)), 32767), -32768)
  496. def __getAI0(self):
  497. if self.isV2:
  498. return self.__convertV(self.pixtend.analog_in0)
  499. return self.__convertV(self.pixtend.analog_input0)
  500. def __getAI1(self):
  501. if self.isV2:
  502. return self.__convertV(self.pixtend.analog_in1)
  503. return self.__convertV(self.pixtend.analog_input1)
  504. def __getAI2(self):
  505. if self.isV2:
  506. assert(0)
  507. return 0
  508. return self.__convertMA(self.pixtend.analog_input2)
  509. def __getAI3(self):
  510. if self.isV2:
  511. assert(0)
  512. return 0
  513. return self.__convertMA(self.pixtend.analog_input3)
  514. getters = (
  515. __getAI0,
  516. __getAI1,
  517. __getAI2,
  518. __getAI3,
  519. )
  520. def __setJumper10V_AI0(self, jumper10V):
  521. pixtend = self.pixtend
  522. value = pixtend.ON if jumper10V else pixtend.OFF
  523. if self.isV2:
  524. pixtend.jumper_setting_ai0 = value
  525. else:
  526. pixtend.analog_input0_10volts_jumper = value
  527. def __setJumper10V_AI1(self, jumper10V):
  528. pixtend = self.pixtend
  529. value = pixtend.ON if jumper10V else pixtend.OFF
  530. if self.isV2:
  531. pixtend.jumper_setting_ai1 = value
  532. else:
  533. pixtend.analog_input1_10volts_jumper = value
  534. settersJumper10V = (
  535. __setJumper10V_AI0,
  536. __setJumper10V_AI1,
  537. )
  538. def __setNos_AI0(self, nos):
  539. if not self.isV2:
  540. self.pixtend.analog_input0_nos = nos
  541. def __setNos_AI1(self, nos):
  542. if not self.isV2:
  543. self.pixtend.analog_input1_nos = nos
  544. def __setNos_AI2(self, nos):
  545. if not self.isV2:
  546. self.pixtend.analog_input2_nos = nos
  547. def __setNos_AI3(self, nos):
  548. if not self.isV2:
  549. self.pixtend.analog_input3_nos = nos
  550. settersNos = (
  551. __setNos_AI0,
  552. __setNos_AI1,
  553. __setNos_AI2,
  554. __setNos_AI3,
  555. )
  556. @staticmethod
  557. def setFreq(pixtend, isV2, freqKHz):
  558. if isV2:
  559. return
  560. kHz2MHz = {
  561. 125 : 0.125,
  562. 250 : 0.250,
  563. 500 : 0.500,
  564. 1000 : 1.0,
  565. 2000 : 2.0,
  566. 4000 : 4.0,
  567. 8000 : 8.0,
  568. }
  569. try:
  570. freqMHz = kHz2MHz[freqKHz]
  571. except KeyError as e:
  572. raise ValueError
  573. pixtend.analog_input_nos_freq = freqMHz
  574. def setup(self, secondaryOffset): #+cpdef
  575. AbstractWordIO.setup(self, secondaryOffset)
  576. if self.jumper10V is not None:
  577. setJumper10V = self.settersJumper10V[self.index]
  578. setJumper10V(self, self.pixtend.ON if self.jumper10V
  579. else self.pixtend.OFF)
  580. if self.numberOfSamples is not None:
  581. setNos = self.settersNos[self.index]
  582. setNos(self, self.numberOfSamples)
  583. class AnalogOut(AbstractWordIO): #+cdef
  584. """PiXtend analog output I/O handler.
  585. """
  586. def __convert(self, s7Value): #@nocy
  587. #@cy cdef uint16_t __convert(self, uint16_t s7Value):
  588. # dac = (s7Value / 27648) * 1023
  589. return clamp(int(round((wordToSignedPyInt(s7Value) * 1023) / 27648)),
  590. 0, 1023)
  591. def __setAO0(self, value):
  592. pixtend = self.pixtend
  593. if self.isV2:
  594. pixtend.set_dac_output(pixtend.DAC_A, self.__convert(value))
  595. else:
  596. pixtend.dac_selection = pixtend.DAC_A
  597. pixtend.set_dac_output(self.__convert(value))
  598. def __setAO1(self, value):
  599. pixtend = self.pixtend
  600. if self.isV2:
  601. pixtend.set_dac_output(pixtend.DAC_B, self.__convert(value))
  602. else:
  603. pixtend.dac_selection = pixtend.DAC_B
  604. pixtend.set_dac_output(self.__convert(value))
  605. setters = (
  606. __setAO0,
  607. __setAO1,
  608. )
  609. class PWM0Period(AbstractWordIO): #+cdef
  610. """PiXtend PWM0 period I/O handler.
  611. """
  612. def setPWMPeriod(self, period):
  613. if self.isV2:
  614. self.pixtend.pwm0_ctrl1 = clamp(period, 0, 65535)
  615. else:
  616. self.pixtend.pwm_ctrl_period = clamp(period, 0, 65000)
  617. self.pixtend.pwm_ctrl_configure()
  618. setters = (
  619. setPWMPeriod,
  620. )
  621. @staticmethod
  622. def setBaseFreq(pixtend, isV2, freqHz):
  623. cpuHz = 16000000
  624. csMap = {
  625. 0 : (0, 0, 0), # PS=off
  626. cpuHz // 1 : (0, 0, 1), # PS=1
  627. cpuHz // 8 : (0, 1, 0), # PS=8
  628. cpuHz // 64 : (0, 1, 1), # PS=64
  629. cpuHz // 256 : (1, 0, 0), # PS=256
  630. cpuHz // 1024 : (1, 0, 1), # PS=1024
  631. }
  632. try:
  633. cs2, cs1, cs0 = csMap[freqHz]
  634. except KeyError as e:
  635. raise ValueError
  636. if isV2:
  637. ctrl0 = pixtend.pwm0_ctrl0
  638. ctrl0 &= ~((1 << 5) | (1 << 6) | (1 << 7))
  639. ctrl0 |= (cs0 << 5) | (cs1 << 6) | (cs2 << 7)
  640. if freqHz == 0:
  641. ctrl0 &= ~((1 << 3) | (1 << 4)) # Disable A and B
  642. pixtend.pwm0_ctrl0 = ctrl0 & 0xFF
  643. else:
  644. pixtend.pwm_ctrl_cs0 = cs0
  645. pixtend.pwm_ctrl_cs1 = cs1
  646. pixtend.pwm_ctrl_cs2 = cs2
  647. pixtend.pwm_ctrl_configure()
  648. class PWM0(AbstractWordIO): #+cdef
  649. """PiXtend PWM0 output I/O handler.
  650. """
  651. def __init__(self, *args, **kwargs):
  652. AbstractWordIO.__init__(self, *args, **kwargs)
  653. self.enabled = False
  654. self.servoMode = False
  655. def __setPWMA(self, value):
  656. if self.enabled:
  657. if self.servoMode:
  658. if self.isV2:
  659. self.pixtend.servo0 = clamp(value, 0, 16000)
  660. else:
  661. self.pixtend.servo0 = clamp(value, 0, 250)
  662. else:
  663. if self.isV2:
  664. self.pixtend.pwm0a = clamp(value, 0, 65535)
  665. else:
  666. self.pixtend.pwm0 = clamp(value, 0, 65000)
  667. def __setPWMB(self, value):
  668. if self.enabled:
  669. if self.servoMode:
  670. if self.isV2:
  671. self.pixtend.servo1 = clamp(value, 0, 16000)
  672. else:
  673. self.pixtend.servo1 = clamp(value, 0, 250)
  674. else:
  675. if self.isV2:
  676. self.pixtend.pwm0b = clamp(value, 0, 65535)
  677. else:
  678. self.pixtend.pwm1 = clamp(value, 0, 65000)
  679. setters = (
  680. __setPWMA,
  681. __setPWMB,
  682. )
  683. @staticmethod
  684. def setServoMode(pixtend, isV2, enServoMode):
  685. if isV2:
  686. ctrl0 = pixtend.pwm0_ctrl0
  687. ctrl0 &= ~((1 << 0) | (1 << 1))
  688. if not enServoMode:
  689. ctrl0 |= 1 << 0
  690. pixtend.pwm0_ctrl0 = ctrl0
  691. else:
  692. pixtend.pwm_ctrl_mode = 0 if enServoMode else 1
  693. pixtend.pwm_ctrl_configure()
  694. def __doSetEnabled(self, enabled, bitNr):
  695. self.enabled = enabled
  696. if self.isV2:
  697. ctrl0 = self.pixtend.pwm0_ctrl0
  698. ctrl0 &= ~(1 << bitNr)
  699. if enabled:
  700. ctrl0 |= (1 << bitNr)
  701. self.pixtend.pwm0_ctrl0 = ctrl0
  702. def __setEnabled0(self, enabled):
  703. self.__doSetEnabled(enabled, 3)
  704. def __setEnabled1(self, enabled):
  705. self.__doSetEnabled(enabled, 4)
  706. settersEnabled = (
  707. __setEnabled0,
  708. __setEnabled1,
  709. )
  710. def setup(self, secondaryOffset): #+cpdef
  711. AbstractWordIO.setup(self, secondaryOffset)
  712. setEnabled = self.settersEnabled[self.index]
  713. setEnabled(self, self.enabled)
  714. class PWM1Period(AbstractWordIO): #+cdef
  715. """PiXtend PWM1 period I/O handler. (v2.x only)
  716. """
  717. def setPWMPeriod(self, period):
  718. if self.isV2:
  719. self.pixtend.pwm1_ctrl1 = clamp(period, 0, 255)
  720. else:
  721. assert(0)
  722. setters = (
  723. setPWMPeriod,
  724. )
  725. @staticmethod
  726. def setBaseFreq(pixtend, freqHz):
  727. cpuHz = 16000000
  728. csMap = {
  729. 0 : (0, 0, 0), # PS=off
  730. cpuHz // 1 : (0, 0, 1), # PS=1
  731. cpuHz // 8 : (0, 1, 0), # PS=8
  732. cpuHz // 32 : (0, 1, 1), # PS=32
  733. cpuHz // 64 : (1, 0, 0), # PS=64
  734. cpuHz // 128 : (1, 0, 1), # PS=128
  735. cpuHz // 256 : (1, 1, 0), # PS=256
  736. cpuHz // 1024 : (1, 1, 1), # PS=1024
  737. }
  738. try:
  739. cs2, cs1, cs0 = csMap[freqHz]
  740. except KeyError as e:
  741. raise ValueError
  742. ctrl0 = pixtend.pwm1_ctrl0
  743. ctrl0 &= ~((1 << 5) | (1 << 6) | (1 << 7))
  744. ctrl0 |= (cs0 << 5) | (cs1 << 6) | (cs2 << 7)
  745. if freqHz == 0:
  746. ctrl0 &= ~((1 << 3) | (1 << 4)) # Disable A and B
  747. pixtend.pwm1_ctrl0 = ctrl0 & 0xFF
  748. class PWM1(AbstractWordIO): #+cdef
  749. """PiXtend PWM1 output I/O handler. (v2.x only)
  750. """
  751. def __init__(self, *args, **kwargs):
  752. AbstractWordIO.__init__(self, *args, **kwargs)
  753. self.enabled = False
  754. self.servoMode = False
  755. def __setPWMA(self, value):
  756. if self.enabled:
  757. if self.servoMode:
  758. if self.isV2:
  759. self.pixtend.servo2 = clamp(value, 0, 125)
  760. else:
  761. assert(0)
  762. else:
  763. if self.isV2:
  764. self.pixtend.pwm1a = clamp(value, 0, 255)
  765. else:
  766. assert(0)
  767. def __setPWMB(self, value):
  768. if self.enabled:
  769. if self.servoMode:
  770. if self.isV2:
  771. self.pixtend.servo3 = clamp(value, 0, 125)
  772. else:
  773. assert(0)
  774. else:
  775. if self.isV2:
  776. self.pixtend.pwm1b = clamp(value, 0, 255)
  777. else:
  778. assert(0)
  779. setters = (
  780. __setPWMA,
  781. __setPWMB,
  782. )
  783. @staticmethod
  784. def setServoMode(pixtend, enServoMode):
  785. ctrl0 = pixtend.pwm1_ctrl0
  786. ctrl0 &= ~((1 << 0) | (1 << 1))
  787. if not enServoMode:
  788. ctrl0 |= 1 << 0
  789. pixtend.pwm1_ctrl0 = ctrl0
  790. def __doSetEnabled(self, enabled, bitNr):
  791. self.enabled = enabled
  792. if self.isV2:
  793. ctrl0 = self.pixtend.pwm1_ctrl0
  794. ctrl0 &= ~(1 << bitNr)
  795. if enabled:
  796. ctrl0 |= (1 << bitNr)
  797. self.pixtend.pwm1_ctrl0 = ctrl0
  798. else:
  799. assert(0)
  800. def __setEnabled0(self, enabled):
  801. self.__doSetEnabled(enabled, 3)
  802. def __setEnabled1(self, enabled):
  803. self.__doSetEnabled(enabled, 4)
  804. settersEnabled = (
  805. __setEnabled0,
  806. __setEnabled1,
  807. )
  808. def setup(self, secondaryOffset): #+cpdef
  809. AbstractWordIO.setup(self, secondaryOffset)
  810. setEnabled = self.settersEnabled[self.index]
  811. setEnabled(self, self.enabled)