rpc — biblioteca rpc

El módulo rpc de la OpenMV Cam le permite conectar su OpenMV Cam a otro microcontrolador o computadora y ejecutar llamadas remotas de python (o procedimientos) en su OpenMV Cam. El módulo rpc también permite hacerlo a la inversa si desea que su OpenMV Cam pueda ejecutar llamadas a procedimientos remotos (o python) en otro microcontrolador o computadora.

Cómo usar la biblioteca

Un esclavo mínimo que expone una función de retorno (callback) a través de 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.

El maestro correspondiente que solicita al esclavo un fotograma 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")

Intercambie rpc_uart_master / rpc_uart_slave por el par can, i2c o spi correspondiente para usar un transporte distinto.

En general, para que el dispositivo controlador use la biblioteca rpc deberá crear un objeto de interfaz mediante la biblioteca rpc. Por ejemplo:

interface = rpc.rpc_uart_master(baudrate=115200)

Esto crea una interfaz UART para comunicarse con un esclavo rpc.

Una vez creada la interfaz solo necesita hacer:

memory_view_object_result = interface.call("remote_function_or_method_name", bytes_object_argument)

Y la biblioteca rpc intentará ejecutar ese "remote_function_or_method_name" en el esclavo. La función o método remoto recibirá el bytes_object_argument, que puede tener un tamaño de hasta 2^32-1 bytes. Una vez que el método remoto termine de ejecutarse devolverá un memory_view_object_result, que también puede tener hasta 2^32-1 bytes de tamaño. Dado que tanto el argumento como la respuesta son contenedores genéricos de bytes, puede pasar cualquier cosa a través de la biblioteca rpc y recibir cualquier tipo de respuesta. Una forma sencilla de pasar argumentos es usar struct.pack() para crear el argumento y struct.unpack() para recibir el argumento en el otro lado. En cuanto a la respuesta, el otro lado puede enviar un objeto de cadena o una cadena json como resultado, que el maestro puede luego interpretar.

En cuanto a los errores, si intenta ejecutar un nombre de función o método inexistente, el método rpc_master.call() devolverá un objeto bytes() vacío. Si la biblioteca rpc no logró comunicarse con el esclavo, la biblioteca rpc devolverá None.

Para mantener la simplicidad, la biblioteca rpc no mantiene una conexión entre los dispositivos maestro y esclavo. El método rpc_master.call() encapsula el intento de conectarse al esclavo, el inicio de la ejecución de la función o método remoto y la obtención del resultado.

Ahora, del lado del esclavo debe crear una interfaz rpc para comunicarse con el maestro. Esto se ve así:

interface = rpc.rpc_uart_slave(baudrate=115200)

Esto creará la capa de interfaz UART para comunicarse con un maestro rpc.

Una vez que cree la interfaz del esclavo, deberá registrar funciones de retorno (callbacks) que el maestro pueda llamar mediante el objeto de interfaz:

def remote_function_or_method_name(memoryview_object_argument):
    <lots of code>
    return bytes_object_result

interface.register_callback(remote_function_or_method_name)

Puede registrar tantas funciones de retorno (callbacks) como desee en el esclavo. Finalmente, una vez que haya terminado de registrar las funciones de retorno, solo necesita ejecutar:

interface.loop()

En el esclavo, para iniciar la biblioteca rpc y comenzar a escuchar al maestro. Tenga en cuenta que el método rpc_slave.loop() no retorna.

class rpc – clase base rpc

La clase base rpc es reimplementada por las clases rpc_master y rpc_slave para crear las interfaces maestro y esclavo. No está pensada para usarse directamente.

class rpc.rpc

Crea un objeto rpc. No está pensado para usarse directamente.

get_bytes(buff: bytearray | memoryview, timeout_ms: int) bytes | None

Reimplementado por subclases específicas de transporte. Rellena buff con bytes de la interfaz subyacente dentro de timeout_ms milisegundos. Devuelve None si se agota el tiempo de espera.

put_bytes(data: bytes | memoryview, timeout_ms: int) None

Reimplementado por subclases específicas de transporte. Envía data a través de la interfaz subyacente dentro de timeout_ms milisegundos.

stream_reader(call_back: Callable[[memoryview], None], queue_depth: int = 1, read_timeout_ms: int = 5000) None

