12.7. Channel callbacks#
Het backend-object dat aan protocol.register() wordt doorgegeven, is een Python-klasse. De protocolbibliotheek vraagt de klasse niet welke methoden ze implementeert; ze inspecteert de instantie en koppelt de methoden die ze aantreft. Die introspectie is wat de backend-interface flexibel maakt: de kleinste bruikbare backend bestaat uit twee methoden, de meest uitgebreide uit twaalf, en de applicatie kiest per methode één voor één voor elke mogelijkheid.
12.7.1. De introspectieregels#
Wanneer protocol.register() wordt uitgevoerd, loopt de bibliotheek een vaste lijst met aanroepbare namen af en bindt elke naam die ze op de backend-instantie aantreft:
Het toevoegen van
readaan de klasse zetCHANNEL_FLAG_READaan. Een host-aanroep vanchannel_read()bereikt de backend alleen als deze vlag is ingesteld.Het toevoegen van
writezetCHANNEL_FLAG_WRITEaan en maaktchannel_write()mogelijk.Het toevoegen van
lockenunlockzetCHANNEL_FLAG_LOCKaan, waardoor de host het channel kan vergrendelen voor een atomaire lees-actie over meerdere pakketten.Het toevoegen van
polllaat de host goedkoop vragen “is er iets klaar?”, zonder een volledige lees-actie af te dwingen.
Ontbrekende methoden zijn geen fouten – de protocolbibliotheek laat de bijbehorende mogelijkheid simpelweg uitgeschakeld. Een backend met alleen size en read is volkomen geldig; het is een alleen-lezen datachannel.
12.7.2. Een alleen-lezen sensor-channel#
Een sensor-channel dat elke keer dat de host erom vraagt een verse meting publiceert en host-schrijfacties weigert, gebruikt vier van de callbacks:
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))
Wat elke methode doet, stap voor stap:
pollretourneert de versheidsvlag. De host roept deze aan vóór het lezen en slaat de lees-actie helemaal over wanneer zeFalseretourneert. Dat bespaart de heen-en-weerkosten voor “nog geen nieuwe data.”sizegenereert de buffer op verzoek opnieuw en rapporteert de lengte ervan. Door hier de bemonstering te doen, heeft de backend geen achtergrondtaak nodig – elke host-aanroep stuurt elke meting aan.readretourneert een deel van de buffer. De protocolbibliotheek kan deze meer dan eens aanroepen wanneer de buffer groter is dan de onderhandelde maximale payload; het argumentoffsetloopt door de fragmenten heen.Geen
writebetekent dat host-schrijfacties worden geweigerd in de framinglaag, voordat de backend erbij betrokken wordt.
12.7.3. De volledige set callbacks#
Ter referentie, elke methode waar de bibliotheek naar zoekt op een backend:
Methode | Retourneert | Doel |
|---|---|---|
| object | Optionele eenmalige initialisatie wanneer het channel voor het eerst aan een host wordt gebonden. Retourneer bij succes een willekeurige waarde die niet |
| bool | Retourneer |
| bool | Reserveer het channel voor een atomaire overdracht over meerdere pakketten. |
| bool | Geef een eerdere |
| int | Aantal bytes dat momenteel uit het channel kan worden gelezen. |
| tuple | Tot vier gehele getallen die de datastructuur beschrijven (bijv. hoogte van de afbeelding, breedte, aantal bytes). Wordt door de host gebruikt om getypeerde buffers uit te pakken. |
| bytes | Retourneer tot size bytes vanaf offset. Wordt eenmaal per fragment aangeroepen wanneer de payload de onderhandelde maximumwaarde overschrijdt. |
| bytes | Zero-copy-variant van |
| int | De host heeft data geschreven op offset. |
| int | Door de applicatie gedefinieerde opcode buiten het lees-/schrijfmodel. Een negatieve retourwaarde is een fout. |
| object | Verwijder alle gebufferde data. Wordt aangeroepen wanneer de host het channel wil resetten. |
| bool | Alleen zinvol op backends die een fysiek transport vertegenwoordigen (de ingebouwde USB-channels). Applicatie-channels hebben dit niet nodig. |
Dat is de volledige backend-interface. Twaalf methodenamen, allemaal optioneel, en de protocolbibliotheek bepaalt op basis van welke aanwezig zijn wat elk channel kan doen.