protocol --- Saluran Protokol OpenMV

Modul protocol mengekspos protokol host OpenMV ke Python. Modul ini memungkinkan tumpukan protokol sisi firmware untuk diinisialisasi dan dikonfigurasi, serta memungkinkan kode pengguna mendaftarkan saluran logis kustom yang didukung oleh objek Python yang mengimplementasikan antarmuka saluran (read, write, size, poll, dll.). Inilah yang digunakan alat pendamping desktop ketika mereka melakukan streaming data citra atau mengekspos widget interaktif ke kamera yang terhubung.

Contoh

Melakukan streaming citra RGB565 ke alat host menggunakan backend kustom yang mengimplementasikan antarmuka saluran mentah (backend.size(), backend.shape(), backend.poll(), backend.read()):

import csi
import protocol

csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.HD)

img = csi0.snapshot()
img_mv = memoryview(img.bytearray())
frame_ready = True


class FrameChannel:
    def size(self):
        return len(img_mv)

    def shape(self):
        return (img.height(), img.width(), len(img_mv))

    def poll(self):
        return frame_ready

    def read(self, offset, size):
        global frame_ready
        end = offset + size
        chunk = img_mv[offset:end]
        if end >= len(img_mv):
            frame_ready = False
        return chunk


protocol.register(name="frame", backend=FrameChannel())

while True:
    if not frame_ready:
        img = csi0.snapshot()
        img_mv = memoryview(img.bytearray())
        frame_ready = True

Skrip sisi host yang sesuai, menggunakan paket Python openmv (pip install openmv) untuk terhubung, mendorong skrip di kamera, dan menarik setiap bingkai:

import cv2
import numpy as np
from openmv.camera import Camera

# The on-cam script above, stored as a string (or read from a file).
SCRIPT = open("frame_streamer_on_cam.py").read()

