Shop OBEX P1 Docs P2 Docs Learn Events
C Example Of SD Card Reading — Parallax Forums

C Example Of SD Card Reading

idbruceidbruce Posts: 6,197
edited 2015-03-25 07:33 in Propeller 1
It was my intention of posting this code as an example, which I am, but there is a problem with it, and I would like to know what it is. Besides the main function, there is the SD_PrintValidFileLine(void) function and the void SD_PrintAllCharacters(void) function. Both of these functions work individually, but when run consecutively, one fails. I have tried inserting a pause, thinking that the file was not closed yet, but this did not help.
#include <stdio.h>
#include "simpletools.h"

#define SD_DI 8
#define SD_DO 9
#define SD_CS 12
#define SD_CLK 15

static void SD_PrintValidFileLine(void)
{    
	FILE * pFile;

	char fileline[100];

	pFile = fopen("debug.txt","r");

	if(pFile == NULL)
	{
		print("Error opening file");
	}
	else
	{
		do
		{
               if (fgets(fileline, 100, pFile) != NULL )
               {
                   // Exclude lines that begin with certain characters
                   // E.G. Remove newlines, carriage returns, and lines
                   // that begin with a semi-colon.
                   if(fileline[0] != 59 && fileline[0] != 13 && fileline[0] != 10)
                   {                       
                       print(fileline);
                   }                       
               }
		}
		while(fileline[0] != EOF);
        
		fclose(pFile);
	}
}

static void SD_PrintAllCharacters(void)
{
    
	FILE * pFile;

	int c;

	pFile = fopen("debug.txt","r");

	if(pFile == NULL)
	{
		print("Error opening file");
	}
	else
	{
		do
		{
                c = getc(pFile);
                print("%c", c);
		}
		while(c != EOF);
        
		fclose (pFile);
	}
}

int main(void)
{
	#if defined SD_DO && defined SD_CLK && defined SD_DI && defined SD_CS

	// Mount SD card
	sd_mount(SD_DO, SD_CLK, SD_DI, SD_CS);
     
	print("Print Valid File Lines\n\n");
	SD_PrintValidFileLine();
	pause(2000);
	print("Print All Characters\n\n");
	SD_PrintAllCharacters();
 
	#else
    
	print("The proper inputs and outputs must be defined for SD card usage");
    
	#endif
    
	return 0;
}


EDIT: I wish we could get an editor that works with proper tab layout :)

