__init__.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. #!/usr/bin/env python3.5
  2. # Copyright 2017 Digital
  3. #
  4. # This file is part of DigiLib.
  5. #
  6. # DigiLib is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # DigiLib is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with DigiLib. If not, see <http://www.gnu.org/licenses/>.
  18. # Python modules
  19. import logging
  20. import threading
  21. import traceback
  22. # Third party modules
  23. import blinker
  24. import curio
  25. import digilib.network
  26. log = logging.getLogger(__name__+"")
  27. lgpio = logging.getLogger(__name__+".gpio")
  28. # Error messages
  29. ERROR_TAKES_ARGUMENTS = "{} takes {} {} argument(s): {}"
  30. # respond(ERROR_TAKES_ARGUMENTS.format(
  31. # command, "one", "positional", "<name>"))
  32. _pins_for_cleanup = set()
  33. _gpio = None
  34. class GPIOWrapper(object):
  35. gpio = None
  36. OUT = "out"
  37. IN = "in"
  38. # BCM = "broadcom"
  39. pin_values = {}
  40. def __init__(self):
  41. super(GPIOWrapper,self).__init__()
  42. self.load_rpi_gpio()
  43. lgpio.debug("setting pin numbering to broadcom")
  44. if self.gpio:
  45. self.gpio.setmode(self.gpio.BCM)
  46. sig_exit = blinker.signal("global-exit")
  47. sig_exit.connect(self.cleanup)
  48. def cleanup(self,*args):
  49. lgpio.debug("cleanup! ({})".format(args))
  50. if self.gpio:
  51. self.gpio.cleanup(_pins_for_cleanup)
  52. def load_rpi_gpio(self):
  53. try:
  54. self.gpio = False
  55. self.gpio = __import__("RPi.GPIO",fromlist="GPIO")
  56. except ImportError as e:
  57. lgpio.debug("failed to import RPi.GPIO")
  58. print("134")
  59. except Exception as e:
  60. lgpio.debug("unknown error occured", exc_info=e)
  61. print("137")
  62. finally:
  63. self.OUT = getattr(self.gpio,"OUT",self.OUT)
  64. self.IN = getattr(self.gpio,"IN",self.IN)
  65. # self.BCM = getattr(self.gpio,self.BCM)
  66. def output(self,pins,state,*args):
  67. lgpio.debug("setting pin(s) {:0>2} to value {}".format(
  68. pins,state))
  69. if type(pins) is int:
  70. pins = [pins]
  71. _pins_for_cleanup.update(pins)
  72. if self.gpio:
  73. self.gpio.output(pins,state)
  74. else:
  75. lgpio.debug("no gpio module")
  76. lgpio.debug("gpio module: {}".format(self.gpio))
  77. def parse_to_int_list(self,parse,*args):
  78. if type(parse) is list:
  79. return parse
  80. elif type(parse) is int:
  81. return [parse]
  82. elif type(parse) is bool:
  83. return [int(parse)]
  84. elif type(parse) is not str:
  85. raise ValueError("Failed to parse value {}".format(parse))
  86. if parse.lower() in ["true","high"]:
  87. return [1]
  88. elif parse.lower() in ["false","low"]:
  89. return [0]
  90. parse = parse.split(".")
  91. for part in parse.copy():
  92. parse.remove(part)
  93. parse.append(int(part))
  94. return parse
  95. def read(self,pin,*args):
  96. if self.gpio:
  97. state = self.gpio.read(pin)
  98. else:
  99. state = -1
  100. lgpio.debug("reading pin {:0>2}: {}".format(
  101. pin,state))
  102. return state
  103. def setup(self,pins,value,*args):
  104. lgpio.debug("setting pin(s) {} to {}".format(pins,value))
  105. if self.gpio:
  106. self.gpio.setup(pins,value)
  107. _gpio = GPIOWrapper()
  108. class PinBase(object):
  109. """PinBase is the base class for all classes representing a gpio pin"""
  110. pin_number = None
  111. value = None
  112. def __init__(self,pin_number,mode):
  113. super(PinBase,self).__init__()
  114. self.pin_number = pin_number
  115. self.value = self.value_low
  116. _gpio.setup(self.pin_number,_gpio.OUT)
  117. def output(self,value):
  118. [value] = _gpio.parse_to_int_list(value)
  119. self.value = value
  120. _gpio.output(self.pin_number,value)
  121. def read(self):
  122. value = _gpio.ead(self.pin_number,value)
  123. return value
  124. class DigitalPin(PinBase):
  125. value_high = True
  126. value_low = False
  127. def __init__(self,pin_number,mode):
  128. super(DigitalPin,self).__init__(pin_number,mode)
  129. class AnalogPin(PinBase):
  130. value_high = 1
  131. value_low = 0
  132. def __init__(self,pin_number):
  133. super(AnalogPin,self).__init__(pin_number)
  134. class PinControllerBase(object):
  135. """docstring for PinControllerBase.
  136. PinControllerBase is the base class for all classes controlling one or more physical devices connected to a gpio header
  137. """
  138. pins = []
  139. def __init__(self,pins):
  140. super(PinControllerBase, self).__init__()
  141. self.pins.extend(pins)
  142. # def make_digital_pin(self,*args):
  143. # return DigitalPin(*args)
  144. # def make_analog_pin(self,*args):
  145. # return AnalogPin(*args)
  146. class PinAPIBase(object):
  147. """docstring for PinAPI.
  148. PinAPIBase is the base class for all classes providing an api to multiple
  149. PinController.
  150. """
  151. controllers = []
  152. def __init__(self):
  153. super(PinAPIBase, self).__init__()
  154. class PCEngine(PinControllerBase):
  155. """Test Class"""
  156. max_speed=1
  157. speed = 0
  158. turn_on_speed = 1
  159. is_on = False
  160. def __init__(self,pin_on_off,pin_analog):
  161. super(PCEngine, self).__init__([pin_on_off,pin_analog])
  162. # self.pins.append(pin_on_off)
  163. # self.pins.append(pin_analog)
  164. self.pin_on_off = DigitalPin(pin_on_off,_gpio.OUT)
  165. self.pin_analog = DigitalPin(pin_analog,_gpio.OUT)
  166. # self.pins.append(self.pin_on_off)
  167. # self.pins.append(self.pin_analog)
  168. # gpio.setup(self.pins,_gpio.OUT)
  169. # gpio.setup(self.pin_analog,_gpio.OUT)
  170. self.set_speed(1)
  171. self.set_state(1)
  172. def set_speed(self,speed):
  173. self.pin_analog.output(speed)
  174. self.speed = speed
  175. def set_state(self,state):
  176. """state is integer and specifies if the engine should be turned on (1) or turned off (0) """
  177. if state == self.is_on:
  178. return
  179. # self.set_speed(speed)
  180. self.pin_on_off.output(state)
  181. self.is_on = state
  182. class EnginesController(PinAPIBase):
  183. engine_left = None
  184. engine_right = None
  185. action_in_process = False
  186. def __init__(self,left,right):
  187. super(EnginesController,self).__init__()
  188. self.engine_right = self.make_engine(*right)
  189. self.engine_left = self.make_engine(*left)
  190. def __enter__(self):
  191. if self.action_in_process:
  192. lgpio.debug("action already in process, not entering")
  193. return False
  194. def make_engine(self,*args):
  195. return digilib.pin.PCEngine(*args)
  196. def set_engine_state(self,args=[],command=None,respond=None):
  197. if len(args) != 2:
  198. respond("missing argument(s): <engine> <state>")
  199. return
  200. [engine,state] = args
  201. if engine == "right":
  202. self.engine_right.set_state(state)
  203. elif engine == "left":
  204. self.engine_left.set_state(state)
  205. else:
  206. respond("unknown engine. use 'left' or 'right'")
  207. def set_engine_speed(self,args=[],command=None,respond=None):
  208. if len(args) != 2:
  209. respond("missing argument(s): <engine> <speed>")
  210. return
  211. [engine,speed] = args
  212. if engine == "right":
  213. self.engine_right.set_speed(speed)
  214. elif engine == "left":
  215. self.engine_left.set_speed(speed)
  216. else:
  217. respond("unknown engine. use 'left' or 'right'")
  218. async def turn(self,args=[],command=None,respond=None):
  219. if len(args) != 1:
  220. respond("one missing argument: direction")
  221. return
  222. [direction] = args
  223. # lgpio.debug(threading.current_thread())
  224. # with self ad
  225. lgpio.info("turning {}".format(direction))
  226. right_state = self.engine_right.is_on
  227. right_speed = self.engine_right.speed
  228. left_state = self.engine_left.is_on
  229. left_speed = self.engine_left.speed
  230. if direction == "right":
  231. self.engine_right.set_state(False)
  232. self.engine_left.set_state(True)
  233. self.engine_left.set_speed(1)
  234. elif direction == "left":
  235. self.engine_right.set_state(True)
  236. self.engine_right.set_speed(1)
  237. self.engine_left.set_state(False)
  238. await curio.sleep(2)
  239. # time.sleep(2)
  240. self.engine_right.set_state(right_state)
  241. self.engine_right.set_speed(right_speed)
  242. self.engine_left.set_state(left_state)
  243. self.engine_left.set_speed(left_speed)
  244. lgpio.info("done turning {}".format(direction))
  245. # set engines to previous values
  246. class LED(DigitalPin):
  247. def __init__(self,pin):
  248. super(DigitalPin,self).__init__(pin,_gpio.OUT)
  249. self.on()
  250. def on(self,args=[],command=None,respond=None):
  251. self.output(True)
  252. def off(self,args=[],command=None,respond=None):
  253. self.output(False)
  254. def set(self,args=[],command=None,respond=None):
  255. if len(args) != 1:
  256. respond("one missing argument: state")
  257. return
  258. [state] = args
  259. self.output(state)
  260. class LEDRGB(PinControllerBase):
  261. def __init__(self,pin_red,pin_green):
  262. super(LEDRGB,self).__init__([pin_red,pin_green])
  263. self.pin_red = DigitalPin(pin_red,_gpio.OUT)
  264. self.pin_green = DigitalPin(pin_green,_gpio.OUT)
  265. self.red()
  266. def red(self,args=[],command=None,respond=None):
  267. if len(args) > 1:
  268. respond("{} takes one optinal agument: <state>".foramt(command))
  269. return
  270. elif len(args) == 1:
  271. state = int(*args)
  272. else:
  273. state = 1
  274. self.pin_red.output(state)
  275. def green(self,args=[],command=None,respond=None):
  276. if len(args) > 1:
  277. respond("{} takes one optinal agument: <state>".foramt(command))
  278. return
  279. elif len(args) == 1:
  280. state = int(*args)
  281. else:
  282. state = 1
  283. self.pin_green.output(state)
  284. class DebugPinController(PinControllerBase):
  285. def output(self,args=[],command=None,respond=None):
  286. if len(args) != 2:
  287. respond(ERROR_TAKES_ARGUMENTS.format(
  288. command, "two", "positional", "<name>"))
  289. return False
  290. pins = _gpio.arse_to_int_list(args[0])
  291. [state] = _gpio.arse_to_int_list(args[1])
  292. gpio.output(pins,state)
  293. def read(self,args=[],command=None,respond=None):
  294. if len(args) != 2:
  295. respond(ERROR_TAKES_ARGUMENTS.format(
  296. command, "two", "positional", "<name>"))
  297. return False
  298. pins = _gpio.arse_to_int_list(args[0])
  299. [state] = _gpio.arse_to_int_list(args[1])
  300. return _gpio.ead(pins,state)
  301. if __name__ == "__main__":
  302. pass
  303. #