# Rozhraní ovladačů pro Control Web

Ovladače vstupně/výstupních zařízení tvoří samostatné komponenty systému, které se do systému Control Web zařazují jako dynamicky linkované knihovny (DLL) až podle potřeby při návrhu aplikace nebo při jejím spuštění. Každá taková knihovna proto musí mít jednotné rozhraní (interface), které je tvořeno skupinou procedur a funkcí. Říkáme, že knihovna tyto procedury a funkce vyváží. Pro ovladače systému Control Web bylo vytvořeno rozhraní, které se postupem času stabilizovalo a které se snaží obsáhnout pokud možno co nejvíce variant v chování připojených zařízení. Při návrhu jednoduchého ovladače je proto možno použít pouze některé procedury a funkce rozhraní, přičemž ostatní musí být nadefinovány a implementovány jako prázdné. U komplexnějších ovladačů pak budou zřejmě využity všechny nebo většina těchto procedur a funkcí. V současné době existují dvě rozhraní ovladačů. První rozhraní bylo definováno pro Control Web verze 3.x. V nové verzi systému Control Web 2000 (verze 4.x) je toto rozhraní rozšířeno. Pro zachování kompatibility zpět musí ovladače s novým rozhraním implementovat všechny procedury a funkce rozhraní původního. Samozřejmé je, že ovladače s rozhraním starým budou pracovat i s novými verzemi produktu Control Web.

## Procedury a funkce rozhraní ovladačů

Rozhraní ovladače (3.x) je tvořeno následujícími procedurami a funkcemi:

  Version
  Check
  GetDriverInfo
  MakeDriver
  DisposeDriver
  Init
  Done
  BufferInfo
  SetBufferAddr
  InputRequest
  InputRequestCompleted
  InputFinalized
  GetInput
  OutputRequest
  OutputRequestCompleted
  OutputFinalized
  DriverProc
  QueryProc

Rozšířené rozhraní (4.x) je doplněno o následující procedury a funkce:

  GetInput2
  OutputRequest2

Callback procedura ovladače:

  DriverCallback

## Popis jednotlivých procedur a funkcí rozhraní ovladačů pro Control Web

### Version

    unsigned Version()

Vrací číslo verze rozhraní (API) ovladače. Číslo verze je složeno ze dvou částí (vyšší slovo - major version, nižší slovo - minor version). Pro major version platí, že musí mít hodnotu 3, minor version má různou hodnotu podle toho, jaké rozhraní ovladač implemetuje.

Návratová hodnota:

- 0x30000 - pokud ovladač používá rozhraní Control Web verze 3.x
- 0x30001 - pokud ovladač používá rozhraní Control Web 2000 verze 4.x

### Check

    char Check(unsigned szErrorString,
               char *ErrorString,
               unsigned CWVersion,
               unsigned MajorVersion,
               unsigned MinorVersion,
               unsigned APIMajorVersion,
               unsigned APIMinorVersion);

Volá se po zavedení DLL knihovny pro zjištění kompatibility ovladače s API. Všechny ovladače, které jsou nezávislé na API systému Control Web mohou vrátit hodnotu 1.

Parametry:

- szErrorString - velikost řetězce ErrorString
- ErrorString - chybové hlášení, které se zobrazí v případě chyby
- CWVersion - rozlišení produktu.
    0 - vývojová verze
    1 - runtime verze
    2 - demonstrační verze
    3 - beta verze
- MajorVersion, MinorVersion vyšší a nižší slovo aktuální verze produktu
- APIMajorVersion, APIMinorVersion vyšší a nižší slovo aktuální verze API

Návratová hodnota:

- 1 je-li inicializace úspěšná, 0 při chybě

### GetDriverInfo

    void GetDriverInfo(unsigned szDriverName,
                       char *DriverName);

Vrací jméno ovladače pro zobrazení v inspektoru ovladačů.

Parametry:

- szDriverName - velikost řetězce DriverName
- DriverName - jméno ovladače (řetězec zakončený znakem 0x0)

### MakeDriver

    HANDLE MakeDriver();

