rpc — libreria rpc¶
Il modulo rpc sull’OpenMV Cam consente di collegare la propria OpenMV Cam a un altro microcontrollore o computer ed eseguire chiamate remote a funzioni (o procedure) python sulla propria OpenMV Cam. Il modulo rpc permette anche il contrario, ossia di far eseguire alla propria OpenMV Cam chiamate remote a procedure (o funzioni python) su un altro microcontrollore o computer.
Come usare la libreria¶
Uno slave minimale che espone un callback su 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.
Il master corrispondente che richiede allo slave un frame 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")
Sostituisci rpc_uart_master / rpc_uart_slave con la coppia can, i2c o spi corrispondente per utilizzare un trasporto diverso.
In generale, affinché il dispositivo controllore possa usare la libreria rpc occorre creare un oggetto interfaccia utilizzando la libreria rpc. Per esempio:
interface = rpc.rpc_uart_master(baudrate=115200)
Questo crea un’interfaccia UART per comunicare con uno slave rpc.
Una volta creata l’interfaccia basta eseguire:
memory_view_object_result = interface.call("remote_function_or_method_name", bytes_object_argument)
E la libreria rpc proverà a eseguire quella "remote_function_or_method_name" sullo slave. La funzione o il metodo remoto riceverà l’argomento bytes_object_argument, che può avere una dimensione fino a 2^32-1 byte. Una volta terminata l’esecuzione, il metodo remoto restituirà un memory_view_object_result che può anch’esso avere una dimensione fino a 2^32-1 byte. Poiché sia l’argomento che la risposta sono contenitori di byte generici, è possibile passare qualsiasi cosa attraverso la libreria rpc e ricevere qualsiasi tipo di risposta. Un modo semplice per passare gli argomenti è usare struct.pack() per creare l’argomento e struct.unpack() per riceverlo dall’altra parte. Per la risposta, l’altra parte può inviare come risultato un oggetto stringa o una stringa json che il master può poi interpretare.
Per quanto riguarda gli errori, se si tenta di eseguire un nome di funzione o metodo inesistente il metodo rpc_master.call() restituirà un oggetto bytes() vuoto. Se la libreria rpc non è riuscita a comunicare con lo slave, la libreria rpc restituirà None.
Per mantenere le cose semplici, la libreria rpc non mantiene una connessione tra i dispositivi master e slave. Il metodo rpc_master.call() incapsula il tentativo di connettersi allo slave, l’avvio dell’esecuzione della funzione o del metodo remoto e l’ottenimento del risultato.
Ora, dal lato slave, occorre creare un’interfaccia rpc per comunicare con il master. Questo si presenta così:
interface = rpc.rpc_uart_slave(baudrate=115200)
Questo creerà il livello di interfaccia UART per comunicare con un master rpc.
Una volta creata l’interfaccia slave, occorre registrare i callback che il master può chiamare con l’oggetto interfaccia:
def remote_function_or_method_name(memoryview_object_argument):
<lots of code>
return bytes_object_result
interface.register_callback(remote_function_or_method_name)
È possibile registrare tutti i callback che si desidera sullo slave. Infine, una volta terminata la registrazione dei callback, basta eseguire:
interface.loop()
Sullo slave per avviare la libreria rpc e iniziare l’ascolto del master. Si noti che il metodo rpc_slave.loop() non ritorna.
classe rpc – classe base rpc¶
La classe base rpc viene reimplementata dalle classi rpc_master e rpc_slave per creare le interfacce master e slave. Non è pensata per essere usata direttamente.
- class rpc.rpc¶
Crea un oggetto
rpc. Non è pensato per essere usato direttamente.- get_bytes(buff: bytearray | memoryview, timeout_ms: int) bytes | None¶
Reimplementato dalle sottoclassi specifiche del trasporto. Riempie
buffcon i byte provenienti dall’interfaccia sottostante entrotimeout_msmillisecondi. RestituisceNonein caso di timeout.
- put_bytes(data: bytes | memoryview, timeout_ms: int) None¶
Reimplementato dalle sottoclassi specifiche del trasporto. Invia
dataattraverso l’interfaccia sottostante entrotimeout_msmillisecondi.
- stream_reader(call_back: Callable[[memoryview], None], queue_depth: int = 1, read_timeout_ms: int = 5000) None¶
Riceve un flusso di payload da un
rpc.stream_writerremoto. Dovrebbe essere chiamato dall’interno di un callbackrpc_slave(o direttamente dopo unarpc_master.callriuscita) una volta che entrambe le parti si sono sincronizzate.call_back– callable invocato una volta per ogni payload ricevuto comecall_back(data)dovedataè unmemoryview. Il valore di ritorno viene ignorato.queue_depth– numero di frame in transito che il writer può inviare prima di attendere il reader. Valori più alti aumentano il throughput a scapito della memoria.read_timeout_ms– millisecondi da attendere per ogni payload.
Ritorna in caso di qualsiasi errore. Per annullare, sollevare un’eccezione all’interno di
call_back; la parte remota andrà in timeout.
- stream_writer(call_back: Callable[[], bytes | memoryview], write_timeout_ms: int = 5000) None¶
Invia un flusso di payload a un
rpc.stream_readerremoto. Dovrebbe essere chiamato dall’interno di un callbackrpc_slave(o direttamente dopo unarpc_master.callriuscita) una volta che entrambe le parti si sono sincronizzate.call_back– callable invocato senza argomenti che restituisce il prossimo payloadbytesomemoryviewda inviare.write_timeout_ms– millisecondi da attendere durante l’invio di ogni payload.
Ritorna in caso di qualsiasi errore. Per annullare, sollevare un’eccezione all’interno di
call_back; la parte remota andrà in timeout.
classe rpc_master – classe base rpc_master¶
rpc_master è una classe base. Usare una delle sottoclassi specifiche del trasporto (rpc_can_master, rpc_i2c_master, rpc_spi_master, rpc_uart_master).
- class rpc.rpc_master¶
Crea un oggetto
rpc_master. Non è pensato per essere usato direttamente.- call(name: str, data: bytes = bytes(), send_timeout: int = 1000, recv_timeout: int = 1000) memoryview | None¶
Esegue una chiamata remota sul dispositivo slave.
name– nome stringa della funzione o del metodo remoto da eseguire.data– oggetto di tipobytespassato come argomento alla funzione remota.send_timeout– millisecondi da attendere durante la connessione allo slave e l’avvio dell’esecuzione della funzione remota. Una volta che il master inizia a inviare l’argomento questo non si applica più; la libreria consente fino a 5 secondi per il trasferimento dell’argomento.recv_timeout– millisecondi da attendere affinché lo slave inizi a restituire una risposta. Una volta che il master inizia a ricevere la risposta questo non si applica più; la libreria consente fino a 5 secondi per il trasferimento della risposta.
Restituisce un
memoryviewdella risposta in caso di successo, unbytes()vuoto se il nome remoto non esiste sullo slave, oppureNonein caso di errore di comunicazione.
classe rpc_slave – classe base rpc_slave¶
rpc_slave è una classe base. Usare una delle sottoclassi specifiche del trasporto (rpc_can_slave, rpc_i2c_slave, rpc_spi_slave, rpc_uart_slave).
- class rpc.rpc_slave¶
Crea un oggetto
rpc_slave. Non è pensato per essere usato direttamente.- register_callback(cb: Callable[[memoryview], bytes | memoryview]) None¶
Registra un callback che il master può invocare per nome.
cbè un callable che accetta un argomentomemoryviewe restituisce un oggetto di tipobytes. Il__name__del callback viene usato come chiave di ricerca.
- schedule_callback(cb: Callable[[], None]) None¶
Pianifica l’esecuzione di
cb(un callable senza argomenti) una sola volta, immediatamente dopo che il callback rpc attualmente in esecuzione ha restituito con successo la sua risposta al master. Deve essere chiamato dall’interno di un callback rpc. Consente l’esecuzione di lavori di lunga durata o di trasferimenti cut-throughrpc.get_bytes/rpc.put_bytestra le transazioni rpc. Registrare nuovamente a ogni invocazione se è richiesta l’esecuzione ripetuta.
- setup_loop_callback(cb: Callable[[], None]) None¶
Registra
cb(un callable senza argomenti) affinché venga invocato a ogni iterazione dirpc_slave.loop. A differenza dirpc_slave.schedule_callback, questo callback rimane registrato. Deve essere non bloccante; la frequenza di chiamata è variabile.
- loop(recv_timeout: int = 1000, send_timeout: int = 1000) None¶
Esegue il ciclo di dispatch dello slave rpc. Non ritorna se non tramite un’eccezione sollevata da un callback.
recv_timeout– millisecondi da attendere per un comando dal master prima di riprovare.send_timeout– millisecondi da attendere affinché il master confermi la risposta prima di tornare alla ricezione.
classe rpc_can_master – Interfaccia Master CAN¶
Controlla un altro dispositivo rpc tramite 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 del messaggio CAN a 11 bit usato per il trasporto dati.bit_rate– bit rate CAN in bit al secondo.sample_point– percentuale del sample-point Tseg1/Tseg2 (es. 50.0, 62.5, 75, 87.5).can_bus– numero della periferica CAN.
I valori
message_idebit_ratedel master e dello slave devono corrispondere. Il bus deve essere terminato con 120 ohm.
classe rpc_can_slave – Interfaccia Slave CAN¶
Viene controllato da un altro dispositivo rpc tramite CAN.
classe rpc_i2c_master – Interfaccia Master I2C¶
Controlla un altro dispositivo rpc tramite I2C.
- class rpc.rpc_i2c_master(slave_addr: int = 0x12, rate: int = 100000, i2c_bus: int = 2)¶
slave_addr– indirizzo I2C a 7 bit del dispositivo slave.rate– frequenza di clock del bus I2C in Hz.i2c_bus– numero della periferica I2C.
Gli indirizzi del master e dello slave devono corrispondere. Sono richieste pull-up esterne su SCL e SDA, ed entrambi i dispositivi devono condividere una massa comune.
classe rpc_i2c_slave – Interfaccia Slave I2C¶
Viene controllato da un altro dispositivo rpc tramite I2C.
classe rpc_spi_master – Interfaccia Master SPI¶
Controlla un altro dispositivo rpc tramite 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 del pin di chip-select.freq– frequenza di clock del bus SPI in Hz.clk_polarity– livello del clock a riposo (0 o 1).clk_phase– campiona i dati sul primo (0) o sul secondo (1) fronte di clock.spi_bus– numero della periferica SPI.
Le impostazioni del master e dello slave devono corrispondere. Collegare CS, SCLK, MOSI, MISO direttamente. Entrambi i dispositivi devono condividere una massa comune.
classe rpc_spi_slave – Interfaccia Slave SPI¶
Viene controllato da un altro dispositivo rpc tramite 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 del pin di ingresso chip-select.clk_polarity– livello del clock a riposo (0 o 1).clk_phase– campiona i dati sul primo (0) o sul secondo (1) fronte di clock.spi_bus– numero della periferica SPI.
classe rpc_uart_master – Interfaccia Master UART¶
Controlla un altro dispositivo rpc tramite Seriale Asincrona (UART).
- class rpc.rpc_uart_master(baudrate: int = 9600, uart_port: int = 3)¶
baudrate– baud rate seriale.uart_port– numero della periferica UART.
I baud rate del master e dello slave devono corrispondere. Collegare il TX del master al RX dello slave e il RX del master al TX dello slave. Entrambi i dispositivi devono condividere una massa comune.
classe rpc_uart_slave – Interfaccia Slave UART¶
Viene controllato da un altro dispositivo rpc tramite Seriale Asincrona (UART).