Aktuální vydání

celé číslo

03

2021

Digitální transformace, chytrá výroba, digitální dvojčata

Komunikační sítě, IIoT, kybernetická bezpečnost

celé číslo

Programování v prostředí LabWindows a Microsoft C

Automa 1/2000

Ing. Tomáš Jakl, CSc.,
katedra měření FEL ČVUT Praha

Programování v prostředí LabWindows a Microsoft C

Obsahem tohoto článku jsou zkušenosti se spojením programů napsaných v prostředí Microsoft C a v prostředí LabWindows for DOS.

Ačkoli většina programátorů již přešla na platformu Windows, LabWindows for DOS má opodstatnění všude tam, kde je potřeba dodělat grafické uživatelské rozhraní k programům vytvořeným pro systém DOS. Taková úloha se může vyskytnout např. v souvislosti s rámem VXI, jehož zásuvné moduly mají v podpoře pouze knihovny pro DOS. Uživatelské rozhraní v prostředí LabWindows se skládá z panelů a nabídkových lišt.

Nejprve je třeba si uvědomit, že běh programu, který obsluhuje uživatelské rozhraní, je řízen událostmi, ovšem pouze událostmi jediného druhu, a to akcemi uživatele na uživatelském rozhraní. Zjednodušeně řečeno, každý zásah uživatele v uživatelském rozhraní je událostí, kterou program očekává. Program také nemusí očekávat událost u všech prvků uživatelského rozhraní. U některých prvků může pouze číst stavovou informaci. Co však není v uživatelské příručce LabWindows napsáno, je skutečnost, že uživatelské rozhraní pracuje podle pohybů myši, popř. stisků kláves, pouze je-li právě v běhu některá z funkcí knihovny uživatelského rozhraní – tzn. že program právě nemá nic jiného na práci než čekat na akci uživatele. Chce-li však programátor pouze testovat stav prvků uživatelského rozhraní poolingem (rozuměj: čtením stavu jednotlivých prvků), neuspěje, protože stav jednotlivých prvků sice načte, ale uživatelské rozhraní není funkční.

Někdy se stane, že programátor stojí před úkolem dodělat program grafického uživatelského rozhraní k programu, který je vytvořen např. v Microsoft C. Uživatelské rozhraní lze dobře tvořit v systému LabWindows a s použitím příslušných knihoven. Jak tedy pokračovat? Jednou z možností je předělat celý program a zdrojový text, který byl původně určen pro Microsoft C, přeložit do systému Lab Windows. Tato možnost, která na první pohled vypadá jednoduše, v podstatě znamená realizovat předem neurčené zásahy do celého programu, a tedy i nutnost zcela jej pochopit. Může se také stát, že prostředí Microsoft C přineslo některé výhody (např. datová pole velkého rozsahu), které v prostředí Lab Windows nejsou dostupné. To potom znamená úplnou rekonstrukci celého programu.

Druhou možností je zavést externí modul typu .OBJ, kterou nabízí prostředí LabWindows. Tuto funkci se však autorovi článku nepodařilo oživit.

Třetí, autorem článku doporučovanou možností je vytvořit z programu, který vznikl pod systémem Microsoft C, uživatelskou knihovnu a tu spojit s programem uživatelského rozhraní, který vznikl v prostředí LabWindows. Touto možností se budeme dále zabývat.

Takto mohou být oba programy vytvářeny ve svých původních prostředích a mohou být spojeny až v okamžiku sestavení programem LINK. Je samozřejmé, že programátor, který je zvyklý na komfortní testování svého programu v jednom nebo druhém prostředí, se bude muset svého pohodlí vzdát a vytvořit si vhodný dávkový soubor. Vhodný je dávkový soubor pro vytvoření knihovny z modulu, který vznikl pod Microsoft C, protože knihovní program LIB vyžaduje několik parametrů. Sestavit programy pak není možné (resp. vhodné) přímo v prostředí LabWindows, ale je nutné volat samostatně existující sestavovací program LWMAKE. Do tohoto programu se zadají všechny potřebné knihovny a program vytvoří spustitelný modul typu EXE.