Vytvoří novou instanci ovladače a vrací její handle do systému. Systém pak volá všechny ostatní procedury a funkce ovladače s parametrem hDriver, kterým je právě tento handle. Jako handle může být vrácen např. ukazatel na alokovaná data ovladače nebo ukazatel na objekt ovladače a podobně.

Návratová hodnota:

- handle instance ovladače

### DisposeDriver

    void DisposeDriver(HANDLE hDriver);

Volá se při ukončení aplikace nebo při odinstalování ovladače, který byl spuštěn samostatně. Toto volání následuje za voláním procedury Done.

Parametry:

- hDriver - handle ovladače

### Init

    char Init(HANDLE hDriver,
              unsigned szParamFileName,
              char *ParamFileName,
              unsigned szInitMessage,
              char *InitMessage,
              unsigned LoginLevel,
              char RunningFlag,
              HANDLE CBHandle,
              tDriverCallback DriverCallback );

Volá se po zavedení ovladače do paměti a slouží k inicializaci ovladače. Parametr InitMessage při vstupu do procedury obsahuje symbolické jméno ovladače, pod kterým vystupuje v aplikaci. Procedura vrací hodnotu 1, když inicializace ovladače proběhla korektně. V případě, že se inicializace nezdařila, vrátí hodnotu 0 a parametr InitMessage musí obsahovat hlášení, které bude následně vypsáno v chybovém okně.

Parametry:

- hDriver - handle ovladače
- szParamFileName - velikost řetězce ParamFileName
- ParamFileName - jméno souboru parametrů ovladače
- szInitMessage - velikost řetězce InitMessage
- InitMessage - chybové hlášení, které se zobrazí v případě neúspěšné inicializace
- LoginLevel - úroveň přístupových práv pro manipulaci s oknem ovladače. Ovladač by měl uživateli s nižší úrovní zabránit v manipulaci s prvky dialogového okna. Úroveň přihlášeného uživatele získá ovladač automaticky při přihlášení tak, že mu systém zavolá proceduru DriverProc.
- RunningFlag - příznak spuštění ovladače. Hodnota 0 znamená, že ovladač je spuštěn samostatně, hodnota 1 znamená, že ovladač je spuštěn v rámci spuštění celé aplikace.
- CBHandle - handle callback procedury DriverCallback
- DriverCallback - adresa procedury, kterou ovladač zavolá pro signalizaci dokončení svých akcí nebo pro vygenerování vyjímky ovladače.

Návratová hodnota:

- 1 je-li inicializace úspěšná, 0 při chybě

### Done

    void  Done(HANDLE hDriver);

Volá se při ukončení činnosti ovladače, tj. při zastavení aplikace nebo při odinstalování ovladače spuštěného samostatně, ale také po chybě při inicializaci ovladače. Toto volání předchází volání DisposeDriver.

Parametry:

- hDriver - handle ovladače

### BufferInfo

    char  BufferInfo(HANDLE hDriver,
                     unsigned ChannelNumber,
                     unsigned char BType,
                     unsigned long BLen);

Tato procedura je dotazovací funkcí, ověřující schopnost ovladače spolupracovat s kanálem typu buffer definovaných vlastností. Tyto informace jsou čerpány z bloku definice kanálů (v případě deklarace v grafickém prostředí jsou získány nejprve z příslušného souboru '*.dmf'). V případě, že ovladač podporuje spolupráci s kanálem typu buffer daných vlastností, vrací procedura hodnotu 1, jinak hodnotu 0.

Parametry:

- hDriver - ukazatel na globální data ovladače
- ChannelNumber - logické číslo dotazovaného kanálu
- BType - typ dat bufferu
- BLen - velikost vyhrazené paměti pro buffer (bytes)

Návratová hodnota:

- 1 pokud je kanál podporován, jinak 0

Poznámka:
Procedura je volána jádrem systému postupně při zpracování sekce definice kanálů. Pokud procedura vrátí negativní výsledek, je překlad aplikace přerušen a oznámena chyba.

### SetBufferAddr

    void  SetBufferAddr(HANDLE hDriver,
                        unsigned ChannelNumber,
                        HANDLE PBuffer);

Pro každý ověřený kanál (předchozím voláním BufferInfo) je jádrem systému volána tato procedura. Slouží k předání informace o adrese bufferu ovladači. Tato adresa se za běhu aplikace nemění.

