rpc — biblioteca rpc¶
O módulo rpc na OpenMV Cam permite que você conecte sua OpenMV Cam a outro microcontrolador ou computador e execute chamadas remotas de python (ou de procedimento) na sua OpenMV Cam. O módulo rpc também permite o inverso, caso você queira que sua OpenMV Cam seja capaz de executar chamadas remotas de procedimento (ou de python) em outro microcontrolador ou computador.
Como usar a biblioteca¶
Um slave mínimo que expõe um callback via 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.
O master correspondente que pede ao slave um quadro 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")
Troque rpc_uart_master / rpc_uart_slave pelo par can, i2c ou spi correspondente para usar um transporte diferente.
Em geral, para que o dispositivo controlador use a biblioteca rpc, você criará um objeto de interface usando a biblioteca rpc. Por exemplo:
interface = rpc.rpc_uart_master(baudrate=115200)
Isso cria uma interface UART para se comunicar com um slave rpc.
Uma vez criada a interface, você só precisa fazer:
memory_view_object_result = interface.call("remote_function_or_method_name", bytes_object_argument)
E a biblioteca rpc tentará executar essa "remote_function_or_method_name" no slave. A função ou método remoto receberá o bytes_object_argument, que pode ter até 2^32-1 bytes de tamanho. Assim que o método remoto terminar de executar, ele retornará um memory_view_object_result, que também pode ter até 2^32-1 bytes de tamanho. Como o argumento e a resposta são ambos contêineres genéricos de bytes, você pode passar qualquer coisa pela biblioteca rpc e receber qualquer tipo de resposta. Uma forma simples de passar argumentos é usar struct.pack() para criar o argumento e struct.unpack() para receber o argumento do outro lado. Para a resposta, o outro lado pode enviar um objeto string ou uma string json como resultado, que o master pode então interpretar.
Quanto a erros, se você tentar executar um nome de função ou método inexistente, o método rpc_master.call() retornará um objeto bytes() vazio. Se a biblioteca rpc falhar ao se comunicar com o slave, a biblioteca rpc retornará None.
Para manter as coisas simples, a biblioteca rpc não mantém uma conexão entre os dispositivos master e slave. O método rpc_master.call() encapsula a tentativa de se conectar ao slave, o início da execução da função ou método remoto e a obtenção do resultado.
Agora, no lado do slave, você precisa criar uma interface rpc para se comunicar com o master. Isso se parece com:
interface = rpc.rpc_uart_slave(baudrate=115200)
Isso criará a camada de interface UART para se comunicar com um master rpc.
Uma vez criada a interface do slave, você precisa registrar callbacks que o master pode chamar usando o objeto de interface:
def remote_function_or_method_name(memoryview_object_argument):
<lots of code>
return bytes_object_result
interface.register_callback(remote_function_or_method_name)
Você pode registrar quantos callbacks quiser no slave. Por fim, depois de terminar de registrar os callbacks, você só precisa executar:
interface.loop()
No slave, para iniciar a biblioteca rpc e começar a escutar o master. Observe que o método rpc_slave.loop() não retorna.
class rpc – classe base rpc¶
A classe base rpc é reimplementada pelas classes rpc_master e rpc_slave para criar as interfaces master e slave. Ela não foi feita para ser usada diretamente.
- class rpc.rpc¶
Cria um objeto
rpc. Não foi feito para ser usado diretamente.- get_bytes(buff: bytearray | memoryview, timeout_ms: int) bytes | None¶
Reimplementado por subclasses específicas de transporte. Preenche
buffcom bytes da interface subjacente dentro detimeout_msmilissegundos. RetornaNoneem caso de timeout.
- put_bytes(data: bytes | memoryview, timeout_ms: int) None¶
Reimplementado por subclasses específicas de transporte. Envia
datapela interface subjacente dentro detimeout_msmilissegundos.
- stream_reader(call_back: Callable[[memoryview], None], queue_depth: int = 1, read_timeout_ms: int = 5000) None¶
Recebe um fluxo de payloads de um
rpc.stream_writerremoto. Deve ser chamado de dentro de um callback derpc_slave(ou diretamente após uma chamadarpc_master.callbem-sucedida) depois que ambos os lados tiverem sincronizado.call_back– callable invocado uma vez por payload recebido, comocall_back(data), ondedataé ummemoryview. O valor de retorno é ignorado.queue_depth– número de quadros em trânsito que o writer tem permissão para enviar antes de aguardar pelo reader. Valores mais altos aumentam o throughput ao custo de memória.read_timeout_ms– milissegundos a aguardar por payload.
Retorna em qualquer erro. Para cancelar, levante uma exceção dentro de
call_back; o lado remoto entrará em timeout.
- stream_writer(call_back: Callable[[], bytes | memoryview], write_timeout_ms: int = 5000) None¶
Envia um fluxo de payloads para um
rpc.stream_readerremoto. Deve ser chamado de dentro de um callback derpc_slave(ou diretamente após uma chamadarpc_master.callbem-sucedida) depois que ambos os lados tiverem sincronizado.call_back– callable invocado sem argumentos que retorna o próximo payloadbytesoumemoryviewa ser enviado.write_timeout_ms– milissegundos a aguardar ao enviar cada payload.
Retorna em qualquer erro. Para cancelar, levante uma exceção dentro de
call_back; o lado remoto entrará em timeout.
class rpc_master – classe base rpc_master¶
O rpc_master é uma classe base. Use uma das subclasses específicas de transporte (rpc_can_master, rpc_i2c_master, rpc_spi_master, rpc_uart_master).
- class rpc.rpc_master¶
Cria um objeto
rpc_master. Não foi feito para ser usado diretamente.- call(name: str, data: bytes = bytes(), send_timeout: int = 1000, recv_timeout: int = 1000) memoryview | None¶
Executa uma chamada remota no dispositivo slave.
name– nome em string da função ou método remoto a executar.data– objeto do tipobytespassado como argumento para a função remota.send_timeout– milissegundos a aguardar enquanto se conecta ao slave e inicia a execução da função remota. Uma vez que o master começa a enviar o argumento, isso deixa de se aplicar; a biblioteca permite até 5 segundos para a transferência do argumento.recv_timeout– milissegundos a aguardar para que o slave comece a retornar uma resposta. Uma vez que o master começa a receber a resposta, isso deixa de se aplicar; a biblioteca permite até 5 segundos para a transferência da resposta.
Retorna um
memoryviewda resposta em caso de sucesso, umbytes()vazio se o nome remoto não existir no slave, ouNoneem caso de falha de comunicação.
class rpc_slave – classe base rpc_slave¶
O rpc_slave é uma classe base. Use uma das subclasses específicas de transporte (rpc_can_slave, rpc_i2c_slave, rpc_spi_slave, rpc_uart_slave).
- class rpc.rpc_slave¶
Cria um objeto
rpc_slave. Não foi feito para ser usado diretamente.- register_callback(cb: Callable[[memoryview], bytes | memoryview]) None¶
Registra um callback que o master pode invocar pelo nome.
cbé um callable que recebe um argumentomemoryviewe retorna um objeto do tipobytes. O__name__do callback é usado como chave de busca.
- schedule_callback(cb: Callable[[], None]) None¶
Agenda
cb(um callable que não recebe argumentos) para ser executado uma vez, imediatamente após o callback rpc em execução retornar com sucesso sua resposta ao master. Deve ser chamado de dentro de um callback rpc. Permite que trabalhos de longa duração ou transferências cut-throughrpc.get_bytes/rpc.put_bytessejam executados entre as transações rpc. Registre novamente a cada invocação se for necessária execução repetida.
- setup_loop_callback(cb: Callable[[], None]) None¶
Registra
cb(um callable que não recebe argumentos) para ser invocado em cada iteração derpc_slave.loop. Diferente derpc_slave.schedule_callback, esse callback permanece registrado. Deve ser não bloqueante; a taxa de chamadas é variável.
- loop(recv_timeout: int = 1000, send_timeout: int = 1000) None¶
Executa o loop de despacho do slave rpc. Não retorna, exceto por uma exceção levantada a partir de um callback.
recv_timeout– milissegundos a aguardar por um comando do master antes de tentar novamente.send_timeout– milissegundos a aguardar para que o master confirme a resposta antes de voltar a receber.
class rpc_can_master – Interface Master CAN¶
Controla outro dispositivo rpc via 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 mensagem CAN de 11 bits usado para o transporte de dados.bit_rate– bit rate CAN em bits por segundo.sample_point– porcentagem do ponto de amostragem Tseg1/Tseg2 (por exemplo, 50.0, 62.5, 75, 87.5).can_bus– número do periférico CAN.
message_idebit_ratedo master e do slave devem coincidir. O barramento deve ser terminado com 120 ohms.
class rpc_can_slave – Interface Slave CAN¶
É controlado por outro dispositivo rpc via CAN.
class rpc_i2c_master – Interface Master I2C¶
Controla outro dispositivo rpc via I2C.
- class rpc.rpc_i2c_master(slave_addr: int = 0x12, rate: int = 100000, i2c_bus: int = 2)¶
slave_addr– endereço I2C de 7 bits do dispositivo slave.rate– frequência de clock do barramento I2C em Hz.i2c_bus– número do periférico I2C.
Os endereços do master e do slave devem coincidir. São necessários pull-ups externos em SCL e SDA, e ambos os dispositivos devem compartilhar um terra comum.
class rpc_i2c_slave – Interface Slave I2C¶
É controlado por outro dispositivo rpc via I2C.
class rpc_spi_master – Interface Master SPI¶
Controla outro dispositivo rpc via 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– nome do pino de chip-select.freq– frequência de clock do barramento SPI em Hz.clk_polarity– nível de clock em repouso (0 ou 1).clk_phase– amostra os dados na primeira (0) ou na segunda (1) borda do clock.spi_bus– número do periférico SPI.
As configurações do master e do slave devem coincidir. Conecte CS, SCLK, MOSI, MISO diretamente. Ambos os dispositivos devem compartilhar um terra comum.
class rpc_spi_slave – Interface Slave SPI¶
É controlado por outro dispositivo rpc via SPI.
- class rpc.rpc_spi_slave(cs_pin: str = 'P3', clk_polarity: int = 1, clk_phase: int = 0, spi_bus: int = 2)¶
cs_pin– nome do pino de entrada de chip-select.clk_polarity– nível de clock em repouso (0 ou 1).clk_phase– amostra os dados na primeira (0) ou na segunda (1) borda do clock.spi_bus– número do periférico SPI.
class rpc_uart_master – Interface Master UART¶
Controla outro dispositivo rpc via Serial Assíncrona (UART).
- class rpc.rpc_uart_master(baudrate: int = 9600, uart_port: int = 3)¶
baudrate– taxa de transmissão (baud rate) serial.uart_port– número do periférico UART.
As taxas de transmissão (baud rate) do master e do slave devem coincidir. Conecte o TX do master ao RX do slave e o RX do master ao TX do slave. Ambos os dispositivos devem compartilhar um terra comum.
class rpc_uart_slave – Interface Slave UART¶
É controlado por outro dispositivo rpc via Serial Assíncrona (UART).