13.3.1.4. Aangepaste kanalen¶
Een kanaal is een benoemde, bidirectionele bytestroom tussen een cam-zijdig script en de host. De cam registreert een kanaal en levert callbacks die data produceren of consumeren; de host leest van en schrijft naar dat kanaal op naam. Hetzelfde mechanisme dat het pakket intern gebruikt voor het stream kanaal dat frames draagt, het stdout kanaal dat scriptuitvoer draagt en het stdin kanaal dat de scriptupload draagt, wordt blootgesteld aan gebruikersscripts, zodat alle applicatiespecifieke data die de host nodig heeft over dezelfde USB-verbinding kan meeliften zonder een tweede protocol uit te vinden.
Dit is de nuttigste functie van het pakket en degene die de standaarddocumentatie het slechtst behandelt, dus deze pagina werkt het van begin tot eind door.
13.3.1.4.1. De twee helften¶
Een aangepast kanaal heeft samenwerkende code aan beide kanten nodig. Het cam-zijdige script importeert protocol, definieert een klasse met drie methoden (size(), read(), poll()) plus een optionele write(), en roept protocol.register(name=..., backend=...) aan om het kanaal onder een gekozen naam te publiceren:
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())
De size() methode geeft terug hoeveel bytes het kanaal momenteel beschikbaar heeft. read() is de producent: gegeven een offset en size die door de host worden gevraagd, geeft het de bytes terug (of een string die de protocollaag codeert). poll() geeft True terug wanneer er iets te lezen valt – de protocollaag gebruikt dit om het kanaal als gereed te markeren in read_status().
Het host-zijdige programma gebruikt vier openmv.Camera methoden: has_channel() om te controleren of het kanaal bestaat, channel_size() om te vragen hoeveel data er wacht, channel_read() om bytes eruit te halen, en channel_write() om bytes erin te duwen. read_status() peilt elk kanaal tegelijk:
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()}")
De hostlus peilt read_status(); wanneer het ticks kanaal gereed is, roept het channel_read() aan zonder size om op te halen wat er beschikbaar is. De TicksChannel.poll() van de cam geeft bij elke controle True terug, dus het kanaal is altijd “gereed” en de host krijgt bij elke peiling een verse tickwaarde.
13.3.1.4.2. Een bidirectioneel kanaal¶
Voor een host die data terug moet duwen, voegt de cam-zijdige klasse een write() methode toe die de inkomende bytes accepteert:
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())
De host schrijft naar het kanaal met channel_write() en leest het antwoord terug via het gebruikelijke read_status() / channel_read() patroon:
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. Wat dit de applicatie oplevert¶
Aangepaste kanalen zijn het juiste hulpmiddel wanneer een applicatie de bestaande USB-verbinding wil gebruiken voor niet-frame-, niet-printdata: telemetrietellers, configuratieknoppen die live vanaf een UI op de host worden gestreamd, besturingscommando’s die de andere kant op worden gestuurd, resultaten van een meting die de cam heeft berekend en die niet passen in het “image”-frame dat het stream-kanaal veronderstelt. De protocollaag handelt het framen, fragmenteren, bevestigen en opnieuw proberen af; het script hoeft alleen de vier-methoden-backend te implementeren, en de host hoeft alleen de kanaalnaam en de datavorm te kennen.
De --channel NAME vlag van de CLI is een snelle manier om een aangepast kanaal vanuit de terminal te verifiëren zonder een host-zijdig programma te schrijven: de CLI peilt het benoemde kanaal en drukt de eerste tien bytes van elke update af.
De groottelimiet voor een enkele channel_read() of channel_write() aanroep is de onderhandelde max_payload van het protocol – standaard 4096 bytes. De host-zijdige methoden splitsen grotere schrijfbewerkingen automatisch op in het juiste aantal pakketten, zodat de applicatie willekeurig grote buffers kan doorgeven; de fragmentatie is onzichtbaar.