ahio  1.0.0
I/O Communication Library
raspberry.py
Go to the documentation of this file.
1 # -*- coding: utf-8; -*-
2 #
3 # Copyright (c) 2016 Álan Crístoffer
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining a copy
6 # of this software and associated documentation files (the "Software"), to deal
7 # in the Software without restriction, including without limitation the rights
8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 # copies of the Software, and to permit persons to whom the Software is
10 # furnished to do so, subject to the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be included in
13 # all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 # THE SOFTWARE.
22 
24 
25 import os.path
26 import platform
27 import re
28 from enum import Enum
29 
30 
31 
37 def pi_version():
38  if not os.path.isfile('/proc/cpuinfo'):
39  return None
40  # Check /proc/cpuinfo for the Hardware field value.
41  # 2708 is pi 1
42  # 2709 is pi 2
43  # Anything else is not a pi.
44  with open('/proc/cpuinfo', 'r') as infile:
45  cpuinfo = infile.read()
46  # Match a line like 'Hardware : BCM2709'
47  match = re.search('^Hardware\s+:\s+(\w+)$', cpuinfo,
48  flags=re.MULTILINE | re.IGNORECASE)
49  if not match:
50  # Couldn't find the hardware, assume it isn't a pi.
51  return None
52  if match.group(1) == 'BCM2708':
53  # Pi 1
54  return 1
55  elif match.group(1) == 'BCM2709':
56  # Pi 2
57  return 2
58  else:
59  # Something else, not a pi.
60  return None
61 
62 
64  NAME = 'Raspberry'
65  AVAILABLE = pi_version() is not None
66 
67 # Just try to import it. Code that depends on it should not be executed outside
68 # of Raspberry Pi anyway
69 try:
70  import RPi.GPIO as GPIO
71 except ImportError:
72  if ahioDriverInfo.AVAILABLE:
73  print("RPi.GPIO not installed: sudo apt-get install python3-rpi.gpio")
74  ahioDriverInfo.AVAILABLE = false
75 except RuntimeError:
76  ahioDriverInfo.AVAILABLE = false
77  print("You probably need superuser privileges. Try running with sudo")
78 
79 
81 
82  Pins = Enum(
83  'Pins',
84  'D3 D5 D7 D8 D10 D12 D13 D15 D16 D18 D19 D21 D22 D23 D24 D26')
85 
86  __pwm = {}
87  __pwm_frequency = {}
88 
89  def __init__(self):
90  if ahioDriverInfo.AVAILABLE:
91  GPIO.setmode(GPIO.BOARD)
92  for pin in Driver.Pins:
93  self._set_pin_direction(pin, ahio.Direction.Output)
94 
95  def __enter__(self):
96  return self
97 
98  def __exit__(self, exc_type, exc_value, traceback):
99  GPIO.cleanup()
100 
101  def __create_pin_info(self, pid):
102  return {
103  'id': pid,
104  'name': 'Digital %s' % self.__pin_to_int(pid),
105  'analog': {
106  'input': False,
107  'output': False,
108  'read_range': None,
109  'write_range': None
110  },
111  'digital': {
112  'input': True,
113  'output': True,
114  'pwm': True
115  }
116  }
117 
118  def __pin_to_int(self, pin):
119  if type(pin) is int:
120  return pin
121  else:
122  return int(pin.name.replace('D', ''))
123 
124  def __clamp(self, value, min, max):
125  return sorted((min, value, max))[1]
126 
127  # pinout used is the second on this link (physical/BOARD pinout):
128  # https://www.raspberrypi.org/documentation/usage/gpio
129  def available_pins(self):
130  return [self.__create_pin_info(pin) for pin in Driver.Pins]
131 
132  def _set_pin_direction(self, pin, direction):
133  pin = self.__pin_to_int(pin)
134  if direction == ahio.Direction.Input:
135  GPIO.setup(pin, GPIO.IN)
136  else:
137  GPIO.setup(pin, GPIO.OUT, initial=GPIO.LOW)
138  self.__pwm.pop(pin, None)
139 
140  def _pin_direction(self, pin):
141  pin = self.__pin_to_int(pin)
142  function = GPIO.gpio_function(pin)
143  if function == GPIO.IN:
144  return ahio.Direction.Input
145  elif function == GPIO.OUT or function == GPIO.PWM:
146  return ahio.Direction.Output
147  else:
148  return None
149 
150  def _set_pin_type(self, pin, ptype):
151  if ptype != ahio.PortType.Digital:
152  raise RuntimeError('Raspberry Pi pins can only be used as Digital')
153 
154  def _pin_type(self, pin):
155  return ahio.PortType.Digital
156 
157  def _write(self, pin, value, pwm):
158  pin = self.__pin_to_int(pin)
159  if self._pin_direction(pin) == ahio.Direction.Input:
160  return
161  if pwm:
162  if type(value) is int or type(value) is float:
163  value = int(100 * self.__clamp(float(value), 0.0, 1.0))
164  p = self.__pwm.get(pin, None)
165  if not p:
166  freq = self.__pwm_frequency.get(pin, None)
167  if not freq:
168  freq = 1
169  p = GPIO.PWM(pin, freq)
170  p.start(value)
171  else:
172  raise TypeError(
173  'Value should be a float or int between 0 and 1')
174  else:
175  if type(value) is ahio.LogicValue:
176  lv = ahio.LogicValue
177  value = GPIO.HIGH if value == lv.High else GPIO.LOW
178  GPIO.output(pin, value)
179  else:
180  raise TypeError('Value should be of type ahio.LogicValue')
181 
182  def _read(self, pin):
183  pin = self.__pin_to_int(pin)
184  return GPIO.input(pin)
185 
186  def analog_references(self):
187  return []
188 
189  def _set_analog_reference(self, reference, pin):
190  raise RuntimeError('Raspberry Pi does not have analog pins')
191 
192  def _analog_reference(self, pin):
193  raise RuntimeError('Raspberry Pi does not have analog pins')
194 
195  def _set_pwm_frequency(self, frequency, pin):
196  if pin:
197  pin = self.__pin_to_int(pin)
198  self.__pwm_frequency[pin] = frequency
199  pwm = self.__pwm.get(pin, None)
200  if pwm:
201  pwm.ChangeFrequency(frequency)
202  else:
203  for pin in Driver.Pins:
204  self._set_pwm_frequency(frequency, pin)
def __clamp(self, value, min, max)
Definition: raspberry.py:124
def __create_pin_info(self, pid)
Definition: raspberry.py:101
def pi_version()
Detect the version of the Raspberry Pi.
Definition: raspberry.py:37
def __pin_to_int(self, pin)
Definition: raspberry.py:118
Abstract class containing information about the driver.
def _pin_direction(self, pin)
Definition: raspberry.py:140
def __exit__(self, exc_type, exc_value, traceback)
Definition: raspberry.py:98
def _set_pin_direction(self, pin, direction)
Definition: raspberry.py:132
Contains abstract classes that should be implemented by drivers.
def _set_pwm_frequency(self, frequency, pin)
Definition: raspberry.py:195