13.3.1.4. Mukautetut kanavat¶
Kanava on nimetty, kaksisuuntainen tavuvirta kameran skriptin ja isännän välillä. Kamera rekisteröi kanavan ja tarjoaa takaisinkutsut, jotka tuottavat tai kuluttavat dataa; isäntä lukee ja kirjoittaa kyseiseen kanavaan nimellä. Sama mekanismi, jota paketti käyttää sisäisesti kehyksiä kuljettavalle stream-kanavalle, skriptin tulostetta kuljettavalle stdout-kanavalle ja skriptin latausta kuljettavalle stdin-kanavalle, on käyttäjäskriptien käytettävissä, joten mikä tahansa sovelluskohtainen data, jota isäntä tarvitsee, voi kulkea samalla USB-yhteydellä ilman toisen protokollan keksimistä.
Tämä on paketin hyödyllisin ominaisuus ja se, jonka vakiodokumentaatio kattaa heikoimmin, joten tämä sivu käy sen läpi alusta loppuun.
13.3.1.4.1. Kaksi puoliskoa¶
Mukautettu kanava tarvitsee yhteistyössä toimivaa koodia molemmilla puolilla. Kameran skripti tuo protocol, määrittelee luokan, jossa on kolme metodia (size(), read(), poll()) sekä valinnainen write(), ja kutsuu protocol.register(name=..., backend=...) julkaistakseen kanavan valitulla nimellä:
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())
size()-metodi palauttaa, kuinka monta tavua kanavalla on tällä hetkellä saatavilla. read() on tuottaja: isännän pyytämällä offset- ja size-arvolla se palauttaa tavut (tai merkkijonon, jonka protokollakerros koodaa). poll() palauttaa True, kun luettavaa on – protokollakerros käyttää tätä merkitäkseen kanavan valmiiksi metodissa read_status().
Isäntäohjelma käyttää neljää openmv.Camera-metodia: has_channel() tarkistaakseen kanavan olemassaolon, channel_size() kysyäkseen, kuinka paljon dataa odottaa, channel_read() vetääkseen tavuja ulos ja channel_write() työntääkseen tavuja sisään. read_status() kyselee jokaista kanavaa kerralla:
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()}")
Isäntäsilmukka kyselee read_status(); kun ticks-kanava on valmis, se kutsuu channel_read() ilman size-arvoa vetääkseen kaiken saatavilla olevan. Kameran TicksChannel.poll() palauttaa True jokaisella tarkistuksella, joten kanava on aina ”valmis” ja isäntä saa tuoreen tick-arvon jokaisella kyselyllä.
13.3.1.4.2. Kaksisuuntainen kanava¶
Isännälle, jonka täytyy työntää dataa takaisin, kameran luokka lisää write()-metodin, joka ottaa vastaan saapuvat tavut:
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())
Isäntä kirjoittaa kanavaan kutsulla channel_write() ja lukee vastauksen takaisin tavanomaisella read_status() / channel_read() -mallilla:
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. Mitä tämä antaa sovellukselle¶
Mukautetut kanavat ovat oikea työkalu aina, kun sovellus haluaa hyödyntää olemassa olevaa USB-yhteyttä muulle kuin kehys- tai tulostedatalle: telemetrialaskurit, käyttöliittymästä isännällä reaaliajassa suoratoistetut konfiguraationupit, toiseen suuntaan lähetetyt ohjauskomennot, tulokset kameran laskemasta mittauksesta, joka ei sovi stream-kanavan olettamaan ”kuva”-kehystykseen. Protokollakerros hoitaa kehystyksen, fragmentoinnin, kuittauksen ja uudelleenyrityksen; skriptin tarvitsee vain toteuttaa nelimetodinen taustajärjestelmä, ja isännän tarvitsee vain tietää kanavan nimi ja datan muoto.
Komentorivityökalun --channel NAME -lippu on nopea tapa todentaa mukautettu kanava terminaalista ilman isäntäohjelman kirjoittamista: komentorivityökalu kyselee nimettyä kanavaa ja tulostaa jokaisen päivityksen ensimmäiset kymmenen tavua.
Yksittäisen channel_read()- tai channel_write()-kutsun kokoraja on protokollan neuvottelema max_payload – oletuksena 4096 tavua. Isäntäpuolen metodit jakavat automaattisesti suuremmat kirjoitukset oikeaan määrään paketteja, joten sovellus voi välittää mielivaltaisen suuria puskureita; fragmentointi on näkymätöntä.