12.7. Csatorna-visszahívások

A protocol.register() függvénynek átadott backend objektum egy Python osztály. A protokollkönyvtár nem kérdezi meg az osztálytól, hogy mely metódusokat valósítja meg; megvizsgálja a példányt, és bedrótozza azokat, amelyeket megtalál. Ez az introspekció teszi rugalmassá a backend felületet: a legkisebb hasznos backend két metódusból áll, a legkidolgozottabb tizenkettőből, és az alkalmazás metódusonként, egyesével iratkozik fel az egyes képességekre.

12.7.1. Az introspekciós szabályok

Amikor a protocol.register() lefut, a könyvtár végigjárja a hívható nevek rögzített listáját, és mindegyiket hozzákapcsolja, amelyet megtalál a backend példányon:

  • A read hozzáadása az osztályhoz bekapcsolja a CHANNEL_FLAG_READ jelzőt. A channel_read() gazdagéphívás csak akkor jut el a backendhez, ha ez a jelző be van állítva.

  • A write hozzáadása bekapcsolja a CHANNEL_FLAG_WRITE jelzőt, lehetővé téve a channel_write() használatát.

  • A lock és unlock hozzáadása bekapcsolja a CHANNEL_FLAG_LOCK jelzőt, lehetővé téve a gazdagép számára, hogy zárolja a csatornát egy több csomagból álló atomi olvasáshoz.

  • A poll hozzáadása lehetővé teszi a gazdagép számára, hogy olcsón megkérdezze: „van valami készen?”, anélkül hogy teljes olvasásra kényszerülne.

A hiányzó metódusok nem hibák – a protokollkönyvtár egyszerűen letiltva hagyja a megfelelő képességet. Egy olyan backend, amelynek csak size és read metódusa van, teljesen érvényes; ez egy csak olvasható adatcsatorna.

12.7.2. Egy csak olvasható érzékelőcsatorna

Egy olyan érzékelőcsatorna, amely minden gazdagéphívásra friss mérést tesz közzé, és elutasítja a gazdagép írásait, négyet használ a visszahívások közül:

import protocol
import struct

class TempChannel:
    def __init__(self, read_sensor):
        self._read_sensor = read_sensor
        self._buf = b''
        self._fresh = False

    def poll(self):
        # Tell the host whether a reading is waiting.
        return self._fresh

    def size(self):
        # Sample fresh data on every host-side size query.
        value = self._read_sensor()
        self._buf = struct.pack('<f', value)
        self._fresh = True
        return len(self._buf)

    def read(self, offset, size):
        end = offset + size
        if end >= len(self._buf):
            self._fresh = False
        return self._buf[offset:end]

protocol.register(name='temp', backend=TempChannel(read_temperature))

Végigvezetve azon, hogy mit csinál az egyes metódusok:

  • A poll visszaadja a frissesség jelzőt. A gazdagép olvasás előtt hívja meg, és teljesen kihagyja az olvasást, amikor False értéket ad vissza. Ez megspórolja az oda-vissza út költségét a „még nincs új adat” esetében.

  • A size igény szerint újragenerálja a puffert, és jelenti annak hosszát. A mintavételezés itteni elvégzése azt jelenti, hogy a backendnek nincs szüksége háttérfeladatra – minden mérést egy gazdagéphívás vezérel.

  • A read a puffer egy szeletét adja vissza. A protokollkönyvtár többször is meghívhatja, ha a puffer nagyobb a tárgyalt maximális hasznos terhelésnél; az offset argumentum végigjárja a töredékeket.

  • A write hiánya azt jelenti, hogy a gazdagép írásai a keretezési rétegben elutasításra kerülnek, még mielőtt a backend bevonódna.

12.7.3. A teljes visszahívás-készlet

Referenciaként minden metódus, amelyet a könyvtár keres egy backenden:

Metódus

Visszaadott érték

Cél

init(self)

object

Opcionális egyszeri inicializálás, amikor a csatorna először kapcsolódik egy gazdagéphez. Sikeres esetén adjon vissza bármilyen nem None értéket.

poll(self)

bool

Adjon vissza True értéket, ha adat áll rendelkezésre.

lock(self)

bool

Lefoglalja a csatornát egy atomi, több csomagból álló átvitelhez.

unlock(self)

bool

Felold egy korábbi lock zárolást.

size(self)

int

A csatornából jelenleg olvasható bájtok száma.

shape(self)

tuple

Legfeljebb négy egész szám, amely leírja az adatstruktúrát (pl. képmagasság, szélesség, bájtszám). A gazdagép használja a típusos pufferek kibontásához.

read(self, offset, size)

bytes

Legfeljebb size bájtot ad vissza offset pozíciótól kezdve. Töredékenként egyszer hívódik meg, ha a hasznos terhelés meghaladja a tárgyalt maximumot.

readp(self, offset, size)

bytes

A read másolásmentes változata: a puffer memóriájának érvényesnek kell maradnia az átvitel teljes időtartama alatt.

write(self, offset, data)

int

A gazdagép data adatot írt offset pozícióra. A data egy bytearray nézet a protokollréteg fogadási pufferébe – másolja ki azt, amit meg szeretne tartani, mielőtt visszatér.

ioctl(self, cmd, length, arg)

int

Az olvasás/írás modellen kívüli, alkalmazás által definiált opkód. A negatív visszatérési érték hibát jelez.

flush(self)

object

Eldobja a pufferelt adatokat. Akkor hívódik meg, amikor a gazdagép vissza akarja állítani a csatornát.

is_active(self)

bool

Csak olyan backendeken értelmes, amelyek fizikai átvitelt képviselnek (a beépített USB-csatornák). Az alkalmazáscsatornáknak nincs erre szükségük.

Ez a teljes backend felület. Tizenkét metódusnév, mind opcionális, és a protokollkönyvtár az alapján dönti el, hogy az egyes csatornák mit tehetnek, hogy melyek vannak jelen.