rpc — bibliothèque rpc

Le module rpc de l’OpenMV Cam vous permet de connecter votre OpenMV Cam à un autre microcontrôleur ou ordinateur et d’exécuter des appels python (ou de procédure) distants sur votre OpenMV Cam. Le module rpc permet également l’inverse si vous souhaitez que votre OpenMV Cam puisse exécuter des appels de procédure (ou python) distants sur un autre microcontrôleur ou ordinateur.

Comment utiliser la bibliothèque

Un esclave minimal qui expose une fonction de rappel 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.

Le maître correspondant qui demande une trame JPEG à l’esclave

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

Remplacez rpc_uart_master / rpc_uart_slave par la paire can, i2c ou spi correspondante pour utiliser un transport différent.

En général, pour que le dispositif contrôleur utilise la bibliothèque rpc, vous allez créer un objet interface à l’aide de la bibliothèque rpc. Par exemple

interface = rpc.rpc_uart_master(baudrate=115200)

Cela crée une interface UART pour communiquer avec un esclave rpc.

Une fois l’interface créée, il vous suffit de faire

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

Et la bibliothèque rpc essaiera d’exécuter ce "remote_function_or_method_name" sur l’esclave. La fonction ou méthode distante recevra le bytes_object_argument qui peut atteindre une taille de 2^32-1 octets. Une fois que la méthode distante a terminé son exécution, elle retournera un memory_view_object_result qui peut également atteindre 2^32-1 octets. Comme l’argument et la réponse sont tous deux des conteneurs d’octets génériques, vous pouvez faire passer n’importe quoi à travers la bibliothèque rpc et recevoir n’importe quel type de réponse. Une manière simple de transmettre des arguments consiste à utiliser struct.pack() pour créer l’argument et struct.unpack() pour le recevoir de l’autre côté. Pour la réponse, l’autre côté peut envoyer un objet chaîne ou une chaîne json comme résultat, que le maître peut ensuite interpréter.

Quant aux erreurs, si vous essayez d’exécuter un nom de fonction ou de méthode inexistant, la méthode rpc_master.call() retournera un objet bytes() vide. Si la bibliothèque rpc n’a pas réussi à communiquer avec l’esclave, la bibliothèque rpc retournera None.

Pour rester simple, la bibliothèque rpc ne maintient pas de connexion entre les dispositifs maître et esclave. La méthode rpc_master.call() encapsule la tentative de connexion à l’esclave, le démarrage de l’exécution de la fonction ou méthode distante, et la récupération du résultat.

Maintenant, du côté de l’esclave, vous devez créer une interface rpc pour communiquer avec le maître. Cela ressemble à ceci

interface = rpc.rpc_uart_slave(baudrate=115200)

Cela créera la couche d’interface UART pour communiquer avec un maître rpc.

Une fois l’interface esclave créée, vous devez ensuite enregistrer les fonctions de rappel que le maître peut appeler avec l’objet 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)

Vous pouvez enregistrer autant de fonctions de rappel que vous le souhaitez sur l’esclave. Enfin, une fois que vous avez terminé l’enregistrement des fonctions de rappel, il vous suffit d’exécuter

interface.loop()

sur l’esclave pour démarrer la bibliothèque rpc et commencer à écouter le maître. Notez que la méthode rpc_slave.loop() ne retourne pas.

classe rpc – classe de base rpc

La classe de base rpc est réimplémentée par les classes rpc_master et rpc_slave pour créer les interfaces maître et esclave. Elle n’est pas destinée à être utilisée directement.

class rpc.rpc

Crée un objet rpc. N’est pas destiné à être utilisé directement.

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

Réimplémentée par les sous-classes spécifiques au transport. Remplit buff avec des octets provenant de l’interface sous-jacente dans un délai de timeout_ms millisecondes. Retourne None en cas de dépassement de délai.

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

Réimplémentée par les sous-classes spécifiques au transport. Envoie data via l’interface sous-jacente dans un délai de timeout_ms millisecondes.

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