Parametry:

- hDriver - ukazatel na globální data ovladače
- ChannelNumber - logické číslo požadovaného kanálu
- PBuffer - ukazatel na alokovanou komunikační oblast kanálu

### InputRequest

    void  InputRequest(HANDLE hDriver,
                       unsigned ChannelNumber);

Procedura slouží k předání požadavku na získání hodnoty kanálu ovladače. V rámci právě zpracovávaného časového kroku se volá postupně pro všechny požadované kanály. Zadávání požadavků se ukončí voláním procedury InputRequestCompleted. Další požadavek na stejný kanál může přijít až po dokončení komunikace a potvrzení procedurou InputFinalized.

Parametry:

- hDriver - handle ovladače
- ChannelNumber - číslo kanálu.

### InputRequestCompleted

    void  InputRequestCompleted(HANDLE hDriver);

Procedura ukončí zadávání požadavků na čtení kanálů ovladače (InputRequest). V tomto okamžiku může ovladač zahájit činnost vedoucí k získání všech požadovaných hodnot (zahájení měření, komunikace apod.).

Parametry:

- hDriver - handle ovladače

### InputFinalized

    char  InputFinalized(HANDLE hDriver,
                         unsigned ChannelNumber,
                         unsigned *ErrorCode );

Volá se po zadání požadavků na čtení kanálů a zahájení operací čtení (InputRequestCompleted) postupně pro všechny požadované kanály. Vrací hodnotu 1, je-li operace ukončena. Nejsou-li hodnoty kanálů ještě k dispozici, vrátí hodnotu 0 a parametr ErrorCode s hodnotou ceOK. V tomto případě je nutno po doměření nebo po chybě zavolat proceduru DriverCallback s funkčním kódem dcfDriverInputFinalized. To způsobí opětovné volání procedury InputFinalized, která může nyní vrátit hodnotu 1. Dojde-li k chybě, musí být nastaven parametr ErrorCode na hodnotu ceTimeout nebo ceValue a do okna zpráv systému se vypíše chybové hlášení.

Parametry:

- hDriver - handle ovladače
- ChannelNumber - číslo kanálu
- ErrorCode - kód chyby
    ceOK = 0
    ceTimeout = 1
    ceValue = 2

Návratová hodnota:

- 1 pokud je operace čtení nebo zápis ukončena, jinak 0

### GetInput

    void  GetInput(HANDLE hDriver,
                   unsigned ChannelNumber,
                   TValue *ChannelValue);

Pomocí této procedury se přečte hodnota kanálu z ovladače a zapíše se do tabulky aktuálních hodnot kanálů, kde je k dispozici pro všechny virtuální přístroje. Hodnota kanálu se přenáší proměnnou ChannelValue, která je typu TValue. Je to variantní záznam, který je složen z položky Type a podle ní dále z položky obsahující vlastní hodnotu. Před naplněním hodnoty záznamu je nutno otestovat, jestli souhlasí Type. V případě kanálu typu string je nutno dále testovat ukazatel na řetězec ValPString na různost od null. Tento ukazatel nesmí být přepsán ani odalokován. Řetězec, který se přenáší z ovladače do aplikace je nutno zkopírovat na adresu, na kterou ValPString ukazuje.

Tato procedura je volána v případě ovladače s rozhraním 3.x, to znamená v případě, že ovladač nemá implementovány procedury a funkce rozhraní 4.x.

Parametry:

- hDriver - handle ovladače
- ChannelNumber - číslo kanálu
- ChannelValue - přečtená hodnota kanálu z ovladače

### GetInput2

     void GetInput2( HANDLE hDriver,
                     unsigned ChannelNumber,
                     TValue *InputValue,
                     unsigned *QOS,
                     timeStamp *TimeStamp );

