]> Repositories - Adafruit_Blinka-hackapet.git/blob - src/adafruit_blinka/microcontroller/generic_agnostic_board/PWMOut.py
Merge branch 'adafruit:main' into add-pwmout-generic-board
[Adafruit_Blinka-hackapet.git] / src / adafruit_blinka / microcontroller / generic_agnostic_board / PWMOut.py
1 # SPDX-FileCopyrightText: 2024 Brent Rubell for Adafruit Industries
2 #
3 # SPDX-License-Identifier: MIT
4 """Mock PWMOut Wrapper for Generic Agnostic Board"""
5
6 class PWMError(IOError):
7     """Base class for PWM errors."""
8
9
10 class PWMOut:
11     """Pulse Width Modulation Output Class"""
12
13     def __init__(self, pin, *, frequency=500, duty_cycle=0, variable_frequency=False):
14         self._pwmpin = None
15         self._period = 0
16         self._open(pin, duty_cycle, frequency, variable_frequency)
17
18     def __del__(self):
19         self.deinit()
20
21     def __enter__(self):
22         return self
23
24     def __exit__(self, t, value, traceback):
25         self.deinit()
26
27     def _open(self, pin, duty=0, freq=500, variable_frequency=False):
28         self._pin = pin
29
30         # set frequency
31         self.frequency = freq
32         # set duty
33         self.duty_cycle = duty
34
35         self.enabled = True
36
37     def deinit(self):
38         """Deinit the PWM."""
39         if self._pwmpin is not None:
40             self._pwmpin = None
41
42     def _is_deinited(self):
43         if self._pwmpin is None:
44             raise ValueError(
45                 "Object has been deinitialize and can no longer "
46                 "be used. Create a new object."
47             )
48
49     @property
50     def period(self):
51         """Get or set the PWM's output period in seconds.
52
53         Raises:
54             PWMError: if an I/O or OS error occurs.
55             TypeError: if value type is not int or float.
56
57         :type: int, float
58         """
59         return 1.0 / self.frequency
60
61     @period.setter
62     def period(self, period):
63         if not isinstance(period, (int, float)):
64             raise TypeError("Invalid period type, should be int or float.")
65
66         self.frequency = 1.0 / period
67
68     @property
69     def duty_cycle(self):
70         """Get or set the PWM's output duty cycle which is the fraction of
71         each pulse which is high. 16-bit
72
73         Raises:
74             PWMError: if an I/O or OS error occurs.
75             TypeError: if value type is not int or float.
76             ValueError: if value is out of bounds of 0.0 to 1.0.
77
78         :type: int, float
79         """
80         return int(self._duty_cycle * 65535)
81
82     @duty_cycle.setter
83     def duty_cycle(self, duty_cycle):
84         if not isinstance(duty_cycle, (int, float)):
85             raise TypeError("Invalid duty cycle type, should be int or float.")
86
87         if not 0 <= duty_cycle <= 65535:
88             raise ValueError("Invalid duty cycle value, should be between 0 and 65535")
89
90         # convert from 16-bit
91         duty_cycle /= 65535.0
92
93         self._duty_cycle = duty_cycle
94
95     @property
96     def frequency(self):
97         """Get or set the PWM's output frequency in Hertz.
98
99         Raises:
100             PWMError: if an I/O or OS error occurs.
101             TypeError: if value type is not int or float.
102
103         :type: int, float
104         """
105
106         return self._frequency
107
108     @frequency.setter
109     def frequency(self, frequency):
110         if not isinstance(frequency, (int, float)):
111             raise TypeError("Invalid frequency type, should be int or float.")
112         self._frequency = frequency
113
114     @property
115     def enabled(self):
116         """Get or set the PWM's output enabled state.
117
118         Raises:
119             PWMError: if an I/O or OS error occurs.
120             TypeError: if value type is not bool.
121
122         :type: bool
123         """
124         return self._enabled
125
126     @enabled.setter
127     def enabled(self, value):
128         if not isinstance(value, bool):
129             raise TypeError("Invalid enabled type, should be string.")
130
131         self._enabled = value
132
133     # String representation
134     def __str__(self):
135         return "pin %s (freq=%f Hz, duty_cycle=%f%%)" % (
136             self._pin,
137             self.frequency,
138             self.duty_cycle,
139         )