rpc — rpc-Bibliothek

Das rpc-Modul auf der OpenMV Cam ermöglicht es Ihnen, Ihre OpenMV Cam mit einem anderen Mikrocontroller oder Computer zu verbinden und entfernte Python- (oder Prozedur-)Aufrufe auf Ihrer OpenMV Cam auszuführen. Das rpc-Modul erlaubt auch den umgekehrten Weg, falls Sie möchten, dass Ihre OpenMV Cam entfernte Prozedur- (oder Python-)Aufrufe auf einem anderen Mikrocontroller oder Computer ausführen kann.

Verwendung der Bibliothek

Ein minimaler Slave, der einen Callback über UART bereitstellt:

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.

Der passende Master, der den Slave nach einem JPEG-Einzelbild fragt:

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

Tauschen Sie rpc_uart_master / rpc_uart_slave gegen das passende can-, i2c- oder spi-Paar aus, um einen anderen Transportweg zu verwenden.

Im Allgemeinen erstellen Sie für das steuernde Gerät zur Nutzung der rpc-Bibliothek ein Schnittstellenobjekt mit der rpc-Bibliothek. Zum Beispiel:

interface = rpc.rpc_uart_master(baudrate=115200)

Dies erstellt eine UART-Schnittstelle, um mit einem rpc-Slave zu kommunizieren.

Sobald die Schnittstelle erstellt ist, müssen Sie nur Folgendes tun:

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

Und die rpc-Bibliothek wird versuchen, diese "remote_function_or_method_name" auf dem Slave auszuführen. Die entfernte Funktion oder Methode erhält das bytes_object_argument, das bis zu 2^32-1 Byte groß sein kann. Sobald die entfernte Methode die Ausführung beendet hat, gibt sie ein memory_view_object_result zurück, das ebenfalls bis zu 2^32-1 Byte groß sein kann. Da Argument und Antwort beide generische Byte-Container sind, können Sie alles über die rpc-Bibliothek übergeben und jede Art von Antwort empfangen. Eine einfache Möglichkeit, Argumente zu übergeben, besteht darin, struct.pack() zu verwenden, um das Argument zu erstellen, und struct.unpack(), um das Argument auf der anderen Seite zu empfangen. Für die Antwort kann die andere Seite ein String-Objekt oder einen JSON-String als Ergebnis senden, das der Master dann interpretieren kann.

Was Fehler betrifft: Wenn Sie versuchen, einen nicht existierenden Funktions- oder Methodennamen auszuführen, gibt die rpc_master.call()-Methode ein leeres bytes()-Objekt zurück. Falls die rpc-Bibliothek nicht mit dem Slave kommunizieren konnte, gibt die rpc-Bibliothek None zurück.

Um die Dinge einfach zu halten, hält die rpc-Bibliothek keine Verbindung zwischen Master- und Slave-Geräten aufrecht. Die rpc_master.call()-Methode kapselt den Versuch, sich mit dem Slave zu verbinden, die Ausführung der entfernten Funktion oder Methode zu starten und das Ergebnis abzurufen.

Auf der Slave-Seite müssen Sie nun eine rpc-Schnittstelle erstellen, um mit dem Master zu kommunizieren. Das sieht so aus:

interface = rpc.rpc_uart_slave(baudrate=115200)

Dies erstellt die UART-Schnittstellenschicht, um mit einem rpc-Master zu kommunizieren.

Sobald Sie die Slave-Schnittstelle erstellt haben, müssen Sie Callbacks registrieren, die der Master mit dem Schnittstellenobjekt aufrufen kann:

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

interface.register_callback(remote_function_or_method_name)

Sie können auf dem Slave so viele Callbacks registrieren, wie Sie möchten. Sobald Sie mit dem Registrieren der Callbacks fertig sind, müssen Sie schließlich nur noch Folgendes ausführen:

interface.loop()

Auf dem Slave, um die rpc-Bibliothek zu starten und auf den Master zu lauschen. Beachten Sie, dass die rpc_slave.loop()-Methode nicht zurückkehrt.

class rpc – rpc-Basisklasse

Die rpc-Basisklasse wird von den Klassen rpc_master und rpc_slave neu implementiert, um die Master- und Slave-Schnittstellen zu erstellen. Sie ist nicht zur direkten Verwendung gedacht.

class rpc.rpc

Erstellt ein rpc-Objekt. Nicht zur direkten Verwendung gedacht.

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

Von transportspezifischen Unterklassen neu implementiert. Füllt buff innerhalb von timeout_ms Millisekunden mit Bytes aus der zugrunde liegenden Schnittstelle. Gibt bei Zeitüberschreitung None zurück.

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

