13.3.1.4. Saluran kustom¶
Sebuah saluran adalah aliran byte bidirectional bernama antara skrip sisi kamera dan host. Kamera mendaftarkan saluran dan menyediakan callback yang menghasilkan atau mengonsumsi data; host membaca dari dan menulis ke saluran tersebut berdasarkan nama. Mekanisme yang sama yang digunakan paket secara internal untuk saluran stream yang membawa bingkai, saluran stdout yang membawa output skrip, dan saluran stdin yang membawa unggahan skrip diekspos ke skrip pengguna, sehingga data spesifik aplikasi apa pun yang dibutuhkan host dapat menggunakan koneksi USB yang sama tanpa harus membuat protokol kedua.
Ini adalah fitur paling berguna dari paket ini dan yang paling kurang dicakup dalam dokumentasi standar, sehingga halaman ini membahasnya dari awal hingga akhir.
13.3.1.4.1. Dua bagian¶
Saluran kustom membutuhkan kode yang bekerja sama di kedua sisi. Skrip sisi kamera mengimpor protocol, mendefinisikan kelas dengan tiga metode (size(), read(), poll()) ditambah write() opsional, dan memanggil protocol.register(name=..., backend=...) untuk mempublikasikan saluran dengan nama yang dipilih:
import protocol
import time
class TicksChannel:
def size(self):
return 10
def read(self, offset, size):
return f'{time.ticks_ms():010d}'
def poll(self):
return True
protocol.register(name='ticks', backend=TicksChannel())
Metode size() mengembalikan berapa byte yang saat ini tersedia di saluran. read() adalah produser: diberikan offset dan size yang diminta oleh host, ia mengembalikan byte tersebut (atau string yang dikodekan oleh lapisan protokol). poll() mengembalikan True ketika ada sesuatu untuk dibaca -- lapisan protokol menggunakannya untuk menandai saluran sebagai siap di read_status().
Program sisi host menggunakan empat metode openmv.Camera: has_channel() untuk memeriksa apakah saluran ada, channel_size() untuk menanyakan berapa banyak data yang menunggu, channel_read() untuk menarik byte, dan channel_write() untuk mendorong byte masuk. read_status() melakukan polling pada semua saluran sekaligus:
from openmv import Camera
with Camera('/dev/ttyACM0') as cam:
cam.stop()
cam.exec(open('ticks_cam.py').read())
while True:
status = cam.read_status()
if status.get('ticks'):
data = cam.channel_read('ticks')
print(f"ticks: {data.decode()}")
Loop host melakukan polling pada read_status(); ketika saluran ticks siap, ia memanggil channel_read() tanpa size untuk menarik apa pun yang tersedia. TicksChannel.poll() milik kamera mengembalikan True pada setiap pemeriksaan, sehingga saluran selalu "siap" dan host mendapatkan nilai tick baru setiap polling.
13.3.1.4.2. Saluran bidirectional¶
Untuk host yang perlu mendorong data balik, kelas sisi kamera menambahkan metode write() yang menerima byte yang masuk:
import protocol
class CommandChannel:
def __init__(self):
self.last_command = b''
self.replied = False
def size(self):
return len(self.last_command)
def read(self, offset, size):
self.replied = True
return self.last_command
def write(self, offset, data):
self.last_command = b'echo: ' + bytes(data)
self.replied = False
def poll(self):
return not self.replied and len(self.last_command) > 0
protocol.register(name='echo', backend=CommandChannel())
Host menulis ke saluran dengan channel_write() dan membaca balasan kembali melalui pola read_status() / channel_read() yang biasa:
with Camera('/dev/ttyACM0') as cam:
cam.stop()
cam.exec(open('echo_cam.py').read())
cam.channel_write('echo', b'hello')
while True:
if cam.read_status().get('echo'):
print(cam.channel_read('echo').decode())
break
13.3.1.4.3. Apa yang diperoleh aplikasi¶
Saluran kustom adalah alat yang tepat setiap kali aplikasi ingin menggunakan koneksi USB yang ada untuk data non-bingkai dan non-cetak: penghitung telemetri, tombol konfigurasi yang dialirkan langsung dari UI di host, perintah kontrol yang dikirimkan ke arah lain, hasil pengukuran yang dihitung kamera yang tidak sesuai dengan framing "citra" yang diasumsikan oleh saluran stream. Lapisan protokol menangani framing, fragmentasi, pengakuan, dan percobaan ulang; skrip hanya perlu mengimplementasikan backend empat-metode, dan host hanya perlu mengetahui nama saluran dan bentuk data.
Flag --channel NAME CLI adalah cara cepat untuk memverifikasi saluran kustom dari terminal tanpa menulis program sisi host: CLI melakukan polling pada saluran yang dinamai dan mencetak sepuluh byte pertama dari setiap pembaruan.
Batas ukuran pada satu panggilan channel_read() atau channel_write() adalah max_payload yang dinegosiasikan protokol -- 4096 byte secara default. Metode sisi host secara otomatis membagi penulisan yang lebih besar menjadi jumlah paket yang tepat, sehingga aplikasi dapat meneruskan buffer berukuran sembarang; fragmentasinya tidak terlihat.