Pages: [1]   Go Down
Author Topic: Trying to make SD.h to render an HTML5 file  (Read 890 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have been working on a project where I am getting a set of readings and dumping them into a csv file.I was thinking of adding an export to HTML option so that the user can can quick visual idea on what is going on while the device is deployed,in addition providing expandability in the future using XBEE or any type of Ethernet.

The first problem is that SD.open (file.extention, FILE_WRITE) does not support 4 letter extentions.So creating an .html file is not possible.I had to overcome this by using .HTM and hoping the browser would be smart enough to render it.

In order to give you an idea of how the page is supposed to be rendered this is the HTML code:

Code:
<!DOCTYPE html>
<html>
<head>
<title>Quantitative Metal Detector Data Visualisation</title>
<style type="text/css">
table { margin-left: auto; margin-right: auto;text-align: center; }
svg { display: block;margin-right:auto;margin-left:auto;margin-top:10px;margin-bottom:10px; }
body { background-color:#EEEEEE;}

</style>
</head>
<body>
<h1 align="center">Metal Detector Data</h1>
<table border="2" width="1000">
  <tr>
    <th>Measurement</th>
    <th>Coil 1</th>
    <th>Coil 2</th>
    <th>Coil 3</th>
    <th>Coil 4</th>
    <th>Coil 5</th>
    <th>Coil 6</th>
    <th>Coil 7</th>
    <th>Coil 8</th>
  </tr>
  <tr>
    <td>1</td>
    <td>100</td>
    <td>200</td>
    <td>100</td>
    <td>200</td>
    <td>100</td>
    <td>200</td>
    <td>100</td>
    <td>200</td>
  </tr>
</table>

<table border="1" width="100">
  <tr>
  <td><svg width="990" height="60"   xmlns="http://www.w3.org/2000/svg" version="1.1">
    <defs>
    <line id="line1" x1="0"  y2="50" y1="0" x2="0" />
    <line id="line2" x1="0"  y2="30" y1="0" x2="0"/>
    <line id="line3" x1="0"  y2="20" y1="0" x2="0"/>
    <line id="line4" x1="0"  y2="50" y1="0" x2="0"/>
    <line id="line5" x1="0"  y2="10" y1="0" x2="0"/>
    <line id="line6" x1="0"  y2="40" y1="0" x2="0"/>  
    <line id="line7" x1="0"  y2="40" y1="0" x2="0"/>
    <line id="line8" x1="0"  y2="50" y1="0" x2="0"/>
  </defs>

  <use xlink:href="#line1" x="260" y="00" stroke="black" stroke-width="2" stroke-dasharray="6 6"/>
  <use xlink:href="#line2" x="360" y="00" stroke="black" stroke-width="2" stroke-dasharray="6 6"/>
  <use xlink:href="#line3" x="460" y="00" stroke="black" stroke-width="2" stroke-dasharray="6 6"/>
  <use xlink:href="#line4" x="560" y="00" stroke="black" stroke-width="2" stroke-dasharray="6 6"/>
  <use xlink:href="#line5" x="660" y="00" stroke="black" stroke-width="2" stroke-dasharray="6 6"/>
  <use xlink:href="#line6" x="760" y="00" stroke="black" stroke-width="2" stroke-dasharray="6 6"/>
  <use xlink:href="#line7" x="860" y="00" stroke="black" stroke-width="2" stroke-dasharray="6 6"/>
  <use xlink:href="#line8" x="960" y="00" stroke="black" stroke-width="2" stroke-dasharray="6 6"/>

   
<polygon points="260,60 260,50
360,30 460,20 560,50 660,10 760,40 860,40
960,50 960,60"
          style="stroke:#660000; fill:#cc3333; stroke-width: 1;"/></td>


</svg></td>
  <tr>
</table>

 
</body>
</HTML>


Using notepad++ and replacing " with \" tabs with \t and newlines with \n I came up across this code on arduino based on the SD ReadWrite example I created this draft sketch:

Code:
/*
  SD card read/write
 
 This example shows how to read and write data to and from an SD card file
 The circuit:
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4
 
 created   Nov 2010
 by David A. Mellis
 updated 2 Dec 2010
 by Tom Igoe
 
 This example code is in the public domain.
 
 */
 
#include <SD.h>

File myFile;
int cx = 300;
int lineReadings[8];
int lineNo = 1;
int xcoord = 260;

void getReadings(){
  for (int i=0;i<8;i++)
  {
    lineReadings[i] = random(0,10);
  }
}

void printReadings()
{
  for (int i=0;i<8;i++)
  {
    Serial.print("Reading : \t");
    Serial.print(i+1);
    Serial.print(" = ");
    Serial.print(lineReadings[i]);
    Serial.println("");
  }
}
void setup()
{
  getReadings();
 
  Serial.begin(9600);
 
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
  // Note that even if it's not used as the CS pin, the hardware SS pin
  // (10 on most Arduino boards, 53 on the Mega) must be left as an output
  // or the SD library functions will not work.
   pinMode(10, OUTPUT);
   Serial.println("Initializing SD card...");
}

void loop()
{
  Serial.println("Begin");
 
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
  }
  else{
  Serial.println("initialization done.");
    renderHtml(); 
  }
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
    //Cannot open 4 characters extention name so html is replaced by htm
  printReadings();
  Serial.print("END");
  while(1);
  // nothing happens after setup
}

void renderHtml(){
  myFile = SD.open("data.htm", FILE_WRITE);
 
  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("Writing to test.txt...");
   
   
    //Begin with HTML file header
    myFile.println("<!DOCTYPE html>\n<html>\n<head>\n<title>Quantitative Metal Detector Data Visualisation</title>\n");

    //We cannot afford external CSS so we add them in the head section of the HTML and close the head
    myFile.println("<style type=\"text/css\">\ntable { margin-left:auto; margin-right:auto;text-align:center; }\nsvg { display:block;margin-right:auto;margin-left:auto;margin-top:10px;margin-bottom:10px; }\nbody {background-color:#EEEEEE;}\n</style>\n</head>\n");
   
    //Start printing the body and header
    myFile.println("<body><h1 align=\"center\">Metal Detector Data</h1>");   
   
    //Create the Name Part of the Data Table
    myFile.print("<table border=\"2\" width=\"1000\">\n\t<tr>\n\t\t<th>Measurement</th>\n\t\t<th>Coil 1</th>\n\t\t<th>Coil 2</th>\n\t\t<th>Coil 3</th>\n\t\t<th>Coil 4</th>");
    myFile.print("\n\t\t<th>Coil 5</th>\n\t\t<th>Coil 6</th>\n\t\t<th>Coil 7</th>\n\t\t<th>Coil 8</th>\n\t</tr>\n");
   
    //Create the Data part of the Table
   
    myFile.print("\t<tr>\n\t\t<td>");
    myFile.print(lineNo);//Print the Line Number
    myFile.print("</td>\n");
   
    //Go through each of the readings   
    for(int i =0;i<8;i++){
      myFile.print("\t\t<td>");
      myFile.print(lineReadings[i]);//Dump the readings into the HTML table
      myFile.print("</td>\n");   
    }
   
    //Close the table   
    myFile.println("\t</tr>\n</table>\n");
   
    //Start Printing the SVG part of the file
    /*
    //Create the container table
    myFile.println("<table border=\"1\" width=\"100\">\n\t<tr>");
   
    //Create the svg header
    myFile.println("<td><svg width=\"990\" height=\"60\"   xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n\t<defs>");
   
    //Damp readings into the line euations
    for(int i =0;i<8;i++){
      myFile.print("<line id=\"line");
      myFile.print(i); //required to name lines differently
      myFile.print("\" x1=\"0\"  y2=\"");
      myFile.print(lineReadings[i]); //Data input line
      myFile.print("\" y1=\"0\" x2=\"0\" />\n"); 
    }
    //Close the definitions part of the svg
    myFile.println("\t</defs>");
    //dotPrint();
    /*
    //Make the lines Dotted and place them in X coordinates
   

   
    for(int i =0;i<8;i++){
      myFile.print("<use xlink:href=\"#line");
      myFile.print(i);//syncronize with the line name afrom above
      myFile.print("\" x=\"");
      myFile.print(xcoord); //add the current point coordinate
      myFile.print("\" y=\"00\" stroke=\"black\" stroke-width=\"2\" stroke-dasharray=\"6 6\"/>\n");
      xcoord = xcoord + 100;
      delayMicroseconds(100);
    }
    /*
    xcoord = 260; //Reset xcoord for next loop
    */
    //close the table and SVG
    myFile.println("</svg></td>\n\t<tr>\n</table>");
   
    //Close the html File
    myFile.println("</body>\n</html>");

// close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
}

The main problem occurs after the line     //Start Printing the SVG
if the the code get un-commented.Even though if tested separately all the code functions create a working file i have to comment out part of it in order for the arduino not to get into bootloop crashing on the line
Serial.println("Initializing SD card...");

I do suspect it is a memory issue even though the Binary sketch size: 15316 bytes (of a 30720 byte maximum) seems to be ok.I also tried closing and opening the file halfway to clear the buffer but with no luck..

The board is a Duemilanove with 328P chip
Any help is greatly appreciated.

« Last Edit: April 05, 2012, 06:16:36 pm by minos197 » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 551
Posts: 46215
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I was thinking of adding an export to HTML option so that the user can can quick visual idea on what is going on while the device is deployed,in addition providing expandability in the future using XBEE or any type of Ethernet.
Why would you need to save the htm(l) file? Just create the data on the fly, when requested.

Quote
I do suspect it is a memory issue even though the Binary sketch size: 15316 bytes (of a 30720 byte maximum) seems to be ok.
There are 3 kinds of memory. Knowing how much Flash you are using tells you nothing about the (very large) amount of SRAM you are using. All those strings take up SRAM, and the SD library itself needs over 1/4 of your SRAM. You are almost certainly running out.

Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
<!DOCTYPE html>
<html>
<head>
<title>Quantitative Metal Detector Data Visualisation</title>
...
</table>
</body>
</HTML>

Your HTML alone was 2451 bytes. You have 2048 bytes of SRAM.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for your replies.Do you know if there is any any workaround around it?

Logically the file open is loading the whole file onto SRAM so even if I close it and re-open to add things to it,i will fully load onto the ram.In addition I have not done it before but i think SRAM expansion chips also require the SPI  pins so using it along with the SD card is non feasible.Maybe i could try doing it with PROGMEM command.

Since I am parsing the file line by line ,is there any way to dump or inject data onto the file without fully opening it?Something similar to the unix/linux >>dumpfile operation?

Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Don't mind my previous reply I managed to solve it using PROGMEM to push the long strings onto the Flash memory.I am posting the modified code(modifications made according to arduino.cc reference guide) in case anyone else faces similar issue.It is draft and dirty but works.

Code:
/*
  SD card read/write
 
 This example shows how to read and write data to and from an SD card file
 The circuit:
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4
 
 created   Nov 2010
 by David A. Mellis
 updated 2 Dec 2010
 by Tom Igoe
 
 This example code is in the public domain.
 
 */
 
#include <SD.h>
#include <avr/pgmspace.h>
prog_char string_0[] PROGMEM = "<!DOCTYPE html>\n<html>\n<head>\n<title>Quantitative Metal Detector Data Visualisation</title>\n";
prog_char string_1[] PROGMEM = "<style type=\"text/css\">\ntable { margin-left:auto; margin-right:auto;text-align:center; }\nsvg { display:block;margin-right:auto;margin-left:auto;margin-top:10px;margin-bottom:10px; }\nbody {background-color:#EEEEEE;}\n</style>\n</head>\n";
prog_char string_2[] PROGMEM = "<body><h1 align=\"center\">Metal Detector Data</h1>";//HTLM Title
prog_char string_3[] PROGMEM = "<table border=\"2\" width=\"1000\">\n\t<tr>\n\t\t<th>Measurement</th>\n\t\t<th>Coil 1</th>\n\t\t<th>Coil 2</th>\n\t\t<th>Coil 3</th>\n\t\t<th>Coil 4</th>\n\t\t<th>Coil 5</th>\n\t\t<th>Coil 6</th>\n\t\t<th>Coil 7</th>\n\t\t<th>Coil 8</th>\n\t</tr>\n";
prog_char string_4[] PROGMEM = "<table border=\"1\" width=\"100\">\n\t<tr>"; //SGV Container table
prog_char string_5[] PROGMEM = "<td><svg width=\"990\" height=\"60\"   xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n\t<defs>"; //SVG Header
prog_char string_6[] PROGMEM = "\" y=\"00\" stroke=\"black\" stroke-width=\"2\" stroke-dasharray=\"6 6\"/>\n"; //Dash Array text
prog_char string_7[] PROGMEM = "960,60\" style=\"stroke:#660000; fill:#cc3333; stroke-width: 1;\"/></td>\n\n</svg></td>\n\n<tr></table>\n</body>\n</html>\n";//SGV POLYGON and close of HTML

PROGMEM const char *string_table[] =    // change "string_table" name to suit
{   
  string_0,
  string_1,
  string_2,
  string_3,
  string_4,
  string_5,
  string_6,
  string_7
 };

char buffer[250];    // make sure this is large enough for the largest string it must hold

//Kano retrieve me bazontas to i san to string pou thelo kai meta print to buffer
//strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i])));


File myFile;
int cx = 300;
int lineReadings[8];
int lineNo = 1;
int xcoord = 260;

void getReadings(){
  for (int i=0;i<8;i++)
  {
    lineReadings[i] = random(0,10)*5;
  }
}

void printReadings()
{
  for (int i=0;i<8;i++)
  {
    Serial.print("Reading : \t");
    Serial.print(i+1);
    Serial.print(" = ");
    Serial.print(lineReadings[i]);
    Serial.println("");
  }
}
void setup()
{
  getReadings();
 
  Serial.begin(9600);
 
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
  // Note that even if it's not used as the CS pin, the hardware SS pin
  // (10 on most Arduino boards, 53 on the Mega) must be left as an output
  // or the SD library functions will not work.
   pinMode(10, OUTPUT);
   Serial.println("Initializing SD card...");
}

void loop()
{
  Serial.println("Begin");
 
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
  }
  else{
  Serial.println("initialization done.");
    renderHtml(); 
  }
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
    //Cannot open 4 characters extention name so html is replaced by htm
  printReadings();
  Serial.print("END");
  while(1);
  // nothing happens after setup
}

