Read line out of a stored file

Hi,

I am trying to read .gpx files from a LinkIt One board. Therefore I think I need to read each line separately, because the files look like this:

<trk>
    <name>Bahn 1</name>
    <trkseg>
      <trkpt lat="48.1074939" lon="11.2841079">
        <time>2016-08-24T14:21:35Z</time>
      </trkpt>
      <trkpt lat="48.1075139" lon="11.2841409">
        <time>2016-08-24T14:21:35Z</time>
      </trkpt>
      <trkpt lat="48.1075367" lon="11.2841914">
        <time>2016-08-24T14:21:35Z</time>
      </trkpt>
      <trkpt lat="48.1075543" lon="11.284243">
        <time>2016-08-24T14:21:35Z</time>
      </trkpt>
      <trkpt lat="48.1075668" lon="11.2842908">
        <time>2016-08-24T14:21:35Z</time>
      </trkpt>

I only want to know latitude and longitude, so I'd like to read each line individually and then separate the string so that only << lat="......." lon="....." >> remain.
My problem is how to read only one line? I don't understand the MediaTek documentation because there are no examples. This is the docu. What does the void * buf part mean? What do I have to insert there?
If you know another way how to read a file line by line I would be happy to hear.

Sorry for my question does not adress an arduino problem directly but more of a programming in C toppic. I just hope there are enough programming pros who can help me :slight_smile:

'void * buf' means that you need to pass the address of the buffer that will receive the incoming data.

What are you using to read the *.gpx files? If not an Arduino, you're in the wrong place.

OldSteve:
'void * buf' means that you need to pass the address of the buffer that will receive the incoming data.

What are you using to read the *.gpx files? If not an Arduino, you're in the wrong place.

Sorry for seeming like a total noob but how do I do that? Do you have a short example how this should look like? Is it like

char buff[255];
uint16_t nbyte=50;
dataFile.read(buff, nbyte);

or am I completely wrong with this?

I'm using the LinkIt One. Not an Arduino directly but it uses the Arduino.exe programm for PC and its libraries so I thought I can find some help here.

btsens:
I'm using the LinkIt One. Not an Arduino directly but it uses the Arduino.exe programm for PC and its libraries so I thought I can find some help here.

Right, if it uses the Arduino IDE and libraries than it should be fine. (I had no idea what a LinkIt was.)

So I guess "LFile" is a library that you include, based on the Arduino "Stream" class. I was just wondering if we were speaking the same language. :slight_smile:

btsens:
Is it like

char buff[255];

uint16_t nbyte=50;
dataFile.read(buff, nbyte);



or am I completely wrong with this?

Close, but nbyte should hold the size of the buffer:-

char buff[255];
dataFile.read(buff, 255);

Of course, you need to ensure that the buffer is large enough to hold the data that you'll be reading.

Parameters Description
void * buf [OUT] The buffer to retrieve data.
uint16_t nbyte [IN] The size of buffer.

OldSteve:
Right, if it uses the Arduino IDE and libraries than it should be fine. (I had no idea what a LinkIt was.)

So I guess "LFile" is a library that you include, based on the Arduino "Stream" class. I was just wondering if we were speaking the same language. :slight_smile:

The LFile comes from a library for the LinkIt for storage access. The board has Flash storage and an SD slot, so they have a library a little different from the arduino ones (I guess? Though arduino has no SD slot on board as far as I know, so the libraries should be from the distributors of SD shields?)
The main problem is that in this library there is no such thing as .readline included as I know it from C# or JAVA programming. The whole thing with reading data is relatively new for me.

I tried with this:

#include <LFlash.h>
#include <LSD.h>
#include <LStorage.h>


#define Drv LFlash   

LFile dataFile;
char buff[255];
uint16_t nbyte=50;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Drv.begin();
  dataFile=Drv.open("Windach_bahnen.gpx", FILE_READ);
  String readline;
  if(dataFile){
    while(dataFile.available()){
     // readline=dataFile.read(buff, 255);
      Serial.println(dataFile.read(buff, 255));
  }
}
}

but all I get is a row full of "255" and the last number is "239"...I guess this is not how this works :smiley:
Probably this is because the read() method is in int. But why should read() be int? Wouldn't it be much more sensible to get data as a char or string? I don't find other methods though, with which I could read a file.

Edit: Problem found (partly): If I use Serial.write instead of Serial.println I get the whole document (as long as I just use dataFile.read();). Though when I use dataFile.read(buff, 50); I get a line full of "2"...

read returns an int so it can indicate that there was no character available (value -1) while bytes go from 0..255.

btsens:
The LFile comes from a library for the LinkIt for storage access. The board has Flash storage and an SD slot, so they have a library a little different from the arduino ones (I guess? Though arduino has no SD slot on board as far as I know, so the libraries should be from the distributors of SD shields?)
The main problem is that in this library there is no such thing as .readline included as I know it from C# or JAVA programming. The whole thing with reading data is relatively new for me.

If you want to read each line into a buffer, then parse it, you might be better to use the single byte version of 'read()', and check each char that's read for a newline character, '\n', to signify the end of the line. Then you could use 'strstr()' to find lat=" or long=", followed by 'parseFloat()' (Edit: Silly mistake.) 'strtof()' to retrieve the value.

To use the single byte version of 'read()', you'd do this:-

char c = dataFile.read();

I'm far from an expert on this, so someone else will probably help with a better method.

I just saw your latest reply. You can't use the multi-byte version of 'read()' like that. The return value is the number of bytes read, so it should be 255. (The bytes received will be stored in the buffer that you passed the address of.)

OldSteve:
If you want to read each line into a buffer, then parse it, you might be better to use the single byte version of 'read()', and check each char that's read for a newline character, '\n', to signify the end of the line. Then you could use 'strstr()' to find lat=" or long=", followed by 'parseFloat()' to retrieve the value.

To use the single byte version of 'read()', you'd do this:-

char c = dataFile.read();

I'm far from an expert on this, so someone else will probably help with a better method.

I just saw your latest reply. You can't use the multi-byte version of 'read()' like that. The return value is the number of bytes read, so it should be 255. (The bytes received will be stored in the buffer that you passed the address of.)

All right, I will try with this version. I guess with some "if"s and "while"s I should make this work. Thank you :slight_smile:

This will probably work; it will read one character at a time till it finds the newline character (it depends on how the file is generated if it is '\n\ or '\r'). Once the '\n' is found, it's replaced by the nul character (so it's valid c-style string) and displayed.

void loop()
{
  static int index = 0;
  if (dataFile)
  {
    if (index >= sizeof(buff))
    {
      Serial.println("buffer overflow prevented; data discarded");
      index = 0;
    }

    if (dataFile.available())
    {
      // read a character and place in buffer
      buff[index] = dataFile.read();
      // if newline character
      if (buff[index] == '\n')
      {
        // replace with nul terminator
        buff[index] = '\0';
        // reset index
        index = 0;
        // display
        Serial.println(buff);
      }
      else
      {
        // for next read, character should be stored in next position
        index++;
      }
    }
  }
}

Note that it uses loop() to do the looping; for setup() you need to modify it a little :wink:

sterretje:
This will probably work; it will read one character at a time till it finds the newline character (it depends on how the file is generated if it is '\n\ or '\r'). Once the '\n' is found, it's replaced by the nul character (so it's valid c-style string) and displayed.

void loop()

{
 static int index = 0;
 if (dataFile)
 {
   if (index >= sizeof(buff))
   {
     Serial.println("buffer overflow prevented; data discarded");
     index = 0;
   }

if (dataFile.available())
   {
     // read a character and place in buffer
     buff[index] = dataFile.read();
     // if newline character
     if (buff[index] == '\n')
     {
       // replace with nul terminator
       buff[index] = '\0';
       // reset index
       index = 0;
       // display
       Serial.println(buff);
     }
     else
     {
       // for next read, character should be stored in next position
       index++;
     }
   }
 }
}



Note that it uses loop() to do the looping; for setup() you need to modify it a little ;)

Thanks for the help. I'm cooking a meal right now, and didn't have time to show how to retrieve each line.
As I said, I'm no expert, so there's probably a better method of parsing than using 'strstr()' followed by 'parseFloat()'(Edit: Silly mistake again.) 'strtof()', but it should work.
Back to the food.........

It works with:

#include <LFlash.h>
#include <LSD.h>
#include <LStorage.h>


#define Drv LFlash   

LFile dataFile;
char buff[50];
uint16_t nbyte=50;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Drv.begin();
  dataFile=Drv.open("Windach_bahnen.gpx", FILE_READ);
  char readline;
  String line="";
  if(dataFile){
    while(dataFile.available()){
      readline=dataFile.read();
      while(readline!='\n' && readline!='\r'){
        line+=readline;
        readline=dataFile.read();
      }
      Serial.println(line);
      line="";
  }
}
}

So now I just need to parse my string "line" at the points I want to :slight_smile: Thank you very much for your help. I appreciate it a lot.

btsens:
It works with:

#include <LFlash.h>

#include <LSD.h>
#include <LStorage.h>

#define Drv LFlash

LFile dataFile;
char buff[50];
uint16_t nbyte=50;

void setup() {
 // put your setup code here, to run once:
 Serial.begin(9600);
 Drv.begin();
 dataFile=Drv.open("Windach_bahnen.gpx", FILE_READ);
 char readline;
 String line="";
 if(dataFile){
   while(dataFile.available()){
     readline=dataFile.read();
     while(readline!='\n' && readline!='\r'){
       line+=readline;
       readline=dataFile.read();
     }
     Serial.println(line);
     line="";
 }
}
}




So now I just need to parse my string "line" at the points I want to :) Thank you very much for your help. I appreciate it a lot.

'I for got to add, 'strstr()' points to the first character of the search string, so you'll need to add the length of the search string to the returned pointer, to point at the first character of the float.
Oops, and 'parseFloat()' won't work on a string. I was rushing. You'll need to use 'strtof()'. Sorry. :-[

Edit: I just noticed you've changed to using the "String" class. The C string functions 'strstr()' and 'strtof()' won't work with that class. You're better to stick to C strings. Take a look at sterretje's suggestion. (No "String" class.)