Von transportspezifischen Unterklassen neu implementiert. Sendet data innerhalb von timeout_ms Millisekunden über die zugrunde liegende Schnittstelle.

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

Empfängt einen Strom von Nutzdaten von einem entfernten rpc.stream_writer. Sollte innerhalb eines rpc_slave-Callbacks (oder direkt nach einem erfolgreichen rpc_master.call) aufgerufen werden, sobald sich beide Seiten synchronisiert haben.

  • call_back – aufrufbares Objekt, das einmal pro empfangener Nutzlast als call_back(data) aufgerufen wird, wobei data ein memoryview ist. Der Rückgabewert wird ignoriert.

  • queue_depth – Anzahl der in Übertragung befindlichen Einzelbilder, die der Writer senden darf, bevor er auf den Reader wartet. Höhere Werte erhöhen den Durchsatz auf Kosten des Speichers.

  • read_timeout_ms – Millisekunden, die pro Nutzlast gewartet werden soll.

Kehrt bei jedem Fehler zurück. Zum Abbrechen lösen Sie innerhalb von call_back eine Ausnahme aus; die Gegenseite wird in eine Zeitüberschreitung laufen.

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

Sendet einen Strom von Nutzdaten an einen entfernten rpc.stream_reader. Sollte innerhalb eines rpc_slave-Callbacks (oder direkt nach einem erfolgreichen rpc_master.call) aufgerufen werden, sobald sich beide Seiten synchronisiert haben.

  • call_back – aufrufbares Objekt, das ohne Argumente aufgerufen wird und die nächste zu sendende bytes- oder memoryview-Nutzlast zurückgibt.

  • write_timeout_ms – Millisekunden, die beim Senden jeder Nutzlast gewartet werden soll.

Kehrt bei jedem Fehler zurück. Zum Abbrechen lösen Sie innerhalb von call_back eine Ausnahme aus; die Gegenseite wird in eine Zeitüberschreitung laufen.

class rpc_master – rpc_master-Basisklasse

Der rpc_master ist eine Basisklasse. Verwenden Sie eine der transportspezifischen Unterklassen (rpc_can_master, rpc_i2c_master, rpc_spi_master, rpc_uart_master).

class rpc.rpc_master

Erstellt ein rpc_master-Objekt. Nicht zur direkten Verwendung gedacht.

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

Führt einen entfernten Aufruf auf dem Slave-Gerät aus.

  • name – String-Name der auszuführenden entfernten Funktion oder Methode.

  • databytes-ähnliches Objekt, das als Argument an die entfernte Funktion übergeben wird.

  • send_timeout – Millisekunden, die beim Verbinden mit dem Slave und beim Starten der Ausführung der entfernten Funktion gewartet werden soll. Sobald der Master beginnt, das Argument zu senden, gilt dies nicht mehr; die Bibliothek erlaubt bis zu 5 Sekunden für die Argumentübertragung.

  • recv_timeout – Millisekunden, die darauf gewartet werden soll, dass der Slave beginnt, eine Antwort zurückzugeben. Sobald der Master beginnt, die Antwort zu empfangen, gilt dies nicht mehr; die Bibliothek erlaubt bis zu 5 Sekunden für die Antwortübertragung.

Gibt bei Erfolg ein memoryview der Antwort zurück, ein leeres bytes(), falls der entfernte Name auf dem Slave nicht existiert, oder None bei einem Kommunikationsfehler.

class rpc_slave – rpc_slave-Basisklasse

Der rpc_slave ist eine Basisklasse. Verwenden Sie eine der transportspezifischen Unterklassen (rpc_can_slave, rpc_i2c_slave, rpc_spi_slave, rpc_uart_slave).

class rpc.rpc_slave

Erstellt ein rpc_slave-Objekt. Nicht zur direkten Verwendung gedacht.

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

Registriert einen Callback, den der Master über seinen Namen aufrufen kann. cb ist ein aufrufbares Objekt, das ein memoryview-Argument annimmt und ein bytes-ähnliches Objekt zurückgibt. Das __name__ des Callbacks wird als Suchschlüssel verwendet.

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

Plant cb (ein aufrufbares Objekt ohne Argumente) zur einmaligen Ausführung, unmittelbar nachdem der aktuell laufende rpc-Callback seine Antwort erfolgreich an den Master zurückgegeben hat. Muss innerhalb eines rpc-Callbacks aufgerufen werden. Ermöglicht es, dass langlaufende Arbeit oder rpc.get_bytes/rpc.put_bytes-Direktdurchleitungsübertragungen zwischen rpc-Transaktionen ausgeführt werden. Bei wiederholter Ausführung muss bei jedem Aufruf erneut registriert werden.

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

