]> Repositories - Adafruit_Blinka-hackapet.git/blob - src/adafruit_blinka/microcontroller/generic_agnostic_board/pin.py
9ad99052c3b5007867a3252de763e68330bf47a9
[Adafruit_Blinka-hackapet.git] / src / adafruit_blinka / microcontroller / generic_agnostic_board / pin.py
1 # SPDX-FileCopyrightText: 2024 Melissa LeBlanc-Williams for Adafruit Industries
2 #
3 # SPDX-License-Identifier: MIT
4 """generic_agnostic_board pin interface"""
5 import random
6
7 # Values for sine wave output
8 # (data points = 20, amplitude=100, frequency=1)
9 sine_wave = [
10     0,
11     31,
12     59,
13     81,
14     95,
15     100,
16     95,
17     81,
18     59,
19     31,
20     0,
21     -31,
22     -59,
23     -81,
24     -95,
25     -100,
26     -95,
27     -81,
28     -59,
29     -31,
30 ]
31
32
33 class Pin:
34     """A basic Pin class for use with generic_agnostic_board"""
35
36     # pin modes
37     OUT = 0
38     IN = 1
39     ADC = 2
40     DAC = 3
41     # pin values
42     LOW = 0
43     HIGH = 1
44     # pin pulls
45     PULL_NONE = 0
46     PULL_UP = 1
47     PULL_DOWN = 2
48
49     def return_toggle(self):
50         """Returns the pin's expected value, toggling between True and False"""
51         toggle_state = not self.previous_value
52         return toggle_state
53
54     def return_false(self):
55         """Returns the pin's expected value, False"""
56         return False
57
58     def return_true(self):
59         """Returns the pin's expected value, True"""
60         return True
61
62     def return_random_int(self):
63         """Returns a random integer"""
64         return random.randint(0, 65535)
65
66     def return_fixed_int_pi(self):
67         """Returns the first five digits of Pi, 31415"""
68         return 31415
69
70     def return_sine_wave(self):
71         """Returns the next value in the sine wave"""
72         if self._wave_idx is None:
73             self._wave_idx = 0
74         else:
75             self._wave_idx += 1
76         if self._wave_idx >= len(sine_wave):
77             self._wave_idx = 0
78         return sine_wave[self._wave_idx]
79
80     def __init__(self, pin_id=None):
81         self.id = pin_id
82         self._mode = None
83         self._pull = None
84         self.previous_value = False
85         self.current_value = None
86         self._wave_idx = None
87
88         # mapping of pin definition names to expected behavior
89         self.pin_behavior = {
90             0: self.return_true,  # Dx_INPUT_TRUE
91             1: self.return_false,  # Dx_INPUT_FALSE
92             2: self.return_true,  # Dx_INPUT_TRUE_PULL_UP
93             3: self.return_true,  # Dx_INPUT_TRUE_PULL_DOWN
94             4: self.return_true,  # Dx_OUTPUT
95             6: self.return_true,  # NEOPIXEL
96             7: self.return_random_int,  # Ax_INPUT_RAND_INT
97             8: self.return_fixed_int_pi,  # Ax_INPUT_FIXED_INT_PI
98             9: self.return_sine_wave,  # Ax_OUTPUT_WAVE_SINE
99             10: self.return_true,  # Ax_OUTPUT_WAVE_SAWTOOTH
100             11: self.return_toggle,  # Dx_INPUT_TOGGLE
101             # Add other mappings as needed
102         }
103
104     def init(self, mode=IN, pull=None):
105         """Initialize the Pin"""
106         if self.id is None:
107             raise RuntimeError("Can not init a None type pin.")
108         pull = Pin.PULL_NONE if pull is None else pull
109         self._pull = pull
110         self._mode = mode
111
112     def write(self, new_value):
113         """Saves the new_value to the pin for subsequent calls to .value"""
114         self.previous_value = self.current_value
115         self.current_value = new_value
116
117     def read(self):
118         """Returns the pin's expected value."""
119         self.previous_value = self.current_value
120         # perform a lookup on the pin_behavior dict to get the value
121         self.current_value = self.pin_behavior.get(self.id)()
122
123         # is pin a pull up and pin is LOW?
124         if self._pull == Pin.PULL_UP and self.current_value == False:
125             self.current_value = False
126         # is pin a pull down and pin is HIGH?
127         if self._pull == Pin.PULL_DOWN and self.current_value == True:
128             self.current_value = False
129         return self.current_value
130
131     def value(self, val=None):
132         """Set or return the Pin Value"""
133         # Digital In / Out
134         if self._mode in (Pin.IN, Pin.OUT):
135             # digital read
136             if val is None:
137                 return self.read()
138             # digital write
139             if val in (Pin.LOW, Pin.HIGH):
140                 return self.write(val)
141             # nope
142             raise ValueError("Invalid value for pin.")
143         # Analog In
144         if self._mode == Pin.ADC:
145             if val is None:
146                 return self.read()
147             # read only
148             raise AttributeError("'AnalogIn' object has no attribute 'value'")
149         # Analog Out
150         if self._mode == Pin.DAC:
151             if val is None:
152                 # write only
153                 raise AttributeError("unreadable attribute")
154             self.write(val)
155             return None
156         raise RuntimeError(
157             "No action for mode {} with value {}".format(self._mode, val)
158         )
159
160
161 # create pin instances for each pin
162 D0 = Pin(0)
163 D1 = Pin(1)
164 D2 = Pin(2)
165 D3 = Pin(3)
166 D4 = Pin(4)
167 # Special "digital" pins
168 D6 = Pin(6)
169 # Analog pins
170 A0 = Pin(7)
171 A1 = Pin(8)
172 A2 = Pin(9)
173 A3 = Pin(10)
174
175 D7 = Pin(11)
176
177 # I2C pins
178 SDA = Pin()
179 SCL = Pin()
180
181 # SPI pins
182 SCLK = Pin()
183 SCK = Pin()
184 MOSI = Pin()
185 MISO = Pin()
186 CS = Pin()
187
188 # UART pins
189 UART_TX = Pin()
190 UART_RX = Pin()