# Komunikace, ovladače a kanály

## Jak kanály pracují?

Aplikace systému Control Web používá název kanály pro datové elementy (o datových elementech se dočtete v kapitole Datové elementy a výrazy, které mají vztah k reálným snímačům nebo řídicím prvkům. Podle takto definovaného směru (je-li kanál připojen na snímač nebo řídicí prvek) se rozlišují kanály vstupní (určené k měření) a výstupní (určené k zápisu dat do technologie).

Vstupní kanály primárně existují v technologii a aplikace používá jen jejich obraz. Výstupní kanály naopak "vznikají" v aplikaci a technologie, která data z výstupních kanálů používá, pracuje závisle. Aby byla zaručena vzájemná koherence hodnot v technologii a aplikaci, musejí být kanály přenášeny — komunikovány jednou do aplikace a jednou do technologie. Směr, jakým jsou kanály komunikovány, je důležitý pro základní obsluhu komunikace — vstupní kanál je v aplikaci pouhým obrazem a jeho měření proto musí řízeně sledovat, jak a jestli se jej podařilo z technologie přenést; zatímco výstupní kanál je správný v aplikaci a klade na zápis menší nároky — jestli a jak se hodnota dostane do technologie — s určitou nadsázkou — již není věcí aplikace.

Zároveň je však komunikační část aplikace navržena symetricky, a i přes zřetelný významový rozdíl vstupních a výstupních kanálů je možné shodně sledovat jak průběh měření tak průběh zápisu. Aplikace (neboli přístroje) používá pro komunikaci (souhrnný název pro měření i zápis) jednoho mechanizmu a obsluha kanálů obou směrů je (na první pohled) shodná.

Aplikace reálného času při komunikaci pečlivě váží, který kanál bude v konkrétním časovém kroku jádra potřebovat (o časovém kroku jádra a časování vůbec se dočtete v kapitole Časování aplikací reálného času. Rozhodování, který kanál změřit a který ne, provádí jádro ve spolupráci s přístroji, které samy nejlépe vědí, jaké kanály budou při své aktivaci potřebovat. Přístroje s procedurami a časovače navíc dokáží s jádrem komunikovat složitěji a jednotlivé potřebné kanály jsou tak měřeny postupně (odpovídající mechanizmus časování je přerušovaná aktivace přístroje) podle postupně se vyvíjejícího běhu přístroje.

Časový krok jádra je elementární jednotka běhu aplikace, a je proto nutné zaručit, aby během něj pracovaly všechny přístroje se shodnými hodnotami kanálů. V opačném případě by dva grafy shodně časované ukázaly různé hodnoty kanálů, a to je jistě situace nepřípustná. Každý vstupní kanál je proto v jednotlivém časovém kroku jádra měřen pouze jedenkrát, a to i v případě, že je přístroji požadován (kvůli přerušované aktivaci) vícekrát.

Bylo by všechno příliš jednoduché, kdyby neexistovaly výjimky. Vstupní kanály během jednoho kroku jádra mohou nabýt dvou hodnot v případě, že jejich komunikace doběhla zpožděně až během aktivace přístrojů. První hodnota vstupního kanálu je stará (z některého předcházejícího časového kroku), druhá se potom v kanále objeví během přerušení aktivace, byl-li kanál úspěšně doměřen. Dvojí hodnota kanálu se nikdy nevyskytne v časových krocích, které doměří všechna data před vypršením komunikační prodlevy — o prodlevách pojednává následující oddíl této kapitoly.

Odlišným způsobem se pracuje s výstupními kanály. Přístroje během svých aktivací mohou výstupní kanál libovolně nastavovat (a musí tak činit, jinak by aplikace nemohla vůbec nic ovládat), přičemž je přirozené, že v jednom časovém kroku může jeden kanál zapisovat více přístrojů. Jádro všechny požadavky respektuje a hodnota výstupního kanálu se proto během jednoho časového kroku jádra může měnit. Výstupní kanál se v tomto ohledu chová velice podobně, jako proměnná, a může být během jednoho časového kroku několikrát přepsán. Po dokončení aktivací přístrojů je tudíž do technologie zapsána poslední hodnota výstupního kanálu.

Výstupní kanály mohou být během jednoho časového kroku jádra nejen několikrát přístroji zapsány, ale také několikrát komunikovány. Způsobuje to mechanizmus přerušované aktivace přístrojů, který musí během jednotlivých přerušení kromě měření nových vstupních kanálů také zapisovat kanály výstupní, neboť jejich zapsání může ovlivnit bezprostředně následující měření — vše (měření i zápis) se přitom odehraje během jednoho přerušení aktivace.

Výsledkem je důležitý rozdíl mezi vstupními a výstupními kanály: vstupní kanály jsou během jednoho kroku měřeny jen jednou a mohou tak mít jen jednu hodnotu, výstupní kanály jsou během jednoho kroku potenciálně několikrát upravovány a také několikrát komunikovány.

Souhrnný průběh časového kroku z pohledu vstupních kanálů je následující:

1. počáteční zjištění, které kanály budou přístroje aktivované v začínajícím časovém kroku jádra potřebovat
2. změření kanálů — tato fáze je popsána detailně v další sekci kapitoly
3. aktivace přístrojů — probíhají-li přístroje bez přerušení aktivace, neděje se se vstupními kanály nic. V opačném případě přístrojů s přerušovanou aktivací jádro získává postupně nové informace o potřebných kanálech a musí je, pokud již nebyly v tomto kroku změřeny, měřit. Pokračuje proto opět krokem 1. a 2.
4. ukončení aktivace — přístroje, které byly zdrojem dat o měřených kanálech, jsou všechny dokončeny a v probíhajícím časovém kroku již nebude třeba měřit žádný kanál. Pro vstupní kanály časový krok jádra skončil a nová měření kanálů proběhnou až v dalším časovém kroku jádra.

Souhrnný průběh časového kroku z pohledu výstupních kanálů je následující:

1. aktivace přístrojů — postupně aktivované přístroje mohou postupně do výstupních kanálů zapisovat jakékoli hodnoty, takže se v kanále vyskytuje vždy poslední zapsaná hodnota. Probíhá-li aktivace přerušovaně, jsou výstupní kanály v jednolivých přerušeních zapsány — proběhne bod 2. Po dokončení zápisu přerušená aktivace pokračuje dále.
2. zápis hodnot — po dokončení aktivací přístrojů jsou zapsány všechny zbylé dosud nevyřízené požadavky za zápis. Stejně jako měření bude i zápis popsán v další sekci.

Všimněte si, že se u výstupních kanálů nikde nehovoří o ukončení vzniku požadavků (jako u vstupů). Tato vlastnost je přímým důsledkem okamžitých reakcí ovládacích prvků na uživatelské zásahy. Stisk tlačítka (nebo jiná podobná akce) může v principu nastat v jakémkoli časovém okamžiku, bez sebemenší vazby na časový krok jádra. Jádro proto zpracovává všechny požadavky na zápis kanálů asynchronně. Pokud se okamžik asynchronního zápisu na kanál vyskytne během nějakého časového kroku jádra, je požadavek přiřazen k normálním — synchronním zápisům (zápisům uskutečněným během aktivací) a je vyřízen spolu s nimi. Požadavek se pouze přidá k existujícím.

Pokud však asynchronní zápis vznikne mimo časový krok jádra, musí jádro provést mimořádný časový krok, ve kterém se uskuteční pouze komunikace asynchronně vzniklých požadavků. Je proto možné navrhnout a zkonstruovat aplikaci, která nebude mít žádné časované přístroje — jádro proto nikdy nebude periodicky spuštěno, aby aktivovalo přístroje — a stále bude možné zcela normálně zapisovat na výstupní kanály. To je další důležitý rozdíl mezi vstupními a výstupními kanály — požadavek na měření vždy vychází z aktivovaného přístroje, a je proto vždy synchronní, zatímco požadavek na zápis může být asynchronní, neboť může vzniknou v důsledku uživatelského zásahu.

Kromě vstupních a výstupních kanálů existují také kanály obousměrné. Obousměrné kanály jsou kombinací vstupního a výstupního kanálu a systém se k nim chová podle situace, v níž jsou použity. Obousměrný kanál použitý jako vstup bude měřen, obousměrný kanál použitý jako výstup bude zapisován. Používají-li se obousměrné kanály v jednom kroku jádra současně jako vstupní i výstupní, může nastat takzvaný překryv komunikace, kdy buď později dokončené měření přepíše předchozí hodnotu připravenou k zápisu nebo kdy zápis do kanálu přepíše aktuálně změřenou hodnotu. Jádro pro obousměrné kanály nedefinuje žádná dodatečná pravidla, a proto vždy "vyhrává poslední", ať to již je dokončené měření nebo požadavek na zápis. Vznikne-li překryv, je možné, že aplikace může pracovat s hodnotou, kterou nezměřila (protože ji překryl zápis hodnoty jiné) nebo že se do technologie zapíše hodnota, která nebyla zapsána (protože ji překryla hodnota z později dokončeného měření). Obousměrné kanály je proto třeba používat obezřetně a pokud není jejich použití skutečně nutné, je vhodnější používat kanály jednosměrné.

## Kanály a ovladače

Veškerá komunikace kanálů aplikace probíhá pomocí ovladačů. Kanály jsou datové elementy aplikace, ovladače potom samostatné komponenty (malé samostatné programy), které realizují přenášení kanálů z a do technologie. Logika komunikací, tedy kdy a jaký kanál se má měřit nebo zapisovat, je součástí jádra aplikace, ovladač je jen prostředník, který požadavky aplikace vyřizuje a transformuje je do podoby, které rozumí snímač nebo řídicí prvek.

Každý ovladač je spjat s nějakým "svým" zařízením, se kterým dokáže komunikovat. Existují také ovladače, které nepatří "k zařízení" ale "k protokolu", a je proto možné je nasadit ke komunikaci s mnoha různými zařízeními. Obecně vzato, ovladač vždy komunikuje nějakým protokolem — i třeba zápis a čtení dat z měřicí karty zasunuté přímo v počítači je řízen protokolem — i když velmi jednoduchým. Ovladač tedy rozumí svému protokolu a je pomocí něj schopen předávat vstupně/výstupnímu zařízení požadavky aplikace.

Ovladač je obyčejně pomocí souboru s parametry (o souborech hovoří kapitola Soubory systému Control Web) nastaven na určitou množinu dat — vnitřních kanálů — které odpovídají nějakým způsobem datům přímo v techologickém zařízení. Každý vnitřní kanál má své číslo — číslo kanálu v ovladači — které se používá při definici kanálu v aplikaci. Pomocí tohoto čísla tedy dochází k logickému propojení pojmenovaného kanálu — datového elementu s kanálem — částí ovladače. Číslo kanálu v ovladači je základní informace, která se při výměně dat mezi jádrem a ovladačem používá k rozlišení kanálu, a každý požadavek jádra směrovaný k ovladači je proto tímto číslem vybaven.

Výměna dat mezi jádrem a ovladačem je při čtení i zápisu velmi podobná. Protokol těchto výměn je v obou případech shrnut do tří významově shodných kroků, které jsou realizovány pomocí pěti (nebo čtyř) procedur.

Při čtení dat (měření) používá jádro tyto procedury ovladače (všechny procedury kromě InputRequestCompleted zpracovávají jeden kanál a všechny proto mají v jednom svém parametru jeho číslo):

- InputRequest — proceduru jádro volá ovladači jednotlivě pro každý kanál, který si přeje změřit. Procedura je volána tak dlouho, dokud jádro ovladači neoznámí všechny kanály, které potřebuje. Jádro proceduru volá ve všech případech, kdy zahajuje vstupní komunikaci — tedy i během přerušované aktivace. Dokud ovladač neukončí komunikaci daného kanálu pomocí procedury InputFinalized, není InputRequest pro daný kanál volána i přesto, že aplikace požaduje novou hodnotu tohoto kanálu opakovaně.
- InputRequestCompleted — po dokončení všech volání procedury InputRequest jádro voláním této procedury ovladači oznamuje, že již nemá další požadavky a že tudíž ovladač může začít měřit.
- InputFinalized — proceduru jádro ovladači volá jednotlivě pro každý dosud nezměřený kanál bezprostředně po volání procedury InputRequestCompleted. U této procedury je vhodné ještě chvilku setrvat:

- Jádro InputFinalized volá pro daný kanál poprvé vždy po volání procedury InputRequestCompleted. Pokud kanál není doměřen, může jádro tuto proceduru volat opakovaně v případě, kdy buď probíhá jiný (nový) časový krok jádra a nebo když je ovladačem požádáno, aby dokončilo komunikaci doměřených kanálů. Jinými slovy, dokud není kanál doměřen, volá jádro tuto proceduru "v příhodných okamžicích".
- Ovladač musí podle aktuálního stavu komunikace daného kanálu jádru podat korektní informaci. Má-li ovladač kanál změřen, musí vrátit hodnotu true, nemá-li ovladač kanál změřen, musí vrátit hodnotu false. V prvém případě jádro okamžitě změřenou hodnotu z ovladače vyčítá procedurou GetInput. Ve druhém případě, kdy ovladač ještě nemá data k dispozici, jádro pouze kanál vnitřně zařadí do seznamu nezměřených kanálů.
- Ovladač může komunikaci kanálu ukončit chybou (například chyba vypršení času, chyba převodu hodnoty, ...). Tehdy musí procedura InputFinalized vrátit hodnotu true a navíc musí být její návratový parametr s číslem chyby naplněn nenulovou hodnotou. Informace o chybě je zapsána do okna zpráv a do diagnostických informací kanálu a ovladače. Hlášení chyby není povinné a ovladač je nemusí implementovat.
- Ovladač návratem hodnoty false zároveň jádru říká, že sám jádru doměření hodnoty oznámí. K oznámení doměření ovladač musí použít proceduru DriverCallBack s kódem dfcDriverInputFinalized. V okamžiku přijetí této zprávy jádro zajistí opětovné volání InputFinalized pro dosud nezměřené kanály.
- Dokud není daný kanál procedurou InputFinalized potvrzen, nebude pro tento kanál volána ani procedura InputRequest ani procedura GetInput. V případě programové chyby ovladače se proto může stát, že nepotvrzený kanál již nikdy nebude změřen.
- Vrátí-li procedura pro alespoň jeden kanál požadovaný v aktuálním měření hodnotu false, čeká jádro po stanovenou dobu na dokončení komunikace. Po tuto dobu aplikace neběží a ovladač může průběžně dodávat nově doměřená data. Pokud komunikační prodleva vyprší, pokračuje jádro s aktivací přístrojů a použijí se naposledy změřené hodnoty. Prodleva je vypočítána jako maximum ze všech prodlev jednotlivých nedoměřených kanálů, přičemž se nikdy neuplatní hodnoty prodlev kanálů nepotvrzených již v předchozích měřeních.

- GetInput a GetInput2 — vrátí-li procedura InputFinalized hodnotu true a není-li nastaven žádný chybový kód, volá jádro jednu z těchto procedur pro vyčtení hodnoty kanálu z ovladače. Procedury jsou dvě, neboť existují dvě verze ovladačů (bližší popis rozdílu obsahuje kapitola Rozhraní ovladačů.
- DriverCallBack s kódem dcfDriverInputFinalized — proceduru volá ovladač v případě, že doměřil kanály (jeden nebo více), které jádru dosud nepotvrdil (při volání procedury InputFinalized vrátil ovladač hodnotu false). Jedno volání této procedury může signalizovat více doměřených kanálů, je proto neefektivní volat tuto proceduru pro každý kanál zvlášť. Pokud ovladač DriverCallBack nezavolá (zapomene na něj) nemusí jádro v určitých případech (záleží to na konstrukci aplikace) již nikdy daný kanál po ovladači požadovat. Je proto důležité v ovladači zajistit, aby každému nepotvrzenému kanálu odpovídal nějaký DriverCallBack v okamžiku doměření kanálu.

Při zápisu dat (měření) používá jádro tyto procedury ovladače (všechny procedury kromě OutputRequestCompleted zpracovávají jeden kanál a všechny proto mají v jednom svém parametru jeho číslo):

- OutputRequest (nebo OutputRequest2) — proceduru jádro volá ovladači jednotlivě pro každý kanál, který si přeje přenést do technologie. Současně s informací o zápisu kanálu jádro předává proceduře i hodnotu kanálu, kterou potřebuje zapsat. Procedura je volána tak dlouho, dokud jádro ovladači neoznámí všechny zapisované kanály. Jádro proceduru volá ve všech případech, kdy zahajuje výstupní komunikaci — tedy i během přerušované aktivace. Rozlišení mezi OutputRequest a OutputRequest2 popisuje kapitola Rozhraní ovladačů.
- OutputRequestCompleted — po dokončení všech volání procedury OutputRequest jádro voláním této procedury ovladači oznamuje, že již nemá další požadavky a že tudíž ovladač může začít zapisovat do technologie.
- OutputFinalized — proceduru jádro ovladači volá jednotlivě pro každý dosud nepotvrzený (nezapsaný) kanál bezprostředně po volání procedury OutputRequestCompleted. Také u této procedury je vhodné setrvat:

- Jádro OutputFinalized volá pro daný kanál poprvé vždy po volání procedury OutputRequestCompleted. Pokud kanál není dosud zapsán, může jádro tuto proceduru volat opakovaně buď v případě zápisu nového požadavku, nebo probíhá-li jiný (nový) časový krok jádra a nebo když je jádro ovladačem požádáno, aby dokončilo komunikaci zapsaných kanálů. Jinými slovy, dokud není kanál zapsán, volá jádro tuto proceduru "v příhodných okamžicích".
- Ovladač musí podle aktuálního stavu komunikace daného kanálu jádru podat korektní informaci. Má-li ovladač kanál zapsán, musí vrátit hodnotu true, nemá-li ovladač kanál zapsán, musí vrátit hodnotu false. Ve druhém případě, kdy ovladač ještě nemá zápis dat do technologie potvrzen, jádro pouze kanál vnitřně zařadí do seznamu nezapsaných kanálů.
- Ovladač může zápis kanálu ukončit chybou (například chyba vypršení času, chyba převodu hodnoty, ...). Tehdy musí procedura OutputFinalized vrátit hodnotu true a navíc musí být její návratový parametr s číslem chyby naplněn nenulovou hodnotou. Informace o chybě je zapsána do okna zpráv a do diagnostických informací kanálu a ovladače. Hlášení chyby není povinné a ovladač je nemusí implementovat.
- Ovladač návratem hodnoty false zároveň jádru říká, že sám jádru potvrzení zápisu oznámí. K potvrzení zápisu ovladač musí použít proceduru DriverCallBack s kódem dfcDriverOutputFinalized. V okamžiku přijetí této zprávy jádro zajistí opětovné volání OutputFinalized pro dosud nezapsané kanály.
- I v případě, že není daný kanál procedurou OutputFinalized potvrzen, může jádro pro tento kanál nově volat proceduru OutputRequest. Jinými slovy, jádro do ovladače zapisuje vždy aktuální hodnotu výstupního kanálu bez ohledu na výsledek jeho předešlé komunikace.
- Vrátí-li procedura pro alespoň jeden kanál zapisovaný v daném komunikačním cyklu hodnotu false, čeká jádro po stanovenou dobu na dokončení komunikace. Po tuto dobu aplikace neběží a ovladač může průběžně potvrzovat nově zapsané kanály. Pokud komunikační prodleva vyprší, pokračuje jádro dále ve svém časovém kroku. Prodleva je vypočítána jako maximum ze všech prodlev jednotlivých nepotvrzených kanálů, přičemž se nikdy neuplatní hodnoty prodlev kanálů nezapsaných již v předchozích komunikacích.

- DriverCallBack s kódem dcfDriverOutputFinalized — proceduru volá ovladač v případě, že obdržel z technologického zařízení potvrzení o zápisu kanálů (jednoho nebo více), které jádru dosud nepotvrdil (při volání procedury OutputFinalized vrátil ovladač hodnotu false). Jedno volání této procedury může signalizovat více zapsaných kanálů, je proto neefektivní volat tuto proceduru pro každý kanál zvlášť.

Mechanizmy vstupní i výstupní komunikace jsou pevnou specifikací a ovladač je musí dodržet, jinak systém nemůže zaručit správný běh aplikace. Existuje jedna situace, kdy ovladač i při (formálním) splnění požadavků může pracovat chybně. Chyba ovladače vznikne tehdy, potvrzuje-li ovladač měření i zápisy pomocí procedur InputFinalized a OutputFinalized bez ohledu na stav komunikace. Například, ovladač komunikující s průmyslovým automatem po sériové lince je téměř vždy jádrem donucen vrátit se z procedur s hodnotou false, neboť po sériové lince data okamžitě změřit nelze. Pokud ovladač přesto vrací v této situaci systematicky hodnotu true, tak podvádí.

Popisované chování je chybné, neboť ovladač předstírá, že se komunikace vyřeší ihned — a aplikace v takové situaci nemůže čekat na výsledek komunikace s použitím prodlev a nemá možnost komunikaci řídit. Kvůli ovladači potom aplikace nedokáže správně (předpovídatelně a podle specifikací systému) komunikovat.

V některých speciálních případech je popsané chybné chování žádoucí, jedná se však vždy o nestandardní způsoby komunikace (například určité módy DDE komunikace). Ovladače, které se takto chovají, by měly mít tuto odchylku dobře popsánu ve své dokumentaci, aby se nemohla stát zdrojem nedorozumění.

### Stavy kanálů

Průběh komunikace kanálu je velmi přesně signalizován pomocí obsahu atributu status. Atribut je v aplikaci kdykoli k dosažení, takže je možné zjistit momentální stav každého kanálu (o jiných atributech se můžete dočíst v kapitole Datové elementy a výrazy). Typicky (avšak řídce) se stavy kanálů používají při řízené komunikaci, která je popsána v kapitole Časování aplikací reálného času. Stavy kanálu jsou reprezentovány jednotlivými bity atributu status, takže k jejich testování s výhodou použijete bitových funkcí, zejména pak funkci bitget (funkce je popsána v kapitole Datové elementy a výrazy).

Pro oba směry komunikace jsou definovány celkem čtyři stavy kanálů (u jména stavu je vždy v hranatých závorkách číslo bitu, které je třeba použít v parametru funkce bitget):

- kanál čeká na dokončení komunikace (stav čtení stGetWaitACK[3] a zápisu stSetWaitACK[1]) — stav se stane aktivní, zapíše-li jádro do ovladače požadavek na zápis nebo měření procedurou OutputRequest nebo InputRequest. Stav přestane být aktivní buď dokončí-li jádro s ovladačem komunikaci pomocí OutputFinalized nebo InputFinalized, nebo uplyne-li komunikační prodleva a komunikace kanálu není stále dokončena.
- kanál nebyl potvrzen do vypršení komunikační prodlevy (stGetTimeout[7] a stSetTimeout[4]) — stav se stane aktivní uplyne-li komunikační prodleva a kanál stále není doměřen nebo zapsán. Definujete-li komunikační prodlevu nulovou, bude stav aktivní u každého kanálu s neukončenou komunikací. Jako v předchozím případě je tento stav shozen, ukončí li ovladač a jádro komunikaci pomocí funkce OutputFinalized nebo InputFinalized.
- komunikace byla úspěšně dokončena (stGetACKed[8] a stSetACKed[5]) — stav se stane aktivní, dokončí-li jádro ve spolupráci s ovladačem komunikaci pomocí OutputFinalized nebo InputFinalized bez signalizace chyby. Stav přestane být aktivní okamžikem zavolání funkce OutputRequest nebo InputRequest.
- komunikace byla dokončena s chybou (stGetError[9] a stSetError[6]) — stav se stane aktivní, dokončí-li jádro ve sploupráci s ovladačem komunikaci pomocí OutputFinalized nebo InputFinalized signalizací chyby. Stav přestane být aktivní okamžikem zavolání funkce OutputRequest nebo InputRequest.

Povšimněte si, že stavy stWaitACK a stTimeout se vylučují se stavy stError a stACKed a nikdy nemohou být aktivní současně. Stavy stWaitACK a stTimeout mohou být současně aktivní za situace, kdy vznikl nový požadavek na komunikaci a starý ještě nebyl dokončen. Vzhledem k rozdílu chování vstupních a výstupních kanálů je současný výskyt těchto bitů možný pouze u výstupních kanálů, neboť u vstupních kanálů nikdy není zahájena nová komunikace před dokončením komunikace předchozí.

## Typy kanálů a předávaných dat

Jádro a ovladač si navzájem vyměňují hodnoty buď pomocí procedury ovladače GetInput (GetInput2) v případě měření a nebo pomocí procedury ovladače OutputRequest (OutputRequest2) v případě zápisu. V obou případech je nutné do ovladače zapisovat (a z něj číst) kanály všech dostupných datových typů, a je proto třeba, aby existoval nějaký univerzální způsob, jak toho dosáhnout.

Systém Control Web definuje pro přenos hodnot (jakýchkoli hodnot, ne pouze kanálů, ale i proměnných a externích dat) pomocnou datovou strukturu s následující definicí (použit je zápis jazyka C):

    typedef char typeString255[255];

      struct TValue {                       // Value storage
        struct {
          unsigned Type;
          union {                           // switch (Type)
            char             ValBoolean;    // vtBoolean
            unsigned char    ValShortCard;  // vtShortCard
            unsigned short   ValCardinal;   // vtCardinal
            unsigned         ValLongCard;   // vtLongCard
            signed char      ValShortInt;   // vtShortInt
            signed short     ValInteger;    // vtInteger
            signed           ValLongInt;    // vtLongInt
            float            ValReal;       // vtReal
            double           ValLongReal;   // vtLongReal
            typeString255    *ValPString;   // vtPString
            struct {                        // vtBuffer
              unsigned char  BType;
              unsigned short BLen256;
              void           *PBuffer;
            };
          };
        };
      };

Všechny výměny dat v aplikaci probíhají s použitím tohoto typu. Položka Type obsahuje vždy jednu z hodnot vtBoolean..vtBuffer a určuje tak, jaká data záznamu jsou platná (definici použitých konstant, stejně jako definice jiných typů, které se používají při výměně dat s ovladačem obsahuje kapitola Rozhraní ovladačů pro Control Web). Datové typy obsáhnuté typem TValue ekvivalentně odpovídají datovým typům dostupným v aplikaci. Popis těchto typů včetně jejich paměťové náročnosti najdete v kapitole Datové elementy a výrazy.

Pro práci s daty ve formátu TValue platí tři jednoduchá pravidla:

- Při plnění i čtení struktury je třeba kontrolovat položku Type. Pokud data neodpovídají, neměl by ovladač data ani přijmout ani plnit. Výsledkem kolize typů může být například chyba komunikace ceValue hlášená při volání procedur ovladače InputFinalized a OutputFinalized.
- Pracuje-li ovladač s řetězcovou hodnotou (používá-li *ValPString) musí navíc kromě kontroly typu hodnoty kontrolovat, není-li ValPString nulový (null). Tehdy je řetězec nedostupný. Pokud jsou taková data použita při zápisu do ovladače (procedurou OutputRequest), je možné řetězec považovat za prázdný. (Pokud jsou taková data použita při volání procedury GetInput, jedná se o chybu jádra, a ovladač musí při InputFinalized chybu hlásit. Mohu vás uklidnit, že tato situace nikdy nenastane.) Není-li hodnota ValPString nulová, nesmí ji ovladač ani změnit, ani odalokovat. OutputRequest řetězec *ValPString musí zkopírovat do vnitřních dat ovladače, GetInput musí řetezec naopak kopírovat z vnitřní paměti do oblasti, na kterou ValPString ukazuje. Dynamicky alokovaná paměť ukazetele ValPString patří jádru a je proto nepřípustné s ní jakkoli manipulovat. Navíc, pro jeden konkrétní kanál může být hodnota ukazatele při různých voláních procedur OutputRequest a GetInput různá, takže ani není přípustné ukazatel jakkoli vnitřně v ovladači uchovávat. Řetězce se prostě kopírují.
- Hodnota PBuffer typu vtBuffer je naopak po dobu běhu aplikace stabilní, na což se může ovladač spolehnout. *PBuffer je podobně jako *ValPString "majetkem" aplikace, a je proto také nepřípustné s ním jakkoli manipulovat.

Hovoří se o datových typech kanálů, strukturách pro jejich přenos, ale jak se typ kanálu přiřazuje? Celkem existují tři místa, která s typem kanálu souvisejí:

- Definice kanálu v aplikaci — součástí definice kanálu je datový typ, kterým jako tvůrci aplikace říkáte, jaká si přejete data mít. Určení typu v aplikaci ovlivňuje překlad a podobu kanálu v datových strukturách jádra. Datový typ, který přiřadíte kanálu při jeho definici, bude jádro používat při volání procedur GetInput a OutputRequest.
- Mapovací soubor ('*.dmf' - o souborech se více dočtete v kapitole Soubory systému Control Web) — v souboru je zapsán většinou "maximální rozumný" rozsah kanálů, které ovladač může použít. Údaje z tohoto souboru používá překladač, aby ověřil, jestli je typ určený definicí kanálu přípustný. Mapovací soubory se dodávají většinou s ovladači, některé ovladače navíc dokáží tento soubor vytvářet svými pomocnými nástroji.
- Parametrický soubor ('*.par') — obsahuje definice kanálů ve specifickém formátu ovladače. Parametrický soubor řídí, jaké datové typy kanálů bude ovladač používat ve svých datových strukturách. Struktura souboru je svázána s ovladačem (jedná se o konfigurační soubor ovladače) a parametrické souboru různých ovladačů proto není možné zaměňovat.

Kolize typů, popsaná v prvním pravidle o práci s typem TValue proto nastane, neodpovídají-li si navzájem parametrický soubor a definice kanálu (případně soubor '*.dmf', neboť bez souladu definice kanálu a '*.dmf' souboru se aplikaci nepodaří ani přeložit).

Kanály číselných typů jsou uvnitř jádra uloženy v podobě odpovídající jejich typu. V této podobě se také hodnoty všech kanálů dostávají protřednictvím funkcí GetInput a OutputRequest do ovladače. Při předávání hodnot do aplikace (přístrojům) [při ukládání výsledků přístrojů do jádra] dochází ke konverzi hodnot na dlouhé reálné (desetinné) číslo [z reálného čísla na typ kanálu]. Konverze urychluje výpočty v běžící aplikaci, neboť veškeré výpočty výrazů probíhají v reálných číslech. O výpočtech výrazů a číselných datových typech se dočtete také v kapitole Datové elementy a výrazy.

## Koncepce ovladače

Ovladač můžete navrhnout několika způsoby v závislosti na typu zařízení, se kterým ovladač komunikuje. Zařízení je možné rozdělit na dvě velké skupiny — "blízká" zařízení, se kterými je možno data vyměňovat okamžitě, a "daleká" zařízení, která k poskytnutí a přijetí dat potřebují jistý čas. Těmto dvěma základním skupinám také odpovídají dvě základní strategie návrhu ovladače.

První skupina blízkých a rychlých zařízení (to jsou například měřicí karty zasunuté přímo v počítači) poskytuje hodnoty okamžitě, a ovladač proto může pracovat jen jako prodloužená ruka jádra aplikace. Hodnoty jsou při měření čteny přímo ze zařízení a bezprostředně vraceny jádru, při zápisu ovladač data okamžitě předá zařízení. Taková komunikace neobsahuje žádná zdržení a ovladač proto nemusí mít žádný výkonný kód, který by na pozadí řešil paralelně probíhající komunikaci. Ovladače této třídy jsou velmi jednoduché a je možné je vytvořit ve velice krátké době.

Druhá skupina ovladačů zařízení, s nimiž se musí komunikovat, je složitější. Komplikace způsobuje zpoždění, které nutně vzniká při přenosu dat po jakýchkoli komunikačních linkách (zpoždění vzniká i na 100MBps lokální síti, a i přesto, že je toto zpoždění o několik řádů menší než zpoždění na sériové lince, je stále natolik velké, že počítač brzdí). Ovladač musí jednak reagovat na požadavky aplikace a jednak musí průběžně vyřizovat komunikaci se zařízením. Komunikace se zařízením přitom běží zcela nezávisle na aplikaci a jejím časování, a ovladač proto musí pracovat samostatně bez vazby na systém Control Web. Aby bylo možné takovou činnost realizovat, musí mít ovladač svůj samostatný prováděcí tok (thread), který bude komunikaci na pozadí podle potřeb zajišťovat. Ovladače této třídy jsou obecně složitější, protože musejí jednak umět komunikační protokol svého zařízení (protokoly bývají občas velmi komplikované) a jednak musejí pracovat nezávisle (ve svém toku), což vyžaduje větší programátorskou obezřetnost (o prováděcích tocích se můžete dočíst v kapitole Co to jsou procesy a prováděcí toky).

Oba přístupy k návrhu ovladače je možné shrnout následovně:

- Zařízení reaguje na požadavky okamžitě — Ovladač nemusí se zařízením komunikovat a nikdy nevznikají žádné prodlevy. Měření i zápis se uskutečňují v okamžiku požadavku jádra. Ovladač pracuje synchronně. Procedury ovladače pracují následovně:

- InputRequest, InputRequestCompleted, stejně jako OutputRequestCompleted jsou prázdné, a ovladač na ně nijak nereaguje.
- InputRequestCompleted a OutputRequestCompleted vracejí vždy true bez jakékoli další činnosti.
- GetInput vyčte data ze zařízení a bezprostředně je vrátí jádru aplikace.
- OutputRequest převezme data od jádra a bezprostředně je zapíše do zařízení.

- Zařízení nereaguje na požadavky okamžitě — Ovladač musí se zařízením komunikovat, což znamená, že při výměnách dat vznikají časové prodlevy. Jádro do ovladače zapisuje požadavky a ovladač je podle rychlosti komunikace a zařízení postupně vyřizuje ve svém vlastním prováděcím toku. V okamžiku dokončení komunikace kanálu ovladač jádro informuje a jádro měření nabo zápis kanálu ukončí. Ovladač tedy pracuje asynchronně. Procedury ovladače pracují následovně:

- InputRequest shromažďuje požadavky jádra na měření. Ovladač si požadavky zapamatuje ve svých datových strukturách.
- OutputRequest shromažďuje požadavky jádra na zápis. Ovladač si požadavky spolu se zapisovanou hodnotou zapamatuje ve svých datových strukturách.
- InputRequestCompleted a OutputRequestCompleted zahajují komunikaci se zařízením.
- InputFinalized a OutputFinalized vracejí aktuální stav komunikace konkrétního kanálu. Byl-li požadavek vyřízen (nebo nastala-li chyba) vracejí procedury hodnotu true. Není-li požadavek vyřízen, vracejí procedury hodnotu false.
- GetInput zkopíruje změřená data uschovaná v ovladači na požadované místo (do předané struktury TValue.
- Výkonný tok ovladače pracuje v rytmu komunikace a vyřizuje požadavky, které vznikají voláním procedur InputRequest a OutputRequest. Jakmile tok ovladače dokončí komunikaci kanálu (tj. obdrží-li ze zařízení potvrzení čtení nebo zápisu) informuje jádro voláním procedury DriverCallback s parametrem dcfDriverInputFinalized pro vstupní kanály nebo s parametrem dcfDriverOutputFinalized pro výstupní kanály. Procedury InputFinalized a OutputFinalized po volání procedury DriverCallBack musejí pro kanál, jehož se volání DriverCallBack týká, vrátit hodnotu true, jinak jádro komunikaci kanálu nedokončí.

V určitých speciálních případech je možné, aby se ovladač choval podle obou vzorů najednou. Komunikace probíhá složitějším způsobem (na pozadí) ale procedury InputFinalized a OutputFinalized vracejí vždy hodnotu true. Pokud není toto chování ovladače zapnuto uživatelem, nebo není jinak dobře zdůvodněno, je považováno za chybné, protože znemožňuje aplikaci řízení komunikace. Programování ovladače s touto chybou je jednodušší, než programování ovladače pracujícího plně podle druhého vzoru — chybný ovladač nemusí obsahovat logiku obsluhování potvrzení komunikace kanálu. K vytvoření chybného ovladače je nutné vynaložit méně práce, což může k takovému řešení svádět. Výsledkem menšího množství práce však bude špatný ovladač.

## Shrnutí

- Kanály jsou datové elementy, které v aplikaci slouží k přenosu dat do technologie nebo z technologie. Podle takto definovaného směru rozeznáváme kanály výstupní a vstupní.
- Každý kanál je spojen s nějakým ovladačem, který zajišťuje fyzickou komunikaci se vstupně/výstupním zařízením. Ovladač vnitřně definuje množinu kanálů ovladače, která je pomocí čísel kanálů spojena s kanály aplikace.
- Kanály jsou měřeny a zapisovány optimalizovaně, přičemž rozhodnutí, jaký kanál bude v probíhajícím časovém kroku jádra čten, záleží na přístrojích aplikace a jádru aplikace.
- Jádro komunikuje s ovladačem pomocí procedur ovladače. Pro vstup i výstup je určena samostatná sada procedur.
- Ovladač v principu pracuje tak, že přijímá od jádra požadavky na měření a zápis kanálů, a tyto požadavky postupně vyřizuje. Komunikace jádra s ovladačem probíhá asynchronně.
- Podle charakteru zařízení, s nímž ovladač komunikuje, je možné rozlišit ovladače pracující okamžitě a ovladače pracující asynchronně.
- Ovladače asynchronní jsou složitější. Způsob jejich činnosti vynucuje jejich samostatný běh, což vede k použití separátního prováděcího toku ovladače.