Forum: Mikrocontroller und Digitale Elektronik uIP+httpd+Daten zum Webserver senden


von Stefan K. (whassup)


Lesenswert?

Hallo Zusammen,

ich nutze den uIP sowie den zugehörigen Web Server von Adam Dunkel.
Per cgi-calls kann ich auch Daten von meinem uC im Web-Client 
darstellen.

Nun möchte ich aber Daten im Web Client in ein Textfeld eingeben und per 
Knopfdruck an den Web Server schicken.
Könnte mir evtl. jemand einen Link zu einem Code-Beispiel schicken, der 
zeigt, wie das prinzipiell funktioniert?
Per Butten kann ja ein GET-Befehl an den Web Server geschickt werden. 
Aber an welcher Stelle im httpd.c Code kann ich diese Daten dann 
abfangen und weiterverarbeiten? ode geht das dann auch über cgi?

Vielen Dank für Eure Hilfe.
Gruß
Stefan

von Georg G. (df2au)


Lesenswert?

Nicht httpGET sondern httpPOST. Der Knopf im Formular macht dann 
"submit". Das kannst du bei der Auswertung des Headers im Server 
abfangen und passend verarbeiten.

Sieh dir als Beispiel mal den Radig Webserver an. Der ist zwar für einen 
anderen Stack und etwas buggy, aber für Anregungen prima geeignet, weil 
gut kommentiert.

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Mit GET.

Der Browser baut dann eine Anfrage nach dem Muster "GET scriptname".
Optional die Formulardaten als Wertepaare hinterher, jeweils mit &
getrennt in der Form name=wert.

Den String fängst Du auf und wertest ihn aus.

von Stefan K. (whassup)


Lesenswert?

Hallo Joachim,

wo (httpd.c? und in welcher Funktion?)kann ich den String abfangen? Gibt 
es dafür eine Call-back Funktion?
Danke.
Stefan

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Sers Stefan,

ich kenne den leider nicht. Aber irgendwo muß eine Stelle sein die
den String auswertet. Muß man halt finden (der Server muß ja auf
Eingaben reagieren können).

von Karl H. (kbuchegg)


Lesenswert?

Stefan K. schrieb:

> Könnte mir evtl. jemand einen Link zu einem Code-Beispiel schicken, der
> zeigt, wie das prinzipiell funktioniert?

Hast du doch schon.
Die "Settings" Seite im httpd ist genau so gemacht.

> Aber an welcher Stelle im httpd.c Code kann ich diese Daten dann
> abfangen und weiterverarbeiten? ode geht das dann auch über cgi?


Sieh dir im httpd-cgi.c an, wie er da die "Settings" Seite reingebaut 
hat

Es beginnt ganz oben, wo er offenbar ein 'Schlüsselwort' "settings" mit 
einer auszuführenden Funktion verknüpft
1
HTTPD_CGI_CALL(cgi_settings, "settings", run_settings);

Diese Verknüpfung muss in die Tabelle der Verknüpfungen eingetragen 
werden
1
static const struct httpd_cgi_call *calls[] = 
2
{ 
3
    &cgi_hello,
4
    &cgi_settings, 
5
    &cgi_welcome,
6
    NULL 
7
};

aufgerufen wird die Funktion offenbar, weil in der settings.shtml
1
%!: /header.html
2
<h1>Network Settings</h1><br>
3
%! settings
4
%!: /footer.html
genau dieses Schlüsselwort "%! settings" vorkommt, was den http Server 
offenbar veranlasst die entsprechende Funktion aufzurufen.

