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.