Pages

Tuesday 17 February 2015

Integrating PHP with Embedded System : Chapter -8


3. With Pic 16F877A

 

PIN CONNECTION

code

/*
 * Project Name:
     httpserver_example (Ethernet Library http server demo for ENC28J60 mcu)
 * Copyright:
     (c) Mikroelektronika, 2005-2010.
 * Revision History:
     2007/12/10:
       - initial release; Author: Bruno Gavand.
     2010/12/20:
       - modified for PRO compilers (FJ);
     2012/10/19:
     Modifier pour usage personnel

* description  :
 *      this code shows how to use the Spi_Ethernet mini library :
 *              the board will reply to ARP & ICMP echo requests
 *              the board will reply to HTTP requests on port 80, GET method with pathnames :
 *                      /               will return the HTML main page
 *                      /s              will return board status as text string
 *                      /t0 ... /t7     will toggle PD0 to PD7 bit and return HTML main page
 *                      all other requests return also HTML main page
 * Test configuration:
     MCU:                 PIC16F877A
                          http://ww1.microchip.com/downloads/en/DeviceDoc/41291D.pdf

     Dev.Board:           PIC-Ready1
                          http://www.mikroe.com/products/view/177/pic-ready-prototype-board/
                          http://www.mikroe.com/products/view/305/pic-ready1-board/

     Oscillator:          External Clock 8.0000 MHz
     Ext. Modules:        ac:Serial_Ethernet_board
                          http://www.mikroe.com/eng/products/view/14/serial-ethernet-board/

     SW:                  mikroC PRO for PIC

                          http://www.mikroe.com/en/compilers/mikroc/pro/pic/
 * NOTES:
     - Connect Serial Ethernet Board on PortC (Board and MCU Specific)
     - Since the ENC28J60 doesn't support auto-negotiation, full-duplex mode is
       not compatible with most switches/routers.  If a dedicated network is used
       where the duplex of the remote node can be manually configured, you may
       change this configuration.  Otherwise, half duplex should always be used.
     - External power supply should be used due to Serial Ethernet Board power consumption.
 */
/*
Pour voir l'états des variables tapper : 192.168.0.170/s

Pour faire une commande d'interrupteur faire :
192.168.0.170/dXo ouvre(OFF)
192.168.0.170/dXf ferme(ON)

avec X pour valeur : 0 a 7
*/
// duplex config flags
#define Spi_Ethernet_HALFDUPLEX     0x00  // half duplex
#define Spi_Ethernet_FULLDUPLEX     0x01  // full duplex

// mE ehternet NIC pinout
sfr sbit SPI_Ethernet_Rst at RC0_bit;
sfr sbit SPI_Ethernet_CS  at RC1_bit;
sfr sbit SPI_Ethernet_Rst_Direction at TRISC0_bit;
sfr sbit SPI_Ethernet_CS_Direction  at TRISC1_bit;
// end ethernet NIC definitions

typedef struct
{
  unsigned canCloseTCP: 1;  // flag which closes TCP socket (not relevant to UDP)
  unsigned isBroadcast: 1;  // flag which denotes that the IP package has been received via subnet broadcast address (not used for PIC16 family)
} TEthPktFlags;

/************************************************************
 * ROM constant strings
 */
const unsigned char httpHeader[] = "HTTP/1.1 200 OK\nContent-type: " ;  // HTTP header
const unsigned char httpMimeTypeHTML[] = "text/html\n\n" ;              // HTML MIME type
const unsigned char httpMimeTypeScript[] = "text/plain\n\n" ;           // TEXT MIME type
unsigned char httpMethod[] = "GET /";
/*
 * web page, splited into 2 parts :
 * when coming short of ROM, fragmented data is handled more efficiently by linker
 *
 * this HTML page calls the boards to get its status, and builds itself with javascript
 */
 //*************************************************************************
 // Change the IP address of the page to be refreshed

const char *indexPageHEAD = "<meta http-equiv='refresh' content='10;url=http://192.168.1.15/'>\
<HTML><HEAD></HEAD><BODY>\
<h1>RESEARCH DESIGN LAB,<p></h1>\
<p><a href=\"http://olivier.fournet.free.fr/e.html\">NOTICE</a><p>\
<p><a href=/>Reload</a><p>\
<script src=/s></script>";

const char *indexPageBODY =  "<table><tr><td valign=top><table border=1 style='font-size:20px; font-family: terminal;'>\
<tr><th colspan=2>ADC</th></tr>\
<tr><td>AN2</td><td><script>document.write(AN2);</script></td></tr>\