Comments

  • DavidZemonDavidZemon Posts: 2,973
    edited 2015-03-23 18:45
    Just to clarify, when you say "consecutively", you don't mean same time in two different cogs do you?

    Unfortunately, I don't see any issues with the code as you've posted it :(
  • r.daneelr.daneel Posts: 96
    edited 2015-03-23 19:01
    idbruce wrote: »
    Both of these functions work individually, but when run consecutively, one fails.

    With what symptoms?
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-03-23 19:22
    Does you first function ever return? I don't believe EOF is stored in the first character of the buffer when you encounter the end of file. And even if it were, EOF is defined as -1, and PropGCC's char type is unsigned, so the value would never equal -1, but would be 255 instead. You should just use the fact that fgets return NULL when it encounters the EOF to terminate the loop.
  • idbruceidbruce Posts: 6,197
    edited 2015-03-24 01:47
    Dave
    And even if it were, EOF is defined as -1, and PropGCC's char type is unsigned, so the value would never equal -1, but would be 255 instead. You should just use the fact that fgets return NULL when it encounters the EOF to terminate the loop.

    I tried them both with -1 also and with int instead of char, but still no good, however I did not try NULL fgets. I will try that.
    Does you first function ever return?

    I will redeclare the function to provide a result. That is the most likely answer.
  • idbruceidbruce Posts: 6,197
    edited 2015-03-24 01:49
    Just to clarify, when you say "consecutively", you don't mean same time in two different cogs do you?

    No, I mean one after the other :)
  • TorTor Posts: 2,010
    edited 2015-03-24 02:20
    while(fileline[0] != EOF);
    is almost certainly wrong, there is no EOF stored in the data read from a file (or sd card or anything). EOF is only a special return value from certain LibC functions, like fgetc() (but not fgets()), but that's it. It's not a character found in a file stream.

    -Tor
  • idbruceidbruce Posts: 6,197
    edited 2015-03-24 02:31
    Dave was right, the char needed to be tested wilth NULL.

    Here is a nice working example.
    #include <stdio.h>
    #include "simpletools.h"
    
    #define SD_DI 8
    #define SD_DO 9
    #define SD_CS 12
    #define SD_CLK 15
    
    static int SD_PrintValidFileLine(void)
    {    
    	FILE * pFile;
    
    	char fileline[100];
    
    	pFile = fopen("debug.txt","r");
    
    	if(pFile == NULL)
    	{
    		print("Error opening file");
    	}
    	else
    	{
    		do
    		{
                   if (fgets(fileline, 100, pFile) != NULL )
                   {
                       // Exclude lines that begin with certain characters
                       // E.G. Remove newlines, carriage returns, and lines
                       // that begin with a semi-colon.
                       if(fileline[0] != 59 && fileline[0] != 13 && fileline[0] != 10)
                       {                       
                           print(fileline);
                       }                       
                   }
    		}
    		while(fileline[0] != NULL);
            
    		fclose(pFile);
    	}
    	return -1;
    }
    
    static int SD_PrintAllCharacters(void)
    {
        
    	FILE * pFile;
    
    	int c;
    
    	pFile = fopen("debug.txt","r");
    
    	if(pFile == NULL)
    	{
    		print("Error opening file");
    	}
    	else
    	{
    		do
    		{
                    c = getc(pFile);
                    print("%c", c);
    		}
    		while(c != EOF);
            
    		fclose (pFile);
    	}
    	return -1;
    }
    
    int main(void)
    {
    	int nResult;
    
    	#if defined SD_DO && defined SD_CLK && defined SD_DI && defined SD_CS
    
    	// Mount SD card
    	sd_mount(SD_DO, SD_CLK, SD_DI, SD_CS);
         
    	print("Print Valid File Lines\n\n"); 
    	nResult = SD_PrintValidFileLine();
     
    	print("\n\n");
     
    	if(nResult == -1)
    	{
    		print("SD_PrintValidFileLine() returned successfully");
    	}     
     
    	print("\n\n");
     
    	print("Print All Characters\n\n");
    	nResult = SD_PrintAllCharacters();
     
    	print("\n\n");
     
    	if(nResult == -1)
    	{
    		print("SD_PrintAllCharacters() returned successfully");
    	}     
     
    	#else
        
    	print("The proper inputs and outputs must be defined for SD card usage");
        
    	#endif
        
    	return 0;
    }
    
  • kuronekokuroneko Posts: 3,623
    edited 2015-03-24 03:00
    idbruce wrote: »
    Dave was right, the char needed to be tested wilth NULL.
    I don't buy this. There is no way I can see right now that the first character in the buffer ends up as 0 (not counting fgets failing immediately and the array being cleared to start with). I'd use something like this:
    do
    {
        ...
    }
    while (!feof(pFile));
    

    Also, in SD_PrintAllCharacters you want to test for EOF first before printing it.
    while((c = getc(pFile)) != EOF)
    {
        printf("%c", c);
    }
    
  • idbruceidbruce Posts: 6,197
    edited 2015-03-24 04:58
    Okay kuroneko

    I would have to agree on both accounts. It looks a whole lot better.
    #include <stdio.h>
    #include "simpletools.h"
    
    #define SD_DI 8
    #define SD_DO 9
    #define SD_CS 12
    #define SD_CLK 15
    
    #define DEBUG 1
    
    #ifdef DEBUG
    
    	#define DEBUG_ERROR 2
    
    #else
    
    	// set to zero to optimise out
    	#define DEBUG_ERROR 0
    
    #endif
    
    static uint8_t debug_flags;
    
    static int SD_PrintValidFileLine(void)
    {    
    	FILE * pFile;
    
    	char fileline[100];
    
    	pFile = fopen("debug.txt","r");
    
    	if(pFile == NULL)
    	{
    		if(DEBUG && (debug_flags & DEBUG_ERROR))
    		{
    			print("ERROR - The file could not be opened!");
    		}
    	}
    	else
    	{
    		do
    		{
                   if (fgets(fileline, 100, pFile) != NULL )
                   {
                       // Exclude lines that begin with certain characters
                       // E.G. Remove newlines, carriage returns, and lines
                       // that begin with a semi-colon.
                       if(fileline[0] != 59 && fileline[0] != 13 && fileline[0] != 10)
                       {                       
                           print(fileline);
                       }                       
                   }
    		}
    		while(!feof(pFile));
            
    		fclose(pFile);
    	}
    	return -1;
    }
    
    static int SD_PrintAllCharacters(void)
    {
        
    	FILE * pFile;
    
    	int c;
    
    	pFile = fopen("debug.txt","r");
    
    	if(pFile == NULL)
    	{
    		if(DEBUG && (debug_flags & DEBUG_ERROR))
    		{
    			print("ERROR - The file could not be opened!");
    		}
    	}
    	else
    	{
    		do
    		{
                    while((c = getc(pFile)) != EOF)
                    {
                        print("%c", c);
                    }                    
    		}
    		while(c != EOF);
            
    		fclose (pFile);
    	}
    	return -1;
    }
    
    int main(void)
    {
    	int nResult;
    
    	debug_flags |= DEBUG_ERROR;
    
    	#if defined SD_DO && defined SD_CLK && defined SD_DI && defined SD_CS
    
    	// Mount SD card
    	sd_mount(SD_DO, SD_CLK, SD_DI, SD_CS);
         
    	print("Print Valid File Lines\n\n"); 
    	nResult = SD_PrintValidFileLine();
     
    	print("\n\n");
     
    	if(nResult == -1)
    	{
    		print("SD_PrintValidFileLine() returned successfully");
    	}     
     
    	print("\n\n");
     
    	print("Print All Characters\n\n");
    	nResult = SD_PrintAllCharacters();
     
    	print("\n\n");
     
    	if(nResult == -1)
    	{
    		print("SD_PrintAllCharacters() returned successfully");
    	}     
     
    	#else
        
    	if(DEBUG && (debug_flags & DEBUG_ERROR))
    	{
    		print("ERROR - The proper inputs and outputs must be defined for SD card usage!");
    	}
        
    	#endif
        
    	return 0;
    }
    
  • kuronekokuroneko Posts: 3,623
    edited 2015-03-24 05:02
    idbruce wrote: »
    [color="red"]do
    {[/color]
        while((c = getc(pFile)) != EOF)
        {
            print("%c", c);
        }                    
    [color="red"]}
    while(c != EOF);[/color]
    
    The outer do/while can be omitted :)
  • idbruceidbruce Posts: 6,197
    edited 2015-03-24 05:12
    LOL :)

    I suppose it can.
  • idbruceidbruce Posts: 6,197
    edited 2015-03-24 05:19
    Okay here is a corrected example.... Thanks kuroneko.

    For those who care, over next couple of days, I will be extending this sample to manioulate data.

    EDIT: Actually it will be a different example, more specifically reading a file line and manipulating the contents.
    #include <stdio.h>
    #include "simpletools.h"
    
    #define SD_DI 8
    #define SD_DO 9
    #define SD_CS 12
    #define SD_CLK 15
    
    #define DEBUG 1
    
    #ifdef DEBUG
    
    	#define DEBUG_ERROR 2
    
    #else
    
    	// set to zero to optimise out
    	#define DEBUG_ERROR 0
    
    #endif
    
    static uint8_t debug_flags;
    
    static int SD_PrintValidFileLine(void)
    {    
    	FILE * pFile;
    
    	char fileline[100];
    
    	pFile = fopen("debug.txt","r");
    
    	if(pFile == NULL)
    	{
    		if(DEBUG && (debug_flags & DEBUG_ERROR))
    		{
    			print("ERROR - The file could not be opened!");
    		}
    	}
    	else
    	{
    		do
    		{
                   if (fgets(fileline, 100, pFile) != NULL )
                   {
                       // Exclude lines that begin with certain characters
                       // E.G. Remove newlines, carriage returns, and lines
                       // that begin with a semi-colon.
                       if(fileline[0] != 59 && fileline[0] != 13 && fileline[0] != 10)
                       {                       
                           print(fileline);
                       }                       
                   }
    		}
    		while(!feof(pFile));
            
    		fclose(pFile);
    	}
    	return -1;
    }
    
    static int SD_PrintAllCharacters(void)
    {
        
    	FILE * pFile;
    
    	int c;
    
    	pFile = fopen("debug.txt","r");
    
    	if(pFile == NULL)
    	{
    		if(DEBUG && (debug_flags & DEBUG_ERROR))
    		{
    			print("ERROR - The file could not be opened!");
    		}
    	}
    	else
    	{
    		while((c = getc(pFile)) != EOF)
    		{
    			print("%c", c); 
    		}
            
    		fclose (pFile);
    	}
    	return -1;
    }
    
    int main(void)
    {
    	int nResult;
    
    	debug_flags |= DEBUG_ERROR;
    
    	#if defined SD_DO && defined SD_CLK && defined SD_DI && defined SD_CS
    
    	// Mount SD card
    	sd_mount(SD_DO, SD_CLK, SD_DI, SD_CS);
         
    	print("Print Valid File Lines\n\n"); 
    	nResult = SD_PrintValidFileLine();
     
    	print("\n\n");
     
    	if(nResult == -1)
    	{
    		print("SD_PrintValidFileLine() returned successfully");
    	}     
     
    	print("\n\n");
     
    	print("Print All Characters\n\n");
    	nResult = SD_PrintAllCharacters();
     
    	print("\n\n");
     
    	if(nResult == -1)
    	{
    		print("SD_PrintAllCharacters() returned successfully");
    	}     
     
    	#else
        
    	if(DEBUG && (debug_flags & DEBUG_ERROR))
    	{
    		print("ERROR - The proper inputs and outputs must be defined for SD card usage!");
    	}
        
    	#endif
        
    	return 0;
    }
    
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-03-24 05:20
    idbruce wrote: »
    Dave was right, the char needed to be tested wilth NULL.
    That is not what I said. You misunderstood my comment. You should look at the return value coming from fgets, and if that is NULL you have hit the end of the file, and you should terminate the loop.

    Your loop can be simplified to:
                   while (fgets(fileline, 100, pFile))
                   {
                       // Exclude lines that begin with certain characters
                       // E.G. Remove newlines, carriage returns, and lines
                       // that begin with a semi-colon.
                       if(fileline[0] != 59 && fileline[0] != 13 && fileline[0] != 10)
                       {                       
                           print(fileline);
                       }                       
                   }
    
  • idbruceidbruce Posts: 6,197
    edited 2015-03-24 05:34
    Sorry Dave, I misunderstood you.

    Or how about this?
    		while(!feof(pFile))
    		{
    			fgets(fileline, 100, pFile);
    
    			// Exclude lines that begin with certain characters
    			// E.G. Remove newlines, carriage returns, and lines
    			// that begin with a semi-colon.
    			if(fileline[0] != 59 && fileline[0] != 13 && fileline[0] != 10)
    			{
                        print(fileline);
    			}
    		}
    
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-03-24 05:44
    That will probably work, but the extra code is superfluous.
  • idbruceidbruce Posts: 6,197
    edited 2015-03-24 10:28
    Dave
    That will probably work, but the extra code is superfluous.

    Considering that fgets will return upon EOF, I would agree that your loop is better.

    So the code now becomes:
    #include <stdio.h>
    #include "simpletools.h"
    
    #define SD_DI 8
    #define SD_DO 9
    #define SD_CS 12
    #define SD_CLK 15
    
    #define DEBUG 1
    
    #ifdef DEBUG
    
    	#define DEBUG_ERROR 2
    
    #else
    
    	// set to zero to optimise out
    	#define DEBUG_ERROR 0
    
    #endif
    
    static uint8_t debug_flags;
    
    static int SD_PrintValidFileLine(void)
    {    
    	FILE * pFile;
    
    	char fileline[100];
    
    	pFile = fopen("debug.txt","r");
    
    	if(pFile == NULL)
    	{
    		if(DEBUG && (debug_flags & DEBUG_ERROR))
    		{
    			print("ERROR - The file could not be opened!");
    		}
    	}
    	else
    	{
    		while(fgets(fileline, 100, pFile))
    		{
    			// Exclude lines that begin with certain characters
    			// E.G. Remove newlines, carriage returns, and lines
    			// that begin with a semi-colon.
    			if(fileline[0] != 59 && fileline[0] != 13 && fileline[0] != 10)
    			{
                        print(fileline);
    			}
    		}
            
    		fclose(pFile);
    	}
    	return -1;
    }
    
    static int SD_PrintAllCharacters(void)
    {
        
    	FILE * pFile;
    
    	int c;
    
    	pFile = fopen("debug.txt","r");
    
    	if(pFile == NULL)
    	{
    		if(DEBUG && (debug_flags & DEBUG_ERROR))
    		{
    			print("ERROR - The file could not be opened!");
    		}
    	}
    	else
    	{
    		while((c = getc(pFile)) != EOF)
    		{
    			print("%c", c); 
    		}
            
    		fclose (pFile);
    	}
    	return -1;
    }
    
    int main(void)
    {
    	int nResult;
    
    	debug_flags |= DEBUG_ERROR;
    
    	#if defined SD_DO && defined SD_CLK && defined SD_DI && defined SD_CS
    
    	// Mount SD card
    	sd_mount(SD_DO, SD_CLK, SD_DI, SD_CS);
         
    	print("Print Valid File Lines\n\n"); 
    	nResult = SD_PrintValidFileLine();
     
    	print("\n\n");
     
    	if(nResult == -1)
    	{
    		print("SD_PrintValidFileLine() returned successfully");
    	}     
     
    	print("\n\n");
     
    	print("Print All Characters\n\n");
    	nResult = SD_PrintAllCharacters();
     
    	print("\n\n");
     
    	if(nResult == -1)
    	{
    		print("SD_PrintAllCharacters() returned successfully");
    	}     
     
    	#else
        
    	if(DEBUG && (debug_flags & DEBUG_ERROR))
    	{
    		print("ERROR - The proper inputs and outputs must be defined for SD card usage!");
    	}
        
    	#endif
        
    	return 0;
    }
    
  • idbruceidbruce Posts: 6,197
    edited 2015-03-25 07:33
    As promised, I have extended a portion of the previous example.

    In this current example, I have eliminated grabbing the fille characters one by one, but I have expanded the program pertaining to grabbing filelines and manipulating the data. This program demonstrates some very useful techniques and functions, for those learning C. Basically, this program is the start of a GCODE parser, in which filelines are grabbed from a GCODE file and the various sections of data are stored within a GCODE structure, and during the course of the processing, the results are displayed on the terminal. Additionally, there is an ample amount of comments within the source code to give you a good idea of what is occuring and how it is done.

    I have also attached some GCODE commands in the text file below, so that you can test it out.

    From this point forward, this specific example and it's growth will documented at this location: http://forums.parallax.com/showthread.php/159950-The-Teacup-Port-A-Work-In-Progress-3D-Printer-Firmware



    ####WARNING######
    If you decide to run this project, please ensure that you set the proper IO pins for your SD card reader in config.h!!!

Sign In or Register to comment.