Reçoit un flux de charges utiles depuis un rpc.stream_writer distant. Doit être appelée depuis l’intérieur d’une fonction de rappel rpc_slave (ou directement après un rpc_master.call réussi) une fois que les deux côtés se sont synchronisés.

  • call_back – objet appelable invoqué une fois par charge utile reçue sous la forme call_back(data)data est un memoryview. La valeur de retour est ignorée.

  • queue_depth – nombre de trames en transit que l’émetteur est autorisé à envoyer avant d’attendre le lecteur. Des valeurs plus élevées augmentent le débit au prix de la mémoire.

  • read_timeout_ms – millisecondes à attendre par charge utile.

Retourne en cas d’erreur. Pour annuler, levez une exception à l’intérieur de call_back ; le côté distant arrivera à expiration.

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

Envoie un flux de charges utiles vers un rpc.stream_reader distant. Doit être appelée depuis l’intérieur d’une fonction de rappel rpc_slave (ou directement après un rpc_master.call réussi) une fois que les deux côtés se sont synchronisés.

  • call_back – objet appelable invoqué sans argument qui retourne la prochaine charge utile bytes ou memoryview à envoyer.

  • write_timeout_ms – millisecondes à attendre lors de l’envoi de chaque charge utile.

Retourne en cas d’erreur. Pour annuler, levez une exception à l’intérieur de call_back ; le côté distant arrivera à expiration.

classe rpc_master – classe de base rpc_master

Le rpc_master est une classe de base. Utilisez l’une des sous-classes spécifiques au transport (rpc_can_master, rpc_i2c_master, rpc_spi_master, rpc_uart_master).

class rpc.rpc_master

Crée un objet rpc_master. N’est pas destiné à être utilisé directement.

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

Exécute un appel distant sur le dispositif esclave.

  • name – nom sous forme de chaîne de la fonction ou méthode distante à exécuter.

  • data – objet de type bytes passé comme argument à la fonction distante.

  • send_timeout – millisecondes à attendre lors de la connexion à l’esclave et du démarrage de l’exécution de la fonction distante. Une fois que le maître commence à envoyer l’argument, cela ne s’applique plus ; la bibliothèque autorise jusqu’à 5 secondes pour le transfert de l’argument.

  • recv_timeout – millisecondes à attendre que l’esclave commence à renvoyer une réponse. Une fois que le maître commence à recevoir la réponse, cela ne s’applique plus ; la bibliothèque autorise jusqu’à 5 secondes pour le transfert de la réponse.

Retourne un memoryview de la réponse en cas de succès, un bytes() vide si le nom distant n’existe pas sur l’esclave, ou None en cas d’échec de communication.

classe rpc_slave – classe de base rpc_slave

Le rpc_slave est une classe de base. Utilisez l’une des sous-classes spécifiques au transport (rpc_can_slave, rpc_i2c_slave, rpc_spi_slave, rpc_uart_slave).

class rpc.rpc_slave

Crée un objet rpc_slave. N’est pas destiné à être utilisé directement.

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

Enregistre une fonction de rappel que le maître peut invoquer par son nom. cb est un objet appelable prenant un argument memoryview et retournant un objet de type bytes. Le __name__ de la fonction de rappel est utilisé comme clé de recherche.

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

Planifie l’exécution de cb (un objet appelable sans argument) une seule fois, immédiatement après que la fonction de rappel rpc en cours d’exécution a renvoyé sa réponse avec succès au maître. Doit être appelée depuis l’intérieur d’une fonction de rappel rpc. Permet d’exécuter des travaux de longue durée ou des transferts directs rpc.get_bytes/rpc.put_bytes entre les transactions rpc. Réenregistrez à chaque invocation si une exécution répétée est requise.

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

Enregistre cb (un objet appelable sans argument) pour qu’il soit invoqué à chaque itération de rpc_slave.loop. Contrairement à rpc_slave.schedule_callback, cette fonction de rappel reste enregistrée. Doit être non bloquante ; la fréquence d’appel est variable.

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

