Here is the latest version of LCDfontManager:
/*-------------------------------------------------------*/
/* LCDfontManager() - Liquid Crstal Display Font Manager */
/*-------------------------------------------------------*/
void LCDfontManager() {
//Serial.begin(9600);
bool fontEncoded = true;
String merged_lcdString= "";
char CC_char_id[3] = {" "};
// BEGIN FONT PROCESSING...
// ==[1]====================
// SCAN lcdString TO DETECT PRESENCE OF '|' FONT-ENCODING MARKERS...
int8_t marker_idx = lcdString.indexOf('|');
if (marker_idx == -1) fontEncoded = false; // If lcdString is plain text, print it more-or-less directly...
// ==[2]====================
// PERFORM AN INTERLEAVE MERGE OF fontChar & fontFlag SECTIONS OF lcdString, EXCLUDING THE '|' MARKER.
// (e.g., "LR DoobyoD| ll bBB LBb" --> "LlRl DboBoBb yLoBDb"). This also processes the top row of
// double-row symbols (e.g., "Test|b CASE|bbbb|" --> "Tbe s t "):
// %%%%% The setupRow2() function allows the second row of a double-row
// symbol to be processed by LCDfontManager as a pseudo-first row.
// The font-encoding test cases give several examples of this.
if (fontEncoded == true) {
merged_lcdString = "";
for (uint8_t i = 0; i < marker_idx; i++) {
merged_lcdString += lcdString.charAt(i);
merged_lcdString += lcdString.charAt(marker_idx + 1 + i);
}
}
else { // if lcdString isn't font-encoded, treat as plain text...
merged_lcdString = "";
for (uint8_t i = 0; i < lcdString.length(); i++) merged_lcdString += (lcdString.charAt(i) + String(" "));
in_CC_id_table = false;
}
// ==[3]====================
// TO MAXIMIZE THE EIGHT-CC CGRAM RESOURCE, WE NOW NEED TO CLEAN UP THE CC_id_table, REMOVING ANY TABLE
// ENTRIES THAT WILL BE OVERWRITTEN BY CCs IN THE NEW lcdString, BUT DON'T EXIST ELSEWHERE IN screenImage...
int16_t mystartPos;
mystartPos = startPos << 1;
uint8_t scrn_ptr = mystartPos;
while (scrn_ptr < (mystartPos + merged_lcdString.length())) {
uint8_t fontByte = screenImage.charAt(scrn_ptr);
// Overwrite the character before checking if it exists elsewhere in screenImage:
screenImage.setCharAt(scrn_ptr, ' '); // (david_2018 patch 9/26/2024)
if ((fontByte >= 0x08) && (fontByte <= 0x0f) && (screenImage.indexOf(fontByte) == -1)) CC_id_table[fontByte - 8] = "";
scrn_ptr += 2;
}
screenImage = screenImage.substring(0, mystartPos) + merged_lcdString + screenImage.substring((mystartPos) + merged_lcdString.length());
// ==[4]====================
// BEGIN A LONG LOOP, PROCESSING THE MERGED LCDSTRING INTO SCREENIMAGE AT STARTPOS, LOADING CC
// BITMAPS INTO THE CGRAM, FLAGGING FONT ERRORS AND ANY CGRAM OVERFLOW (@ and # errors, respectively).
// Parse screenImage for CC flags, loading the CC bitmaps to the LCD chip, also replacing fontChars
// in screenImage with CGRAM_ptrs. Processed CCs have the fontChar part replaced with a byte between 0x08
// and 0x0f, and the fontFlag part with " ". Subtracting 8 from the 0x08-0x0f byte gives the 0-7 location
// of the CC in the CC_id_table. This offset of 8 avoids problems caused by ASCII null characters (0x00),
// related to the use of \0 as an end-of-string marker in C and C++.
scrn_ptr = startPos; // Lines 60-71 rewritten. Also see comment on line 79.
while (scrn_ptr < 40) {
uint16_t even_scrn_ptr = scrn_ptr << 1;
String current_CC_id = screenImage.substring(even_scrn_ptr,even_scrn_ptr+2);
current_CC_id.toCharArray(CC_char_id,3);
const char fontChar = CC_char_id[0];
const char fontFlag = CC_char_id[1];
// %%%%% If the current fontChar has a non-blank fontFlag, we assume that it must be an unprocessed CC...
// (There are two types of CCs: Those that are in the cc_id_table and those that are not.)
if (CC_char_id[1] != ' ') {
uint8_t* gBitmap = getBitmap(fontChar, fontFlag); //revised
if (gBitmap) {
// Type (A) --- Those that already have a bitmap in CGRAM and are in the CC_id_table:
// For these we replace all instances of it in screenImage with the index of the current_CC_id in the CC_id_table (0x08-0x0f + " ")...
in_CC_id_table = false; // initial assumption is that current_CC_id is not in CC_id_table
for (CGRAM_ptr = 0; CGRAM_ptr < 8; CGRAM_ptr++)
if (CC_id_table[CGRAM_ptr] == current_CC_id) { // E.g., if CC_id_table[0-7] == "ql", then...
in_CC_id_table = true; // ...set in_CC_id_table to true, and replace all instances of current_CC_id:
screenImage.replace(current_CC_id, String(char(CGRAM_ptr + 0x08)) + String(" ")); // We need to rewrite replace to use only even byte boundaries!
}
// Type (B) --- Those that have no bitmap and are not in the CC_id_table:
// IF the current_CC_id is not already in the CC_id_table, save it to a free location in the table, and then replace
// all instances of it in screenImage with the index of the current_CC_id in the CC_id_table (0x08-0x0f + " " )...
if (in_CC_id_table == false) {
// Locate 1st free location in CC_id_table:
CGRAM_ptr = 0; while ((CGRAM_ptr < 8) && (CC_id_table[CGRAM_ptr] != "")) CGRAM_ptr++;
// If CC_id_table has a free location, save the current_CC_id there,
// load the bitmap into CGRAM, and replace all instances in screenImage with (CGRAM_ptr + 0x08) + " ":
if (CGRAM_ptr < 8) {
CC_id_table[CGRAM_ptr] = current_CC_id; // CC_id format is, e.g., "ql"
lcd.createChar((CGRAM_ptr + 0x08), gBitmap); // Load bitmap into the LCD chip's CGRAM
in_CC_id_table = true; // Set in == true, and then replace all instances of current_CC_id in...
screenImage.replace(current_CC_id, String(char(CGRAM_ptr + 0x08)) + String(" ")); // ...screenImage with (CGRAM_ptr + 0x08) + " "
}
// If the CC_id_table is full (due to all eight CCGRAM locations being in use),
// signal CGRAM overflow by replacing all instances of the current_CC_id in screenImage with "# ":
if (CGRAM_ptr == 8) screenImage.replace(current_CC_id, String("# "));
}
}
// IF the current bitmap is not found (due to the char/font combination being missing or incorrect),
// signal a Char/Font Error by replacing all instances of the current_CC_id in screenImage with "@ ":
else screenImage.replace(current_CC_id, String("@ "));
}
// %%%%% CC_ids ignored by the above font processing include the following:
// Plain-text characters in font-formatted Strings, e.g., "a ";
// Characters in plain-text Strings e.g., "Plain Text!";
// Processed CCs, e.g. String(char(0x0a) + String(" ");
// The "@ " (bad char/font), and "# " (CGRAM overflow) error flags.
//
scrn_ptr += 1; // Loop back to beginning to process the next CC_id in screenImage...
}
// ==[5]====================
// FINALLY, PRINT ALL EVEN CHARACTERS IN screenImage 0,2,4,6,..., TO THE LCD:
lcd.setCursor(0,0);
String final_screenImage = "";
for (scrn_ptr = 0; scrn_ptr < screenImage.length(); scrn_ptr += 2) final_screenImage = final_screenImage + screenImage.charAt(scrn_ptr);
lcd.setCursor(0,0); // row 0
lcd.print(final_screenImage.substring(0, 20));
lcd.setCursor(0,1); // row 1
lcd.print(final_screenImage.substring(20, 40));
final_screenImage = "";
}