Die Funktion selber ist ebenfalls in httpd-cgi.c enthalten
1
static PT_THREAD(run_settings(struct httpd_state *s, PGM_P ptr))
2
{
3
  //NOTE:local variables are not preserved during the calls to proto socket functins
4
  static uint8_t pcount;
5
  PSOCK_BEGIN(&s->sout);
6
  //check if there are parameters passed 
7
  if(s->param[0] && (pcount=http_get_parameters_parse(s->param,sizeof(s->param)))>0)
8
  {
9
10
    static uint8_t i,j;
11
    static uint8_t result;
12
    result=(pcount==4 || pcount==5 ); //correct number of parameters
13
    _enable_dhcp=0;
14
    //walk through parameters
15
    for(i=0;i<pcount;i++)
16
    {
17
      static char *pname,*pval;
18
      pname=http_get_parameter_name(s->param,i,sizeof(s->param));
19
      pval =http_get_parameter_value(s->param,i,sizeof(s->param));
20
21
      if(!strcmp_P(pname,PSTR("mac")) )
22
      {
23
        result = result && ( decode_mac(pval,_eth_addr) == 6);
24
      } else if(!strcmp_P(pname,PSTR("dhcp")) )
25
      {
26
        _enable_dhcp=(pval[0]=='1');
27
      } else if(!strcmp_P(pname,PSTR("ip")) )
28
      {
29
30
        result = result && (decode_ip(pval,_ip_addr)==4);
31
      } else if(!strcmp_P(pname,PSTR("netmask")) )
32
      {
33
        result = result && (decode_ip(pval,_net_mask)==4);
34
      } else if(!strcmp_P(pname,PSTR("gw")) )
35
      {
36
        result = result && (decode_ip(pval,_gateway)==4);
37
      } else {
38
39
#if DEBUG_SERIAL
40
        printf_P(PSTR("Unknown:%s = %s\r\n"),pname,pval);
41
#endif
42
        result=0; //unknown parameter, probably an error!
43
      }
44
    }
45
    if(result) {
46
      eeprom_write_byte(&ee_enable_dhcp,_enable_dhcp);
47
      eeprom_write_block (_eth_addr,&ee_eth_addr,6);
48
      eeprom_write_block (_ip_addr, &ee_ip_addr, 4);
49
      eeprom_write_block (_net_mask,&ee_net_mask,4);
50
      eeprom_write_block (_gateway, &ee_gateway, 4);
51
      
52
      PSOCK_SEND_PSTR(&s->sout,PSTR("<b>Parameters Accepted, cycle power to make active!</b>"));
53
    } else {
54
      PSOCK_SEND_PSTR(&s->sout,PSTR("<b>Parameters incorrect!</b>"));
55
    }
56
  }
57
58
  _enable_dhcp=eeprom_read_byte(&ee_enable_dhcp);;
59
  eeprom_read_block ((void *)_eth_addr,(const void *)&ee_eth_addr,6);
60
  eeprom_read_block ((void *)_ip_addr, (const void *)&ee_ip_addr, 4);
61
  eeprom_read_block ((void *)_net_mask,(const void *)&ee_net_mask,4);
62
  eeprom_read_block ((void *)_gateway, (const void *)&ee_gateway, 4);
63
64
  char temp[30];
65
  PSOCK_SEND_PSTR(&s->sout,PSTR("\
66
<form action=\"/settings.shtml\" method=\"get\" bgcolor=\"#808080\">\ 
67
<table>\
68
<tr><td>MAC:</td><td><input type=\"text\" name=\"mac\" size=\"18\" maxlength=\"18\" value=\""));
69
70
  snprintf_P(temp,sizeof(temp),PSTR("%02x:%02x:%02x:%02x:%02x:%02x"),
71
   (int)_eth_addr[0],(int)_eth_addr[1],(int)_eth_addr[2],
72
   (int)_eth_addr[3],(int)_eth_addr[4],(int)_eth_addr[5]);
73
74
  PSOCK_SEND_STR(&s->sout,temp);
75
76
  PSOCK_SEND_PSTR(&s->sout,PSTR("\"></td></tr>\
77
<tr><td>DHCP:</td><td><input type=\"checkbox\" name=\"dhcp\" value=\"1\""));
78
79
  if(_enable_dhcp) 
80
    PSOCK_SEND_PSTR(&s->sout,PSTR("CHECKED"));
81
82
  PSOCK_SEND_PSTR(&s->sout,PSTR("/></td></tr>\
83
<tr><td>IP:</td><td><input type=\"text\" name=\"ip\" size=\"15\" maxlength=\"15\" value=\""));
84
85
  snprintf_P(temp,sizeof(temp),PSTR("%d.%d.%d.%d"),
86
   (int)_ip_addr[0],(int)_ip_addr[1],(int)_ip_addr[2],(int)_ip_addr[3]);
87
88
  PSOCK_SEND_STR(&s->sout,temp);
89
90
PSOCK_SEND_PSTR(&s->sout,PSTR("\"></td></tr>\
91
<tr><td>Netmask:</td><td><input type=\"text\" name=\"netmask\" size=\"15\" maxlength=\"15\" value=\""));
92
93
  snprintf_P(temp,sizeof(temp),PSTR("%d.%d.%d.%d"),
94
   (int)_net_mask[0],(int)_net_mask[1],(int)_net_mask[2],(int)_net_mask[3]);
95
96
  PSOCK_SEND_STR(&s->sout,temp);
97
98
  PSOCK_SEND_PSTR(&s->sout,PSTR("\"/></td></tr>\
99
<tr><td>Gateway:</td><td><input type=\"text\" name=\"gw\" size=\"15\" maxlength=\"15\" value=\""));
100
101
  snprintf_P(temp,sizeof(temp),PSTR("%d.%d.%d.%d"),
102
   (int)_gateway[0],(int)_gateway[1],(int)_gateway[2],(int)_gateway[3]);
103
104
  PSOCK_SEND_STR(&s->sout,temp);
105
106
  PSOCK_SEND_PSTR(&s->sout,PSTR("\"/></td></tr>\
107
<tr align=\"justify\"><td colspan=2><INPUT TYPE=submit VALUE=\"Submit\">  <INPUT TYPE=reset VALUE=\"Reset\"></td></tr>\
108
</table></form>"));
109
110
  PSOCK_END(&s->sout);
111
}

und unterscheidet 2 Modi.
Wird sie mit oder ohne Parameter aufgerufen.
Ohne Parameter, der Fall kommt dann zum Zug, wenn die settings.shtml von 
einer anderen Seite verlinkt wurde und über diesen Link betreten wird.
Mit Parameter: Der Fall tritt deswegen ein, weil bei der Erzeugung des 
Formulars
1
... <form action=\"/settings.shtml\"  ....
wieder settings.shtml als Empfänger angegeben wurde


Das ist alles keine Raketentechnik. Aber ein wenig C sollte man schon 
können.

von Stefan K. (whassup)


Lesenswert?

Vielen Dank für die ausführliche Beschreibung.
Die Datei settings.shtml ist in meinem UIP-Stack + http Server nicht 
enthalten. Da gibts nur Beispiele für Status-Anzeigen und nichts zum 
Schreiben in Richtung http-Server.
Auf googlecode.com habe ich aber ein avr uhttpd Beispiel gefunden, dass 
deiner Beschreibung entspricht. Werde ich nun mal ausprobieren.
Also, noch mal vielen Dank.
Gruß
Stefan

von web neuling (Gast)


Lesenswert?

Karl Heinz schrieb:
> Stefan K. schrieb:
>
>> Könnte mir evtl. jemand einen Link zu einem Code-Beispiel schicken, der
>> zeigt, wie das prinzipiell funktioniert?

> Sieh dir im httpd-cgi.c an, wie er da die "Settings" Seite reingebaut
> hat
>
> Es beginnt ganz oben, wo er offenbar ein 'Schlüsselwort' "settings" mit
> einer auszuführenden Funktion verknüpftHTTPD_CGI_CALL(cgi_settings,
> "settings", run_settings);

> Die Funktion selber ist ebenfalls in httpd-cgi.c enthaltenstatic
> PT_THREAD(run_settings(struct httpd_state *s, PGM_P ptr))


schade das läuft nicht unter keil
bei mir kommt der fehler
httpd-cgi.c(1526): error:  #136: struct "httpd_state" has no field 
"param"

von Stefan F. (Gast)


Lesenswert?

Schau Dir mal meine Firmware an: 
http://stefanfrings.de/avr_io/index.html

Mein httpd ist inzwischen weit von dem ursprünglichen entfernt, aber mit 
etwas Phantasie kannst du den gemeinsamen Ursprung noch erkennen :-)

Jedenfalls habe ich da genau das implementiert, was du brauchst. 
Vermutlich findest du dort hilfreiche Lösungsansätze.

von Stefan F. (Gast)


Lesenswert?

Schau dir in httpd-functions.c zuerst die Funktion 
httpd_function_dispatcher() an, da wird je nach Parameter eine andere 
Unterfunktion aufgerufen.

Und in httpd.c kannst du dir anschauen, wie die URL in 
Dateiname/Funktionsname und Parameter gesplittet wird. Genau genommen 
wir gar nicht gesplittet, sondern nur zwei Pointer auf die Positionen 
gesetzt und Null-bytes eingefügt.

von web neuling (Gast)


Angehängte Dateien:

Lesenswert?

ich spiele ein bischen mit diesen 
Beitrag "ARM-Webserver auf uIP-Basis" Webserver.
Meine Leds kann ich damit schalten.
nun wollte ich in einem Textfeld etwas eingeben die seite wird mir auch 
angezeigt.
Aber die Variable pcount bleibt immer null.

könnte mir jemand weiterhelfen
danke

1
uint8_t http_get_parameters_parse(char *par,uint8_t mx)
2
{ 
3
  uint8_t count=0;
4
  uint8_t i=0;
5
  
6
  for(;par[i]&&i<mx;i++)
7
  {
8
    if(par[i]=='=') 
9
    {
10
      count++;
11
      par[i]=0;
12
    } else if(par[i]=='&')
13
      par[i]=0;
14
  }
15
16
  return count;
17
}
18
19
char * http_get_parameter_name(char *par,uint8_t cnt,uint8_t mx)
20
{
21
  uint8_t i,j;
22
  cnt*=2;
23
  for(i=0,j=0;j<mx&&i<cnt;j++)
24
    if(!par[j]) i++;
25
26
  return j==mx?"":par+j;
27
}
28
29
char * http_get_parameter_value(char *par,uint8_t cnt,uint8_t mx)
30
{
31
  uint8_t i,j;
32
  cnt*=2;
33
  cnt++;
34
  for(i=0,j=0;j<mx&&i<cnt;j++)
35
    if(!par[j]) i++;
36
37
  return j==mx?"":par+j;
38
}
39
40
void http_url_decode(const char *in,char *out,uint8_t mx)
41
{
42
  uint8_t i,j;
43
  char tmp[3]={0,0,0};
44
  for(i=0,j=0;j<mx&&in[i];i++)
45
  {
46
    if(in[i]=='%')
47
    {
48
      tmp[0]=in[++i];
49
      tmp[1]=in[++i];
50
51
      out[j++]=(char)strtol(tmp,NULL,16);
52
    } else 
53
      out[j++]=in[i];
54
  }
55
}
56
57
static uint8_t decode_ip(char *in,uint8_t *out)
58
{
59
  uint8_t i;
60
  char tmp[20];
61
  char *dig;
62
  strncpy(tmp,in,sizeof(tmp));
63
  
64
  dig=strtok(tmp,".");
65
66
  for(i=0 ; i<4 && dig ;i++,dig=strtok(NULL,"."))
67
    out[i]=(uint8_t)strtoul(dig,NULL,10);
68
69
  return i;
70
}
71
72
static uint8_t decode_mac(char *in,uint8_t *out)
73
{
74
  char tmp[20];
75
  char *dig;
76
  uint8_t i;  
77
  http_url_decode(in,tmp,sizeof(tmp)-1);
78
79
80
  
81
  dig=strtok(tmp,":");
82
83
  for(i=0 ; i<6 && dig ;i++,dig=strtok(NULL,":"))
84
    out[i]=(uint8_t)strtoul(dig,NULL,16);
85
86
  return i;
87
}
88
89
90
91
92
93
static PT_THREAD(run_settings(struct httpd_state *s, char *ptr))
94
{  char temp[30];
95
    static uint8_t i,j;
96
    static uint8_t result;
97
    static char *pname,*pval;  
98
  //NOTE:local variables are not preserved during the calls to proto socket functins
99
   uint8_t pcount;
100
    PSOCK_BEGIN(&s->sout);
101
102
  //check if there are parameters passed 
103
  if(s->param[0] && pcount=http_get_parameters_parse(s->param,sizeof(s->param)))>0)
104
105
  
106
  {
107
108
109
    result=(pcount==4 || pcount==5 ); //correct number of parameters
110
    _enable_dhcp=0;
111
    //walk through parameters
112
    for(i=0;i<pcount;i++)
113
    {
114
      
115
      pname=http_get_parameter_name(s->param,i,sizeof(s->param));
116
      pval =http_get_parameter_value(s->param,i,sizeof(s->param));
117
118
      
119
      if(!strcmp(pname,("mac")) )
120
      {  
121
        result = result && ( decode_mac(pval,_eth_addr) == 6);
122
      } 
123
      else if(!strcmp(pname,("dhcp")) )
124
      {  
125
        _enable_dhcp=(pval[0]=='1');
126
      } 
127
      else if(!strcmp(pname,("ip")) )
128
      {  
129
130
        result = result && (decode_ip(pval,_ip_addr)==4);
131
      } 
132
      else if(!strcmp(pname,("netmask")) )
133
      {  
134
        result = result && (decode_ip(pval,_net_mask)==4);
135
      } 
136
      else if(!strcmp(pname,("gw")) )
137
      {  
138
        result = result && (decode_ip(pval,_gateway)==4);
139
      } else {
140
141
#if DEBUG_SERIAL
142
        printf_P(PSTR("Unknown:%s = %s\r\n"),pname,pval);
143
#endif
144
        result=0; //unknown parameter, probably an error!
145
      }
146
    }
147
    if(result) {
148
      eeprom_write_byte(&ee_enable_dhcp,_enable_dhcp);
149
      eeprom_write_block (_eth_addr,&ee_eth_addr,6);
150
      eeprom_write_block (_ip_addr, &ee_ip_addr, 4);
151
      eeprom_write_block (_net_mask,&ee_net_mask,4);
152
      eeprom_write_block (_gateway, &ee_gateway, 4);
153
    
154
      PSOCK_SEND_STR(&s->sout,("Parameters Accepted, cycle power to make active!"));
155
    } else {
156
      PSOCK_SEND_STR(&s->sout,("Parameters incorrect!"));
157
    }
158
  }
159
160
  _enable_dhcp=eeprom_read_byte(&ee_enable_dhcp);;
161
  eeprom_read_block ((void *)_eth_addr,(const void *)&ee_eth_addr,6);
162
  eeprom_read_block ((void *)_ip_addr, (const void *)&ee_ip_addr, 4);
163
  eeprom_read_block ((void *)_net_mask,(const void *)&ee_net_mask,4);
164
  eeprom_read_block ((void *)_gateway, (const void *)&ee_gateway, 4);
165
166
  
167
  PSOCK_SEND_STR(&s->sout,("\<form action=\"/setting.shtml\" method=\"get\" bgcolor=\"#808080\">\<table>\<tr><td>MAC:</td><td><input type=\"text\" name=\"mac\" size=\"18\" maxlength=\"18\" value=\""));
168
169
  snprintf(temp,sizeof(temp),("%02x:%02x:%02x:%02x:%02x:%02x"),
170
   (int)_eth_addr[0],(int)_eth_addr[1],(int)_eth_addr[2],
171
   (int)_eth_addr[3],(int)_eth_addr[4],(int)_eth_addr[5]);
172
173
  PSOCK_SEND_STR(&s->sout,temp);
174
175
  PSOCK_SEND_STR(&s->sout,("\"></td></tr>\<tr><td>DHCP:</td><td><input type=\"checkbox\" name=\"dhcp\" value=\"1\""));
176
177
  if(_enable_dhcp) 
178
    PSOCK_SEND_STR(&s->sout,("CHECKED"));
179
180
  PSOCK_SEND_STR(&s->sout,("/></td></tr>\<tr><td>IP:</td><td><input type=\"text\" name=\"ip\" size=\"15\" maxlength=\"15\" value=\""));
181
182
  snprintf(temp,sizeof(temp),("%d.%d.%d.%d"),
183
   (int)_ip_addr[0],(int)_ip_addr[1],(int)_ip_addr[2],(int)_ip_addr[3]);
184
185
  PSOCK_SEND_STR(&s->sout,temp);
186
187
PSOCK_SEND_STR(&s->sout,("\"></td></tr>\<tr><td>Netmask:</td><td><input type=\"text\" name=\"netmask\" size=\"15\" maxlength=\"15\" value=\""));
188
189
  snprintf(temp,sizeof(temp),("%d.%d.%d.%d"),
190
   (int)_net_mask[0],(int)_net_mask[1],(int)_net_mask[2],(int)_net_mask[3]);
191
192
  PSOCK_SEND_STR(&s->sout,temp);
193
194
  PSOCK_SEND_STR(&s->sout,("\"/></td></tr>\<tr><td>Gateway:</td><td><input type=\"text\" name=\"gw\" size=\"15\" maxlength=\"15\" value=\""));
195
196
  snprintf(temp,sizeof(temp),("%d.%d.%d.%d"),
197
   (int)_gateway[0],(int)_gateway[1],(int)_gateway[2],(int)_gateway[3]);
198
199
  PSOCK_SEND_STR(&s->sout,temp);
200
201
  PSOCK_SEND_STR(&s->sout,("\"/></td></tr>\<tr align=\"justify\"><td colspan=2><INPUT TYPE=submit VALUE=\"Submit\">  <INPUT TYPE=reset VALUE=\"Reset\"></td></tr>\</table></form>"));
202
203
  PSOCK_END(&s->sout);
204
}

von Stefan F. (Gast)


Lesenswert?

Für meinen Geschmack ist das zuviel code um ihn rein theoretisch nur im 
Kopf durchzuanalysieren.

Nutze den seriellen Port, um Debug Meldungen zu loggen. Jede Funktion 
loggt am Anfange, dass sie aufgerufen wurde und mit welchen Parametern. 
Nach jedem if-Ausdruck loggst du das Ergebnis (ob es strue oder false 
ergab).

Damit kannst du Schrittweise herausfinden, was genau das Programm tut 
oder auch nicht tut. Oder verwende einen Hardware Debugger, falls 
verfügbar.

von wen neuling (Gast)


Lesenswert?

Hallo
Das Problem  ist das Point immer Null bleibt
Und somit die if nicht war wird

if(s->param[0] && 
pcount=http_get_parameters_parse(s->param,sizeof(s->param)))>0)

von wen neuling (Gast)


Lesenswert?

wen neuling schrieb:
> Hallo
> Das Problem  ist das Point immer Null bleibt
> Und somit die if nicht war wird
>
> if(s->param[0] &&
> pcount=http_get_parameters_parse(s->param,sizeof(s->param)))>0)

Ich meinte pcount

So als ob der String vom Browser  nicht empfangen wird

von Stefan F. (Gast)


Lesenswert?

Ja dann logge doch mal den kompletten Request.

von wen neuling (Gast)


Lesenswert?

Hallo
So das beispiel funktioniert bei mir eigentlich ganz gut bis auf das ich 
den
button Submit 2mal anklicken muss damit die werte übernommen werden.
beim 1mal anklicken gehts nich.

nutze den aktuellen Mozilla

Woran könnte das liegen.

mfg

von Stefan F. (Gast)


Lesenswert?

Es kann an einem Programmfehler liegen. Mal im ernst - ohne Logmeldungen 
bzw. Debugger kann jetzt nur noch reines Raten stattfinden.

von web neuling (Gast)


Lesenswert?

Einen Debugger hab ich nicht
Das Beispiel läuft ja die werte werden gespeichert,halt nur beim 2ten 
anklicken.
Beitrag "Re: uIP+httpd+Daten zum Webserver senden"

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.