with Camera("/dev/ttyACM0", baudrate=921600) as cam:
    cam.stop()
    cam.exec(SCRIPT)

    while True:
        status = cam.read_status()
        if not cam.has_channel("frame") or not status.get("frame"):
            continue

        h, w, size = cam._channel_shape(cam.get_channel(name="frame"))
        if cam.channel_size("frame") < size:
            continue

        data = cam.channel_read("frame", size)
        rgb565 = np.frombuffer(data, dtype="<u2").reshape(h, w)

        # Unpack RGB565 to an HxWx3 uint8 RGB image.
        r = ((rgb565 >> 11) & 0x1F) << 3
        g = ((rgb565 >>  5) & 0x3F) << 2
        b = ( rgb565        & 0x1F) << 3
        frame = np.dstack([r, g, b]).astype(np.uint8)

        # Display with OpenCV (cv2 expects BGR, not RGB).
        cv2.imshow("OpenMV", cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
        if cv2.waitKey(1) == ord("q"):
            break

cv2.destroyAllWindows()

Ganti /dev/ttyACM0 dengan port serial kamera (misalnya COM3 di Windows). Konstruktor openmv.camera.Camera menerima parameter protokol yang sama dengan init (crc / seq / ack / events / max_payload / max_retry / timeout) ketika tumpukan sisi kamera telah dikonfigurasi ulang agar sesuai.

Fungsi

protocol.init(crc: bool = True, seq: bool = True, ack: bool = True, events: bool = True, max_payload: int = ..., rtx_retries: int = 3, rtx_timeout_ms: int = 500, lock_interval_ms: int = 10, poll_ms: int = 0) None

Menginisialisasi (atau mengonfigurasi ulang) tumpukan protokol dan mendaftarkan saluran data logis default (stdin, stdout, stream dan, jika dikompilasi, profile). Memunculkan RuntimeError jika inisialisasi gagal. Firmware melakukan boot dengan tumpukan protokol USB default yang sudah berjalan, sehingga pemanggilan ini hanya diperlukan untuk mengubah transport atau mengganti parameter pembingkaian default.

crc mengaktifkan validasi CRC pada bingkai protokol.

seq mengaktifkan pelacakan nomor urutan.

ack mengaktifkan pengakuan per bingkai.

events mengaktifkan notifikasi event saluran.

max_payload adalah ukuran payload maksimum dalam byte. Jika dihilangkan, default per kamera di bawah ini digunakan; ini diturunkan dari ukuran buffer protokol setiap board sebagai buffer - 10 (header) - 4 (CRC).

Kamera

Ukuran buffer

Payload maksimum

OpenMV Cam M4 (OPENMV2)

512

498

OpenMV Cam M7 (OPENMV3)

512

498

OpenMV Cam H7 (OPENMV4)

512

498

OpenMV Cam H7 Plus (OPENMV4P)

4096

4082

OpenMV Pure Thermal (OPENMVPT)

4096

4082

OpenMV Cam RT1062 (OPENMV_RT1060)

4096

4082

OpenMV Cam N6 (OPENMV_N6)

8192

8178

OpenMV AE3 (OPENMV_AE3)

8192

8178

Arduino Portenta H7 (ARDUINO_PORTENTA_H7)

4096

4082

Arduino Giga (ARDUINO_GIGA)

4096

4082

Arduino Nicla Vision (ARDUINO_NICLA_VISION)

4096

4082

rtx_retries adalah jumlah upaya retransmisi. Default 3.

rtx_timeout_ms adalah timeout retransmisi dalam milidetik (digandakan setelah setiap timeout). Default 500.

lock_interval_ms adalah interval kunci minimum dalam milidetik. Default 10.

poll_ms adalah interval polling dalam milidetik. 0 (default) menonaktifkan polling timer.

protocol.is_active() bool

Mengembalikan True jika host saat ini terhubung dan tumpukan protokol aktif, jika tidak False.

protocol.register(name: str, *, backend: object, flags: int = 0) ProtocolChannel

Mendaftarkan objek Python backend sebagai saluran logis baru dan mengembalikan handle ProtocolChannel. Metode yang tersedia pada objek backend (lihat Antarmuka Backend di bawah) menentukan kemampuan saluran; protocol.CHANNEL_FLAG_READ, protocol.CHANNEL_FLAG_WRITE dan protocol.CHANNEL_FLAG_LOCK ditambahkan ke flags secara otomatis ketika metode yang sesuai diimplementasikan.

name adalah nama saluran sebagai string. Dipotong ke ukuran buffer nama saluran firmware. Wajib.

backend adalah objek Python yang mengimplementasikan antarmuka backend. Wajib. Biasanya diteruskan melalui kata kunci (backend=...).

flags adalah bit flag saluran tambahan (lihat konstanta CHANNEL_FLAG_*). Opsional; default ke 0.

Memunculkan RuntimeError jika saluran tidak dapat didaftarkan (misalnya tidak ada slot saluran yang kosong).

Kelas

class protocol.ProtocolChannel

Handle yang dikembalikan oleh protocol.register. Instance tidak dibuat secara langsung.

send_event(event: int, wait_ack: bool = False) None

Mengirim notifikasi event saluran ke host.

event adalah pengenal event (integer).

wait_ack jika True memblokir hingga host mengakui event tersebut.

Memunculkan RuntimeError jika pengiriman event gagal.

Antarmuka Backend

Objek backend yang diteruskan ke protocol.register dapat mengimplementasikan subset dari metode berikut. Hanya metode yang ada pada objek yang dihubungkan ke lapisan protokol C; metode yang hilang membuat kemampuan yang sesuai dinonaktifkan.

class protocol.backend

Objek backend saluran yang diteruskan ke protocol.register. Metode di bawah ini menjelaskan antarmuka opsional yang dapat diimplementasikan oleh backend Python.

init() object

Dipanggil sekali ketika saluran diinisialisasi. Kembalikan nilai non-None apa pun jika berhasil; pengecualian atau pengembalian yang hilang diperlakukan sebagai error.

poll() bool

Mengembalikan True jika saluran memiliki data yang siap dibaca oleh host.

lock() bool

Memperoleh saluran untuk transfer. Mengembalikan True jika berhasil.

unlock() bool

Melepaskan saluran setelah transfer. Mengembalikan True jika berhasil.

size() int

Mengembalikan jumlah byte yang saat ini dapat dibaca dari saluran.

shape() tuple

Mengembalikan tuple hingga empat integer yang mendeskripsikan bentuk data (misalnya dimensi citra). Hingga empat elemen dikonsumsi oleh lapisan protokol.

flush() object

Membuang semua data yang tertunda. Mengembalikan nilai non-None apa pun jika berhasil.

read(offset: int, size: int) bytes

Mengembalikan hingga size byte mulai dari offset sebagai objek seperti bytes yang mendukung protokol buffer.

readp(offset: int, size: int) bytes

Varian tanpa salinan dari read. Mengembalikan buffer yang memori dasarnya dibaca langsung oleh lapisan protokol; buffer harus tetap valid selama durasi transfer.

write(offset: int, data: bytearray) int

Menulis data pada offset. data adalah bytearray yang merujuk buffer C secara langsung. Mengembalikan jumlah byte yang ditulis, atau 0 untuk keberhasilan default.

ioctl(cmd: int, length: int, arg: bytearray | None) int

Menangani ioctl. arg adalah None jika length adalah nol, jika tidak bytearray yang merujuk buffer C. Mengembalikan 0 atau None jika berhasil, atau integer negatif jika error.

is_active() bool

Untuk saluran transport, mengembalikan True jika transport yang mendasarinya saat ini terhubung.

class protocol.CBORChannel(on_read: Callable | None = None, on_write: Callable | None = None)

Backend Python tingkat tinggi (disediakan oleh paket protocol yang dibekukan) yang menserialisasi field bernama ke CBOR menggunakan kunci integer yang kompatibel dengan SenML. Mendukung widget tampilan (label, depth) dan kontrol interaktif (toggle, slider, select) dengan callback on_read/on_write.

on_read adalah callable opsional on_read(channel) yang dipanggil sebelum saluran diserialisasi untuk host. Gunakan untuk menyegarkan nilai field.

on_write adalah callable opsional on_write(channel, name, value) yang dipanggil ketika host menulis nilai baru untuk field bernama.

add(name: str, type: str, value: Any = None, unit: str | None = None, min: int | float | None = None, max: int | float | None = None, step: int | float | None = None, options: list | None = None, width: int | None = None, height: int | None = None) None

Menambahkan field bernama ke saluran.

name adalah nama tampilan; harus unik dalam saluran ini.

type adalah tipe widget: "label", "toggle", "slider", "select", atau "depth".

value adalah nilai awal. Default bergantung pada type.

unit adalah string unit untuk label/slider (misalnya "Cel", "%RH").

min adalah nilai minimum (rentang slider atau rentang depth).

max adalah nilai maksimum (rentang slider atau rentang depth).

step adalah ukuran langkah (slider).

options adalah daftar string pilihan (select).

width adalah lebar piksel (depth).

height adalah tinggi piksel (depth).

__getitem__(name: str) object

Mengembalikan nilai saat ini dari field bernama. Untuk field depth, buffer data biner dikembalikan, jika tidak nilai skalar.

__setitem__(name: str, value: Any) None

Mengatur nilai field bernama. Untuk field slider, tuple (min, max, value) memperbarui rentang dan nilai saat ini secara bersamaan. Untuk field depth, value adalah buffer data biner.

poll() bool

Metode antarmuka backend. Mengembalikan True ketika data yang diserialisasi tersedia untuk host.

size() int

Metode antarmuka backend. Memanggil on_read (jika diatur) dan mengembalikan ukuran buffer yang diserialisasi.

read(offset: int, size: int) bytes

Metode antarmuka backend. Mengembalikan irisan dari buffer yang diserialisasi.

write(offset: int, data: bytearray) int

Metode antarmuka backend. Mendekode daftar pembaruan CBOR dan menerapkan nilai ke field bernama yang cocok, memanggil on_write untuk masing-masing.

Konstanta

Bit flag saluran (digabungkan secara bitwise; diteruskan ke protocol.register melalui flags atau diatur secara otomatis berdasarkan metode backend).

protocol.CHANNEL_FLAG_READ: int

Saluran mendukung pembacaan.

protocol.CHANNEL_FLAG_WRITE: int

Saluran mendukung penulisan.

protocol.CHANNEL_FLAG_LOCK: int

Saluran mengimplementasikan lock/unlock.

protocol.CHANNEL_FLAG_PHYSICAL: int

Saluran mewakili transport fisik (sebagai lawan dari saluran data logis).

Pengenal saluran bawaan.

protocol.CHANNEL_ID_TRANSPORT: int

ID saluran yang dicadangkan untuk transport aktif.

protocol.CHANNEL_ID_STDIN: int

ID saluran dari saluran stdin bawaan.

protocol.CHANNEL_ID_STDOUT: int

ID saluran dari saluran stdout bawaan.

protocol.CHANNEL_ID_STREAM: int

ID saluran dari saluran stream bawaan.

protocol.CHANNEL_ID_PROFILE: int

ID saluran dari saluran profiler bawaan (hanya ada ketika firmware dibangun dengan profiler diaktifkan).