13.3.1.4. Egyéni csatornák¶
A csatorna egy elnevezett, kétirányú bájtfolyam egy kameraoldali szkript és a gazdagép között. A kamera regisztrál egy csatornát, és visszahívásokat biztosít, amelyek adatot állítanak elő vagy fogyasztanak; a gazdagép név szerint olvas erről a csatornáról és ír rá. Ugyanazt a mechanizmust, amelyet a csomag belsőleg a képkockákat hordozó stream csatornához, a szkriptkimenetet hordozó stdout csatornához és a szkriptfeltöltést hordozó stdin csatornához használ, a felhasználói szkriptek számára is elérhetővé teszi, így bármilyen alkalmazásspecifikus adat, amelyre a gazdagépnek szüksége van, ugyanazon az USB-kapcsolaton utazhat, anélkül, hogy egy második protokollt kellene kitalálni.
Ez a csomag leghasznosabb funkciója, és az, amelyet a szabványos dokumentáció a legkevésbé jól ismertet, így ez az oldal végigvezet rajta végponttól végpontig.
13.3.1.4.1. A két fél¶
Egy egyéni csatornához mindkét oldalon együttműködő kódra van szükség. A kameraoldali szkript importálja a protocol modult, definiál egy három metódust (size(), read(), poll()) tartalmazó osztályt egy opcionális write() metódussal kiegészítve, és meghívja a protocol.register(name=..., backend=...) függvényt, hogy a csatornát egy választott néven közzétegye:
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())
A size() metódus visszaadja, hány bájt érhető el jelenleg a csatornán. A read() a termelő: a gazdagép által kért offset és size alapján visszaadja a bájtokat (vagy egy karakterláncot, amelyet a protokollréteg kódol). A poll() True értéket ad vissza, ha van olvasnivaló – a protokollréteg ezt használja arra, hogy a csatornát készként jelölje a read_status() metódusban.
A gazdaoldali program négy openmv.Camera metódust használ: a has_channel() metódust a csatorna létezésének ellenőrzéséhez, a channel_size() metódust annak megkérdezéséhez, mennyi adat várakozik, a channel_read() metódust a bájtok kihúzásához, és a channel_write() metódust a bájtok betolásához. A read_status() egyszerre kérdezi le az összes csatornát:
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()}")
A gazdaciklus lekérdezi a read_status() metódust; amikor a ticks csatorna készen áll, meghívja a channel_read() metódust size nélkül, hogy kihúzza, ami éppen elérhető. A kamera TicksChannel.poll() metódusa minden ellenőrzéskor True értéket ad vissza, így a csatorna mindig „kész”, és a gazdagép minden lekérdezéskor friss tick-értéket kap.
13.3.1.4.2. Kétirányú csatorna¶
Egy olyan gazdagéphez, amelynek adatot kell visszatolnia, a kameraoldali osztály egy write() metódust ad hozzá, amely fogadja a bejövő bájtokat:
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())
A gazdagép a channel_write() metódussal ír a csatornára, és a választ a szokásos read_status() / channel_read() mintán keresztül olvassa vissza:
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 nyer ezzel az alkalmazás¶
Az egyéni csatornák a megfelelő eszköz, amikor egy alkalmazás a meglévő USB-kapcsolatot szeretné felhasználni nem képkocka és nem kiírás jellegű adatokhoz: telemetriaszámlálók, a gazdagépen lévő felületről élőben streamelt konfigurációs gombok, a másik irányba küldött vezérlőparancsok, vagy a kamera által kiszámított mérés eredményei, amelyek nem férnek bele a „kép” keretezésbe, amelyet a stream csatorna feltételez. A protokollréteg kezeli a keretezést, a darabolást, a visszaigazolást és az újrapróbálkozást; a szkriptnek csak a négymetódusos backendet kell megvalósítania, a gazdagépnek pedig csak a csatorna nevét és az adat alakját kell ismernie.
A CLI --channel NAME kapcsolója gyors módja egy egyéni csatorna ellenőrzésének a terminálból, gazdaoldali program írása nélkül: a CLI lekérdezi a megnevezett csatornát, és minden frissítés első tíz bájtját kiírja.
Egyetlen channel_read() vagy channel_write() hívás méretkorlátja a protokoll által kialkudott max_payload – alapértelmezés szerint 4096 bájt. A gazdaoldali metódusok automatikusan a megfelelő számú csomagra osztják a nagyobb írásokat, így az alkalmazás tetszőlegesen nagy puffereket adhat át; a darabolás láthatatlan.