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.rpc_can_slave(message_id: int = 0x7FF, bit_rate: int = 250000, sample_point: float = 75, can_bus: int = 2)

Дивіться rpc_can_master для опису аргументів.

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.rpc_i2c_slave(slave_addr: int = 0x12, i2c_bus: int = 2)
  • slave_addr – 7-бітна адреса I2C, на яку цей підлеглий відповідає.

  • i2c_bus – номер периферійного пристрою 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).

class rpc.rpc_uart_slave(baudrate: int = 9600, uart_port: int = 3)
  • baudrate – швидкість передачі послідовного порту (бод).

  • uart_port – номер периферійного пристрою UART.