rpc — biblioteca rpc

Modulul rpc de pe OpenMV Cam vă permite să conectați OpenMV Cam la un alt microcontroler sau computer și să executați apeluri Python (sau de procedură) la distanță pe OpenMV Cam. Modulul rpc permite și inversul, dacă doriți ca OpenMV Cam să poată executa apeluri de procedură (sau Python) la distanță pe un alt microcontroler sau computer.

Cum se folosește biblioteca

Un slave minimal care expune o singură funcție de retroapelare (callback) prin 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-ul corespunzător care îi cere slave-ului un cadru 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")

Înlocuiți rpc_uart_master / rpc_uart_slave cu perechea corespunzătoare can, i2c sau spi pentru a folosi un alt transport.

În general, pentru ca dispozitivul controler să folosească biblioteca rpc, veți crea un obiect de interfață folosind biblioteca rpc. De exemplu:

interface = rpc.rpc_uart_master(baudrate=115200)

Acest lucru creează o interfață UART pentru a comunica cu un slave rpc.

Odată creată interfața, trebuie doar să faceți:

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

Iar biblioteca rpc va încerca să execute acel "remote_function_or_method_name" pe slave. Funcția sau metoda de la distanță va primi bytes_object_argument, care poate avea o dimensiune de până la 2^32-1 octeți. Odată ce metoda de la distanță își termină execuția, va returna un memory_view_object_result, care poate avea și el o dimensiune de până la 2^32-1 octeți. Deoarece atât argumentul, cât și răspunsul sunt containere generice de octeți, puteți transmite orice prin biblioteca rpc și puteți primi orice tip de răspuns. O modalitate simplă de a transmite argumente este să folosiți struct.pack() pentru a crea argumentul și struct.unpack() pentru a-l primi de cealaltă parte. Pentru răspuns, cealaltă parte poate trimite ca rezultat un obiect string sau un string json pe care master-ul îl poate interpreta apoi.

În ceea ce privește erorile, dacă încercați să executați un nume de funcție sau metodă inexistent, metoda rpc_master.call() va returna un obiect bytes() gol. Dacă biblioteca rpc nu a reușit să comunice cu slave-ul, biblioteca rpc va returna None.

Pentru a păstra lucrurile simple, biblioteca rpc nu menține o conexiune între dispozitivele master și slave. Metoda rpc_master.call() încapsulează încercarea de a se conecta la slave, pornirea execuției funcției sau metodei de la distanță și obținerea rezultatului.

Acum, în privința slave-ului, trebuie să creați o interfață rpc pentru a comunica cu master-ul. Aceasta arată astfel:

interface = rpc.rpc_uart_slave(baudrate=115200)

Acest lucru va crea stratul de interfață UART pentru a comunica cu un master rpc.

Odată ce creați interfața slave, trebuie apoi să înregistrați funcțiile de retroapelare (callback) pe care master-ul le poate apela cu obiectul de interfață:

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

interface.register_callback(remote_function_or_method_name)

Puteți înregistra oricâte funcții de retroapelare (callback) doriți pe slave. În cele din urmă, odată ce ați terminat de înregistrat funcțiile de retroapelare, trebuie doar să executați:

interface.loop()

Pe slave, pentru a porni biblioteca rpc și a începe să ascultați master-ul. Rețineți că metoda rpc_slave.loop() nu se întoarce.

clasa rpc – clasa de bază rpc

Clasa de bază rpc este reimplementată de clasele rpc_master și rpc_slave pentru a crea interfețele master și slave. Nu este destinată utilizării directe.

class rpc.rpc

Creează un obiect rpc. Nu este destinat utilizării directe.

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

Reimplementată de subclase specifice transportului. Umple buff cu octeți de la interfața subiacentă în decurs de timeout_ms milisecunde. Returnează None la expirarea timpului.

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

Reimplementată de subclase specifice transportului. Trimite data prin interfața subiacentă în decurs de timeout_ms milisecunde.

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

