AS5600
241 строка · 13.3 Кб
1# micropython
2# MIT license
3# Copyright (c) 2022 Roman Shevchik goctaprog@gmail.com
4"""MicroPython модуль для работы с шинами ввода/вывода"""
5
6import math
7from machine import I2C, SPI, Pin
8
9
10def _mpy_bl(value: int) -> int:
11"""Возвращает место, занимаемое значением value в битах.
12Аналог int.bit_length(), которая есть в Python, но отсутствует в MicroPython!"""
13if 0 == value:
14return 0
15return 1 + int(math.log2(abs(value)))
16
17
18class BusAdapter:
19"""Посредник между шиной ввода/вывода и классом ввода/вывода устройства"""
20def __init__(self, bus: [I2C, SPI]):
21self.bus = bus
22
23def get_bus_type(self) -> type:
24"""Возвращает тип шины"""
25return type(self.bus)
26
27def read_register(self, device_addr: [int, Pin], reg_addr: int, bytes_count: int) -> bytes:
28"""считывает из регистра датчика значение.
29device_addr - адрес датчика на шине. Для шины SPI это физический вывод MCU!
30reg_addr - адрес регистра в адресном пространстве датчика.
31bytes_count - размер значения в байтах."""
32raise NotImplementedError
33
34def write_register(self, device_addr: [int, Pin], reg_addr: int, value: [int, bytes, bytearray],
35bytes_count: int, byte_order: str):
36"""записывает данные value в датчик, по адресу reg_addr.
37bytes_count - кол-во записываемых байт из value.
38byte_order - порядок расположения байт в записываемом значении."""
39raise NotImplementedError
40
41def read(self, device_addr: [int, Pin], n_bytes: int) -> bytes:
42"""Читает из устройства на шине с адресом device_addr, n_bytes байт.
43Возвращает экземпляр класса типа bytes"""
44raise NotImplementedError
45
46def read_to_buf(self, device_addr: [int, Pin], buf: bytearray) -> bytes:
47"""Читает из устройства на шине, с адресом device_addr, кол-во байт, равное длине буфера buf.
48Возвращает ссылку на buf"""
49raise NotImplementedError
50
51def write(self, device_addr: [int, Pin], buf: bytes):
52"""Записывает в устройство на шине все байты из буфера buf"""
53raise NotImplementedError
54
55def write_const(self, device_addr: [int, Pin], val: int, count: int):
56"""Отправляет пакет байт со значение val количеством count на шину.
57Часто, при работе с дисплеями или памятью, требуется заполнение экрана/области
58постоянным значением. Для этого и предназначен этот метод!
59Вызов его для сравнительно медленных шин - плохая идея!"""
60if 0 == count:
61return # нет ничего
62# bl = val.bit_length() # bit_length() отсутствует в MicroPython
63bl = _mpy_bl(val)
64if bl > 8:
65raise ValueError(f"The value must take no more than 8 bits! Current: {bl}")
66_max = 16
67if count < _max:
68_max = count
69# вычисляю кол-во повторений тела цикла
70repeats = count // _max # количество итераций
71b = bytearray([val for _ in range(_max)])
72for _ in range(repeats):
73self.write(device_addr, b)
74# вычисляю остаток
75remainder = count - _max * repeats
76if remainder:
77b = bytearray([val for _ in range(remainder)])
78self.write(device_addr, b)
79
80def read_buf_from_memory(self, device_addr: [int, Pin], mem_addr, buf, address_size: int):
81"""Читает из устройства с адресом device_addr в буфер buf, начиная с адреса в устройстве mem_addr.
82Количество считываемых байт определяется длинной буфера buf.
83address_size - определяет размер адреса в байтах. (в ESP8266 этот аргумент не
84распознается и размер адреса всегда равен 1 (8 бит))."""
85raise NotImplementedError
86
87def write_buf_to_memory(self, device_addr: [int, Pin], mem_addr, buf):
88raise NotImplementedError
89
90
91class I2cAdapter(BusAdapter):
92"""Адаптер шины I2C"""
93def __init__(self, bus: I2C):
94super().__init__(bus)
95
96def write_register(self, device_addr: int, reg_addr: int, value: [int, bytes, bytearray],
97bytes_count: int, byte_order: str):
98"""записывает данные value в датчик, по адресу reg_addr.
99bytes_count - кол-во записываемых данных
100value - должно быть типов int, bytes, bytearray"""
101buf = None
102if isinstance(value, int):
103buf = value.to_bytes(bytes_count, byte_order)
104if isinstance(value, (bytes, bytearray)):
105buf = value
106
107return self.bus.writeto_mem(device_addr, reg_addr, buf)
108
109def read_register(self, device_addr: int, reg_addr: int, bytes_count: int) -> bytes:
110"""считывает из регистра датчика значение.
111bytes_count - размер значения в байтах"""
112return self.bus.readfrom_mem(device_addr, reg_addr, bytes_count)
113
114def read(self, device_addr: int, n_bytes: int) -> bytes:
115return self.bus.readfrom(device_addr, n_bytes)
116
117def read_to_buf(self, device_addr: int, buf: bytearray) -> bytes:
118"""Читает из устройства на шине с адресом device_addr в буфер buf количество байт, равное длине(len) буфера!"""
119self.bus.readfrom_into(device_addr, buf)
120return buf
121
122def write(self, device_addr: int, buf: bytes):
123return self.bus.writeto(device_addr, buf)
124
125def read_buf_from_memory(self, device_addr: int, mem_addr, buf, address_size: int = 1):
126"""Читает из устройства с адресом device_addr в буфер buf, начиная с адреса в устройстве mem_addr.
127Количество считываемых байт определяется длинной буфера buf.
128address_size - определяет размер адреса в байтах. (в ESP8266 этот аргумент не распознается и размер адреса
129всегда равен 1 (8 бит)).
130Расширение возможностей базового класса."""
131return self.bus.readfrom_mem_into(device_addr, mem_addr, buf)
132
133def write_buf_to_memory(self, device_addr: int, mem_addr, buf):
134"""Записывает в устройство с адресом device_addr все байты из буфера buf.
135Запись начинается с адреса в устройстве: mem_addr.
136Расширение возможностей базового класса."""
137return self.bus.writeto_mem(device_addr, mem_addr, buf)
138
139
140class SpiAdapter(BusAdapter):
141"""Адаптер шины SPI"""
142def __init__(self, bus: SPI, data_mode: Pin = None):
143"""Параметр data_mode представляет собой вывод MCU, который используется для установки флага,
144что посылка является данными (high) или командой (low). Например это необходимо при обмене с ILI9481."""
145super().__init__(bus)
146# вывод MCU для режима данных
147self.data_mode_pin = data_mode
148# использовать ли вывод MCU для режима данных (Истина) или команд (Ложь)
149self.use_data_mode_pin = False
150# флаг для методов write.. . Если Истина, то data_mode (Pin) будет установлена в Истина, иначе в Ложь!
151# flag for write.. methods. If True, then data_mode (Pin) will be set to True, otherwise to False!
152self.data_packet = False
153# индекс/номер байта в пересылаемом устройству по шину буферу, в котором находится адрес регистра устройства!
154self._address_index = 0
155# ссылка на функцию подготовки содержимого буфера перед его пересылкой в устройство!
156# вида prepare(buf:bytearray, address_index:int) -> bytes: ...
157# или None
158self._prepare_before_send_ref = None
159
160@property
161def prepare_func(self):
162"""Возвращает ссылку на функцию обработки буфера перед отправкой его по шине"""
163return self._prepare_before_send_ref
164
165@prepare_func.setter
166def prepare_func(self, value):
167"""Устанавливает ссылку на функцию обработки буфера перед отправкой его по шине"""
168self._prepare_before_send_ref = value
169
170def _call_prepare(self, buf: bytearray):
171ref = self._prepare_before_send_ref
172if ref is not None:
173ref(buf, self._address_index)
174
175def read(self, device_addr: Pin, n_bytes: int) -> bytes:
176"""Read a number of bytes specified by n_bytes while continuously writing the single byte given by write.
177Returns a bytes object with the data that was read."""
178try:
179device_addr.low()
180return self.bus.read(n_bytes)
181finally:
182device_addr.high()
183
184def read_to_buf(self, device_addr: Pin, buf) -> bytes:
185"""Читает из устройства на шине с адресом device_addr в буфер buf количество байт, равное длине(len) буфера!"""
186try:
187device_addr.low()
188self.bus.readinto(buf, 0x00)
189return buf
190finally:
191device_addr.high()
192
193def write(self, device_addr: Pin, buf: bytes):
194"""Параметр data_packet представляет собой признак того, что посылка является данными (high) или командой (low).
195Например это необходимо при обмене ILI9481.
196Write the bytes contained in buf. Returns None.
197The data_packet parameter is an indication that the package is data (high) or command (low).
198For example, this is necessary when exchanging ILI9481."""
199try:
200device_addr.low() # chip select
201if self.use_data_mode_pin and self.data_mode_pin:
202self.data_mode_pin.value(self.data_packet)
203return self.bus.write(buf)
204finally:
205device_addr.high()
206
207def write_and_read(self, device_addr: Pin, wr_buf: bytes, rd_buf: bytes):
208"""Параметр data_packet представляет собой признак того, что посылка является данными (high) или командой (low).
209Например это необходимо при обмене ILI9481.
210Расширение возможностей базового класса.
211Write the bytes from write_buf while reading into read_buf. The buffers can be the same or different,
212but both buffers must have the same length. Returns None.
213The data_packet parameter is an indication that the package is data (high) or command (low).
214For example, this is necessary when exchanging ILI9481."""
215try:
216device_addr.low() # chip select
217if self.use_data_mode_pin and self.data_mode_pin:
218self.data_mode_pin.value(self.data_packet)
219return self.bus.write_readinto(wr_buf, rd_buf)
220finally:
221device_addr.high()
222
223def read_buf_from_memory(self, device_addr: Pin, mem_addr, buf):
224"""Читает из устройства с адресом device_addr в буфер buf, начиная с адреса в устройстве mem_addr.
225Количество считываемых байт определяется длинной буфера buf."""
226try:
227device_addr.low() # chip select
228# пока нет реализации!!!
229raise NotImplementedError
230finally:
231device_addr.high()
232
233def write_buf_to_memory(self, device_addr: Pin, mem_addr, buf):
234try:
235device_addr.low() # chip select
236# подготовка буфера к пересылке
237self._call_prepare(buf)
238# пока нет реализации!!!
239raise NotImplementedError
240finally:
241device_addr.high()
242