Pomocí této procedury se přečte hodnota kanálu z ovladače a zapíše se do tabulky aktuálních hodnot kanálů, kde je k dispozici pro všechny virtuální přístroje. Hodnota kanálu se přenáší proměnnou ChannelValue, která je typu TValue. Je to variantní záznam, který je složen z položky Type a podle ní dále z položky obsahující vlastní hodnotu. Před naplněním hodnoty záznamu je nutno otestovat, jestli souhlasí Type. V případě kanálu typu string je nutno dále testovat ukazatel na řetězec ValPString na různost od null. Tento ukazatel nesmí být přepsán ani odalokován. Řetězec, který se přenáší z ovladače do aplikace je nutno zkopírovat na adresu, na kterou ValPString ukazuje. Kromě hodnoty kanálu se pomocí této procedury přenáší do aplikace ještě informace o kvalitě (QOS) a časová značka (TimeStamp), tj. čas, kdy byla hodnota získána. Obě tyto informace jsou dosažitelné jako atributy kanálů.

Tato procedura je volána v případě ovladače s rozhraním 4.x namísto procedury GetInput.

Parametry:

- hDriver - handle ovladače
- ChannelNumber - číslo kanálu
- InputValue - přečtená hodnota kanálu z ovladače
- QOS - kvalita služby (quality of service).
  Předdefinované konstanty jsou:
    qosUnknown = -1
    qosLowest = 0
    qosLow = 250
    qosNormal = 500
    qosHigh = 750
    qosHighest = 1000
    qosUser = 10000
- TimeStamp - časová značka

### OutputRequest

    void  OutputRequest(HANDLE hDriver, unsigned ChannelNumber,
                        TValue ChannelValue);

Procedura slouží k předání požadavku na zápis hodnoty kanálu do ovladače. V rámci právě zpracovávaného časového kroku se volá postupně pro všechny požadované kanály. Zadávání požadavků se ukončí voláním procedury OutputRequestCompleted. Ovladač musí být schopen přijímat požadavky i v okamžiku, kdy je zaneprázdněn komunikací se zařízením.

Tato procedura je volána v případě ovladače s rozhraním 3.x, to znamená v případě, že ovladač nemá implementovány procedury a funkce rozhraní 4.x.

Parametry:

- hDriver - handle ovladače
- ChannelNumber - číslo kanálu.
- ChannelValue - zapisovaná hodnota kanálu.

### OutputRequest2

    void OutputRequest2( HANDLE hDriver,
                         unsigned ChannelNumber,
                         TValue OutputValue,
                         unsigned QOS,
                         timeStamp *TimeStamp );

Procedura slouží k předání požadavku na zápis hodnoty kanálu do ovladače. V rámci právě zpracovávaného časového kroku se volá postupně pro všechny požadované kanály. Zadávání požadavků se ukončí voláním procedury OutputRequestCompleted. Ovladač musí být schopen přijímat požadavky i v okamžiku, kdy je zaneprázdněn komunikací se zařízením. Kromě hodnoty kanálu se pomocí této procedury přenáší do ovladače ještě informace o kvalitě (QOS), což je jeden z atributů kanálu a časová značka (TimeStamp), tj. čas, kdy byla hodnota zapsána do ovladače. S kvalitou a časovou značkou může ovladač naložit dle vlastního uvážení.

Tato procedura je volána v případě ovladače s rozhraním 4.x namísto procedury OutputRequest.

Parametry:

- hDriver - handle ovladače
- ChannelNumber - číslo kanálu
- OutputValue - zapisovaná hodnota kanálu
- QOS - kvalita služby (quality of service)
  Předdefinované konstanty jsou:
    qosUnknown = -1
    qosLowest = 0
    qosLow = 250
    qosNormal = 500
    qosHigh = 750
    qosHighest = 1000
    qosUser = 10000
- TimeStamp - časová značka

### OutputRequestCompleted

    void  OutputRequestCompleted(HANDLE hDriver);

Procedura ukončí zadávání požadavků na zápis kanálů do ovladače po volání (OutputRequest2) resp. (OutputRequest). V tomto okamžiku může ovladač zahájit činnost vedoucí k zápisu všech požadovaných hodnot (nastavení výstupů, zahájení komunikace apod.).

Parametry:

- hDriver - handle ovladače

### OutputFinalized

    char  OutputFinalized(HANDLE hDriver,
                          unsigned ChannelNumber,
                          unsigned *ErrorCode );

