Individální projekty MPOA

Mikroprocesory s architekturou ARM

Uživatelské nástroje

Nástroje pro tento web


2014:mbed-http

Rozdíly

Zde můžete vidět rozdíly mezi vybranou verzí a aktuální verzí dané stránky.

Odkaz na výstup diff

Obě strany předchozí revize Předchozí verze
Následující verze
Předchozí verze
2014:mbed-http [2015/01/19 04:27]
Maximilián Tydor [Webová stránka a periferie]
2014:mbed-http [2015/01/19 06:02] (aktuální)
Maximilián Tydor [vykreslení webové stránky]
Řádek 33: Řádek 33:
 ===== REALIZACE ===== ===== REALIZACE =====
  
-Základem byl výše ​zmíněný projekt. Důležité bylo **neaktualizovat** žádnou knihovnujinak se aplikace kompletně ​rozpadla.+Postup prací: 
 +  - Importovat dříve ​zmíněný projekt ​**neaktualizovat** žádnou knihovnu! (jinak se aplikace kompletně ​rozpadne) 
 +  - Odebrat obsluhu SD karty (nebylo už možné tímto strácet čas) 
 +  - Implementovat HTTP autorizaci 
 +  - Implementovat POST metodu 
 +  - Nakonfigurovat periferie 
 +  - Vytovřit webovou stránku a obslužné metody 
 + 
 +==== HTTP Autorizace ==== 
 +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"//​. 
 +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> 
 +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)); ​                   //​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>"​);​ 
 +  client.send(httpHeader,​strlen(httpHeader)); ​                   //Formát stránky s chybovým hlášením 
 +  client.close();​ 
 +
 +</​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>​ 
 + 
 +-------
2014/mbed-http.1421638045.txt.gz · Poslední úprava: 2015/01/19 04:27 autor: Maximilián Tydor