Recibe un flujo de cargas útiles desde un rpc.stream_writer remoto. Debe llamarse desde dentro de una función de retorno de rpc_slave (o directamente después de una llamada rpc_master.call exitosa) una vez que ambos lados se hayan sincronizado.

  • call_back – objeto invocable llamado una vez por cada carga útil recibida como call_back(data), donde data es un memoryview. El valor de retorno se ignora.

  • queue_depth – número de fotogramas en tránsito que el escritor puede enviar antes de esperar al lector. Valores más altos aumentan el rendimiento a costa de memoria.

  • read_timeout_ms – milisegundos a esperar por cada carga útil.

Retorna ante cualquier error. Para cancelar, lance una excepción dentro de call_back; el lado remoto agotará el tiempo de espera.

stream_writer(call_back: Callable[[], bytes | memoryview], write_timeout_ms: int = 5000) None

Envía un flujo de cargas útiles a un rpc.stream_reader remoto. Debe llamarse desde dentro de una función de retorno de rpc_slave (o directamente después de una llamada rpc_master.call exitosa) una vez que ambos lados se hayan sincronizado.

  • call_back – objeto invocable llamado sin argumentos que devuelve la siguiente carga útil bytes o memoryview a enviar.

  • write_timeout_ms – milisegundos a esperar al enviar cada carga útil.

Retorna ante cualquier error. Para cancelar, lance una excepción dentro de call_back; el lado remoto agotará el tiempo de espera.

class rpc_master – clase base rpc_master

rpc_master es una clase base. Use una de las subclases específicas de transporte (rpc_can_master, rpc_i2c_master, rpc_spi_master, rpc_uart_master).

class rpc.rpc_master

Crea un objeto rpc_master. No está pensado para usarse directamente.

call(name: str, data: bytes = bytes(), send_timeout: int = 1000, recv_timeout: int = 1000) memoryview | None

Ejecuta una llamada remota en el dispositivo esclavo.

  • name – nombre en forma de cadena de la función o método remoto a ejecutar.

  • data – objeto de tipo bytes que se pasa como argumento a la función remota.

  • send_timeout – milisegundos a esperar mientras se conecta al esclavo y se inicia la ejecución de la función remota. Una vez que el maestro comienza a enviar el argumento esto deja de aplicar; la biblioteca permite hasta 5 segundos para la transferencia del argumento.

  • recv_timeout – milisegundos a esperar a que el esclavo comience a devolver una respuesta. Una vez que el maestro comienza a recibir la respuesta esto deja de aplicar; la biblioteca permite hasta 5 segundos para la transferencia de la respuesta.

Devuelve un memoryview de la respuesta en caso de éxito, un bytes() vacío si el nombre remoto no existe en el esclavo, o None si falla la comunicación.

class rpc_slave – clase base rpc_slave

rpc_slave es una clase base. Use una de las subclases específicas de transporte (rpc_can_slave, rpc_i2c_slave, rpc_spi_slave, rpc_uart_slave).

class rpc.rpc_slave

Crea un objeto rpc_slave. No está pensado para usarse directamente.

register_callback(cb: Callable[[memoryview], bytes | memoryview]) None

Registra una función de retorno (callback) que el maestro puede invocar por nombre. cb es un objeto invocable que toma un argumento memoryview y devuelve un objeto de tipo bytes. El __name__ de la función de retorno se usa como clave de búsqueda.

schedule_callback(cb: Callable[[], None]) None

Programa cb (un objeto invocable que no toma argumentos) para que se ejecute una vez, inmediatamente después de que la función de retorno rpc actualmente en ejecución devuelva correctamente su respuesta al maestro. Debe llamarse desde dentro de una función de retorno rpc. Permite que un trabajo de larga duración o transferencias de paso directo rpc.get_bytes/rpc.put_bytes se ejecuten entre transacciones rpc. Vuelva a registrarla en cada invocación si se requiere su ejecución repetida.

setup_loop_callback(cb: Callable[[], None]) None

Registra cb (un objeto invocable que no toma argumentos) para que se invoque en cada iteración de rpc_slave.loop. A diferencia de rpc_slave.schedule_callback, esta función de retorno permanece registrada. Debe ser no bloqueante; la frecuencia de llamada es variable.

loop(recv_timeout: int = 1000, send_timeout: int = 1000) None

