12.6. Namngivna kanaler¶
Kanal-ID:t i varje pakets header gör att upp till 32 oberoende strömmar kan dela samma fysiska transport. Kanallagret omvandlar de numeriska ID:na till namngivna, applikationssynliga slutpunkter som värdkoden kan referera till med en sträng.
12.6.1. De fyra inbyggda kanalerna¶
Kameran registrerar fyra kanaler vid uppstart, innan någon applikationskod körs:
stdin– skriptbyte som värden skickar till kameran för att köras. IDE:n använder denna kanal för att skicka skriptet som redigeras;exec()på värd-SDK:n är motsvarande anrop från ett Python-program.stdout– byte frånprint()-anrop på kameran och spårningar för oavfångade undantag. IDE:ns seriekonsol läser denna kanal.stream– kanalen för direktförhandsvisning. IDE:n hämtar JPEG-bildrutor från den; vilket värdskript som helst kan göra detsamma medread_frame().profile– profilerarhändelser, närvarande endast när kameran byggdes med profilering aktiverad. De flesta utgåvebyggen utelämnar den.
Applikationskod behöver sällan röra någon av de inbyggda; det intressanta arbetet sker på kanaler som applikationen själv registrerar.
12.6.2. Registrera en kanal¶
Ett skript på kamerasidan registrerar en ny kanal genom att anropa protocol.register() med ett namn och ett Python-backend-objekt:
import json
import protocol
import time
trigger_count = 0
class StatusChannel:
def size(self):
# Refresh the snapshot on every host query.
self._buf = json.dumps({
'uptime_s': time.ticks_ms() // 1000,
'triggers': trigger_count,
}).encode()
return len(self._buf)
def read(self, offset, size):
return self._buf[offset:offset + size]
protocol.register(name='status', backend=StatusChannel())
Backend-objektets metoder avgör vad kanalen kan göra. En backend med endast size och read är en skrivskyddad datakanal; lägg till write så blir den dubbelriktad; lägg till poll så kan värden fråga om ny data är klar innan en läsning betalas. Att sampla data inuti size är det enklaste mönstret när nyttolasten är liten nog att rymmas i ett fragment – bufferten genereras vid behov, cachas aldrig, drabbas aldrig av kapplöpning. Större nyttolaster – bildrutor, sensorspår – behöver ett spärrmönster som håller kvar bufferten tills värden avslutar sin flerfragmentläsning, vilket behandlas i avsnittet om bildruterkanalen.
En liten mängd bokföring sker automatiskt:
Biblioteket tilldelar nästa lediga kanal-ID (mellan 0 och 31).
Förmågeflaggorna härleds från de metoder som finns:
CHANNEL_FLAG_READomreadär definierad,CHANNEL_FLAG_WRITEomwriteär definierad,CHANNEL_FLAG_LOCKomlock/unlockär definierade.Ett
CHANNEL_REGISTERED-händelsepaket skickas till varje ansluten värd så att dess kanallista uppdateras.
Returvärdet är ett protocol.ProtocolChannel-handtag som applikationen kan behålla. Handtagets metod send_event() är kamerasidans krok för att tala om för värden att ”något hände på denna kanal utan att den läsbara datan ändrades” – en trigger utlöstes, en knapp trycktes ned, en milstolpe i antal sampel passerades.
12.6.3. Läsa kanaler från värden¶
Värd-SDK:n levereras som paketet openmv på PyPI (pip install openmv), byggt på pyserial för transporten. Dess klass openmv.camera.Camera exponerar kamerans namngivna kanaler genom högnivåmetoder:
from openmv.camera import Camera
with Camera('/dev/ttyACM0', baudrate=921600) as cam:
cam.update_channels()
if cam.has_channel('status'):
size = cam.channel_size('status')
data = cam.channel_read('status', size)
Varning
Paketet openmv kräver CPython 3.12 eller senare. Tidigare tolkar saknar funktioner som SDK:n är beroende av; installera ett 3.12+-bygge innan pip install openmv.
Några saker att lägga märke till om uppsättningen:
Serieportssträngen –
/dev/ttyACM0här – är iCOM3-stil på Windows,/dev/cu.usbmodemXXXXpå macOS och/dev/ttyACM*på Linux. Det faktiska numret beror på vilken port kameran räknades upp som.Baudhastigheten är protokollets magiska värde
921600, som kamerans USB-CDC-stack känner igen som ”den här klienten talar protokollet, inte REPL:en”. Vilken annan hastighet som helst faller tillbaka på en vanlig seriell linje.Kontexthanteraren
with Camera(...) as cam:öppnar transporten, körPROTO_SYNC, utbyter förmågor och stänger porten rent vid avslut. Det explicita anropetupdate_channels()efter inträde uppdaterar den lokala kanallistan med eventuella kanaler som applikationen registrerade efter uppstart.
channel_size() och channel_read() är arbetshästmetoderna; channel_write() skickar en buffert tur och retur till kameran om backenden har en write-metod; has_channel() är det säkra sättet att kontrollera att ett namn är registrerat innan det används. Kanalnamnet slås upp en gång till det kanal-ID som kameran tilldelade under register och används i varje paket från och med då.
Varje par av channel_size() / channel_read() kostar två tur-och-retur-resor: ett paket för att fråga efter storleken, ett för att fråga efter byten. Över USB-CDC avslutas båda på cirka en millisekund tillsammans; över UART tar samma utbyte längre tid i proportion till den seriella linjens baudhastighet. Applikationskod som läser i en tät slinga bör anropa channel_size() endast när storleken faktiskt kan ändras – för data av fast storlek kan storleken från det första anropet cachas.
12.6.4. Oberoende mellan kanaler¶
Tre saker är värda att veta om hur kanaler samverkar:
Oberoende flödeskontroll. Varje kanal har sitt eget tillstånd för väntande läsning, sin egen data och sina egna återanrop
size/read/write. En långvarig läsning på kanalenstreamblockerar inte läsningar på applikationensconfig-kanal.Sekventiellt per kanal. Inom en enda kanal levereras paket i ordning. Tillförlitlighetslagret garanterar detta även när omsändningar är inblandade.
Delad transport, delad budget för omsändning. Alla kanaler delar den enda fysiska länken, så en störtflod av trafik på en kanal saktar ned de andra genom att lägga beslag på tråden. Mekanismen
CHANNEL_LOCKlåter en kanal reservera tråden för en atomär flerpaketsläsning; backenden ansluter sig genom att implementera återanropenlock/unlock.
En kanal är den minsta gränsyta på vilken ett värdprogram och ett kameraprogram kommer överens om att samverka. Namnet, riktningen (läsa eller skriva eller båda), återanropsmetoderna på kamerasidan och de matchande metodanropen på värdsidan är hela kontraktet.