Vývoj USB ovládača – 5. časť
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Vývoj USB ovládača – 5. časťVývoj USB ovládača – 5. časť

 
Hledat
Moderní platforma pro vytvoření vašeho nového webu – Wix.com.
Nyní už můžete mít web zdarma.
Vybavení pro Laser Game
Spuštěn Filmový magazín

Vývoj USB ovládača – 5. časť

Google       Google       18. 11. 2013       16 784×

V tejto časti si vytvoríme GUI klientsku aplikáciu v jazyku C#, ktorej základom bude rozhranie na komunikáciu medzi ovládačom zariadenia a .Net aplikáciou vytvorené s pomocou PInvoke (Platform Invoke).

Reklama
Reklama

Úvod

V tomto kroku máme funkčné USB zariadenie a ovládač s ním komunikujúci pomocou libusb. Ďalším krokom je vytvorenie koncovej aplikácie, pomocou ktorej môže používateľ hardvér ovládať. Pre zmenu som si vybral platformu .NET a jazyk C#, vďaka ktorým bude jednoduchšie demonštrovať princípy.

Aplikácia bude tvorená jedným oknom, v ktorom sa bude zobrazovať stav tlačidiel na zariadení, teplota procesora a napätie na potenciometri. Taktiež bude obsahovať prvky na ovládanie LED diód, na vypísanie textu a odoslanie bitmapy na LCD. Pri vytvorení okna sa aplikácia pokúsi otvoriť spojenie s USB zariadením; pokiaľ zariadenie nebude pripojené, skončí s chybovým hlásením.

Celú komunikáciu so zariadením vložíme do jedného objektu, ktorý bude pomocou P/Invoke (Platform Invoke) komunikovať s natívnou knižnicou ovládača vytvorenou v minulom dieli tohto seriálu. Tento objekt alebo wrapper sa bude taktiež starať o spracovanie vzniknutých chýb a namiesto číselných hodnôt vrátených ovládačom vyhodí príslušnú výnimku.

P/Invoke – Platform Invoke

Pokiaľ v .NET programujete už nejaký ten čas, je dosť možné, že ste sa stretli s potrebou importovať funkcie natívnych knižníc. V C/C++ by ste toho dosiahli jednoducho prilinkovaním knižnice k vášmu programu alebo by ste knižnicu načítali pomocou funkcie LoadLibrary, získali adresu funkcie volaním GetProcAddress a pretypovaním by vám vznikol odkaz na funkciu, ktorú by ste zavolali ako každú inú. V .Net to ale funguje trochu inak, na volanie funkcií v natívnych knižniciach musíme využiť DllImport (System.Runtime.InteropServices v knižnici System.Core).

V prvom kroku si v zdrojovom súbore zadeklarujeme použitie názvoslovia:

using System.Runtime.InteropServices;

Potom nám stačí v triede deklarovať statickú metódu nasledovným spôsobom:

/// <summary>
/// Vyčistí obrazovku jednou farbou
/// </summary>
/// <param name="color">Farba</param>
/// <returns></returns>
[DllImport("DeviceWrapper.dll",
 CallingConvention = CallingConvention.Cdecl)]
private static extern uint ClearScreen(uint color);

Čím prekladač vie, že metóda ClearScreen je externá a nachádza sa v knižnici DeviceWrapper.dll (to je náš ovládač). Každá takto vložená funkcia musí byť označená ako static extern s atribútom DllImport.

Naša klientska aplikácia bude importovať všetky funkcie exportované v ovládači DeviceWrapper, nebudú sa ale používať priamo. Napr. funkcia ClearScreen preberá jeden argument, ktorým je 24bitové číslo reprezentujúce farbu. Návratová hodnota je taktiež číslo (0 v prípade, že funkcia uspeje alebo iná hodnota popisujúca chybu). My ale túto metódu zabalíme v objekte (wrapper) tak, aby parameter farby nebol číslo, ale typ System.Color, a odstránime návratový typ, zmeníme ju na void. V prípade, že volanie funkcie ClearScreen z knižnice DeviceWrapper.dll zlyhá, nevrátime volajúcemu kód chyby, ale vyhodíme výnimku. Je to omnoho prijateľnejší spôsob. Týmto spôsobom dosiahneme to, aby bola metóda ClearScreen volaná vždy v správnom kontexte.

/// <summary>
/// Vyčistí obrazovku
/// </summary>
/// <param name="color">Farba</param>
public void ClearScreen(Color color)
{
    // Spojenie so zariadením musí byť otvorené
    if (!isOpen)
        throw new DeviceFailException(
            DeviceFailException.DeviceError.NotOpen);

    // Zavolať funkciu ClearScreen z DeviceWrapper.dll
    uint result = ClearScreen((uint)color.ToArgb());

    // Pokiaľ volanie zlyhalo, vyhodíme výnimku s kódom chyby
    if (result != 0)
        throw new DeviceFailException(
            (DeviceFailException.DeviceError)result);
}

