Tak a máme tady další díl týkající se komunikace po ethernetu pomocí ENC28J60 připojeného k STM32 VL Discovery kitu. V minulých dílech jsme probrali jak základy TCP/IP komunikace, tak i popis ENC28J60 modulu. Nyní tedy probereme praktické řešení maximálně primitivního web serveru.



Úvod

Jak je uvedeno, tak zde prezentované řešení je na maximální míru zjednodušené, aby zejména začátečníci s touto problematikou se mohli ve věci orientovat. Toto zjednodušení znamená, že řešení zpracování příjmu a vysílání TCP/IP ethernetových rámců spoustu věcí nezná a neumí. Pokud k takovému případu dojde, tak rámec s daty zahodí a nereaguje na něj. Bylo využito řešení, kterého autorem je Guido Socher a původně bylo navrženo pro ATmega mcu. Jednoduchost řešení přináší drobné problémy, například se pro vytváření odpovědních paketů využívá těch příchozích co možná nejjednodušeji - proto občas třeba dostanete na PING odezvu se záporným časem. Na druhou stranu, podstatné věci fungují.
Existují pochopitelně komplikovanější řešení a pokud bude zájem, tak jim můžeme věnovat některý z dalších dílů. Rovněž řešení příjmu paketů z ethernetu je zjednodušené - data přijímáme tak, že se pravidelně ptáme ENC28J60 (dále jen ENC), zda už něco přijal a pokud ano, tak to zpracujeme. Tohle řešení je sice jednoduché, ale pro ARM Cortex neefektivní. Lepším řešením je využití výstupního pinu INT, které vyvolá přerušení mcu, který v handleru obsluhy tohoto přerušení přečte paket. Tudíž mcu se nemusí zdržovat tím že se trvale vyptává ENC na přijatá data a nezatěžuje ENC touto komunikací. Toto vylepšené řešení bude obsahem následujícího dílu.
Ještě mám jednu poznámku ke zjednodušení - aplikace je postavena jako server. Tj. Discovery kit čeká na příjem paketu a pokud dorazí, tak s ním "něco" provede. Pokud bude zájem, tak můžeme ještě prezentovat v budoucnu klientskou aplikaci - např. "vzdálené tlačítko", které po stisku samo odešle po ethernetu informaci o této události (aplikace pro různé alarmy, hlídače teploty, převodníky RS232-Ethernet, atd.).
Takže závěrem - zde prezentované řešení umí odpovídat na PING a odpovídat na HTTP dotazy na portu 80 (web server), což ale pro mnoho řešení stačí - řídicí aplikace si pravidelných intervalech vyžádá obsah webstránky a z přijatého řetězce vyseparuje hodnoty kterého zajímají s tím, že i lidská obsluha má možnost se přímo podívat na hodnoty pomocí webového prohlížeče. Aplikace také umí UDP komunikaci, ale o té až jindy.


Řešení HW

Raději pro jistotu probereme jak je řešeno připojení kitu k ENC. Zopakuji obrázek z dílu o ENC.



Na straně kitu jsou piny trochu jinak značeny, místo SCK nalezneme v datasheetu STM32F100 (Table 4.) alternativní funkci pro PA5 - SPI1_SCK, jako SDI použijeme PA6 (SPI1_MISO) a na místě SDO použijeme PA7 (SPI1_MOSI). Na místě označeném I/O použijeme pin PA4, který budeme ovládat jako běžný GPIO pin (nikoliv jako SPI1_NSS! - nechtěl jsem to komplikovat) - ze strany ENC jde o pin CS, který povoluje SPI komunikaci pro ENC.

Pin od ENC RESET je na +3.3V, stejně jako UCC. GND od END je spojeno s GND na kitu, WOL není zapojeno, stejně jako INT.


Řešení SW

