/*
example in how to implement the menu library for and ESP32 and Adafruit libraries. This is an example that
uses both menu types
1) a simple selection menu (ItemMenu) where the user can scroll up/down and select
an item and some action be performed such as drawing a screen or activating a sub menu
2) an menu with in-line where the user can scroll up/down the list and select an item
however the difference is that move/up down on a selected item will scroll the values of that
menu item and NOT scroll the list, selecing a selected item will restore control to moving up/down
3) a EditMenu menu with in-line an no icons (down and dirty)
highlights
1. menu items exceeds screen size but library handles wrapping
2. each item selection has a range, increment and decimal readout
3. items can also be read from a char array
ESP32 display
3v3 VCC
GND GND
42 TFT_CS
41 TFT_RESET
40 TFT_DC
11 MOSI
12 SCK
5v LED
13 MISO
ESP32 SD Card
13 DO (MISO)
12 SCK
11 DI (MOSI)
7 CS
ESP32 Encoder
32 select button 1
GND select button 2
27 encoder direction 1
33 encoder direction 2
GND encoder dir ground
*/
// required libraries
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#include "Adafruit_ILI9341_Menu.h"
//#include <ESP32Encoder.h> // https://github.com/madhephaestus/ESP32Encoder
#include "ESP32Encoder.h"
#include <RTClib.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// found in \Arduino\libraries\Adafruit-GFX-Library-master
#include "FreeSans18pt7b.h" // Changed, used to be : #include "fonts\FreeSans18pt7b.h"
#include "FreeSans12pt7b.h"
#include "FreeSansBold12pt7b.h"
#include "FreeSansBold9pt7b.h"
#include "FreeSans9pt7b.h"
#include <FS.h>
#include <SD.h>
#include <SPI.h>
#include "Icons.h"
#define ROW_HEIGHT 35
#define ROWS 5
#define DATA_COLUMN 220 // Sets distance at which EditMenu values are shown
// Declare TFT screen pins
#define TFT_DC 40
#define TFT_CS 42 // Changed
#define TFT_RST 41 // Changed
#define LED_PIN 18 // Changed
// Declare SD card pins
//#define SD_MOSI 11 // DI pin Same as screen
//#define SD_MISO 13 // DO pin Same as screen
//#define SD_SCLK 12 // SCK pin Same as screen
#define SD_CS 7 // CS pin
// Try max SPI clock for an SD. Reduce SPI_CLOCK if errors occur.
#define SPI_SPEED SD_SCK_MHZ(25) // Default was 50, but probably too high. If not working use 10
#define EN1_PIN 15 // Changed
#define EN2_PIN 16 // Changed
#define SE_PIN 17 // Changed (Encoder push button)
#define PREV_PIN 39 // Added
#define NEXT_PIN 38 // Added
#define MENU_PIN 37 // Added
#define BL_PIN 1 // Pin to simulate BLE device connected
// GPIO where the DS18B20 is connected to
#define DS18B20_PIN 5
// RTC pins (I2C)
#define SDA_PIN 36
#define SCL_PIN 35
// easy way to include fonts but change globally
#define FONT_SMALL FreeSans9pt7b // font for menus
#define FONT_EDITTITLE FreeSans18pt7b // font for menus
#define FONT_ITEM FreeSans12pt7b // font for menus
#define FONT_TITLE FreeSans18pt7b // font for all headings
#define DEBOUNCE 75
float oldValue;
int MenuOption = 0;
bool ShowTripFlag = 1;
bool ShowOdoFlag = 1;
bool tempUnit = 0; // 0 = F; 1 = C
bool distUnit = 0; // 0 = Mi; 1 = km
bool autoBrightFlag = 1;
int defaultVol = 20;
float SpeedoFactor = 1.2;
int GPSspeed = 53; // mph
float odoValue = 103322.5; // Miles
float odoTrip = 103185.7; // Miles
float tripValue = odoValue - odoTrip; // Miles
int brightnessValue = 10;
int nightBrightValue = 5;
int milesToMaint;
float odoMaint = 102834.3;
float RTCtemp = 38.5;
int curSpeed = 46;
byte EPASValue = 1; // 0 = Off, 1 = On, 2-6 speed
byte day;
byte month;
int year;
byte minutes;
byte hours;
#define MAXDEV 4
bool currentBLState = false;
bool previousBLState = !currentBLState; // Force update upon startup
int currentDev = MAXDEV + 2;
// Smoothing variables
int smoothWater = 1;
int smoothOil = 1;
int smoothFuel = 25; // alpha = 1.0/25
int smoothVolt = 1;
int smoothRPM = 1;
int smoothSpeed = 1;
unsigned long start = 0;
unsigned long updateInt = 1000*60;
int maintInt = 0;
// SD Card Variables
const int maxLen = 50;
char dateL[4][11], milesL[4][8], noteL[4][maxLen];
int dataEntries = 0;
int dataIndex = 0; // Start from the last record
const int linesOnScreen = 4;
// must have variables for each menu item
// best to have these global so you can use them in processing functions
int RootOption1 = 0, RootOption2 = 0, RootOption3 = 0, RootOption4 = 0, RootOption5 = 0, RootOption6 = 0;
int BLEaudioOption1 = 0, BLEaudioOption2 = 0, BLEaudioOption3 = 0, BLEaudioOption4 = 0;
int ChangeDevOption1 = 0, ChangeDevOption2 = 0, ChangeDevOption3 = 0, ChangeDevOption4 = 0;
int OdoSpeedOption1 = 0, OdoSpeedOption2 = 0, OdoSpeedOption3 = 0, OdoSpeedOption4 = 0, OdoSpeedOption5 = 0, OdoSpeedOption6 = 0, OdoSpeedOption7 = 0, OdoSpeedOption8 = 0;
int SettingsOption1 = 0, SettingsOption2 = 0, SettingsOption3 = 0, SettingsOption4 = 0, SettingsOption5 = 0, SettingsOption6 = 0;
int MaintenanceOption1 = 0, MaintenanceOption2 = 0, MaintenanceOption3 = 0, MaintenanceOption4 = 0, MaintenanceOption5 = 0;
int SystemOption1 = 0, SystemOption2 = 0, SystemOption3 = 0, SystemOption4 = 0;
int FilterOption1 = 0, FilterOption2 = 0, FilterOption3 = 0, FilterOption4 = 0, FilterOption5 = 0, FilterOption6 = 0;
// encoder stuff
long Position = 0, oldPosition = 0;
// create some selectable menu sub-items, these are lists inside a menu item
char *TempUnitItems[] = {"Deg F", "Deg C"};
char *DistUnitItems[] = {"Miles","Kilomtr"};
char *OffOnItems[] = {"Off", "On"};
char *ShowHideItems[] = {"Show", "Hide"};
char *int500Items[] = {"500", "1000", "2000", "2500", "3000", "4000", "5000"};
char *IncreaseItems[] = {"0", "+1", "+2", "+3", "+4", "+5"};
char *EpasItems[] = {"Off", "Ign On", "10mph", "20mph", "30mph", "40mph", "50mph"};
char *ESPid[] = {"", "Music + Inputs", "Data + Display"};
char *optList[] = {"...","Con/Discon","Move Down","Remove"};
char *SysTemp[] = {""};
char *devices[MAXDEV+2] = {"Pixel 3A", "Phone 2", "Phone 3","","New","Discntd"}; // MAXDEV number of entries for devices, last two entries HAVE to be for New and Disconnected
int deviceCnt = 3;
// OK i'm going crazy with examples, but this will help show more processing when an int is needed but a float returned
// from the menu code
const char *C_NAMES[] = {"White", "Black", "Grey", "Blue", "Red", "Green", "Cyan", "Magenta",
"Yellow", "Teal", "Orange", "Pink", "Purple", "Lt Grey", "Lt Blue", "Lt Red",
"Lt Green", "Lt Cyan", "Lt Magenta", "Lt Yellow", "Lt Teal", "Lt Orange", "Lt Pink", "Lt Purple",
"Medium Grey", "Medium Blue", "Medium Red", "Medium Green", "Medium Cyan", "Medium Magenta", "Medium Yellow", "Medium Teal",
"Medium Orange", "Medium Pink", "Medium Purple", "Dk Grey", "Dk Blue", "Dk Red", "Dk Green", "Dk Cyan",
"Dk Magenta", "Dk Yellow", "Dk Teal", "Dk Orange", "Dk Pink", "Dk Purple"
};
// Define colors in array; Same as above
const uint16_t C_VALUES[] = { 0XFFFF, 0X0000, 0XC618, 0X001F, 0XF800, 0X07E0, 0X07FF, 0XF81F, //7
0XFFE0, 0X0438, 0XFD20, 0XF81F, 0X801F, 0XE71C, 0X73DF, 0XFBAE, //15
0X7FEE, 0X77BF, 0XFBB7, 0XF7EE, 0X77FE, 0XFDEE, 0XFBBA, 0XD3BF, //23
0X7BCF, 0X1016, 0XB000, 0X0584, 0X04B6, 0XB010, 0XAD80, 0X0594, //31
0XB340, 0XB00E, 0X8816, 0X4A49, 0X0812, 0X9000, 0X04A3, 0X0372, //39
0X900B, 0X94A0, 0X0452, 0X92E0, 0X9009, 0X8012 //45
};
// set default colors
uint16_t MENU_TEXT = C_VALUES[13];
uint16_t MENU_BACKGROUND = C_VALUES[1];
uint16_t MENU_HIGHLIGHTTEXT = C_VALUES[1];
uint16_t MENU_HIGHLIGHT = C_VALUES[21];
uint16_t MENU_HIGHBORDER = C_VALUES[10];
uint16_t MENU_SELECTTEXT = C_VALUES[0];
uint16_t MENU_SELECT = C_VALUES[4];
uint16_t MENU_SELECTBORDER = C_VALUES[35]; // 37 before
uint16_t MENU_DISABLE = C_VALUES[2];
uint16_t TITLE_TEXT = C_VALUES[13];
uint16_t TITLE_BACK = C_VALUES[36];
// you know the drill
Adafruit_ILI9341 Display = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
// required, you must create either an Item menu (no inline editing) or an EditMenu (allows inline editing)
//ClassName YourMenuName(&DisplayObject, True=Touch input, False(Default)=mechanical input);
ItemMenu MainMenu(&Display);
// since we're showing both menu types, create an object for each where the item menu is the main and calls edit menus
// you can have an item menu call other item menus an edit menu can call an edit menu but in a round about way--not recommended
//ClassName YourMenuName(&DisplayObject, True=Touch input, False(Default)=mechanical input);
EditMenu BLEaudioMenu(&Display);
EditMenu ChangeDevMenu(&Display);
EditMenu SourceMenu(&Display);
EditMenu OdoSpeedMenu(&Display);
EditMenu SettingsMenu(&Display);
EditMenu MaintenanceMenu(&Display);
EditMenu SystemMenu(&Display);
EditMenu FilteringMenu(&Display);
// Create instances
File root;
RTC_DS3231 rtc;
ESP32Encoder encoder;
OneWire oneWire(DS18B20_PIN);
// Pass oneWire reference to Dallas Temperature sensor
DallasTemperature TempSen(&oneWire);
// Declare all functions (needed for compile in PlatformIO)
void MusicScreen();
void ProcessBLEaudioMenu();
void ProcessOdoSpeedMenu();
void ProcessSettingsMenu();
void ProcessMaintenanceMenu();
void ProcessAddMaintMenu();
void ProcessSystemMenu();
void ProcessChangeDevMenu();
void ProcessSetDateTimeMenu();
void ProcessMaintRecordScreen();
void ProcessFilteringMenu();
void addDevice(char *device);
void moveDevice(int index);
void removeDevice(int index);
void addCommas(float value, char* result);
void drawBluetoothLogo(int x, int y, uint16_t color);
void drawMusicScreen(bool BLstateFlag);
bool getBTstate();
void drawYear(bool isBlack);
void drawMonth(bool isBlack);
void drawDay(bool isBlack);
void drawHours(bool isBlack);
void drawMinutes(bool isBlack);
void maintenanceRecScreen(char date[4][11], char miles[4][8], char note[4][maxLen], int num, int showMessage = 0);
void listDir(fs::FS &fs, const char * dirname, uint8_t levels);
void readEntries(fs::FS &fs, const char * path);
void readAndProcess(fs::FS &fs, const char * path);
void splitData(char* data, char* date, char* miles, char* note);
void processIncomingBT(char* text);
void setup() {
Serial.begin(9600);
Wire.begin(SDA_PIN, SCL_PIN);
rtc.begin();
// Set the initial time on the RTC
if (rtc.lostPower()) {
Serial.println("RTC lost power, time needs to be reset.");
//rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // Set date time at compile
rtc.adjust(DateTime(2024, 12, 31, 23, 59, 40)); // Set custom date time YYYY,MN,DY,HR,MN,SC
}
DateTime now = rtc.now();
day = now.day();
month = now.month();
year = now.year();
hours = now.hour();
minutes = now.minute();
// Start the DS18B20 sensor
TempSen.begin();
// Set all chip selects high to avoid bus contention during initialisation of each peripheral
digitalWrite(42, HIGH); // TFT screen chip select
digitalWrite(SD_CS, HIGH); // SD card chip select
delay(10);
//SD.begin(SD_CS, Display.getSPIinstance()); // Use with tft_eSPI library
Serial.print("Initializing SD card...\n");
if (!SD.begin(SD_CS)) {
Serial.println("SD initialization failed!");
while (true);
}
Serial.println("SD initialization done.");
uint32_t cardSize = SD.cardSize() / (1024 * 1024);
String str = "SDCard Size: " + String(cardSize) + "MB";
Serial.println(str);
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE) {
Serial.println("No SD card attached");
} // end if
// List directories on card
listDir(SD, "/", 0);
// disableCore0WDT();
ESP32Encoder::useInternalWeakPullResistors = puType::up;
encoder.attachHalfQuad(EN1_PIN, EN2_PIN);
encoder.clearCount();
// button in the encoder
pinMode(SE_PIN, INPUT_PULLUP);
// Previous and next buttons
pinMode(PREV_PIN, INPUT_PULLUP);
pinMode(NEXT_PIN, INPUT_PULLUP);
pinMode(MENU_PIN, INPUT_PULLUP);
// Pin to simulate bluetooth device connected
pinMode(BL_PIN, INPUT_PULLUP);
// Turn on screen to full brightness
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, HIGH);
// fire up the display
Display.begin();
Display.setRotation(1);
/*
while (1) {
Serial.println("Encoder count = " + String((int32_t)encoder.getCount()));
if (digitalRead(SE_PIN) == LOW) {
Serial.println("button press");
}
delay(100);
} */
/*
init(TextColor, BackgroundColor, HighLtTextColor, HighLtColor,
ItemRowHeight, MaxRowsPerScreen, TitleText, ItemFont, TitleFont);
*/
MainMenu.init(MENU_TEXT, MENU_BACKGROUND, MENU_HIGHLIGHTTEXT, MENU_HIGHLIGHT, 64, 3, "Main Menu", FONT_TITLE, FONT_TITLE);
// now add each item, text is what's displayed for each menu item, there are no other arguments
// there are 3 add types
// 1. addNI for no icon
// 2. addMono for simple 1 color icon each item
// 3. add565 for displaying a color icon for each item
// note the return value for each item will be it's returned item id and will be > 0
// a return of 0 is reserved for the exit item
// the exit item is actually the title bar--if user moves selector to the title bar
// it's temporarily renamed to "Exit"
/*
addNI(ItemLabel);
addMono(ItemLabel, MonoBitmap, BitmapWidth, BitmapHeight );
add565(ItemLabel, ColorBitmap, uint8_t BitmapWidth, uint8_t BitmapHeight);
*/
RootOption1 = MainMenu.addMono("Dashboard", Dashboard_64, 64, 64);
RootOption2 = MainMenu.addMono("BT & Audio Settings", BLESet_64, 64, 64);
RootOption3 = MainMenu.addMono("Odo & Speed Settings", OdoSpeed_64, 64, 64);
RootOption4 = MainMenu.addMono("General Settings", Settings_64, 64, 64);
RootOption5 = MainMenu.addMono("Maintenance", Maintenance_64, 64, 64);
RootOption6 = MainMenu.addMono("System", FirmSet_64, 64, 64);
// the remaing method calls for this menu are optional and shown as an example on what some of the things you can do
// however, you will most likely need to set xxxMarginxxx stuff as the library does not attempt to get text bounds
// and center, you will have to put pixel values in to control where text is display in menu items, title bars, etc.
// Setting enable state for the zero list entry (titlebar) makes it so
// that title bar is skipped when scrolling.
// Exiting will have to be done with button for instance.
MainMenu.disable(0);
// optional, but you can change title bar colors
// setTitleColors(TitleTextColor, TitleFillColor);
MainMenu.setTitleColors(TITLE_TEXT, TITLE_BACK);
// these are all optional, but you can change title bar colors, size, and margins.
// setTitleBarSize(TitleTop, TitleLeft, TitleWith, TitleHeight);
MainMenu.setTitleBarSize(0, 0, 320, 40);
// optional but lets center the title text about the height but scoot it in a bit from the left
// setTitleTextMargins(LeftMargin, TopMargin);
MainMenu.setTitleTextMargins(60, 30);
// optional but you can set the left margin and top to scoot the menu highLt over and down
// not needed but recommended so you can better control where the text is placed
// the library will not determine font height and such and adjust--that will be on you
// setMenuBarMargins(LeftMargin, Width, BorderRadius, BorderThickness);
MainMenu.setMenuBarMargins(0, 320, 15, 4);
// optional but you can set the menu highLt special colors (disable text color and border color)
// not needed if you dont plan on disabling menu items
// the library will not determine font height and such and adjust--that will be on you
// setItemColors(DisableTextColor, BorderColor);
MainMenu.setItemColors(MENU_DISABLE, MENU_HIGHBORDER);
// setItemTextMargins(LeftMargin, TopMargin, MarginBetweenTitleBarAndMenu);
MainMenu.setItemTextMargins(10, 45, 5);
// end of ItemMenu setup
//##################################################################################################################################
// this example includes both menu types, the first (above was a menu where items have no editing)
// this menu type EditMenu allows changes for each items value--basically in-line editing
// more capability? more arguements...
/*
init(TextColor, BackgroundColor, HighLtTextColor, HighLtColor, SelectedTextColor, SelectedColor,
MenuColumn, ItemRowHeight,MaxRowsPerScreen, TitleText, ItemFont, TitleFont);
*/
BLEaudioMenu.init(MENU_TEXT, MENU_BACKGROUND, MENU_HIGHLIGHTTEXT, MENU_HIGHLIGHT, MENU_SELECTTEXT, MENU_SELECT,
DATA_COLUMN, ROW_HEIGHT, ROWS, "BT & Audio Settings", FONT_ITEM, FONT_ITEM);
// now add each item, text is what's displayed for each menu item, there are no other arguements
// there are 3 add types
// 1. addNI for no icon
// 2. addMono for simple 1 color icon for each item
// 3. add565 for displaying a color icon for each item
// note the return value for each item will be it's returned itemid and will be > 0
// a return of 0 is reserved for the exit item
// the exit item is actually the title bar--if user moves selector to the title bar
// it's temporarily renamed to "Exit" while the selector is on the menu bar
/*
addNI(ItemText, InitalDisplayData, LowLimit, HighLimit, IncrementValue, DisplayDecimalPlaces, ItemMenuText);
addMono(ItemText, Data, LowLimit, HighLimit, Increment, DecimalPlaces, ItemMenuText,
Bitmap, BitmapWidth, BitmapHeight);
add565(ItemText, Data, LowLimit, HighLimit, Increment, DecimalPlaces, ItemMenuText,
Bitmap, BitmapWidth, BitmapHeight);
*/
BLEaudioOption1 = BLEaudioMenu.addNI("Saved Devices", currentDev, 0, 0, 0, 0, devices);
BLEaudioOption2 = BLEaudioMenu.addNI("Save Current Device", 0, 0, 0, 0, 0, NULL);
BLEaudioOption3 = BLEaudioMenu.addNI("Set Default Volume", defaultVol, 0, 60, 1, 0);
BLEaudioOption4 = BLEaudioMenu.addNI("Speed/Vol Increase", 0, 0, sizeof(IncreaseItems) / sizeof(IncreaseItems[0]), 1, 0, IncreaseItems);
BLEaudioMenu.disable(0); // Disable title bar exit
BLEaudioMenu.disableEdit(1); // No value to display, move to different screen
BLEaudioMenu.disableEdit(2); // No value to display, shows "Added" when clicked
BLEaudioMenu.setValueMargin(240);
// again all these calls are optional, but you most likely will want to set margins
// optional but you can store a setting such as a calibration value in EEPROM, read at startup
// and populate with SetItemValue(), even though the item data was set in the add method, you can change it later
// SetItemValue(ItemID, ItemValue){
//BLEaudioMenu.SetItemValue(OptionOption1, 0.12);
//BLEaudioMenu.setItemValue(BLEaudioOption3, 0);
// optional but can can set the title colors
// setTitleColors(TitleTextColor, TitleFillColor);
//BLEaudioMenu.setTitleColors(TITLE_TEXT, TITLE_BACK);
// optional but you can set the size of the title bar
// setTitleBarSize(TitleTop, TitleLeft, TitleWith, TitleHeight);
//BLEaudioMenu.setTitleBarSize(0, 0, 320, 40);
// optional but you can set the margins in how the text in the title bar is centered
// setTitleTextMargins(LeftMargin, TopMargin);
BLEaudioMenu.setTitleTextMargins(60, 30);
// optional but you can set the margins and size of the text in the menu bar
// setItemTextMargins(LeftMargin, TopMargin, MarginBetweenTitleBarAndMenu);
BLEaudioMenu.setItemTextMargins(7, 25, 0);
// optional but you can change colors other that in the init method
// colors such as disable text and border color (if you display a border of course)
// setItemColors(DisableTextColor, HighLtBorderColor, EditSelectBorderColor);
BLEaudioMenu.setItemColors(MENU_DISABLE, MENU_HIGHBORDER, MENU_SELECTBORDER);
BLEaudioMenu.setTitleColors(TITLE_TEXT, TITLE_BACK);
// optional but you can set the left margin and top to scoot the menu highLt over and down
// not needed but recommended so you can better control where the text is placed
// the library will not determine font height and such and adjust--that will be on you
// setMenuBarMargins(LeftMargin, Width, BorderRadius, BorderThickness);
BLEaudioMenu.setMenuBarMargins(5, 320, 10, 2);
//##################################################################################################################################
ChangeDevMenu.init(MENU_TEXT, MENU_BACKGROUND, MENU_HIGHLIGHTTEXT, MENU_HIGHLIGHT, MENU_SELECTTEXT, MENU_SELECT,
DATA_COLUMN, ROW_HEIGHT, ROWS, "Saved Devices", FONT_ITEM, FONT_ITEM);
/*
addNI(ItemText, InitalDisplayData, LowLimit, HighLimit, IncrementValue, DisplayDecimalPlaces, ItemMenuText);
addMono(ItemText, Data, LowLimit, HighLimit, Increment, DecimalPlaces, ItemMenuText,
Bitmap, BitmapWidth, BitmapHeight);
add565(ItemText, Data, LowLimit, HighLimit, Increment, DecimalPlaces, ItemMenuText,
Bitmap, BitmapWidth, BitmapHeight);
*/
ChangeDevOption1 = ChangeDevMenu.addNI("", 0, 0, sizeof(optList) / sizeof(optList[0]) , 1, 0, optList);
ChangeDevOption2 = ChangeDevMenu.addNI("", 0, 0, sizeof(optList) / sizeof(optList[0]) , 1, 0, optList);
ChangeDevOption3 = ChangeDevMenu.addNI("", 0, 0, sizeof(optList) / sizeof(optList[0]) , 1, 0, optList);
ChangeDevOption4 = ChangeDevMenu.addNI("", 0, 0, sizeof(optList) / sizeof(optList[0]) , 1, 0, optList);
ChangeDevMenu.disable(0); // Disable header select
for (int i = 0; i < deviceCnt; i++) {
ChangeDevMenu.setItemText(i+1, devices[i], false); // Third argument supresses redraw
}
ChangeDevMenu.disableLast(MAXDEV - deviceCnt); // Hide last menu items based on max number of devices
ChangeDevMenu.setValueMargin(220);
ChangeDevMenu.setTitleTextMargins(60, 30);
ChangeDevMenu.setItemTextMargins(7, 25, 0);
ChangeDevMenu.setMenuBarMargins(5, 320, 10, 2); // setMenuBarMargins(LeftMargin, Width, BorderRadius, BorderThickness);
ChangeDevMenu.setItemColors(MENU_DISABLE, MENU_HIGHBORDER, MENU_SELECTBORDER);
ChangeDevMenu.setTitleColors(TITLE_TEXT, TITLE_BACK);
//##################################################################################################################################
OdoSpeedMenu.init(MENU_TEXT, MENU_BACKGROUND, MENU_HIGHLIGHTTEXT, MENU_HIGHLIGHT, MENU_SELECTTEXT, MENU_SELECT,
DATA_COLUMN, ROW_HEIGHT, ROWS, "Odo & Speed Settings", FONT_ITEM, FONT_ITEM);
/*
addNI(ItemText, InitalDisplayData, LowLimit, HighLimit, IncrementValue, DisplayDecimalPlaces, ItemMenuText);
addMono(ItemText, Data, LowLimit, HighLimit, Increment, DecimalPlaces, ItemMenuText,
Bitmap, BitmapWidth, BitmapHeight);
add565(ItemText, Data, LowLimit, HighLimit, Increment, DecimalPlaces, ItemMenuText,
Bitmap, BitmapWidth, BitmapHeight);
*/
OdoSpeedOption1 = OdoSpeedMenu.addNI("Reset Trip", tripValue, 0, 999 , 1, 1, NULL);
OdoSpeedOption2 = OdoSpeedMenu.addNI("Adjust Odometer", odoValue, 0, 999999 , 1, NULL);
OdoSpeedOption3 = OdoSpeedMenu.addNI("Show Trip Odo", ShowTripFlag, 0, sizeof(ShowHideItems) / sizeof(ShowHideItems[0]), 1, 0, ShowHideItems);
OdoSpeedOption4 = OdoSpeedMenu.addNI("Show Odometer", ShowOdoFlag, 0, sizeof(ShowHideItems) / sizeof(ShowHideItems[0]), 1, 0, ShowHideItems);
OdoSpeedOption5 = OdoSpeedMenu.addNI("EPAS Settings", EPASValue, 0, sizeof(EpasItems) / sizeof(EpasItems[0]), 1, 0, EpasItems);
OdoSpeedOption6 = OdoSpeedMenu.addNI("GPS Calibrate", GPSspeed, 0, 120 , 1, 0, NULL); // needs to go to different screen
OdoSpeedOption7 = OdoSpeedMenu.addNI("Speedo Calibrate", SpeedoFactor, 0, 100 , 0.1, 1, NULL);
OdoSpeedOption8 = OdoSpeedMenu.addNI("", curSpeed, 0, 120, 1, 0, NULL);
OdoSpeedMenu.disable(0); // Disable header select
OdoSpeedMenu.disableSelect(1); // Disable trip select
OdoSpeedMenu.realTimeUpdate(7);// Update speedo in realtime while calibrating
OdoSpeedMenu.disableSelect(8); // Disable trip select
OdoSpeedMenu.realTimeUpdate(8);
OdoSpeedMenu.disableLast(); // Hide last menu item
OdoSpeedMenu.setValueMargin(220);
OdoSpeedMenu.setTitleTextMargins(60, 30);
OdoSpeedMenu.setItemTextMargins(7, 25, 0);
OdoSpeedMenu.setMenuBarMargins(5, 320, 10, 2); // setMenuBarMargins(LeftMargin, Width, BorderRadius, BorderThickness);
OdoSpeedMenu.setItemColors(MENU_DISABLE, MENU_HIGHBORDER, MENU_SELECTBORDER);
OdoSpeedMenu.setTitleColors(TITLE_TEXT, TITLE_BACK);
//Set correct initial values
OdoSpeedMenu.setItemValue(OdoSpeedOption1, tripValue);
OdoSpeedMenu.setItemValue(OdoSpeedOption2, odoValue);
OdoSpeedMenu.setItemValue(OdoSpeedOption3, 0); // Show trip
OdoSpeedMenu.setItemValue(OdoSpeedOption4, 0); // Show odo
OdoSpeedMenu.setItemValue(OdoSpeedOption5, EPASValue);
//##################################################################################################################################
SettingsMenu.init(MENU_TEXT, MENU_BACKGROUND, MENU_HIGHLIGHTTEXT, MENU_HIGHLIGHT, MENU_SELECTTEXT, MENU_SELECT,
DATA_COLUMN, ROW_HEIGHT, ROWS, "General Settings", FONT_ITEM, FONT_ITEM);
/*
addNI(ItemText, InitalDisplayData, LowLimit, HighLimit, IncrementValue, DisplayDecimalPlaces, ItemMenuText);
addMono(ItemText, Data, LowLimit, HighLimit, Increment, DecimalPlaces, ItemMenuText,
Bitmap, BitmapWidth, BitmapHeight);
add565(ItemText, Data, LowLimit, HighLimit, Increment, DecimalPlaces, ItemMenuText,
Bitmap, BitmapWidth, BitmapHeight);
*/
SettingsOption1 = SettingsMenu.addNI("Set Date/Time", 0, 0, 63 , 1, NULL); // needs to go to different screen
SettingsOption2 = SettingsMenu.addNI("Temperature Units", tempUnit, 0, sizeof(TempUnitItems) / sizeof(TempUnitItems[0]), 1, 0, TempUnitItems);
SettingsOption3 = SettingsMenu.addNI("Distance Units", distUnit, 0, sizeof(DistUnitItems) / sizeof(DistUnitItems[0]), 1, 0, DistUnitItems);
SettingsOption4 = SettingsMenu.addNI("Set Brightness", brightnessValue, 0, 10, 1, 0, NULL);
SettingsOption5 = SettingsMenu.addNI("Auto Brightness", autoBrightFlag, 0, sizeof(OffOnItems) / sizeof(OffOnItems[0]), 1, 0, OffOnItems);
SettingsOption6 = SettingsMenu.addNI("Set Night Bright", nightBrightValue, 0, 10, 1, 0, NULL);
SettingsMenu.disable(0); // Disable header select
SettingsMenu.disableEdit(1); // No value to display, move to different screen
SettingsMenu.realTimeUpdate(4);
SettingsMenu.setValueMargin(220);
SettingsMenu.setTitleTextMargins(60, 30);
SettingsMenu.setItemTextMargins(7, 25, 0);
SettingsMenu.setMenuBarMargins(5, 320, 10, 2); // setMenuBarMargins(LeftMargin, Width, BorderRadius, BorderThickness);
SettingsMenu.setItemColors(MENU_DISABLE, MENU_HIGHBORDER, MENU_SELECTBORDER);
SettingsMenu.setTitleColors(TITLE_TEXT, TITLE_BACK);
//Set correct initial values
SettingsMenu.setItemValue(SettingsOption2, 0); // Temp Unit F
SettingsMenu.setItemValue(SettingsOption3, 0); // Dist Unit miles
SettingsMenu.setItemValue(SettingsOption5, 1); // Auto Brightness on
MaintenanceMenu.init(MENU_TEXT, MENU_BACKGROUND, MENU_HIGHLIGHTTEXT, MENU_HIGHLIGHT, MENU_SELECTTEXT, MENU_SELECT,
DATA_COLUMN, ROW_HEIGHT, ROWS, "Maintenance", FONT_ITEM, FONT_ITEM);
/*
addNI(ItemText, InitalDisplayData, LowLimit, HighLimit, IncrementValue, DisplayDecimalPlaces, ItemMenuText);
addMono(ItemText, Data, LowLimit, HighLimit, Increment, DecimalPlaces, ItemMenuText,
Bitmap, BitmapWidth, BitmapHeight);
add565(ItemText, Data, LowLimit, HighLimit, Increment, DecimalPlaces, ItemMenuText,
Bitmap, BitmapWidth, BitmapHeight);
*/
MaintenanceOption1 = MaintenanceMenu.addNI("Miles till next", milesToMaint, 0, 999999, 0, 0, NULL);
MaintenanceOption2 = MaintenanceMenu.addNI("Reset Interval", 0, 0, 0, 1, 0, NULL);
MaintenanceOption3 = MaintenanceMenu.addNI("Maintenance Record", 0, 0, 0, 1, 0, NULL);
MaintenanceOption4 = MaintenanceMenu.addNI("Add Maintenance", 0, 0, 0, 1, 0, NULL);
MaintenanceOption5 = MaintenanceMenu.addNI("Maint. Interval", 1, 0, sizeof(int500Items) / sizeof(int500Items[0]), 1, 0, int500Items);
MaintenanceMenu.disable(0); // Disable header select
MaintenanceMenu.disableSelect(1); // Disable line select; just shows data
MaintenanceMenu.disableEdit(2); // Disable in-line edit, won't display value
MaintenanceMenu.disableEdit(3); // Disable in-line edit, won't display value, move to different screen
MaintenanceMenu.disableEdit(4); // Disable in-line edit, won't display value, move to different screen
MaintenanceMenu.setValueMargin(220);
MaintenanceMenu.setTitleTextMargins(60, 30);
MaintenanceMenu.setItemTextMargins(7, 25, 0);
MaintenanceMenu.setMenuBarMargins(5, 320, 10, 2); // setMenuBarMargins(LeftMargin, Width, BorderRadius, BorderThickness);
MaintenanceMenu.setItemColors(MENU_DISABLE, MENU_HIGHBORDER, MENU_SELECTBORDER);
MaintenanceMenu.setTitleColors(TITLE_TEXT, TITLE_BACK);
// Set initial values
maintInt = atoi(int500Items[(int)MaintenanceMenu.value[MaintenanceOption5]]);
milesToMaint = odoMaint - odoValue + maintInt;
MaintenanceMenu.setItemValue(MaintenanceOption1, milesToMaint);
SystemMenu.init(MENU_TEXT, MENU_BACKGROUND, MENU_HIGHLIGHTTEXT, MENU_HIGHLIGHT, MENU_SELECTTEXT, MENU_SELECT,
DATA_COLUMN, ROW_HEIGHT, ROWS, "System", FONT_ITEM, FONT_ITEM);
/*
addNI(ItemText, InitalDisplayData, LowLimit, HighLimit, IncrementValue, DisplayDecimalPlaces, ItemMenuText);
addMono(ItemText, Data, LowLimit, HighLimit, Increment, DecimalPlaces, ItemMenuText,
Bitmap, BitmapWidth, BitmapHeight);
add565(ItemText, Data, LowLimit, HighLimit, Increment, DecimalPlaces, ItemMenuText,
Bitmap, BitmapWidth, BitmapHeight);
*/
SystemOption1 = SystemMenu.addNI("Restart ESP32", 0, 0, 3, 1, 0, ESPid);
SystemOption2 = SystemMenu.addNI("OTA Update", 0, 0, 0, 0, 0, NULL);
SystemOption3 = SystemMenu.addNI("Sensor Filtering", 0, 0, 0, 0, 0, NULL);
SystemOption4 = SystemMenu.addNI("System Temp", 0, 0, 200, 0, 1, SysTemp);
SystemMenu.disable(0); // Disable header select
SystemMenu.disableEdit(2); // Disable in-line edit, won't display value
SystemMenu.disableEdit(3); // Disable in-line edit, won't display value
SystemMenu.disableSelect(4); // Disable line select; just shows data
SystemMenu.setValueMargin(220);
SystemMenu.setTitleTextMargins(60, 30);
SystemMenu.setItemTextMargins(7, 25, 0);
SystemMenu.setMenuBarMargins(5, 320, 10, 2); // setMenuBarMargins(LeftMargin, Width, BorderRadius, BorderThickness);
SystemMenu.setItemColors(MENU_DISABLE, MENU_HIGHBORDER, MENU_SELECTBORDER);
SystemMenu.setTitleColors(TITLE_TEXT, TITLE_BACK);
FilteringMenu.init(MENU_TEXT, MENU_BACKGROUND, MENU_HIGHLIGHTTEXT, MENU_HIGHLIGHT, MENU_SELECTTEXT, MENU_SELECT,
DATA_COLUMN, ROW_HEIGHT, ROWS, "Sensor Filtering Settings", FONT_ITEM, FONT_ITEM);
/*
addNI(ItemText, InitalDisplayData, LowLimit, HighLimit, IncrementValue, DisplayDecimalPlaces, ItemMenuText);
addMono(ItemText, Data, LowLimit, HighLimit, Increment, DecimalPlaces, ItemMenuText,
Bitmap, BitmapWidth, BitmapHeight);
add565(ItemText, Data, LowLimit, HighLimit, Increment, DecimalPlaces, ItemMenuText,
Bitmap, BitmapWidth, BitmapHeight);
*/
FilterOption1 = FilteringMenu.addNI("Oil Pressure", smoothOil, 1, 15, 1, 0, NULL);
FilterOption2 = FilteringMenu.addNI("Water Temp", smoothWater, 1, 15, 1, 0, NULL);
FilterOption3 = FilteringMenu.addNI("Voltage", smoothVolt, 1, 15, 1, 0, NULL);
FilterOption4 = FilteringMenu.addNI("Fuel Level", smoothFuel, 1, 30, 1, 0, NULL);
FilterOption5 = FilteringMenu.addNI("Tachometer", smoothRPM, 1, 15, 1, 0, NULL);
FilterOption6 = FilteringMenu.addNI("Speedometer", smoothSpeed, 1, 15, 1, 0, NULL);
FilteringMenu.disable(0); // Disable header select
FilteringMenu.setValueMargin(220);
FilteringMenu.setTitleTextMargins(20, 30);
FilteringMenu.setItemTextMargins(7, 25, 0);
FilteringMenu.setMenuBarMargins(5, 320, 10, 2); // setMenuBarMargins(LeftMargin, Width, BorderRadius, BorderThickness);
FilteringMenu.setItemColors(MENU_DISABLE, MENU_HIGHBORDER, MENU_SELECTBORDER);
FilteringMenu.setTitleColors(TITLE_TEXT, TITLE_BACK);
//Set correct initial values
FilteringMenu.setItemValue(SettingsOption1, smoothOil);
FilteringMenu.setItemValue(SettingsOption2, smoothWater);
FilteringMenu.setItemValue(SettingsOption3, smoothVolt);
FilteringMenu.setItemValue(SettingsOption4, smoothFuel);
FilteringMenu.setItemValue(SettingsOption5, smoothRPM);
FilteringMenu.setItemValue(SettingsOption6, smoothSpeed);
// Initiate header, use for
int tbh = 40; // title bar height
int sx = Display.width(); // screen width, default to screen width (320 for ILI9341)
int sy = Display.height(); // screen height, default to screen width (320 for ILI9341)
} // end setup
void loop() {
// To increase simulation speed
delay(10);
// this is just a processor for when you exit the top level menu
MusicScreen();
/*
Display.setCursor(10, 100);
Display.setFont(&FONT_TITLE);
Display.setTextColor(ILI9341_RED, ILI9341_WHITE);
Display.print(F("Done"));
delay(500);
Display.setCursor(10, 100);
Display.setFont(&FONT_TITLE);
Display.setTextColor(ILI9341_BLUE, ILI9341_BLUE);
Display.print(F("Done"));
delay(500);
if (digitalRead(MENU_PIN) == LOW) {
// debounce the button press
while (digitalRead(MENU_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("MENU Pressed");
ProcessMainMenu();
Display.fillScreen(MENU_BACKGROUND);
}
*/
}
// function to process main menu interaction
// ideally this implementation makes it easy to launch your menu from anywhere in the script
void ProcessMainMenu() {
// set an inital flag that will be used to store what menu item the user exited on
int MainMenuOption = 1;
// blank out the screen
Display.fillScreen(MENU_BACKGROUND);
// draw the main menu
MainMenu.draw();
// run the processing loop until user move selector to title bar (which becomes exit, i.e. 0 return val)
// and selectes it
// note menu code can return - 1 for errors so run unitl non zero
while (MainMenuOption != 0) {
// Make buttons act as encoder
if (digitalRead(PREV_PIN) == LOW) {
// debounce the button press
while (digitalRead(PREV_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("PREV Pressed");
Position = Position - 1;
MainMenu.MoveUp();
}
if (digitalRead(NEXT_PIN) == LOW) {
// debounce the button press
while (digitalRead(NEXT_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("NEXT Pressed");
Position = Position + 1;
MainMenu.MoveDown();
}
if (digitalRead(MENU_PIN) == LOW) {
// debounce the button press
while (digitalRead(MENU_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("MENU Pressed");
// Exit menu
MainMenuOption = 0;
// Reset menu position
MainMenu.exitMenu();
// Exit to MusicScreen
MusicScreen();
}
/*
// standard encoder read
Position = encoder.getCount();
// attempt to debouce these darn things...
if ((Position - oldPosition) > 0) {
delay(DEBOUNCE);
while (oldPosition != Position) {
oldPosition = Position;
Position = encoder.getCount();
}
// once encoder calms down and is done cycling, move selector up
// since encoder reads are increasing
// any menu wrapping is handled in the library
MainMenu.MoveUp();
}
// attempt to debouce these darn things...
if ((Position - oldPosition) < 0) {
delay(DEBOUNCE);
while (oldPosition != Position) {
oldPosition = Position;
Position = encoder.getCount();
}
// once encoder calms down and is done cycling, move selector up
// since encoder reads are decreasing
// any menu wrapping is handled in the library
MainMenu.MoveDown();
}
*/
// but wait...the user pressed the button on the encoder
if (digitalRead(SE_PIN) == LOW) {
// debounce the button press
while (digitalRead(SE_PIN) == LOW) {
delay(DEBOUNCE);
}
// get the row the selector is on
MainMenuOption = MainMenu.selectRow();
// here is where you process accordingly
// remember on pressing button on title bar 0 is returned and will exit the loop
if (MainMenuOption == RootOption1) {
// Show Dashboard
// when done processing that menu, return here
// clear display and redraw this main menu
Display.fillScreen(MENU_BACKGROUND);
MainMenu.draw();
}
if (MainMenuOption == RootOption2) {
ProcessBLEaudioMenu();
Display.fillScreen(MENU_BACKGROUND);
MainMenu.draw();
}
if (MainMenuOption == RootOption3) {
ProcessOdoSpeedMenu();
// After exit of previous menu, redraw main menu
Display.fillScreen(MENU_BACKGROUND);
MainMenu.draw();
}
if (MainMenuOption == RootOption4) {
ProcessSettingsMenu();
Display.fillScreen(MENU_BACKGROUND);
MainMenu.draw();
}
if (MainMenuOption == RootOption5) {
ProcessMaintenanceMenu();
Display.fillScreen(MENU_BACKGROUND);
MainMenu.draw();
}
if (MainMenuOption == RootOption6) {
ProcessSystemMenu();
Display.fillScreen(MENU_BACKGROUND);
MainMenu.draw();
}
}
}
}
// menu to handle processing for a sub-menu
// since this menu will be a menu that allows edits (EditMenu object type)
// process is exactly the same as an ItemMenu
// meaning you simply use the same MoveUp, MoveDown and the library will know if you are
// wanting to move the selector or cycle through a range
void ProcessBLEaudioMenu() {
// the entire menu processing are basically 3 calls
// YourMenu.MoveUp();
// YourMenu.MoveDown();
// EditMenuOption = YourMenu.selectRow();
// set an inital flag that will be used to store what menu item the user exited on
int BLEaudioOption = 1;
// blank out the screen
Display.fillScreen(MENU_BACKGROUND);
// draw the main menu
BLEaudioMenu.draw();
if (!BLEaudioMenu.getEnableState(1)) {
BLEaudioMenu.MoveDown();
}
if (getBTstate()) {
BLEaudioMenu.drawValue(BLEaudioOption1, devices[currentDev]);
BLEaudioMenu.drawRow(2);
}
BLEaudioMenu.drawValue(BLEaudioOption1, devices[currentDev]);
// run the processing loop until user move selector to title bar (which becomes exit)
// and selectes it
while (BLEaudioOption != 0) {
if (getBTstate()) {
BLEaudioMenu.drawValue(BLEaudioOption1, devices[currentDev]);
BLEaudioMenu.drawRow(2);
}
// Make buttons act as encoder
if (digitalRead(PREV_PIN) == LOW) {
// debounce the button press
while (digitalRead(PREV_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("PREV Pressed");
Position = Position - 1;
BLEaudioMenu.MoveUp();
BLEaudioMenu.drawValue(BLEaudioOption1, devices[currentDev]);
}
if (digitalRead(NEXT_PIN) == LOW) {
// debounce the button press
while (digitalRead(NEXT_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("NEXT Pressed");
Position = Position + 1;
BLEaudioMenu.MoveDown();
BLEaudioMenu.drawValue(BLEaudioOption1, devices[currentDev]);
}
if (digitalRead(MENU_PIN) == LOW) {
// debounce the button press
while (digitalRead(MENU_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("MENU Pressed");
if (BLEaudioMenu.rowselected) { // Stop edit, restore old value
BLEaudioMenu.setItemValue(BLEaudioOption, oldValue);
BLEaudioMenu.rowselected = !BLEaudioMenu.rowselected;
BLEaudioMenu.drawRow(BLEaudioOption);
}
else{ // Exit menu
BLEaudioOption = 0;
BLEaudioMenu.exitMenu();
}
}
// standard encoder read
Position = encoder.getCount();
// attempt to debouce these darn things...
if ((Position - oldPosition) > 0) {
delay(DEBOUNCE);
while (oldPosition != Position) {
oldPosition = Position;
Position = encoder.getCount();
}
// once encoder calms down and is done cycling, move selector up
// since encoder reads are increasing
// any menu wrapping is handled in the library
// the EditMenu object type is special cased
// 1. if a row was NOT selected, MoveUp / MoveDown will cycle throuh menu items
// 2. if a row IS selected, MoveUp / MoveDown will cycle throuh the range of values withing the item
BLEaudioMenu.MoveUp();
}
if ((Position - oldPosition) < 0) {
delay(DEBOUNCE);
while (oldPosition != Position) {
oldPosition = Position;
Position = encoder.getCount();
}
// once encoder calms down and is done cycling, move selector up
// since encoder reads are decreasing
// any menu wrapping is handled in the library
// the EditMenu object type is special cased
// 1. if a row was NOT selected, MoveUp / MoveDown will cycle throuh menu items
// 2. if a row IS selected, MoveUp / MoveDown will cycle throuh the range of values withing the item
BLEaudioMenu.MoveDown();
}
if (digitalRead(SE_PIN) == LOW) {
// debounce the selector button
while (digitalRead(SE_PIN) == LOW) {
delay(DEBOUNCE);
}
// use the selectRow to
// 1. select a row for editing
// a. when a row is selected, moveup, movedown will then scroll through the editable values (values or a list)
// 2. unselect a row when editing is done
// 3. when selector is on the title bar annd selecRow is called a 0 is returned
BLEaudioOption = BLEaudioMenu.selectRow();
oldValue = BLEaudioMenu.value[BLEaudioOption];
if (BLEaudioOption == BLEaudioOption1) {
ProcessChangeDevMenu();
Display.fillScreen(MENU_BACKGROUND);
BLEaudioMenu.draw();
BLEaudioMenu.drawValue(BLEaudioOption1, devices[currentDev]);
}
else if (BLEaudioOption == BLEaudioOption2) {
addDevice("test");
if (deviceCnt == 1) {
BLEaudioMenu.enable(BLEaudioOption1);
BLEaudioMenu.drawRow(BLEaudioOption1);
}
BLEaudioMenu.disable(BLEaudioOption2);
BLEaudioMenu.MoveUp();
BLEaudioMenu.drawValue(BLEaudioOption1, devices[currentDev]);
}
}
}
}
void ProcessOdoSpeedMenu() {
// the entire menu processing are basically 3 calls
// YourMenu.MoveUp();
// YourMenu.MoveDown();
// EditMenuOption = YourMenu.selectRow();
// set an inital flag that will be used to store what menu item the user exited on
int OdoSpeedOption = 1;
// blank out the screen
Display.fillScreen(MENU_BACKGROUND);
// draw the main menu
OdoSpeedMenu.draw();
long startT;
float tempValue;
// run the processing loop until user move selector to title bar (which becomes exit)
// and selectes it
while (OdoSpeedOption != 0) {
// Make buttons act as encoder
if (digitalRead(PREV_PIN) == LOW) {
// debounce the button press
while (digitalRead(PREV_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("PREV Pressed");
Position = Position - 1;
OdoSpeedMenu.MoveUp();
}
if (digitalRead(NEXT_PIN) == LOW) {
// debounce the button press
while (digitalRead(NEXT_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("NEXT Pressed");
Position = Position + 1;
OdoSpeedMenu.MoveDown();
}
if (digitalRead(MENU_PIN) == LOW) {
// debounce the button press
while (digitalRead(MENU_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("MENU Pressed");
if (OdoSpeedMenu.rowselected) { // Stop edit, restore old value
OdoSpeedMenu.setItemValue(OdoSpeedOption, oldValue);
OdoSpeedMenu.rowselected = !OdoSpeedMenu.rowselected;
OdoSpeedMenu.realTimeUpdateFlag = false;
OdoSpeedMenu.drawRow(OdoSpeedOption);
if (OdoSpeedOption == OdoSpeedOption7) {
Serial.println("Menu pressed while calibrating speedo");
OdoSpeedMenu.disableLast(); // Hide last menu item
OdoSpeedMenu.disable(OdoSpeedOption8); // Hide value
OdoSpeedMenu.setItemText(OdoSpeedOption8, "");
OdoSpeedMenu.drawRow(OdoSpeedOption8);
}
}
else{ // Exit menu
OdoSpeedOption = 0;
OdoSpeedMenu.exitMenu();
}
}
// standard encoder read
Position = encoder.getCount();
// attempt to debouce these darn things...
if ((Position - oldPosition) > 0) {
delay(DEBOUNCE);
while (oldPosition != Position) {
oldPosition = Position;
Position = encoder.getCount();
}
// once encoder calms down and is done cycling, move selector up
// since encoder reads are increasing
// any menu wrapping is handled in the library
// the EditMenu object type is special cased
// 1. if a row was NOT selected, MoveUp / MoveDown will cycle throuh menu items
// 2. if a row IS selected, MoveUp / MoveDown will cycle throuh the range of values withing the item
OdoSpeedMenu.MoveUp();
}
if ((Position - oldPosition) < 0) {
delay(DEBOUNCE);
while (oldPosition != Position) {
oldPosition = Position;
Position = encoder.getCount();
}
// once encoder calms down and is done cycling, move selector up
// since encoder reads are decreasing
// any menu wrapping is handled in the library
// the EditMenu object type is special cased
// 1. if a row was NOT selected, MoveUp / MoveDown will cycle throuh menu items
// 2. if a row IS selected, MoveUp / MoveDown will cycle throuh the range of values withing the item
OdoSpeedMenu.MoveDown();
}
if (digitalRead(SE_PIN) == LOW) {
// debounce the selector button
while (digitalRead(SE_PIN) == LOW) {
delay(DEBOUNCE);
}
// use the selectRow to
// 1. select a row for editing
// a. when a row is selected, moveup, movedown will then scroll through the editable values (values or a list)
// 2. unselect a row when editing is done
// 3. when selector is on the title bar annd selecRow is called a 0 is returned
OdoSpeedOption = OdoSpeedMenu.selectRow();
oldValue = OdoSpeedMenu.value[OdoSpeedOption];
if (OdoSpeedOption == 1) { // reset trip
OdoSpeedMenu.drawValue(OdoSpeedOption1, "Reset"); // Print temporary text using optional string argument
odoTrip = odoValue;
tripValue = 0.0;
OdoSpeedMenu.setItemValue(OdoSpeedOption1, tripValue);
}
else if(OdoSpeedOption == 2) { // Adjust odo
if (OdoSpeedMenu.rowselected) {
tempValue = oldValue;
}
else {
odoValue = OdoSpeedMenu.value[OdoSpeedOption];
// Update variables dependent on odometer value
float diff = odoValue - tempValue;
odoTrip = odoTrip + diff;
odoMaint = odoMaint + diff;
}
}
else if (OdoSpeedOption == OdoSpeedOption3) { // Show/Hide Trip
ShowTripFlag = !OdoSpeedMenu.value[OdoSpeedOption];
}
else if (OdoSpeedOption == OdoSpeedOption4) { // Show/Hide Odo
ShowOdoFlag = !OdoSpeedMenu.value[OdoSpeedOption];
}
else if (OdoSpeedOption == OdoSpeedOption5) { // EPAS Settings
if (OdoSpeedMenu.rowselected) {
tempValue = oldValue;
}
else {
EPASValue = OdoSpeedMenu.value[OdoSpeedOption];
if (EPASValue == 0) {
// Write EPAS pin low
Serial.println("EPAS off");
}
else if (EPASValue == 1){
// Write EPAS pin high
Serial.println("EPAS on");
}
else {
// Asjust settings for speed
Serial.print("EPAS speed ");
Serial.println(EpasItems[EPASValue]);
}
}
}
else if (OdoSpeedOption == OdoSpeedOption7) { // Calibrate speedo (adds current speed line)
Serial.println("Calibrating speedo");
if (OdoSpeedMenu.rowselected) {
Serial.println("Calibrating speedo");
OdoSpeedMenu.setItemText(OdoSpeedOption8, "Current Speed");
OdoSpeedMenu.enable(OdoSpeedOption8); // Show value
OdoSpeedMenu.enableLast(); // Show last menu item
OdoSpeedMenu.moveFrame(8-ROWS, 4); // Move frame Frame = listLength - frameItems
startT = millis();
}
else {
OdoSpeedMenu.disableLast(); // Hide last menu item
OdoSpeedMenu.disable(OdoSpeedOption8); // Hide value
OdoSpeedMenu.setItemText(OdoSpeedOption8, "");
OdoSpeedMenu.drawRow(OdoSpeedOption8);
}
}
}
if ((millis() - startT) > 1000 && OdoSpeedOption == 7 && OdoSpeedMenu.rowselected) {
float randNum = (float)random(950,1050) / 1000; // random float between 0.95 and 1.05
curSpeed = curSpeed * randNum; // Simulate change
OdoSpeedMenu.setItemValue(OdoSpeedOption8, curSpeed);
OdoSpeedMenu.drawValue(OdoSpeedOption8);
startT = millis();
}
}
}
void ProcessSettingsMenu() {
// the entire menu processing are basically 3 calls
// YourMenu.MoveUp();
// YourMenu.MoveDown();
// EditMenuOption = YourMenu.selectRow();
// set an inital flag that will be used to store what menu item the user exited on
int SettingsOption = 1;
// blank out the screen
Display.fillScreen(MENU_BACKGROUND);
// draw the main menu
SettingsMenu.draw();
// run the processing loop until user move selector to title bar (which becomes exit)
// and selectes it
while (SettingsOption != 0) {
// Enable real-time editing on this line
if (SettingsOption == SettingsOption4){
if (SettingsMenu.value[SettingsOption4] == 0){
digitalWrite(LED_PIN, LOW);
}
else{digitalWrite(LED_PIN, HIGH);
}
}
// Make buttons act as encoder
if (digitalRead(PREV_PIN) == LOW) {
// debounce the button press
while (digitalRead(PREV_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("PREV Pressed");
Position = Position - 1;
SettingsMenu.MoveUp();
}
if (digitalRead(NEXT_PIN) == LOW) {
// debounce the button press
while (digitalRead(NEXT_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("NEXT Pressed");
Position = Position + 1;
SettingsMenu.MoveDown();
}
if (digitalRead(MENU_PIN) == LOW) {
// debounce the button press
while (digitalRead(MENU_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("MENU Pressed");
if (SettingsMenu.rowselected) { // Stop edit, restore old value
SettingsMenu.setItemValue(SettingsOption, oldValue);
SettingsMenu.rowselected = !SettingsMenu.rowselected;
SettingsMenu.realTimeUpdateFlag = false;
SettingsMenu.drawRow(SettingsOption);
}
else{ // Exit menu
SettingsOption = 0;
SettingsMenu.exitMenu();
}
}
// standard encoder read
Position = encoder.getCount();
// attempt to debouce these darn things...
if ((Position - oldPosition) > 0) {
delay(DEBOUNCE);
while (oldPosition != Position) {
oldPosition = Position;
Position = encoder.getCount();
}
// once encoder calms down and is done cycling, move selector up
// since encoder reads are increasing
// any menu wrapping is handled in the library
// the EditMenu object type is special cased
// 1. if a row was NOT selected, MoveUp / MoveDown will cycle throuh menu items
// 2. if a row IS selected, MoveUp / MoveDown will cycle throuh the range of values withing the item
SettingsMenu.MoveUp();
}
if ((Position - oldPosition) < 0) {
delay(DEBOUNCE);
while (oldPosition != Position) {
oldPosition = Position;
Position = encoder.getCount();
}
// once encoder calms down and is done cycling, move selector up
// since encoder reads are decreasing
// any menu wrapping is handled in the library
// the EditMenu object type is special cased
// 1. if a row was NOT selected, MoveUp / MoveDown will cycle throuh menu items
// 2. if a row IS selected, MoveUp / MoveDown will cycle throuh the range of values withing the item
SettingsMenu.MoveDown();
}
if (digitalRead(SE_PIN) == LOW) {
// debounce the selector button
while (digitalRead(SE_PIN) == LOW) {
delay(DEBOUNCE);
}
SettingsOption = SettingsMenu.selectRow();
oldValue = SettingsMenu.value[SettingsOption];
if (SettingsOption == SettingsOption1) { // Set Date/time
ProcessSetDateTimeMenu();
// blank out the screen
Display.fillScreen(MENU_BACKGROUND);
SettingsMenu.draw();
}
if (SettingsOption == SettingsOption2) { // Temp Units
if (SettingsMenu.value[SettingsOption2] == 0) {
tempUnit = 0;
}
else{
tempUnit = 1;
}
}
else if (SettingsOption == SettingsOption3) { // Distance Units
if (SettingsMenu.value[SettingsOption3] == 0) { // miles
distUnit = 0;
EpasItems[2] = "10mph";
EpasItems[3] = "20mph";
EpasItems[4] = "30mph";
EpasItems[5] = "40mph";
EpasItems[6] = "50mph";
}
else{
distUnit = 1; // kilometers
EpasItems[2] = "10kph";
EpasItems[3] = "20kph";
EpasItems[4] = "30kph";
EpasItems[5] = "40kph";
EpasItems[6] = "50kph";
}
}
if (SettingsOption == SettingsOption5) { // Auto Brightness
if (SettingsMenu.value[SettingsOption5] == 0 && !SettingsMenu.rowselected) {
SettingsMenu.disableLast();
SettingsMenu.disable(SettingsOption6);
SettingsMenu.setItemText(SettingsOption6, "");
SettingsMenu.drawRow(SettingsOption6);
}
else if (SettingsMenu.value[SettingsOption5] == 1 && !SettingsMenu.rowselected){
SettingsMenu.enableLast();
SettingsMenu.enable(SettingsOption6);
SettingsMenu.setItemText(SettingsOption6, "Set Night Bright");
SettingsMenu.drawRow(SettingsOption6);
}
}
}
}
}
void ProcessMaintenanceMenu() {
// set an inital flag that will be used to store what menu item the user exited on
int option = 1;
// blank out the screen
Display.fillScreen(MENU_BACKGROUND);
// draw the main menu
MaintenanceMenu.draw();
// run the processing loop until user move selector to title bar (which becomes exit)
// and selectes it
while (option != 0) {
// Make buttons act as encoder
if (digitalRead(PREV_PIN) == LOW) {
// debounce the button press
while (digitalRead(PREV_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("PREV Pressed");
Position = Position - 1;
MaintenanceMenu.MoveUp();
}
if (digitalRead(NEXT_PIN) == LOW) {
// debounce the button press
while (digitalRead(NEXT_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("NEXT Pressed");
Position = Position + 1;
MaintenanceMenu.MoveDown();
}
if (digitalRead(MENU_PIN) == LOW) {
// debounce the button press
while (digitalRead(MENU_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("MENU Pressed");
if (MaintenanceMenu.rowselected) { // Stop edit, restore old value
MaintenanceMenu.setItemValue(option, oldValue);
MaintenanceMenu.rowselected = !MaintenanceMenu.rowselected;
MaintenanceMenu.drawRow(option);
}
else{ // Exit menu
option = 0;
MaintenanceMenu.exitMenu();
}
}
// standard encoder read
Position = encoder.getCount();
// attempt to debouce these darn things...
if ((Position - oldPosition) > 0) {
delay(DEBOUNCE);
while (oldPosition != Position) {
oldPosition = Position;
Position = encoder.getCount();
}
// once encoder calms down and is done cycling, move selector up
// since encoder reads are increasing
// any menu wrapping is handled in the library
// the EditMenu object type is special cased
// 1. if a row was NOT selected, MoveUp / MoveDown will cycle throuh menu items
// 2. if a row IS selected, MoveUp / MoveDown will cycle throuh the range of values withing the item
MaintenanceMenu.MoveUp();
}
if ((Position - oldPosition) < 0) {
delay(DEBOUNCE);
while (oldPosition != Position) {
oldPosition = Position;
Position = encoder.getCount();
}
// once encoder calms down and is done cycling, move selector up
// since encoder reads are decreasing
// any menu wrapping is handled in the library
// the EditMenu object type is special cased
// 1. if a row was NOT selected, MoveUp / MoveDown will cycle throuh menu items
// 2. if a row IS selected, MoveUp / MoveDown will cycle throuh the range of values withing the item
MaintenanceMenu.MoveDown();
}
if (digitalRead(SE_PIN) == LOW) {
// debounce the selector button
while (digitalRead(SE_PIN) == LOW) {
delay(DEBOUNCE);
}
option = MaintenanceMenu.selectRow();
oldValue = MaintenanceMenu.value[option];
if (option == MaintenanceOption2) { // Reset maintenance interval
odoMaint = odoValue;
milesToMaint = odoMaint - odoValue + maintInt;
MaintenanceMenu.setItemValue(MaintenanceOption1, milesToMaint);
MaintenanceMenu.drawRow(1);
MaintenanceMenu.drawValue(MaintenanceOption2, "Reset"); // Print temporary text using optional string argument
}
else if (option == MaintenanceOption3) { // Process "Show maintenance" screen
ProcessMaintRecordScreen();
option = MaintenanceOption1;
// blank out the screen
Display.fillScreen(MENU_BACKGROUND);
MaintenanceMenu.draw();
}
else if (option == MaintenanceOption4) { // Process "Add maintenace" screen
Serial.println("Pressed");
ProcessAddMaintMenu();
// ^^^^^ ATTEMPT CONNECT TO BT AUDIO
option = MaintenanceOption1;
// blank out the screen
Display.fillScreen(MENU_BACKGROUND);
MaintenanceMenu.draw();
}
else if (option == MaintenanceOption5) { // Set Maintenance interval
maintInt = atoi(int500Items[(int)MaintenanceMenu.value[MaintenanceOption5]]);
milesToMaint = odoMaint - odoValue + maintInt;
MaintenanceMenu.setItemValue(MaintenanceOption1, milesToMaint);
MaintenanceMenu.drawRow(1);
}
}
}
}
void ProcessAddMaintMenu() {
int option = 1;
unsigned long now = millis();
Display.fillScreen(0xFFFF);
//drawTitleBar("Add Maintenace");
// Header
Display.fillRect(1, 40, 320-1, 29, 0x4208);
Display.setTextColor(0xFFFF);
//Display.setTTFFont(Arial_8_Bold);
Display.setFont(&FONT_SMALL);
// ^^^^^ GET BT STATUS
currentBLState = digitalRead(BL_PIN);
Serial.print("At start BT State is:");
Serial.println(currentBLState);
Display.setCursor(76, 61);
if (currentBLState) { // If BT connected, disconnect first
int dly = 1500;
int dataEntries = 0;
int previousEntries = dataEntries;
Display.fillRect(1, 40, 320-1, 29, 0x4208);
Display.setCursor(76, 61);
Display.print("Disconnecting BT Audio");
while(currentBLState) {
if (digitalRead(MENU_PIN) == LOW) {
while (digitalRead(MENU_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("MENU Pressed - Exiting.");
Display.fillRect(1, 40, 320-1, 29, 0x4208);
option = 0;
break;
}
if (millis() - now >= 100) {
now = millis();
// ^^^^^ GET BT STATUS
currentBLState = digitalRead(BL_PIN);
}
}
Serial.println("Disconnected");
Display.fillRect(1, 40, 320-1, 29, 0x4208);
Display.setCursor(76, 61);
Display.print("Disconnected");
}
// ^^^^^ Send start BT Serial command
Serial.println("BT Serial Ready");
bool textDisplayed = false;
bool oldState = currentBLState;
while(!currentBLState && option != 0) { // Wait for BT Serial to connect
if (!textDisplayed) {
Display.fillRect(1, 40, 320-1, 29, 0x4208);
Display.setCursor(76, 61);
Display.print("Connecting to app"); // Prints for every while loop, needs to print only once
textDisplayed = true;
}
if (digitalRead(MENU_PIN) == LOW) {
while (digitalRead(MENU_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("MENU Pressed - Exiting.");
option = 0;
break;
}
if (millis() - now >= 100) {
now = millis();
// ^^^^^ GET BT STATUS
currentBLState = digitalRead(BL_PIN);
}
}
textDisplayed = false;
// While connected to BT Serial
while(option != 0) {
// Check if BT still connected
if (millis() - now >= 100) {
now = millis();
// ^^^^^ GET BT STATUS
currentBLState = digitalRead(BL_PIN);
if (currentBLState != oldState){
oldState = currentBLState;
textDisplayed = false;
}
}
if (!currentBLState) { // BT disconnected
if (!textDisplayed){
Serial.println("BT Disconnected");
Display.fillRect(1, 40, 320-1, 58, 0x4208);
Display.setCursor(76, 61);
Display.print("BT disconnected");
Display.setCursor(76, 80 );
Display.print("Press ENTER to continue"); // ADD NICE BUTTON LOOK
textDisplayed = true;
}
// Wait for confirmation
if (digitalRead(SE_PIN) == LOW) {
// debounce the selector button
while (digitalRead(SE_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("ENTER Pressed");
option = 0;
}
else if (digitalRead(MENU_PIN) == LOW) {
// debounce the button press
while (digitalRead(MENU_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("MENU Pressed");
option = 0;
}
}
// If menu pressed
else if (digitalRead(MENU_PIN) == LOW) {
// debounce the button press
while (digitalRead(MENU_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("MENU Pressed");
Serial.println("Disconnecting, awaiting timeout or disconnect");
// exit menu
Display.fillRect(1, 40, 320-1, 29, 0x4208);
Display.setCursor(76, 61);
Display.print("Disconnecting");
// ^^^^^ SEND DISCONNECT COMMAND TO OTHER ESP
now = millis();
unsigned long timer = millis();
const unsigned long timeout = 5000;
while(currentBLState || option != 0) {
if (millis() - timer >= timeout) {
Serial.println("BT disconnect timeout.");
Display.fillRect(1, 40, 320-1, 29, 0x4208);
Display.setCursor(76, 61);
Display.print("BT disconnect timeout");
option = 0;
break;
}
if (millis() - now >= 100) {
now = millis();
// ^^^^^ GET BT STATUS
currentBLState = digitalRead(BL_PIN);
}
}
Serial.println("Disconnected BT Serial");
// ^^^^^ SEND BT_SERIAL.end command
option = 0;
}
else if(currentBLState) {
if (!textDisplayed){
// Send data from SD card to other ESP
// Await for potential fault codes and display
Serial.println("Connected, do things through the app now");
Display.fillRect(1, 40, 320-1, 29, 0x4208);
Display.setCursor(76, 61);
Display.print("BT Communication Established");
textDisplayed = true;
}
}
}
} // end void ProcessAddMaintMenu
void ProcessSystemMenu() {
// set an inital flag that will be used to store what menu item the user exited on
int option = 1;
// blank out the screen
Display.fillScreen(MENU_BACKGROUND);
// Update system temp every time menu is called
char result[20];
float randNum = (float)random(950,1050) / 1000; // random float between 0.95 and 1.05
RTCtemp = RTCtemp * randNum; // Simulate change
if (tempUnit == 0) {
float temperatureF = (RTCtemp * 1.8) + 32;
sprintf(result, "%.1f ºF", temperatureF);
}
else {
sprintf(result, "%.1f ºC", RTCtemp);
}
SysTemp[0] = {result};
SystemMenu.setPickListItem(SystemOption4, SysTemp);
//SystemMenu.drawValue(SystemOption4, result);
// draw the main menu
SystemMenu.draw();
// run the processing loop until user move selector to title bar (which becomes exit)
// and selectes it
while (option != 0) {
// Make buttons act as encoder
if (digitalRead(PREV_PIN) == LOW) {
// debounce the button press
while (digitalRead(PREV_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("PREV Pressed");
Position = Position - 1;
SystemMenu.MoveUp();
}
if (digitalRead(NEXT_PIN) == LOW) {
// debounce the button press
while (digitalRead(NEXT_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("NEXT Pressed");
Position = Position + 1;
SystemMenu.MoveDown();
}
if (digitalRead(MENU_PIN) == LOW) {
// debounce the button press
while (digitalRead(MENU_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("MENU Pressed");
if (SystemMenu.rowselected) { // Stop edit, restore old value
SystemMenu.setItemValue(option, oldValue);
SystemMenu.rowselected = !SystemMenu.rowselected;
if (option == 1) {
SystemMenu.setItemText(option, "Restart ESP32");
}
else {
SystemMenu.drawRow(option);
}
}
else{ // Exit menu
option = 0;
SystemMenu.exitMenu();
}
}
// standard encoder read
Position = encoder.getCount();
// attempt to debouce these darn things...
if ((Position - oldPosition) > 0) {
delay(DEBOUNCE);
while (oldPosition != Position) {
oldPosition = Position;
Position = encoder.getCount();
}
// once encoder calms down and is done cycling, move selector up
// since encoder reads are increasing
// any menu wrapping is handled in the library
// the EditMenu object type is special cased
// 1. if a row was NOT selected, MoveUp / MoveDown will cycle throuh menu items
// 2. if a row IS selected, MoveUp / MoveDown will cycle throuh the range of values withing the item
SystemMenu.MoveUp();
}
if ((Position - oldPosition) < 0) {
delay(DEBOUNCE);
while (oldPosition != Position) {
oldPosition = Position;
Position = encoder.getCount();
}
// once encoder calms down and is done cycling, move selector up
// since encoder reads are decreasing
// any menu wrapping is handled in the library
// the EditMenu object type is special cased
// 1. if a row was NOT selected, MoveUp / MoveDown will cycle throuh menu items
// 2. if a row IS selected, MoveUp / MoveDown will cycle throuh the range of values withing the item
SystemMenu.MoveDown();
}
if (digitalRead(SE_PIN) == LOW) {
// debounce the selector button
while (digitalRead(SE_PIN) == LOW) {
delay(DEBOUNCE);
}
// use the selectRow to
// 1. select a row for editing
// a. when a row is selected, moveup, movedown will then scroll through the editable values (values or a list)
// 2. unselect a row when editing is done
// 3. when selector is on the title bar annd selecRow is called a 0 is returned
option = SystemMenu.selectRow();
if (option == 1) {
if (SystemMenu.rowselected) {
SystemMenu.setItemText(option, "Scroll for options >>>");
}
else {
if (SystemMenu.value[option] == 1) {
// Restart music ESP32
SystemMenu.setItemValue(option, 0);
//SystemMenu.drawRow(option);
}
else if (SystemMenu.value[option] == 2) {
// Restart screen ESP32
SystemMenu.setItemValue(option, 0);
//SystemMenu.drawRow(option);
}
SystemMenu.setItemText(option, "Restart ESP32");
}
}
if (option == 2) {
// OTA Update Menu
}
if (option == 3) { // Adjust filering factors
ProcessFilteringMenu();
// blank out the screen
Display.fillScreen(MENU_BACKGROUND);
SystemMenu.draw();
}
}
}
}
void ProcessFilteringMenu() {
// the entire menu processing are basically 3 calls
// YourMenu.MoveUp();
// YourMenu.MoveDown();
// EditMenuOption = YourMenu.selectRow();
// set an inital flag that will be used to store what menu item the user exited on
int option = 1;
// blank out the screen
Display.fillScreen(MENU_BACKGROUND);
// draw the main menu
FilteringMenu.draw();
// run the processing loop until user move selector to title bar (which becomes exit)
// and selectes it
while (option != 0) {
// Make buttons act as encoder
if (digitalRead(PREV_PIN) == LOW) {
// debounce the button press
while (digitalRead(PREV_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("PREV Pressed");
Position = Position - 1;
FilteringMenu.MoveUp();
}
if (digitalRead(NEXT_PIN) == LOW) {
// debounce the button press
while (digitalRead(NEXT_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("NEXT Pressed");
Position = Position + 1;
FilteringMenu.MoveDown();
}
if (digitalRead(MENU_PIN) == LOW) {
// debounce the button press
while (digitalRead(MENU_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("MENU Pressed");
if (FilteringMenu.rowselected) { // Stop edit, restore old value
FilteringMenu.setItemValue(option, oldValue);
FilteringMenu.rowselected = !FilteringMenu.rowselected;
FilteringMenu.drawRow(option);
}
else{ // Exit menu
option = 0;
FilteringMenu.exitMenu();
}
}
// standard encoder read
Position = encoder.getCount();
// attempt to debouce these darn things...
if ((Position - oldPosition) > 0) {
delay(DEBOUNCE);
while (oldPosition != Position) {
oldPosition = Position;
Position = encoder.getCount();
}
// once encoder calms down and is done cycling, move selector up
// since encoder reads are increasing
// any menu wrapping is handled in the library
// the EditMenu object type is special cased
// 1. if a row was NOT selected, MoveUp / MoveDown will cycle throuh menu items
// 2. if a row IS selected, MoveUp / MoveDown will cycle throuh the range of values withing the item
FilteringMenu.MoveUp();
}
if ((Position - oldPosition) < 0) {
delay(DEBOUNCE);
while (oldPosition != Position) {
oldPosition = Position;
Position = encoder.getCount();
}
// once encoder calms down and is done cycling, move selector up
// since encoder reads are decreasing
// any menu wrapping is handled in the library
// the EditMenu object type is special cased
// 1. if a row was NOT selected, MoveUp / MoveDown will cycle throuh menu items
// 2. if a row IS selected, MoveUp / MoveDown will cycle throuh the range of values withing the item
FilteringMenu.MoveDown();
}
if (digitalRead(SE_PIN) == LOW) {
// debounce the selector button
while (digitalRead(SE_PIN) == LOW) {
delay(DEBOUNCE);
}
// use the selectRow to
// 1. select a row for editing
// a. when a row is selected, moveup, movedown will then scroll through the editable values (values or a list)
// 2. unselect a row when editing is done
// 3. when selector is on the title bar annd selecRow is called a 0 is returned
option = FilteringMenu.selectRow();
float alpha;
switch (option) {
case 1:
alpha = 1.0/FilteringMenu.value[option];
//fuelLevelAvgEMA.updateAlpha(alpha);
break;
case 2:
alpha = 1.0/FilteringMenu.value[option];
//fuelLevelAvgEMA.updateAlpha(alpha);
break;
case 3:
alpha = 1.0/FilteringMenu.value[option];
//fuelLevelAvgEMA.updateAlpha(alpha);
break;
case 4:
alpha = 1.0/FilteringMenu.value[option];
//fuelLevelAvgEMA.updateAlpha(alpha);
break;
case 5:
alpha = 1.0/FilteringMenu.value[option];
//RPMAvgEMA.updateAlpha(alpha);
break;
case 6:
alpha = 1.0/FilteringMenu.value[option];
//speedAvgEMA.updateAlpha(alpha);
break;
}
}
}
}
void ProcessChangeDevMenu() {
// set an inital flag that will be used to store what menu item the user exited on
int option = 1;
// blank out the screen
Display.fillScreen(MENU_BACKGROUND);
// draw the main menu
ChangeDevMenu.draw();
// run the processing loop until user move selector to title bar (which becomes exit)
// and selectes it
while (option != 0) {
// Make buttons act as encoder
if (digitalRead(PREV_PIN) == LOW) {
// debounce the button press
while (digitalRead(PREV_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("PREV Pressed");
Position = Position - 1;
ChangeDevMenu.MoveUp();
}
if (digitalRead(NEXT_PIN) == LOW) {
// debounce the button press
while (digitalRead(NEXT_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("NEXT Pressed");
Position = Position + 1;
ChangeDevMenu.MoveDown();
}
if (digitalRead(MENU_PIN) == LOW) {
// debounce the button press
while (digitalRead(MENU_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("MENU Pressed");
if (ChangeDevMenu.rowselected) { // Stop edit, restore old value
ChangeDevMenu.setItemValue(option, 0);
ChangeDevMenu.rowselected = !ChangeDevMenu.rowselected;
ChangeDevMenu.drawRow(option);
}
else{ // Exit menu
option = 0;
ChangeDevMenu.exitMenu();
}
}
// standard encoder read
Position = encoder.getCount();
// attempt to debouce these darn things...
if ((Position - oldPosition) > 0) {
delay(DEBOUNCE);
while (oldPosition != Position) {
oldPosition = Position;
Position = encoder.getCount();
}
ChangeDevMenu.MoveUp();
}
if ((Position - oldPosition) < 0) {
delay(DEBOUNCE);
while (oldPosition != Position) {
oldPosition = Position;
Position = encoder.getCount();
}
ChangeDevMenu.MoveDown();
}
if (digitalRead(SE_PIN) == LOW) {
// debounce the selector button
while (digitalRead(SE_PIN) == LOW) {
delay(DEBOUNCE);
}
option = ChangeDevMenu.selectRow();
if (!ChangeDevMenu.rowselected) {
switch (option) {
case 1:
if (ChangeDevMenu.value[option] == 1) {
Serial.println("Connect");
bool attempt = false;
if (!currentBLState && currentDev <= MAXDEV +1) { // Connecting from disconnected state
ChangeDevMenu.drawValue(option, "Connecting...");
attempt = true;
}
else if (currentBLState && currentDev != (option - 1)) { // Connecting from connected state, but other device than 0
attempt = true;
ChangeDevMenu.drawValue(option, "Connecting...");
}
else {
Serial.println("Disconnecting");
ChangeDevMenu.drawValue(option, "Disconnecting...");
}
// Run connect command, pause for confirmation.
delay(2000);
currentBLState = digitalRead(BL_PIN);
if (currentBLState) { // BT Connected
ChangeDevMenu.setItemText(currentDev + 1, devices[currentDev]); // Update previous device line
currentDev = option - 1;
char formatCurrentDev[20]; // Ensure this is large enough to hold the formatted string
snprintf(formatCurrentDev, sizeof(formatCurrentDev), "%s <))", devices[currentDev]);
ChangeDevMenu.setItemText(option, formatCurrentDev);
ChangeDevMenu.drawValue(option, "Connected");
BLEaudioMenu.setItemText(BLEaudioOption2, "Current Device Saved", false);
currentBLState = 1;
previousBLState = 1;
} else { // BT not connected
if (currentDev != (option - 1) && attempt) { // attempted to connect, but failed
ChangeDevMenu.setItemText(currentDev + 1, devices[currentDev]);
currentDev = MAXDEV + 1;
ChangeDevMenu.drawValue(option, "Failed");
BLEaudioMenu.setItemText(BLEaudioOption2, "No device connected", false);
attempt = false;
}
else { // disconnected device 0
ChangeDevMenu.setItemText(option, devices[option - 1]);
currentDev = MAXDEV + 1;
ChangeDevMenu.drawValue(option, "Disconnected");
BLEaudioMenu.setItemText(BLEaudioOption2, "No device connected", false);
}
currentBLState = 0;
previousBLState = 0;
}
BLEaudioMenu.disable(BLEaudioOption2);
ChangeDevMenu.setItemValue(option, 0);
}
else if (ChangeDevMenu.value[option] == 2) {
Serial.println("Move");
ChangeDevMenu.setItemValue(option, 0);
if (deviceCnt > 1) {
moveDevice(option);
}
else {
ChangeDevMenu.drawValue(ChangeDevOption1, "Unable");
}
}
else if (ChangeDevMenu.value[option] == 3) {
Serial.println("Remove");
ChangeDevMenu.setItemValue(option, 0);
removeDevice(option - 1);
ChangeDevMenu.disableLast();
if (deviceCnt < 1) {
option = 0;
ChangeDevMenu.exitMenu();
BLEaudioMenu.disable(BLEaudioOption1);
BLEaudioMenu.MoveDown();
}
else {
Display.fillScreen(MENU_BACKGROUND);
ChangeDevMenu.draw();
}
}
break;
case 2:
if (ChangeDevMenu.value[option] == 1) {
Serial.println("Connect");
bool attempt = false;
if (!currentBLState && currentDev <= MAXDEV +1) { // Connecting from disconnected state
ChangeDevMenu.drawValue(option, "Connecting...");
attempt = true;
}
else if (currentBLState && currentDev != (option - 1)) { // Connecting from connected state, but other device than 0
attempt = true;
ChangeDevMenu.drawValue(option, "Connecting...");
}
else {
Serial.println("Disconnecting");
ChangeDevMenu.drawValue(option, "Disconnecting...");
}
// Run connect command, pause for confirmation.
delay(2000);
currentBLState = digitalRead(BL_PIN);
if (currentBLState) { // BT Connected
ChangeDevMenu.setItemText(currentDev + 1, devices[currentDev]); // Update previous device line
currentDev = option - 1;
char formatCurrentDev[20]; // Ensure this is large enough to hold the formatted string
snprintf(formatCurrentDev, sizeof(formatCurrentDev), "%s <))", devices[currentDev]);
ChangeDevMenu.setItemText(option, formatCurrentDev);
ChangeDevMenu.drawValue(option, "Connected");
BLEaudioMenu.setItemText(BLEaudioOption2, "Current Device Saved", false);
currentBLState = 1;
previousBLState = 1;
} else { // BT not connected
if (currentDev != (option - 1) && attempt) { // attempted to connect, but failed
ChangeDevMenu.setItemText(currentDev + 1, devices[currentDev]);
currentDev = MAXDEV + 1;
ChangeDevMenu.drawValue(option, "Failed");
BLEaudioMenu.setItemText(BLEaudioOption2, "No device connected", false);
attempt = false;
}
else { // disconnected device 0
ChangeDevMenu.setItemText(option, devices[option - 1]);
currentDev = MAXDEV + 1;
ChangeDevMenu.drawValue(option, "Disconnected");
BLEaudioMenu.setItemText(BLEaudioOption2, "No device connected", false);
}
currentBLState = 0;
previousBLState = 0;
}
BLEaudioMenu.disable(BLEaudioOption2);
ChangeDevMenu.setItemValue(option, 0);
}
else if (ChangeDevMenu.value[option] == 2) {
Serial.println("Move");
ChangeDevMenu.setItemValue(option, 0);
moveDevice(option);
}
else if (ChangeDevMenu.value[option] == 3) {
Serial.println("Remove");
ChangeDevMenu.setItemValue(option, 0);
removeDevice(option - 1);
currentBLState = digitalRead(BL_PIN);
if (currentBLState && currentDev == option - 1) { // BT Connected
currentDev = MAXDEV; // New, not saved
} else { // BT disconnected
currentDev = MAXDEV + 1; // Disconnected
}
ChangeDevMenu.disableLast();
if (deviceCnt < 1) {
option = 0;
ChangeDevMenu.exitMenu();
BLEaudioMenu.disable(BLEaudioOption1);
BLEaudioMenu.MoveDown();
}
else {
Display.fillScreen(MENU_BACKGROUND);
ChangeDevMenu.draw();
}
}
break;
case 3:
if (ChangeDevMenu.value[option] == 1) {
Serial.println("Connect");
bool attempt = false;
if (!currentBLState && currentDev <= MAXDEV +1) { // Connecting from disconnected state
ChangeDevMenu.drawValue(option, "Connecting...");
attempt = true;
}
else if (currentBLState && currentDev != (option - 1)) { // Connecting from connected state, but other device than 0
attempt = true;
ChangeDevMenu.drawValue(option, "Connecting...");
}
else {
Serial.println("Disconnecting");
ChangeDevMenu.drawValue(option, "Disconnecting...");
}
// Run connect command, pause for confirmation.
delay(2000);
currentBLState = digitalRead(BL_PIN);
if (currentBLState) { // BT Connected
ChangeDevMenu.setItemText(currentDev + 1, devices[currentDev]); // Update previous device line
currentDev = option - 1;
char formatCurrentDev[20]; // Ensure this is large enough to hold the formatted string
snprintf(formatCurrentDev, sizeof(formatCurrentDev), "%s <))", devices[currentDev]);
ChangeDevMenu.setItemText(option, formatCurrentDev);
ChangeDevMenu.drawValue(option, "Connected");
BLEaudioMenu.setItemText(BLEaudioOption2, "Current Device Saved", false);
currentBLState = 1;
previousBLState = 1;
} else { // BT not connected
if (currentDev != (option - 1) && attempt) { // attempted to connect, but failed
ChangeDevMenu.setItemText(currentDev + 1, devices[currentDev]);
currentDev = MAXDEV + 1;
ChangeDevMenu.drawValue(option, "Failed");
BLEaudioMenu.setItemText(BLEaudioOption2, "No device connected", false);
attempt = false;
}
else { // disconnected device 0
ChangeDevMenu.setItemText(option, devices[option - 1]);
currentDev = MAXDEV + 1;
ChangeDevMenu.drawValue(option, "Disconnected");
BLEaudioMenu.setItemText(BLEaudioOption2, "No device connected", false);
}
currentBLState = 0;
previousBLState = 0;
}
BLEaudioMenu.disable(BLEaudioOption2);
ChangeDevMenu.setItemValue(option, 0);
}
else if (ChangeDevMenu.value[option] == 2) {
Serial.println("Move");
ChangeDevMenu.setItemValue(option, 0);
moveDevice(option);
}
else if (ChangeDevMenu.value[option] == 3) {
Serial.println("Remove");
ChangeDevMenu.setItemValue(option, 0);
removeDevice(option - 1);
currentBLState = digitalRead(BL_PIN);
if (currentBLState) { // BT Connected
currentDev = MAXDEV; // New, not saved
} else { // BT disconnected
currentDev = MAXDEV + 1; // Disconnected
}
ChangeDevMenu.disableLast();
if (deviceCnt < 1) {
option = 0;
ChangeDevMenu.exitMenu();
BLEaudioMenu.disable(BLEaudioOption1);
BLEaudioMenu.MoveDown();
}
else {
Display.fillScreen(MENU_BACKGROUND);
ChangeDevMenu.draw();
}
}
break;
case 4:
if (ChangeDevMenu.value[option] == 1) {
Serial.println("Connect");
bool attempt = false;
if (!currentBLState && currentDev <= MAXDEV +1) { // Connecting from disconnected state
ChangeDevMenu.drawValue(option, "Connecting...");
attempt = true;
}
else if (currentBLState && currentDev != (option - 1)) { // Connecting from connected state, but other device than 0
attempt = true;
ChangeDevMenu.drawValue(option, "Connecting...");
}
else {
Serial.println("Disconnecting");
ChangeDevMenu.drawValue(option, "Disconnecting...");
}
// Run connect command, pause for confirmation.
delay(2000);
currentBLState = digitalRead(BL_PIN);
if (currentBLState) { // BT Connected
ChangeDevMenu.setItemText(currentDev + 1, devices[currentDev]); // Update previous device line
currentDev = option - 1;
char formatCurrentDev[20]; // Ensure this is large enough to hold the formatted string
snprintf(formatCurrentDev, sizeof(formatCurrentDev), "%s <))", devices[currentDev]);
ChangeDevMenu.setItemText(option, formatCurrentDev);
ChangeDevMenu.drawValue(option, "Connected");
BLEaudioMenu.setItemText(BLEaudioOption2, "Current Device Saved", false);
currentBLState = 1;
previousBLState = 1;
} else { // BT not connected
if (currentDev != (option - 1) && attempt) { // attempted to connect, but failed
ChangeDevMenu.setItemText(currentDev + 1, devices[currentDev]);
currentDev = MAXDEV + 1;
ChangeDevMenu.drawValue(option, "Failed");
BLEaudioMenu.setItemText(BLEaudioOption2, "No device connected", false);
attempt = false;
}
else { // disconnected device 0
ChangeDevMenu.setItemText(option, devices[option - 1]);
currentDev = MAXDEV + 1;
ChangeDevMenu.drawValue(option, "Disconnected");
BLEaudioMenu.setItemText(BLEaudioOption2, "No device connected", false);
}
currentBLState = 0;
previousBLState = 0;
}
BLEaudioMenu.disable(BLEaudioOption2);
ChangeDevMenu.setItemValue(option, 0);
}
else if (ChangeDevMenu.value[option] == 2) {
Serial.println("Move");
ChangeDevMenu.setItemValue(option, 0);
moveDevice(option);
}
else if (ChangeDevMenu.value[option] == 3) {
Serial.println("Remove");
ChangeDevMenu.setItemValue(option, 0);
removeDevice(option - 1);
currentBLState = digitalRead(BL_PIN);
if (currentBLState) { // BT Connected
currentDev = MAXDEV; // New, not saved
} else { // BT disconnected
currentDev = MAXDEV + 1; // Disconnected
}
ChangeDevMenu.disableLast();
if (deviceCnt < 1) {
option = 0;
ChangeDevMenu.exitMenu();
BLEaudioMenu.disable(BLEaudioOption1);
BLEaudioMenu.MoveDown();
}
else {
Display.fillScreen(MENU_BACKGROUND);
ChangeDevMenu.draw();
}
}
break;
} // end switch
} else {
ChangeDevMenu.setItemValue(option, 1);
ChangeDevMenu.drawRow(option);
}// end if
}
}
}
// Function to add to menu array
void addDevice(char *device ) {
if (deviceCnt < MAXDEV) {
devices[deviceCnt] = device;
deviceCnt++;
ChangeDevMenu.enableLast();
char formatCurrentDev[20]; // Ensure this is large enough to hold the formatted string
snprintf(formatCurrentDev, sizeof(formatCurrentDev), "%s <))", devices[deviceCnt - 1]);
ChangeDevMenu.setItemText(deviceCnt, formatCurrentDev,false); // Third argument supresses redraw
currentDev = deviceCnt - 1;
BLEaudioMenu.disable(2);
BLEaudioMenu.setItemText(BLEaudioOption2, "Current Device Saved");
}
}
void removeDevice(int index) { // index = option - 1
if (index >= 0 && index < deviceCnt) {
currentBLState = digitalRead(BL_PIN);
if (currentDev != 0 && index < currentDev && currentDev < MAXDEV) {
currentDev--;
}
else if (index == currentDev) { // remove currently connected device
BLEaudioMenu.enable(2);
BLEaudioMenu.setItemText(BLEaudioOption2, "Save Current Device", false);
currentBLState = digitalRead(BL_PIN);
currentDev = MAXDEV; // New, not saved
Serial.println(devices[currentDev]);
}
devices[index] = NULL;
// Shift all items down
for (int i = index; i < deviceCnt - 1; i++) {
devices[i] = devices[i + 1];
ChangeDevMenu.setItemText(i + 1, devices[i], false);
if (i == currentDev) {
char formatCurrentDev[20]; // Ensure this is large enough to hold the formatted string
snprintf(formatCurrentDev, sizeof(formatCurrentDev), "%s <))", devices[index+1]);
ChangeDevMenu.setItemText(i+1, formatCurrentDev,false);
}
}
// Decrease deviceCnt and clear the last item
ChangeDevMenu.setItemText(deviceCnt, "", false);
deviceCnt--;
devices[deviceCnt] = NULL;
}
}
// Moves device down 1 row
void moveDevice(int index) {
if (index >= 1 && index < deviceCnt) {
// Swap the devices
auto temp = devices[index - 1];
devices[index - 1] = devices[index];
devices[index] = temp;
// Update the menu
if (index == currentDev) { // swap with currentDev
currentDev--;
char formatCurrentDev[20]; // Ensure this is large enough to hold the formatted string
snprintf(formatCurrentDev, sizeof(formatCurrentDev), "%s <))", devices[index - 1]);
ChangeDevMenu.setItemText(index, formatCurrentDev,false);
ChangeDevMenu.setItemText(index + 1, devices[index], false);
}
else if (index - 1 == currentDev) { // currentDev selected
currentDev++;
char formatCurrentDev[20]; // Ensure this is large enough to hold the formatted string
snprintf(formatCurrentDev, sizeof(formatCurrentDev), "%s <))", devices[index]);
ChangeDevMenu.setItemText(index, devices[index - 1], false);
ChangeDevMenu.setItemText(index + 1, formatCurrentDev,false);
}
else {
ChangeDevMenu.setItemText(index, devices[index - 1], false);
ChangeDevMenu.setItemText(index + 1, devices[index], false);
}
// Update currentDev if necessary
//if (index == currentDev) {
// currentDev++;
//} else if (index + 1 == currentDev) {
// currentDev--;
//}
ChangeDevMenu.MoveDown();
}
else if (index == deviceCnt) {
// Move the last device to the top
auto temp = devices[deviceCnt - 1];
for (int i = deviceCnt - 1; i > 0; i--) {
devices[i] = devices[i - 1];
}
devices[0] = temp;
// Update the menu
for (int i = 0; i < deviceCnt; i++) {
ChangeDevMenu.setItemText(i + 1, devices[i]);
}
// Update currentDev if necessary
char formatCurrentDev[20]; // Ensure this is large enough to hold the formatted string
if (currentDev == deviceCnt - 1) {
currentDev = 0;
snprintf(formatCurrentDev, sizeof(formatCurrentDev), "%s <))", devices[currentDev]);
ChangeDevMenu.setItemText(1, formatCurrentDev, false);
} else {
currentDev++;
snprintf(formatCurrentDev, sizeof(formatCurrentDev), "%s <))", devices[currentDev]);
ChangeDevMenu.setItemText(currentDev + 1, formatCurrentDev, false);
}
ChangeDevMenu.MoveDown();
}
}
void UpdateHeader(bool BLstateFlag) {
start = millis();
// Draw background
Display.fillRect(0, 0, Display.width(), 40, TITLE_BACK);
Display.setTextColor(TITLE_TEXT);
// Display time
Display.setFont(&FONT_TITLE);
Display.setCursor(120, 35);
DateTime now = rtc.now();
char curTime[] = "hh:mm";
Display.print(now.toString(curTime));
char temp[20];
char result[20];
// Display outside temp
Display.setFont(&FONT_ITEM);
Display.setCursor(250, 20);
TempSen.requestTemperatures();
if (tempUnit == 0) {
float temperatureF = TempSen.getTempFByIndex(0);
sprintf(result, "%.1f ºF", temperatureF);
}
else {
float temperatureC = TempSen.getTempCByIndex(0);
sprintf(result, "%.1f ºC", temperatureC);
}
Display.print(result);
// Show odometers
if (ShowTripFlag) {
addCommas(tripValue, temp);
sprintf(result, "T: %s Mi", temp);
Display.setCursor(0, 20);
Display.print(result);
}
if (ShowOdoFlag) {
addCommas(odoValue, temp);
sprintf(result, "O: %s Mi", temp);
Display.setCursor(0, ShowTripFlag ? 40 : 20); // If trip is shown, move odometer down
Display.print(result);
}
// Display BLE status
drawBluetoothLogo(210, 60, ILI9341_BLUE);
if (BLstateFlag){
MainMenu.draw565Bitmap(210, 0, BLE_Connected_40, 40, 40);
} else{
MainMenu.draw565Bitmap(210, 0, BLE_Disconnected_40, 40, 40);
}
}
void drawBluetoothLogo(int x, int y, uint16_t color) {
Display.fillRoundRect(x, y, 25, 38, 12, ILI9341_BLUE);
// Draw the two triangles
Display.drawTriangle(x + 13, y + 4, x + 21, y + 11, x + 13, y + 18, ILI9341_WHITE);
Display.drawTriangle(x + 12, y + 4, x + 20, y + 11, x + 12, y + 18, ILI9341_WHITE);
Display.drawTriangle(x + 12, y + 5, x + 19, y + 11, x + 12, y + 18, ILI9341_WHITE);
Display.drawTriangle(x + 13, y + 19, x + 21, y + 26, x + 13, y + 33, ILI9341_WHITE);
Display.drawTriangle(x + 12, y + 19, x + 20, y + 26, x + 12, y + 33, ILI9341_WHITE);
Display.drawTriangle(x + 12, y + 20, x + 21, y + 26, x + 12, y + 32, ILI9341_WHITE);
// Draw the two diagonal lines
Display.drawLine(x + 4, y + 11, x + 11, y + 18, ILI9341_WHITE);
Display.drawLine(x + 5, y + 11, x + 12, y + 18, ILI9341_WHITE);
Display.drawLine(x + 4, y + 26, x + 11, y + 18, ILI9341_WHITE);
Display.drawLine(x + 5, y + 26, x + 12, y + 18, ILI9341_WHITE);
}
void MusicScreen() {
int option = 1;
currentBLState = digitalRead(BL_PIN);
// Initial drawing based on the initial state of BL_PIN
drawMusicScreen(currentBLState);
UpdateHeader(currentBLState);
while (option != 0) {
if (millis() >= start + updateInt) {
UpdateHeader(currentBLState);
}
if (getBTstate()) {
drawMusicScreen(currentBLState);
UpdateHeader(currentBLState);
}
//currentBLState = digitalRead(BL_PIN);
//if (currentBLState != previousBLState) { // Check against previous state
// drawMusicScreen(currentBLState);
// previousBLState = currentBLState; // Update previous state
// Serial.println("Bluetooth state changed");
// UpdateHeader(currentBLState);
// if (currentBLState) {
// currentDev = 0; // Adjust based on connected device
// Need to check if device is already added under devices array
// if in devices, match index.
// if device is known, disable "Save Current Device" option
// if (currentDev < 4) {
// BLEaudioMenu.disable(2);
// BLEaudioMenu.setItemText(BLEaudioOption2, "Current Device Saved", false);
// char formatCurrentDev[20]; // Ensure this is large enough to hold the formatted string
// snprintf(formatCurrentDev, sizeof(formatCurrentDev), "%s <))", devices[currentDev]);
// ChangeDevMenu.setItemText(currentDev + 1, formatCurrentDev, false);
// }
// else {
// BLEaudioMenu.enable(2);
// BLEaudioMenu.setItemText(BLEaudioOption2, "Save Current Device", false);
// ChangeDevMenu.setItemText(currentDev + 1, devices[currentDev], false);
// }
// }
// else {
// // No BL device connected, disable "Save Current Device" option and change text
// currentDev = MAXDEV + 1;
// BLEaudioMenu.disable(2);
// BLEaudioMenu.setItemText(BLEaudioOption2, "No device connected", false);
// }
//}
if (digitalRead(MENU_PIN) == LOW) {
// debounce the button press
while (digitalRead(MENU_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("MENU Pressed");
ProcessMainMenu();
Display.fillScreen(MENU_BACKGROUND);
}
}
}
void drawMusicScreen(bool BLstateFlag) {
Display.fillScreen(0xFFFF);
if (BLstateFlag) {
// Rectangle 2
//Display.fillRectVGradient(0, 13, 320, 213, 0x5B0D, 0x0000);
Display.fillRect(0, 30, 320, 213, 0x5B0D);
// Oval 1
//Display.drawEllipse(160, 187, 27, 27, 0xFFFF);
Display.drawCircle(160, 187, 27, 0xFFFF);
// Isosceles Triangle 3
Display.fillTriangle(146, 204, 186, 204, 166, 171, 0xFFFF);
Display.drawTriangle(146, 204, 186, 204, 166, 171, 0x7BEF);
// Oval 4
//Display.drawEllipse(251, 187, 27, 27, 0xFFFF);
Display.drawCircle(251, 187, 27, 0xFFFF);
// Rectangle 6
Display.fillRect(238, 168, 10, 38, 0x7BEF);
Display.fillRect(239, 169, 8, 36, 0xFFFF);
// Rectangle 8
Display.fillRect(254, 168, 10, 38, 0x7BEF);
Display.fillRect(255, 169, 8, 36, 0xFFFF);
// TextBox 12
Display.setTextColor(0x0000);
//Display.setTTFFont(Arial_14.64);
Display.setFont(&FONT_SMALL);
Display.setCursor(11, 63);
Display.print("Track:");
// TextBox 20
Display.setTextColor(0x0000);
//Display.setTTFFont(Arial_14.64);
Display.setFont(&FONT_SMALL);
Display.setCursor(11, 96);
Display.print("Artist:");
// TextBox 21
Display.setTextColor(0x0000);
//Display.setTTFFont(Arial_14.64);
Display.setFont(&FONT_SMALL);
Display.setCursor(10, 129);
Display.print("Album:");
// TextBox 25
Display.setTextColor(0x0000);
//Display.setTTFFont(Arial_11.98);
Display.setFont(&FONT_SMALL);
Display.setCursor(62, 211);
Display.print("\\");
// TextBox 26
Display.setTextColor(0x0000);
//Display.setTTFFont(Arial_14.64);
Display.setFont(&FONT_SMALL);
Display.setCursor(78, 63);
const char track[] = "Text";
Display.print(track);
// TextBox 27
Display.setTextColor(0x0000);
//Display.setTTFFont(Arial_14.64);
Display.setFont(&FONT_SMALL);
Display.setCursor(78, 96);
const char artist[] = "Text";
Display.print(artist);
// TextBox 28
Display.setTextColor(0x0000);
//Display.setTTFFont(Arial_14.64);
Display.setFont(&FONT_SMALL);
Display.setCursor(78, 128);
const char album[] = "Text";
Display.print(album);
// TextBox 29
Display.setTextColor(0x0000);
//Display.setTTFFont(Arial_9.32);
Display.setFont(&FONT_SMALL);
Display.setCursor(6, 212);
const char trackNo[] = "Text";
Display.print(trackNo);
// TextBox 30
Display.setTextColor(0x0000);
//Display.setTTFFont(Arial_9.32);
Display.setFont(&FONT_SMALL);
Display.setCursor(73, 211);
const char noTracks[] = "Text";
Display.print(noTracks);
// Isosceles Triangle 7
Display.fillTriangle(292, 216, 319, 216, 306, 200, 0x0000);
// Isosceles Triangle 23
Display.fillTriangle(199, 37, 225, 37, 212, 21, 0xFFFF);
// Isosceles Triangle 34
Display.fillTriangle(211, 48, 213, 48, 212, 10, 0xFFFF);
// Isosceles Triangle 35
Display.fillTriangle(212, 47, 213, 47, 212, 9, 0xFFFF);
// Isosceles Triangle 36
Display.fillTriangle(211, 48, 213, 48, 212, 10, 0xFFFF);
// Isosceles Triangle 38
Display.fillTriangle(211, 47, 213, 47, 212, 9, 0xFFFF);
} else {
// No device connected
Display.setTextColor(0x0000);
Display.setFont(&FONT_SMALL);
Display.setCursor(78, 85);
Display.print("No Device Connected");
}
}
bool getBTstate() {
currentBLState = digitalRead(BL_PIN);
if (currentBLState != previousBLState) { // Check against previous state
previousBLState = currentBLState; // Update previous state
Serial.println("Bluetooth state changed");
if (currentBLState) {
currentDev = 0; // Adjust based on connected device
// Need to check if device is already added under devices array
// if in devices, match index.
// if device is known, disable "Save Current Device" option
if (currentDev < 4) {
BLEaudioMenu.disable(2);
BLEaudioMenu.setItemText(BLEaudioOption2, "Current Device Saved", false);
char formatCurrentDev[20]; // Ensure this is large enough to hold the formatted string
snprintf(formatCurrentDev, sizeof(formatCurrentDev), "%s <))", devices[currentDev]);
ChangeDevMenu.setItemText(currentDev + 1, formatCurrentDev, false);
}
else {
BLEaudioMenu.enable(2);
BLEaudioMenu.setItemText(BLEaudioOption2, "Save Current Device", false);
ChangeDevMenu.setItemText(currentDev + 1, devices[currentDev], false);
}
}
else {
// No BL device connected, disable "Save Current Device" option and change text
currentDev = MAXDEV + 1;
BLEaudioMenu.disable(2);
BLEaudioMenu.setItemText(BLEaudioOption2, "No device connected", false);
for (int i = 0; i < deviceCnt; i++) {
ChangeDevMenu.setItemText(i + 1, devices[i], false);
}
}
return true;
}
return false;
}
void drawDateTime(int option, int prev_option = 0) {
/*
// Time/date formatting by library
//buffer can be defined using following combinations:
//hh - the hour with a leading zero (00 to 23)
//mm - the minute with a leading zero (00 to 59)
//ss - the whole second with a leading zero where applicable (00 to 59)
//YYYY - the year as four digit number
//YY - the year as two digit number (00-99)
//MM - the month as number with a leading zero (01-12)
//MMM - the abbreviated English month name ('Jan' to 'Dec')
//DD - the day as number with a leading zero (01 to 31)
//DDD - the abbreviated English day name ('Mon' to 'Sun')
char buf1[] = "hh:mm";
Serial.println(now.toString(buf1));
char buf2[] = "YYMMDD-hh:mm:ss";
Serial.println(now.toString(buf2));
char buf3[] = "Today is DDD, MMM DD YYYY";
Serial.println(now.toString(buf3));
char buf4[] = "MM-DD-YYYY";
Serial.println(now.toString(buf4));
*/
// An array of functions to draw each option
void (*drawFuncs[5])(bool) = {drawMonth, drawDay, drawYear, drawHours, drawMinutes};
// Only redraw the whole screen if no previous option is provided
if (prev_option == 0) {
// Background
//Display.fillRectVGradient(0, 0, 480, 320, 0x5B0D, 0x0000);
Display.fillRect(0, 0, 320, 240, 0XC618); // Gray
// Date
Display.setTextColor(0XFFFF); // White
//Display.setTTFFont(Arial_22);
Display.setFont(&FONT_SMALL);
Display.setCursor(11, 106);
//Display.print(F("Date:"));
Display.print("Date:");
Display.setCursor(11, 185);
//Display.print(F("Date:"));
Display.print("Time:");
for (int i = 0; i <= 4; i++) {
(*drawFuncs[i])(false);
}
// Add indicator to show what is what
Display.setCursor(87, 76);
Display.print("MM");
Display.setCursor(135, 76);
Display.print("DD");
Display.setCursor(195, 76);
Display.print("YYYY");
}
// Redraw the previous option in its normal color
if (prev_option != 0 && prev_option != option) {
(*drawFuncs[prev_option - 1])(false);
}
// Draw the current option in black
(*drawFuncs[option - 1])(true);
}
void ProcessSetDateTimeMenu() {
int option = 1;
int prev_option = option;
//Get current time
DateTime now = rtc.now();
day = now.day();
month = now.month();
year = now.year();
hours = now.hour();
minutes = now.minute();
drawDateTime(option);
// Make buttons act as encoder
while (option != 0) {
if (digitalRead(PREV_PIN) == LOW) {
// debounce the button press
while (digitalRead(PREV_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("PREV Pressed");
switch (option) {
case 1:
if (month > 1) {
month--;
}
else if (month == 1) {
month = 12;
}
break;
case 2:
if (day > 1) {
day--;
}
else if (day == 1) {
day = 31;
}
break;
case 3: year--; break;
case 4:
if (hours > 0) {
hours--;
}
else if (hours == 0) {
hours = 23;
}
break;
case 5:
if (minutes > 0) {
minutes--;
}
else if (minutes == 0) {
minutes = 59;
}
break;
}
prev_option = option;
drawDateTime(option, prev_option); // Redraw the date/time with the updated value
}
if (digitalRead(NEXT_PIN) == LOW) {
// debounce the button press
while (digitalRead(NEXT_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("NEXT Pressed");
switch (option) {
case 1:
if (month < 12) {
month++;
}
else if (month == 12) {
month = 1;
}
break;
case 2:
if (day < 31) {
day++;
}
else if (day == 31) {
day = 1;
}
break;
case 3: year++; break;
case 4:
if (hours < 23) {
hours++;
}
else if (hours == 23) {
hours = 0;
}
break;
case 5:
if (minutes < 59) {
minutes++;
}
else if (minutes == 59) {
minutes = 0;
}
break;
}
prev_option = option;
drawDateTime(option, prev_option); // Redraw the date/time with the updated value
}
if (digitalRead(MENU_PIN) == LOW) {
// debounce the button press
while (digitalRead(MENU_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("MENU Pressed");
// exit editing
option = 0;
}
if (digitalRead(SE_PIN) == LOW) {
// debounce the selector button
while (digitalRead(SE_PIN) == LOW) {
delay(DEBOUNCE);
}
// Move to next field
prev_option = option;
option = (option % 6) + 1; // This will cycle option from 1 to 5
if (option == 6) {
option = 0;
rtc.adjust(DateTime(year, month, day, hours, minutes, 0));
// Grab new date/time
DateTime now = rtc.now();
// Background
//Display.fillRectVGradient(0, 0, 480, 320, 0x5B0D, 0x0000);
Display.fillRect(0, 0, 320, 240, MENU_BACKGROUND);
// Date
Display.setTextColor(0XFFFF); // White
//Display.setTTFFont(Arial_22);
Display.setFont(&FONT_SMALL);
Display.setCursor(11, 106);
//Display.print(F("Date:"));
Display.print("Date: ");
char buf1[] = "DDD, MMM DD, YYYY";
Display.print(now.toString(buf1));
Display.setCursor(11, 185);
//Display.print(F("Date:"));
Display.print("Time: ");
char buf2[] = "hh:mm";
Display.print(now.toString(buf2));
start = millis();
// Display for 4 seconds, then return
while (millis() - start < 4000) {delay(2);}
return;
}
drawDateTime(option, prev_option); // Redraw the date/time with the new option
}
}
}
void drawMonth(bool isBlack) {
int color = isBlack ? 0x0000 : 0XE71C; // Black if isBlack is true, otherwise Lt Gray
Display.fillRect(80, 80, 40, 40, color);
Display.setCursor(87, 106);
Display.print(month);
}
void drawDay(bool isBlack) {
int color = isBlack ? 0x0000 : 0XE71C;
Display.fillRect(130, 80, 40, 40, color);
Display.setCursor(135, 106);
Display.print(day);
}
void drawYear(bool isBlack) {
int color = isBlack ? 0x0000 : 0XE71C;
Display.fillRect(180, 80, 80, 40, color);
Display.setCursor(195, 106);
Display.print(year);
}
void drawHours(bool isBlack) {
int color = isBlack ? 0x0000 : 0XE71C;
Display.fillRect(80, 160, 50, 40, color);
Display.setCursor(90, 185);
char hoursStr[3];
sprintf(hoursStr, "%02d", hours);
Display.print(hoursStr);
}
void drawMinutes(bool isBlack) {
int color = isBlack ? 0x0000 : 0XE71C;
Display.fillRect(140, 160, 50, 40, color);
Display.setCursor(150, 185);
char minutesStr[3];
sprintf(minutesStr, "%02d", minutes);
Display.print(minutesStr);
}
// Function to add 1000s comma to float and return as string
void addCommas(float value, char* result) {
// Split the float into integer and fractional parts
unsigned long intPart = (unsigned long)value;
unsigned int fracPart = (unsigned int)((value - intPart) * 10);
// Convert the integer part to a string with commas
char intPartWithCommas[20];
char temp[20];
sprintf(temp, "%lu", intPart);
int len = strlen(temp);
int j = 0;
for (int i = 0; i < len; i++) {
if (i > 0 && (len - i) % 3 == 0) {
intPartWithCommas[j++] = ',';
}
intPartWithCommas[j++] = temp[i];
}
intPartWithCommas[j] = '\0'; // Null-terminate the string
// Print the string
sprintf(result, "%s.%u", intPartWithCommas, fracPart);
} // end void addCommas
void ProcessMaintRecordScreen() {
int option = 1;
readEntries(SD, "/wokwi.csv");
// Get data
readAndProcess(SD, "/wokwi.csv");
Display.fillScreen(0xFFFF);
//drawTitleBar("Maintenace Record");
// Table header
Display.fillRect(1, 40, 320-1, 29, 0x4208);
Display.setTextColor(0xFFFF);
//Display.setTTFFont(Arial_8_Bold);
Display.setFont(&FONT_SMALL);
Display.setCursor(7, 61 );
//Display.print(F("Date"));
Display.print("Date");
//Display.fillRect(63, 40, 69, 29, 0x4208);
//Display.setTextColor(0xFFFF);
//Display.setTTFFont(Arial_8_Bold);
//Display.setFont(&FONT_SMALL);
Display.setCursor(76, 61 );
//Display.print(F("Mileage"));
Display.print("Mileage");
//Display.fillRect(133, 40, 186, 29, 0x4208);
//Display.setTextColor(0xFFFF);
//Display.setTTFFont(Arial_8_Bold);
//Display.setFont(&FONT_SMALL);
Display.setCursor(139, 61 );
//Display.print(F("Notes"));
Display.print("Notes");
maintenanceRecScreen(dateL, milesL, noteL, dataIndex);
// Make buttons act as encoder
while (option != 0) {
if (digitalRead(PREV_PIN) == LOW) {
// debounce the button press
while (digitalRead(PREV_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("PREV Pressed");
// Scroll screen up
if (dataIndex < dataEntries) {
dataIndex++;
readAndProcess(SD, "/wokwi.csv");
maintenanceRecScreen(dateL, milesL, noteL, dataIndex);
} else if (dataIndex == dataEntries) {
readAndProcess(SD, "/wokwi.csv");
dataIndex++;
Serial.println("Top Reached");
maintenanceRecScreen(dateL, milesL, noteL, dataIndex, 2); // top reached
}
}
if (digitalRead(NEXT_PIN) == LOW) {
// debounce the button press
while (digitalRead(NEXT_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("NEXT Pressed");
// Scroll screen down
if (dataIndex > linesOnScreen) {
dataIndex--;
readAndProcess(SD, "/wokwi.csv");
maintenanceRecScreen(dateL, milesL, noteL, dataIndex);
} else if (dataIndex == linesOnScreen) {
readAndProcess(SD, "/wokwi.csv");
dataIndex--;
Serial.println("Bottom Reached");
maintenanceRecScreen(dateL, milesL, noteL, dataIndex, 1); // bottom reached
}
}
if (digitalRead(MENU_PIN) == LOW) {
// debounce the button press
while (digitalRead(MENU_PIN) == LOW) {
delay(DEBOUNCE);
}
Serial.println("MENU Pressed");
// exit menu
option = 0;
dataIndex = dataEntries;
}
}
}
// Poputale Maintenance record screen with info in dateL, milesL, noteL
// Optional argument showMessage to display if bottom or top is reached
void maintenanceRecScreen(char date[4][11], char miles[4][8], char note[4][maxLen], int num, int showMessage) {
bool isEven = (num % 2 == 0);
int color1 = isEven ? 0xDEDB : 0xF79E;
int color2 = isEven ? 0xF79E : 0xDEDB;
Display.fillRect(1, 69, 160, 320-1, color1);
Display.setTextColor(0x0000);
Display.setFont(&FONT_SMALL);
for (int i = 0; i < 4; i++) {
Display.fillRect(1, 69 + i * 44, 320-1, 44, (i % 2 == 0) ? color1 : color2);
if (showMessage == 1) {
if (i == 3) {
// Display the message on the last line
Display.setCursor(139, 97 + i * 44);
Display.print("BOTTOM REACHED");
} else {
// Shift the data up by one line
Display.setCursor(7, 97 + i * 44);
Display.print(date[i + 1]);
Display.setCursor(76, 97 + i * 44);
Display.print(miles[i + 1]);
Display.setCursor(139, 97 + i * 44);
Display.print(note[i + 1]);
}
}
else if (showMessage == 2) {
if (i == 0) {
// Display the message on the first line
Display.setCursor(139, 97 + i * 44);
Display.print("TOP REACHED");
} else {
// Shift the data up by one line
Display.setCursor(7, 97 + i * 44);
Display.print(date[i - 1]);
Display.setCursor(76, 97 + i * 44);
Display.print(miles[i - 1]);
Display.setCursor(139, 97 + i * 44);
Display.print(note[i - 1]);
}
}
// Display the data entries as usual
else {
Display.setCursor(7, 97 + i * 44);
Display.print(date[i]);
Display.setCursor(76, 97 + i * 44);
Display.print(miles[i]);
Display.setCursor(139, 97 + i * 44);
Display.print(note[i]);
}
}
Display.drawFastHLine(1, 40, 319, 0xFFFF);
Display.drawFastHLine(1, 69, 319, 0xFFFF);
Display.drawFastHLine(1, 113, 319, 0xFFFF);
Display.drawFastHLine(1, 157, 319, 0xFFFF);
Display.drawFastHLine(1, 201, 319, 0xFFFF);
Display.drawFastHLine(1, 238, 319, 0xFFFF);
Display.drawFastHLine(1, 40, 319, 0xFFFF);
Display.drawFastVLine(1, 40, 207, 0xFFFF);
Display.drawFastVLine(70, 40, 207, 0xFFFF);
Display.drawFastVLine(133, 40, 207, 0xFFFF);
Display.drawFastVLine(319, 40, 207, 0xFFFF);
}
// ############################################################
// #### SD CARD FUNCTIONS #########
// ############################################################
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
Serial.printf("Listing directory: %s\n", dirname);
File root = fs.open(dirname);
if(!root){
Serial.println("Failed to open directory");
return;
}
if(!root.isDirectory()){
Serial.println("Not a directory");
return;
}
File file = root.openNextFile();
while(file){
if(file.isDirectory()){
Serial.print(" DIR : ");
Serial.println(file.name());
if(levels){
listDir(fs, file.path(), levels -1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
// Read first line of file (which indicates the number of data entries)
void readEntries(fs::FS &fs, const char * path){
Serial.printf("Getting entries from: %s\n", path);
File file = fs.open(path);
if(!file){
Serial.println("Failed to open file for reading");
return;
}
char firstLine[3];
file.readBytesUntil('\n', firstLine, sizeof(firstLine));
firstLine[sizeof(firstLine) - 1] = '\0'; // Ensure null termination
dataEntries = atoi(firstLine);
Serial.printf("Data Index: %d\n", dataEntries);
dataIndex = dataEntries;
file.close();
}
// void appendFile(fs::FS &fs, const char * path, const char * message, int newDataEntries){
// Serial.printf("Updating file: %s\n", path);
// // Open file for reading
// File file = fs.open(path, FILE_READ);
// if(!file){
// Serial.println("Failed to open file for reading");
// return;
// }
// // Create a new file
// File newFile = fs.open("/temp.csv", FILE_WRITE);
// if(!newFile){
// Serial.println("Failed to create new file");
// file.close(); // Ensure the original file is closed
// return;
// }
// // Write the new data index to the new file
// newFile.println(newDataEntries);
// // Skip the first line of the original file
// file.readStringUntil('\n');
// // Copy the rest of the original file to the new file
// while(file.available()){
// newFile.write(file.read());
// }
// if(newFile.print(message)){
// Serial.println("Data appended");
// } else {
// Serial.println("Append failed");
// }
// // Close both files
// file.close();
// newFile.close();
// // Delete the original file
// if(!fs.remove(path)){
// Serial.println("Failed to remove original file");
// return;
// }
// // Rename the new file to the original file's name
// if(!fs.rename("/temp.csv", path)){
// Serial.println("Failed to rename new file");
// return;
// }
// Serial.println("File updated successfully");
// }
void sendData(fs::FS &fs, const char * path) {
Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if (!file) {
Serial.println("Failed to open file for reading");
return;
}
while (file.available()) {
// Read a line from the file
char line[64]; // Adjust the size as needed
int i = 0;
while (file.available() && i < sizeof(line) - 1) { // Leave space for null terminator
char c = file.read();
if (c == '\n') {
break;
}
line[i++] = c;
}
line[i] = '\0'; // Null terminate the string
//SerialBT.println(line);
delay(1000); // Send each line with a 1-second delay
}
file.close();
}
// void startA2DP() {
// a2dp_sink.start("ESP32_A2DP");
// Serial.println("A2DP started");
// }
// void stopA2DP() {
// a2dp_sink.end();
// Serial.println("A2DP stopped");
// }
// void startSerial() {
// if (!SerialBT.begin("ESP32_Serial")) {
// Serial.println("An error occurred initializing Bluetooth Serial");
// } else {
// Serial.println("Bluetooth Serial started");
// }
// }
// void stopSerial() {
// SerialBT.end();
// Serial.println("Bluetooth Serial stopped");
// }
void readAndProcess(fs::FS &fs, const char * path){
Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if(!file){
Serial.println("Failed to open file for reading");
return;
}
int lineIndex = 0;
while(file.available()){
// Read a line from the file
char line[11 + 8 + maxLen];
int i = 0;
while(file.available() && i < (11 + 8 + maxLen-1)) { // Date, miles and 49 to leave space for null terminator
char c = file.read();
if(c == '\n') {
break;
}
line[i] = c;
i++;
}
line[i] = '\0'; // Null terminate the string
// Adjust index if there's less data entries in the .csv file
// than there are lines on the screen
int adjustedIndex = lineIndex - dataIndex + (linesOnScreen - 1);
if (dataEntries < linesOnScreen) {
adjustedIndex -= (linesOnScreen - dataEntries);
}
// If this is one of the lines we're interested in, split and store the data
if(lineIndex >= dataIndex - (linesOnScreen - 1) && lineIndex <= dataIndex && lineIndex > 0) {
splitData(line, dateL[adjustedIndex], milesL[adjustedIndex], noteL[adjustedIndex]);
}
lineIndex++;
}
file.close();
}
// Splits data line at delimiter ","
void splitData(char* data, char* date, char* miles, char* note) {
char* token = strtok(data, ",");
strcpy(date, token);
token = strtok(NULL, ",");
strcpy(miles, token);
token = strtok(NULL, ",");
strcpy(note, token);
}
Loading
esp32-s3-devkitc-1
esp32-s3-devkitc-1