Rozhranie na komunikáciu s ovládačom

Základ aplikácie bude tvorený jedným objektom – rozhraním na komunikáciu s ovládačom. Pri štarte aplikácie sa vytvorí inštancia tohto objektu, otvorí sa spojenie s USB zariadením a ďalšia komunikácia s ním už bude prebiehať iba pomocou tohto objektu. Pri ukončení aplikácie sa objekt odstráni, tým sa zatvorí spojenie s ovládačom a zariadením. Na obrázku je znázornené, aké metódy bude objekt obsahovať a ďalšie pomocné štruktúry, triedy a dátové typy.

Je dôležité uvedomiť si, že dátové štruktúry (pakety) sú rovnaké pre zariadenie, ovládač aj koncovú aplikáciu. Preto pri vývoji ovládača pracujeme s rovnakými dátovými typmi v zariadení aj na strane hosta. Táto klientska aplikácia definuje štyri takéto štruktúry, a to usbapp_bulk_out_t, usbapp_control_in_t, usbapp_control_out_t a usbapp_interrupt_in_t.

Ďalej potrebujeme definovať výnimky, ktoré objekt vyhodí pri chybnej komunikácii alebo pri nesprávnom použití rozhrania. Na to nám budú slúžiť dve triedy, DeviceFailException, ktorá bude vyhodená, ak dôjde k chybe v ovládači alebo zariadení, a DeviceNotOpenException, ktorú rozhranie vyhodí, ak sa programu nepodarí nadviazať spojenie so zariadením.

Nakoniec zadefinujeme štruktúry a enumy, ktoré poskytnú informácie z paketov cieľovému používateľovi rozhrania. Ako príklad uvediem nastavenie LED a LCD.

Aplikácia potrebuje odoslať zariadeniu príkaz, aby rozsvietilo modrú a zelenú LED diódu, zaplo LCD displej a taktiež aby posunulo obsah LCD displeja o 50 px. Keďže každé nastavenie v pakete je číselné, užívateľ nášho rozhrania by musel poznať, aké čísla pripadajú na modrú a zelenú LED. Taktiež by musel vedieť, akým príznakom zapne LCD displej. Preto je dôležité, aby naše rozhranie tieto čísla skrylo za enum dátové typy ako napr. zoznam LED diód a ich číselné hodnoty:

/// <summary>
/// Nastavenia LED diód
/// </summary>
public enum Led
{
    None = 0,
    Blue = 0x1,
    Green = 0x2,
    Amber = 0x4
};

Potom môže užívateľ jednoduchým spôsobom zostaviť nastavenia a odoslať ich zariadeniu:

// Vytvoriť nastavenie LED a LCD
Device.LedLcdOptions ledLcd = new Device.LedLcdOptions(
    Device.Led.Blue | Device.Led.Green, // Modrá a zelená LED
    0, // Oranžová nebude svietiť
    Device.DisplayOption.DisplayOn, // Zapnúť LCD displej
    0, // Displej nebude podsvietený
    50); // Obsah displeja bude posunutý o 50 px
 
// Odoslať nastavenie zariadeniu
device.SetupLedLcd(ledLcd);

Metóda Device.SetupLedLcd(LedLcdOptions options) skontroluje, či je spojenie na zariadenie otvorené a ak áno, zostaví paket usbapp_control_out_t z nastavení, ktoré užívateľ predal ako argument options. Zároveň skontroluje platnosť nastavení a to, či hodnota PWM a hodnota podsvietenia LCD displeja neprekročia max. hodnoty stanovené USB zariadením. Následne paket posunie ovládaču volaním funkcie SetupDevice z knižnice ovládača DeviceWrapper.dll.
Tá vytvorí USB paket, jeho dáta naplní obsahom štruktúry usbapp_control_out_t a odošle ho zariadeniu, ktoré paket prijme a spracuje. Akonáhle host potvrdí príjem paketu zariadením, funkcia SetupDevice vráti hodnotu určujúcu, či prenos prebehol v poriadku alebo sa vyskytla chyba.

Naše rozhranie túto vrátenú hodnotu porovná a pokiaľ zistí, že počas prenosu nastala chyba, vyhodí výnimku.

/// <summary>
/// Nastavi LED a LCD
/// </summary>
/// <param name="options">LED a LCD nastavenia</param>
public void SetupLedLcd(LedLcdOptions options)
{
    if (!isOpen)
        throw new DeviceFailException(
            DeviceFailException.DeviceError.NotOpen);
 
    // Vytvoriť paket obsahujúci nastavenia LED a LCD
    usbapp_control_out_t data = new usbapp_control_out_t();
    data.leds = options.Leds;
    data.pwmLedDuty = options.PwmLedDuty > MaxPwm ?
        MaxPwm : options.PwmLedDuty;
    data.display = options.LcdOptions;
    data.backlight = options.Backlight > MaxBacklight ?
        MaxBacklight : options.Backlight;
    data.displayScroll = options.LcdScroll;

    // Posunúť paket ovládaču, ktorý ho odošle
    uint result = SetupDevice(ref data);

    // Vyhodiť výnimku ak počas prenosu vznikla chyba
    if (result != 0)
        throw new DeviceFailException(
            (DeviceFailException.DeviceError)result);
}

