rpc --- rpc 函式庫¶
OpenMV Cam 上的 rpc 模組可讓你將 OpenMV Cam 連接到另一個微控制器或電腦,並在 OpenMV Cam 上執行遠端 python(或程序)呼叫。rpc 模組也支援反向操作,讓你的 OpenMV Cam 能夠在另一個微控制器或電腦上執行遠端程序(或 python)呼叫。
如何使用本函式庫¶
透過 UART 公開單一回呼函式的最小化 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)
這會建立一個 UART 介面以與 rpc slave 通訊。
介面建立完成後,你只需要執行:
memory_view_object_result = interface.call("remote_function_or_method_name", bytes_object_argument)
接著 rpc 函式庫會嘗試在 slave 上執行該 "remote_function_or_method_name"。遠端函式或方法會收到 bytes_object_argument,其大小最多可達 2^32-1 位元組。當遠端方法執行完畢後,它會回傳 memory_view_object_result,其大小同樣最多可達 2^32-1 位元組。由於引數與回應都是通用的位元組容器,你可以透過 rpc 函式庫傳遞任何資料,並接收任何型別的回應。傳遞引數的一個簡單方式是使用 struct.pack() 來建立引數,並在另一端使用 struct.unpack() 來接收引數。至於回應,另一端可以傳送字串物件或 json 字串作為結果,master 接著即可加以解讀。
至於錯誤處理,若你嘗試執行不存在的函式或方法名稱,rpc_master.call() 方法會回傳一個空的 bytes() 物件。若 rpc 函式庫無法與 slave 通訊,則 rpc 函式庫會回傳 None。
為了保持簡單,rpc 函式庫不會在 master 與 slave 裝置之間維持連線。rpc_master.call() 方法封裝了嘗試連接 slave、開始執行遠端函式或方法,以及取得結果等動作。
現在,在 slave 端,你必須建立一個 rpc 介面以與 master 通訊。其寫法如下:
interface = rpc.rpc_uart_slave(baudrate=115200)
這會建立 UART 介面層以與 rpc master 通訊。
建立 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-- 每收到一個酬載即被呼叫一次的可呼叫物件,呼叫形式為call_back(data),其中data為memoryview。其回傳值會被忽略。queue_depth-- 寫入端在等待讀取端之前可送出的在途影格數量。較高的值能提升吞吐量,但會消耗較多記憶體。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酬載。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是一個可呼叫物件,接受一個memoryview引數並回傳類bytes物件。回呼函式的__name__會作為查找用的鍵。
- schedule_callback(cb: Callable[[], None]) None¶
排程
cb(一個不帶引數的可呼叫物件)執行一次,時機為目前執行中的 rpc 回呼函式成功將其回應回傳給 master 之後。必須在 rpc 回呼函式內呼叫。這可讓長時間執行的工作或rpc.get_bytes/rpc.put_bytes直通傳輸在 rpc 交易之間執行。若需要重複執行,請在每次被呼叫時重新註冊。
- setup_loop_callback(cb: Callable[[], None]) None¶
註冊
cb(一個不帶引數的可呼叫物件),使其在rpc_slave.loop的每次迭代時被呼叫。與rpc_slave.schedule_callback不同,此回呼函式會持續保持註冊狀態。它必須是非阻塞的;呼叫頻率並不固定。
class rpc_can_master -- CAN Master 介面¶
透過 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 Slave 介面¶
由另一個 rpc 裝置透過 CAN 控制。
class rpc_i2c_master -- I2C Master 介面¶
透過 I2C 控制另一個 rpc 裝置。
class rpc_i2c_slave -- I2C Slave 介面¶
由另一個 rpc 裝置透過 I2C 控制。
class rpc_spi_master -- SPI Master 介面¶
透過 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-- 以 Hz 表示的 SPI 匯流排時脈頻率。clk_polarity-- 閒置時的時脈準位(0 或 1)。clk_phase-- 在第一個(0)或第二個(1)時脈邊緣取樣資料。spi_bus-- SPI 周邊裝置編號。
master 與 slave 的設定必須相符。請直接連接 CS、SCLK、MOSI、MISO。兩個裝置必須共用同一接地。
class rpc_spi_slave -- SPI Slave 介面¶
由另一個 rpc 裝置透過 SPI 控制。
class rpc_uart_master -- UART Master 介面¶
透過非同步序列(UART)控制另一個 rpc 裝置。
class rpc_uart_slave -- UART Slave 介面¶
由另一個 rpc 裝置透過非同步序列(UART)控制。