rpc — библиотека rpc¶
Модуль rpc на OpenMV Cam позволяет подключить вашу OpenMV Cam к другому микроконтроллеру или компьютеру и выполнять удалённые вызовы python (или процедур) на вашей OpenMV Cam. Модуль rpc также допускает обратное направление, если вы хотите, чтобы ваша OpenMV Cam могла выполнять удалённые вызовы процедур (или python) на другом микроконтроллере или компьютере.
Как использовать библиотеку¶
Минимальный ведомый (slave), который предоставляет одну функцию обратного вызова по UART:
import rpc
import csi
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)
interface = rpc.rpc_uart_slave(baudrate=115200)
def snapshot(_):
return csi0.snapshot().compress().bytearray()
interface.register_callback(snapshot)
interface.loop() # Does not return.
Соответствующий ведущий (master), запрашивающий у ведомого кадр JPEG:
import rpc
interface = rpc.rpc_uart_master(baudrate=115200)
result = interface.call("snapshot")
if result is None:
print("communication failed")
elif len(result) == 0:
print("remote function not registered on the slave")
else:
# result is a memoryview of the JPEG bytes returned by the slave.
print("received", len(result), "bytes")
Замените rpc_uart_master / rpc_uart_slave на соответствующую пару can, i2c или spi, чтобы использовать другой транспорт.
В общем случае, чтобы устройство-контроллер могло использовать библиотеку rpc, вы создаёте объект интерфейса с помощью библиотеки rpc. Например:
interface = rpc.rpc_uart_master(baudrate=115200)
Это создаёт интерфейс UART для взаимодействия с ведомым rpc.
После создания интерфейса вам нужно просто выполнить:
memory_view_object_result = interface.call("remote_function_or_method_name", bytes_object_argument)
И библиотека rpc попытается выполнить эту "remote_function_or_method_name" на ведомом устройстве. Удалённая функция или метод получит bytes_object_argument, размер которого может достигать 2^32-1 байт. После завершения выполнения удалённый метод вернёт memory_view_object_result, размер которого также может достигать 2^32-1 байт. Поскольку аргумент и ответ являются обобщёнными контейнерами байтов, вы можете передавать через библиотеку rpc что угодно и получать ответ любого типа. Простой способ передачи аргументов — использовать struct.pack() для создания аргумента и struct.unpack() для приёма аргумента на другой стороне. В качестве ответа другая сторона может отправить строковый объект или строку json в качестве результата, который затем может интерпретировать ведущий.
Что касается ошибок: если вы попытаетесь выполнить несуществующее имя функции или метода, метод rpc_master.call() вернёт пустой объект bytes(). Если библиотеке rpc не удалось связаться с ведомым устройством, библиотека rpc вернёт None.
Для простоты библиотека rpc не поддерживает постоянное соединение между ведущим и ведомым устройствами. Метод rpc_master.call() объединяет попытку подключения к ведомому, запуск выполнения удалённой функции или метода и получение результата.
Теперь, на стороне ведомого устройства вам нужно создать интерфейс rpc для связи с ведущим. Это выглядит так:
interface = rpc.rpc_uart_slave(baudrate=115200)
Это создаст слой интерфейса UART для взаимодействия с ведущим rpc.
После создания интерфейса ведомого вам нужно зарегистрировать функции обратного вызова, которые ведущий сможет вызывать через объект интерфейса:
def remote_function_or_method_name(memoryview_object_argument):
<lots of code>
return bytes_object_result
interface.register_callback(remote_function_or_method_name)
Вы можете зарегистрировать на ведомом устройстве сколько угодно функций обратного вызова. Наконец, после завершения регистрации функций обратного вызова вам нужно просто выполнить:
interface.loop()
На ведомом устройстве, чтобы запустить библиотеку rpc и начать прослушивание ведущего. Обратите внимание, что метод rpc_slave.loop() не возвращает управление.
class rpc – базовый класс rpc¶
Базовый класс rpc переопределяется классами rpc_master и rpc_slave для создания интерфейсов ведущего и ведомого. Он не предназначен для прямого использования.
- class rpc.rpc¶
Создаёт объект
rpc. Не предназначен для прямого использования.- get_bytes(buff: bytearray | memoryview, timeout_ms: int) bytes | None¶
Переопределяется транспортно-зависимыми подклассами. Заполняет
buffбайтами из нижележащего интерфейса в течениеtimeout_msмиллисекунд. ВозвращаетNoneпри истечении времени ожидания.
- put_bytes(data: bytes | memoryview, timeout_ms: int) None¶
Переопределяется транспортно-зависимыми подклассами. Отправляет
dataчерез нижележащий интерфейс в течениеtimeout_msмиллисекунд.
- stream_reader(call_back: Callable[[memoryview], None], queue_depth: int = 1, read_timeout_ms: int = 5000) None¶
Принимает поток полезных нагрузок от удалённого
rpc.stream_writer. Должен вызываться изнутри функции обратного вызоваrpc_slave(или непосредственно после успешногоrpc_master.call), как только обе стороны синхронизировались.call_back– вызываемый объект, вызываемый один раз для каждой принятой полезной нагрузки какcall_back(data), гдеdata— этоmemoryview. Возвращаемое значение игнорируется.queue_depth– число кадров «в пути», которые писателю разрешено отправить до ожидания читателя. Большие значения увеличивают пропускную способность ценой памяти.read_timeout_ms– миллисекунды ожидания на каждую полезную нагрузку.
Возвращает управление при любой ошибке. Чтобы отменить, возбудите исключение внутри
call_back; на удалённой стороне истечёт время ожидания.
- stream_writer(call_back: Callable[[], bytes | memoryview], write_timeout_ms: int = 5000) None¶
Отправляет поток полезных нагрузок удалённому
rpc.stream_reader. Должен вызываться изнутри функции обратного вызоваrpc_slave(или непосредственно после успешногоrpc_master.call), как только обе стороны синхронизировались.call_back– вызываемый объект, вызываемый без аргументов, который возвращает следующую полезную нагрузкуbytesилиmemoryviewдля отправки.write_timeout_ms– миллисекунды ожидания при отправке каждой полезной нагрузки.
Возвращает управление при любой ошибке. Чтобы отменить, возбудите исключение внутри
call_back; на удалённой стороне истечёт время ожидания.
class rpc_master – базовый класс rpc_master¶
rpc_master — это базовый класс. Используйте один из транспортно-зависимых подклассов (rpc_can_master, rpc_i2c_master, rpc_spi_master, rpc_uart_master).
- class rpc.rpc_master¶
Создаёт объект
rpc_master. Не предназначен для прямого использования.- call(name: str, data: bytes = bytes(), send_timeout: int = 1000, recv_timeout: int = 1000) memoryview | None¶
Выполняет удалённый вызов на ведомом устройстве.
name– строковое имя удалённой функции или метода для выполнения.data– объект типаbytes, передаваемый в качестве аргумента удалённой функции.send_timeout– миллисекунды ожидания при подключении к ведомому и запуске выполнения удалённой функции. После того как ведущий начинает отправлять аргумент, это больше не применяется; библиотека выделяет до 5 секунд на передачу аргумента.recv_timeout– миллисекунды ожидания начала возврата ответа ведомым устройством. После того как ведущий начинает принимать ответ, это больше не применяется; библиотека выделяет до 5 секунд на передачу ответа.
Возвращает
memoryviewответа при успехе, пустойbytes(), если удалённое имя не существует на ведомом, илиNoneпри сбое связи.
class rpc_slave – базовый класс rpc_slave¶
rpc_slave — это базовый класс. Используйте один из транспортно-зависимых подклассов (rpc_can_slave, rpc_i2c_slave, rpc_spi_slave, rpc_uart_slave).
- class rpc.rpc_slave¶
Создаёт объект
rpc_slave. Не предназначен для прямого использования.- register_callback(cb: Callable[[memoryview], bytes | memoryview]) None¶
Регистрирует функцию обратного вызова, которую ведущий может вызвать по имени.
cb— это вызываемый объект, принимающий один аргументmemoryviewи возвращающий объект типаbytes. В качестве ключа поиска используется__name__функции обратного вызова.
- schedule_callback(cb: Callable[[], None]) None¶
Планирует однократное выполнение
cb(вызываемого объекта без аргументов) сразу после того, как выполняющаяся в данный момент функция обратного вызова rpc успешно вернёт свой ответ ведущему. Должен вызываться изнутри функции обратного вызова rpc. Позволяет выполнять длительную работу или сквозные передачиrpc.get_bytes/rpc.put_bytesмежду транзакциями rpc. Повторно регистрируйте при каждом вызове, если требуется повторное выполнение.
- setup_loop_callback(cb: Callable[[], None]) None¶
Регистрирует
cb(вызываемый объект без аргументов) для вызова на каждой итерацииrpc_slave.loop. В отличие отrpc_slave.schedule_callback, эта функция обратного вызова остаётся зарегистрированной. Должна быть неблокирующей; частота вызова непостоянна.
- loop(recv_timeout: int = 1000, send_timeout: int = 1000) None¶
Запускает цикл диспетчеризации ведомого rpc. Не возвращает управление, кроме как при исключении, возбуждённом из функции обратного вызова.
recv_timeout– миллисекунды ожидания команды от ведущего перед повторной попыткой.send_timeout– миллисекунды ожидания подтверждения ответа ведущим перед возвратом к приёму.
class rpc_can_master – интерфейс ведущего CAN¶
Управление другим устройством rpc по CAN.
- class rpc.rpc_can_master(message_id: int = 0x7FF, bit_rate: int = 250000, sample_point: float = 75, can_bus: int = 2)¶
message_id– 11-битный идентификатор сообщения CAN, используемый для передачи данных.bit_rate– битовая скорость CAN в битах в секунду.sample_point– процент точки выборки Tseg1/Tseg2 (например, 50.0, 62.5, 75, 87.5).can_bus– номер периферийного устройства CAN.
message_idиbit_rateведущего и ведомого должны совпадать. Шина должна быть терминирована резистором 120 Ом.
class rpc_can_slave – интерфейс ведомого CAN¶
Управление со стороны другого устройства rpc по CAN.
class rpc_i2c_master – интерфейс ведущего I2C¶
Управление другим устройством rpc по I2C.
- class rpc.rpc_i2c_master(slave_addr: int = 0x12, rate: int = 100000, i2c_bus: int = 2)¶
slave_addr– 7-битный I2C-адрес ведомого устройства.rate– тактовая частота шины I2C в Гц.i2c_bus– номер периферийного устройства I2C.
Адреса ведущего и ведомого должны совпадать. На линиях SCL и SDA требуются внешние подтягивающие резисторы, и оба устройства должны иметь общую землю.
class rpc_i2c_slave – интерфейс ведомого I2C¶
Управление со стороны другого устройства rpc по I2C.
class rpc_spi_master – интерфейс ведущего SPI¶
Управление другим устройством rpc по SPI.
- class rpc.rpc_spi_master(cs_pin: str = 'P3', freq: int = 1000000, clk_polarity: int = 1, clk_phase: int = 0, spi_bus: int = 2)¶
cs_pin– имя вывода выбора кристалла (chip-select).freq– тактовая частота шины SPI в Гц.clk_polarity– уровень тактового сигнала в покое (0 или 1).clk_phase– выборка данных по первому (0) или второму (1) фронту тактового сигнала.spi_bus– номер периферийного устройства SPI.
Настройки ведущего и ведомого должны совпадать. Подключайте CS, SCLK, MOSI, MISO напрямую. Оба устройства должны иметь общую землю.
class rpc_spi_slave – интерфейс ведомого SPI¶
Управление со стороны другого устройства rpc по SPI.
- class rpc.rpc_spi_slave(cs_pin: str = 'P3', clk_polarity: int = 1, clk_phase: int = 0, spi_bus: int = 2)¶
cs_pin– имя входного вывода выбора кристалла (chip-select).clk_polarity– уровень тактового сигнала в покое (0 или 1).clk_phase– выборка данных по первому (0) или второму (1) фронту тактового сигнала.spi_bus– номер периферийного устройства SPI.
class rpc_uart_master – интерфейс ведущего UART¶
Управление другим устройством rpc по асинхронному последовательному интерфейсу (UART).
- class rpc.rpc_uart_master(baudrate: int = 9600, uart_port: int = 3)¶
baudrate– скорость передачи последовательного порта (бод).uart_port– номер периферийного устройства UART.
Скорости передачи ведущего и ведомого должны совпадать. Подключите TX ведущего к RX ведомого и RX ведущего к TX ведомого. Оба устройства должны иметь общую землю.
class rpc_uart_slave – интерфейс ведомого UART¶
Управление со стороны другого устройства rpc по асинхронному последовательному интерфейсу (UART).