rpc — rpc-bibliotek

Modulen rpc på OpenMV Cam låter dig ansluta din OpenMV Cam till en annan mikrokontroller eller dator och köra fjärranrop av python (eller procedurer) på din OpenMV Cam. Modulen rpc möjliggör även det omvända om du vill att din OpenMV Cam ska kunna köra fjärranrop av procedurer (eller python) på en annan mikrokontroller eller dator.

Hur du använder biblioteket

En minimal slav som exponerar ett återanrop över 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.

Den matchande mastern som ber slaven om en JPEG-bildruta:

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")

Byt ut rpc_uart_master / rpc_uart_slave mot motsvarande par can, i2c eller spi för att använda en annan transport.

I allmänhet skapar du, för att styrenheten ska kunna använda biblioteket rpc, ett gränssnittsobjekt med hjälp av biblioteket rpc. Till exempel:

interface = rpc.rpc_uart_master(baudrate=115200)

Detta skapar ett UART-gränssnitt för att kommunicera med en rpc-slav.

När gränssnittet har skapats behöver du bara göra:

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

Och biblioteket rpc kommer att försöka köra "remote_function_or_method_name" på slaven. Fjärrfunktionen eller -metoden tar emot bytes_object_argument som kan vara upp till 2^32-1 byte stort. När fjärrmetoden har kört klart returnerar den ett memory_view_object_result som också kan vara upp till 2^32-1 byte stort. Eftersom både argumentet och svaret är generiska byte-behållare kan du skicka vad som helst genom biblioteket rpc och ta emot vilken typ av svar som helst. Ett enkelt sätt att skicka argument är att använda struct.pack() för att skapa argumentet och struct.unpack() för att ta emot argumentet på den andra sidan. För svaret kan den andra sidan skicka ett strängobjekt eller en json-sträng som resultat, vilket mastern sedan kan tolka.

När det gäller fel, om du försöker köra ett funktions- eller metodnamn som inte finns kommer metoden rpc_master.call() att returnera ett tomt bytes()-objekt. Om biblioteket rpc misslyckas med att kommunicera med slaven kommer biblioteket rpc att returnera None.

För att hålla saker enkelt upprätthåller biblioteket rpc inte någon anslutning mellan master- och slavenheterna. Metoden rpc_master.call() kapslar in att försöka ansluta till slaven, starta körningen av fjärrfunktionen eller -metoden och hämta resultatet.

På slavsidan måste du nu skapa ett rpc-gränssnitt för att kommunicera med mastern. Det ser ut så här:

interface = rpc.rpc_uart_slave(baudrate=115200)

Detta skapar UART-gränssnittslagret för att kommunicera med en rpc-master.

När du har skapat slavgränssnittet behöver du sedan registrera återanrop som mastern kan anropa med gränssnittsobjektet:

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

interface.register_callback(remote_function_or_method_name)

Du kan registrera så många återanrop du vill på slaven. Slutligen, när du är klar med att registrera återanrop behöver du bara köra:

interface.loop()

På slaven för att starta upp biblioteket rpc och börja lyssna efter mastern. Observera att metoden rpc_slave.loop() inte returnerar.

class rpc – basklass för rpc

Basklassen rpc återimplementeras av klasserna rpc_master och rpc_slave för att skapa master- och slavgränssnitten. Den är inte avsedd att användas direkt.

class rpc.rpc

Skapar ett rpc-objekt. Inte avsett att användas direkt.

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

Återimplementeras av transportspecifika underklasser. Fyller buff med byte från det underliggande gränssnittet inom timeout_ms millisekunder. Returnerar None vid tidsgräns.

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

Återimplementeras av transportspecifika underklasser. Skickar data över det underliggande gränssnittet inom timeout_ms millisekunder.

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

Tar emot en ström av nyttolaster från en fjärransluten rpc.stream_writer. Bör anropas inifrån ett rpc_slave-återanrop (eller direkt efter ett lyckat rpc_master.call) när båda sidor har synkroniserats.

  • call_back – anropbar funktion som anropas en gång per mottagen nyttolast som call_back(data) där data är en memoryview. Returvärdet ignoreras.

  • queue_depth – antal bildrutor under överföring som skrivaren tillåts skicka innan den väntar på läsaren. Högre värden ökar genomströmningen på bekostnad av minne.

  • read_timeout_ms – millisekunder att vänta per nyttolast.

Returnerar vid alla fel. För att avbryta, kasta ett undantag inuti call_back; den fjärranslutna sidan kommer att nå tidsgränsen.

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

Skickar en ström av nyttolaster till en fjärransluten rpc.stream_reader. Bör anropas inifrån ett rpc_slave-återanrop (eller direkt efter ett lyckat rpc_master.call) när båda sidor har synkroniserats.

  • call_back – anropbar funktion som anropas utan argument och returnerar nästa bytes- eller memoryview-nyttolast att skicka.

  • write_timeout_ms – millisekunder att vänta vid sändning av varje nyttolast.

Returnerar vid alla fel. För att avbryta, kasta ett undantag inuti call_back; den fjärranslutna sidan kommer att nå tidsgränsen.

class rpc_master – basklass för rpc_master

rpc_master är en basklass. Använd en av de transportspecifika underklasserna (rpc_can_master, rpc_i2c_master, rpc_spi_master, rpc_uart_master).

class rpc.rpc_master

Skapar ett rpc_master-objekt. Inte avsett att användas direkt.

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

