12.6. Channel bernama

ID channel dalam header setiap paket memungkinkan hingga 32 stream independen berbagi transport fisik yang sama. Lapisan channel mengubah ID numerik tersebut menjadi endpoint bernama yang terlihat oleh aplikasi yang dapat dirujuk oleh kode host dengan string.

One transport wire on the left fanning out into four labelled channels on the cam side -- stdin, stdout, stream, and a user-registered status channel -- each showing as an independent box.

12.6.1. Empat channel bawaan

Cam mendaftarkan empat channel saat boot, sebelum kode aplikasi apa pun dijalankan:

  • stdin -- byte skrip yang didorong host ke cam untuk dieksekusi. IDE menggunakan channel ini untuk mengirim skrip yang sedang diedit; exec() pada SDK host adalah panggilan setara dari program Python.

  • stdout -- byte dari panggilan print() cam dan traceback pengecualian yang tidak tertangkap. Konsol serial IDE membaca channel ini.

  • stream -- channel pratinjau langsung. IDE mengambil bingkai JPEG darinya; skrip host mana pun dapat melakukan hal yang sama dengan read_frame().

  • profile -- event profiler, hanya ada ketika cam dibangun dengan profiling diaktifkan. Sebagian besar build rilis menghilangkannya.

Kode aplikasi jarang perlu menyentuh channel bawaan mana pun; pekerjaan menarik terjadi pada channel yang didaftarkan aplikasi itu sendiri.

12.6.2. Mendaftarkan channel

Skrip sisi cam mendaftarkan channel baru dengan memanggil protocol.register() dengan nama dan objek backend Python:

import json
import protocol
import time

trigger_count = 0

class StatusChannel:
    def size(self):
        # Refresh the snapshot on every host query.
        self._buf = json.dumps({
            'uptime_s': time.ticks_ms() // 1000,
            'triggers': trigger_count,
        }).encode()
        return len(self._buf)

    def read(self, offset, size):
        return self._buf[offset:offset + size]

protocol.register(name='status', backend=StatusChannel())

Metode objek backend menentukan apa yang dapat dilakukan channel. Backend dengan hanya size dan read adalah channel data hanya-baca; tambahkan write dan itu menjadi dua arah; tambahkan poll dan host dapat bertanya apakah data baru siap sebelum membayar biaya pembacaan. Mengambil sampel data di dalam size adalah pola paling sederhana ketika payload cukup kecil untuk dimuat dalam satu fragmen -- buffer dibuat sesuai permintaan, tidak pernah di-cache, tidak pernah dalam kondisi balapan. Payload yang lebih besar -- bingkai citra, jejak sensor -- memerlukan pola penguncian yang menahan buffer sampai host selesai membaca multi-fragmennya, dibahas bersama channel bingkai.

Sejumlah kecil pembukuan terjadi secara otomatis:

  • Pustaka menetapkan ID channel berikutnya yang tersedia (antara 0 dan 31).

  • Flag kemampuan diturunkan dari metode yang ada: CHANNEL_FLAG_READ jika read didefinisikan, CHANNEL_FLAG_WRITE jika write didefinisikan, CHANNEL_FLAG_LOCK jika lock / unlock didefinisikan.

  • Paket event CHANNEL_REGISTERED dikirim ke host yang terhubung sehingga daftar channel-nya diperbarui.

Nilai kembalian adalah handle protocol.ProtocolChannel yang dapat dipegang aplikasi. Metode send_event() handle adalah hook sisi cam untuk memberi tahu host "sesuatu terjadi pada channel ini tanpa mengubah data yang dapat dibaca" -- trigger aktif, tombol ditekan, tonggak jumlah sampel tercapai.

12.6.3. Membaca channel dari host

SDK host dikirimkan sebagai paket openmv di PyPI (pip install openmv), dibangun di atas pyserial untuk transport. Kelas openmv.camera.Camera-nya mengekspos channel bernama cam melalui metode tingkat tinggi:

from openmv.camera import Camera

with Camera('/dev/ttyACM0', baudrate=921600) as cam:
    cam.update_channels()
    if cam.has_channel('status'):
        size = cam.channel_size('status')
        data = cam.channel_read('status', size)

Peringatan

Paket openmv memerlukan CPython 3.12 atau lebih baru. Interpreter yang lebih lama tidak memiliki fitur yang bergantung pada SDK; instal build 3.12+ sebelum pip install openmv.

Beberapa hal yang perlu diperhatikan tentang pengaturan:

  • String port serial -- /dev/ttyACM0 di sini -- adalah gaya COM3 di Windows, /dev/cu.usbmodemXXXX di macOS, dan /dev/ttyACM* di Linux. Nomor sebenarnya tergantung pada port mana yang dienumerasi cam.

  • Laju baud adalah nilai ajaib protokol 921600, yang dikenali oleh stack USB-CDC cam sebagai "klien ini berbicara protokol, bukan REPL." Laju lainnya kembali ke saluran serial biasa.

  • Pengelola konteks with Camera(...) as cam: membuka transport, menjalankan PROTO_SYNC, bertukar kemampuan, dan saat keluar menutup port dengan bersih. Panggilan update_channels() eksplisit setelah masuk memperbarui daftar channel lokal dengan channel yang didaftarkan aplikasi setelah boot.

channel_size() dan channel_read() adalah metode utama; channel_write() melakukan round-trip buffer ke cam jika backend memiliki metode write; has_channel() adalah cara aman untuk memeriksa bahwa nama terdaftar sebelum digunakan. Nama channel dicari sekali menjadi ID channel yang ditetapkan cam selama register dan digunakan dalam setiap paket setelahnya.

Setiap pasangan channel_size() / channel_read() membutuhkan dua round-trip: satu paket untuk menanyakan ukurannya, satu untuk menanyakan byte-nya. Melalui USB-CDC keduanya selesai dalam sekitar satu milidetik gabungan; melalui UART pertukaran yang sama memakan waktu lebih lama sebanding dengan laju baud saluran serial. Kode aplikasi yang membaca dalam loop ketat harus memanggil channel_size() hanya ketika ukurannya benar-benar dapat berubah -- untuk data berukuran tetap, ukuran dari panggilan pertama dapat di-cache.

12.6.4. Independensi antar channel

Tiga hal yang perlu diketahui tentang cara channel berinteraksi:

  • Kontrol alur independen. Setiap channel memiliki status pembacaan tertunda sendiri, data sendiri, dan callback size / read / write sendiri. Pembacaan yang berjalan lama pada channel stream tidak memblokir pembacaan pada channel config aplikasi.

  • Berurutan per channel. Dalam satu channel, paket dikirimkan secara berurutan. Lapisan keandalan menjamin ini bahkan ketika retransmit terlibat.

  • Transport bersama, anggaran retransmit bersama. Semua channel berbagi satu tautan fisik, sehingga lonjakan lalu lintas pada satu channel memperlambat yang lain dengan memonopoli kabel. Mekanisme CHANNEL_LOCK memungkinkan satu channel memesan kabel untuk pembacaan multi-paket atomik; backend memilih masuk dengan mengimplementasikan callback lock / unlock.

Channel adalah luas permukaan minimum di mana program host dan program cam setuju untuk bekerja sama. Nama, arah (baca atau tulis atau keduanya), metode callback di sisi cam, dan panggilan metode yang sesuai di sisi host adalah keseluruhan kontrak.