<tr><td>AN3</td><td><script>document.write(AN3);</script></td></tr>\
</table></td><td><table border=1 style='font-size:20px; font-family: terminal;'>\
<tr><th colspan=2>PORTB (IN) : <script>document.write(PORTB);</script></th></tr>\
<script>\
var str,i;\
str='';\
for(i=0;i<8;i++)\
{\
str+='<tr><td bgcolor=#cccccc>BUTTON #'+i+'</td>';\
if(PORTB&(1<<i))\
{str+='<td bgcolor=green>ON';}\
else\
{str+='<td bgcolor=red>OFF';}\
str+='</td></tr>';}\
document.write(str);\
</script>";

const char *indexPageBODY2 =  "</table></td><td>\
<table border=1 style='font-size:20px; font-family: terminal;'>\
<tr><th colspan=3>PORTD (OUT) : <script>document.write(PORTD);</script></th></tr>\
<script>\
var str,i;\
str='';\
for(i=0;i<8;i++)\
{\
str+='<tr><td bgcolor=#cccccc>LED #'+i+'</td>';\
if(PORTD&(1<<i))\
{\
str+='<td bgcolor=yellow>ON';\
}\
else\
{\
str+='<td bgcolor=#999999>OFF';\
}\
str+='</td></tr>';}\
document.write(str);\
</script>\
</table></td></tr></table>\
<p>This is HTTP request #<script>document.write(REQ)</script><p>\
</BODY></HTML>";

//*************************************************************************


/***********************************
 * RAM variables
 */
unsigned char   myMacAddr[6] = {0x54, 0x55, 0x58, 0x10, 0x00, 0x24};   // my MAC address
unsigned char   myIpAddr[4]  = {192, 168, 1, 15};                     // my IP address
unsigned char   getRequest[15];                                        // HTTP request buffer
unsigned char   get_Request, digit_getRequest, etat_interrupteur;
unsigned char   dyna[30];                                              // buffer for dynamic response
unsigned long   httpCounter = 0;                                       // counter of HTTP requests

/*******************************************
 * functions
 */

/*
 * put the constant string pointed to by s to the ENC transmit buffer.
 */
/*unsigned int    putConstString(const char *s)
        {
        unsigned int ctr = 0 ;

        while(*s)
                {
                Spi_Ethernet_putByte(*s++) ;
                ctr++ ;
                }
        return(ctr) ;
        }*/
/*
 * it will be much faster to use library Spi_Ethernet_putConstString routine
 * instead of putConstString routine above. However, the code will be a little
 * bit bigger. User should choose between size and speed and pick the implementation that
 * suites him best. If you choose to go with the putConstString definition above
 * the #define line below should be commented out.
 *
 */
#define putConstString  SPI_Ethernet_putConstString

/*
 * put the string pointed to by s to the ENC transmit buffer
 */
/*unsigned int    putString(char *s)
        {
        unsigned int ctr = 0 ;

        while(*s)
                {
                Spi_Ethernet_putByte(*s++) ;

                ctr++ ;
                }
        return(ctr) ;
        }*/
/*
 * it will be much faster to use library Spi_Ethernet_putString routine
 * instead of putString routine above. However, the code will be a little
 * bit bigger. User should choose between size and speed and pick the implementation that
 * suites him best. If you choose to go with the putString definition above
 * the #define line below should be commented out.
 *
 */
#define putString  SPI_Ethernet_putString

/*
 * this function is called by the library
 * the user accesses to the HTTP request by successive calls to Spi_Ethernet_getByte()
 * the user puts data in the transmit buffer by successive calls to Spi_Ethernet_putByte()
 * the function must return the length in bytes of the HTTP reply, or 0 if nothing to transmit
 *
 * if you don't need to reply to HTTP requests,
 * just define this function with a return(0) as single statement
 *
 */