Program běží jako nikdy nekončící funkce uint8_t simple_server(void), kterou najdete v souboru simple_server.c! V této funkci po úvodní inicializaci se skočí do cyklu while (1), což je nekonečný cyklus. V tomto cyklu se trvale testuje přijetí paketu pomocí
unsigned int enc28j60PacketReceive(unsigned int maxlen, unsigned char* packet)
{
        if( enc28j60Read(EPKTCNT) ==0 )
        {
                return(0);
        }
        // teprve ted nasleduje vlastni nahravani dat z bufferu


Tedy v případě že buffer neobsahuje nic, tak se hned provede return s minimální ztrátou času. Pouze v případě, když něco v příjmovém bufferu je, tak se data zpracuji.

Pokud dojde k příjmu paketu (= délka (plen) je nenulová), tak se začne zkoumat. Následující kus kódu zkoumá, zda jde o ARP dotaz na MAC adresu našeho zařízení.
if(eth_type_is_arp_and_my_ip(buf,plen))
        {
                make_arp_answer_from_request(buf); // odpovez na dotaz
                continue; // timto se zase skoci na zacatek - na nacteni paketu
        }
 


A úplně stejně je detekována komunikace na portu 80, tedy dotaz na webový server. Ale detekce je složitější, protože nejde o jednoduchý ARP paket, ale o TCP dotaz.
if (buf[IP_PROTO_P]==IP_PROTO_TCP_V && buf[TCP_DST_PORT_H_P]== 0 && buf[TCP_DST_PORT_L_P]==mywwwport)


Pomocí mywwwport si můžeme změnit port, na kterém nám server běží (ale jen v rozsahu 1-255), protože podmínka buf[TCP_DST_PORT_H_P]== 0 nám vylučuje jiné porty než porty typu 0x00NN.

Pro jednoduchost je dekódování adresy url prováděno tak, že za IP adresou je nutno zadat heslo a pak typ požadované operace. Tedy na svém PC zadáváte do prohlížeče adresu http://192.168.1.25/123456/1 pro rozsvícení modré LED na kitu a http://192.168.1.25/123456/0 pro její zhasnutí. Pro pouhé zobrazení stavu, bez změny svitu LED zadáte jen http://192.168.1.25/123456. Pochopitelně se Vám ve všech případech též zobrazí velice jednoduchá webová stránka. Heslo můžete změnit velice snadno, stejně jako detekci požadované operace. Pokud změníte port na jiný, tak budete zadávat například "192.168.1.25:85" (pokud změníte port na 85) a zbytek zůstane stejný.

Webovou stránku, jako odpověď na dotaz od PC připravíme a odešleme pomocí následujícího kódu.
plen=print_webpage(buf,(i));
make_tcp_ack_from_any(buf); // send ack for http get, tj. potvrdíme přijetí paketu s dotazem od PC
make_tcp_ack_with_data(buf,plen); // send data
continue; // pomocí continue se zase dostaneme na zacatek nekonecneho while cyklu


Vše ostatní je záležitostí manipulace s pakety a jejich obsahem, které je ukryto v souboru ip_arp_udp_tcp.c, který využívá knihovny pro komunikaci s ENC (ENC28J60.c), kterou jsme si již představili v dílu o ENC. Co si představit pod pojmem manipulace s pakety? Jedná se zejména o vkládání správných IP a MAC adres do jak hlaviček ethernetových paketů, tak i TCP a UDP datagramů, výpočty potřebných dat (vkládaný údaj o délce, vkládané CRC, atd.), změny parametrů paketů (např. pro přijatý paket typu REQUEST se v odpovědi typ přepíše na REPLY, atd.). Knihovna ip_arp_udp_tcp.c je sice krátká (děkuji ti , Guido Sochore ), ale poměrně komplexní a jde využít i pro jiné aplikace než pouhý webový server. Díky své jednoduchosti je i velice rychlá a nepředstavuje pro STM32F100 žádnou podstatnou zátěž.


Příklad komunikace

Aby jste mohli sledovat, co se na síti děje, tak doporučuji aby jste si stáhli a nainstalovali program WireShark (viz odkazy níž), který používám já, když se chci podívat na ethernet, co se na něm konkrétně děje. Jde o ethernet sniffer, s poměrně velice dokonalým dekódováním paketů, což výrazně šetří čas, který by jste museli věnovat na luštění paketů. Po spuštění capture na ethernetovém adaptéru vašeho PC uvidíte podobný obrázek.



Práce s WireSharkem je natolik intuitivní, že asi manuál nebudete potřebovat, ale pokud ano, tak jej naleznete zde.

Jako příklad komunikace si můžeme uvést PING. Ping je utilita, která otestuje, jak dlouho trvá paketům, než dorazí. Spustíte si MS DOS okénko (linuxáci otevřou okénko se shellem ) a napíšete "ping 192.168.1.25". PC zatím neví, jaké zařízení na síti má IP adresu 192.168.1.25 a zda takové zařízení vůbec existuje. Proto první co udělá je že vyšle dotaz ARP, které zařízení má IP adresu rovnou 192.168.1.25. Tento paket doputuje také k našemu ENC, které jej přijme a předá Discovery kitu. Ten vypracuje odpověď (ARP REPLY), do které vloží svou MAC adresu a tu odešle tázajícímu se PC - to budou první dva řádky ve WireSharku, které zachytíte (pokud na síti není nějaká jiná komunikace). Řádky budou mít bleděmodrou barvu. Nyní když PC zjistí MAC adresu zařízení, tak provede ping (odeslání paketu) pomocí ICMP. Ten doputuje na ENC, který jej předá kitu. Ten po určení typu paketu, připraví odpověď, kterou odešle. PC paket přijme a z údajů o času vypočte, jaká je doma potřebná na doručení paketu.

Podobným způsobem probíhá komunikace za situace, když zadáte v PC do prohlížeče IP adresu ENC. Pokud jste již před tím nezkoušeli PING, tak PC zatím nezná MAC adresu ENC a úplně stejně jako v předchozím příkladu se pomocí ARP dotazu na MAC zeptá. Když MAC zná, tak otevře TCP spojení na port 80 (TCP je potvrzované spojení, takže ENC po přijetí každého TCP paketu musí potvrdit jeho úspěšný příjem) a odešle GET požadavek. ENC požadavek přijme, kit jej načte z ENC, pak rozkóduje paket a dekóduje ULR adresu v GET požadavku. Podle výsledku dekódování URL vypracuje odpověď (zkuste například zadat špatné heslo), potvrdí přijatý paket a odešle pomocí TCP odpověď obsahující HTML kód.


Závěr

Doufám, že tento díl bude inspirací pro mnoho z Vás a brzy se objeví vaše konstrukce a nápady. Ethernet je dnes médium, které je skoro všudypřítomné a když se využije skutečnosti, že je možné zařízení po ethernetovém kabelu i napájet (PoE), tak pomocí ethernetového konektoru získáte snadno aplikovatelné zařízení, připojitelné až po 100m dlouhém kabelu. V dnešním světě plném rušení, jsou často s bezdrátovým přenosem problémy a proto je ethernet zajímavou alternativou. Doufám že TCP/IP komunikace Vám nebude připadat příliš komplikovaná, snažil jsem se o srozumitelnost i pro ty, kteří ještě nemají s tímto typem komunikace velké zkušenosti. Pokud nebude něco jasné, tak očekávám dotaz do komentářů.

Pokud máte pocit že Vám tento článek pomohl a domníváte se, že si text zaslouží Vaše drobné ocenění, tak můžete poslat malou dotaci. Pochopitelně že od odesílatelů dotace rád zjistím jejich názor na to, co by je zajímalo v dalších dílech.





Odkazy

STM32-VL DISCOVERY popis je zde.
STM32-VL Discovery 2. (další popis, osobní poznatky) je zde.
Začínáme s STM32 VL Discovery kitem naleznete zde.
Začínáme s STM32 VL Discovery kitem _2. naleznete zde.
Začínáme s STM32 VL Discovery kitem _3. naleznete zde.
Začínáme s STM32 VL Discovery kitem _4. naleznete zde.
Začínáme s STM32 VL Discovery kitem _5. naleznete zde.
Začínáme s STM32 VL Discovery kitem _6. naleznete zde. (blikání LED)
Začínáme s STM32 VL Discovery kitem _7. naleznete zde. (ladění)
Začínáme s STM32 VL Discovery kitem _8. naleznete zde. (využití SysTick)
Začínáme s STM32 VL Discovery kitem _9. naleznete zde. (změna CLK)
Začínáme s STM32 VL Discovery kitem 10. naleznete zde. (kontaktní pole)
Začínáme s STM32 VL Discovery kitem 11. naleznete zde. (PWM)
Začínáme s STM32 VL Discovery kitem 12. naleznete zde. (watchdog)
Začínáme s STM32 VL Discovery kitem 13. naleznete zde. (externí přerušení)
Začínáme s STM32 VL Discovery kitem 14. naleznete zde. (LCD)
Začínáme s STM32 VL Discovery kitem 15. naleznete zde. (ADC)
Začínáme s STM32 VL Discovery kitem 16. naleznete zde. (Teplotní čidlo)
Začínáme s STM32 VL Discovery kitem 17. naleznete zde. (klávesnice PS/2)
Začínáme s STM32 VL Discovery kitem 18. naleznete zde. (správná verze LCD.c)
Začínáme s STM32 VL Discovery kitem 19. naleznete zde. (DAC převodník)
Začínáme s STM32 VL Discovery kitem 20. naleznete zde. (DAC s přerušením)
Začínáme s STM32 VL Discovery kitem 21. naleznete zde. (DMA v paměti)
Začínáme s STM32 VL Discovery kitem 22. naleznete zde. (DMA s DAC)
Začínáme s STM32 VL Discovery kitem 23. naleznete zde. (RTC)
Dodatek k "Začínáme s STM32 VL Discovery kitem 23." je zde. (RTC úprava)
Začínáme s STM32 VL Discovery kitem 24. naleznete zde. (RTOS-přehled)
Začínáme s STM32 VL Discovery kitem 25. naleznete zde. (USART-přerušení)
Začínáme s STM32 VL Discovery kitem 26. naleznete zde. (USART-přesměrování vstupů a výstupů)
Začínáme s STM32 VL Discovery kitem 27. naleznete zde. (Assembler vkládaný do C kódu)
Začínáme s STM32 VL Discovery kitem 28. naleznete zde. (Vnořované přerušení)
Začínáme s STM32 VL Discovery kitem 29. naleznete zde. (Přímé řízení znakového LCD)
Začínáme s STM32 VL Discovery kitem 30. naleznete zde. (I2C komunikace)
Začínáme s STM32 VL Discovery kitem 31. naleznete zde. (mcu řady STM32L)
Začínáme s STM32 VL Discovery kitem 32. naleznete zde. (RTC)
Začínáme s STM32 VL Discovery kitem 33. naleznete zde. (vícekanálové ADC)
Začínáme s STM32 VL Discovery kitem 34. naleznete zde. (popis TCP/IP)
Začínáme s STM32 VL Discovery kitem 35. naleznete zde. (errata mcu)

InterNiche TCP/IP stack info odkaz
Microchip TCP/IP Stack info zde.
Light Weight TCP/IP Stack odkaz (lwIP)


Definice konektorů STM VL Discovery kitu v Eagle pro vytvoření projektu
s konektorem, do něhož jde zasunout kit naleznete zde.
Jak na STM VL Discovery s programovým vybavením od Keil 1. je zde.
Jak na STM VL Discovery s programovým vybavením od Keil 2. je zde.
Jak zprovoznit STM VL Discovery pokud si při pokusech zakážete JTAG piny pomocí bootloaderu je zde.

Zazipovaný example k tomuto dílu naleznete zde.
Předcházející článek popisující ENC28J60 naleznete zde.
WireShark naleznete zde.

Reference manuál k Value Line naleznete zde.


Ještě drobné dodatečné doplnění: zaregistroval jsem podiv nad využitím ENC28J60 k ARM mcu. Přičemž já mám dojem, že díky tomu, že pro ovládání potřebuji jen 4 piny, tak můžu mít svou konstrukci modulární. Kdo potřebuje ethernetovou konektivitu a je ochoten si připlatit, tak ten dostane zařízení jehož součástí bude deska s ENC. Ostatní budou mít zařízení jen s mcu za 50 Kč. Pokud bych měl zařízení s mcu, které v sobě má ethernetový MAC (to znamená že místo 100 Kč za ENC28J60 s MAC+PHY zaplatím jen 20-30 Kč za čip s PHY), tak 80 Kč ušetřím ale musím si připlatit za dražší mcu. ARM mcu s ethernetovým MAC jsou typy STM32F107, STM32F2xx a STM32F4xx, což jsou výrazně dražší typy. Proto řešení s ENC28J60 pokládám za efektivní a přínosné a u aplikací typu převodník RS232-ethernet bude asi nejefektivnější.

Doplnění 20.02.2012: Opraveny drobné chyby ve zdrojových kódech. Zazipovaný soubor s projektem je aktualizovaný. Původní varianta při počtu vyměněných paketů mezi PC a kitem > než 255 zatuhla. Důvodem je to, že proměnnou 16 bit jsem přenášel pomocí 8 bitové proměnné.