Kör ett fjärranrop på slavenheten.

  • name – strängnamn på fjärrfunktionen eller -metoden som ska köras.

  • databytes-liknande objekt som skickas som argument till fjärrfunktionen.

  • send_timeout – millisekunder att vänta vid anslutning till slaven och vid start av körningen av fjärrfunktionen. När mastern börjar skicka argumentet gäller detta inte längre; biblioteket tillåter upp till 5 sekunder för argumentöverföringen.

  • recv_timeout – millisekunder att vänta på att slaven ska börja returnera ett svar. När mastern börjar ta emot svaret gäller detta inte längre; biblioteket tillåter upp till 5 sekunder för svarsöverföringen.

Returnerar en memoryview av svaret vid lyckat anrop, ett tomt bytes() om fjärrnamnet inte finns på slaven, eller None vid kommunikationsfel.

class rpc_slave – basklass för rpc_slave

rpc_slave är en basklass. Använd en av de transportspecifika underklasserna (rpc_can_slave, rpc_i2c_slave, rpc_spi_slave, rpc_uart_slave).

class rpc.rpc_slave

Skapar ett rpc_slave-objekt. Inte avsett att användas direkt.

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

Registrerar ett återanrop som mastern kan anropa med namn. cb är en anropbar funktion som tar ett memoryview-argument och returnerar ett bytes-liknande objekt. Återanropets __name__ används som uppslagsnyckel.

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

Schemalägger cb (en anropbar funktion som inte tar några argument) för att köras en gång, omedelbart efter att det för närvarande körande rpc-återanropet har returnerat sitt svar till mastern. Måste anropas inifrån ett rpc-återanrop. Tillåter långvarigt arbete eller cut-through-överföringar med rpc.get_bytes/rpc.put_bytes att köras mellan rpc-transaktioner. Registrera om vid varje anrop om upprepad körning krävs.

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

Registrerar cb (en anropbar funktion som inte tar några argument) för att anropas vid varje iteration av rpc_slave.loop. Till skillnad från rpc_slave.schedule_callback förblir detta återanrop registrerat. Måste vara icke-blockerande; anropsfrekvensen är variabel.

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

Kör rpc-slavens dispatch-loop. Returnerar inte annat än genom ett undantag som kastas från ett återanrop.

  • recv_timeout – millisekunder att vänta på ett kommando från mastern innan nytt försök görs.

  • send_timeout – millisekunder att vänta på att mastern ska bekräfta svaret innan den återgår till att ta emot.

class rpc_can_master – CAN-mastergränssnitt

Styr en annan rpc-enhet över 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-bitars CAN-meddelande-id som används för datatransport.

  • bit_rate – CAN-bithastighet i bitar per sekund.

  • sample_point – Tseg1/Tseg2-samplingspunktsprocent (t.ex. 50.0, 62.5, 75, 87.5).

  • can_bus – CAN-kringutrustningens nummer.

Masterns och slavens message_id och bit_rate måste matcha. Bussen måste termineras med 120 ohm.

class rpc_can_slave – CAN-slavgränssnitt

Styras av en annan rpc-enhet över CAN.

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

Se rpc_can_master för argumentbeskrivningar.

class rpc_i2c_master – I2C-mastergränssnitt

Styr en annan rpc-enhet över I2C.

class rpc.rpc_i2c_master(slave_addr: int = 0x12, rate: int = 100000, i2c_bus: int = 2)
  • slave_addr – 7-bitars I2C-adress för slavenheten.

  • rate – I2C-bussens klockfrekvens i Hz.

  • i2c_bus – I2C-kringutrustningens nummer.

Master- och slavadresserna måste matcha. Externa pull-up-motstånd krävs på SCL och SDA, och båda enheterna måste dela en gemensam jord.

class rpc_i2c_slave – I2C-slavgränssnitt

Styras av en annan rpc-enhet över I2C.

class rpc.rpc_i2c_slave(slave_addr: int = 0x12, i2c_bus: int = 2)
  • slave_addr – 7-bitars I2C-adress som denna slav svarar på.

  • i2c_bus – I2C-kringutrustningens nummer.

class rpc_spi_master – SPI-mastergränssnitt

Styr en annan rpc-enhet över 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 – namn på chip-select-stiftet.

  • freq – SPI-bussens klockfrekvens i Hz.

  • clk_polarity – klocknivå i viloläge (0 eller 1).

  • clk_phase – sampla data på den första (0) eller andra (1) klockflanken.

  • spi_bus – SPI-kringutrustningens nummer.

Master- och slavinställningarna måste matcha. Anslut CS, SCLK, MOSI, MISO direkt. Båda enheterna måste dela en gemensam jord.

class rpc_spi_slave – SPI-slavgränssnitt

Styras av en annan rpc-enhet över SPI.

class rpc.rpc_spi_slave(cs_pin: str = 'P3', clk_polarity: int = 1, clk_phase: int = 0, spi_bus: int = 2)
  • cs_pin – namn på chip-select-ingångsstiftet.

  • clk_polarity – klocknivå i viloläge (0 eller 1).

  • clk_phase – sampla data på den första (0) eller andra (1) klockflanken.

  • spi_bus – SPI-kringutrustningens nummer.

class rpc_uart_master – UART-mastergränssnitt

Styr en annan rpc-enhet över asynkron seriell kommunikation (UART).

class rpc.rpc_uart_master(baudrate: int = 9600, uart_port: int = 3)
  • baudrate – seriell baudhastighet.

  • uart_port – UART-kringutrustningens nummer.

Master- och slavbaudhastigheterna måste matcha. Anslut masterns TX till slavens RX och masterns RX till slavens TX. Båda enheterna måste dela en gemensam jord.

class rpc_uart_slave – UART-slavgränssnitt

Styras av en annan rpc-enhet över asynkron seriell kommunikation (UART).

class rpc.rpc_uart_slave(baudrate: int = 9600, uart_port: int = 3)
  • baudrate – seriell baudhastighet.

  • uart_port – UART-kringutrustningens nummer.