rpc --- rpc ライブラリ¶
OpenMV Cam の rpc モジュールを使うと、OpenMV Cam を別のマイクロコントローラやコンピュータに接続し、OpenMV Cam 上でリモートの Python(またはプロシージャ)呼び出しを実行できます。rpc モジュールは逆方向にも対応しており、OpenMV Cam から別のマイクロコントローラやコンピュータ上でリモートプロシージャ(または Python)呼び出しを実行することもできます。
ライブラリの使い方¶
UART 経由で 1 つのコールバックを公開する最小限の slave:
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.
slave に JPEG フレームを要求する対応した master:
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")
別のトランスポートを使うには、rpc_uart_master / rpc_uart_slave を対応する can、i2c、spi のペアに置き換えてください。
一般に、制御側デバイスで rpc ライブラリを使うには、rpc ライブラリを使ってインターフェースオブジェクトを作成します。例えば次のようになります:
interface = rpc.rpc_uart_master(baudrate=115200)
これにより、rpc の slave と通信するための UART インターフェースが作成されます。
インターフェースを作成したら、あとは次を実行するだけです:
memory_view_object_result = interface.call("remote_function_or_method_name", bytes_object_argument)
すると rpc ライブラリは slave 上でその "remote_function_or_method_name" の実行を試みます。リモートの関数またはメソッドは、最大 2^32-1 バイトまでの bytes_object_argument を受け取ります。リモートメソッドの実行が完了すると、これも最大 2^32-1 バイトまでの memory_view_object_result を返します。引数と応答はどちらも汎用的なバイトコンテナであるため、rpc ライブラリを通じて任意のものを渡し、任意の型の応答を受け取ることができます。引数を渡す簡単な方法は、struct.pack() を使って引数を作成し、もう一方の側で struct.unpack() を使って引数を受け取ることです。応答については、もう一方の側が結果として文字列オブジェクトや json 文字列を送信し、master がそれを解釈できます。
エラーについては、存在しない関数名やメソッド名を実行しようとすると rpc_master.call() メソッドは空の bytes() オブジェクトを返します。rpc ライブラリが slave との通信に失敗した場合、rpc ライブラリは None を返します。
簡潔さを保つため、rpc ライブラリは master デバイスと slave デバイスの間で接続を維持しません。rpc_master.call() メソッドは、slave への接続試行、リモート関数またはメソッドの実行開始、結果の取得を一括して行います。
次に、slave 側では、master と通信するための rpc インターフェースを作成する必要があります。これは次のようになります:
interface = rpc.rpc_uart_slave(baudrate=115200)
これにより、rpc の master と通信するための UART インターフェース層が作成されます。
slave インターフェースを作成したら、master が呼び出せるコールバックをインターフェースオブジェクトに登録する必要があります:
def remote_function_or_method_name(memoryview_object_argument):
<lots of code>
return bytes_object_result
interface.register_callback(remote_function_or_method_name)
slave には好きなだけコールバックを登録できます。最後に、コールバックの登録が終わったら、次を実行するだけです:
interface.loop()
これを slave 上で実行すると rpc ライブラリが起動し、master からの待ち受けを開始します。rpc_slave.loop() メソッドは戻らないことに注意してください。
class rpc -- rpc 基底クラス¶
rpc 基底クラスは rpc_master クラスと rpc_slave クラスによって再実装され、master インターフェースと slave インターフェースを作成します。直接使用することは意図されていません。
- class rpc.rpc¶
rpcオブジェクトを作成します。直接使用することは意図されていません。- get_bytes(buff: bytearray | memoryview, timeout_ms: int) bytes | None¶
トランスポート固有のサブクラスによって再実装されます。
timeout_msミリ秒以内に、基盤となるインターフェースから取得したバイトでbuffを埋めます。タイムアウト時にはNoneを返します。
- put_bytes(data: bytes | memoryview, timeout_ms: int) None¶
トランスポート固有のサブクラスによって再実装されます。
timeout_msミリ秒以内に、基盤となるインターフェース経由でdataを送信します。
- stream_reader(call_back: Callable[[memoryview], None], queue_depth: int = 1, read_timeout_ms: int = 5000) None¶
リモートの
rpc.stream_writerからペイロードのストリームを受信します。両側が同期した後、rpc_slaveのコールバック内(またはrpc_master.callの成功直後)から呼び出す必要があります。call_back-- 受信したペイロードごとに 1 回call_back(data)として呼び出される callable で、dataはmemoryviewです。戻り値は無視されます。queue_depth-- writer が reader を待つ前に送信できる処理中フレームの数です。値を大きくするとスループットが向上しますが、メモリを消費します。read_timeout_ms-- ペイロードごとに待機するミリ秒数です。
エラーが発生すると戻ります。キャンセルするには
call_back内で例外を発生させてください。リモート側はタイムアウトします。
- stream_writer(call_back: Callable[[], bytes | memoryview], write_timeout_ms: int = 5000) None¶
リモートの
rpc.stream_readerにペイロードのストリームを送信します。両側が同期した後、rpc_slaveのコールバック内(またはrpc_master.callの成功直後)から呼び出す必要があります。call_back-- 引数なしで呼び出され、送信する次のbytesまたはmemoryviewペイロードを返す callable です。write_timeout_ms-- 各ペイロードを送信する際に待機するミリ秒数です。
エラーが発生すると戻ります。キャンセルするには
call_back内で例外を発生させてください。リモート側はタイムアウトします。
class rpc_master -- rpc_master 基底クラス¶
rpc_master は基底クラスです。トランスポート固有のサブクラス(rpc_can_master、rpc_i2c_master、rpc_spi_master、rpc_uart_master)のいずれかを使用してください。
- class rpc.rpc_master¶
rpc_masterオブジェクトを作成します。直接使用することは意図されていません。- call(name: str, data: bytes = bytes(), send_timeout: int = 1000, recv_timeout: int = 1000) memoryview | None¶
slave デバイス上でリモート呼び出しを実行します。
name-- 実行するリモート関数またはメソッドの名前を表す文字列です。data-- リモート関数への引数として渡されるbytes様オブジェクトです。send_timeout-- slave への接続およびリモート関数の実行開始の間に待機するミリ秒数です。master が引数の送信を開始した後は、これは適用されなくなります。ライブラリは引数の転送に最大 5 秒を許容します。recv_timeout-- slave が応答の返送を開始するまで待機するミリ秒数です。master が応答の受信を開始した後は、これは適用されなくなります。ライブラリは応答の転送に最大 5 秒を許容します。
成功時には応答の
memoryviewを返し、リモート名が slave 上に存在しない場合は空のbytes()を、通信失敗時にはNoneを返します。
class rpc_slave -- rpc_slave 基底クラス¶
rpc_slave は基底クラスです。トランスポート固有のサブクラス(rpc_can_slave、rpc_i2c_slave、rpc_spi_slave、rpc_uart_slave)のいずれかを使用してください。
- class rpc.rpc_slave¶
rpc_slaveオブジェクトを作成します。直接使用することは意図されていません。- register_callback(cb: Callable[[memoryview], bytes | memoryview]) None¶
master が名前で呼び出せるコールバックを登録します。
cbは 1 つのmemoryview引数を取り、bytes様オブジェクトを返す callable です。コールバックの__name__がルックアップキーとして使用されます。
- schedule_callback(cb: Callable[[], None]) None¶
cb(引数を取らない callable)を、現在実行中の rpc コールバックが master への応答の返送に成功した直後に 1 回だけ実行されるようスケジュールします。rpc コールバック内から呼び出す必要があります。これにより、長時間実行される処理やrpc.get_bytes/rpc.put_bytesのカットスルー転送を rpc トランザクションの間に実行できます。繰り返し実行が必要な場合は、各呼び出しごとに再登録してください。
- setup_loop_callback(cb: Callable[[], None]) None¶
cb(引数を取らない callable)を、rpc_slave.loopの各反復で呼び出されるよう登録します。rpc_slave.schedule_callbackとは異なり、このコールバックは登録されたまま残ります。呼び出しレートは可変であるため、ブロッキングしないようにする必要があります。
class rpc_can_master -- CAN マスターインターフェース¶
CAN 経由で別の rpc デバイスを制御します。
- class rpc.rpc_can_master(message_id: int = 0x7FF, bit_rate: int = 250000, sample_point: float = 75, can_bus: int = 2)¶
message_id-- データ転送に使用される 11 ビットの CAN メッセージ ID です。bit_rate-- CAN のビットレート(ビット毎秒)です。sample_point-- Tseg1/Tseg2 のサンプルポイント割合です(例: 50.0、62.5、75、87.5)。can_bus-- CAN ペリフェラル番号です。
master と slave の
message_idとbit_rateは一致している必要があります。バスは 120 オームで終端する必要があります。
class rpc_can_slave -- CAN スレーブインターフェース¶
CAN 経由で別の rpc デバイスから制御されます。
class rpc_i2c_master -- I2C マスターインターフェース¶
I2C 経由で別の rpc デバイスを制御します。
class rpc_i2c_slave -- I2C スレーブインターフェース¶
I2C 経由で別の rpc デバイスから制御されます。
class rpc_spi_master -- SPI マスターインターフェース¶
SPI 経由で別の rpc デバイスを制御します。
- 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-- チップセレクトピン名です。freq-- SPI バスのクロック周波数(Hz)です。clk_polarity-- アイドル時のクロックレベル(0 または 1)です。clk_phase-- 最初の(0)または 2 番目の(1)クロックエッジでデータをサンプリングします。spi_bus-- SPI ペリフェラル番号です。
master と slave の設定は一致している必要があります。CS、SCLK、MOSI、MISO を直接接続してください。両方のデバイスは共通のグランドを共有する必要があります。
class rpc_spi_slave -- SPI スレーブインターフェース¶
SPI 経由で別の rpc デバイスから制御されます。
class rpc_uart_master -- UART マスターインターフェース¶
非同期シリアル(UART)経由で別の rpc デバイスを制御します。
class rpc_uart_slave -- UART スレーブインターフェース¶
非同期シリアル(UART)経由で別の rpc デバイスから制御されます。