|
|
View previous topic :: View next topic |
Author |
Message |
leejok2003
Joined: 25 Dec 2008 Posts: 32
|
sprintf problem in webpage... |
Posted: Fri Feb 13, 2009 9:23 am |
|
|
Hi,
I am working with CCS TCPIP stack for a microcontroller based web server. I am facing problem in printing the values in CGI in the webpage. The value printed for the first variable will include the 2nd variable as well. e.g if var1=90, var2="hello" then the result printed in var1 will be "90hel" something like this. Below is the code I wrote:
Code: |
#define STACK_USE_ICMP 1
#define STACK_USE_ARP 1
#define STACK_USE_TCP 1
#define STACK_USE_HTTP 1
#include "ccstcpip.h"
#if STACK_USE_CCS_PICENS
#include "tcpip/mlcd.c"
#else
#include "tcpip/dlcd.c"
#endif
int sta1,sta2,pus;
//here is this examples / page
const char HTML_INDEX_PAGE[]="
<HTML>
<HEAD>
<META HTTP-EQUIV=REFRESH CONTENT=8>
<\HEAD>
<TITLE>Monitoring Page</TITLE>
<BODY BGCOLOR=#ADD8E6 TEXT=#000000>
<H1 align= center>CCS HTTP/CGI EXAMPLE</H1>
<HR>
<BR><I>This is a prototype which uses " in code" html page edit.</I>
<FORM METHOD=GET>
<P>LCD: <INPUT TYPE=\"text\" NAME=\"lcd\" size=20 maxlength=16>
<BR>LED1:<INPUT type=\"radio\" name=\"led1\" value=1>ON
<INPUT type=\"radio\" name=\"led1\" value=0 checked>OFF
<BR>LED2:<INPUT type=\"radio\" name=\"led2\" value=1>ON
<INPUT type=\"radio\" name=\"led2\" value=0 checked>OFF
<BR><INPUT TYPE=\"submit\"></FORM>
<\P>
<P>
STATUS
<TABLE WIDTH=100% BORDER-STYLE: BORDER >
<TR>
<TD>
%4
<\TD>
<\TR>
<TR>
<TD>
%5
<\TD>
<\TR>
<TR>
<TD>
%2
<\TD>
<\TR>
<TR>
<TD>
%3
<\TD>
<\TR>
<\TABLE>
<BR>
<\P>
<P ALIGN=LEFT><A HREF=\"/analog\">Analog Readings</A><\P>
</BODY></HTML>
";
const char HTML_ANALOG_PAGE[]="
<HTML><BODY BGCOLOR=#ADD8E6 TEXT=#000000>
<HEAD>
<META HTTP-EQUIV=REFRESH CONTENT=8>
<\HEAD>
<H1>PICNET ADC READINGS</H1>
<TABLE>
<TR>
<TD>
<DIV>Temperature</DIV>
</TD>
<TD><DIV STYLE= BACKGROUND-COLOR:GREEN; WIDTH: HORX>%0<\DIV>
</TD>
</TR>
<TR>
<TD>
<\TD>
<\TR>
</TABLE>
<BR>%1
<P><A HREF=\"/\">Change LCD/LEDs</A>
</BODY></HTML>
";
//this is a callback function to the HTTP stack. see http.c
//this demo provides to web "pages", an index (/) and an about page (/about)
int32 http_get_page(char *file_str) {
int32 file_loc=0;
static char index[]="/";
static char about[]="/analog";
printf("\r\nRequest %s ",file_str);
if (stricmp(file_str,index)==0)
file_loc=label_address(HTML_INDEX_PAGE);
else if (stricmp(file_str,about)==0)
file_loc=label_address(HTML_ANALOG_PAGE);
if (file_loc)
printf("(FILE=%LU)",file_loc);
else
printf("(File Not Found)");
return(file_loc);
}
//this is a callback function to the HTTP stack. see http.c
// this demo provides handling for two formatting chars, %0 and %1.
// %0 is ADC for channel 0, %1 is ADC for channel 1.
/*
%0=AN0
%1=AN1
%2 - CHECKED if LED1 is ON
%3 - CHECKED if LED1 is OFF
%4 - CHECKED if LED2 is ON
%8 - CHECKED if LED2 is OFF
*/
int8 http_format_char(int32 file, char id, char *str, int8 max_ret) {
char new_str[20];
int8 len=0;
float i,temp,real_volt;
*str=0;
switch(id)
{
case '0':
set_adc_channel(0);
delay_us(100);
i=read_adc();
real_volt=((float)i/204.6);
temp= real_volt*100;
sprintf(new_str,"<B>%1.1f </B>",temp);
//printf("\r\n temperature= %1.1f",temp);
len=strlen(new_str);
break;
#if defined(USER_BUTTON1)
case '4':
sprintf(new_str,"<B>BTN1 = </B>");
if (input(USER_BUTTON1))
sprintf(&new_str[14], "ON");
else
sprintf(&new_str[14], "OFF");
len=strlen(new_str);
break;
#endif
#if defined(USER_BUTTON2)
case '5':
sprintf(new_str,"<B>BTN2 = </B>");
if (input(USER_BUTTON2))
sprintf(&new_str[14], "ON");
else
sprintf(&new_str[14], "OFF");
len=strlen(new_str);
break;
#endif
case '1':
#if STACK_USE_CCS_PICNET
set_adc_channel(1);
delay_us(100);
i=read_adc();
sprintf(new_str,"<B>AN1 = </B>0x%X",i);
len=strlen(new_str);
#else
len=0;
#endif
break;
case '2':
sprintf(new_str,"<B>LED1= </B>%D",sta1);
len=strlen(new_str);
break;
case '3':
sprintf(new_str, "<B>LED2= </B>%D",sta2);
len=strlen(new_str);
break;
}
if (len) {
if (len>max_ret) {len=max_ret;}
memcpy(str,new_str,len);
}
return(len);
}
//this is a callback function to the HTTP stack. see http.c
//in this example it verifies that "pwd" is "master", if it is
//then it sets led1 and led2 ("led1" and "led2") based on their value
//and changes the lcd screen ("lcd").
void http_exec_cgi(int32 file, char *key, char *val) {
static char led1_key[]="led1";
static char led2_key[]="led2";
static char lcd_key[]="lcd";
int8 v;
printf("\r\nCGI FILE=%LD KEY=%S VAL=%S", file, key, val);
if (stricmp(key,led1_key)==0) {
v=atoi(val);
if (!v)
{output_low(USER_LED1);
sta1=0;}
else {output_high(USER_LED1);
sta1=1;}
}
if (stricmp(key,led2_key)==0) {
v=atoi(val);
if (!v)
{output_low(USER_LED2);
sta2=0;}
else {output_high(USER_LED2);
sta2=1;}
}
if (stricmp(key,lcd_key)==0) {
printf(lcd_putc,"\f%s",val);
}
}
void main(void)
{
printf("\r\n PIC ready");
MACAddrInit();
IPAddrInit();
init_user_io();
//lcd_init();
//printf(lcd_putc,"\fCCS CGI Example\nWaiting");
printf("\r\n\nCCS CGI Example\r\nWaiting");
setup_adc_ports(AN0); // saluran 0 sbg input analog
setup_adc(ADC_CLOCK_DIV_64); // 20000000/625000 = 30.769 => 32
StackInit();
while(TRUE) {
StackTask();
}
}
|
The webpage coding is inside the code...can anyone help me with this?? Thank you... |
|
|
leejok2003
Joined: 25 Dec 2008 Posts: 32
|
|
Posted: Sat Feb 14, 2009 8:25 am |
|
|
It's anyone there can help me? |
|
|
Guest
|
|
Posted: Sat Feb 14, 2009 11:34 am |
|
|
Hi
Maybe I am wrong but I expire problem if a const is longer than 512 byte.
If so I normally split it in smaller parts. |
|
|
leejok2003
Joined: 25 Dec 2008 Posts: 32
|
|
Posted: Sat Feb 14, 2009 10:32 pm |
|
|
Anonymous wrote: | Hi
Maybe Iam wrong but I expire problem if a const is longer than 512 byte.
If so I normally split it in smaller parts. |
Hi, can you please explain it further? I am really in a big problem now...thanks. |
|
|
MikeP
Joined: 07 Sep 2003 Posts: 49
|
|
Posted: Sat Feb 14, 2009 11:13 pm |
|
|
Code: | int8 http_format_char(int32 file, char id, char *str, int8 max_ret) {
char new_str[20];
int8 len=0;
float i,temp,real_volt;
|
Try making the i variable an int16 |
|
|
leejok2003
Joined: 25 Dec 2008 Posts: 32
|
|
Posted: Sun Feb 15, 2009 12:51 am |
|
|
MikeP wrote: | Code: | int8 http_format_char(int32 file, char id, char *str, int8 max_ret) {
char new_str[20];
int8 len=0;
float i,temp,real_volt;
|
Try making the i variable an int16 |
I have tried and it seems still the same... |
|
|
eskimobob
Joined: 07 Feb 2009 Posts: 40
|
|
Posted: Sun Feb 15, 2009 4:04 am |
|
|
A few questions:
1) Why have you commented out lcd_init() - how do you initialise the lcd instead?
2) In your HTML, you do not specify an escape character for the LCD value. What are you expecting the LCD box in the webpage to show? - or are you only using that box for input that you want to show on the actual LCD itself?
3) In your "http_exec_cgi", you are printing the key and value pairs to the serial port. Do you see what you would expect on the serial port?
4) Presumably your var2="hello" is coming from the text types into the LCD box on the webpage. Where is var1=90 coming from?
It looks like the null terminations are not being added between values but I'm not convinced your code makes sense at the moment. Does the CCS example work correctly? |
|
|
leejok2003
Joined: 25 Dec 2008 Posts: 32
|
|
Posted: Sun Feb 15, 2009 10:25 am |
|
|
eskimobob wrote: | A few questions:
1) Why have you commented out lcd_init() - how do you initialise the lcd instead?
2) In your HTML, you do not specify an escape character for the LCD value. What are you expecting the LCD box in the webpage to show? - or are you only using that box for input that you want to show on the actual LCD itself?
3) In your "http_exec_cgi", you are printing the key and value pairs to the serial port. Do you see what you would expect on the serial port?
4) Presumably your var2="hello" is coming from the text types into the LCD box on the webpage. Where is var1=90 coming from?
It looks like the null terminations are not being added between values but I'm not convinced your code makes sense at the moment. Does the CCS example work correctly? |
Hi eskimobob,
1. I didn't use the LCD function in the page, it was included in the examples by CCS.
2. this function are also comes with the examples, I use the key to update the status and the output in serial port is ok.
3. the var was assigned in the example...I didn't really care about it.
The CCS example does work fine, but when I added more status to monitor, the var display goes wrong. |
|
|
eskimobob
Joined: 07 Feb 2009 Posts: 40
|
|
Posted: Sun Feb 15, 2009 11:05 am |
|
|
leejok2003 wrote: | 1. I didn't use the LCD function in the page, it was included in the examples by CCS. |
Sorry, something does not make sense. If you are not using the LCD, why in "http_exec_cgi" are you printing to the LCD? - eg:
"printf(lcd_putc,"\f%s",val);"
If you are using the LCD then why are you not calling lcd_init?
leejok2003 wrote: | 2. this function are also comes with the examples, I use the key to update the status and the output in serial port is ok. |
Do you mean, referring to the embedded HTML, you are trying to update variables %4, %5, %2 and %3?
leejok2003 wrote: | 3. the var was assigned in the example...I didn't really care about it. |
I am really confused - which values do you care about and which do you not care about - eg where does var1=90 and var2='hello' come from? - Are these values you intend to submit to the webpage?
leejok2003 wrote: | The CCS example does work fine, but when I added more status to monitor, the var display goes wrong. |
I'd suggest starting again with the CCS example since it works. Add in a new variable and tell us what goes wrong. It should be easier to spot the problem then. I've added to the CCS example and it works for me. |
|
|
leejok2003
Joined: 25 Dec 2008 Posts: 32
|
|
Posted: Mon Feb 16, 2009 6:27 am |
|
|
Hi eskimobob,
Sorry for confusing you...i will try my best to explain about my question:
1. I forgot to comment the LCD there. In my board, i didn't use LCD, so i just comment the "lcd_init(); and printf(lcd_putc,"\fCCS CGI Example\nWaiting");"
2. About the var =90 and var=hello, actually they are the var in %4, %5 and so on, which i want to submit them in the webpage. In my page, %4 refers to button 1 and %5 is button 2, and print out in the page as "ON" if the button is pushed and "OFF" if opened. The original TCPIP examples did shows these variable in the page and it works fine initially.
3. After i added other variable like led status (%2 and %3), the LED status there by default should print "1" or "0". But in actual, it prints "1On " or "1Of" depending the state of button. |
|
|
eskimobob
Joined: 07 Feb 2009 Posts: 40
|
|
Posted: Mon Feb 16, 2009 6:57 am |
|
|
Hi leejok2003,
I think I understand what you are asking now.
leejok2003 wrote: | 1. I forgot to comment the LCD there. In my board, i didn't use LCD, so i just comment the "lcd_init(); and printf(lcd_putc,"\fCCS CGI Example\nWaiting");" |
Since you are not using the LCD, remember also to comment out a few lines in http_exec_cgi as follows:
Code: | if (stricmp(key,lcd_key)==0) {
printf(lcd_putc,"\f%s",val);
}
|
leejok2003 wrote: | 3. After i added other variable like led status (%2 and %3), the LED status there by default should print "1" or "0". But in actual, it prints "1On " or "1Of" depending the state of button. |
That's odd. It looks like you need to figure out why the line is not being null terminated correctly.
It's probably not an issue but I'd change your uppercase D to lower case:
sprintf(new_str,"<B>LED1= </B>%D",sta1);
change to
sprintf(new_str,"<B>LED1= </B>%d",sta1);
As a test, you could always hard code it to see if you still get the same effect:
sprintf(new_str,"<B>LED1= </B>1");
Could also try:
sprintf(new_str,"<B>LED1= </B>%d%c",sta1,0);
Or initialise new_str so that all chars are \0 to begin with.
This won't solve the problem but should give some pointers
Edit: Thinking about it a bit more, it's possibly not a null termination thing because if it was, it ought to show "1On" or "0Of". I'm happy to try out your code if you wish - since we have both bought TCP-IP stack then that should be fine - PM me if you like. |
|
|
eskimobob
Joined: 07 Feb 2009 Posts: 40
|
|
Posted: Mon Feb 16, 2009 12:50 pm |
|
|
Hi leejok2003,
Thanks for sending your code; as it happens, I didn't need it since the same problem exists in the CCS examples! Anyway, I have found the problem and it now works for me. It is a null termination problem as I thought and it is simple to fix.
In the function "http_format_char", find the line:
Code: | memcpy(str,new_str,len);
|
and change it to:
Code: | memcpy(str,new_str,len + 1);
|
Basically this causes an extra character (the null termination) to be copied across to the destination. Without that, the static destination array will be terminated by whatever the longest string is that gets copied.
That was why you were seeing incorrect results, the destination had been filled with the string for On or Off and therefore it contained a longer string than you were copying later (the 1 or 0).
Good luck with the rest of your project |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon Feb 16, 2009 1:21 pm |
|
|
Nice find!
Has this bug been reported to CCS so they can incorporate it in the next release?
Also, I would recommend a slightly different fix as the proposed solution does not correct for the maximum allowed buffer length.
Change: Code: | if (len) {
if (len>max_ret) {len=max_ret;}
memcpy(str,new_str,len);
} | to: Code: | if (len){
strncpy(str, new_str, max_ret);
}else
*str=0; | This last code part was taken from the same function in ex_st_webserver.c |
|
|
eskimobob
Joined: 07 Feb 2009 Posts: 40
|
|
Posted: Mon Feb 16, 2009 2:35 pm |
|
|
ckielstra wrote: | Also, I would recommend a slightly different fix as the proposed solution does not correct for the maximum allowed buffer length. |
Good point ckielstra
Yes, I have emailed CCS support to inform them that there is a problem with it. I wonder what their response will be.
I guess if we are being accurate, we ought to ensure that it is always null terminated under all circumstances. Also, since the function returns the result "len", we need to adjust that value as below.
Code: |
if (len)
{
strncpy(str, new_str, max_ret);
if (len >= max_ret)
{
len = max_ret - 1;
*(str + len) = 0;
}
}
else
{
*str = 0;
}
return(len);
|
Would you agree - If so, it seems that "ex_st_webserver.c" needs attention too.
Even then, the example is still not perfect since max_ret can be 39 characters whereas the space allocated for new_str is only 20 characters. It could still behave badly |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon Feb 16, 2009 5:33 pm |
|
|
I assumed strncpy always adds a terminating zero, but I was wrong. And yes, the returned len value should be adjusted in case of buffer truncation. Your suggested code looks fine to me.
So we have two example programs with two bugs each... |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|