rpc — rpc 라이브러리

OpenMV Cam의 rpc 모듈은 OpenMV Cam을 다른 마이크로컨트롤러나 컴퓨터에 연결하여 OpenMV Cam에서 원격 파이썬(또는 프로시저) 호출을 실행할 수 있게 해줍니다. rpc 모듈은 그 반대도 지원하므로, OpenMV Cam이 다른 마이크로컨트롤러나 컴퓨터에서 원격 프로시저(또는 파이썬) 호출을 실행하도록 할 수도 있습니다.

라이브러리 사용 방법

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)

이는 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 기반 클래스는 master 및 slave 인터페이스를 생성하기 위해 rpc_masterrpc_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) 형태로 호출되는 호출 가능 객체이며, 여기서 datamemoryview 입니다. 반환값은 무시됩니다.

  • 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 페이로드를 반환하는 호출 가능 객체입니다.

  • 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

현재 실행 중인 rpc 콜백이 master에게 응답을 성공적으로 반환한 직후에 cb (인자를 받지 않는 호출 가능 객체)를 한 번 실행하도록 예약합니다. rpc 콜백 내부에서 호출해야 합니다. 이를 통해 장시간 실행되는 작업이나 rpc.get_bytes/rpc.put_bytes 컷스루 전송이 rpc 트랜잭션 사이에 실행될 수 있습니다. 반복 실행이 필요한 경우 매 호출마다 다시 등록하세요.

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

rpc_slave.loop 의 매 반복마다 호출되도록 cb (인자를 받지 않는 호출 가능 객체)를 등록합니다. rpc_slave.schedule_callback 과 달리 이 콜백은 등록된 상태로 유지됩니다. 비차단이어야 하며, 호출 빈도는 가변적입니다.

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

rpc slave 디스패치 루프를 실행합니다. 콜백에서 발생한 예외로만 반환됩니다.

  • recv_timeout – 재시도하기 전에 master로부터의 명령을 대기할 밀리초입니다.

  • send_timeout – 수신 상태로 돌아가기 전에 master가 응답을 확인하기를 대기할 밀리초입니다.

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_idbit_rate 는 일치해야 합니다. 버스는 120옴으로 종단되어야 합니다.

class rpc_can_slave – CAN Slave 인터페이스

CAN을 통해 다른 rpc 장치에 의해 제어됩니다.

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

인자 설명은 rpc_can_master 를 참조하세요.

class rpc_i2c_master – I2C Master 인터페이스

I2C를 통해 다른 rpc 장치를 제어합니다.

class rpc.rpc_i2c_master(slave_addr: int = 0x12, rate: int = 100000, i2c_bus: int = 2)
  • slave_addr – slave 장치의 7비트 I2C 주소입니다.

  • rate – Hz 단위의 I2C 버스 클럭 주파수입니다.

  • i2c_bus – I2C 주변장치 번호입니다.

master와 slave 주소는 일치해야 합니다. SCL과 SDA에 외부 풀업이 필요하며, 두 장치는 공통 그라운드를 공유해야 합니다.

class rpc_i2c_slave – I2C Slave 인터페이스

I2C를 통해 다른 rpc 장치에 의해 제어됩니다.

class rpc.rpc_i2c_slave(slave_addr: int = 0x12, i2c_bus: int = 2)
  • slave_addr – 이 slave가 응답하는 7비트 I2C 주소입니다.

  • i2c_bus – 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 인터페이스

SPI를 통해 다른 rpc 장치에 의해 제어됩니다.

class rpc.rpc_spi_slave(cs_pin: str = 'P3', clk_polarity: int = 1, clk_phase: int = 0, spi_bus: int = 2)
  • cs_pin – 칩 셀렉트 입력 핀 이름입니다.

  • clk_polarity – 유휴 클럭 레벨입니다(0 또는 1).

  • clk_phase – 첫 번째(0) 또는 두 번째(1) 클럭 에지에서 데이터를 샘플링합니다.

  • spi_bus – SPI 주변장치 번호입니다.

class rpc_uart_master – UART Master 인터페이스

비동기 직렬(UART)을 통해 다른 rpc 장치를 제어합니다.

class rpc.rpc_uart_master(baudrate: int = 9600, uart_port: int = 3)
  • baudrate – 직렬 보드 레이트입니다.

  • uart_port – UART 주변장치 번호입니다.

master와 slave 보드 레이트는 일치해야 합니다. master TX를 slave RX에, master RX를 slave TX에 연결하세요. 두 장치는 공통 그라운드를 공유해야 합니다.

class rpc_uart_slave – UART Slave 인터페이스

비동기 직렬(UART)을 통해 다른 rpc 장치에 의해 제어됩니다.

class rpc.rpc_uart_slave(baudrate: int = 9600, uart_port: int = 3)
  • baudrate – 직렬 보드 레이트입니다.

  • uart_port – UART 주변장치 번호입니다.