This is an old revision of the document!
Vajalikud teadmised: [HW] Kontrollermoodul, [LIB]Ethernet
Ethernet on põhiline juhtmetega kohtvõrgu (inglise keeles Local Area Network, lühend LAN) tehnoloogia, mille kaudu on omavahel ühendatud enamik maailma arvutitest moodustades niimoodi Interneti. Seda tutvustati esmakordselt aastal 1980 ja aastast 1985 standardiseeriti kui IEEE 802.3.
Etherneti standard määrab juhtmete ja pistikute tüübid, kirjeldab füüsilise signaali ülekande ning määrab andmevahetuse formaadi. Selle standardid on tihedalt seotud OSI füüsilise kihiga, täites mudeli kahe alumise kihi (füüsiline kiht ja lülikiht) funktsioone. Algusaegadel kasutati Etherneti ülesehitamiseks koksiaalkaableid, mis vastasid standardile 10BASE5. Praegu kasutatakse nii vasest keerupaari ja fiiberoptilisi kaableid. Ethernet võimaldab andmevahetust kõikide kohtvõrku ühendatud seadmete vahel kiirustega 10 Mbit/s kuni 100 Gbit/s. Etherneti standard on ajale hästi püsinud ja suurimad alternatiivid on sellel hoopis juhtmevabad võrgustandardid nagu näiteks Wifi ja mobiilsidevõrgud.
Ethernetil baseeruvas lokaalvõrgus jagatakse andmevood väiksemateks kaadriteks (inglise keeles frame). Iga kaader peab sisaldama saatja ja vastuvõtja MAC aadressi ja andmeid veakontrolliks. MAC aadress on unikaalne 48-bitine võrguseadmele tootja poolt antud number. Etherneti kaadri keskosas on piirkond ülekantavate andmete jaoks. Andmed võivad sisaldada teiste protokollide päiseid, nagu näiteks IP protokoll (inglise keeles Internet Protocol). Veakontroll on realiseeritud 32-bitise tsükkelkoodkontrolli meetodil, kus saatepoolel rakendatakse edastamisele kuuluvale andmeplokile 32-bitist polünoomi, mille tulemusena saadav kood lisatakse plokile. Vastuvõtupoolel rakendatakse andmeplokile sama polünoomi ja kui tulemused kokku langevad, loetakse andmeedastus õnnestunuks.
Nagu öeldud baseerub Ethernetil IP protoll mis paneb aluse Internetile kuna selle päises on kirjas 32-bitine IP aadress mille järgi kõik Internetti “püsivalt” ühendatud seadmed identifitseeritud on. Tänasel päeval on IP protokolli 32-bitisest aadressiruumist (~4 miljardit aadresssi) väheks jäänud ja seepärast on seda asendamas IPv6 milles aadressiruum on 64-bitine. IPv6 tulekust muide sõltub ka IoT (inglise keeles Internet of Things) “asjade interneti” laiem levik kuna kõik neid “asjad” vajavad omale aadressi. Sarnaselt Ethernetiga edastatakse IP protokolli kaudu ainult kaadreid, ehk andmelõike. Selleks, et edastada suuri andmehulkasid ja veenduda kõiki üksikute kaadrite kohalejõudmises on kasutusel IP protokollil baseeruv transpordiprotokoll TCP. TCP protokolli järgi vastab andmete saaja saatjale alati kinnitusega.
TCP protokoll loob ka võimaluse erinevate andmete jaoks erinevaid porte (kanaleid) kasutada. Üks port, mis kannab nime HTTP ja numbrit 80, paneb aluse World Wide Web'ile kuna selle kaudu edastatakse HTML'i ehk hüperteksti markeerimiskeelt (inglise keeles HyperText Markup Language)
Etherneti kasutatakse peamiselt veebilehtede edastamiseks serverilt kliendi veebilehitsejale. Mikrokontrolleril on võimalik realiseerida lihtsaid veebilehti, mille kaudu on omakorda võimalik muuta kontrolleri sisend-väljund viike või lugeda nendest infot. Lihtsamad veebilehed on realiseeritud HTML kirjelduskeele abil, mida veebilehitsejad (inglise keeles browser) kasutajale kuvavad. HTML on lihtne kirjelduskeel, mis kasutab dokumendi vormindamiseks erinevaid märgendeid (inglise keeles tag). Allolev näide on lihtsast veebilehest, mis kuvab tervitusteksti, viite ja rohelist värvi tekstiosa.
<!DOCTYPE html> <html> <body> <h1>Tere! Olen mikrokontroller</h1> <p>See leht näitab kontrolleri viigu olekut</p> <a href="muuda.html">VIIDE</a><br> <font color="green">ON</font> </body> </html>
Robootika Kodulabori arvutivõrguga ühendamiseks on Kodulabor II kontrolleriplaadil RJ45 standardile vastav ühenduspesa ja Kodulabor III eraldi Etherneti moodul, mida juhib Etherneti kontroller ENC28J60. ENC28J60 ühendub mikrokontrolleriga SPI liidese kaudu. Kiibi maksimaalne ühenduskiirus on 10 Mbps.
ENC28J60 vastab kõigile IEEE 802.3 poolt kehtestatud nõuetele ja sisaldab mitmeid pakettide filtreerimise võimalusi, sisenevate ja väljuvate pakettide jaoks omaette puhvrit ja MAC (inglise keeles Medium Access Control) ja PHY (inglise keeles Physical Layer) kihte. Tänu sellele tehakse keerukas Etherneti kaadrite töötlus nagu näiteks aadressi- ja veakontrolli lisamine lõppkasutaja eest automaatselt ära.
Etherneti kasutamiseks on Kodulabori teegis järgmised funktsioonid:
// Etherneti kontrolleri algseadistus koos MAC ja IP aadressidega void ethernet_init(uint8_t *mac, uint8_t *ip) { // ENC28J60 seadistamine enc28j60Init(mac); enc28j60clkout(2); // Vaikimisi clkout 6.25 MHz muutmine 12.5 MHz hw_delay_ms(12); // 12 ms // Magjack LED-ide seadistamine (vaata enc28j60 andmelehte, lehekülg 11) // LEDB = kollane, LEDA = roheline // 0x476 on PHLCON LEDA = ühenduse staatus, LEDB = vastuvõtmine või edastamine // enc28j60PhyWrite(PHLCON,0b0000 0100 0111 01 10); enc28j60PhyWrite(PHLCON,0x476); hw_delay_ms(12); // 12ms // Etherneti/ip kihtide seadistamine: init_ip_arp_udp_tcp(mac,ip,MYWWWPORT); } // Võrgu kuulamine (kuni saab endale mõeldud ja andmeid sisaldava andmepaketi) uint16_t ethernet_get_packet (uint16_t maxlen, uint8_t* packet) { return(enc28j60PacketReceive(maxlen, packet)); } // HTML-koodi kontrolleri programmimälust TCP saatmise puhvrisse laadimine uint16_t ethernet_load_data (uint8_t *buf,uint16_t pos, const prog_char *progmem_s) { return(fill_tcp_data_p(buf,pos, progmem_s)); } // Veebilehe kuvamine vastavalt valmislaetud HTML-koodile void ethernet_print_webpage (uint8_t *buf,uint16_t dlen) { return(www_server_reply(buf,dlen)); } // Vastuvõetud andmepaketist URL-i tuvastamine // Pingile vastamine uint16_t ethernet_analyse_packet(uint8_t *buf,uint16_t plen) { return(packetloop_icmp_tcp(buf,plen)); }
Etherneti kontrolleri kasutamiseks tuleb kõigepealt välja kutsuda funktsioon ethernet_init, mis seadistab Etherneti kontrolleri. Parameetrina tuleb ette anda MAC ja IP aadress. Peale seda, kasutades funktsiooni ethernet_get_packet saadakse kätte varem seadistatud IP aadressile saabunud paketid. Kui pakett on saabunud, tagastab selle pikkuse baitides, vastasel juhul tagastab 0. Funktsioon ethernet_analyse_packet analüüsib, kas vastuvõetud andmepakett sisaldab URL-i kohta andmeid. Vajadusel vastab ka pingile ja tagastab URL-i esimese tähemärgi aadressi, kui URL on tühi, siis tagastab nulli. Funktsiooni kasutusotstarve on edasise töötlemise eesmärgil URL-i eraldamine muust infost. Funktsioone ethernet_get_packet ja ethernet_analyse_packet on soovitav välja kutsuda programmi tsükli lõpus.
Veebileht laetakse funktsiooniga ethernet_load_data. Funktsioon laeb HTML-koodi kontrolleri programmimälust TCP saatmise puhvrisse. Funktsioon tagastab andmejada lõpu aadressi, mida saab sisestada parameetrina järgmise HTML-koodi laadimiseks. Lõpuks kuvatakse varem TCP puhvrisse laetud veebileht funktsiooniga ethernet_print_webpage.
Näide on mõeldud lihtsa veebiserveri loomiseks. Allpool toodud näiteprogramm loob IP aadressile 192.168.1.100 veebilehe, millel oleva lingi kaudu on võimalik lülitada sisse ja välja Kontrollermoodulil olevat LED-i. Selleks töödeldakse URL-is olevat informatsiooni, mis on eelnevalt salvestatud muutujasse gPlen. Otsitakse sealt LED-i olekut määravat tunnust “/1” või “/0”. Veebilehe HTML kood asub eraldiseisvas funktsioonis ethernet_load_webpage kus see on PSTR makroga salvestatud kontrolleri programmimälusse.
// Kodulabori Etherneti kasutamise näidisprogramm // Kodulabor II ühendused: CS - PE0, SCK - PE1, MISO - PE2, MOSI - PE3 #include <string.h> #include <homelab/module/ethernet.h> #include <homelab/pin.h> // Veebilehe koostamise funktsioon uint16_t ethernet_load_webpage(uint8_t on_off); // MAC ja IP peavad olema kohtvõrgus olema unikaalsed // Antud näites olev MAC on juhuslik (üldjuhul see ka sobib) static uint8_t mymac[6] = {0x54,0x55,0x58,0x10,0x00,0x24}; // IP vastavalt kohtvõrgule (viimane number valida ise) static uint8_t myip[4] = {192,168,1,100}; // Andmejada pikkus static uint16_t gPlen; // Andmete puhvri suurus #define BUFFER_SIZE 600 static uint8_t buf[BUFFER_SIZE+1]; // Põhiprogramm int main(void) { uint16_t pktlen; char *str; // Kontrollerplaadil oleva LED-i väljundiks määramine pin_setup_output(LED0); // Etherneti algväärtustamine vastavalt etteantud aadressidele ethernet_init(mymac, myip); // Lõputu tsükkel while(1) { // Pakettide muutmine, kuni endale määratud andmetega paketi saamiseni pktlen=ethernet_get_packet(BUFFER_SIZE, buf); // Paketi eeltöötluse tegemine ja "ping" paketile vastamine // Paketi URL-i tagastamine gPlen=ethernet_analyse_packet(buf,pktlen); // URL-is oleva info analüüsimine if (gPlen!=0) { // URL-i aadressiosa viida "str" laadimine // URL-is on neli esimest kohta IP aadressi numbrid str = (char *)&(buf[gPlen+4]); // URL-ist stringi "/1" laadimine if (strncmp("/1",str,2)==0) { // Veebilehe laadimine gPlen = ethernet_load_webpage(0); led_on(LED0); } // URL-ist stringi "/0" otsimine else if (strncmp("/0",str,2)==0) { // Veebilehe laadimine gPlen = ethernet_load_webpage(1); led_off(LED0); } // Muul juhul veebilehe laadimine vastavalt LED olekule else gPlen=ethernet_load_webpage(pin_get_value(LED1)); // Varem valmis laetud veebilehe kuvamine ethernet_print_webpage (buf,gPlen); } } } // Funktsioon veebilehe kuvamiseks, kirjutades andmed TCP saatmise puhvrisse uint16_t ethernet_load_webpage(uint8_t on_off) { uint16_t plen=0; // Veebilehe päise laadimine plen=ethernet_load_data(buf,0, PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nPragma: no-cache\r\n\r\n")); plen=ethernet_load_data(buf,plen,PSTR("<center><p>Homelab PB7 LED: ")); // Kui LED ei põle if (on_off) plen=ethernet_load_data(buf,plen,PSTR("<font color=\"#00FF00\"> OFF</font>")); // Kui LED põleb else plen=ethernet_load_data(buf,plen,PSTR("<font color=\"#FF0000\"> ON</font>")); // "Refresh" nupu laadimine plen=ethernet_load_data(buf,plen, PSTR(" <small><a href=\".\">[refresh status]</a></small></p>\n<p><a href=\".")); // LED-i oleku muutmise nupu laadimine vastavalt selle olekule if (on_off) plen=ethernet_load_data(buf,plen,PSTR("/1\">Switch on</a><p>")); else plen=ethernet_load_data(buf,plen,PSTR("/0\">Switch off</a><p>")); // Andmete lõpu aadressi väljastamine puhvrist return(plen); }