Hello,
Microcontroller: Uno
Platform: PlatformIO / VSCode
Skill Level: Beginner + 50 hours of trail and error and Googling
Hopefully my terminology in the title makes sense and let me know if there's a better or more searchable title.
I'm attempting to make a class called CookBook which inherits from the "File" class in the Adafruit SD library. I'm stuck at the point where I need to open the file. If it wanted to do this in main.cpp it looks something like...
File file;
void setup()
{
// Initialize the SD.
if (!SD.begin(csPin)) {
Serial.println(F("Could not initialize SD card. Try reinserting or restarting."));
while(1);
}
// Open the file
file = SD.open("CookBook.csv", FILE_READ);
if (!file) {
Serial.println(F("Could not open the Cook Book. Make sure it is named \"CookBook\" and is a .csv."));
return;
}
}
However, this can't be copy pasted into the Constructor of my CookBook class because when you get to this part...
file = SD.open("CookBook.csv", FILE_READ);
the "identifier "file" is undefined."
How can I open the file within the constructor of my CookBook class?
And bonus question if anyone is feeling helpful, what's happening under the hood with class inheritance? I think a File object is effectively being created when I create and object of my derived class, CookBook. And does an SD object also get created? Why do I have to do SD.begin(), but I can't do File.avalable()?
Thank you for any help. I really appreciate it.
Here's the entire CookBook.cpp file for the class. Note that it's not finished so there may be some weird comments in there.
#include <Arduino.h>
#include "CookBook.h"
CookBook::CookBook(byte csPin) : File()
{
// Initialize the SD card
if (!SD.begin(csPin))
{
Serial.println(F("Could not initialize the SD card."));
}
// Open the file
file = SD.open("CookBook.csv", FILE_READ);
if (!file)
{
Serial.println(F("Could not open the Cook Book. Make sure it is named \"CookBook\" and is a .csv."));
return;
}
}
//////////////////////////////////////////////////////////////////////////////////////////
bool CookBook::skipToLine(unsigned int lineNumber)
{
for (unsigned int i=0; i<lineNumber; i++)
{
// Read until delimeter and place the cursor after it
readStringUntil('\n');
// Error check - Did we skip past all the data?
if (available() == 0)
{
Serial.println(F("Error: Skipped to the end of the file. Either no end line was found or the lineNumber > the number of lines"));
return 0;
}
return 1;
}
}
// //////////////////////////////////////////////////////////////////////////////////////////
unsigned int* CookBook::readIngredients(byte arraySize, unsigned int recipeIdx)
{
unsigned int ingredientArray[arraySize];
byte arrayIdx = 0; // Iterator for output ingredient array
bool endl = false; // Flag to tell the loop to stop iterating if the end of a line is reached
String element = ""; // String to store succesive characters until parsing
char ch; // Temp variable to store individual characters read from the csv
while (!endl) // loop until we hit the end of the line
{
// If we've reached the end of the file, parse then stop looping
// Note: Check before reading the next character otherwise the loop will exit before parsing the last character
if (available() == 0) {endl = true;}
// Read the next character
ch = read();
// DEBUG // Serial.print("The current ch: "); Serial.print((int)ch); Serial.print(" and there are this many characters left to read: "); Serial.println(file.available());
// If it's the end of a line or carrage return, parse then stop looping
if (ch == '\n' || ch == '\r') {endl = true;}
// Comma or end of the line... so we want to save or ignore it depending on what it is
if (ch == ',' || endl)
{
// If the string to int conversion fails, it's not an int (it's a letter or something else)
// Get rid of the string because we only want to read ingredients which are integers
if (!element.toInt())
{
// DEBUG // Serial.println("Deleted the string because it wasn't just integers.");
element = "";
}
// The string is made of integers
else
{
// DEBUG // Serial.print("Saved a string as the fallowing int: "); Serial.println(element);
ingredientArray[arrayIdx] = element.toInt(); // Store string as int
element = ""; // Clear the string
arrayIdx++;
}
continue; // Go to the next loop iteration without saving the escape character to the string
}
// Non-reasonable characters
if (ch > 122 || ch < 48) // Less than ASCII "0" and greater than ASCII "z"
{
// DEBUG // Serial.println("Found an unreasonable character (not a number or letter). Skipping.");
}
// If no other criteria are met
element += ch;
}
close();
// Warning: Empty Array/Blank File
if (ingredientArray[0] == 0) {Serial.println(F("Warning: The recipe seems to have no ingredients."));}
return ingredientArray;
}
And here's the header file if it's relevant.
#ifndef CookBook_header
#define CookBook_header
#include <Arduino.h>
#include <SPI.h>
#include <SD.h>
class CookBook : private File
{
public:
// Constructor
CookBook(byte csPin);
unsigned int* readIngredients(byte arraySize, unsigned int recipeIdx);
//byte* readRecipes();
private:
// Assumes a row, or line, ends with \n so fcn sets the cursor after "lineNumber" \n's
// \input lineNumber - an integer value
// \output - bool: 1 if successful, 0 if error
bool skipToLine(unsigned int lineNumber);
};
#endif