Volá se po zadání požadavků na zápis kanálů a zahájení operace zápis (OutputRequestCompleted) postupně pro všechny požadované kanály. Vrací hodnotu 1, je-li operace ukončena. Nejsou-li hodnoty kanálů ještě zapsány, vrátí hodnotu 0 a parametr ErrorCode s hodnotou ceOK. V tomto okamžiku je nutno po dokončení zápisu nebo po chybě zavolat proceduru DriverCallback s funkčním kódem dcfDriverOutputFinalized. Dojde-li k chybě, musí být nastaven parametr ErrorCode na hodnotu ceTimeout nebo ceValue. V tom případě se vypíše chybové hlášení do okna zpráv.

Parametry:

- hDriver - handle ovladače
- ChannelNumber - číslo kanálu
- ErrorCode - kód chyby
    ceOK = 0
    ceTimeout = 1
    ceValue = 2

Návratová hodnota:

- 1 pokud je operace čtení nebo zápis ukončena, jinak 0

### DriverProc

    void  DriverProc(HANDLE hDriver,
                     unsigned Func,
                     unsigned Param1,
                     unsigned Param2,
                     unsigned Param3,
                     unsigned Param4);

Procedura slouží k předání řídicího povelu z aplikace do ovladače. Povel je definován kódem a množinou parametrů, jejichž význam je určen typem povelu.

Parametry:

- hDriver - handle ovladače
- Func - kód povelu
- Param1..Param4 - parametry závislé na kódu funkce
    0 - Hide - skrytí okna ovladače
    1 - Show - zobrazení okna ovladače
    2 - Minimize - minimalizace okna ovladače
    3 - Restore - obnovení okna ovladače
    4 - Select - výběr okna ovladače
    5 - NewRect - nastavení nových souřadnic okna ovladače
    Param1 - x-ová souřadnice levého horního rohu
    Param2 - y-ová souřadnice levého horního rohu
    Param3 - šířka okna
    Param4 - výška okna
    6 - Login - předání úrovně přístupových práv právě přihlášeného uživatele
    Param1 - úroveň přístupových práv (UserLoginLevel)

### QueryProc

    void  QueryProc(HANDLE hDriver,
                    TValue Param1,
                    TValue *Param2);

Procedura slouží k vyvolání obecné uživatelské funkce ovladače prostřednictvím nativní procedury system.DriverQueryProc( DriverName : string; DrvParam1 : any; &DrvParam2 : any ). Parametr DriverName určuje symbolické jméno ovladače, kterému je zavolána procedura QueryProc. Parametr DrvParam1 se předává do ovladače a parametr DrvParam2 slouží jak k předání hodnoty, tak k vrácení hodnoty z ovladače. Funkce nativní procedury je závislá na implementaci procedury QueryProc v ovladači.

Parametry:

- hDriver - handle ovladače
- Param1, Param2 - parametry odpovídají stejným parametrům nativní procedury

### DriverCallback

    unsigned DriverCallback(HANDLE CBHandle,
                            unsigned Func,
                            void *Param);

Tato procedura slouží k tomu, aby ovladač signalizoval do systému dokončení vyvolané akce nebo k vyvolání vyjímky ovladače. Adresa této procedury je předána spolu s jejím handlem procedurou Init. Typ procedury je definován jako:

    typedef unsigned (*tDriverCallback)(HANDLE, unsigned, void *);

Parametry:

- CBHandle - handle procedury, který se získá z parametru CBHandle procedury Init
- Func - funkční kód
    0 - dcfDriverInputFinalized
  tato funkce musí být zavolána po dokončení akce ovladače v případě, že ovladač předtím v proceduře InputFinalized vrátil hodnotu false(0), protože nebyl schopen okamžitě vrátit data čtených kanálů.
    1 - dcfDriverOutputFinalized
  tato funkce musí být zavolána po dokončení akce ovladače v případě, že ovladač předtím v proceduře OutputFinalized vrátil hodnotu false(0), protože nebyl schopen okamžitě zapsat data do výstupního zařízení.
    2- dcfDriverInterrupt
  tuto funkci volá ovladač v případě, že chce vygenerovat vyjímku do aplikace.
- Param - proměnné, přes kterou procedura získává a vrací data. Typ proměnné záleží na funkčním kódu.

Návratová hodnota:

