What is RabbitWeb?

RabbitWeb is a system of special HTML tags combined with C compiler enhancements that take most of the work out of creating web page interfaces to control and monitor your Rabbit-based embedded systems. Web pages are the ideal remote interface for network-enabled systems. Who wants to create proprietary PC applications when everybody has a web browser already? However, the Common Gateway Interface (CGI) programming needed to create more than a simple interface between embedded application memory and HTML forms can be as time consuming as writing a custom PC application. If security is an issue, Z-World has a secure HTTPS server to provide embedded web pages with SSL level security with the addition a few lines of code.

Dynamic web page generation and HTML form input parsing can add thousands of lines of code and months of development time to a control program. RabbitWeb can reduce all this to a few compiler directives and some HTML tags, and a few days or even hours.

In addition to greatly reducing development time, this allows significant changes to the functionality of Web page interfaces to be made simply by updating web pages on embedded targets without loading new firmware.

Here is an example of a simple interface and how it is created with RabbitWeb: This example shows dynamic HTML generation based on the value of a C program variable. The variable value is input by clicking buttons on an HTML form. A character array in the C program is accessible from an HTML form also.

Source Code with RabbitWeb:

C Source HTML Source
#define TCPCONFIG 1
#define USE_RABBITWEB 1
#use "dcrtcp.lib"
#use "http.lib"

#ximport "/form.zhtml"  index_html

//*** Set up resources and handlers
SSPEC_MIMETABLE_START
  SSPEC_MIME_FUNC(".zhtml","text/html",zhtml_handler),
  SSPEC_MIME(".html", "text/html")
SSPEC_MIMETABLE_END
SSPEC_RESOURCETABLE_START
   SSPEC_RESOURCE_XMEMFILE("/", index_html),
   SSPEC_RESOURCE_XMEMFILE("/index.html",index_html)
SSPEC_RESOURCETABLE_END

//*** Define web variables
char text[64];
#web text
int func;
#web func

void main(){
   func = text[0] = 0;
   sock_init();
   http_init();

   while (1) {
      http_handler();
   }
}
<html><head><title>Sample form</title></head>
<body>
<FORM ACTION="/" METHOD="POST">
<?z if($func==0) { ?>
      <B>Enter Text:</B>
      <INPUT TYPE="TEXT" NAME="text" SIZE=50>
      <INPUT TYPE="hidden" NAME = "func" VALUE="1">
      <INPUT TYPE="SUBMIT" VALUE="Enter">
<?z } ?>
<?z if($func==1) { ?>
      Text: <?z echo($text) ?>
      <INPUT TYPE="hidden" NAME = "func" VALUE="0">
      <p><INPUT TYPE="SUBMIT" VALUE="Go Home">
<?z } ?>
</FORM>
</body>
</html>

This is the initially generated web page:

After we type in the string shown and hit Enter, this page is displayed.

The only lines of code needed in this C program to use RabbitWeb are these:

   #define USE_RABBITWEB 1
   SSPEC_MIME_FUNC(".zhtml","text/html",zhtml_handler)
   #web text
   #web func

All of the work of parsing HTML form input and conditionally generating HTML is handled by the HTTP engine in the tick call to http_handler(). Compare how much C code is needed without RabbitWeb to implement even this simple example. The parsing of input and dynamic generation of HTML is the programmer's responsibility.

The more elaborate the web page, the more error-prone and tedious the task of generating HTML in your C program. Interleaving HTML page elements that change depending on program values with decorative and informative elements that make a good, professional-looking web page is hard. RabbitWeb combines HTML scripting language concepts from the PC world with HTTP server customizations and C compiler/preprocessor extensions to make it easy.

Source Code without RabbitWeb:

C Source
#define TCPCONFIG 1
#define REDIRECTHOST _PRIMARY_STATIC_IP
#define REDIRECTTO  "http://" REDIRECTHOST ""
#use "dcrtcp.lib"
#use "http.lib"
#ximport "/form.html" index_html
int submit(HttpState* state);
SSPEC_RESOURCETABLE_START
   SSPEC_RESOURCE_XMEMFILE("/index.html", index_html),
   SSPEC_RESOURCE_FUNCTION("/submit.cgi", submit)
SSPEC_RESOURCETABLE_END
SSPEC_MIMETABLE_START
   SSPEC_MIME_FUNC(".shtml", "text/html", shtml_handler),
   SSPEC_MIME(".html", "text/html"),
   SSPEC_MIME(".cgi", "")
SSPEC_MIMETABLE_END

#define MAX_FORMSIZE 64
typedef struct {
   char *name;
   char value[MAX_FORMSIZE];
} FORMType;
FORMType FORMSpec;

int parse_post(HttpState* state){
   auto int retval;
   auto int i;
   retval = sock_aread(&state->s, state->p,
      (state->content_length < HTTP_MAXBUFFER-1)?
      (int)state->content_length:HTTP_MAXBUFFER-1);
   if (retval < 0) {
      return 1;
   }

   state->subsubstate += retval;
   if (state->subsubstate >= state->content_length) {
      state->buffer[(int)state->content_length] = '\0';
      http_scanpost(FORMSpec.name, state->buffer, FORMSpec.value, MAX_FORMSIZE);
      return 1;
   }
   return 0;
}

int submit(HttpState* state){
   auto int i;
   if(state->length) {
      if(state->offset < state->length) {
         state->offset +=
            sock_fastwrite(&state->s, state->buffer + (int)state->offset,
            (int)state->length - (int)state->offset);
      }
      else
      {
         state->offset = 0;
         state->length = 0;
      }
   }
   else
   {
      switch(state->substate)
      {
         case 0:
            strcpy(state->buffer,"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
            state->length = strlen(state->buffer);
            state->offset = 0; state->substate++;
            break;
         case 1:
            strcpy(state->buffer,
               "<html><head><title>Results</title></head><body>\r\n");
            state->length = strlen(state->buffer);
            state->substate++;
            break;
         case 2:
            FORMSpec.value[0] = '\0';
            state->p = state->buffer;
            state->substate++;
            break;
         case 3:
            if(parse_post(state)) {
               sprintf(state->buffer, "<p>Text: %s\r\n",FORMSpec.value);
               state->length = strlen(state->buffer);
               state->substate++;
            }
            break;
            case 4:
               strcpy(state->buffer,"<FORM ACTION=\"/\
                  " METHOD=\"POST\"><br>\r\n" \
                  "<INPUT TYPE=\"SUBMIT\" VALUE=\"Go Home\"></FORM>\r\n"
               );
               state->length = strlen(state->buffer);
               state->substate++;
               break;
            default:
               state->substate = 0;
               return 1;
      }
   }
   return 0;
}

main(){
   FORMSpec.name = "text";
   sock_init();
   http_init();

   while (1) {
       http_handler();
   }
}
HTML Source
<html><head><title>Sample form</title></head> 
<body>
   <FORM ACTION="submit.cgi" METHOD="POST">
   <B>Enter Text:</B>
   <INPUT TYPE="TEXT" NAME="text" SIZE=50>
   <INPUT TYPE="SUBMIT" VALUE="Enter">
   </FORM>
</body>
</html>

There are only three simple compiler directives and ten new HTML tags and associated syntax that developers need to learn to use RabbitWeb. The compiler directives allow the user to easily define:

If you are planning a to have a browser interface for your embedded application, you want RabbitWeb! The RabbitWeb module comes with plenty of sample programs and applications to get you started.

More information:
RabbitWeb Manual (300 Kbyte PDF)