SHARE
TWEET

Arduino: HTML to LCD v1.1

ejrob May 19th, 2011 6,653 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /* ***********************************************************************************************
  2.  * HTML to LCD Server v1.1
  3.  * Everett Robinson
  4.  *
  5.  * This project uses the Arduino ethernet shield and a sparkfun 16x2 character LCD to produce a
  6.  * webpage which shows what the LCD is currently displaying, and where a user can change what's
  7.  * displayed by entering something into a couple text fields (one for each row of the lcd). The Arduino
  8.  * then parses the Html Header using some code adapted from Kevin Haw's RoboSapien Server project:
  9.  * (http://www.arduino.cc/playground/Main/RoboSapienServer).
  10.  * The result of this parsing is the extraction and updating of the LCD with the strings the user
  11.  * entered, which are also converted back to something readable at the same time.
  12.  *
  13.  * Bug fixes:
  14.  * A problem in which any zero's were removed from the input has been fixed
  15.  *
  16.  * Remaining Bugs:
  17.  * - Some minor memory leaks may still remain, since strings are nasty like that
  18.  *
  19.  *************************************************************************************************
  20.  * LCD pin to Arduino Digital pin Connection Map (for Sparkfun 16x2 LCD)
  21.  *
  22.  *  // LCD pin 1  to GND
  23.  *  // LCD pin 2  to +5V
  24.  *  // LCD pin 3  to Resistor(2.2K) to GND
  25.  *  // LCD pin 4  (RS) to Arduino pin 2
  26.  *  // LCD pin 5  (RW) to Arduino pin 3
  27.  *  // LCD pin 6  (enable) to Arduino pin 5
  28.  *  // LCD pin 7
  29.  *  // LCD pin 8
  30.  *  // LCD pin 9
  31.  *  // LCD pin 10
  32.  *  // LCD pin 11 (Data 4) to Arduino pin 6
  33.  *  // LCD pin 12 (Data 5) to Arduino pin 7
  34.  *  // LCD pin 13 (Data 6) to Arduino pin 8
  35.  *  // LCD pin 14 (Data 7) to Arduino pin 9
  36.  *  // LCD pin 15 to +5V
  37.  *  // LCD pin 16 to GND
  38.  ************************************************************************************************/
  39.  
  40. //////////////////////////////////////////////////////////////////
  41. //Include all necessary libraries
  42. //////////////////////////////////////////////////////////////////
  43. #include <SPI.h>
  44. #include <Ethernet.h>
  45. #include <string.h>
  46. #include <LiquidCrystal.h>
  47. #include <avr/pgmspace.h>
  48. //#include <MemoryFree.h>  // Used to try and track down mem leaks, requires http://www.arduino.cc/playground/Code/AvailableMemory
  49.                            // Use the code from the forums half way down the page
  50.  
  51.  
  52. //////////////////////////////////////////////////////////////////
  53. //Start initializing webserver, lcd and other miscellaneous stuff
  54. //////////////////////////////////////////////////////////////////
  55.  
  56. byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x4C, 0x64 };
  57. byte ip[] = { 192,168,1, 99 };
  58. byte gateway[] = { 192,168,1, 1 };
  59. byte subnet[] = { 255, 255, 0, 0 };
  60.  
  61. // Server for web requests
  62. Server server(80);
  63.  
  64. // Initialize lcd pins according to previous mapping
  65. LiquidCrystal lcd(2, 3, 5, 6, 7, 8, 9);
  66.  
  67. // String variables fo each line on the LCD declared globally because I'm lazy, but also
  68. // because it needs to survive loop(), without being cleared from the stack (also to hell with good practice)
  69. String line1 = "                ";
  70. String line2 = "                ";
  71.  
  72. /////////////////////////////////////////////////////////////////////////
  73. // Constant strings for rendering the Webpage are stored in flash
  74. // memory to ration it for other non constant variables
  75. /////////////////////////////////////////////////////////////////////////
  76.  
  77. // Strings stored in flash mem for the Html Header
  78. prog_char Header_0[] PROGMEM = "HTTP/1.1 200 OK";            //
  79. prog_char Header_1[] PROGMEM = "Content-Type: text/html";    //
  80. prog_char Header_2[] PROGMEM = "";                           //
  81. prog_char Header_3[] PROGMEM = "<HTML>\n<HEAD>";             // The header lines
  82. prog_char Header_4[] PROGMEM = "<TITLE>HTML to LCD</TITLE>"; //
  83. prog_char Header_5[] PROGMEM = "</HEAD><BODY>";              //
  84.  
  85. // A table of pointers to the flash memory strings for the header
  86. PROGMEM const char *Header_table[] =
  87. {  
  88.   Header_0,
  89.   Header_1,
  90.   Header_2,
  91.   Header_3,
  92.   Header_4,
  93.   Header_5};
  94.  
  95. // Strings stored in flash mem for the body of the webpage, including the input forms
  96. // Only the longer lines, not involving variables are stored here
  97. prog_char Body_0[] PROGMEM = "<H2>Currently Displayed:</H2>";            
  98. prog_char Body_1[] PROGMEM = "<H2>Change it to something else!</H2>";    
  99. prog_char Body_2[] PROGMEM = "<form action=\"/?\" method=get>";                          
  100. prog_char Body_3[] PROGMEM = "<b>Line 1: </b><input type=\"text\" name=\"L1\" maxlength=\"16\" size=\"16\" /><br />";            
  101. prog_char Body_4[] PROGMEM = "<b>Line 2: </b><input type=\"text\" name=\"L2\" maxlength=\"16\" size=\"16\" /><br />";
  102. prog_char Body_5[] PROGMEM = "<input type=\"submit\" value=\"Submit\" /></form>";              
  103.  
  104. // A table of pointers to the flash memory strings for the body
  105. PROGMEM const char *Body_table[] =
  106. {  
  107.   Body_0,
  108.   Body_1,
  109.   Body_2,
  110.   Body_3,
  111.   Body_4,
  112.   Body_5};
  113.  
  114.  
  115.  
  116. //////////////////////////////////////////////////////////////////
  117. // Begin Webserver Specific Code
  118. //////////////////////////////////////////////////////////////////
  119.  
  120. // Print out MIME and HTML header at top of webpage using the
  121. // strings previously stored in flash memory
  122. void HtmlHeader(Client client) {
  123.  
  124.     char buffer[30]; //A character array to hold the strings from the flash mem
  125.    
  126.     for (int i = 0; i < 6; i++) {
  127.       strcpy_P(buffer, (char*)pgm_read_word(&(Header_table[i]))); // Necessary casts and dereferencing, just copy.
  128.       client.println( buffer );
  129.     }
  130. }
  131.  
  132. // Print the footer at the bottom of the webpage
  133. void HtmlFooter(Client client) {
  134.     client.println("</BODY></HTML>");
  135. }
  136.  
  137.  
  138. // Parse an HTTP request header one character at a time, seeking string variables (modified from Kevin Haw's code)
  139. void ParseHttpHeader(Client &client) {
  140.     char c;
  141.     int i = 0;    //An integer use to limit the size of rawUrlText (prevents crashing due to running out of memory)
  142.     String rawUrlText = "";
  143.  
  144.     // Skip through until we hit a question mark (first one)
  145.     while((c = client.read()) != '?' && client.available()) {
  146.       // Debug - print data
  147.       Serial.print(c);
  148.     }
  149.    
  150.     // Are we here for a question mark or did we run out of data?
  151.     if(client.available() > 2) {
  152.  
  153.       // Read the data and add it to our unmodified string rawURLText!
  154.       // the incrementer limits the input to about 1 line of plain text and 1/2 line of symbols, more causes line2 to truncate
  155.       while((c = client.read()) != ' ' && client.available() && i < 55) {
  156.           rawUrlText = rawUrlText + c;
  157.           Serial.print(c);
  158.           i++;
  159.       }
  160.      
  161.       htmlToHuman(rawUrlText);            // Make it readable
  162.       line1.setCharAt(line1.lastIndexOf('0'), ' '); // the lcd prints the 0's in the null terminator, so we remove them
  163.       line2.setCharAt(line2.lastIndexOf('0'), ' '); //This has been revised to prevent remove of legit 0's
  164.       lcd.clear();
  165.       lcd.setCursor(0,0);                 // set cursor to column 0, row 0 (the first row), and print
  166.       lcd.print(line1);
  167.       lcd.setCursor(0,1);                 // set cursor to column 0, row 1 (the second row), and print
  168.       lcd.print(line2);
  169.     }  
  170.   return;
  171. }
  172.  
  173. // A function that takes the html formatted string and makes it readable again
  174. void htmlToHuman(String URLstring) {
  175.  
  176.     int indexOfDelim = 0;  //This variable stores the location of our delimiter so we can find where line1 ends and line2 begins
  177.    
  178.     // The following array stores a list of ugly html codes, and the special charaters they represent (for changing them back)
  179.     const String CHAR_CONVERSIONS[29][2] = {{"+"," "},{"%40","@"},{"%23","#"},{"%24","$"},{"%2B","+"},{"%21","!"},{"%7E","~"},
  180.                                             {"%3A",":"},{"%3B",";"},{"%2C",","},{"%3F","?"},{"%2F","/"},{"%7C","|"},{"%5E","^"},
  181.                                             {"%5C","\\"},{"%7B","{"},{"%7D","}"},{"%5B","["},{"%5D","]"},{"%3C","<"},{"%3E",">"},
  182.                                             {"%28","("},{"%29",")"},{"%27","'"},{"%22","\""},{"%3F","?"},{"%26","&"},{"%3D","="},
  183.                                             {"%25","%"}};
  184.    
  185.     URLstring = URLstring.replace("L1=","");     // remove the unecessary field variable names
  186.     URLstring = URLstring.replace("&L2=","`");   // and turn this one into our delimiter character ` (The one on the ~ key)
  187.    
  188.     //A for loop that replaces all the html codes with the right symbols
  189.     for (int i=0 ; i < 29; i++) {
  190.       URLstring = URLstring.replace(CHAR_CONVERSIONS[i][0],CHAR_CONVERSIONS[i][1]);
  191.     }
  192.    
  193.     indexOfDelim = URLstring.indexOf("`");       // find the index of that delimiter
  194.    
  195.     line1 = URLstring.substring(0,indexOfDelim); // set line1 and line 2 using that knowlege
  196.     line1 += NULL;                               // but add a null terminator to each to avoid some odd bugs
  197.     line2 = URLstring.substring(indexOfDelim+1,URLstring.length());
  198.     line2 += NULL;
  199.    
  200.     return;
  201. }
  202.  
  203. // Set up webserver functionality (from Kevin Haw)
  204. void WebServerSetup() {
  205.   Ethernet.begin(mac, ip);
  206.   server.begin();
  207. }
  208.  
  209. // Web server loop (modified from Kevin Haw's code)
  210. void WebServerLoop() {  
  211.   Client client = server.available();
  212.   boolean bPendingHttpResponse = false; // True when we've received a whole HTTP request and need to output the webpage
  213.   boolean bPreventSecondParse = false;  //Stops a second successive run of parseHttpHeader(), this prevents some nasty bugs.
  214.   char c;  // For reading in HTTP request one character at a time
  215.  
  216.   if (client) {
  217.     // Loop as long as there's a connection
  218.     while (client.connected()) {
  219.       // Do we have pending data (an HTTP request) and is this the first parse?    
  220.       if (client.available() && !bPreventSecondParse) {
  221.  
  222.         // Indicate we need to respond to the HTTP request as soon as we're done processing it
  223.         bPendingHttpResponse = true;
  224.         bPreventSecondParse = true;
  225.        
  226.         ParseHttpHeader(client);  
  227.       }
  228.       else {
  229.         // There's no data waiting to be read in on the client socket.  Do we have a pending HTTP request?
  230.         if(bPendingHttpResponse) {
  231.           // Yes, we have a pending request.  Clear the flag and then send the webpage to the client
  232.           bPendingHttpResponse = false;
  233.           bPreventSecondParse = false;
  234.  
  235.           // send a standard http response header and HTML header
  236.           HtmlHeader(client);
  237.  
  238.           // The following code Sends the relevant Html to the connected connected client to render the web page
  239.           /* For readability, the Html sent to the client is as follows (the second and third lines are not stored in flash memory)
  240.            *"<H2>Currently Displayed:</H2>"
  241.            *"<b>Line 1:</b> " + line1 + "<br />"        
  242.            *"<b>Line 2:</b> " + line2 + "<br /><br />"
  243.            *"<H2>Change it to something else!</H2>"
  244.            *"<form action=\"/?\" method=get>"
  245.            *"<b>Line 1: </b><input type=\"text\" name=\"L1\" maxlength=\"16\" size=\"16\" /><br />"
  246.            *"<b>Line 2: </b><input type=\"text\" name=\"L2\" maxlength=\"16\" size=\"16\" /><br />"
  247.            *"<input type=\"submit\" value=\"Submit\" /></form>"
  248.            */
  249.            
  250.           char buffer[90]; //A character array to hold the strings from the flash mem
  251.          
  252.           strcpy_P(buffer, (char*)pgm_read_word(&(Body_table[0])));        // gets and prints the first line
  253.           client.println( buffer );
  254.           client.println("<b>Line 1:</b> " + line1 + "<br />");            // manually print the lines involving variables
  255.           client.println("<b>Line 2:</b> " + line2 + "<br /><br />");
  256.           for(int i = 1; i < 6; i++) {                                     // Use a for loop to print the remaining lines
  257.             strcpy_P(buffer, (char*)pgm_read_word(&(Body_table[i])));
  258.             client.println( buffer );
  259.           }
  260.          
  261.           // send HTML footer
  262.           HtmlFooter(client);
  263.  
  264.           // give the web browser time to receive the data
  265.           delay(1);
  266.           client.stop();
  267.         }
  268.       }
  269.     }  // End while(connected)
  270.   }
  271. }
  272.  
  273.  
  274. void setup(){
  275.   // open the serial port at 9600 bps:
  276.   Serial.begin(9600);
  277.   lcd.begin(16,2);                    // columns, rows.  use 16,2 for a 16x2 LCD, etc.
  278.   lcd.clear();                        // start with a blank screen
  279.   WebServerSetup();
  280. }
  281.  
  282.  
  283. void loop(){
  284.   WebServerLoop();
  285. }
RAW Paste Data
Top