ArduinoForum.de - Das deutschsprachige Forum rund um den Arduino
Erweiterung für SD: fprintf_, fgets_, fscanf_ - Druckversion

+- ArduinoForum.de - Das deutschsprachige Forum rund um den Arduino (https://www.arduinoforum.de)
+-- Forum: Arduino-Allgemein (/arduino-Forum-Arduino-Allgemein)
+--- Forum: Arduino-Projekte (/arduino-Forum-Arduino-Projekte)
+--- Thema: Erweiterung für SD: fprintf_, fgets_, fscanf_ (/arduino-Thread-Erweiterung-f%C3%BCr-SD-fprintf-fgets-fscanf)



Erweiterung für SD: fprintf_, fgets_, fscanf_ - HaWe - 08.03.2015 17:23

hallo,
habe endlich fertig: Cool

es werden ja bekanntlich für SD-Files keine stdio.h -Funktionen unterstützt, z.B. gibt es in der SD-Klasse kein fprintf und kein fscanf,
sondern z.B. Funktionen wie (myFile).print und (myFile).println zum Schreiben,
und nur (myFile).read zum Byte-weise Lesen, was die Sache sehr umständlich macht
(z.B. ein (myFile).readln gibt es nicht, würde aber auch nicht einer C-Standard-Funktion entsprechen!)

Zum Schreiben und Lesen von Strings und formatierter Variablen in SD-Files habe ich daher eigene Funktionen
fprintf_() , fgets_() und fscanf_()
geschrieben, die praktisch genau so arbeiten wie die Originale in ANSI C.

Hier der Sourcecode:

int fprintf_ ( File * stream, const char fmtstr[], ... )
arbeitet wie das stdio.h C-Original fprintf(): Es schreibt einen string in ein file, dabei werden die Variablen/Argumente entsprechend dem formatstring als strings formatiert (gleiche Funktionsweise wie auch bei printf oder sprintf)

char * fgets_ ( char * str, int32_t num, File * stream )
Liest entsprechend der Original C-stdio.h Funktion einen string aus einem File, bis eine String-Terminierung oder ein Zeilenumbruch oder eof() oder die max Länge des übergebenen Puffers erreicht ist (je nachdem, was früher eintritt).
Im Falle dass "mein" fgets_() keine lesbaren Daten findet, wird ein Leerstring ("") zurückgegeben, kein Nullpointer NULL wie bei Original fgets(), da der Nullpointer IMO bei Sketch schwer zu handhaben ist - natürlich kann man das ändern.


int32_t fscanf_ ( File * stream, const char fmtstr[], ... );
liest einen String aus einem File und re-formatiert alle darin enthaltenen Variablen entsprechend dem Formatstring
(also %d zu int und %f zu float)
Achtung: ints müssen int32_t sein, int_16_t ist nicht erlaubt.
teilw. bekannte Probleme mit double, float funktioniert aber.


Aufruf z.B.:
Code:
File myFile;
char sdata[128];

fprintf_(&myFile, "%s\n%d\n%d\n%f\n%f\n", "EinTeststring", 1, 2, PI, 4.567890);
// schreibt die 5 Variablen (1x string, 2x int, 2x float), getrennt durch Zeilenumbrüche, in ein File.
fprintf_(&myFile, "%s %d %d %f %f", "EinTeststring", 1, 2, PI, 4.567890);
// dto, aber getrennt durch Leerzeichen, kein Zeilenvorschub.


fgets_ ( sdata, 20, &myFile );
// liest und kopiert aus der Datei einen Teilstring in den String-Buffer "sdata",
// der dann anschließend als string oder umgewandelt zu int oder float weiterverwendet werden kann.



int32_t  m, n, cnt;
float    x, y;
cnt = fscanf_ ( myFile,  "%d %d %f %f",  &m, &n, &x, &y );
// liest einen String aus einem File,
// re-formatiert alle darin enthaltenen Variablen entsprechend dem Formatstring (%d als ints, %f als floats)
// und weist sie den übergebenen Variablen m,n,x,y zu.

Sourcecode der Funktionen:

Code:
//********************************************************************************​​***********  
int fprintf_ ( File * stream, const char fmtstr[], ... ) {
   char      str[1024];
   va_list   arguments;
   int16_t   num;
    
   va_start( arguments, fmtstr);
   num = vsprintf(str, fmtstr, arguments);
   stream->print(str);
   va_end( arguments );

   return num;
}
//********************************************************************************​​***********

Code:
//********************************************************************************​***********
char * fgets_ ( char * str, int32_t num, File * stream ) {
  int32_t i = 0;
  
  strcpy(str, "");
  while (i < (num - 1)) { // got room for newline and terminating null?
    int16_t ch = stream->read();
    if (ch < 0) // end of file
      break;
    str[i++] = ch;
    if ('\n' == ch) // end of line
      break;
  }
  
  if (i) { // room in buffer for terminating null
    str[i] = 0;
    return str;
  }
  else
  return NULL; // buffer too small or immediate end of file
  // { strcpy(str, ""); return str; } // alternative
}
//********************************************************************************​***********


Code:
//********************************************************************************​​***********  
int32_t  fscanf_ ( File * stream, const char fmtstr[], ... ) {
   const  int32_t   MAXSTRSIZE = 1024;
   char   str[MAXSTRSIZE];
   va_list   args;  
   int16_t   i=0, cnt=0;
   int16_t   chr;
  
   va_start(args, fmtstr);
  
   strcpy(str, "");
   while ( (stream->available()) && (i < MAXSTRSIZE-1) ) {    
      chr = stream->read() ;
      if (chr>=0 && chr!='\n') {
           str[i]=(char)chr;      
           ++i;
      }
      else break;      
   }  
  
   str[++i] = '\0';
                                                        
   cnt = vsscanf ( str, fmtstr, args );  
   va_end(args);
  
   return cnt;
}
//********************************************************************************​​***********



Testcode für fprintf_ und fgets_():
Code:
/*
SD card: fprintf_() und fgets_()
ver 1.01
*/

#include <SPI.h>
#include <SD.h>


// SD Card
#define SD_CSpin 4
File myFile;
char fname[64];

char sdata[128];
char sbuf[128];



//********************************************************************************​***********
char * fgets_ ( char * str, int32_t num, File * stream ) {
  int32_t i = 0;
  
  strcpy(str, "");
  while (i < (num - 1)) { // got room for newline and terminating null?
    int16_t ch = stream->read();
    if (ch < 0) // end of file
      break;
    str[i++] = ch;
    if ('\n' == ch) // end of line
      break;
  }
  
  if (i) { // room in buffer for terminating null
    str[i] = 0;
    return str;
  }
  else
  return NULL; // buffer too small or immediate end of file
  // { strcpy(str, ""); return str; } // alternative
}
//********************************************************************************​***********



//********************************************************************************​***********  
int fprintf_ ( File * stream, const char fmtstr[], ... ) {
   char      str[1024];
   va_list   arguments;
   int16_t   num;
    
   va_start( arguments, fmtstr);
   num = vsnprintf(str, sizeof str, fmtstr, arguments);
   // #debug
   // Serial.println( "string to write to file="); Serial.println( str);    
   stream->print(str);
   va_end( arguments );

   return num;
}
//********************************************************************************​***********  


void setup()
{
  int16_t  p, i, cnt;
  float    x;
  char     sval[20];
  int16_t  ival;
  double   fval;
  
  pinMode(SD_CSpin, OUTPUT);  
  Serial.begin(9600);
  
  sprintf(sbuf,"#: SD Initializing... ");
  Serial.println(sbuf);  

  while(!SD.begin(SD_CSpin) ) {
    sprintf(sbuf,"#: ...SD init failed ");
    Serial.println(sbuf);
    delay(1000);
  }
  
  sprintf(sbuf,"#: ...SD OK !      ");
  Serial.println(sbuf);  
  strcpy(fname,"test.txt");
  
  if (SD.exists(fname) ) {
    sprintf(sbuf,"#: %s exists     ",fname);
    Serial.println(sbuf);  
    
    sprintf(sbuf,"#: Removing %s      ",fname);  
    Serial.println(sbuf);
    
    SD.remove("test.txt");
    // removed: success ?
    if (SD.exists(fname) ) {
       sprintf(sbuf,"#: %s  exists     ",fname);  
       Serial.println(sbuf);  
    }
    else {
       sprintf(sbuf,"#: %s  N/A     ",fname);  
       Serial.println(sbuf);  
     }
  }
    
  
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.  
  myFile = SD.open(fname, FILE_WRITE);
  
  if (myFile) {
    // if the file opened okay, write to it, then close file:
    sprintf(sbuf,"#: Writing strings to %s ",fname);
    Serial.println(sbuf);
    
    //---------------------------------------------------------------------------------
    // write data to file
    fprintf_(&myFile, "%s\n%d\n%d\n%f\n%f\n", "Teststring", 1, 2, PI, 4.567890);    
    //---------------------------------------------------------------------------------
  
    // close the file:
    myFile.close();
    sprintf(sbuf,"#: %s closed.   ",fname);
    Serial.println(sbuf);  
  }  
  else {
    // if the file didn't open, print an error:
    sprintf(sbuf,"#: error opening %s   ",fname);
    Serial.println(sbuf);      
  }
  
  Serial.println();
  // re-open the file for reading:
  myFile = SD.open(fname);
  if (myFile) {
    sprintf(sbuf,"#: reading %s ",fname);
    Serial.println(sbuf);  
    
    // read from the file until there's nothing else in it:
    i=0;
    cnt=1;  
    
    while (myFile.available()) {
      strcpy(sdata, "");
      fgets_ ( sdata, 20, &myFile );  
      Serial.print(cnt); Serial.print(": string raw="); Serial.println(sdata);
      Serial.println("rueckformatiert:");
      if (cnt==1) {Serial.print("str  ="); Serial.println(sdata); }
      if (cnt==2) {Serial.print("int  ="); Serial.println(atoi(sdata) ); }
      if (cnt==3) {Serial.print("int  ="); Serial.println(atoi(sdata) ); }
      if (cnt==4) {Serial.print("float="); Serial.println(atof(sdata) ); }
      if (cnt==5) {Serial.print("float="); Serial.println(atof(sdata) ); }
      ++cnt;
    }  
    
    // close the file:
    myFile.close();        
    sprintf(sbuf,"#: %s closed. ",fname);
    Serial.println(sbuf);      
  } else {
    // if the file didn't open, print an error:
    sprintf(sbuf,"#: error opening %s   ",fname);      
    Serial.println(sbuf);

  }
}

void loop()
{
  // nothing happens after setup
}


Testcode für fprintf_() und fscanf_():
Code:
/*
SD card: fprintf_() und fscanf_()
ver 0.04
*/

#include <SPI.h>
#include <SD.h>
#include <stdarg.h>
#include <stdio.h>


// SD Card
#define SD_CSpin 4
File myFile;
char fname[64];

char sdata[128];
char sbuf[128];



//********************************************************************************​​***********  
int32_t  fscanf_ ( File * stream, const char fmtstr[], ... ) {
   const  int32_t   MAXSTRSIZE = 1024;
   char   str[MAXSTRSIZE];
   va_list   args;  
   int16_t   i=0, cnt=0;
   int16_t   chr;
  
   va_start(args, fmtstr);
  
   strcpy(str, "");
   while ( (stream->available()) && (i < MAXSTRSIZE-1) ) {    
      chr = stream->read() ;
      if (chr>=0 && chr!='\n') {
           str[i]=(char)chr;      
           ++i;
      }
      else break;      
   }  
  
   str[++i] = '\0';
   // #debug
   // Serial.print("fscanstr:"); Serial.println(str);
                                                        
   cnt = vsscanf ( str, fmtstr, args );  
   va_end(args);

   return cnt;
}


//********************************************************************************​​***********  

int fprintf_ ( File * stream, const char fmtstr[], ... ) {
   char      str[1024];
   va_list   args;
   int32_t   num;
    
   va_start( args, fmtstr );
   num = vsnprintf(str, sizeof(str), fmtstr, args);
   stream->print(str);
   // #debug
  
   va_end( args );
   Serial.print("fprintf_:"); Serial.println(str);
   return num;
}

//********************************************************************************​​***********  


void setup()
{
  int32_t  p, i, cnt;
  char     sval[20];
  int32_t  ival, n, m;
  float   fval, x, y;
  // alternativ, ohne jeden Effekt: float   fval, x, y;

  pinMode(SD_CSpin, OUTPUT);  
  Serial.begin(9600);
  
  sprintf(sbuf,"#: SD Initializing... ");
  Serial.println(sbuf);  

  while(!SD.begin(SD_CSpin) ) {
    sprintf(sbuf,"#: ...SD init failed ");
    Serial.println(sbuf);
    delay(1000);
  }
  
  sprintf(sbuf,"#: ...SD OK !      ");
  Serial.println(sbuf);  
  strcpy(fname,"test.txt");
  
  if (SD.exists(fname) ) {
    sprintf(sbuf,"#: %s exists     ",fname);
    Serial.println(sbuf);  
    
    sprintf(sbuf,"#: Removing %s      ",fname);  
    Serial.println(sbuf);
    
    SD.remove("test.txt");
    // removed: success ?
    if (SD.exists(fname) ) {
       sprintf(sbuf,"#: %s  exists     ",fname);  
       Serial.println(sbuf);  
    }
    else {
       sprintf(sbuf,"#: %s  N/A     ",fname);  
       Serial.println(sbuf);  
     }
  }
    


  
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.  
  myFile = SD.open(fname, FILE_WRITE);
  
  if (myFile) {
    // if the file opened okay, write to it, then close file:
    sprintf(sbuf,"#: Writing strings to %s ",fname);
    Serial.println(sbuf);
    
    //---------------------------------------------------------------------------------
    // write data to file
    fprintf_(&myFile, "%d %d %f %f\n",  1, 2, PI, 4.567890);    
    //---------------------------------------------------------------------------------
  
    // close the file:
    myFile.close();
    sprintf(sbuf,"#: %s closed.   ",fname);
    Serial.println(sbuf);  
  }  
  else {
    // if the file didn't open, print an error:
    sprintf(sbuf,"#: error opening %s   ",fname);
    Serial.println(sbuf);      
  }
  
  
  
  
  
  // re-open the file for reading:
  Serial.println();
  
  myFile = SD.open(fname);
  if (myFile) {
    sprintf(sbuf,"#: reading %s ",fname);
    Serial.println(sbuf);  
    
    // read from the file until there's nothing else in it:
    i=0;
    cnt=0;  
    strcpy(sdata, "");
    
    //---------------------------------------------------------------------------------
    cnt = fscanf_(&myFile, "%d %d %f %f", &m, &n, &x, &y);
    //---------------------------------------------------------------------------------
                            
    Serial.println("# nach Aufruf cnt=fscanf_ im Hauptprogramm");    
       // Testausgabe:
       Serial.print("returned cnt="); Serial.println(cnt);  
       Serial.println();
       Serial.println("returned reformatted variables m,n,x,y:");
       Serial.println(m);
       Serial.println(n);
       Serial.println(x);
       Serial.println(y);

    
    // close the file:
    myFile.close();        
    sprintf(sbuf,"#: %s closed. ",fname);
    Serial.println(sbuf);      
  } else {
    // if the file didn't open, print an error:
    sprintf(sbuf,"#: error opening %s   ",fname);      
    Serial.println(sbuf);

  }
}

void loop()
{
  // nothing happens after setup
}

share and enjoy! Cool