Pages: [1]   Go Down
Author Topic: Ottimizzare codice html web server  (Read 416 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
God Member
*****
Karma: 0
Posts: 600
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ma ciao smiley
Ho una cosa stupidissima da fare che però non mi viene, ogni suggerimento sarà cosa gradita.

Sto ottimizzando il codice del mio web server e visto che spesso ho dei client.print ridondanti, volevo trovare il modo di archiviarli in memoria una volta sola e stamparli dove ne ho necessità.
Passiamo all'esempio pratico cosi ci capiamo meglio smiley

Invio tre pagine html, ripetendo per tre volte l'invio dell'header http.
Code:
client.println(F("HTTP/1.1 200 OK"));
client.println(F("Content-Type: text/html"));
client.println();

E' uno spreco di spazio inutile, quindi pensavo alla possibilità di creare una funzione di questo tipo:
Code:
PageHttpOk();
...
void PageHttpOk() {
client.println(F("HTTP/1.1 200 OK"));
client.println(F("Content-Type: text/html"));
client.println();
Serial.println(F("Debug: funzione inviata"));
}

E richiamarla nel loop ogni qual volta ci fosse necessità di stampare un header.
Mi sembrava una cosa stupidissima e banalissima... ma non funziona!
Ponendo la chiamata della funzione nel loop e la funzione fuori dal loop... l'header non viene inviato!
So che la funzione viene correttamente chiamata perché a seriale leggo il debug, tuttavia è come se il client print non funzionasse.
Anche analizzando i pacchetti inviati tramite whireshark vedo chiaramente che il response header non viene inviato. La conseguenza è ovviamente una pagina html completamente rovinata.

Idee del perché accade ciò?
Il client non si inizializza correttamente se richiamato da una funzione esterna?
Suggerimenti per ovviare a ciò?

Con la libreria flash potrei creare una stringa
Code:
FLASH_STRING(PageHttpOk, " blablabla l'header ecc");
e fare un client print dove voglio tutte le volte che voglio.
Code:
PageHttpOk.print(client);
Ho già provato e funziona, tuttavia includere la libreria flash occupa più spazio di quanto ne vado a liberare ottimizzando il codice smiley
Logged

0
Offline Offline
Shannon Member
****
Karma: 117
Posts: 10115
:(){:|:&};: TOX id: fcb8e918bef08581e23f6ddf9d4dba77697c25b217bf372736ed959a95fde36df5b8c5b90fbb
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

molto strano, quello che mi viene in mente è un'ottimizzazione aggressiva che elimina la funzione e la sua chiamata credendola inutile.

sarebbe carino capire cosa fa quella funzione F, per risolvere prova a mettere un valore di ritorno che viene utilizzato dal chiamante, e deve essere modificato anche dal chiamato (magari fai un check sullo stato di client, anche qullo è un possibile problema)
Logged

my Arduino code: https://github.com/lestofante/arduinoSketch
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Offline Offline
God Member
*****
Karma: 0
Posts: 600
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Lesto scusa ma non ho capito :/
Che prova vuoi che faccia?
Per il client, tutti gli altri client.print all'interno del loop vengono inviati senza problemi.
Il client.connected and avaiable funzionano regolarlmente.
Tanto è vero che la pagina HTML viene inviata, senonché mancando l'header appare completamente senza formattazione.
L'unica parte di codice che non viene eseguita sono i client print fuori dal loop richiamati da una funzione.

Logged

Cagliari, Italy
Offline Offline
Tesla Member
***
Karma: 104
Posts: 6626
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

sarebbe carino capire cosa fa quella funzione F
E' stata introdotta con l'IDE 1.0
--> http://arduino.cc/playground/Main/Printf --> Using Flash Memory for string storage
Logged

Code fast. Code easy. Codebender --> http://codebender.cc/?referrer=PaoloP

0
Offline Offline
Shannon Member
****
Karma: 117
Posts: 10115
:(){:|:&};: TOX id: fcb8e918bef08581e23f6ddf9d4dba77697c25b217bf372736ed959a95fde36df5b8c5b90fbb
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Lesto scusa ma non ho capito :/
Che prova vuoi che faccia?
Per il client, tutti gli altri client.print all'interno del loop vengono inviati senza problemi.
Il client.connected and avaiable funzionano regolarlmente.
Tanto è vero che la pagina HTML viene inviata, senonché mancando l'header appare completamente senza formattazione.
L'unica parte di codice che non viene eseguita sono i client print fuori dal loop richiamati da una funzione.


sono confuso anche io dal tipo di errore che hai. Prima di tutto farei una prova evitando di usare la F, si sa mai che abbia qualche bug infido & balordo.
Logged

my Arduino code: https://github.com/lestofante/arduinoSketch
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Offline Offline
God Member
*****
Karma: 0
Posts: 600
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Prova fatta, anche togliendo la F il problema rimane.
Per la verità ho trovato una soluzione... Ma non serve a nulla perché non è una ottimizzazione.
Il consumo di RAM aumenta cosi come le dimensioni dello sketch.
vediamo se riesco a scrivere il codice dall'iphone
Code:
PageHttpOk(client);
...
void PageHttpOk(EthernetClient client){
client.println(F("HTTP/1.1 200 OK"));
Ecc.

Questa funziona. L'header viene correttamente inviato.
Però consuma un casino di RAM e di sketch. Quindi nn ha senso.

Proviamo a vedere il problema in un altro modo.
Se archivio la stringa in PROGMEM come la printo?

Eg
Code:

PROGMEM prog_char PageHttpOk[] = "HTTP/1.1 200 OK";
client.print( ?? );

Logged

Milan, Italy
Offline Offline
Sr. Member
****
Karma: 0
Posts: 329
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Non è che client è fuori dal contesto, prova a passare il client alla funzione esplicitamente come parametro tipo

Code:
PageHttpOk(Client mioclient) {
        mioclient.println(F("HTTP/1.1 200 OK"));
        mioclient.println(F("Content-Type: text/html"));
        mioclient.println();
        Serial.println(F("Debug: funzione inviata"));
}

e poi chiamala con

Code:
PageHttpOk(client);
Logged


0
Offline Offline
Shannon Member
****
Karma: 117
Posts: 10115
:(){:|:&};: TOX id: fcb8e918bef08581e23f6ddf9d4dba77697c25b217bf372736ed959a95fde36df5b8c5b90fbb
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

consuma un casino di ram perchè stai passando TUTTO l'oggetto, quando basta l'indirizzo:

Code:
PageHttpOk(&client); //passa l'indirizzo di client

Code:
PageHttpOk(Client* mioclient) //ricevi l'indirizzo di client nel puntatore mioclient{
        (*mioclient).println(F("HTTP/1.1 200 OK")); //usa il valore di mioclient
        (*mioclient).println(F("Content-Type: text/html"));
        (*mioclient).println();
        Serial.println(F("Debug: funzione inviata"));
}

c'è un pò di confusione perchè in C la dichiarazione e l'uso DEL VALORE si fa attraverso lo stesso simbolo, ovvero *
poi quì
PageHttpOk(Client* mioclient)
sembra che l'indirizzo finisca nel valore: invece no, succede una cosa simile;
Code:
Client* mioclient; //dichiarazione puntatore
mioclient = &client; //metti l'indirizzo di client nel puntatore
(*mioclient).println(); //usa IL VALORE contenuto nel puntatore, ovvero "client"!

comunque a quanto pare ha ragione bigjohnson: tu hai una dichiarazione globale di Client, che però non usi o contiene qualcosa che non ti serve.
Poi hai una dichiarazione locale, con lo stesso nome, all'interno del loop: per la visibilità delle variabili, tu usi sempre la locale, a meno che non fai this.nomevariabile.
A questo punto, è facile capire che se chiami la funzione senza parametri, la funzione usa la variabile globale che contiene roba che non ci interessa, e se invece passi il parametro passi l'istanza locale del loop, che è quella che ci serve.

Probabilmente NON ti serve avere queste 2 istanze separate (a meno che una rappresenta il server in ascolto e l'altra il client connesso, non conosco il tuo codice), quindi potresti eliminare una delle due. Visto che la locale sta nel loop, che quindi è sempre attivo, piuttosto che crearla e distruggerla ogni loop tieni quella globale, così risparmi i tempi di scrazione e distruzione dell'oggetto.

Se invece sei nel caso tra parentesi, usa 2 istanze globali, magari una chiamala server e una client, così non ti confonderai più, e cmq risparmi i tempi di creazione e distruzione, mantenendo lo stesso uso di ram.
Logged

my Arduino code: https://github.com/lestofante/arduinoSketch
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Milan, Italy
Offline Offline
Sr. Member
****
Karma: 0
Posts: 329
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Si si si si, molto meglio passare la variabile by reference che by value!
Concordo.
Logged


Offline Offline
God Member
*****
Karma: 0
Posts: 600
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Eccoci!
Allora, al solito complimentoni a lesto.

Io ho due istanze. Una per il web client (globale) ed una per il web server (locale)... entrambe nominate client!
Mi rendo conto ora che richiamando il client locale del webserver con una fx esterna in realtà passavo il client globale del webclient!
Ecco quindi spiegato perché non printava nulla.

Potrei rinominarle come suggerisce lesto, tuttavia se mantengo la sintassi attuale ovvero:
webclient globale e webserver locale, dovrò comunque creare un puntatore ed utilizzarne il valore contenuto, se sposto i print del webserver in una fx esterna.
Devo vedere se inizializzando entrambi webclient e webserver globali, con nomi diversi, ci guadango qualcosa in termini di sketch.

Cmq la sintassi di lesto è l'unica che compila, ho provato anche quella di bigJ ma dava una serie di errori.

Btw tutto questo lavoro ha portato un guadagno di 0.8k
Non male!

EDIT:
Ho provato ad inizializzare entrambi webserver e webclient globali, con nomi diversi.
In questo modo evito l'ultilizzo dei puntatori.
Tuttavia l'utilizzo dei puntatori con le istanze in locale occupa meno spazio in sketch.
Inizializzare globali sia webserver che web client nn conviene (questione di 0.1k, quindi poca roba... però qui nn si butta via niente.)

BTW2 alla fine utilizzo la sintassi di lesto, per futura memoria:
Code:
PageHttpOk(&client);
...
void PageHttpOk(Client* mioclient){
(*mioclient).println(F("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"));
}

Logged

0
Offline Offline
Shannon Member
****
Karma: 117
Posts: 10115
:(){:|:&};: TOX id: fcb8e918bef08581e23f6ddf9d4dba77697c25b217bf372736ed959a95fde36df5b8c5b90fbb
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Logged

my Arduino code: https://github.com/lestofante/arduinoSketch
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Offline Offline
God Member
*****
Karma: 0
Posts: 600
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Mi domando sempre se questi disegni li fai tu al volo o se ti sei fatto una cartellina riempita dopo lunghe esplorazioni in rete smiley-razz
Logged

0
Offline Offline
Shannon Member
****
Karma: 117
Posts: 10115
:(){:|:&};: TOX id: fcb8e918bef08581e23f6ddf9d4dba77697c25b217bf372736ed959a95fde36df5b8c5b90fbb
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

assolutamente internet. io non saprei disegnare manco uno stick man
Logged

my Arduino code: https://github.com/lestofante/arduinoSketch
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Pages: [1]   Go Up
Jump to: