Software Structure
You have to make two files to CGI.
- HTML file included Form script
- Load module
Illustlate this structure.
This CGI must have five functions.
- Get command strings from standard input(stdin)
- Analyze command strings
- Put control signals
- Get sensor states
- Generate HTML script
After define system functions, write source code step by step.
Get command strings from standard input(stdin)
Get string length from 'Environment Variable' CONTENT_LENGTH
in order to get 'POST' formated strings.
When you will store these strings temporarily,
apply malloc system call.
Apply fread system call to store strings.
char *pcCL = getenv("CONTENT_LENGTH");
char *pcQS = NULL ;
int nCL ;
if ( pcCL != NULL ) {
nCL = 0 ;
sscanf( pcCL , "%d" , &nCL );
if ( nCL > 0 ) {
pcQS = malloc( nCL + 1 );
if ( pcQS == NULL ) {
fprintf( stderr , "No memory <%d> \n",nCL );
exit(1);
}
fread( pcQS , 1 , nCL , stdin );
pcQS[nCL] = 0 ;
}
}
if ( pcQS == NULL ) pcQS = "" ;
Analyze command strings
The following strings is to be put from 'stdin' (standard input).
b0=1&b1=0&b2=1&b3=0
Actuator control signal informations are placed in fixed location.
Get bit informations (1 or 0) from strings
and concatenate them to be 4 bits control signal.
I have written the following source code.
int i ;
UBYTE result ;
result = 0 ;
for ( i = 0 ; i < 4 ; i++ ) {
result |= (pcQS[18-5*i] - '0') ;
if ( i < 3 ) result <<= 1 ;
}
Put control signals
Refer the following GPIO bit assignment
and put control word to fd_dr (file discriptor).
- GPIO_3 : control compressor
- GPIO_2 : control lamp
- GPIO_1 : close door
- GPIO_0 : open door
Lower 4 bits are avairable because this system has four actuators.
#define MASK0F 0x0f
void put_actuator(UBYTE x)
{
UBYTE tmp ;
tmp = x & MASK0F ;
write( fd_dr , &tmp , sizeof(UBYTE) );
}
Get sensor states
Refer the following GPIO bit assignment
and get sensor states from fd_dr (file discriptor).
- GPIO_7 : spare input
- GPIO_6 : spare input
- GPIO_5 : detect objects
- GPIO_4 : door micro switch
Upper 4 bits are avairable.
UBYTE get_sensor(void)
{
UBYTE tmp ;
read( fd_dr , &tmp , sizeof(UBYTE) );
tmp >>= 4 ;
tmp &= MASK0F ;
return tmp ;
}
Generate HTML script
Make sequence and structure to show table and Form.
- header to indicate context
- title
- make table
- make form
- post processing
Define a function to put header information and execute some sequences.
void make_html(PROP *x)
{
/* send content type */
out_header();
/* send header */
fprintf(stdout,"<html>"); crlf();
fprintf(stdout,"<title>Automatic Door</title>"); crlf();
fprintf(stdout,"<h3>"); crlf();
fprintf(stdout,"<body>"); crlf();
fprintf(stdout,"<blockquote>"); crlf();
/* update table script */
generate_table(x);
/* update form script */
generate_form(x);
/* send trailer */
fprintf(stdout,"</blockquote>"); crlf();
fprintf(stdout,"</body>"); crlf();
fprintf(stdout,"</h3>"); crlf();
fprintf(stdout,"</html>"); crlf();
/* flush buffer */
fflush(stdout);
}
After make top level control function, define some functions.
*Make a function to send 'carriage return' and 'new line'.
void crlf(void)
{
fprintf(stdout,"\r\n");
}
*Make a function to send content type.
void out_header(void)
{
fprintf( stdout , "Content-type: text/html");
crlf();
crlf();
}
Define table format to show the state of sensors and actuators.
void generate_table(PROP *x)
{
int up_index,low_index ;
/* get parameters */
up_index = x->inf ;
low_index = x->outf ;
/* send top */
fprintf(stdout,"<pre>");crlf();
fprintf(stdout,"<table border>");crlf();
fprintf(stdout,"<tr><th colspan=\"2\">INPUT</th><th colspan=\"2\">OUTPUT</th></tr>");
crlf();
fprintf(stdout,"<tr>");crlf();
/* send first row */
fprintf(stdout,"<td align=middle>detect</td><td align=middle>");
if ( up_index & 2 ) fprintf(stdout,"yes");
else fprintf(stdout,"no");
fprintf(stdout,"</td>");crlf();
fprintf(stdout,"<td align=left>open</td><td align=right>");
if ( low_index & 1 ) fprintf(stdout,"enable");
else fprintf(stdout,"disable");
fprintf(stdout,"</td></tr>");crlf();
/* send second row */
fprintf(stdout,"<td align=middle>opened</td><td align=middle>");
if ( up_index & 1 ) fprintf(stdout,"yes");
else fprintf(stdout,"no");
fprintf(stdout,"</td>");crlf();
fprintf(stdout,"<td align=left>close</td><td align=right>");
if ( low_index & 2 ) fprintf(stdout,"enable");
else fprintf(stdout,"disable");
fprintf(stdout,"</td></tr>");crlf();
/* third row */
fprintf(stdout,"<tr>");crlf();
fprintf(stdout,"<td></td><td></td>");crlf();
fprintf(stdout,"<td align=left>light</td><td align=right>");
if ( low_index & 4 ) fprintf(stdout,"enable");
else fprintf(stdout,"disable");
fprintf(stdout,"</td></tr>");crlf();
/* last row */
fprintf(stdout,"<tr>");crlf();
fprintf(stdout,"<td></td><td></td>");crlf();
fprintf(stdout,"<td align=left>pump</td><td align=right>");
if ( low_index & 8 ) fprintf(stdout,"enable");
else fprintf(stdout,"disable");
fprintf(stdout,"</td></tr>");crlf();
/* send bottom */
fprintf(stdout,"</pre>");crlf();
fprintf(stdout,"<hr>");crlf();
}
Form area indicates 'check' boxes and 'submit' buttons.
void generate_radio(int x,int y)
{
/* check range */
if ( x < 0 || 3 < x ) return ;
if ( y < 0 || 1 < y ) return ;
/* send item string */
switch ( x ) {
case 0 : fprintf(stdout,"<li>open" ) ; crlf(); break;
case 1 : fprintf(stdout,"<li>close" ); crlf(); break;
case 2 : fprintf(stdout,"<li>light" ); crlf(); break;
case 3 : fprintf(stdout,"<li>pump" ) ; crlf(); break;
}
/* first line */
fprintf(stdout,"<input type=\"radio\" name=\"b%d\" value=\"0\" ",x);
if ( y == 0 ) fprintf(stdout,"checked");
fprintf(stdout, ">OFF");crlf();
/* second line */
fprintf(stdout,"<input type=\"radio\" name=\"b%d\" value=\"1\" ",x);
if ( y == 1 ) fprintf(stdout,"checked");
fprintf(stdout,">ON");crlf();
}
main function
After define primitive functions, write control sequence in main function.
- Get strings length from 'Environment Variable'
- Get command strings from 'stdin'
- Analyze command strings
- Put control signals to actuators according to information
- Get sensor states
- Generate HTML script
- Send HTML script to network
Convert the above sequence to source code.
int main(void)
{
char *pcCL = getenv("CONTENT_LENGTH");
char *pcQS = NULL ;
int i,nCL ;
UBYTE result ;
PROP profile ;
/* set initial values */
profile.inf = 0 ;
profile.outf = 0 ;
/* show parameter strings */
if ( pcCL != NULL ) {
nCL = 0 ;
sscanf( pcCL , "%d" , &nCL );
if ( nCL > 0 ) {
pcQS = malloc( nCL + 1 );
if ( pcQS == NULL ) {
fprintf( stderr , "No memory <%d> \n",nCL );
exit(1);
}
fread( pcQS , 1 , nCL , stdin );
pcQS[nCL] = 0 ;
}
}
if ( pcQS == NULL ) pcQS = "" ;
result = 0 ;
for ( i = 0 ; i < 4 ; i++ ) {
result |= (pcQS[18-5*i] - '0') ;
if ( i < 3 ) result <<= 1 ;
}
/* check control code */
if ( check_double_booking(result) == TRUE ) {
send_err_msg("Can't set both OPEN and CLOSE !");
return -1 ;
}
/* actual perform */
profile.outf = result ;
if ( initialize() == 0 ) {
/* output information */
put_actuator(profile.outf);
/* wait */
sleep(3) ;
/* input information */
profile.inf = get_sensor();
set_close();
}
/* update html context */
make_html(&profile);
return 0;
}
Define structure
I have defined structure to manage some informations simultaneously.
typedef struct {
UBYTE inf ; /* input information */
UBYTE outf ; /* output information */
} PROP ;
Set permission of device files
You must set permmision of device files in CGI controlling.
Set permission in 'root' mode.
# chmod 666 /dev/pbddr
# chmod 666 /dev/pbdr
I could not run this system at first.
Because I didn't change permmision of device files.