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 kui ka fiiberoptilisi kaableid. Ethernet võimaldab andmevahetust kõikide kohtvõrku ühendatud seadmete vahel kiirustega 10 Mbit/s kuni 100 Gbit/s. Etherneti standard on ajas hästi püsinud ja suurimad alternatiivid on hoopis juhtmevabad võrgustandardid, nagu 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 kaadreid, nagu näiteks IP protokolli (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.
IP ehk võrgukihi protokollil põhineb internet. Täpsemalt on see reeglistik, mida järgitakse pakettide saatmisel võrguseadmete vahel. IP paketti päises paikneb lisaks muudele andmetele ka 32-bitine IP aadress mille järgi toimub kõigi internetti püsivalt ühendatud seadmete identifitseerimine. Tänasel päeval on IP protokolli 32-bitisest aadressiruumist (~4 miljardit aadressi) väheks jäänud ja seepärast on seda asendamas IPv6, milles aadressiruum on 64-bitine. IPv6 tulekust sõltub veel asjadeinterneti (inglise keeles Internet of Things, lühend IoT) laiem levik, kuna kõik need “asjad” vajavad omale aadressi. Lisaks päisele sisaldab IP pakett veel saadetist, mis on andmeväli suvaliste andmete edastamiseks.
IP paketi saatmisel puudub kontroll, kas see ikka jõudis kohale. Probleemi lahendamiseks arendati välja TCP protokoll, mille transpordikihiks on IP pakett. TCP pakett paikneb seega IP paketi sees. TCP on kui ühendus otspunktide vahel (näiteks kliendi ja serveri vahel). Andmevahetuse alguses saadab klient serverile ühenduse loomise soovi. Sellele vastab server paketiga ja saadab omakorda kliendile paketi sooviga luua ühendus. Kui klient selle soovi kinnitab, siis on ühendus kahe otspunkti vahel loodud ja saab alustada andmete vahetamisega.
TCP protokoll loob omakorda võimaluse erinevate andmete jaoks erinevaid porte (kanaleid) kasutada. Üks port, mis kannab nime HTTP ja numbrit 80, paneb aluse World Wide Web-ile (WWW). HTTP pordi kaudu edastatakse hüperteksti markeerimiskeelt (inglise keeles HyperText Markup Language, lühend HTML), mida kuvavad veebibrauserid. HTTP klient, ehk veebibrauser peab HTTP serverile edastama tekstikujul päringu “GET”, veebilehe nime ja mõningad parameetrid ning vastuseks saadab server kliendile HTML keeles soovitud veebilehe. Allolev näide on lihtsast HTML keeles veebilehest, mis kuvab tervitusteksti, viida 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>
Hoolimata hulgast protokollidest mida on vaja veebilehe edastamiseks on seda Ethernet liidese olemasolul võimalik teha ka mikrokontrolleriga, sest kõik teised protokollid on realiseeritavad tarkvaras. Kasutades mikrokontrollerit veebiserverina on võimalik oma veebibrauserist muuta kontrolleri väljundeid või lugeda sisendite olekut.
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); // Vaikimisi clkout 6,25 MHz muutmine 12,5 MHz enc28j60clkout(2); hw_delay_ms(12); // 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,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 ja 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 III ü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); }