Zde můžete vidět rozdíly mezi vybranou verzí a aktuální verzí dané stránky.
Obě strany předchozí revize Předchozí verze Následující verze | Předchozí verze | ||
2014:mbed-http [2015/01/19 04:50] Maximilián Tydor [REALIZACE] |
2014:mbed-http [2015/01/19 06:02] (aktuální) Maximilián Tydor [vykreslení webové stránky] |
||
---|---|---|---|
Řádek 44: | Řádek 44: | ||
Vytvořený skript hledá v HTTP hlavičce odeslané klientem tento řádek: //"Authorization: Basic TVBPQToyMDE0"//, | Vytvořený skript hledá v HTTP hlavičce odeslané klientem tento řádek: //"Authorization: Basic TVBPQToyMDE0"//, | ||
co je zahashovaná kombinace uživatelského jména //"MPOA"// a hesla //"2014"//. | co je zahashovaná kombinace uživatelského jména //"MPOA"// a hesla //"2014"//. | ||
- | Pokud tuto kombinaci nenajde, odešle klientovi zprávu //"401 Authorization Required"// | + | Pokud tuto kombinaci nenajde, odešle klientovi zprávu //"401 Authorization Required"//. |
+ | Prohlížeč pak vyzve uživatele k zadání přihlašovacích údajů jednoduchým formulářem. | ||
+ | |||
+ | {{ 2014:mbed-http:auth.png |Přihlašovací dialog}} | ||
+ | |||
+ | Pokud uživatel dialog zruší, daleko se nedostane... | ||
+ | |||
+ | {{ 2014:mbed-http:unauthorized.png |Chybová stránka v případě zrušení přihlašovacího dialogu}} | ||
+ | |||
+ | Pokouší-li se užívatel odklepnout formulář prázdný nebo s nesprávnými údaji vyskakuje okno pořád dokola. | ||
<code c> | <code c> | ||
if(!strstr(buffer, "Authorization: Basic TVBPQToyMDE0")){ //MPOA 2014 | if(!strstr(buffer, "Authorization: Basic TVBPQToyMDE0")){ //MPOA 2014 | ||
sprintf(httpHeader,"HTTP/1.1 401 Authorization Required \r\nContent-Type: text\r\nWWW-Authenticate: Basic realm='Login required!'\r\n\r\n"); | sprintf(httpHeader,"HTTP/1.1 401 Authorization Required \r\nContent-Type: text\r\nWWW-Authenticate: Basic realm='Login required!'\r\n\r\n"); | ||
- | client.send(httpHeader,strlen(httpHeader)); | + | client.send(httpHeader,strlen(httpHeader)); //Odeslání výzvy k přihlášení |
sprintf(httpHeader, "<HTML>\r\n\t<HEAD>\r\n\t\t<TITLE>Error</TITLE>\r\n\t</HEAD>\r\n\t<BODY>\r\n\t\t<H1>401 Unauthorised.</H1>\r\n\t</BODY>\r\n</HTML>"); | sprintf(httpHeader, "<HTML>\r\n\t<HEAD>\r\n\t\t<TITLE>Error</TITLE>\r\n\t</HEAD>\r\n\t<BODY>\r\n\t\t<H1>401 Unauthorised.</H1>\r\n\t</BODY>\r\n</HTML>"); | ||
- | client.send(httpHeader,strlen(httpHeader)); | + | client.send(httpHeader,strlen(httpHeader)); //Formát stránky s chybovým hlášením |
client.close(); | client.close(); | ||
} | } | ||
</code> | </code> | ||
+ | |||
+ | ==== metoda POST ==== | ||
+ | Přesto že předat těch několik parametrů není problém skrze URL, tedy metodou GET, ale výsledek není zrovna lahodivý oku, | ||
+ | proto byla implementována podpora metody POST. Obsluha je ve výsledku velice jednoduchá (ale ladění zabralo jeden celý den). | ||
+ | Data se posílají dvěma pakety (i když i přes WireShark to lze jen těžko poznat). První obsahuje identifikační hlavičku s identifikátorem metody, prohlížeče klienta, autorizačních ůdajů apod. | ||
+ | V druhém paketu se nacházejí samotná data a je nutné jej příjmout až v samotném průběhu zpracování metody POST, | ||
+ | jinak by do toho kecal autorizační algoritmus a ani selektor metod by si s tím nevěděl rady. | ||
+ | |||
+ | <code c> | ||
+ | } //konec metody GET | ||
+ | else if (!strncmp(buffer, "POST ", 5)) { //ověření, že se jedná o POST data | ||
+ | int n = client.receive(buffer, sizeof(buffer)); //příjem dalšího paketu se samotnými daty | ||
+ | ... //následuje zpracování přijatých dat | ||
+ | </code> | ||
+ | |||
+ | ==== vykreslení webové stránky ==== | ||
+ | Dekódování přijatých dat je věc hraní si s řetězci a následnými převody, ale toho je internet plný a o radu v případě problému není nouze. | ||
+ | Zde tedy pár řádku k nahlédnutí jak vypadá generátor webové stránky uvnitř procesoru. | ||
+ | |||
+ | <code c> | ||
+ | void display_page(void){ | ||
+ | sprintf(httpHeader,"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: Close\r\n\r\n"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"<html>\r\n\t<head>\r\n\t\t<title>K64F HTTP RGB controller</title>\r\n\t\t<meta http-equiv='refresh' content='5'>\r\n\t</head>\r\n\t<body>\r\n\t\t<h1>K64F RGB on-line controller</h1>"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"\r\n\t\t<table cellspacing='5px'>\r\n\t\t\t<tr>\r\n\t\t\t\t<th colspan='2'>RGB controls & status</th>\r\n\t\t\t\t<th>SW2 status</th>\r\n\t\t\t\t<th>SW3 status</th>\r\n\t\t\t</tr>\r\n\t\t\t<tr>\r\n\t\t\t\t<td><form action='' method='post'>"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"\r\n\t\t\t\t\t<label for='R'>R:\t</label><input type='checkbox' name='R' id='R'"); | ||
+ | if(r_on) | ||
+ | strcat(httpHeader, " checked='checked'><br>"); | ||
+ | else | ||
+ | strcat(httpHeader, "><br>"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"\r\n\t\t\t\t\t<label for='G'>G:\t</label><input type='checkbox' name='G' id='G'"); | ||
+ | if(g_on) | ||
+ | strcat(httpHeader, " checked='checked'><br>"); | ||
+ | else | ||
+ | strcat(httpHeader, "><br>"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"\r\n\t\t\t\t\t<label for='B'>B:\t</label><input type='checkbox' name='B' id='B'"); | ||
+ | if(b_on) | ||
+ | strcat(httpHeader, " checked='checked'><br>"); | ||
+ | else | ||
+ | strcat(httpHeader, "><br>"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"\r\n\t\t\t\t\t<input type='submit' value='Save'>\r\n\t\t\t\t</form></td>"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"\r\n\t\t\t\t<td style='vertical-align: bottom;'><div style='background: #%02x%02x%02x; width: 80px; height: 95%; border: 2px solid;'></div></td>",r_col, g_col, b_col); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"\r\n\t\t\t\t<td style='vertical-align: bottom;'><div style='background: black; width: 84px; height: %dpx;'></div></td>",s2_col); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"\r\n\t\t\t\t<td style='vertical-align: bottom;'><div style='background: black; width: 84px; height: %dpx;'></div></td>",s3_col); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"\r\n\t\t\t</tr>\r\n\t\t</table>\r\n\t</body>\r\n</html>"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | a zde výsledek, který už umí přechroustat snad každý prohlížeč: | ||
+ | |||
+ | <code html> | ||
+ | <html> | ||
+ | <head> | ||
+ | <title>K64F HTTP RGB controller</title> | ||
+ | <meta http-equiv='refresh' content='5'> | ||
+ | </head> | ||
+ | <body> | ||
+ | <h1>K64F RGB on-line controller</h1> | ||
+ | <table cellspacing='5px'> | ||
+ | <tr> | ||
+ | <th colspan='2'>RGB controls & status</th> | ||
+ | <th>SW2 status</th> | ||
+ | <th>SW3 status</th> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td><form action='' method='post'> | ||
+ | <label for='R'>R: </label><input type='checkbox' name='R' id='R' checked='checked'><br> | ||
+ | <label for='G'>G: </label><input type='checkbox' name='G' id='G' checked='checked'><br> | ||
+ | <label for='B'>B: </label><input type='checkbox' name='B' id='B'><br> | ||
+ | <input type='submit' value='Save'> | ||
+ | </form></td> | ||
+ | <td style='vertical-align: bottom;'><div style='background: #ffff00; width: 80px; height: 95; border: 2px solid;'></div></td> | ||
+ | <td style='vertical-align: bottom;'><div style='background: black; width: 84px; height: 30px;'></div></td> | ||
+ | <td style='vertical-align: bottom;'><div style='background: black; width: 84px; height: 70px;'></div></td> | ||
+ | </tr> | ||
+ | </table> | ||
+ | </body> | ||
+ | </html> | ||
+ | </code> | ||
+ | |||
+ | a zde ještě výsledek, který je mezi lidmi oblíbenější: | ||
+ | |||
+ | {{ 2014:mbed-http:webpage.png |Obrázek výsledné webové stránky}} | ||
+ | |||
+ | Přes tuto stránku je možné zapínat a vypínat jednotlivé barvy RGB LED a hned vidět i výsledek bez nutnosti být zrovna u desky. | ||
+ | Výsledná barevná kombinace je spočítaná ze všech tří složek a kdyby se aplikace poupravila tak, že samostatné vlákno by simulovalo PWM modulaci, | ||
+ | pořád by přibližně odpovídala barva na webové stránce barvě na LED. | ||
+ | Je to možné velice snadno ověřit na [[http://www.quackit.com/css/css_color_codes.cfm|paletě webových barev]]. | ||
+ | Na stránce se dále zobrazují dva jakoby bargrafy simulující klasické tlačítka (v horní poloze neaktivní). | ||
+ | Pro větší pohodlí a uživatelský komfort se stránka sama obnovuje každých 5 sekund. | ||
+ | ------- | ||
+ | |||
+ | ===== PŘÍLOHY ===== | ||
+ | |||
+ | ==== Zdrojový kód main.cpp ==== | ||
+ | |||
+ | <code c> | ||
+ | #include "mbed.h" | ||
+ | #include "EthernetInterface.h" | ||
+ | #include "SDFileSystem.h" | ||
+ | #include <stdio.h> | ||
+ | #include <string.h> | ||
+ | |||
+ | #define HTTPD_SERVER_PORT 80 | ||
+ | #define HTTPD_MAX_REQ_LENGTH 1023 | ||
+ | #define HTTPD_MAX_HDR_LENGTH 255 | ||
+ | |||
+ | Serial uart(USBTX, USBRX); | ||
+ | |||
+ | EthernetInterface eth; | ||
+ | TCPSocketServer server; | ||
+ | TCPSocketConnection client; | ||
+ | |||
+ | char buffer[HTTPD_MAX_REQ_LENGTH+1]; | ||
+ | char httpHeader[HTTPD_MAX_HDR_LENGTH+1]; | ||
+ | |||
+ | char *uristr; | ||
+ | char *eou; | ||
+ | char *qrystr; | ||
+ | |||
+ | int r_on=0, g_on=0, b_on=0; | ||
+ | int r_col=0, g_col=0, b_col=0, s2_col=80, s3_col=80; | ||
+ | |||
+ | void display_page(void){ | ||
+ | | ||
+ | sprintf(httpHeader,"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: Close\r\n\r\n"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"<html>\r\n\t<head>\r\n\t\t<title>K64F HTTP RGB controller</title>\r\n\t\t<meta http-equiv='refresh' content='5'>\r\n\t</head>\r\n\t<body>\r\n\t\t<h1>K64F RGB on-line controller</h1>"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"\r\n\t\t<table cellspacing='5px'>\r\n\t\t\t<tr>\r\n\t\t\t\t<th colspan='2'>RGB controls & status</th>\r\n\t\t\t\t<th>SW2 status</th>\r\n\t\t\t\t<th>SW3 status</th>\r\n\t\t\t</tr>\r\n\t\t\t<tr>\r\n\t\t\t\t<td><form action='' method='post'>"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"\r\n\t\t\t\t\t<label for='R'>R:\t</label><input type='checkbox' name='R' id='R'"); | ||
+ | if(r_on) | ||
+ | strcat(httpHeader, " checked='checked'><br>"); | ||
+ | else | ||
+ | strcat(httpHeader, "><br>"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"\r\n\t\t\t\t\t<label for='G'>G:\t</label><input type='checkbox' name='G' id='G'"); | ||
+ | if(g_on) | ||
+ | strcat(httpHeader, " checked='checked'><br>"); | ||
+ | else | ||
+ | strcat(httpHeader, "><br>"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"\r\n\t\t\t\t\t<label for='B'>B:\t</label><input type='checkbox' name='B' id='B'"); | ||
+ | if(b_on) | ||
+ | strcat(httpHeader, " checked='checked'><br>"); | ||
+ | else | ||
+ | strcat(httpHeader, "><br>"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"\r\n\t\t\t\t\t<input type='submit' value='Save'>\r\n\t\t\t\t</form></td>"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"\r\n\t\t\t\t<td style='vertical-align: bottom;'><div style='background: #%02x%02x%02x; width: 80px; height: 95%; border: 2px solid;'></div></td>",r_col, g_col, b_col); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"\r\n\t\t\t\t<td style='vertical-align: bottom;'><div style='background: black; width: 84px; height: %dpx;'></div></td>",s2_col); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"\r\n\t\t\t\t<td style='vertical-align: bottom;'><div style='background: black; width: 84px; height: %dpx;'></div></td>",s3_col); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader,"\r\n\t\t\t</tr>\r\n\t\t</table>\r\n\t</body>\r\n</html>"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | |||
+ | } | ||
+ | |||
+ | int main (void) | ||
+ | { | ||
+ | // RGB LED outputs | ||
+ | DigitalOut rled(LED_RED, 1); | ||
+ | DigitalOut gled(LED_GREEN, 1); | ||
+ | DigitalOut bled(LED_BLUE, 1); | ||
+ | | ||
+ | // SW2 & SW3 inputs | ||
+ | DigitalIn sw2(PTC6); | ||
+ | DigitalIn sw3(PTA4); | ||
+ | | ||
+ | // Serial Interface eth; | ||
+ | uart.baud(115200); | ||
+ | uart.printf("Initializing\n"); | ||
+ | |||
+ | // EthernetInterface eth; | ||
+ | uart.printf("Initializing Ethernet\n"); | ||
+ | eth.init(); //Use DHCP | ||
+ | uart.printf("Connecting\n"); | ||
+ | eth.connect(); | ||
+ | uart.printf("IP Address is %s\n", eth.getIPAddress()); | ||
+ | |||
+ | // TCPSocketServer server; | ||
+ | server.bind(HTTPD_SERVER_PORT); | ||
+ | server.listen(); | ||
+ | uart.printf("Server Listening\n"); | ||
+ | |||
+ | while (true) { | ||
+ | uart.printf("\nWaiting for new connection...\r\n"); | ||
+ | server.accept(client); | ||
+ | client.set_blocking(false, 1500); // Timeout after (1.5)s | ||
+ | | ||
+ | if(r_on){ //zadost o rozsviceni cervene LED | ||
+ | rled=0; //led aktivni logickou 0 | ||
+ | } | ||
+ | else{ | ||
+ | rled=1; | ||
+ | } | ||
+ | | ||
+ | if(g_on){ //zadost o rozsviceni zelene LED | ||
+ | gled=0; //led aktivni logickou 0 | ||
+ | } | ||
+ | else{ | ||
+ | gled=1; | ||
+ | } | ||
+ | | ||
+ | if(b_on){ //zadost o rozsviceni modre LED | ||
+ | bled=0; //led aktivni logickou 0 | ||
+ | } | ||
+ | else{ | ||
+ | bled=1; | ||
+ | } | ||
+ | | ||
+ | if(sw2){ //nacteni stavu tlacitka SW2 | ||
+ | s2_col = 70; //pokud neni tlacitko zmacknute zobrazi se vysoky sloupecek | ||
+ | } | ||
+ | else{ | ||
+ | s2_col = 30; //pokud je tlacitko zmacknute zobrazi se nizky sloupecek | ||
+ | } | ||
+ | if(sw3){ | ||
+ | s3_col = 70; | ||
+ | } | ||
+ | else{ | ||
+ | s3_col = 30; | ||
+ | } | ||
+ | | ||
+ | | ||
+ | uart.printf("Connection from: %s\r\n", client.get_address()); | ||
+ | while (true) { | ||
+ | | ||
+ | int n = client.receive(buffer, sizeof(buffer)); | ||
+ | if (n <= 0) break; | ||
+ | uart.printf("Recieved Data: %d\r\n\r\n%.*s\r\n",n,n,buffer); | ||
+ | if (n >= 1024) { | ||
+ | sprintf(httpHeader,"HTTP/1.1 413 Request Entity Too Large \r\nContent-Type: text\r\nConnection: Close\r\n\r\n"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | client.send(buffer,n); | ||
+ | break; | ||
+ | } else { | ||
+ | buffer[n]=0; | ||
+ | } | ||
+ | | ||
+ | if(!strstr(buffer, "Authorization: Basic TVBPQToyMDE0")){ //MPOA 2014 | ||
+ | sprintf(httpHeader,"HTTP/1.1 401 Authorization Required \r\nContent-Type: text\r\nWWW-Authenticate: Basic realm='Login required!'\r\n\r\n"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | sprintf(httpHeader, "<HTML>\r\n\t<HEAD>\r\n\t\t<TITLE>Error</TITLE>\r\n\t</HEAD>\r\n\t<BODY>\r\n\t\t<H1>401 Unauthorised.</H1>\r\n\t</BODY>\r\n</HTML>"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | client.close(); | ||
+ | } | ||
+ | |||
+ | if (!strncmp(buffer, "GET ", 4)) { | ||
+ | uristr = buffer + 4; | ||
+ | eou = strstr(uristr, " "); | ||
+ | if (eou == NULL) { | ||
+ | sprintf(httpHeader,"HTTP/1.1 400 Bad Request \r\nContent-Type: text\r\nConnection: Close\r\n\r\n"); | ||
+ | client.send(httpHeader,strlen(httpHeader)); | ||
+ | client.send(buffer,n); | ||
+ | } | ||
+ | else { | ||
+ | *eou = 0; | ||
+ | display_page(); | ||
+ | client.close(); | ||
+ | } | ||
+ | } | ||
+ | else if (!strncmp(buffer, "POST ", 5)) { | ||
+ | | ||
+ | int n = client.receive(buffer, sizeof(buffer)); | ||
+ | | ||
+ | if (strstr(buffer, "R=on")) { | ||
+ | r_on = 1; | ||
+ | r_col = 255; | ||
+ | } | ||
+ | else{ | ||
+ | r_on = 0; | ||
+ | r_col = 0; | ||
+ | } | ||
+ | if (strstr(buffer, "G=on")) { | ||
+ | g_on = 1; | ||
+ | g_col = 255; | ||
+ | } | ||
+ | else{ | ||
+ | g_on = 0; | ||
+ | g_col = 0; | ||
+ | } | ||
+ | if (strstr(buffer, "B=on")) { | ||
+ | b_on = 1; | ||
+ | b_col = 255; | ||
+ | } | ||
+ | else{ | ||
+ | b_on = 0; | ||
+ | b_col = 0; | ||
+ | } | ||
+ | | ||
+ | display_page(); | ||
+ | client.close(); | ||
+ | } | ||
+ | } | ||
+ | client.close(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | </code> | ||
+ | |||
+ | ------- |