XRAD'S How to get last line of SD data file? - c++

My SD data file does not have a set 'line' limit, nor does it have data of fixed lengths on each 'line.'
Is there a way to read the SD data file to the last 'line' AND then only Serial.print() just that last 'line'?
That last line of SD data is going to be used as the first 'home' coordinate in a GPS tracker if one was to continue a journey from last location.....
even if I add white space to make the first and second saved values XXXXXX (999999), I still am not sure how to find JUST the last line in an SD data file of an unknown length...(trying to keep the SD file as ONE file, not of fixed length)
//teensy 4.1 with BUILTIN_SDCARD
#include <SD.h>
File myFile;
String buffer;//buffer to redraw saved SD data
void lastLine()
{
//myFile = SD.open ("GPS", O_APPEND);
myFile = SD.open("GPS");
while (myFile.available()) {
if (myFile) {
buffer = myFile.readStringUntil('\n');
//either from the buffer or SD I would like to
//just read the last line of the file
Serial.println(buffer);
//Serial.println(myFile.size());
}
}
}
void setup()
{
Serial.begin(9600);
Serial.print("Initializing SD card...");
if (!SD.begin(BUILTIN_SDCARD)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");
// open the file.
myFile = SD.open("GPS", FILE_WRITE);
// if the file opened okay, write to it:
if (myFile) {
Serial.print("Writing to GPS...");
//GPS device / code continually writes data to SD
//but using this below for brevity/debugging
myFile.println("123, 144");//these stand for the x/y data values
myFile.println("1424, 254");//and the length of x/y may go as high
myFile.println("11235, 333");//as x= 999,999, y = 999,999 etc...
//etc..for hundreds/thousands of 'lines'
// close the file:
myFile.close();
Serial.println("done.");
}
lastLine();//just read the LAST line of SD data...
}
void loop()
{
// nothing happens after setup
}
EDIT: Thank you for ideas! OK ..so i tried your suggestions I think. I can get a counter going (first step) but it only increments to 20! I'm confused as to why/how this happens.....
here is my current code. Even though there are 50 'lines' in the SD file, I'm only reading 20 (get to sizeof())....IF I change the code to print ALL the lines to serial, it won't count lines....and IF there are LESS than 20 lines, serial monitor adds empty lines until '20' is reached..
and sizeof(myFile) is also 20..not sure why
//teensy 4.1 with BUILTIN_SDCARD
#include <SD.h>
File myFile;
int counter = 0;
String buffer;//buffer to redraw saved SD data
void lastLine()
{
//myFile = SD.open ("GPS", O_APPEND);
myFile = SD.open("GPS");
while (myFile.available()) {
for (int i = 0; i < sizeof(myFile); i++) {
String line = myFile.readStringUntil('\n');
buffer = myFile.readStringUntil('\n');
const char* listConv = line.c_str();
Serial.print ("line: ");
Serial.println (line);
counter ++;
}
if (counter == sizeof(myFile)) {
Serial.print ("Done. Counter: ");
Serial.println (counter);
Serial.print ("sizeof myFile: ");
Serial.println (sizeof(myFile));
myFile.close();
counter = 0;
}
}
}
//buffer = myFile.readStringUntil('\n');
//either from the buffer or SD I would like to
//just read the last line of the file
//Serial.println(buffer);
//Serial.println(myFile.size());
void setup()
{
Serial.begin(9600);
Serial.print("Initializing SD card...");
if (!SD.begin(BUILTIN_SDCARD)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");
// open the file.
myFile = SD.open("GPS", FILE_WRITE);
// if the file opened okay, write to it:
if (myFile) {
Serial.print("Writing to GPS...");
//GPS device / code continually writes data to SD
//but using this below for brevity/debugging
myFile.println("123, 144");//these stand for the x/y data values
myFile.println("1424, 254");//and the length of x/y may go as high
myFile.println("11235, 333");//as x= 999,999, y = 999,999 etc...
//etc..for hundreds/thousands of 'lines'
// close the file:
myFile.close();
Serial.println("done.");
}
lastLine();//just read the LAST line of SD data...
}
void loop()
{
// nothing happens after setup
}
ok so with some rewriting, I can now count to last file line using:
while (myFile.available()) {
for (int i = 0; i < sizeof(myFile.available()); i++) {
String line = myFile.readStringUntil('\n');
Serial.print ("line: ");
Serial.println (line);
counter ++;
Serial.print ("Counter: ");
Serial.println (counter);
if (counter == 400) {//testing different lines, works...
Serial.print ("Last Line: ");//prints the line at counter 'x'
Serial.println (line);
}
}
}
next step is to grab that last line after calculating the 'maximum' number of lines (minus a few that don't hold data I need at the end of the SD file).....

It was a bug in the library. conflict between SDFat, adafruit fork, and arduino SD. Had to delete all SD libs and reload....
working now...

Related

Alt, Course, and Speed not displaying on the LCD display

I wrote this code for my bike computer; however, the Alt, Course, and Speed are not displaying on the LCD display although it is on the Serial monitor. The GPS module isn't returning values either.
/* BaldwinOS by John Seong
An Open-Source Project
Version 1.0
*/
#include <SPI.h>
#include <SD.h>
#include <TinyGPS++.h> // Include the TinyGPS++ library
#include <Wire.h>
TinyGPSPlus tinyGPS; // Create a TinyGPSPlus object
#define ARDUINO_USD_CS 10 // uSD card CS pin (pin 10 on SparkFun GPS Logger Shield)
/////////////////////////
// Log File Defintions //
/////////////////////////
// Keep in mind, the SD library has max file name lengths of 8.3 - 8 char prefix,
// and a 3 char suffix.
// Our log files are called "gpslogXX.csv, so "gpslog99.csv" is our max file.
#define LOG_FILE_PREFIX "gpslog" // Name of the log file.
#define MAX_LOG_FILES 100 // Number of log files that can be made
#define LOG_FILE_SUFFIX "csv" // Suffix of the log file
char logFileName[13]; // Char string to store the log file name
// Data to be logged:
#define LOG_COLUMN_COUNT 8
char * log_col_names[LOG_COLUMN_COUNT] = {
"longitude", "latitude", "altitude", "speed", "course", "date", "time", "satellites"
}; // log_col_names is printed at the top of the file.
//////////////////////
// Log Rate Control //
//////////////////////
#define LOG_RATE 5000 // Log every 5 seconds
unsigned long lastLog = 0; // Global var to keep of last time we logged
#define GPS_BAUD 9600 // GPS module baud rate. GP3906 defaults to 9600.
#define SerLCD_Address 0x72
#include <SoftwareSerial.h>
#define ARDUINO_GPS_RX 9 // GPS TX, Arduino RX pin
#define ARDUINO_GPS_TX 8 // GPS RX, Arduino TX pin
SoftwareSerial ssGPS(ARDUINO_GPS_TX, ARDUINO_GPS_RX); // Create a SoftwareSerial
#define gpsPort ssGPS
#define SerialMonitor Serial
const int statusLED = 9;
const int blueLeftLED = 8;
const int redLeftLED = 7;
const int blueRightLED = 0;
const int redRightLED = 3;
const int leftButton = A3;
const int rightButton = 11;
const int modeButton = 12;
const int buzzer = 13;
void setup() {
SerialMonitor.begin(9600);
gpsPort.begin(GPS_BAUD);
SerialMonitor.println("Setting up SD card.");
// see if the card is present and can be initialized:
if (!SD.begin(ARDUINO_USD_CS))
{
SerialMonitor.println("Error initializing SD card.");
}
updateFileName(); // Each time we start, create a new file, increment the number
printHeader(); // Print a header at the top of the new file
Wire.begin();
Wire.setClock(400000);
Wire.beginTransmission(SerLCD_Address);
Wire.write('|'); // Put LCD into setting mode
Wire.write('-'); // Send clear display command
Wire.write('|'); // Put LCD into setting mode
Wire.write('+'); // Send the Set RGB command
Wire.write(0xFF); // Send the red value
Wire.write(0x00); // Send the green value
Wire.write(0x00); // Send the blue value
Wire.println("Welcome to");
Wire.print("BaldwinOS!");
Wire.endTransmission();
delay(2000);
}
void loop() {
Wire.beginTransmission(SerLCD_Address);
Wire.write('|'); // Put LCD into setting mode
Wire.write('-'); // Send clear display command
Wire.println("Pathfinder");
Wire.print("Bike Computer");
if ((lastLog + LOG_RATE) <= millis())
{ // If it's been LOG_RATE milliseconds since the last log:
if (tinyGPS.location.isUpdated()) // If the GPS data is vaild
{
if (logGPSData()) // Log the GPS data
{
SerialMonitor.println("GPS logged."); // Print a debug message
lastLog = millis(); // Update the lastLog variable
}
else // If we failed to log GPS
{ // Print an error, don't update lastLog
SerialMonitor.println("Failed to log new GPS data.");
}
}
else // If GPS data isn't valid
{
// Print a debug message. Maybe we don't have enough satellites yet.
SerialMonitor.print("No GPS data. Sats: ");
SerialMonitor.println(tinyGPS.satellites.value());
}
}
printStats1();
smartDelay(1000);
}
byte logGPSData()
{
File logFile = SD.open(logFileName, FILE_WRITE); // Open the log file
if (logFile)
{ // Print longitude, latitude, altitude (in feet), speed (in mph), course
// in (degrees), date, time, and number of satellites.
logFile.print(tinyGPS.location.lng(), 6);
logFile.print(',');
logFile.print(tinyGPS.location.lat(), 6);
logFile.print(',');
logFile.print(tinyGPS.altitude.feet(), 1);
logFile.print(',');
logFile.print(tinyGPS.speed.mph(), 1);
logFile.print(',');
logFile.print(tinyGPS.course.deg(), 1);
logFile.print(',');
logFile.print(tinyGPS.date.value());
logFile.print(',');
logFile.print(tinyGPS.time.value());
logFile.print(',');
logFile.print(tinyGPS.satellites.value());
logFile.println();
logFile.close();
return 1; // Return success
}
return 0; // If we failed to open the file, return fail
}
void printHeader()
{
File logFile = SD.open(logFileName, FILE_WRITE); // Open the log file
if (logFile) // If the log file opened, print our column names to the file
{
int i = 0;
for (; i < LOG_COLUMN_COUNT; i++)
{
logFile.print(log_col_names[i]);
if (i < LOG_COLUMN_COUNT - 1) // If it's anything but the last column
logFile.print(','); // print a comma
else // If it's the last column
logFile.println(); // print a new line
}
logFile.close(); // close the file
}
}
// updateFileName() - Looks through the log files already present on a card,
// and creates a new file with an incremented file index.
void updateFileName()
{
int i = 0;
for (; i < MAX_LOG_FILES; i++)
{
memset(logFileName, 0, strlen(logFileName)); // Clear logFileName string
// Set logFileName to "gpslogXX.csv":
sprintf(logFileName, "%s%d.%s", LOG_FILE_PREFIX, i, LOG_FILE_SUFFIX);
if (!SD.exists(logFileName)) // If a file doesn't exist
{
break; // Break out of this loop. We found our index
}
else // Otherwise:
{
SerialMonitor.print(logFileName);
SerialMonitor.println(" exists"); // Print a debug statement
}
}
SerialMonitor.print("File name: ");
SerialMonitor.println(logFileName); // Debug print the file name
}
void printStats1() {
Wire.beginTransmission(SerLCD_Address);
Wire.write('|'); // Put LCD into setting mode
Wire.write('-'); // Send clear display command
Wire.print("Alt: "); Wire.print(tinyGPS.altitude.feet());
Wire.print(" Course: "); Wire.println(tinyGPS.course.deg());
Wire.print("Speed: "); Wire.println(tinyGPS.speed.mph());
Serial.print("Alt: "); SerialMonitor.println(tinyGPS.altitude.feet());
Serial.print("Course: "); SerialMonitor.println(tinyGPS.course.deg());
Serial.print("Speed: "); SerialMonitor.println(tinyGPS.speed.mph());
}
static void smartDelay(unsigned long ms)
{
unsigned long start = millis();
do
{
// If data has come in from the GPS module
while (gpsPort.available())
tinyGPS.encode(gpsPort.read()); // Send it to the encode function
// tinyGPS.encode(char) continues to "load" the tinGPS object with new
// data coming in from the GPS module. As full NMEA strings begin to come in
// the tinyGPS library will be able to start parsing them for pertinent info
} while (millis() - start < ms);
}
If you are using a passive GPS antenna, you should test it outside (or in an open window pointing the antenna to the sky) to get the satellite fix. TinyGPS lib won't give you back any data if you don't have the fix value

How to create a function: Get a single value from SD card file using the file name as function parameter

I appreciate any guidance or help I can get on this. I am writing a program with values for a PID stored on an SD card so I can change them on the touchscreen without the need to hook it up to my computer. I want a single function that I can call with parameters allowing me to increase or decrease the number and change the file name. The below function is what I have to change whether "pnum.txt" increases or decreases; however I cannot figure out how to make a File work as a parameter.
I have tried making " "pnum.txt" " (with quotes) as a char and as a String, and even though it prints out as it should, it doesn't work when inserted into the function. I have also tried passing the whole SD.open("pnum.txt", FILE_WRITE) and myFile = SD.open("pnum.txt", FILE_WRITE) as a File, but that does something odd - it will create the file when I open it, but it won't write to the file. I'm finding myself just trying the same things over and over, so I clearly have a lack of understanding that I'm not finding anywhere. Thank you again for any help on this!
float incDecValue(float value) {
//This is important, because the libraries are sharing pins
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
value;
SD.remove("pnum.txt");
myFile = SD.open("pnum.txt", FILE_WRITE);
myFile.print(value);
myFile.close();
counter = 0;
myFile = SD.open("pnum.txt");
if (myFile) {
while (myFile.available()) {
testChar[counter] = myFile.read();
counter++;
}
myFile.close();
}
float convertedValue = atof(testChar);
return convertedValue;
}
And I will call it like this.
pValue = incValue(pValue+=.5);
As not exactly knowing what you really want I did the following assumptions:
You want to save a single float value to a file called pnum.txt
You want to do something with that value
You want the processed value to write back to the file pnum.txt (overwriting the content)
Two different functions parametrized each with fileName as input and the value for write
So here a complete sequence (works as posted) you could easily implement into your code. No String class is used and its a one line file read/write only:
/* SD card pid read/write
The circuit:
SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4 */
#include <SPI.h>
#include <SD.h>
const uint8_t chipSelect = 4;
char dataChar[16] = {'\0'};
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect.
}
Serial.print("Initializing SD card...");
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed or no card present");
return;
}
Serial.println("Card initialized");
}
void loop() {
float pValue = readFileValue ("pnum.txt") + 0.5;
writeFileValue ("pnum.txt", pValue);
}
float readFileValue (const char* fileName) {
/* Open the file. note that only one file can be open at a time,
so you have to close this one before opening another.*/
File dataFile = SD.open(fileName, FILE_READ);
// if the file is available, write to it:
if (dataFile) {
char c;
uint8_t i = 0;
while (dataFile.available()) {
c = dataFile.read(); // Read char by char
if (c != '\n') { // As long no line terminator
dataChar[i] = c;
i++;
}
else {
dataChar[i] = '\0'; // Terminate char array properly
dataFile.close();
break;
}
}
Serial.print("Success writing content: ");
Serial.println(dataChar);
}
else { // If the file isn't open, pop up an error:
Serial.print("Error opening requested file: ");
Serial.println(fileName);
}
float fileVal = atof(dataChar);;
return fileVal;
}
bool writeFileValue (const char* fileName, float fileVal) {
SD.remove(fileName); // Delete the existing file if existing
File dataFile = SD.open(fileName, FILE_WRITE);
// If the file opened okay, write to it
if (dataFile) {
// dtostrf(floatvar, StringLengthIncDecimalPoint, numVarsAfterDecimal, charbuf);
dtostrf(fileVal, 5, 2, dataChar); // Not really needed for this simple issue, but ..
Serial.print("Writing to file: ");
Serial.println(fileName);
dataFile.println(dataChar);
// Close the file
dataFile.close();
Serial.println("Success saving done");
return true;
} else {
// if the file didn't open, print an error:
Serial.println("Error opening file: ");
Serial.println(fileName);
return false;
}
}

Arduino: How to show Serial.print value to any textbox or Notepad

So I saw an Arduino program that will show an RFID value to the serial monitor, I just want to know how can I also show it to any textbox or Notepad or wherever. For example, I opened a Notepad or Word, when I swiped the RFID keychain, it suppose to show the value there. Here's the code I got:
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 9
#define SS_PIN 10
MFRC522 mfrc522(SS_PIN, RST_PIN);
void setup()
{
Serial.begin(9600);
SPI.begin();
mfrc522.PCD_Init();
pinMode(7, OUTPUT);
}
void loop() {
RfidScan();
}
void dump_byte_array(byte *buffer, byte bufferSize) {
for (byte i = 0; i < bufferSize; i++) {
Serial.print(buffer[i] < 0x10 ? "0" : ""); // The value I want to show
Serial.print(buffer[i], HEX);
}
digitalWrite(7, HIGH);
delay(100);
digitalWrite(7, LOW);
delay(1000);
Serial.print("\n");
}
void RfidScan()
{
if ( ! mfrc522.PICC_IsNewCardPresent())
return;
if ( ! mfrc522.PICC_ReadCardSerial())
return;
dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
}
You can use stty.
Here's a sample :
stty -F /dev/my_serial_port <baud_rate> cs8 cread clocal > filename
Here you redirect all the output from the serial port to a file. To print out the contents as they come in you can use
tail -f filename
There are multiple ways to do this .using a 3rd party tool will be easy to get the serial output. or else you can try following link. I have explained what you need to do.
Try This
Follow this link
What you need is PrintWriter.
Import PrintWriter :
PrintWriter output;
Instantiate output object in the setup() method :
output = createWriter( "data.txt" );
Writes the data to text file
output.println( value );
This "value" data can be retrieved from serial
String value = serial.readString();
Finally flush the data and close the file.
output.flush(); // Writes the remaining data to the file
output.close(); // Finishes the file

Arduino: AT Commands - Read the last line of the serial output using Serial.read()

I constantly pass AT commands to get GSM Signal Strength
My code copies the entire serial output
Kindly advise how to read the latest serial output (last line)
find the output below, in which i need to assign the output from last line (21,0) to the variable "signal"
My Output:
AT
OK
AT+CREG?
+CREG: 0,1
ok
AT+CSQ
+CSQ: 21,0
My code:
byte gsmDriverPin[3] = {
3,4,5};
char signal[10];
char inChar;
int index;
char inData[200];
void setup()
{
//Init the driver pins for GSM function
for(int i = 0 ; i < 3; i++){
pinMode(gsmDriverPin[i],OUTPUT);
}
digitalWrite(5,HIGH);//Output GSM Timing
delay(1500);
digitalWrite(5,LOW);
digitalWrite(3,LOW);//Enable the GSM mode
digitalWrite(4,HIGH);//Disable the GPS mode
delay(2000);
Serial.begin(9600); //set the baud rate
delay(5000);//call ready
delay(5000);
delay(5000);
start_GSM();
}
void loop()
{
Signal_Strength();
Serial.println("AT+CMGF=1");
delay(1000);
Serial.println("AT+CMGS=\"1234567890\"");//Change the receiver phone number
delay(1000);
Serial.println(signal);
delay(1000);
Serial.write(26);
}
void Signal_Strength(){
Serial.println("AT+CSQ");
delay(2000);
read_String();
strtok(inData, ",");
strcpy(signal,strtok(NULL, ","));
}
void read_String() {
index=0;
while(Serial.available() > 0) // Don't read unless
// there you know there is data
{
if(index < 199) // One less than the size of the array
{
inChar = Serial.read(); // Read a character
inData[index] = inChar; // Store it
index++; // Increment where to write next
inData[index] = '\0'; // Null terminate the string
}
}
}
void start_GSM(){
//Configuracion GPRS Claro Argentina
Serial.println("AT");
delay(2000);
Serial.println("AT+CREG?");
delay(2000);
}
First of all, you must seriously redo your AT command handling to
Read and parse the every single response line given back from the modem until you get a final result code. This applies for every single command line invocation, no exceptions whatsoever. See this answer for more details.
Never ever call delay in any code that handles AT commands. See this answer for more details about the risk of aborting the next command.
Before fixing these fundamental issues you cannot expect any successful behaviour. Parsing AT command responses is not that complicated, have a look at the source code for atinout for an example.

Using SD.remove() and SD library in Arduino

I'm building a program which takes 10 measurements of an analog voltage on pin0 and is printing it to a log file. The issue I'm running into comes when I try to ensure that the file is blank. I am using SD.remove() in order to remove a previous logfile. When I do this, the new log file is never actually written to. When I remove the call to SD.remove(), the program works correctly. Is this some known bug in the SD library or is there some sneaky way around this?
The code is below.
#include <SD.h>
#define OUTPUT_PIN 9 //Using SparkFun MP3 shield
#define DEFAULT_OUTPUT 10
#define VOLTAGE_REF (5)
//Reads a voltage on pin0. by default, the reference voltage is set to 5 V, but
//it can be changed by changing VOLTAGE_REF.
void setup() {
Serial.begin(9600);
Serial.println("Program Initialized");
pinMode(DEFAULT_OUTPUT ,OUTPUT); //Needs to be on to use the library
pinMode(0, INPUT);
if (!SD.begin(OUTPUT_PIN)) {
//init error
Serial.println("Error initializing SD card. Reset the Arduino and try again");
return;
}
Serial.println("Card sucessfully initialized");
if (SD.exists("LOGFILE.LOG") {
SD.remove("LOGFILE.LOG"); //We don't want to use the same file <<THIS IS THE BUG?
}
delay(10); //Make sure changes are applied
File logFile = SD.open("ANALOG.LOG", FILE_WRITE); //Create a new one every time
if (!SD.exists("LOGFILE.LOG")) {
Serial.println("There was some error making a new instance of the logfile?");
delay(1000);
SD.open("ANALOG.LOG", FILE_WRITE);
}
int i;
if (logFile) {
for(i=0;i<10;i++) {
int j = 0;
char str[64];
Serial.print("Reading analog sensor value");
for(j=0;j<=i;j++) {
Serial.print(".");
}
Serial.println();
logFile.print("Read #");
logFile.print(i+1);
logFile.print(" : ");
logFile.print(doVoltageRead(0));
unsigned char l = logFile.println(" V");
if (!l)
Serial.println("No data written");
delay(500);
}
Serial.println("Done.");
logFile.close(); //Close the logfile
Serial.println("Data sucessfully written");
}
else {
//Couldn't create file
Serial.println("There was an error creating the logfile");
}
}
void loop() {
//We don't really need to do anything here
}
float doVoltageRead(int pin) {
int voltageRead = analogRead(pin);
double divisor = (voltageRead * 0.00097752);
float finalVoltage =(VOLTAGE_REF * divisor);
Serial.println(finalVoltage);
return finalVoltage;
}
So.. First you see if LOGFILE.LOG exists, if it does you delete ANALOG.LOG. Then you create ANALOG.LOG. After that you check if LOGFILE.LOG exists. If it doesn't, you print an error and open ANALOG.LOG.
What exactly is the purpose of LOGFILE.LOG? Shouldn't you just change LOGFILE to ANALOG?
I have found the source of the error. When I called if(SD.exists()) after opening a new logfile, the library didn't like that. I am assuming SD.exists() just checks if the address or object returned by open is NULL. However, calling it when the file is already open would cause some strange behaviors. After removing that call inside open, all is well. Thanks for all the suggestions!