I'm trying to display a quote (which can be very long/200+ chars) from a text file on an SD card onto an LED matrix. The quote is stored in a text file in pieces that are 100 characters long (I wrote a program that can modify the length, in characters, of each piece. Here is the format of that text file:
For a single quote:
Piece 1\r/n\0
Piece 2\r\n\0
...
Piece x\r\n\0(EOF)
x varies, depending on how long the quote is. However, each piece is of the same length. (Don't worry about remainders in cases where quotes don't break up evenly. Assume they are of the same length.)
In some cases 2 pieces may read like this:
"Strength of mind rests in sobriety for this keeps reason unclouded by passion. - Pythagoras"
And may be formatted in a text file like this:
"Strength of mind rests\r\n\0"
" in sobriety for this ke\r\n\0"
"eeps reason unclouded\r\n\0"
"by passion. - Pythagor\r\n\0"
"as_________________\r\n\0"
Each line is is stored in a character array and I would like to use Parola to display each string one immediately after the other. Is this possible?
Here is the code and text file, in case you want to work with it. Note that you need an SD card/Micro SD card, and the "U_QUOTES.txt". The code will generate a file called Q_Cached.txt":
/*
* QuotesEditorV2
* QuotesEditor.ino successfully retrieved a quote from a .txt file located on SD but storing the quote as
* a char string on the arduino's SRAM was impractical due to memory constraint. Teddy Roosevelt's quote
* (767 char) took up nearly 40% of RAM mem.
*
* QuotesEditorV2.ino solves the issue of SRAM memory constraint by leveraging the size of SD memory (~32GB).
* Instead of retrieving and storing to SRAM, we retrieve the quote in its entirety from a .txt file,
* store it in an easily read format in another .txt file in SD memory, and read from that .txt file when
* we want to display something. Effectively, we use SD memory to store what we would have stored in SRAM.
*
* Since memory is offchip, a shortcoming of this technique is that we increase memory access time.
* Also, this technique requires the ability to open multiple files simultaneusly. If this isn't possible
* (which might be the case since the Arduino does't have much RAM), we will require a small amount of SRAM
* to store data temporarily while we transfer a selected, reformatted quote. The size of SRAM needed for transfer
* should equal the size allocated to the data structure used with the Parola library functions to display
* a string.
* Notes:
* 1. When the enter key is used in a text document, on a windows machine a \r (carriage return)
* and \n (newline) pair is inserted. At the end of a file, an EOF character is inserted.
* e.g., abcdefg\r\n
* 2. If the string is to be printed using print() or write(), it must be terminated using \0 character
* otherwise, the string to be printed will be printed with junk postfixed.
* e.g., Serial.print("abcdefg\r\n"); gives the output "abcdefgXX" where XX is junk
* e.g., Serial.print("abcdefg\r\n\0"); gives the expected output
*/
#include <string.h>
#include <SPI.h>
#include <SD.h>
#define TRANSFER_SIZE 100 //How many characters per transfer
#define QUOTE_NUM 3 //Which quote to select
int findQuoteStart(char src[], int targetQuote){
File file;
char newChar;
int numEndlines = 0;
int quote_startPosition = 0;
int quote_Index = (targetQuote*2)-2; //Number of endlines BEFORE the target quote begins
file = SD.open(src, FILE_READ);
if(file){
while((numEndlines <= quote_Index) && (numEndlines != quote_Index)){
newChar = file.read();
if(newChar == '\n'){
numEndlines++;
}
quote_startPosition++; //Update where we are in the document
}
}else{Serial.println("ERROR: Failed to open file to find quote start.");}
file.close();
return quote_startPosition;
}
int findQuoteSize(char src[], int startPos){
int i = 0;
char newChar;
int numEndlines = 0;
int quoteSize = 0; //Includes \r,\n,
File file;
file = SD.open(src, FILE_READ);
file.seek(startPos); //Position cursor at start of quote
if(file){
while((numEndlines <= 2) && (numEndlines != 2)){
newChar = file.read();
if(newChar == '\n'){
numEndlines++;
}
quoteSize++;
}
}else{Serial.println("ERROR: Failed to open file to find quote size.");}
file.close();
return quoteSize;
}
bool transferPiece(char src[], char newFile[], int startPos, int transferSize){
File file;
char quotePiece[transferSize+3]; //Terminate each line in new text file with: \r\n
int endlineReached=0; //If 1, write \0 to quotePieces[] that have yet been populated
int eofReached=0; //If 1, write \0 to quotePiecesp[ that have yet been populated
int writeCounter=0;
//Read from quotes text file
file = SD.open(src,FILE_READ);
if(file){
char newChar;
file.seek(startPos); //Go to where quote was left off
quotePiece[transferSize] = '\r';
quotePiece[transferSize+1] = '\n';
quotePiece[transferSize+2] = '\0'; //Needed for print() functions
while(writeCounter<transferSize){
if((writeCounter<transferSize) && !eofReached && !endlineReached)
newChar = file.read(); //Don't get new character if endline or eof reached
switch(newChar){
case 'EOF': //End of file reached
eofReached=1;
break;
case '\r': //Carriage return reached
endlineReached=1;
case '\n': //End of quote reached
endlineReached=1;
default:
if(!endlineReached && !eofReached){
quotePiece[writeCounter] = newChar;
writeCounter++;
}else{
quotePiece[writeCounter] = '_';
writeCounter++;
}
break;
}
if((endlineReached || eofReached) && (writeCounter==transferSize))
break;
}
//Serial.write(quotePiece);
file.close();
}else{Serial.println("Error: Could not transfer quote piece. Cache file doesn't exist");}
//Write to the new file
file = SD.open(newFile, FILE_WRITE);
if(file){
file.seek(file.size()); //go to the end of the file
file.write(quotePiece);
file.write('\r\n'); //???? quotePiece should have a newline
file.close();
}else{Serial.println("Error: Could not write substring of a quote to new text file");}
return 0;
}
void transferQuote(char txtFile[], int quoteIndex, int strLength){
if(quoteIndex>0){
int quote_StartPosition = findQuoteStart(txtFile, quoteIndex);
int quote_Size = findQuoteSize(txtFile, quote_StartPosition); //In Bytes
int numberPieces = (quote_Size/strLength)+1; //Number of lines in the new text file
//Transfer Quotes{
for(int i=0; i<numberPieces; i++){
transferPiece("U_Quotes.txt","Q_Cached.txt", quote_StartPosition+i*strLength, strLength);
}
}else{Serial.println("Quote Transfer Failure: quoteIndex is less than or equal to 0!");}
}
void setup() {
Serial.begin(9600);
//INITIATE SD
//pinMode(10, OUTPUT); //SPI Requirement -- NOT NEEDED FOR SOME REASON?INCLUSION CAUSES CRASH
if(SD.begin(4) == true){Serial.println("SD init success"); Serial.println();}
else if(SD.begin(4) == false){Serial.println("SD init failure"); Serial.println();}
//Delete old, create new text file
File file;
if(SD.exists("Q_Cached.txt")) //Delete old cached file if it exists
{
Serial.println("Q_Cache exists. Removing it now.");
SD.remove("Q_Cached.txt");
}
file = SD.open("Q_Cached.txt", FILE_WRITE); //Make new text file
file.close();
Serial.println("Done deleting old, creating new");
//Transfer the quote of interest to a new file
transferQuote("U_Quotes.txt", QUOTE_NUM, TRANSFER_SIZE);
}
void loop() {}
U_QUOTES.txt (5.3 KB)