Primește un flux de sarcini utile (payloads) de la un rpc.stream_writer la distanță. Ar trebui apelată din interiorul unei funcții de retroapelare rpc_slave (sau direct după un rpc_master.call reușit), odată ce ambele părți s-au sincronizat.

  • call_back – obiect apelabil invocat o dată pentru fiecare sarcină utilă primită sub forma call_back(data), unde data este un memoryview. Valoarea returnată este ignorată.

  • queue_depth – numărul de cadre în tranzit pe care scriitorul are voie să le trimită înainte de a aștepta cititorul. Valorile mai mari cresc debitul cu prețul memoriei.

  • read_timeout_ms – milisecunde de așteptat pentru fiecare sarcină utilă.

Se întoarce la orice eroare. Pentru a anula, ridicați o excepție în interiorul call_back; partea de la distanță va expira.

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

Trimite un flux de sarcini utile (payloads) către un rpc.stream_reader la distanță. Ar trebui apelată din interiorul unei funcții de retroapelare rpc_slave (sau direct după un rpc_master.call reușit), odată ce ambele părți s-au sincronizat.

  • call_back – obiect apelabil invocat fără argumente care returnează următoarea sarcină utilă bytes sau memoryview de trimis.

  • write_timeout_ms – milisecunde de așteptat la trimiterea fiecărei sarcini utile.

Se întoarce la orice eroare. Pentru a anula, ridicați o excepție în interiorul call_back; partea de la distanță va expira.

clasa rpc_master – clasa de bază rpc_master

rpc_master este o clasă de bază. Folosiți una dintre subclasele specifice transportului (rpc_can_master, rpc_i2c_master, rpc_spi_master, rpc_uart_master).

class rpc.rpc_master

Creează un obiect rpc_master. Nu este destinat utilizării directe.

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

Execută un apel la distanță pe dispozitivul slave.

  • name – numele string al funcției sau metodei de la distanță de executat.

  • data – obiect de tip bytes transmis ca argument funcției de la distanță.

  • send_timeout – milisecunde de așteptat în timpul conectării la slave și pornirii execuției funcției de la distanță. Odată ce master-ul începe să trimită argumentul, acest lucru nu se mai aplică; biblioteca permite până la 5 secunde pentru transferul argumentului.

  • recv_timeout – milisecunde de așteptat ca slave-ul să înceapă să returneze un răspuns. Odată ce master-ul începe să primească răspunsul, acest lucru nu se mai aplică; biblioteca permite până la 5 secunde pentru transferul răspunsului.

Returnează un memoryview al răspunsului în caz de succes, un bytes() gol dacă numele de la distanță nu există pe slave sau None în caz de eșec al comunicării.

clasa rpc_slave – clasa de bază rpc_slave

rpc_slave este o clasă de bază. Folosiți una dintre subclasele specifice transportului (rpc_can_slave, rpc_i2c_slave, rpc_spi_slave, rpc_uart_slave).

class rpc.rpc_slave

Creează un obiect rpc_slave. Nu este destinat utilizării directe.

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

Înregistrează o funcție de retroapelare (callback) pe care master-ul o poate invoca după nume. cb este un obiect apelabil care primește un argument memoryview și returnează un obiect de tip bytes. Numele __name__ al funcției de retroapelare este folosit drept cheie de căutare.

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

Programează cb (un obiect apelabil fără argumente) pentru a fi executat o singură dată, imediat după ce funcția de retroapelare rpc aflată în execuție își returnează cu succes răspunsul către master. Trebuie apelată din interiorul unei funcții de retroapelare rpc. Permite executarea de lucrări de lungă durată sau a transferurilor cut-through rpc.get_bytes/rpc.put_bytes între tranzacțiile rpc. Reînregistrați la fiecare invocare dacă este necesară execuția repetată.

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

Înregistrează cb (un obiect apelabil fără argumente) pentru a fi invocat la fiecare iterație a rpc_slave.loop. Spre deosebire de rpc_slave.schedule_callback, această funcție de retroapelare rămâne înregistrată. Trebuie să fie neblocantă; rata de apelare este variabilă.

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