- výsledek operace:
    0 - erOK -volání proběhlo bez chyby
    1 - erNotAccepted - volání nebylo akceptováno (podle možnosti je nutno zopakovat)
    2 - erNoApplication - není spuštěna aplikace
    3 - erNotReady - systém není připraven
    -1 - erNoFunction - neplatný kód funkce

## Definice použitých typů

Následuje popis typů, použitých v definicích procedur a funkcí rozhraní ovladačů. Kompletní definice najdete v hlavičkovém souboru 'cwdriver.h' v adresáři 'ddk'.

### Typ TValue

Datový typ TValue je variantní záznam, který obsahuje hodnotu kanálu čtenou z ovladače nebo zapisovanou do ovladače. Obsah tohoto záznamu je modifikován podle typu kanálu, který je představován položkou Type. Předdefinované konstanty určují typ kanálu.

      // values
      #define valueNothing          0   // indicates "not having been used before"
      #define valueError            1   // error tag
      #define valueBoolean          2   // 8-bit flag
      #define valueShortCard        3   // 8-bit unsigned
      #define valueCardinal         4   // 16-bit unsigned
      #define valueLongCard         5   // 32-bit unsigned
      #define valueShortInt         6   // 8-bit signed
      #define valueInteger          7   // 16-bit signed
      #define valueLongInt          8   // 32-bit signed
      #define valueReal             9   // float  (dword)
      #define valueLongReal         10  // double (qword)
      #define valuePString          11  // char (* pString)[255]
      #define valueBuffer           12  // buffer
      #define valueUnknown          13  // unknown value

      // buffer Header Kinds
      #define hkStdBuffer           0   // standard buffer format (header+data block)

      // buffer status - bits           // be aware - these value represents bits, not masks
      #define stEmpty               0   // empty data
      #define stFillInProgress      1   // filling buffer
      #define stFull                2   // buffer completely valid
      #define stError               3   // not completely valid or if something bad occured
      #define stBusy                4   // if setting channel or something calculating
      #define stInvalid             5   // 2nd phase after stNonactual (before channels read)
      #define stNonactual           6   // if exists new (not actually read) data
      #define stModified            15  // used by instrument to mark modification;
                                        // thus can be set channel only if neccessary

      struct tBufferHeader { // Buffer header
          struct {
            unsigned short HeaderKind;
              union {
                  struct {              // in case of HeaderKind == hkStdBuffer
                      unsigned short Channels;     // number of channels
                      unsigned       NumSamples;   // volume of data block
                      unsigned       CurSamples;   // number of samples currently present
                      double         SampFreq;     // sampling frequency or 0 (0 indicates "Time" usage)
                      unsigned short SampStruct;   // sample structure (0==real data, 1==complex & Channels==2)
                      unsigned short DataType;     // type of data (valueXXX)
                      unsigned short Status;       // buffer status (stXXX)
                      unsigned short Any1;         // not used now; leave 0
                      float          Time;         // sampling time, not period
                  };
              };
          };
      };                                // size of tBufferHeader must be 32 bytes

      typedef char tString255[255];

      struct TValue {  // Value storage
          struct {
              unsigned Type;
              union {                             // switch (Type)
                  char             ValBoolean;    // valueBoolean
                  unsigned char    ValShortCard;  // valueShortCard
                  unsigned short   ValCardinal;   // valueCardinal
                  unsigned         ValLongCard;   // valueLongCard
                  signed char      ValShortInt;   // valueShortInt
                  signed short     ValInteger;    // valueInteger
                  signed           ValLongInt;    // valueLongInt
                  float            ValReal;       // valueReal
                  double           ValLongReal;   // valueLongReal
                  tString255      *ValPString;    // valuePString
                  struct {                        // valueBuffer
                      unsigned char  BType;
                      unsigned short BLen256;
                      void           *PBuffer;
                  };
              };
          };
      };

### Typ timeStamp

Tento typ je tvořen záznamem složeným z následujících položek:

- MilisecondsInDay - aktuální počet milisekund ve dni
- Day - aktuální den
- Month - aktuální měsíc
- Year - aktuální rok

      struct timeStamp { // data time stamp
               unsigned       MilisecondsInDay;
               unsigned char  Day;
               unsigned char  Month;
               unsigned short Year;
             };