Vzhledem k tomu, že program je řízen událostmi na uživatelském rozhraní, je vhodné, aby byl hlavní programový modul (main) obsažen v programu uživatelského rozhraní. Svázat proměnné v jednotlivých modulech lze bez větších problémů. Tohoto úkolu se lze zhostit např. tak, že globální proměnné se v modulu vytvářeném v prostředí Microsoft C deklarují pro třídu EXTERN a sestavovací program si s nimi už poradí.

Až dosud jsme se zabývali jednoduchým případem, kdy se z modulu vytvářeného v prostředí LabWindows, ve kterém je blok main, volají funkce z ostatních knihoven, tedy v podstatě funkce z prostředí LabWindows volají funkce z prostředí Microsoft C. Nyní se budeme zabývat případem opačným, kdy funkce z prostředí Microsoft C budou volat funkce z prostředí LabWindows.

Přímo volat knihovnu uživatelského rozhraní LabWindows z prostředí Microsoft C není možné kvůli problémům s deklarací druhého z parametrů ve volání funkcí uživatelského rozhraní, např.:
SetCtrlVal (panel_hdl, VXI_spousteni, 1);

Parametr VXI_spousteni se v prostředí LabWindows nedeklaruje, ale je-li volání uvedeno v prostředí Microsoft C, objeví se chyba, protože parametr není deklarován. Jak tedy tento problém vyřešit? Problém lze obejít, a to tak, že se v prostředí LabWindows vytvoří funkce, která volá funkci uživatelského rozhraní a která již může být volána z prostředí Microsoft C. Jako příklad uvádíme funkci popupprint:
void popupprint() { MessagePopup(jmeno_popup);}

Jak vypadá situace v prostředí Microsoft C? V modulu, jejž upravujeme, byly všechny výpisy směrovány na obrazovku, která pracovala v řádkovém módu. Tyto výpisy tedy předěláme na volání funkce z prostředí LabWindows tak, že původní tisk přesměrujeme do řetězcové proměnné, kterou předáme jako parametr. Původní řádek byl např.:
(void)printf {”e1430_set_decimation_filter() error: %d, %s”, error, e1430_get_error_string() };

a nové řádky vypadají takto:
(void)sprintf(jmeno_popup, ”e1430_set_decimation_filter() error: %d, %s”, error, e1430_get_error_string());
(void)popupprint();

Když už dokážeme volat funkce uživatelského rozhraní z prostředí Microsoft C, přímo se nabízí možnost vázat funkci v prostředí LabWindows na nějakou akci uživatele na uživatelském rozhraní. Podle očekávání funguje např.:
void popupprint() { MessagePopup(jmeno_popup);}

protože funkce MessagePopup spustí ovládač uživatelského rozhraní, který zaznamená stisknutí tlačítka myši na OK nebo stisk klávesy Enter.

Podstatně odlišná situace nastane při pokusu použít ve funkci pouze čtení stavu prvku uživatelského rozhraní v uzavřeném cyklu while, např.:
GetCtrlVal (panel_hdl, VXI_cekat, value_cekat);
while (value_cekat) {GetCtrlVal (panel_hdl, VXI_cekat, value_cekat);}

Přitom příkaz GetCtrlVal správně čte stav prvku uživatelského rozhraní. Ale při spuštění programu zjistíme, že uživatelské rozhraní nefunguje, nereaguje na události na klávesnici ani na tisknutí tlačítka myši. Tato konstrukce je tedy nepoužitelná. Příčinou je pravděpodobně skutečnost, že není v chodu žádná funkce uživatelského rozhraní, a tedy nepracuje ovládač uživatelského rozhraní, který má na starosti sledování událostí a činnost uživatelského rozhraní.