Exécute la boucle de répartition de l’esclave rpc. Ne retourne pas, sauf par une exception levée depuis une fonction de rappel.

  • recv_timeout – millisecondes à attendre une commande du maître avant de réessayer.

  • send_timeout – millisecondes à attendre que le maître accuse réception de la réponse avant de revenir à la réception.

classe rpc_can_master – Interface maître CAN

Contrôle un autre dispositif 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 – identifiant de message CAN sur 11 bits utilisé pour le transport des données.

  • bit_rate – débit binaire CAN en bits par seconde.

  • sample_point – pourcentage du point d’échantillonnage Tseg1/Tseg2 (par ex. 50.0, 62.5, 75, 87.5).

  • can_bus – numéro du périphérique CAN.

Les message_id et bit_rate du maître et de l’esclave doivent correspondre. Le bus doit être terminé par 120 ohms.

classe rpc_can_slave – Interface esclave CAN

Être contrôlé par un autre dispositif rpc via CAN.

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

Voir rpc_can_master pour la description des arguments.

classe rpc_i2c_master – Interface maître I2C

Contrôle un autre dispositif rpc via I2C.

class rpc.rpc_i2c_master(slave_addr: int = 0x12, rate: int = 100000, i2c_bus: int = 2)
  • slave_addr – adresse I2C sur 7 bits du dispositif esclave.

  • rate – fréquence d’horloge du bus I2C en Hz.

  • i2c_bus – numéro du périphérique I2C.

Les adresses du maître et de l’esclave doivent correspondre. Des résistances de tirage externes sont requises sur SCL et SDA, et les deux dispositifs doivent partager une masse commune.

classe rpc_i2c_slave – Interface esclave I2C

Être contrôlé par un autre dispositif rpc via I2C.

class rpc.rpc_i2c_slave(slave_addr: int = 0x12, i2c_bus: int = 2)
  • slave_addr – adresse I2C sur 7 bits à laquelle cet esclave répond.

  • i2c_bus – numéro du périphérique I2C.

classe rpc_spi_master – Interface maître SPI

Contrôle un autre dispositif 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 – nom de la broche de sélection de puce (chip-select).

  • freq – fréquence d’horloge du bus SPI en Hz.

  • clk_polarity – niveau d’horloge au repos (0 ou 1).

  • clk_phase – échantillonnage des données sur le premier (0) ou le second (1) front d’horloge.

  • spi_bus – numéro du périphérique SPI.

Les réglages du maître et de l’esclave doivent correspondre. Connectez CS, SCLK, MOSI, MISO directement. Les deux dispositifs doivent partager une masse commune.

classe rpc_spi_slave – Interface esclave SPI

Être contrôlé par un autre dispositif 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 – nom de la broche d’entrée de sélection de puce (chip-select).

  • clk_polarity – niveau d’horloge au repos (0 ou 1).

  • clk_phase – échantillonnage des données sur le premier (0) ou le second (1) front d’horloge.

  • spi_bus – numéro du périphérique SPI.

classe rpc_uart_master – Interface maître UART

Contrôle un autre dispositif rpc via série asynchrone (UART).

class rpc.rpc_uart_master(baudrate: int = 9600, uart_port: int = 3)
  • baudrate – débit en bauds de la liaison série.

  • uart_port – numéro du périphérique UART.

Les débits en bauds du maître et de l’esclave doivent correspondre. Connectez le TX du maître au RX de l’esclave et le RX du maître au TX de l’esclave. Les deux dispositifs doivent partager une masse commune.

classe rpc_uart_slave – Interface esclave UART

Être contrôlé par un autre dispositif rpc via série asynchrone (UART).

class rpc.rpc_uart_slave(baudrate: int = 9600, uart_port: int = 3)
  • baudrate – débit en bauds de la liaison série.

  • uart_port – numéro du périphérique UART.