Registriert cb (ein aufrufbares Objekt ohne Argumente), das bei jeder Iteration von rpc_slave.loop aufgerufen wird. Anders als rpc_slave.schedule_callback bleibt dieser Callback registriert. Muss nicht blockierend sein; die Aufrufrate ist variabel.

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

Führt die rpc-Slave-Dispatch-Schleife aus. Kehrt nur durch eine aus einem Callback ausgelöste Ausnahme zurück.

  • recv_timeout – Millisekunden, die auf einen Befehl vom Master gewartet werden soll, bevor erneut versucht wird.

  • send_timeout – Millisekunden, die darauf gewartet werden soll, dass der Master die Antwort bestätigt, bevor zum Empfang zurückgekehrt wird.

class rpc_can_master – CAN-Master-Schnittstelle

Steuern Sie ein anderes rpc-Gerät über 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-Bit-CAN-Nachrichten-ID, die für den Datentransport verwendet wird.

  • bit_rate – CAN-Bitrate in Bit pro Sekunde.

  • sample_point – Tseg1/Tseg2-Abtastpunkt-Prozentsatz (z. B. 50.0, 62.5, 75, 87.5).

  • can_bus – CAN-Peripheriegerätenummer.

message_id und bit_rate von Master und Slave müssen übereinstimmen. Der Bus muss mit 120 Ohm terminiert werden.

class rpc_can_slave – CAN-Slave-Schnittstelle

Lassen Sie sich von einem anderen rpc-Gerät über CAN steuern.

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

Siehe rpc_can_master für die Beschreibungen der Argumente.

class rpc_i2c_master – I2C-Master-Schnittstelle

Steuern Sie ein anderes rpc-Gerät über I2C.

class rpc.rpc_i2c_master(slave_addr: int = 0x12, rate: int = 100000, i2c_bus: int = 2)
  • slave_addr – 7-Bit-I2C-Adresse des Slave-Geräts.

  • rate – I2C-Bus-Taktfrequenz in Hz.

  • i2c_bus – I2C-Peripheriegerätenummer.

Master- und Slave-Adressen müssen übereinstimmen. An SCL und SDA sind externe Pull-up-Widerstände erforderlich, und beide Geräte müssen eine gemeinsame Masse teilen.

class rpc_i2c_slave – I2C-Slave-Schnittstelle

Lassen Sie sich von einem anderen rpc-Gerät über I2C steuern.

class rpc.rpc_i2c_slave(slave_addr: int = 0x12, i2c_bus: int = 2)
  • slave_addr – 7-Bit-I2C-Adresse, auf die dieser Slave antwortet.

  • i2c_bus – I2C-Peripheriegerätenummer.

class rpc_spi_master – SPI-Master-Schnittstelle

Steuern Sie ein anderes rpc-Gerät über 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 – Name des Chip-Select-Pins.

  • freq – SPI-Bus-Taktfrequenz in Hz.

  • clk_polarity – Ruhepegel des Takts (0 oder 1).

  • clk_phase – Daten an der ersten (0) oder zweiten (1) Taktflanke abtasten.

  • spi_bus – SPI-Peripheriegerätenummer.

Master- und Slave-Einstellungen müssen übereinstimmen. Verbinden Sie CS, SCLK, MOSI, MISO direkt. Beide Geräte müssen eine gemeinsame Masse teilen.

class rpc_spi_slave – SPI-Slave-Schnittstelle

Lassen Sie sich von einem anderen rpc-Gerät über SPI steuern.

class rpc.rpc_spi_slave(cs_pin: str = 'P3', clk_polarity: int = 1, clk_phase: int = 0, spi_bus: int = 2)
  • cs_pin – Name des Chip-Select-Eingangspins.

  • clk_polarity – Ruhepegel des Takts (0 oder 1).

  • clk_phase – Daten an der ersten (0) oder zweiten (1) Taktflanke abtasten.

  • spi_bus – SPI-Peripheriegerätenummer.

class rpc_uart_master – UART-Master-Schnittstelle

Steuern Sie ein anderes rpc-Gerät über asynchrone serielle Schnittstelle (UART).

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

  • uart_port – UART-Peripheriegerätenummer.

Die Baudraten von Master und Slave müssen übereinstimmen. Verbinden Sie Master-TX mit Slave-RX und Master-RX mit Slave-TX. Beide Geräte müssen eine gemeinsame Masse teilen.

class rpc_uart_slave – UART-Slave-Schnittstelle

Lassen Sie sich von einem anderen rpc-Gerät über asynchrone serielle Schnittstelle (UART) steuern.

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

  • uart_port – UART-Peripheriegerätenummer.