Autor článku se snažil „zkrotit“ dlouhý výpis na obrazovku, který byl v původním programu jednoduše vytvořen asi osmtisíckrát opakovaným voláním funkce printf bez jakéhokoli zastavování nebo možnosti přerušit jej. Zavedl jej tedy do grafického uživatelského rozhraní s možností zastavit nebo přerušit výpis. Základním problémem je jistě skutečnost, že výpis v původní podobě nedává téměř žádný smysl, ale konstrukce kvalitního prohlížeče takového souboru přesahuje původní úkol programu. Cílem celého programu totiž je sebrat data a uložit je do souboru. Kontrolní výpis celého souboru osmi tisíc hodnot na obrazovku je příliš pracný; kromě toho poskytne obsluze pouze strohou informaci v tom smyslu, že „v souboru něco je“. Co je však podstatné: celý výpis je volitelnou funkcí programu a poučený uživatel jej může vypnout. Chybou zůstává, že program takovou možnost vůbec nabízí. Ke kladům prostředí LabWindows patří, že takový výpis nepodporuje. Nechme však stranou otázku smyslu výpisu a podívejme se na technické možnosti.

Nepřerušitelný výpis mnoha řádků je možné řešit podle následujícího příkladu. V prostředí Microsoft C jsou příkazy:
(void) sprintf(retezec,”formátová specifikace”,...);
(void) listing();

V prostředí LabWindows je funkce:
(void) listing() {SetCtrlVal(panel_hdl,VXI_text, jmeno_popup);}

přičemž objekt VXI_text je typu Text Box Controls. Výsledkem je dosti pomalé, nepřerušitelné a nečitelné rolování textu v okně. Všechny pokusy o přerušení výpisu nebo jeho „přibrzdění“ selhaly, neboť bylo třeba číst stav nějakého prvku uživatelského rozhraní (např. radio button). Přitom však nepracoval ovládač uživatelského rozhraní, takže rozhraní nereagovalo ani na stisky kláves, ani na pohyby myši. Ponechat výpis jako nepřerušitelný nebylo možné, protože byl pomalejší než původní výpis opakovanými příkazy printf, a tedy neúnosně dlouhý.

Uvádíme zde ještě řešení výpisu, ve kterém knihovna uživatelského rozhraní LabWindows zcela uvolnila obrazovku pro původní výpis opakovanými příkazy printf. V prostředí Microsoft C jsou tyto příkazy:
startlistprint();
{(void)printf(”%ld: %10.6f %10.6f %10.6f %10.6f ”, poradi, (double)dataBuffer[i+0], (double)dataBuffer[i+1], (double)dataBuffer[i+2], (double)dataBuffer[i+3] );}
while
(zbyva_precist>=BUFFER_ SIZE);
stoplistprint();

V prostředí LabWindows jsou funkce:
void startlistprint()
{ int status; status=CloseInterfaceManager();}
void stoplistprint() { int status, control; status = OpenInterfaceManager();
panel_hdl = LoadPanel (”treti.uir”, VXI);
if (panel_hdl < 0)
{
FmtOut(”Nemohu precist panel ze zdrojoveho textu. ”);
return;}
bar_hdl = LoadMenuBar (”treti.uir”, bar);
if (bar_hdl < 0) { FmtOut(”Nemohu precist menu ze zdrojoveho textu. ”);
return;}
status = DisplayPanel (panel_hdl);
if (!CompareStrings(value_rozs, 0,”+- 8.0V”,0,0)) val_rozs=0;
if (!CompareStrings(value_rozs, 0,”+- 4.0V”,0,0)) val_rozs=1;
..........
SetCtrlVal (panel_hdl, VXI_frekvence, value_frekvence);
SetCtrlVal (panel_hdl, VXI_popis, value_popis);
}

Výpis funkce stoplistprint je zkrácen. Podstatné je, že zatímco funkce startlistprint ukončí činnost uživatelského rozhraní a přepne obrazovku do textového módu, funkce stoplistprint musí zapnout uživatelské rozhraní a uskutečnit celé úvodní nastavení. Uvedené řešení je nejméně pracné a nejméně komplikované.

Poznamenejme, že možnost celého výpisu na obrazovku opakovanými příkazy printf byla nakonec uzavřena do komentáře a ponechána pro eventuální ladění programu.

Na závěr konstatujme, že kombinace programů, které vznikly v různých prostředích, je vhodná v okamžiku sestavování programu a nepřináší žádné zvláštní obtíže.

(Metodika byla použita při řešení grantu GACR č. 102/99/0775)