12.9. Kétirányú adatáramlás¶
A csatornák nem egyirányúak. Egy write metódust megvalósító backend lehetővé teszi, hogy a gazdagép bájtokat küldjön a kamera felé, és a kamera reagáljon. Ez a minta áll minden valódi interaktív eszköz mögött: a kezelő elforgat egy gombot a gazdagép grafikus felületén, a gazdagép az új értéket egy konfigurációs csatornára írja, a kamera pedig a következő rögzítéskor beolvassa.
12.9.1. Egy konfigurációs csatorna¶
A streamelő kamera-oldali szkriptet kiegészítve tegyél elérhetővé egy második csatornát a JPEG-minőséghez:
class ConfigChannel:
def __init__(self):
self.quality = 85
def size(self):
return 0
def read(self, offset, size):
# Not used for "host writes to cam" -- but the library
# still needs the method present.
return b''
def write(self, offset, data):
# data is a bytearray view into the protocol buffer.
# Copy out the contents before doing anything with it.
new_q = int(bytes(data))
if 1 <= new_q <= 100:
self.quality = new_q
return len(data)
config = ConfigChannel()
protocol.register(name='config', backend=config)
A rögzítési ciklus a config.quality értékről olvas minden alkalommal, amikor egy képkockát tömörít:
while True:
img = csi0.snapshot()
latest_jpeg = bytes(
img.compress(quality=config.quality).bytearray()
)
ch.send_event(0x01)
A gazdagépnek immár van egy gombja. Állítsd 50-re, és a következő képkocka kisebb (és csúnyább) lesz; állítsd 95-re, és a következő képkocka nagyobb (és élesebb) lesz. A kamera újraindítás nélkül folytatja a rögzítést; a gazdagépnek nem kell új szkriptet feltöltenie.
12.9.2. Az írási hívás a gazdagép felől¶
A gazdagép oldalán a channel_write() bájtokat küld egy megnevezett csatornára:
cam.channel_write('config', b'50')
A gazda-SDK a bájtokat egyetlen (vagy fragmentált) CHANNEL_WRITE csomagként kódolja, a protokollréteg kézbesíti a kamerának, lefut a kamera write(offset=0, data=...) hívása, és a kamera oldala visszaigazol. Mire a hívás visszatér, a kamera megkapta és elfogadta az új értéket.
Az írás a kamera szemszögéből atomi – a protokollkönyvtár garantálja, hogy a backend write metódusa teljesen lefut, mielőtt bármely más művelet folytatódna azon a csatornán. Az alkalmazáskód a rögzítési cikluson belülről olvashatja a config.quality értéket anélkül, hogy aggódnia kellene amiatt, hogy a gazdagép pillanatkép közben beletapos.
12.9.3. Csonk méret és olvasás egy csak írható csatornán¶
Egy tisztán írható csatornának is szüksége van a size és a read definícióira, még akkor is, ha ezek 0-t és b''-t visszaadó csonkok. A könyvtár a metódusok jelenléte alapján vezeti le a csatorna képességjelzőit; egy read nélküli backendnél nem lesz beállítva a CHANNEL_FLAG_READ, és a gazdagép elutasít minden olvasási kísérletet.
A csak írható csatornán a read-ből visszaadott bájtok azonban más célra hasznosak: a jelenlegi érték visszatükrözésére, hogy egy éppen csatlakozott gazdagép megkérdezhesse a kamerától, „mi az aktuális beállítás?”, ahelyett, hogy egy alapértelmezésből indulna ki. Hogy ez működjön, mindkét iránynak meg kell egyeznie egy szerializálásban. A korábbi példában szereplő nyers bájtos int(bytes(data)) elemzés egyetlen egész mező esetén működik, de nem skálázódik, amint van egy második beállítandó gomb. Ha a write metódust átállítod JSON elemzésére, és párosítod egy olyan read metódussal, amely az ennek megfelelő JSON-kiírást adja vissza, a csatorna valódi, oda-vissza működő konfigurációs tárrá válik:
import json
class ConfigChannel:
def __init__(self):
self.quality = 85
self._buf = b''
def size(self):
self._buf = json.dumps({'quality': self.quality}).encode()
return len(self._buf)
def read(self, offset, size):
return self._buf[offset:offset + size]
def write(self, offset, data):
new = json.loads(bytes(data))
if 'quality' in new:
self.quality = int(new['quality'])
return len(data)
A gazdagép immár a cam.channel_write('config', b'{"quality": 50}') hívással állít be egy értéket, és a cam.channel_read('config') hívással olvassa vissza az aktuális állapotot. A kamera minden olvasáskor friss JSON-kiírást szerializál, így a gazdagép mindig a legutóbbi értékeket látja, és egy újabb gomb hozzáadása (threshold, exposure, orientation) mindkét oldalon egyetlen sor a JSON-szótárban.
12.9.4. Egy teljes ciklus¶
Egy képkocka-csatornával a kamera → gazdagép adatokhoz, egy konfigurációs csatornával a gazdagép → kamera vezérléshez, és egy kevés összekötő kóddal az alkalmazás interaktív eszközzé válik:
A gazdagép megnyitja a kamerát, elkezdi lehúzni a képkockákat, és egy ablakban megjeleníti őket.
Amikor a kezelő elhúz egy csúszkát, a gazdagép az új értéket a
configcsatornára írja.A kamera rögzítési ciklusa a következő képkockánál veszi át az értéket.
Az új képkockák ugyanazon a
framecsatornán keresztül áramlanak.
Ez az egész modell. Két csatorna, mindegyiken két visszahívás, egy rögzítési ciklus a kamerán, egy olvasó-és-író ciklus a gazdagépen. Semmilyen látható keretezési logika, semmilyen látható hibakezelés – a protokollkönyvtár eltünteti a megbízható bájtmozgatást.
Ezen a ponton túl minden alkalmazáskód. Egy harmadik csatorna hozzáadása egy hisztogramhoz, egy negyediké telemetriához, vagy egy ötödiké érzékelő-triggerekhez ugyanaz a backend-osztály-és-protocol.register recept, megismételve. Amint egy kameraprojekt eléri ezt a pontot, a protokoll megszűnik az érdekes probléma lenni; az alkalmazás saját logikája veszi át a helyét.