unsigned int  SPI_Ethernet_UserTCP(unsigned char *remoteHost, unsigned int remotePort,
                               unsigned int localPort, unsigned int reqLength, TEthPktFlags *flags)
{
  unsigned int    len = 0 ;                   // my reply length
  unsigned int    i ;                         // general purpose integer

  // should we close tcp socket after response is sent?
  // library closes tcp socket by default if canClose flag is not reset here
  // flags->canClose = 0; // 0 - do not close socket
                          // otherwise - close socket

  if(localPort != 80)
  {                        // I listen only to web request on port 80
    return(0) ;
  }

  // get 10 first bytes only of the request, the rest does not matter here
  for(i = 0 ; i < 10 ; i++)
  {
    getRequest[i] = SPI_Ethernet_getByte() ;
  }

  getRequest[i] = 0 ;

  if(memcmp(getRequest, httpMethod, 5))
  {      // only GET method is supported here
    return(0) ;
  }

  httpCounter++ ;   // one more request done

  get_Request = getRequest[5];  // s , d

  if(get_Request == 's')  // utiliser pour <script src=/s></script>
  {
    // if request path name starts with s, store dynamic data in transmit buffer
    // the text string replied by this request can be interpreted as javascript statements
    // by browsers
    len = putConstString(httpHeader);     // HTTP header
    len += putConstString(httpMimeTypeScript); // with text MIME type

    // add AN2 value to reply
    IntToStr(ADC_Read(2), dyna);
    len += putConstString("var AN2=");
    len += putString(dyna);
    len += putConstString(";");

    // add AN3 value to reply
    IntToStr(ADC_Read(3), dyna);
    len += putConstString("var AN3=");
    len += putString(dyna);
    len += putConstString(";");

    // add PORTB value (buttons) to reply
    len += putConstString("var PORTB=");
    IntToStr(PORTB, dyna);
    len += putString(dyna);
    len += putConstString(";");

    // add PORTD value (LEDs) to reply
    len += putConstString("var PORTD=");
    IntToStr(PORTD, dyna);
    len += putString(dyna);
    len += putConstString(";");

    // add HTTP requests counter to reply
    IntToStr(httpCounter, dyna);
    len += putConstString("var REQ=");
    len += putString(dyna);
    len += putConstString(";");
  }
  else
  {
   //
   if(get_Request == 'd') // Commande PORTD
   {
    if( isdigit(getRequest[6]) )
    {
     digit_getRequest  = getRequest[6] - '0'; // numéro de port 0 à 7

     if( getRequest[7] == 'o' )  // Contact Ouvert (OFF)
      etat_interrupteur = 0;

     if( getRequest[7] == 'f' )  // Contact Fermer (ON)
      etat_interrupteur = 1;

     switch(digit_getRequest)
     {
       case 0: PORTD.B0 = etat_interrupteur; break;
       case 1: PORTD.B1 = etat_interrupteur; break;
       case 2: PORTD.B2 = etat_interrupteur; break;
       case 3: PORTD.B3 = etat_interrupteur; break;
       case 4: PORTD.B4 = etat_interrupteur; break;
       case 5: PORTD.B5 = etat_interrupteur; break;
       case 6: PORTD.B6 = etat_interrupteur; break;
       case 7: PORTD.B7 = etat_interrupteur; break;
     }
    }
   }
   //
  }

  if(len == 0)
  {           // what do to by default
    len =  putConstString(httpHeader);       // HTTP header
    len += putConstString(httpMimeTypeHTML); // with HTML MIME type
    len += putConstString(indexPageHEAD);    // HTML page first part
    len += putConstString(indexPageBODY);    // HTML page second part
    len += putConstString(indexPageBODY2);   // HTML page second part
  }

  return(len) ;                               // return to the library with the number of bytes to transmit
}

/*
 * this function is called by the library
 * the user accesses to the UDP request by successive calls to Spi_Ethernet_getByte()
 * the user puts data in the transmit buffer by successive calls to Spi_Ethernet_putByte()
 * the function must return the length in bytes of the UDP reply, or 0 if nothing to transmit
 *
 * if you don't need to reply to UDP requests,
 * just define this function with a return(0) as single statement
 *
 */
unsigned int  SPI_Ethernet_UserUDP(unsigned char *remoteHost, unsigned int remotePort,
                                   unsigned int destPort, unsigned int reqLength, TEthPktFlags *flags)
{
   return 0;              // back to the library with the length of the UDP reply
}

/*
 * main entry
 */
void main()
{
  //ANSEL = 0x0C ;          // AN2 and AN3 convertors will be used
  //C1ON_bit = 0;           // Disable comparators
  //C2ON_bit = 0;
  PORTA = 0 ;
  TRISA = 0xff ;          // set PORTA as input for ADC

  //ANSELH = 0;             // Configure other AN pins as digital I/O
  PORTB = 0 ;
  TRISB = 0xff ;          // set PORTB as input for buttons

  PORTD = 0 ;
  TRISD = 0 ;             // set PORTD as output

  /*
   * starts ENC28J60 with :
   * reset bit on RC0
   * CS bit on RC1
   * my MAC & IP address
   * full duplex
   */
  SPI1_Init();
  SPI_Ethernet_Init(myMacAddr, myIpAddr, Spi_Ethernet_FULLDUPLEX) ;

  while(1)
  {                            // do forever
    /*
     * if necessary, test the return value to get error code
     */
    SPI_Ethernet_doPacket() ;   // process incoming Ethernet packets

    /*
     * add your stuff here if needed
     * Spi_Ethernet_doPacket() must be called as often as possible
     * otherwise packets could be lost
     */
  }
}