Rulează bucla de dispecerizare a slave-ului rpc. Nu se întoarce decât printr-o excepție ridicată dintr-o funcție de retroapelare.

  • recv_timeout – milisecunde de așteptat o comandă de la master înainte de a reîncerca.

  • send_timeout – milisecunde de așteptat ca master-ul să confirme răspunsul înainte de a reveni la recepție.

clasa rpc_can_master – Interfață Master CAN

Controlează un alt dispozitiv rpc prin 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-ul mesajului CAN pe 11 biți folosit pentru transportul de date.

  • bit_rate – rata de biți CAN în biți pe secundă.

  • sample_point – procentajul punctului de eșantionare Tseg1/Tseg2 (de ex. 50.0, 62.5, 75, 87.5).

  • can_bus – numărul perifericului CAN.

Valorile message_id și bit_rate ale master-ului și slave-ului trebuie să coincidă. Magistrala trebuie terminată cu 120 ohmi.

clasa rpc_can_slave – Interfață Slave CAN

Să fie controlat de un alt dispozitiv rpc prin CAN.

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

Consultați rpc_can_master pentru descrierile argumentelor.

clasa rpc_i2c_master – Interfață Master I2C

Controlează un alt dispozitiv rpc prin I2C.

class rpc.rpc_i2c_master(slave_addr: int = 0x12, rate: int = 100000, i2c_bus: int = 2)
  • slave_addr – adresa I2C pe 7 biți a dispozitivului slave.

  • rate – frecvența ceasului magistralei I2C în Hz.

  • i2c_bus – numărul perifericului I2C.

Adresele master-ului și slave-ului trebuie să coincidă. Sunt necesare rezistențe de pull-up externe pe SCL și SDA, iar ambele dispozitive trebuie să aibă o masă comună.

clasa rpc_i2c_slave – Interfață Slave I2C

Să fie controlat de un alt dispozitiv rpc prin I2C.

class rpc.rpc_i2c_slave(slave_addr: int = 0x12, i2c_bus: int = 2)
  • slave_addr – adresa I2C pe 7 biți la care răspunde acest slave.

  • i2c_bus – numărul perifericului I2C.

clasa rpc_spi_master – Interfață Master SPI

Controlează un alt dispozitiv rpc prin 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 – numele pinului de selecție a cipului (chip-select).

  • freq – frecvența ceasului magistralei SPI în Hz.

  • clk_polarity – nivelul de repaus al ceasului (0 sau 1).

  • clk_phase – eșantionarea datelor pe primul (0) sau pe al doilea (1) front al ceasului.

  • spi_bus – numărul perifericului SPI.

Setările master-ului și slave-ului trebuie să coincidă. Conectați direct CS, SCLK, MOSI, MISO. Ambele dispozitive trebuie să aibă o masă comună.

clasa rpc_spi_slave – Interfață Slave SPI

Să fie controlat de un alt dispozitiv rpc prin SPI.

class rpc.rpc_spi_slave(cs_pin: str = 'P3', clk_polarity: int = 1, clk_phase: int = 0, spi_bus: int = 2)
  • cs_pin – numele pinului de intrare pentru selecția cipului (chip-select).

  • clk_polarity – nivelul de repaus al ceasului (0 sau 1).

  • clk_phase – eșantionarea datelor pe primul (0) sau pe al doilea (1) front al ceasului.

  • spi_bus – numărul perifericului SPI.

clasa rpc_uart_master – Interfață Master UART

Controlează un alt dispozitiv rpc prin serial asincron (UART).

class rpc.rpc_uart_master(baudrate: int = 9600, uart_port: int = 3)
  • baudrate – rata baud serială.

  • uart_port – numărul perifericului UART.

Ratele baud ale master-ului și slave-ului trebuie să coincidă. Conectați TX-ul master-ului la RX-ul slave-ului și RX-ul master-ului la TX-ul slave-ului. Ambele dispozitive trebuie să aibă o masă comună.

clasa rpc_uart_slave – Interfață Slave UART

Să fie controlat de un alt dispozitiv rpc prin serial asincron (UART).

class rpc.rpc_uart_slave(baudrate: int = 9600, uart_port: int = 3)
  • baudrate – rata baud serială.

  • uart_port – numărul perifericului UART.