CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

sprintf problem in webpage...
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
leejok2003



Joined: 25 Dec 2008
Posts: 32

View user's profile Send private message

sprintf problem in webpage...
PostPosted: Fri Feb 13, 2009 9:23 am     Reply with quote

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 &quot in code&quot 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 &nbsp; &nbsp; &nbsp;
<INPUT type=\"radio\" name=\"led1\" value=0 checked>OFF
<BR>LED2:<INPUT type=\"radio\" name=\"led2\" value=1>ON &nbsp; &nbsp; &nbsp;
<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

View user's profile Send private message

PostPosted: Sat Feb 14, 2009 8:25 am     Reply with quote

It's anyone there can help me?
Guest








PostPosted: Sat Feb 14, 2009 11:34 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Feb 14, 2009 10:32 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Feb 14, 2009 11:13 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Feb 15, 2009 12:51 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Feb 15, 2009 4:04 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Feb 15, 2009 10:25 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Feb 15, 2009 11:05 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Feb 16, 2009 6:27 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Feb 16, 2009 6:57 am     Reply with quote

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 Wink

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

View user's profile Send private message

PostPosted: Mon Feb 16, 2009 12:50 pm     Reply with quote

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 Very Happy
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Mon Feb 16, 2009 1:21 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Feb 16, 2009 2:35 pm     Reply with quote

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 Cool

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 Confused - 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 Rolling Eyes
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Mon Feb 16, 2009 5:33 pm     Reply with quote

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... Sad
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
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