void renderHtml(){
  myFile = SD.open("data.htm", FILE_WRITE);
 
  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("Writing to test.txt...");
   
    /*
    //Begin with HTML file header
    myFile.println("<!DOCTYPE html>\n<html>\n<head>\n<title>Quantitative Metal Detector Data Visualisation</title>\n");

    //We cannot afford external CSS so we add them in the head section of the HTML and close the head
    myFile.println("<style type=\"text/css\">\ntable { margin-left:auto; margin-right:auto;text-align:center; }\nsvg { display:block;margin-right:auto;margin-left:auto;margin-top:10px;margin-bottom:10px; }\nbody {background-color:#EEEEEE;}\n</style>\n</head>\n");
   
    //Start printing the body and header
    myFile.println("<body><h1 align=\"center\">Metal Detector Data</h1>");   
   
    //Create the Name Part of the Data Table
    myFile.print("<table border=\"2\" width=\"1000\">\n\t<tr>\n\t\t<th>Measurement</th>\n\t\t<th>Coil 1</th>\n\t\t<th>Coil 2</th>\n\t\t<th>Coil 3</th>\n\t\t<th>Coil 4</th>");
    myFile.print("\n\t\t<th>Coil 5</th>\n\t\t<th>Coil 6</th>\n\t\t<th>Coil 7</th>\n\t\t<th>Coil 8</th>\n\t</tr>\n");
    */
    //Create the Data part of the Table
   
    //Newcode with PROGMEM
    for (int i = 0; i < 4; i++)
    {
      strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); // Necessary casts and dereferencing, just copy.
      myFile.println( buffer );
      delay( 500 );
    }
   
   
    myFile.print("\t<tr>\n\t\t<td>");
    myFile.print(lineNo);//Print the Line Number
    myFile.print("</td>\n");
   
    //Go through each of the readings   
    for(int i =0;i<8;i++){
      myFile.print("\t\t<td>");
      myFile.print(lineReadings[i]);//Dump the readings into the HTML table
      myFile.print("</td>\n");   
    }
   
    //Close the table   
    myFile.println("\t</tr>\n</table>\n");
   
    //Start Printing the SVG part of the file
   
    //Create the container table
   // myFile.println("<table border=\"1\" width=\"100\">\n\t<tr>");
      strcpy_P(buffer, (char*)pgm_read_word(&(string_table[4]))); // Necessary casts and dereferencing, just copy.
      myFile.println( buffer );
      delay( 500 );
   
   
    //Create the svg header
    //myFile.println("<td><svg width=\"990\" height=\"60\"   xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n\t<defs>");
   
      strcpy_P(buffer, (char*)pgm_read_word(&(string_table[5]))); // Necessary casts and dereferencing, just copy.
      myFile.println( buffer );
      delay( 500 );
   
   
    //Damp readings into the line euations
    for(int i =0;i<8;i++){
      myFile.print("\t<line id=\"line");
      myFile.print(i); //required to name lines differently
      myFile.print("\" x1=\"0\"  y2=\"");
      myFile.print(lineReadings[i]); //Data input line
      myFile.print("\" y1=\"0\" x2=\"0\" />\n"); 
    }
    //Close the definitions part of the svg
    myFile.println("\t</defs>");
    //dotPrint();
   
    //Make the lines Dotted and place them in X coordinates
   

     strcpy_P(buffer, (char*)pgm_read_word(&(string_table[6]))); // Necessary casts and dereferencing, just copy.
     //myFile.println( buffer );
     //delay( 500 );
     
    for(int i =0;i<8;i++){
      myFile.print("\t<use xlink:href=\"#line");
      myFile.print(i);//syncronize with the line name afrom above
      myFile.print("\" x=\"");
      myFile.print(xcoord); //add the current point coordinate
      myFile.print(buffer );
      //myFile.print("\" y=\"00\" stroke=\"black\" stroke-width=\"2\" stroke-dasharray=\"6 6\"/>\n");
      xcoord = xcoord + 100;
      delayMicroseconds(100);
    }
   
    xcoord = 260; //Reset xcoord for next loop
   
    //Draw the polygon
    myFile.print("<polygon points=\"260,60 ");
    for (int i = 0;i<8;i++)
    {
      myFile.print(xcoord);
      myFile.print(",");
      myFile.print(lineReadings[i]);
      myFile.print(" ");
      xcoord = xcoord + 100;
    }
   
    xcoord = 260; //Reset xcoord for next loop
   
   
    //Close the polygon,tables and html file
     strcpy_P(buffer, (char*)pgm_read_word(&(string_table[7]))); // Necessary casts and dereferencing, just copy.
     myFile.println( buffer );
     //delay( 500 );
   
    //close the table and SVG
    //myFile.println("</svg></td>\n\t<tr>\n</table>");
   
    //Close the html File
    //myFile.println("</body>\n</html>");

// close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
}

To point out the difference using arduino-1.0\hardware\tools\avr\bin\avr-size tool my code had 892 + 817 (DATA + BSS) = 1709 SDRAM usage and the  new one uses 378+1067= 1445 .I think I can optimize it more.


* metal.png (14.38 KB, 1044x250 - viewed 13 times.)
Logged

Pages: [1]   Go Up
Jump to: