ads1115
242 строки · 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Расширение возможностей базового класса."""
131self.bus.readfrom_mem_into(device_addr, mem_addr, buf)
132return buf
133
134def write_buf_to_memory(self, device_addr: int, mem_addr, buf):
135"""Записывает в устройство с адресом device_addr все байты из буфера buf.
136Запись начинается с адреса в устройстве: mem_addr.
137Расширение возможностей базового класса."""
138return self.bus.writeto_mem(device_addr, mem_addr, buf)
139
140
141class SpiAdapter(BusAdapter):
142"""Адаптер шины SPI"""
143def __init__(self, bus: SPI, data_mode: Pin = None):
144"""Параметр data_mode представляет собой вывод MCU, который используется для установки флага,
145что посылка является данными (high) или командой (low). Например это необходимо при обмене с ILI9481."""
146super().__init__(bus)
147# вывод MCU для режима данных
148self.data_mode_pin = data_mode
149# использовать ли вывод MCU для режима данных (Истина) или команд (Ложь)
150self.use_data_mode_pin = False
151# флаг для методов write.. . Если Истина, то data_mode (Pin) будет установлена в Истина, иначе в Ложь!
152# flag for write.. methods. If True, then data_mode (Pin) will be set to True, otherwise to False!
153self.data_packet = False
154# индекс/номер байта в пересылаемом устройству по шину буферу, в котором находится адрес регистра устройства!
155self._address_index = 0
156# ссылка на функцию подготовки содержимого буфера перед его пересылкой в устройство!
157# вида prepare(buf:bytearray, address_index:int) -> bytes: ...
158# или None
159self._prepare_before_send_ref = None
160
161@property
162def prepare_func(self):
163"""Возвращает ссылку на функцию обработки буфера перед отправкой его по шине"""
164return self._prepare_before_send_ref
165
166@prepare_func.setter
167def prepare_func(self, value):
168"""Устанавливает ссылку на функцию обработки буфера перед отправкой его по шине"""
169self._prepare_before_send_ref = value
170
171def _call_prepare(self, buf: bytearray):
172ref = self._prepare_before_send_ref
173if ref is not None:
174ref(buf, self._address_index)
175
176def read(self, device_addr: Pin, n_bytes: int) -> bytes:
177"""Read a number of bytes specified by n_bytes while continuously writing the single byte given by write.
178Returns a bytes object with the data that was read."""
179try:
180device_addr.low()
181return self.bus.read(n_bytes)
182finally:
183device_addr.high()
184
185def read_to_buf(self, device_addr: Pin, buf) -> bytes:
186"""Читает из устройства на шине с адресом device_addr в буфер buf количество байт, равное длине(len) буфера!"""
187try:
188device_addr.low()
189self.bus.readinto(buf, 0x00)
190return buf
191finally:
192device_addr.high()
193
194def write(self, device_addr: Pin, buf: bytes):
195"""Параметр data_packet представляет собой признак того, что посылка является данными (high) или командой (low).
196Например это необходимо при обмене ILI9481.
197Write the bytes contained in buf. Returns None.
198The data_packet parameter is an indication that the package is data (high) or command (low).
199For example, this is necessary when exchanging ILI9481."""
200try:
201device_addr.low() # chip select
202if self.use_data_mode_pin and self.data_mode_pin:
203self.data_mode_pin.value(self.data_packet)
204return self.bus.write(buf)
205finally:
206device_addr.high()
207
208def write_and_read(self, device_addr: Pin, wr_buf: bytes, rd_buf: bytes):
209"""Параметр data_packet представляет собой признак того, что посылка является данными (high) или командой (low).
210Например это необходимо при обмене ILI9481.
211Расширение возможностей базового класса.
212Write the bytes from write_buf while reading into read_buf. The buffers can be the same or different,
213but both buffers must have the same length. Returns None.
214The data_packet parameter is an indication that the package is data (high) or command (low).
215For example, this is necessary when exchanging ILI9481."""
216try:
217device_addr.low() # chip select
218if self.use_data_mode_pin and self.data_mode_pin:
219self.data_mode_pin.value(self.data_packet)
220return self.bus.write_readinto(wr_buf, rd_buf)
221finally:
222device_addr.high()
223
224def read_buf_from_memory(self, device_addr: Pin, mem_addr, buf):
225"""Читает из устройства с адресом device_addr в буфер buf, начиная с адреса в устройстве mem_addr.
226Количество считываемых байт определяется длинной буфера buf."""
227try:
228device_addr.low() # chip select
229# пока нет реализации!!!
230raise NotImplementedError
231finally:
232device_addr.high()
233
234def write_buf_to_memory(self, device_addr: Pin, mem_addr, buf):
235try:
236device_addr.low() # chip select
237# подготовка буфера к пересылке
238self._call_prepare(buf)
239# пока нет реализации!!!
240raise NotImplementedError
241finally:
242device_addr.high()
243