Obdobným spôsobom trieda Device poskytuje prístup k ostatným funkciám ovládača. V princípe je potrebné iba „zabaliť“ volania ovládača takým spôsobom, aby klientska aplikácia na platforme .NET mohla využívať tieto metódy v súlade s konvenciami .NET a taktiež aby bolo možné spracúvať výnimky namiesto chybových kódov.

Front end – používateľské rozhranie

Na otestovanie funkčnosti poslúži jednoduchá GUI aplikácia, ktorá pri svojom štarte skontroluje, či je k počítaču pripojené naše zariadenia a ak áno, vytvorí klientske rozhranie pre komunikáciu s týmto zariadením. Používateľ tak bude mať možnosť jednoducho odosielať príkazy zariadeniu pomocou nami vytvoreného rozhrania.

Komunikácia bude pozostávať z troch častí:

  1. Príkazy odosielané klientom do zariadenia – nastavenie LED a vykresľovanie na LCD
  2. Pravidelná aktualizácia hodnôt z ADC prevodníka
  3. Vlákno bežiace na pozadí aplikácie čakajúce na prerušenia zo strany zariadenia

Keďže väčšinu práce bude mať na starosti rozhranie v triede Device, GUI aplikácii zostáva konvertovať vstupné hodnoty od používateľa a zobrazovať výstup zo zariadenia a čo je podstatnejšie, spracovanie chýb. V našom prípade pri vzniku chyby program zobrazí bližšie informácie o príčine vzniku chyby a následne sa ukončí.

Záver

A na záver si môžete stiahnuť zdrojový kód aplikácie a pozrieť ukážku toho, ako zariadenie a klientska aplikácia fungujú v praxi:

×Odeslání článku na tvůj Kindle

Zadej svůj Kindle e-mail a my ti pošleme článek na tvůj Kindle.
Musíš mít povolený příjem obsahu do svého Kindle z naší e-mailové adresy kindle@programujte.com.

E-mailová adresa (např. novak@kindle.com):

TIP: Pokud chceš dostávat naše články každé ráno do svého Kindle, koukni do sekce Články do Kindle.

2 názory  —  2 nové  
Hlasování bylo ukončeno    
3 hlasy
Google
Autor sa venuje programovaniu v jazykoch C#, C/C++, Delphi a v poslednej dobe sa taktiež zaujíma o vývoj hardvéru.
Web    

Nové články

Obrázek ke článku NopCommerce – dervisní vrstva – 3. díl

NopCommerce – dervisní vrstva – 3. díl

V minulém díle jsme se podívali trochu podrobněji na datovou vrstvu systému NopCommerce. V dnešním díle navážeme na předchozí znalosti, aby se naše pochopení systému zase o něco víc prohloubilo. Zaměříme se na dvě důležité oblasti a to Nop.Core projekt, který udržuje nejen doménu, ale obsahuje i infrastrukturní prvky. Dále se podíváme na projekt Nop.Service, který obsahuje obchodní logiku.

Reklama
Reklama
Obrázek ke článku První český hackathon ve vlaku inspirovaly služby jako  Tinder, Airbnb nebo Uber

První český hackathon ve vlaku inspirovaly služby jako Tinder, Airbnb nebo Uber

Patnáct set kilometrů, cesta přes dva státy, šestnáct hodin programování a přísun energy drinků, tak by se dal shrnout unikátní hackathon ve vlaku pořádaný Kiwi.com. Z Prahy do Košic a zpět se svezlo celkem 13 týmů, každý s originálním nápadem. Hlavní výhru, voucher na letenky v hodnotě 2 500 EUR, si v Praze převzal tým až z Ukrajiny.

Obrázek ke článku Gamifikace nakupování dorazila i do České republiky

Gamifikace nakupování dorazila i do České republiky

Zákazníci zejména retailových společností jsou často znuděni klasickými věrnostními či motivačními programy. Většinou z toho důvodu, že jsou jeden jako druhý a nepřináší nic nového. Ale i v České republice se projevují zahraniční trendy, nedávno zde totiž vstoupila na trh a rychle se uchytila nová platforma kombinující to nejlepší z věrnostních a motivačních programů, která navíc využívá prvky gamifikace – Rondo.cz. Na hlavní milníky vývoje nálad a motivace zákazníků a nejnovější trendy se zaměřil Jan Hřebabecký, spoluzakladatel Rondo.cz

Celý článekGoogle2. listopadu 2017PR

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032018 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý