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

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

 

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

Google       Google       14. 1. 2013       54 057×

USB je dnes najrozšírenejším rozhraním používaným k pripojeniu zariadení či už k počítaču, alebo medzi sebou. V tomto seriáli si ukážeme, ako sa postupne dopracovať k USB ovládaču, ktorý bude komunikovať s našim zariadením. Tým bude vývojová doska osadená mikroprocesorom s architektúrou ARM Cortex-M3, Atmel SAM3X8H. V prvej časti sa budeme venovať princípu, ako USB funguje a taktiež základným pojmom, s ktorými sa pri práci s USB stretnete a je potrebné ich vedieť.

Predtým než začneme, je potrebné podotknúť, že v tomto seriáli sa vyskytnú časti, v ktorých sa bude programovať samotný mikroprocesor pomocou C, preto by ste ho mali brať s nadhľadom a použiť ako všeobecný podklad. Podpora platformy je u rôznych výrobcov mikroprocesorov rozličná, cieľom ani požiadavkou nie je, aby mal čitateľ k dispozícii zariadenie, ktoré je možné naprogramovať.

Celý seriál bude rozdelený do niekoľkých častí. V prvej sa oboznámite so základnými pojmami a princípmi USB. V ďalších častiach sa dozviete, ako naprogramovať mikroprocesor, ktorý bude vedieť rozsvecovať 3 LED diódy (jedna z nich s meniteľnou intenzitou), kresliť na LCD, prečítať teplotu procesora a vstupu na prevodníku ADC a detekovať dotyky (pomocou QTouch) a kliknutia. Nakoniec si ukážeme, ako vytvoriť ovládač pomocou UMDF (User-Mode Driver Framework) a libusb.

Základné pojmy a skratky

Tu je zopár základných pojmov, s ktorými sa počas vývoja USB zrejme stretnete. Je dobré ich vedieť rozlíšiť, neskôr to celé do seba zapadne ako puzzle. Niektoré z nich budú popísané neskôr, keď príde čas ich použiť, ďalšie sa k zoznamu pridajú neskôr.

  • USB – Universal Serial Bus
  • VID – Vendor ID – číslo identifikujúce výrobcu USB zariadenia
  • PID – Product ID – číslo identifikujúce výrobok
  • PID – Packet ID – typ USB paketu
  • OTG – USB On-The-Go – štandard umožňujúci zariadeniu správať sa ako zariadenie alebo host
  • SOF – Start-of-Frame – paket, ktorý posiela host zariadeniam aby predišiel „suspend“ módu, ktorý nastáva, ak zariadenie dlhšiu dobu nekomunikuje
  • Endpoint – taktiež aj ENDP, je virtuálna adresa v zariadení, na ktorú host posiela dáta. Akékoľvek dáta smerujúce do zariadenia sú vždy určené endpoint-u.
  • Descriptor – deskriptor, ktorý poskytuje hostovi informácie o zariadení, napr. názov zariadenia, počet rozhraní a endpointov a pod.
  • Host – spravuje USB zbernicu, všetky zariadenia sa pripájajú k hostovi
  • Unit load - jednotka odberu prúdu zo zbernice (100 mA)
  • LS - Low Speed
  • FS - Full Speed
  • HS - High Speed

Ako funguje USB

Keďže našou úlohou je vyvinúť USB ovládač a naprogramovať zariadenie, aby vedelo komunikovať pomocou USB protokolu, nemusíme poznať elektrické vlastnosti USB do detailu, postačí základ. Na strane PC (hostu) sa o samotnú komunikáciu starajú ovládače USB zbernice, v mikroprocesore sa nachádzajú vrstvené služby, vďaka ktorým sa môže vývojár sústrediť na to, čo má aplikácia robiť, a nie na to, ako má mikroprocesor kódovať bity pri prenose USB.

Zbernica USB je vždy kontrolovaná hostom. To je jeden z najdôležitejších poznatkov pri práci s USB. Nech pomocou USB potrebujete poslať alebo prijať dáta, vždy o tom rozhodne a komunikáciu zaháji až host. Na rozdiel od procesorov, ktoré sa interruptom (prerušeniam) venujú ihneď, ako nastanú, vyvolanie prerušenia vo vašom zariadení (napr. kliknutie tlačidla myši) sa k hostovi dostane až vtedy, keď si ho host vyžiada.

Fyzická topológia USB je vrstvená hviezda. Môžete si to predstaviť ako pyramídu, na vrchole sídli host, ktorý je len jeden a ovláda celú USB zbernicu. Pod ním sa nachádzajú ďalšie vrstvy, na ktorých sú buď zariadenia alebo tzv. huby (pozn. nie tie jedlé :D). Keďže USB podporuje max. 127 pripojených zariadení (vrátane hubov) a ťažko by ste na ktoromkoľvek PC hľadali 127 konektorov USB, Hub-y umožňujú port rozšíriť o ďalšie. Pokiaľ vo svojom zapojení použijete hub, pridáte tým ďalšiu vrstvu do pyramídy.

Verzie a prenosové rýchlosti – najnovšia verzia je USB 3.0, väčšina dnešných počítačov a zariadení však obsahuje minimálne jeden USB 2.0 port. Čo sa týka rýchlostí, USB pozná tieto štyri:

  • Low speed – 1,5 Mbit/s (USB 1.0)
  • Full speed – 12 Mbit/s (USB 1.0)
  • High speed – 480 Mbit/s (USB 2.0)
  • Super speed – 4,8 Gbit/s (USB 3.0)

USB 2.0 podporuje aj LS a FS (Low speed a Full speed), USB 3.0 je kompatibilné s USB 2.0 zariadeniami a konektormi.

Logická topológia

Na rozdiel od fyzickej topológie, software komunikujúci so zariadením nerozlišuje, na ktorej vrstve sa zariadenie nachádza, ale používa jeho adresu, ktorú mu host priradil. Okrem adresy sa používa aj takzvaný endpoint čiže „ukončenie komunikácie v zariadení“. Môžete si to predstaviť ako ďalšiu virtuálnu adresu v samotnom zariadení, na ktorú host posiela alebo z nej prijíma dáta. Tým sa vytvorí virtuálny pipe (po anglicky rúra, vedenie) medzi hostom resp. ovládačom na počítači a endpointom v zariadení. To môže mať hneď niekoľko endpointov rôznych typov a smerov. Typ endpointu (tzn. na aký prenos sa použije) je daný prenosovým módom. Tie môžu byť:

  • Control / Setup – kontrolné dáta, ktorými sa USB zariadenie nastavuje alebo poskytuje informácie o sebe. Zariadenie po pripojení na zbernicu pomocou tohto typu odošle hostovi informácie o svojej konfigurácii, napr. názov zariadenia, aké endpointy podporuje apod.
    Veľkosť paketu pre LS zariadenia musí byť 8 bajtov, pre FS 64 bajtov a HS povoľuje pakety dĺžky 8, 16, 32 a 64 bajtov.
  • Interrupt – prenos súvisiaci s interruptom (prerušením), ktoré vznikne buď v zariadení, alebo v hostovi. Príkladom môže byť myš, ktorá vyvolá interrupt, keď s ňou pohnete. Senzor zaregistruje zmenu, vyvolá interrupt, ktorý čaká na svojom endpointe, až si ho host prevezme. Ten ho následne predá ovládaču a ten operačnému systému, potom vidíte ako sa pohne kurzor na obrazovke. Pri tomto type je dôležité, aby boli doručené v čo najkratšom možnom čase a mali prednosť pred bulk a isochronous prenosmi.
    Max. veľkosť dát (payload) je pre LS zariadenia 8 bajtov, FS 64 bajtov a pre HS 1024 bajtov.
  • Bulk – malé nepravidelne posielané dáta. Ako príklad si vezmeme tlačiareň, ktorej host odosiela dáta pomocou tohto prenosu. Pri tomto type je dôležité, aby dáta, ktoré sa prenášajú, boli prenesené správne. Pokiaľ počas prenosu vznikne chyba, host prenos opakuje. Uprednostňuje sa kvalita pred rýchlosťou. Bulk prenosy sú tie posledné, na ktoré sa dostane pri komunikácii cez USB, prednosť majú všetky ostatné.
    Max. payload je pre FS zariadenia 8, 16, 32 alebo 64 bajtov, HS zariadenia majú max. 512 bajtov. Low speed zariadenia bulk prenos nepodporujú.
  • Isochronous – streamy (toky dát), pri ktorých je dôležité, aby boli doručené čo najskôr. Chyby sa počas prenosu nekontrolujú, pretože ak by aj chyba vznikla, prenos nebude opakovaný. Využitie nájde v prenose audio/video streamov.
    Max. payload je 1023 bajtov pre FS zariadenia a 1024 bajtov pre HS.

Smer endpointu môže byť:

  • In – zariadenie posiela dáta hostovi
  • Out – host posiela dáta zariadeniu

Ako pri vývoji ovládačov, tak i pri programovaní zariadenia sa vždy stretnete s používaním rovnakého označenia smeru prenosu. Pre host je logické použiť OUT, ak chce dáta odoslať zariadeniu, a IN, ak chcete tieto dáta prijať. V zariadení, ktoré budeme programovať, sa ale bude používať OUT pre dáta, ktoré chce zariadenie prijať, a IN pre dáta, ktoré chce odoslať. Keďže host je el numero uno, ten, ktorý riadi USB zbernicu, podriadime sa jeho terminológii tak, aby ak použijeme OUT v zariadení alebo ovládači, budeme tým mať na mysli vždy smer od hosta k zariadeniu.

Je dôležité poznamenať, že každé zariadenie má minimálne jeden endpoint s adresou 0 (nultý endpoint), ktorý podporuje smer IN a OUT. Host ho používa na posielanie kontrolných paketov. Zariadenie potom môže alebo nemusí definovať ďalšie endpointy.

Naše zariadenie bude podporovať tri prenosové módy – interrupt, bulk a control. Interrupt bude smeru IN, to znamená, že bude posielať dáta hostovi, a pošle ich vtedy, keď sa používateľ dotkne tlačidla na vývojovej doske. Control použijeme v dvoch smeroch. OUT bude slúžiť hostovi na posielanie dát, ktorými sa nastavia LED diódy, obrazovka a podsvietenie. IN využije host, ak bude chcieť získať informáciu o teplote mikroprocesora. Prenos pomocou bulk módu bude smerom OUT, host bude zariadeniu posielať obrázok alebo text, ktorý má zariadenie vykresliť na obrazovku.

Logická topológia

Na tomto obrázku môžete vidieť ďalší pojem, a to rozhranie (alebo interface). Rozhranie zlučuje určité funkcie zariadenia (endpointy) do jednej skupiny. Rozhranie je zároveň zaradené pod konfiguráciu. Konfigurácia zariadenia sa dá chápať ako zoskupenie rozhraní. Informuje hosta o tom, koľko rozhraní obsahuje, či je zariadenie napájané zo zbernice alebo má externé napájanie a aký má odber prúdu. Väčšinou má zariadenie jednu konfiguráciu, avšak môže nastať situácia, kedy bude mať konfigurácií viacero. Ak má zariadenie napríklad dve konfigurácie, jedna je nastavená ako „bus-powered“ (napájané zo zbernice) a druhá ako „self-powered“ (napájané externým zdrojom) a host sa rozhodne, že nemôže povoliť ďalšiemu zariadeniu vysoký odber prúdu zo zbernice, zvolí tú konfiguráciu, ktorá je self-powered.

Zoberme si jednoduchú myš. Keďže každé USB zariadenie má minimálne jeden kontrolný endpoint, naša myš bude mať endpointy nasledovné:

  • EP0 IN – kontrolný endpoint, pre odosielanie informácií hostovi

  • EP0 OUT – kontrolný endpoint, pre prijímanie informácií od hosta

  • EP1 INTERRUPT IN – interrupt endpoint, pomocou ktorého myš odosiela hostovi zaregistrované pohyby myšou

Tieto tri endpointy sú zaradené pod jedným rozhraním, keďže myš má iba jeden účel. Pri pripojení myši na zbernicu si host vyžiada deskriptor zariadenia (obsahuje verziu USB protokolu, VID a PID, výrobcu, počet konfigurácií apod.). Následne si vyžiada každú konfiguráciu, ktorá obsahuje aj zoznam rozhraní. Naša myš bude mať jednu konfiguráciu, v nej jedno rozhranie a v ňom 3 endpointy. Pokiaľ to chcem povedať ľudskou rečou: host si najskôr zistí, aké má možnosti konfigurácie. Keď myš poskytne len jednu konfiguráciu, zvolí tú. V tejto sa nachádza jedno rozhranie, ktoré host rozpozná ako HID Mouse. Kontrolný endpoint 0 použije host na to, aby od zariadenia získal informácie alebo mu ich poslal. Endpoint 1 použije ovládač HID myši na zisťovanie pohybu myšou. Takúto myš môj počítač vidí nasledovne:

Device Descriptor:
bcdUSB:             0x0200
bDeviceClass:         0xEF
bDeviceSubClass:      0x02
bDeviceProtocol:      0x01
bMaxPacketSize0:      0x40 (64)
idVendor:           0x04F2 (Chicony Electronics Co., Ltd.)
idProduct:          0xB071
bcdDevice:          0x1515
iManufacturer:        0x02
iProduct:             0x01
iSerialNumber:        0x03
bNumConfigurations:   0x01

ConnectionStatus: DeviceConnected
Current Config Value: 0x01
Device Bus Speed:     High
Device Address:       0x01
Open Pipes:              1

Endpoint Descriptor:
bEndpointAddress:     0x83  IN
Transfer Type:   Interrupt
wMaxPacketSize:     0x0010 (16)
bInterval:            0x06

Princíp prenosu dát

Už vieme, že každý prenos po USB zbernici je inicializovaný hostom. Aby zariadenia, ktoré sú pripojené na zbernici, vedeli, či je paket určený im, host začína každý prenos pomocou token paketu. Ten so sebou nesie adresu zariadenia, adresu endpointu (v adrese je zahrnutý aj smer) a typ paketu, ktorý bude nasledovať. Nasledujú dátové pakety (pokiaľ nejaké sú) a prenos je ukončený handshake paketom, v ktorom je informácia o tom, či prenos prebehol správne, či zariadenie dáta prijalo apod. Keď si to zhrnieme, USB používa tieto typy paketov:

  • Token – inicializuje prenos, obsahuje adresu zariadenia, smer a adresu endpointu a informáciu, čo bude nasledovať
  • Data – dátový paket
  • Handshake – potvrdenie prenosu/oznámenie chyby
  • SOF – Start-of-Frame paket generovaný hostom, pri High speed každých 125µs, Full speed 1ms, Low speed SOF nepoužíva, namiesto toho host vygeneruje keep alive signál každú milisekundu. Zariadenia používajú SOF pakety ako prevenciu pred vstúpením do suspend módu. Pri tomto móde zariadenie nesmie zo zbernice odoberať viac ako 500µA pre 1 unit load (jednotka odberu, 100 mA).
Zloženie USB paketov

V hornom obrázku môžete vidieť, aké údaje obsahujú pakety používané USB.

  • Sync – použitý na synchronizáciu hodín zariadenia s hostom. Low a Full speed používa 8 bitov, High speed 32 bitov
  • PID – Pakcet ID, určuje typ paketu
  • Addr. – Address (adresa) zariadenia
  • Endp. – Endpoint
  • Data – dáta paketu, tzv. payload
  • Frame number – 11bitové poradové číslo
  • CRC5 – kontrolný súčet
  • CRC16 – kontrolný súčet

Vo všeobecnosti je možné prenos dát medzi hostom a zariadením znázorniť ako na obrázku uvedenom pod týmto odsekom.

Pokiaľ host odosiela dáta zariadeniu, inicializuje prenos pomocou token paketu OUT. Za ním nasleduje paket obsahujúci dáta, ktoré host odosiela. Zariadenie tieto informácie prijme a podľa toho, či bol prenos úspešný alebo boli dáta (ne)spracované, odpovie pomocou handshake paketu. V niektorých prípadoch môže nastať situácia, kedy zariadenie hostovi odpovedať nemusí (dátový paket bol porušený).

V prípade, ak host vyžaduje dáta od zariadenia, ten inicializuje prenos pomocou token paketu IN. Následne by malo zariadenie odoslať dáta alebo rovno handshake paket (v zariadení vznikla chyba, pre ktorú dáta nie je možné spracovať apod.). Pokiaľ zariadenie dáta odošle, host musí potvrdiť príjem dát pomocou handshake paketu. Aj v tomto prípade platí, že zariadenie nemusí hostovi odpovedať, napr. ak je paket token IN chybný.

Princíp prenosu dát

Pre rôzne prenosové módy sa diagram a postup líši, pre viac informácií si pozrite priložený PDF dokument, ktorý obsahuje diagramy spolu s vysvetlením ku všetkým prenosovým módom. Tieto informácie môžete taktiež nájsť v rozšírenej forme aj na stránke http://www.beyondlogic.org/usbnutshell/usb4.shtml.

Deskriptory

Poslednou témou, ktorej sa v tejto časti budeme venovať, sú takzvané deskriptory. Z angličtiny je možné výraz descriptor voľne preložiť ako niečo, čo poskytuje popis, vlastnosti, charakteristiku. Môžete si ich predstaviť ako malé štruktúry informácií slúžiacich hostovi na získanie informácií o zariadení alebo jeho nastaveniu. USB má niekoľko typov deskriptorov:

  • Deskriptor zariadenia – je to základný deskriptor, ktorý poskytuje hostovi informácie o verzii USB, ktorú zariadenie podporuje, triede, do ktorej je možné zariadenie zaradiť, VID (Vendor ID), PID (Product ID), verziu zariadenia, počet konfigurácií, index textových hodnôt názvu zariadenia a mena výrobcu a iné.
  • Deskriptor konfigurácie – poskytuje hostovi informácie o počte rozhraní konfigurácie, o max. odbere prúdu zo zbernice (ak bude konfigurácia aktivovaná), o nastaveniach konfigurácie apod. Zariadenie odosiela tento deskriptor spolu s deskriptormi rozhrania (ktoré taktiež odosielajú svoje endpointy).
  • Deskriptor rozhrania – poskytuje informácie o rozhraní ako napr. trieda rozhrania, počet endpointov apod. Ak vaše zariadenie obsahuje viacero rozhraní, nazýva sa composite device. Pokiaľ máte doma alebo v práci tlačiareň so skenerom, tak s najväčšou pravdepodobnosťou obsahuje dve rozhrania. Jedno slúži tlačiarni, druhé skeneru. Váš počítač je následne schopný vám ponúknuť dve zariadenia na používanie, aj napriek tomu, že máte fyzicky pripojené iba jedno.
    Keď sa zmieňujeme o triede rozhrania, myslíme tým identifikátor, ktorý môže host použiť, aby našiel vhodný ovládač. Príkladom môže byť taká myš, ktorá môže mať svoju triedu rozhrania/zariadenia nastavenú na HID (Human Interface Device), tým pádom host vie použiť predvolený ovládač pre štandardné myši. Naše zariadenie bude používať triedu 0xFF (Vendor Specific – umožňuje nám zariadenie naprogramovať podľa našich predstáv, bez predvolených ovládačov). Každé rozhranie môže mať alternatívne nastavenie, ktoré v našom prípade využijeme, aby sme dali vedieť nášmu zariadeniu, že ovládač je pripravený komunikovať.
  • Deskriptor endpointu – poskytuje informácie o adrese, smere a type endpointu, max. veľkosti paketu, ďalšie vlastnosti endpointu a o intervale, v ktorom host kontroluje dáta na IN endpointe pre interrupt a isochronous prenosy.
  • Textový deskriptor – pokiaľ zariadenie používa text na označenie názvu, mena výrobcu apod., tak pomocou tohto deskriptoru odosiela hostovi text.

Akonáhle host dostane deskriptor zariadenia, získa jeho názov pomocou textového deskriptora. Vie koľko konfigurácií zariadenie obsahuje, môže si tak vyžiadať každú konfiguráciu a rozhranie, ktoré zariadenie poskytuje. Následne sa zvolí tá správna konfigurácia, zvolí sa rozhranie a zariadenie je pripravené na použitie. To, aké endpointy budú aktívne, závisí od toho, ktorú konfiguráciu a rozhrania si host zvolí.

Niektorým deskriptorom sa budeme venovať pri programovaní mikroprocesora, ukážeme si ich štruktúru a aké informácie obsahujú. Pre podrobnejšie informácie o deskriptoroch môžete navštíviť stránku http://www.beyondlogic.org/usbnutshell/usb5.shtml.

Elektrické vlastnosti a konektory

USB prenáša dáta sériovo. To znamená, že v jeden okamih môže byť na zbernici jeden bit. Paralelné zbernice (ako napr. LPT) prenášajú dáta paralelne, čiže v jeden okamih je na zbernici viacero bitov (pri LPT je to jeden bajt). Na prenos sa používa diferenciálna signalizácia pomocou D+ a D-, vyhodnocuje sa rozdiel napätí medzi D+ a D-. Na ukážku si vezmeme USB 2.0: pokiaľ je napätie D+ väčšie o 200 mV než napätie na D-, jedná sa o „rozdielovú“ 1 (J), v opačnom prípade je to 0 (K). Informácie sa kódujú pomocou NRZI (Non Return To Zero Inverted), preto ak sa na zbernici objaví zmena z J -> K alebo z K -> J, je toto vyhodnotené ako logická 0. Logická 1 je vyhodnotená ak sa stav nezmení (J -> J alebo K -> K).

USB kábel

Typy konektorov

Pretože USB je vždy riadené hostom, bolo potrebné oddeliť funkciu hosta od zariadenia aj pomocou konektorov. Preto má USB dva základné typy:

  • Typ A – nachádza sa na hostovi alebo na hube
  • Typ B – nachádza sa na zariadení

Typy A a B sa nedajú zameniť, tým pádom nie je možné zapojiť navzájom dvoch hostov ani dve zariadenia, pokiaľ nespĺňajú špecifikáciu On-The-Go, ktorá umožňuje dvom medzi sebou prepojeným zariadeniam dohodnúť sa na tom, ktorý z nich preberie funkciu hosta. Pokiaľ zapájate kábel do konektoru typu A, hovorí sa, že ho zapájate v smere upstream (hore pyramídou), v opačnom prípade je to downstream, keďže komunikácia smeruje od hosta k zariadeniu (dole pyramídou).

Zdroj: http://www.beyondlogic.org/usbnutshell, Wikipedia

×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.

Hlasování bylo ukončeno    
17 hlasů
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 Hybridní inteligentní systémy 2

Hybridní inteligentní systémy 2

V technické praxi využíváme často kombinaci různých disciplín umělé inteligence a klasických výpočtů. Takovým systémům říkáme hybridní systémy. V tomto článku se zmíním o určitém typu hybridního systému, který je užitečný ve velmi složitých výrobních procesech.

Obrázek ke článku Jak vést kvalitně tým v IT oboru: Naprogramujte si ty správné manažerské kvality

Jak vést kvalitně tým v IT oboru: Naprogramujte si ty správné manažerské kvality

Vedení týmu v oboru informačních technologií se nijak zvlášť neliší od jiných oborů. Přesto však IT manažeři čelí výzvě v podobě velmi rychlého rozvoje a tím i rostoucími nároky na své lidi. Udržet pozornost, motivaci a efektivitu týmu vyžaduje opravdu pevné manažerské základy a zároveň otevřenost a flexibilitu pro stále nové výzvy.

Obrázek ke článku Síla týmů se na home office může vytrácet. Odborníci radí, jak z pracovních omezení vytěžit maximum

Síla týmů se na home office může vytrácet. Odborníci radí, jak z pracovních omezení vytěžit maximum

Za poslední rok se podoba práce zaměstnanců změnila k nepoznání. Především plošné zavedení home office, které mělo být zpočátku jen dočasným opatřením, je pro mnohé už více než rok každodenní realitou. Co ale dělat, když se při práci z domova ztrácí motivace, zaměstnanci přestávají komunikovat a dříve fungující tým se rozpadá na skupinu solitérů? Odborníci na personalistiku dali dohromady několik rad, jak udržet tým v chodu, i když pracovní podmínky nejsou ideální.

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