Ejecuta el bucle de despacho del esclavo rpc. No retorna salvo por una excepción lanzada desde una función de retorno.

  • recv_timeout – milisegundos a esperar por un comando del maestro antes de reintentar.

  • send_timeout – milisegundos a esperar a que el maestro confirme la respuesta antes de volver a recibir.

class rpc_can_master – Interfaz Maestro CAN

Controla otro dispositivo rpc a través de CAN.

class rpc.rpc_can_master(message_id: int = 0x7FF, bit_rate: int = 250000, sample_point: float = 75, can_bus: int = 2)
  • message_id – id de mensaje CAN de 11 bits usado para el transporte de datos.

  • bit_rate – tasa de bits CAN en bits por segundo.

  • sample_point – porcentaje del punto de muestreo Tseg1/Tseg2 (p. ej. 50.0, 62.5, 75, 87.5).

  • can_bus – número de periférico CAN.

El message_id y el bit_rate del maestro y del esclavo deben coincidir. El bus debe terminarse con 120 ohmios.

class rpc_can_slave – Interfaz Esclavo CAN

Ser controlado por otro dispositivo rpc a través de CAN.

class rpc.rpc_can_slave(message_id: int = 0x7FF, bit_rate: int = 250000, sample_point: float = 75, can_bus: int = 2)

Consulte rpc_can_master para las descripciones de los argumentos.

class rpc_i2c_master – Interfaz Maestro I2C

Controla otro dispositivo rpc a través de I2C.

class rpc.rpc_i2c_master(slave_addr: int = 0x12, rate: int = 100000, i2c_bus: int = 2)
  • slave_addr – dirección I2C de 7 bits del dispositivo esclavo.

  • rate – frecuencia de reloj del bus I2C en Hz.

  • i2c_bus – número de periférico I2C.

Las direcciones del maestro y del esclavo deben coincidir. Se requieren resistencias pull-up externas en SCL y SDA, y ambos dispositivos deben compartir una masa común.

class rpc_i2c_slave – Interfaz Esclavo I2C

Ser controlado por otro dispositivo rpc a través de I2C.

class rpc.rpc_i2c_slave(slave_addr: int = 0x12, i2c_bus: int = 2)
  • slave_addr – dirección I2C de 7 bits a la que responde este esclavo.

  • i2c_bus – número de periférico I2C.

class rpc_spi_master – Interfaz Maestro SPI

Controla otro dispositivo rpc a través de 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 – nombre del pin de selección de chip (chip-select).

  • freq – frecuencia de reloj del bus SPI en Hz.

  • clk_polarity – nivel de reloj en reposo (0 o 1).

  • clk_phase – muestrea los datos en el primer (0) o segundo (1) flanco de reloj.

  • spi_bus – número de periférico SPI.

Los ajustes del maestro y del esclavo deben coincidir. Conecte CS, SCLK, MOSI, MISO directamente. Ambos dispositivos deben compartir una masa común.

class rpc_spi_slave – Interfaz Esclavo SPI

Ser controlado por otro dispositivo rpc a través de SPI.

class rpc.rpc_spi_slave(cs_pin: str = 'P3', clk_polarity: int = 1, clk_phase: int = 0, spi_bus: int = 2)
  • cs_pin – nombre del pin de entrada de selección de chip (chip-select).

  • clk_polarity – nivel de reloj en reposo (0 o 1).

  • clk_phase – muestrea los datos en el primer (0) o segundo (1) flanco de reloj.

  • spi_bus – número de periférico SPI.

class rpc_uart_master – Interfaz Maestro UART

Controla otro dispositivo rpc a través de serie asíncrona (UART).

class rpc.rpc_uart_master(baudrate: int = 9600, uart_port: int = 3)
  • baudrate – velocidad en baudios serie.

  • uart_port – número de periférico UART.

Las velocidades en baudios del maestro y del esclavo deben coincidir. Conecte el TX del maestro al RX del esclavo y el RX del maestro al TX del esclavo. Ambos dispositivos deben compartir una masa común.

class rpc_uart_slave – Interfaz Esclavo UART

Ser controlado por otro dispositivo rpc a través de serie asíncrona (UART).

class rpc.rpc_uart_slave(baudrate: int = 9600, uart_port: int = 3)
  • baudrate – velocidad en baudios serie.

  • uart_port – número de periférico UART.