Shop OBEX P1 Docs P2 Docs Learn Events
Reading & Printing from SD with Activity Board — Parallax Forums

Reading & Printing from SD with Activity Board

John KauffmanJohn Kauffman Posts: 653
edited 2013-11-19 18:41 in Propeller 1
Propeller Activity Board / C / SImpleIDE
I have code below which writes three data to the SD card. Each write is an independent open,write,close. Then contents of file read from file on SD card.
I know the writes work because I can move the SD to my PC and open with notepad and see three records.
But the read&print part only shows the first record. Perhaps adding \n to data string is problem when print?(although seemed to work on other projects)
Anyone see the flaw? Thanks.

<code>
/* logger to SD*/
#include "simpletools.h" // Include simple tools

int DO = 22, CLK = 23, DI = 24, CS = 25; // SD card pins on Propeller BOE
char FileName[10] = "Test25.txt"; // create char array with filename string
int RecordSize = 13; //#bytes per record. Comma,return and slash are one each
// record format: Recxx,xx,xx\n = 13
int RecordCount = 0;

int main(void)
{
sd_mount(DO, CLK, DI, CS); // Mount SD card

// create file + open + add record
FILE* fp = fopen(FileName, "a"); // Open a file for append
sleep(1);
//print("file open 1st time\n"); //diagnostic
fwrite("Rec01,12,34\n", 1, RecordSize, fp); // Add contents to the file
fclose(fp); // Close the file
RecordCount++;

// open + add record (2nd record)
fopen(FileName, "a"); // Open a file for append
//print("file open 2nd time\n"); //diagnostic
sleep(1);
fwrite("Rec02,56,78\n", 1, RecordSize, fp); // Add contents to the file
fclose(fp); // Close the file
RecordCount++;

// open + add record (3rd record)
fopen(FileName, "a"); // Open a file for append
//print("file open 3rd time\n"); //diagnostic
sleep(1);
fwrite("Rec03,90,12\n", 1, RecordSize, fp); // Add contents to the file
fclose(fp); // Close the file
RecordCount++;

// read whole file into a char array (string)
char s[RecordCount*RecordSize]; // Buffer for characters - size caculated
fp = fopen(FileName, "r"); // Reopen file for reading
fread(s, 1, RecordCount*RecordSize, fp); // Read characters into array "s"
fclose(fp); // Close the file
// print the string
printf("From %s\ with %i records\n",FileName,RecordCount); // Display heading
print("%s", s); // Display characters
print("done\n"); // With a newline at the end
}
</code>

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2013-11-19 05:41
    // record format: Recxx,xx,xx\n = 13
    That string is only 12 bytes in length (\n counts as 1). By writing 13 characters you include the zero terminator which causes printing to stop, i.e. you'll only see the first record. That said, once you start using 12 characters make sure your array s[] is zero terminated (i.e. increase size by 1 and make sure the last character is 0). Otherwise the printf may pick up unwanted data.

    Or you could stick with 13 characters but then you have to print each record individually (a two dimensional array may come in handy here).

    Please use [noparse]
    
    [/noparse] instead of <code> ...                        
  • Dave HeinDave Hein Posts: 6,347
    edited 2013-11-19 05:42
    The value of RecordSize should be 12, and not 13. The "\n" in the string is converted to a single byte by the C compile, so even though it's 2 characters in the source code, it is only 1 byte in the compiled code. Because you're using 13 it is writing an extra garbage a null byte after the string.
  • John KauffmanJohn Kauffman Posts: 653
    edited 2013-11-19 17:55
    Thanks for both solution and for theory. That makes complete sense and dropping the RecordSize to 12 makes all 3 records print.

    But there is a spurious character printing on the last line before the string "done" I think it is ASCII 195 ( T rotated -90 degrees).

    Here is what I am picturing if it was 2 recs by 8 btes each (a little briefer example).
    The data in the file would be "Rec1,11\nRec2,22\n" with \n replaced by the return character
    Since the fread() is fetching exactly 16 characters then wouldn't it get exactly the above string?
    Then the array dimmed s[16] would hold all 16 chars in the file and no more.
    What is the role of a terminal zero?

    Here is how I tried adding a terminal zero in code with two lines ***
    // read whole file into a char array (string)
      char s[(RecordCount*RecordSize)+1];           // create array s[] to hold characters as they are read. ***Extra char for terminal zero
      fp = fopen(FileName, "r");                // Reopen file for reading
      fread(s, 1, RecordCount*RecordSize, fp);  // Read characters into array "s"
      s[(RecordCount*RecordSize)+1] = "0";  //*** add terminal zero
      fclose(fp);                               // Close the file
    

    The result is worse: three spurious characters on last row before "done"
    Thanks for explaining the theory behind this.
  • kuronekokuroneko Posts: 3,623
    edited 2013-11-19 18:03
    What is the role of a terminal zero?
    printf("%s", addr); assumes that a zero terminated string is stored at addr. If there isn't one it keeps going until it finds one. Simple as that.
    s[(RecordCount*RecordSize)+1] = "0"; //*** add terminal zero
    You want either '\0' or simply 0 here. And - being 0 indexed - that should read s[(RecordCount*RecordSize)] = 0 (but allocation still needs to be +1).
  • John KauffmanJohn Kauffman Posts: 653
    edited 2013-11-19 18:41
    I was worrying about s[] and fread(), But the problem was in print(). Thanks.

    Here is final code for future forum searchers.
    /* logger to SD
    Each of 3 new records opens file and appends. Then all data printed to terminal.
    Data hard-coded and records = 3 in this example
    Reulting file is ready to import to Excel as CSV (remove command that prints heading)
    */
    #include "simpletools.h"                      // Include simple tools
    int DO = 22, CLK = 23, DI = 24, CS = 25;      // SD card pins on Propeller Activity Board
    char FileName[10] = "Test31.txt";   // create char array with filename string
    int RecordSize = 12;  //#bytes per record. Comma is one. "\n" is ONE ONLY
      // record format: Recxx,yy,zz\n = 12. xx=record number. y,z = data
    int RecordCount = 0;
    
    int main(void)                                // main function
    {
      sd_mount(DO, CLK, DI, CS);                  // Mount SD card
    
    // Append multiple data
    // create file + open + add first record
      FILE* fp = fopen(FileName, "a");          // Open a file for append
      fwrite("Rec01,12,34\n", 1, RecordSize, fp);      // Add contents to the file
      fclose(fp);                                 // Close the file
      RecordCount++;
    // open + add record (2nd record)
      fopen(FileName, "a");          // Open a file for append
      fwrite("Rec02,56,78\n", 1, RecordSize, fp);      // Add contents to the file
      fclose(fp);                                 // Close the file
      RecordCount++;
    // open + add record (3rd record)
      fopen(FileName, "a");          // Open a file for append
      fwrite("Rec03,90,12\n", 1, RecordSize, fp);      // Add contents to the file
      fclose(fp);                                 // Close the file
      RecordCount++;
    
    // read whole file into a char array (string)
    //Array to hold characters as they are read + one member for zero required by printf()
      char s[(RecordCount*RecordSize)+1];   
      fp = fopen(FileName, "r");                // Reopen file for reading
      fread(s, 1, RecordCount*RecordSize, fp);  // Read characters into array "s"
      s[(RecordCount*RecordSize)] = 0; // for printf() put a zero to terminate the string
      fclose(fp);                               // Close the file
    // print the string
      printf("From %s\ with %i records\n",FileName,RecordCount);     // Display heading
      printf("%s", s);  // Display characters. printf will keep printing until it hits a zero
      print("Done\n"); // ?? string won't show unless final \n added.
    }    
    
Sign In or Register to comment.