kd5rxt-mark
Well-known member
I am working on the next version of my TeensyMIDIPolySynth . . . this one is controlled via TFT sliders & buttons instead of hardware pots, pushbuttons, & LEDs as was used in the original project. I was satisfied with what I had in the initial implementation of the project, but is was impossible to add any more capabilities as it had no place to put any additional pots and/or pushbuttons. So now, by using the TFT, this advanced version of the project is infinitely more versatile & much easier to add/modify/move capabilities. For more capability, I just add more menus (within reason) !!
I have now completed the implementation of all of the previous functionality using the new TFT control interface (using the very nice ILI9341_t3n library: thanks @KurtE !!). Everything is working great. Now that all of the controls are electronic instead of physical, the time has come to implement configuration storage & retrieval to/from EEPROM. This is something that was sorely lacking in the original project (how do you force a physical pot to a particular value upon startup ??). In this new version, everything (EEPROM-related) works great until "Smallest Code" is selected for the compiler optimization, in which case EEPROM writes seem to hang and/or kill SPI.
Symptoms: I can no longer make any control changes on the TFT & the on-board LED (PIN 13 is used for SPI SCLK) extinguishes. Likewise, after a restart, the values in the EEPROM are not correct/complete.
Environment: Windows 10 Pro/64-bit, Arduino 1.8.13 (fresh install) & TD 1.54b6 (fresh install), Teensy4.0, PJRC ILI9341 touchscreen (CS=14, DC=9) using the ILI9341_t3n w/ framebuffer active/used.
Code: included below is a scaled-down version of my latest TeensyMIDIPolySynth which includes just enough code to see the problem in action
Arduino Tools settings: Teensy4.0, USB Type: Serial, CPU Speed: 600MHz, Optimize: (see steps below),
Steps to reproduce the problem:
0) perform a 15-second Blink restore on the Teensy4.0 (to make sure it is factory fresh)
1) set Arduino compiler optimization to "Fastest"
2) build "Teensy-TFT-EEPROM-conflict.ino"
3) install (using PROGRAM button) on a fresh Teensy4.0 & run
4) in Serial Monitor, note that invalid EEPROM contents were detected (as you would expect, since this sketch has not yet saved any settings), so new settings are successfully written to EEPROM
5) perform a 15-second Blink restore on the Teensy4.0 (to make sure it is factory fresh)
6) set Arduino compiler optimization to "Smallest Code"
7) build "Teensy-TFT-EEPROM-conflict.ino"
8) install (using PROGRAM button) on a fresh Teensy4.0 & run
9) in Serial Monitor, little to nothing shows up (& on-board LED, which is SPI SCLK, is extinguished)
10) Teensy4.0 appears to be hung
Under the "Smallest Code" compiler optimization, once the code has been loaded, each time the Teensy4.0 is unplugged/plugged, it will attempt to write fresh setting values to the EEPROM. After 14 unplug/plug cycles, the serial monitor will show that the settings were successfully written to EEPROM (as if one EEPROM location were successfully written with each of the power-on cycles - first location on the first run right after programming, & the remaining 14 w/ each of the unplug/plug cycles). Likewise, after it successfully continues to run, if you change only one slider, it will take 2 unplug/plug cycles to remain running - one EEPROM write seems to succeed when the slider change was detected, & the CHECKSUM & INVERSE CHECKSUM EEPROM writes seem to succeed in the additional 2 unplug/plug cycles).
Also, under any compiler optimization other than "Smallest Code", changes can be made to the sliders on the TFT touchscreen & 5-seconds after the last change, new settings values will be written to the EEPROM successfully. Unfortunately, because of the amount of code & variables in my latest TeensyMIDIPolySynth, I have had to use the "Smallest Code" optimization as that is the only way my sketch variables fit in available RAM.
Please let me know if you are able to reproduce this failure to write to EEPROM under the "Smallest Code" compiler optimization, or if you see something silly either that I've done, or that I've forgotten to do !!
Thanks,
Mark J Culross
KD5RXT
CODE:
I have now completed the implementation of all of the previous functionality using the new TFT control interface (using the very nice ILI9341_t3n library: thanks @KurtE !!). Everything is working great. Now that all of the controls are electronic instead of physical, the time has come to implement configuration storage & retrieval to/from EEPROM. This is something that was sorely lacking in the original project (how do you force a physical pot to a particular value upon startup ??). In this new version, everything (EEPROM-related) works great until "Smallest Code" is selected for the compiler optimization, in which case EEPROM writes seem to hang and/or kill SPI.
Symptoms: I can no longer make any control changes on the TFT & the on-board LED (PIN 13 is used for SPI SCLK) extinguishes. Likewise, after a restart, the values in the EEPROM are not correct/complete.
Environment: Windows 10 Pro/64-bit, Arduino 1.8.13 (fresh install) & TD 1.54b6 (fresh install), Teensy4.0, PJRC ILI9341 touchscreen (CS=14, DC=9) using the ILI9341_t3n w/ framebuffer active/used.
Code: included below is a scaled-down version of my latest TeensyMIDIPolySynth which includes just enough code to see the problem in action
Arduino Tools settings: Teensy4.0, USB Type: Serial, CPU Speed: 600MHz, Optimize: (see steps below),
Steps to reproduce the problem:
0) perform a 15-second Blink restore on the Teensy4.0 (to make sure it is factory fresh)
1) set Arduino compiler optimization to "Fastest"
2) build "Teensy-TFT-EEPROM-conflict.ino"
3) install (using PROGRAM button) on a fresh Teensy4.0 & run
4) in Serial Monitor, note that invalid EEPROM contents were detected (as you would expect, since this sketch has not yet saved any settings), so new settings are successfully written to EEPROM
Code:
Attempting to read saved settings from EEPROM
(READ 000: 255)
(READ 001: 255)
(READ 002: 255)
(READ 003: 255)
(READ 004: 255)
(READ 005: 255)
(READ 006: 255)
(READ 007: 255)
(READ 008: 255)
(READ 009: 255)
(READ 010: 255)
(READ 011: 255)
(READ 012: 255)
(READ 013: 255)
(READ 014: 255)
Invalid settings found in EEPROM
(READ 013) xor_value = 255
(CALC) xor_result = 178
(READ 014) inv_xor_value = 255
(CALC) inv_xor_result = 77
Saving settings to EEPROM
(WRITE 000: 084) Header[0] = T
(WRITE 001: 049) Header[1] = 1
(WRITE 002: 050) Header[2] = 2
(WRITE 003: 080) Header[3] = P
(WRITE 004: 083) Header[4] = S
(WRITE 005: 255) Main Volume Slider = 1.00
(WRITE 006: 191) Main Level A Slider = 0.75
(WRITE 007: 191) Main Level B Slider = 0.75
(WRITE 008: 191) Main Level C Slider = 0.75
(WRITE 009: 127) Main Tuning Slider = 0.00
(WRITE 010: 127) Main Tuning A Slider = 0.00
(WRITE 011: 127) Main Tuning B Slider = 0.00
(WRITE 012: 127) Main Tuning C Slider = 0.00
(WRITE 013: 089) Calculated CHECKSUM = 089
(WRITE 014: 166) Calculated INVERSE CHECKSUM = 166
5) perform a 15-second Blink restore on the Teensy4.0 (to make sure it is factory fresh)
6) set Arduino compiler optimization to "Smallest Code"
7) build "Teensy-TFT-EEPROM-conflict.ino"
8) install (using PROGRAM button) on a fresh Teensy4.0 & run
9) in Serial Monitor, little to nothing shows up (& on-board LED, which is SPI SCLK, is extinguished)
10) Teensy4.0 appears to be hung
Under the "Smallest Code" compiler optimization, once the code has been loaded, each time the Teensy4.0 is unplugged/plugged, it will attempt to write fresh setting values to the EEPROM. After 14 unplug/plug cycles, the serial monitor will show that the settings were successfully written to EEPROM (as if one EEPROM location were successfully written with each of the power-on cycles - first location on the first run right after programming, & the remaining 14 w/ each of the unplug/plug cycles). Likewise, after it successfully continues to run, if you change only one slider, it will take 2 unplug/plug cycles to remain running - one EEPROM write seems to succeed when the slider change was detected, & the CHECKSUM & INVERSE CHECKSUM EEPROM writes seem to succeed in the additional 2 unplug/plug cycles).
Also, under any compiler optimization other than "Smallest Code", changes can be made to the sliders on the TFT touchscreen & 5-seconds after the last change, new settings values will be written to the EEPROM successfully. Unfortunately, because of the amount of code & variables in my latest TeensyMIDIPolySynth, I have had to use the "Smallest Code" optimization as that is the only way my sketch variables fit in available RAM.
Please let me know if you are able to reproduce this failure to write to EEPROM under the "Smallest Code" compiler optimization, or if you see something silly either that I've done, or that I've forgotten to do !!
Thanks,
Mark J Culross
KD5RXT
CODE:
Code:
//
// Scaled down version of Teensy MIDI (12-note / 3-voice) TFT-Controlled Polyphonic Synthesizer - version 1.7 dated 20210205-1835
//
// - written by Mark J Culross (KD5RXT)
//
// - can read MIDI data & controls/commands from any of three sources:
// 1) traditional (serial) MIDI thru the MIDI DIN plugs/cables
// 1) USB MIDI (play MIDI files from PC thru this MIDI device)
// 3) connect a USB MIDI device (keyboard) the the USB Host of this device
//
// - plays the indicated note(s) in three voices, with the specified audio characteristics
//
// - appears as MIDI device "Teensy-MIDI-12-PolySynth"
//
// See documentation on MIDI callbacks here:
// https://github.com/FortySevenEffects/arduino_midi_library/wiki/Using-Callbacks
//
//
// Arduino IDE Configuration:
// Tools/Board: "Teensy 4.0"
// Tools/USB Type: "Serial"
// Tools/CPU Speed: "600MHz"
// Tools/Optimize: "Smallest Code"
// Tools/Keyboard Layout: "US English"
// Tools/Port: "COMx Serial (Teensy 4.0)"
//
String VERSION1 = "Teensy-MIDI-TFT-PolySynth";
String VERSION2 = "version 1.7 dated 02/05/2021 @1835";
String VERSION3 = "designed & written by Mark J Culross (KD5RXT)";
#define DEBUG_EEPROM_READ // uncomment to show specifics of EEPROM reads
#define DEBUG_EEPROM_WRITE // uncomment to show specifics of EEPROM writes
//#define DISABLE_EEPROM_READ_SETTINGS // uncomment to prevent reading settings from EEPROM
//#define DISABLE_EEPROM_WRITE_SETTINGS // uncomment to prevent writing settings to EEPROM
#include <ILI9341_t3n.h>
#include <XPT2046_Touchscreen.h>
#include <EEPROM.h>
// This is calibration data for mapping the raw touch data to the screen coordinates (for my particular PJRC ILI9341 TFT display)
const int TS_MINX = 200;
const int TS_MINY = 250;
const int TS_MAXX = 3750;
const int TS_MAXY = 3900;
// when used w/ Audio Adapter, must use an alternate CS pin for the display
const int TFT_CHIP_SELECT = 14;
const int TFT_DATA_COMMAND = 9;
ILI9341_t3n tft = ILI9341_t3n(TFT_CHIP_SELECT, TFT_DATA_COMMAND);
// create TFT framebuffer
DMAMEM uint16_t framebuf[320 * 240];
// when used w/ Audio Adapter, must use an alternate CS pin for the touchscreen
#define TS_CS_PIN 5
XPT2046_Touchscreen ts(TS_CS_PIN, 255);
//
// The following pins are used in this project:
//
// PIN D1 = (not used)
// PIN D2 = (not used)
// PIN D3 = (not used)
// PIN D4 = (not used)
// PIN D5 = TouchScreen chip select (alternate when used w/ audio adapter)
// PIN D6 = Audio adapter memory chip select
// PIN D7 = Audio adapter data in
// PIN D8 = Audio adapter data out
// PIN D9 = TFT/TS data/command select
// PIN D10 = Audio adapter SD card chip select
// PIN D11 = SPI MOSI (data in)
// PIN D12 = SPI MISO (data out)
// PIN D13 = SPI serial clock + on-board LED
// PIN A0 = (D14) TFT chip select (alternate when used w/ audio adapter)
// PIN A1 = Volume pot on audio adapter
// PIN A2 = (not used)
// PIN A3 = (not used)
// PIN A4 = (D18) Audio adapter SDA (I2C control data)
// PIN A5 = (D19) Audio adapter SCL (I2C control clock)
// onboard LED on pin 13
#define LED_PIN 13
// keep track of how often to repaint the display
#define SCREEN_UPDATE_MILLIS 125
unsigned long screen_update_time = millis();
// keep track of when the screen needs to be updated
bool screen_update_required = false;
// manage accumulating variable changes to reduce EEPROM writes
#define SAVE_DELAY_MILLIS 5000
unsigned long save_delay_millis = 0;
bool save_needed = false;
// custom ILI9341 TFT colors (5-bit RED, 6-bit GREEN, 5-bit BLUE)
#define ILI9341_SHADOWGREY 0x8414 // SHADOWGREY: 0x8414 = 10000 100000 10100 LIGHTGREY: 0xC618 = 11000 110000 11000
typedef enum
{
CONFIG_MODE_MAIN=0,
} CONFIG_MODE;
CONFIG_MODE config_mode = CONFIG_MODE_MAIN;
boolean previously_touched = false;
boolean touch_triggered = false;
// global touchscreen coordinates (in pixels) where touched
int BtnX, BtnY;
int previousBtnX = -1, previousBtnY = -1;
struct BUTTON_TYPE
{
unsigned int xCenterLoc;
unsigned int yCenterLoc;
unsigned int xSize;
unsigned int ySize;
String* textPtr;
uint16_t textColor;
uint16_t buttonColor;
uint16_t borderColor;
bool activated;
};
// MAIN BUTTONS
String mainVolumeButtonText = "VOL";
BUTTON_TYPE mainVolumeButton = { 16, 88, 28, 15, &mainVolumeButtonText, ILI9341_GREEN, ILI9341_BLACK, ILI9341_RED, true };
String mainLevelAButtonText = "LvlA";
BUTTON_TYPE mainLevelAButton = { 53, 88, 28, 15, &mainLevelAButtonText, ILI9341_GREEN, ILI9341_BLACK, ILI9341_RED, true };
String mainLevelBButtonText = "LvlB";
BUTTON_TYPE mainLevelBButton = { 90, 88, 28, 15, &mainLevelBButtonText, ILI9341_GREEN, ILI9341_BLACK, ILI9341_RED, true };
String mainLevelCButtonText = "LvlC";
BUTTON_TYPE mainLevelCButton = {127, 88, 28, 15, &mainLevelCButtonText, ILI9341_GREEN, ILI9341_BLACK, ILI9341_RED, true };
String mainTuningButtonText = "TUNE";
BUTTON_TYPE mainTuningButton = {189, 88, 28, 15, &mainTuningButtonText, ILI9341_GREEN, ILI9341_BLACK, ILI9341_RED, true };
String mainTuningAButtonText = "TunA";
BUTTON_TYPE mainTuningAButton = {226, 88, 28, 15, &mainTuningAButtonText, ILI9341_GREEN, ILI9341_BLACK, ILI9341_RED, true };
String mainTuningBButtonText = "TunB";
BUTTON_TYPE mainTuningBButton = {263, 88, 28, 15, &mainTuningBButtonText, ILI9341_GREEN, ILI9341_BLACK, ILI9341_RED, true };
String mainTuningCButtonText = "TunC";
BUTTON_TYPE mainTuningCButton = {300, 88, 28, 15, &mainTuningCButtonText, ILI9341_GREEN, ILI9341_BLACK, ILI9341_RED, true };
typedef enum
{
SLIDER_MODE_HORIZONTAL=0, SLIDER_MODE_VERTICAL
} SLIDER_MODE;
struct SLIDER_TYPE
{
unsigned int xCenterLoc;
unsigned int yCenterLoc;
unsigned int xSize;
unsigned int ySize;
float value;
unsigned int placesBeforeTheDecimal;
unsigned int placesAfterTheDecimal;
bool showPlusMinusSign;
float minValue; // for HORIZONTAL = all the way to the left, for VERTICAL, all the way up
float maxValue; // for HORIZONTAL = all the way to the right, for VERTICAL, all the way down
unsigned int xValueCenterLoc;
unsigned int yValueCenterLoc;
uint16_t valueColor;
uint16_t backgroundColor;
uint16_t borderColor;
uint16_t scaleColor;
uint16_t handleColor;
uint16_t handleBorderColor;
uint16_t backgroundColorDisabled;
uint16_t borderColorDisabled;
uint16_t scaleColorDisabled;
uint16_t handleColorDisabled;
uint16_t handleBorderColorDisabled;
bool activated;
SLIDER_MODE orientation;
};
SLIDER_TYPE mainVolumeSlider = { 16, 172, 15, 116, 1.00, 1, 1, true, 0.0, 1.0, 16, 101, ILI9341_WHITE, ILI9341_SHADOWGREY, ILI9341_GREEN, ILI9341_BLACK, ILI9341_GREEN, ILI9341_BLACK, ILI9341_BLACK, ILI9341_SHADOWGREY, ILI9341_SHADOWGREY, ILI9341_SHADOWGREY, ILI9341_BLACK, true, SLIDER_MODE_VERTICAL };
SLIDER_TYPE mainLevelASlider = { 53, 172, 15, 116, 0.75, 1, 1, true, 0.0, 1.0, 53, 101, ILI9341_WHITE, ILI9341_SHADOWGREY, ILI9341_GREEN, ILI9341_BLACK, ILI9341_GREEN, ILI9341_BLACK, ILI9341_BLACK, ILI9341_SHADOWGREY, ILI9341_SHADOWGREY, ILI9341_SHADOWGREY, ILI9341_BLACK, true, SLIDER_MODE_VERTICAL };
SLIDER_TYPE mainLevelBSlider = { 90, 172, 15, 116, 0.75, 1, 1, true, 0.0, 1.0, 90, 101, ILI9341_WHITE, ILI9341_SHADOWGREY, ILI9341_GREEN, ILI9341_BLACK, ILI9341_GREEN, ILI9341_BLACK, ILI9341_BLACK, ILI9341_SHADOWGREY, ILI9341_SHADOWGREY, ILI9341_SHADOWGREY, ILI9341_BLACK, true, SLIDER_MODE_VERTICAL };
SLIDER_TYPE mainLevelCSlider = { 127, 172, 15, 116, 0.75, 1, 1, true, 0.0, 1.0, 127, 101, ILI9341_WHITE, ILI9341_SHADOWGREY, ILI9341_GREEN, ILI9341_BLACK, ILI9341_GREEN, ILI9341_BLACK, ILI9341_BLACK, ILI9341_SHADOWGREY, ILI9341_SHADOWGREY, ILI9341_SHADOWGREY, ILI9341_BLACK, true, SLIDER_MODE_VERTICAL };
SLIDER_TYPE mainTuningSlider = { 189, 172, 15, 116, 0.00, 1, 1, true, -0.5, 0.5, 189, 101, ILI9341_WHITE, ILI9341_SHADOWGREY, ILI9341_GREEN, ILI9341_BLACK, ILI9341_GREEN, ILI9341_BLACK, ILI9341_BLACK, ILI9341_SHADOWGREY, ILI9341_SHADOWGREY, ILI9341_SHADOWGREY, ILI9341_BLACK, true, SLIDER_MODE_VERTICAL };
SLIDER_TYPE mainTuningASlider = { 226, 172, 15, 116, 0.00, 1, 1, true, -0.5, 0.5, 226, 101, ILI9341_WHITE, ILI9341_SHADOWGREY, ILI9341_GREEN, ILI9341_BLACK, ILI9341_GREEN, ILI9341_BLACK, ILI9341_BLACK, ILI9341_SHADOWGREY, ILI9341_SHADOWGREY, ILI9341_SHADOWGREY, ILI9341_BLACK, true, SLIDER_MODE_VERTICAL };
SLIDER_TYPE mainTuningBSlider = { 263, 172, 15, 116, 0.00, 1, 1, true, -0.5, 0.5, 263, 101, ILI9341_WHITE, ILI9341_SHADOWGREY, ILI9341_GREEN, ILI9341_BLACK, ILI9341_GREEN, ILI9341_BLACK, ILI9341_BLACK, ILI9341_SHADOWGREY, ILI9341_SHADOWGREY, ILI9341_SHADOWGREY, ILI9341_BLACK, true, SLIDER_MODE_VERTICAL };
SLIDER_TYPE mainTuningCSlider = { 300, 172, 15, 116, 0.00, 1, 1, true, -1.0, 1.0, 300, 101, ILI9341_WHITE, ILI9341_SHADOWGREY, ILI9341_GREEN, ILI9341_BLACK, ILI9341_GREEN, ILI9341_BLACK, ILI9341_BLACK, ILI9341_SHADOWGREY, ILI9341_SHADOWGREY, ILI9341_SHADOWGREY, ILI9341_BLACK, true, SLIDER_MODE_VERTICAL };
const char EEPROM_HEADER[] = "T12PS";
typedef enum
{
EEPROM_INDEX_HEADER_0=0, EEPROM_INDEX_HEADER_1, EEPROM_INDEX_HEADER_2, EEPROM_INDEX_HEADER_3, EEPROM_INDEX_HEADER_4,
EEPROM_INDEX_MAIN_VOLUME, EEPROM_INDEX_MAIN_LEVEL_A, EEPROM_INDEX_MAIN_LEVEL_B, EEPROM_INDEX_MAIN_LEVEL_C,
EEPROM_INDEX_MAIN_TUNING, EEPROM_INDEX_MAIN_TUNING_A, EEPROM_INDEX_MAIN_TUNING_B, EEPROM_INDEX_MAIN_TUNING_C,
EEPROM_INDEX_CHECKSUM, EEPROM_INDEX_INV_CHECKSUM
} EEPROM_INDEX;
// function headers
void centerDrawText(String text, unsigned int xCenterLoc, unsigned int yCenterLoc, uint16_t textColor, uint16_t textBackground);
bool checkButton(BUTTON_TYPE thisButton);
bool checkSlider(SLIDER_TYPE* thisSlider);
void drawButton(BUTTON_TYPE thisButton);
void drawScreen(void);
void drawSlider(SLIDER_TYPE thisSlider);
void loop();
void readSettings(void);
void saveSettings(void);
void setup();
void showIndex(int index);
// draw text, centered around xLoc & yLoc
void centerDrawText(String text, unsigned int xCenterLoc, unsigned int yCenterLoc, uint16_t textColor, uint16_t textBackground)
{
unsigned int xOffset = (text.length() / 2) * 6;
unsigned int yOffset = 3;
if (text.length() % 2)
{
xOffset += 3;
}
tft.setTextColor(textColor, textBackground);
tft.setTextSize(1);
tft.setCursor(xCenterLoc - xOffset, yCenterLoc - yOffset);
tft.print(text);
} // centerDrawText
// check if a button was pressed
bool checkButton(BUTTON_TYPE thisButton)
{
bool retVal = false;
// if touched most recently in thisButton
if ((BtnX >= (int)(thisButton.xCenterLoc - (thisButton.xSize / 2))) &&
(BtnX <= (int)(thisButton.xCenterLoc + (thisButton.xSize / 2))) &&
(BtnY >= (int)(thisButton.yCenterLoc - (thisButton.ySize / 2))) &&
(BtnY <= (int)(thisButton.yCenterLoc + (thisButton.ySize / 2))))
{
retVal = true;
}
return(retVal);
} // checkButton()
// check if a slider has changed
bool checkSlider(SLIDER_TYPE* thisSlider)
{
bool retVal = false;
float newValue = 0.0;
// if thisSlider is active & touched most recently in thisSlider
if ((thisSlider->activated) &&
(BtnX >= (int)(thisSlider->xCenterLoc - (thisSlider->xSize / 2))) &&
(BtnX <= (int)(thisSlider->xCenterLoc + (thisSlider->xSize / 2))) &&
(BtnY >= (int)(thisSlider->yCenterLoc - (thisSlider->ySize / 2))) &&
(BtnY <= (int)(thisSlider->yCenterLoc + (thisSlider->ySize / 2))))
{
if (thisSlider->orientation == SLIDER_MODE_HORIZONTAL)
{
newValue = (float)map((float)BtnX, (float)(thisSlider->xCenterLoc - (thisSlider->xSize / 2)), (float)(thisSlider->xCenterLoc + (thisSlider->xSize / 2)), thisSlider->maxValue, thisSlider->minValue);
} else {
newValue = (float)map((float)BtnY, (float)(thisSlider->yCenterLoc - (thisSlider->ySize / 2)), (float)(thisSlider->yCenterLoc + (thisSlider->ySize / 2)), thisSlider->maxValue, thisSlider->minValue);
}
if (newValue != thisSlider->value)
{
thisSlider->value = newValue;
drawSlider(*thisSlider);
retVal = true;
}
}
return(retVal);
} // checkSlider()
// draw a button
void drawButton(BUTTON_TYPE thisButton)
{
if (thisButton.activated)
{
tft.fillRect(thisButton.xCenterLoc - (thisButton.xSize / 2) + 1, thisButton.yCenterLoc - (thisButton.ySize / 2) + 1, thisButton.xSize - 2, thisButton.ySize - 2, thisButton.buttonColor);
tft.drawRect(thisButton.xCenterLoc - (thisButton.xSize / 2), thisButton.yCenterLoc - (thisButton.ySize / 2), thisButton.xSize, thisButton.ySize, thisButton.borderColor);
centerDrawText(*(thisButton.textPtr), thisButton.xCenterLoc, thisButton.yCenterLoc, thisButton.textColor, thisButton.buttonColor);
} else {
tft.fillRect(thisButton.xCenterLoc - (thisButton.xSize / 2) + 1, thisButton.yCenterLoc - (thisButton.ySize / 2) + 1, thisButton.xSize - 2, thisButton.ySize - 2, thisButton.borderColor);
tft.drawRect(thisButton.xCenterLoc - (thisButton.xSize / 2), thisButton.yCenterLoc - (thisButton.ySize / 2), thisButton.xSize, thisButton.ySize, thisButton.buttonColor);
centerDrawText(*(thisButton.textPtr), thisButton.xCenterLoc, thisButton.yCenterLoc, thisButton.textColor, thisButton.borderColor);
}
} // drawButton()
// update the screen based upon the current mode
void drawScreen(void)
{
// clear the unique portion of the display screen
tft.fillRect(0, 80, 320, 160, ILI9341_BLACK);
// update screen using the current config mode
switch(config_mode)
{
case CONFIG_MODE_MAIN:
{
tft.setTextSize(1);
tft.setTextColor(ILI9341_WHITE);
drawSlider(mainVolumeSlider);
drawButton(mainVolumeButton);
drawSlider(mainTuningSlider);
drawButton(mainTuningButton);
drawSlider(mainLevelASlider);
drawButton(mainLevelAButton);
drawSlider(mainTuningASlider);
drawButton(mainTuningAButton);
drawSlider(mainLevelBSlider);
drawButton(mainLevelBButton);
drawSlider(mainTuningBSlider);
drawButton(mainTuningBButton);
drawSlider(mainLevelCSlider);
drawButton(mainLevelCButton);
drawSlider(mainTuningCSlider);
drawButton(mainTuningCButton);
}
break;
}
} // drawScreen()
// draw a slider
void drawSlider(SLIDER_TYPE thisSlider)
{
int characterCount = 0;
String outString = "";
if (thisSlider.orientation == SLIDER_MODE_HORIZONTAL)
{
if (thisSlider.activated)
{
// clear the entire slider
tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 2, thisSlider.xSize + 15, thisSlider.ySize + 4, thisSlider.backgroundColor);
// draw the slider outline
tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 2, thisSlider.xSize + 15, thisSlider.ySize + 4, thisSlider.borderColor);
// draw the slider handle
tft.fillCircle((int)map(thisSlider.value, thisSlider.minValue, thisSlider.maxValue, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.xCenterLoc + (thisSlider.xSize / 2)), (int)thisSlider.yCenterLoc, 6, thisSlider.handleColor);
tft.drawCircle((int)map(thisSlider.value, thisSlider.minValue, thisSlider.maxValue, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.xCenterLoc + (thisSlider.xSize / 2)), (int)thisSlider.yCenterLoc, 6, thisSlider.handleBorderColor);
tft.drawCircle((int)map(thisSlider.value, thisSlider.minValue, thisSlider.maxValue, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.xCenterLoc + (thisSlider.xSize / 2)), (int)thisSlider.yCenterLoc, 7, thisSlider.handleBorderColor);
// draw the slider lines
tft.drawLine(thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc, thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc, thisSlider.scaleColor);
tft.drawLine(thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc - 3, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc + 3, thisSlider.scaleColor); // left end
tft.drawLine(thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc - 3, thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc + 3, thisSlider.scaleColor); // right end
tft.drawLine(thisSlider.xCenterLoc, thisSlider.yCenterLoc - 2, thisSlider.xCenterLoc, thisSlider.yCenterLoc + 2, thisSlider.scaleColor); // center
} else {
// clear the entire slider
tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 2, thisSlider.xSize + 15, thisSlider.ySize + 4, thisSlider.backgroundColorDisabled);
// draw the slider outline
tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 2, thisSlider.xSize + 15, thisSlider.ySize + 4, thisSlider.borderColorDisabled);
// draw the slider handle
tft.fillCircle((int)map(thisSlider.value, thisSlider.minValue, thisSlider.maxValue, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.xCenterLoc + (thisSlider.xSize / 2)), (int)thisSlider.yCenterLoc, 6, thisSlider.handleColorDisabled);
tft.drawCircle((int)map(thisSlider.value, thisSlider.minValue, thisSlider.maxValue, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.xCenterLoc + (thisSlider.xSize / 2)), (int)thisSlider.yCenterLoc, 6, thisSlider.handleBorderColorDisabled);
tft.drawCircle((int)map(thisSlider.value, thisSlider.minValue, thisSlider.maxValue, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.xCenterLoc + (thisSlider.xSize / 2)), (int)thisSlider.yCenterLoc, 7, thisSlider.handleBorderColorDisabled);
// draw the slider lines
tft.drawLine(thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc, thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc, thisSlider.scaleColorDisabled);
tft.drawLine(thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc - 3, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc + 3, thisSlider.scaleColorDisabled); // left end
tft.drawLine(thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc - 3, thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc + 3, thisSlider.scaleColorDisabled); // right end
tft.drawLine(thisSlider.xCenterLoc, thisSlider.yCenterLoc - 2, thisSlider.xCenterLoc, thisSlider.yCenterLoc + 2, thisSlider.scaleColorDisabled); // center
}
} else {
if (thisSlider.activated)
{
// clear the entire slider
tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 7, thisSlider.xSize + 6, thisSlider.ySize + 15, thisSlider.backgroundColor);
// draw the slider outline
tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 7, thisSlider.xSize + 6, thisSlider.ySize + 15, thisSlider.borderColor);
// draw the slider handle
tft.fillCircle(thisSlider.xCenterLoc, (int)map(thisSlider.value, thisSlider.maxValue, thisSlider.minValue, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.yCenterLoc + (thisSlider.ySize / 2)), 6, thisSlider.handleColor);
tft.drawCircle(thisSlider.xCenterLoc, (int)map(thisSlider.value, thisSlider.maxValue, thisSlider.minValue, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.yCenterLoc + (thisSlider.ySize / 2)), 6, thisSlider.handleBorderColor);
tft.drawCircle(thisSlider.xCenterLoc, (int)map(thisSlider.value, thisSlider.maxValue, thisSlider.minValue, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.yCenterLoc + (thisSlider.ySize / 2)), 7, thisSlider.handleBorderColor);
// draw the slider lines
tft.drawLine(thisSlider.xCenterLoc, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.xCenterLoc, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.scaleColor);
tft.drawLine(thisSlider.xCenterLoc - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.xCenterLoc + 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.scaleColor); // top end
tft.drawLine(thisSlider.xCenterLoc - 3, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.xCenterLoc + 3, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.scaleColor); // bottom end
tft.drawLine(thisSlider.xCenterLoc - 2, thisSlider.yCenterLoc, thisSlider.xCenterLoc + 2, thisSlider.yCenterLoc, thisSlider.scaleColor); // center
} else {
// clear the entire slider
tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 7, thisSlider.xSize + 6, thisSlider.ySize + 15, thisSlider.backgroundColorDisabled);
// draw the slider outline
tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 7, thisSlider.xSize + 6, thisSlider.ySize + 15, thisSlider.borderColorDisabled);
// draw the slider handle
tft.fillCircle(thisSlider.xCenterLoc, (int)map(thisSlider.value, thisSlider.maxValue, thisSlider.minValue, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.yCenterLoc + (thisSlider.ySize / 2)), 6, thisSlider.handleColorDisabled);
tft.drawCircle(thisSlider.xCenterLoc, (int)map(thisSlider.value, thisSlider.maxValue, thisSlider.minValue, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.yCenterLoc + (thisSlider.ySize / 2)), 6, thisSlider.handleBorderColorDisabled);
tft.drawCircle(thisSlider.xCenterLoc, (int)map(thisSlider.value, thisSlider.maxValue, thisSlider.minValue, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.yCenterLoc + (thisSlider.ySize / 2)), 7, thisSlider.handleBorderColorDisabled);
// draw the slider lines
tft.drawLine(thisSlider.xCenterLoc, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.xCenterLoc, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.scaleColorDisabled);
tft.drawLine(thisSlider.xCenterLoc - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.xCenterLoc + 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.scaleColorDisabled); // top end
tft.drawLine(thisSlider.xCenterLoc - 3, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.xCenterLoc + 3, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.scaleColorDisabled); // bottom end
tft.drawLine(thisSlider.xCenterLoc - 2, thisSlider.yCenterLoc, thisSlider.xCenterLoc + 2, thisSlider.yCenterLoc, thisSlider.scaleColorDisabled); // center
}
}
characterCount = thisSlider.placesBeforeTheDecimal + thisSlider.placesAfterTheDecimal;
if (thisSlider.placesAfterTheDecimal != 0)
{
// add one character for the decimal point
characterCount++;
}
if (thisSlider.showPlusMinusSign)
{
// add one for the +/- sign
characterCount++;
if (thisSlider.value >= 0.0)
{
outString = outString + "+";
} else {
outString = outString + "-";
}
}
switch (thisSlider.placesBeforeTheDecimal)
{
case 5:
{
if (thisSlider.value < 10000.0)
{
characterCount--;
} else {
outString = outString + (char)(((int)(abs(thisSlider.value)) / 10000) + 0x30);
}
}
// no break, so fall-thru
case 4:
{
if (thisSlider.value < 1000)
{
characterCount--;
} else {
outString = outString + (char)((((int)(abs(thisSlider.value)) % 10000) / 1000) + 0x30);
}
}
// no break, so fall-thru
case 3:
{
if (thisSlider.value < 100)
{
characterCount--;
} else {
outString = outString + (char)((((int)(abs(thisSlider.value)) % 1000) / 100) + 0x30);
}
}
// no break, so fall-thru
case 2:
{
if (thisSlider.value < 10)
{
characterCount--;
} else {
outString = outString + (char)((((int)(abs(thisSlider.value)) % 100) / 10) + 0x30);
}
}
// no break, so fall-thru
}
outString = outString + (char)(((int)(abs(thisSlider.value)) % 10) + 0x30);
if (thisSlider.placesAfterTheDecimal != 0)
{
outString = outString + ".";
}
switch (thisSlider.placesAfterTheDecimal)
{
case 1:
{
outString = outString + (char)(((int)((abs(thisSlider.value) * 10.0)) % 10) + 0x30);
}
break;
case 2:
{
outString = outString + (char)(((int)((abs(thisSlider.value) * 10.0)) % 10) + 0x30);
outString = outString + (char)(((int)((abs(thisSlider.value) * 100.0)) % 10) + 0x30);
}
break;
}
tft.fillRect(thisSlider.xValueCenterLoc - ((thisSlider.placesBeforeTheDecimal + thisSlider.placesAfterTheDecimal + 2) * 3), thisSlider.yValueCenterLoc - 4, (thisSlider.placesBeforeTheDecimal + thisSlider.placesAfterTheDecimal + 2) * 6, 8, ILI9341_BLACK);
centerDrawText(outString, thisSlider.xValueCenterLoc + 1, thisSlider.yValueCenterLoc, thisSlider.valueColor, ILI9341_BLACK);
} // drawSlider()
// main loop
void loop()
{
bool screen_change = false;
// if the touchscreen is being touched anywhere
if (processTouchscreen())
{
switch(config_mode)
{
case CONFIG_MODE_MAIN:
{
if (checkSlider(&mainVolumeSlider))
{
screen_update_required = true;
save_needed = true;
}
if (checkSlider(&mainTuningSlider))
{
screen_update_required = true;
save_needed = true;
}
if (checkSlider(&mainLevelASlider))
{
screen_update_required = true;
save_needed = true;
}
if (checkSlider(&mainTuningASlider))
{
screen_update_required = true;
save_needed = true;
}
if (checkSlider(&mainLevelBSlider))
{
screen_update_required = true;
save_needed = true;
}
if (checkSlider(&mainTuningBSlider))
{
screen_update_required = true;
save_needed = true;
}
if (checkSlider(&mainLevelCSlider))
{
screen_update_required = true;
save_needed = true;
}
if (checkSlider(&mainTuningCSlider))
{
screen_update_required = true;
save_needed = true;
}
}
break;
}
} else {
// if the touchscreen was touched, but is no longer being touched
if (touch_triggered)
{
touch_triggered = false;
switch(config_mode)
{
case CONFIG_MODE_MAIN:
{
if (checkButton(mainTuningButton))
{
mainTuningSlider.value = 0.0;
drawSlider(mainTuningSlider);
screen_update_required = true;
save_needed = true;
}
if (checkButton(mainTuningAButton))
{
mainTuningASlider.value = 0.0;
drawSlider(mainTuningASlider);
screen_update_required = true;
save_needed = true;
}
if (checkButton(mainTuningBButton))
{
mainTuningBSlider.value = 0.0;
drawSlider(mainTuningBSlider);
screen_update_required = true;
save_needed = true;
}
if (checkButton(mainTuningCButton))
{
mainTuningCSlider.value = 0.0;
drawSlider(mainTuningCSlider);
screen_update_required = true;
save_needed = true;
}
}
break;
}
if (screen_change)
{
drawScreen();
screen_change = false;
screen_update_required = true;
}
BtnX = BtnY = -1;
}
}
// see if a save has been requested
if (save_needed == true)
{
save_needed = false;
// initialize the save accumulator delay timer
save_delay_millis = millis();
} else {
// if a delay is in progress & the dealy timer period is exceeded
if ((save_delay_millis > 0) && ((millis() - save_delay_millis) > SAVE_DELAY_MILLIS))
{
// reset the save accumulator delay timer
save_delay_millis = 0;
// actually save everything to EEPROM
saveSettings();
}
}
if ((screen_update_required) && (millis() > screen_update_time))
{
screen_update_time = millis() + SCREEN_UPDATE_MILLIS;
screen_update_required = false;
tft.updateScreen();
}
} // loop()
// process any touchscreen activity
bool processTouchscreen(void)
{
int i = 5;
TS_Point p = ts.getPoint();
if ((!ts.touched()) && (previously_touched))
{
touch_triggered = true;
}
if (ts.touched())
{
// Scale from raw to tft values to expected width & height using the calibration #'s
BtnX = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
BtnY = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
// see if we can't settle the touchpoint a little
while ((BtnX != previousBtnX) && (BtnY != previousBtnY) && (--i > 0))
{
previousBtnX = BtnX;
previousBtnY = BtnY;
// Scale from raw to tft values to expected width & height using the calibration #'s
BtnX = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
BtnY = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
}
previously_touched = true;
} else {
previously_touched = false;
}
return (ts.touched()); // whether the touchscreen is being touched or not
} // processTouchscreen()
// read the current settings from EEPROM
void readSettings(void)
{
byte eeprom_value, xor_value, inv_xor_value;
byte xor_result = 0x4D; // start with a non-zero value
bool header_is_good = true;
#ifdef DEBUG_EEPROM_READ
Serial.println("");
Serial.println("Attempting to read saved settings from EEPROM");
#endif
for (int eeprom_index = (int)(EEPROM_INDEX_HEADER_0); eeprom_index <= (int)(EEPROM_INDEX_INV_CHECKSUM); eeprom_index++)
{
EEPROM.get(eeprom_index, eeprom_value);
if (eeprom_index < EEPROM_INDEX_CHECKSUM)
{
xor_result = xor_result ^ eeprom_value;
}
#ifdef DEBUG_EEPROM_READ
Serial.print("(READ ");
showIndex(eeprom_index);
Serial.print(": ");
showIndex(eeprom_value);
Serial.println(")");
#endif
if (eeprom_index <= EEPROM_INDEX_HEADER_4)
{
if (eeprom_value != EEPROM_HEADER[eeprom_index])
{
header_is_good = false;
}
}
}
// read the checksum & inverse checksum
EEPROM.get(EEPROM_INDEX_CHECKSUM, xor_value);
EEPROM.get(EEPROM_INDEX_INV_CHECKSUM, inv_xor_value);
// if the checksums match & the header values match, then we seem to have valid settings in EEPROM, so read all of the settings
if ((xor_value == xor_result) &&
(inv_xor_value == (byte)~xor_result) &&
(header_is_good))
{
#ifdef DEBUG_EEPROM_READ
Serial.println("Valid settings found in EEPROM");
Serial.println("");
#endif
#ifndef DISABLE_EEPROM_READ_SETTINGS
for (int eeprom_index = (int)(EEPROM_INDEX_HEADER_0); eeprom_index <= (int)(EEPROM_INDEX_INV_CHECKSUM); eeprom_index++)
{
EEPROM.get(eeprom_index, eeprom_value);
#ifdef DEBUG_EEPROM_READ
Serial.print("(READ ");
showIndex(eeprom_index);
Serial.print(": ");
showIndex(eeprom_value);
#endif
switch(eeprom_index)
{
case EEPROM_INDEX_HEADER_0:
case EEPROM_INDEX_HEADER_1:
case EEPROM_INDEX_HEADER_2:
case EEPROM_INDEX_HEADER_3:
case EEPROM_INDEX_HEADER_4:
{
#ifdef DEBUG_EEPROM_READ
Serial.print(") Header[");
Serial.print(eeprom_index);
Serial.print("] = ");
Serial.println((char)eeprom_value);
#endif
}
break;
case EEPROM_INDEX_MAIN_VOLUME:
{
mainVolumeSlider.value = map((float)eeprom_value, 0.0, 255.0, mainVolumeSlider.minValue, mainVolumeSlider.maxValue);
#ifdef DEBUG_EEPROM_READ
Serial.print(") Main Volume Slider = ");
Serial.println(mainVolumeSlider.value);
#endif
}
break;
case EEPROM_INDEX_MAIN_LEVEL_A:
{
mainLevelASlider.value = map((float)eeprom_value, 0.0, 255.0, mainLevelASlider.minValue, mainLevelASlider.maxValue);
#ifdef DEBUG_EEPROM_READ
Serial.print(") Main Level A Slider = ");
Serial.println(mainLevelASlider.value);
#endif
}
break;
case EEPROM_INDEX_MAIN_LEVEL_B:
{
mainLevelBSlider.value = map((float)eeprom_value, 0.0, 255.0, mainLevelBSlider.minValue, mainLevelBSlider.maxValue);
#ifdef DEBUG_EEPROM_READ
Serial.print(") Main Level B Slider = ");
Serial.println(mainLevelBSlider.value);
#endif
}
break;
case EEPROM_INDEX_MAIN_LEVEL_C:
{
mainLevelCSlider.value = map((float)eeprom_value, 0.0, 255.0, mainLevelCSlider.minValue, mainLevelCSlider.maxValue);
#ifdef DEBUG_EEPROM_READ
Serial.print(") Main Level C Slider = ");
Serial.println(mainLevelCSlider.value);
#endif
}
break;
case EEPROM_INDEX_MAIN_TUNING:
{
mainTuningSlider.value = map((float)eeprom_value, 0.0, 255.0, mainTuningSlider.minValue, mainTuningSlider.maxValue);
#ifdef DEBUG_EEPROM_READ
Serial.print(") Main Tuning Slider = ");
Serial.println(mainTuningSlider.value);
#endif
}
break;
case EEPROM_INDEX_MAIN_TUNING_A:
{
mainTuningASlider.value = map((float)eeprom_value, 0.0, 255.0, mainTuningASlider.minValue, mainTuningASlider.maxValue);
#ifdef DEBUG_EEPROM_READ
Serial.print(") Main Tuning A Slider = ");
Serial.println(mainTuningASlider.value);
#endif
}
break;
case EEPROM_INDEX_MAIN_TUNING_B:
{
mainTuningBSlider.value = map((float)eeprom_value, 0.0, 255.0, mainTuningBSlider.minValue, mainTuningBSlider.maxValue);
#ifdef DEBUG_EEPROM_READ
Serial.print(") Main Tuning B Slider = ");
Serial.println(mainTuningBSlider.value);
#endif
}
break;
case EEPROM_INDEX_MAIN_TUNING_C:
{
mainTuningCSlider.value = map((float)eeprom_value, 0.0, 255.0, mainTuningCSlider.minValue, mainTuningCSlider.maxValue);
#ifdef DEBUG_EEPROM_READ
Serial.print(") Main Tuning C Slider = ");
Serial.println(mainTuningCSlider.value);
#endif
}
break;
case EEPROM_INDEX_CHECKSUM:
{
eeprom_value = (char)(xor_result);
#ifdef DEBUG_EEPROM_WRITE
Serial.print(") Calculated CHECKSUM = ");
showIndex(xor_result);
Serial.println("");
#endif
}
break;
case EEPROM_INDEX_INV_CHECKSUM:
{
eeprom_value = (char)(~xor_result);
#ifdef DEBUG_EEPROM_WRITE
Serial.print(") Calculated INVERSE CHECKSUM = ");
showIndex((byte)~xor_result);
Serial.println("");
#endif
}
break;
default:
{
#ifdef DEBUG_EEPROM_READ
Serial.println(")");
#endif
}
break;
}
}
#endif
} else {
#ifdef DEBUG_EEPROM_READ
Serial.println("Invalid settings found in EEPROM");
Serial.println("");
Serial.print("(READ ");
showIndex(EEPROM_INDEX_CHECKSUM);
Serial.print (") xor_value = ");
Serial.println(xor_value);
Serial.print("(CALC) xor_result = ");
Serial.println(xor_result);
Serial.print("(READ ");
showIndex(EEPROM_INDEX_INV_CHECKSUM);
Serial.print (") inv_xor_value = ");
Serial.println(inv_xor_value);
Serial.print("(CALC) inv_xor_result = ");
Serial.println((byte)~xor_result);
#endif
saveSettings();
}
} // readSettings()
// save the current settings to EEPROM
void saveSettings(void)
{
byte xor_result = 0x4D; // start with a non-zero value
char eeprom_value;
#ifdef DEBUG_EEPROM_WRITE
Serial.println("");
Serial.println("Saving settings to EEPROM");
Serial.println("");
#endif
for (byte eeprom_index = (byte)(EEPROM_INDEX_HEADER_0); eeprom_index <= (byte)(EEPROM_INDEX_INV_CHECKSUM); eeprom_index++)
{
#ifdef DEBUG_EEPROM_WRITE
Serial.print("(WRITE ");
showIndex(eeprom_index);
Serial.print(": ");
#endif
switch(eeprom_index)
{
case EEPROM_INDEX_HEADER_0:
case EEPROM_INDEX_HEADER_1:
case EEPROM_INDEX_HEADER_2:
case EEPROM_INDEX_HEADER_3:
case EEPROM_INDEX_HEADER_4:
{
eeprom_value = EEPROM_HEADER[eeprom_index];
#ifdef DEBUG_EEPROM_WRITE
showIndex(eeprom_value);
Serial.print(") Header[");
Serial.print(eeprom_index);
Serial.print("] = ");
Serial.println(eeprom_value);
#endif
}
break;
case EEPROM_INDEX_MAIN_VOLUME:
{
eeprom_value = (char)map(mainVolumeSlider.value, mainVolumeSlider.minValue, mainVolumeSlider.maxValue, 0, 255);
#ifdef DEBUG_EEPROM_WRITE
showIndex(eeprom_value);
Serial.print(") Main Volume Slider = ");
Serial.println(mainVolumeSlider.value);
#endif
}
break;
case EEPROM_INDEX_MAIN_LEVEL_A:
{
eeprom_value = (char)map(mainLevelASlider.value, mainLevelASlider.minValue, mainLevelASlider.maxValue, 0, 255);
#ifdef DEBUG_EEPROM_WRITE
showIndex(eeprom_value);
Serial.print(") Main Level A Slider = ");
Serial.println(mainLevelASlider.value);
#endif
}
break;
case EEPROM_INDEX_MAIN_LEVEL_B:
{
eeprom_value = (char)map(mainLevelBSlider.value, mainLevelBSlider.minValue, mainLevelBSlider.maxValue, 0, 255);
#ifdef DEBUG_EEPROM_WRITE
showIndex(eeprom_value);
Serial.print(") Main Level B Slider = ");
Serial.println(mainLevelBSlider.value);
#endif
}
break;
case EEPROM_INDEX_MAIN_LEVEL_C:
{
eeprom_value = (char)map(mainLevelCSlider.value, mainLevelCSlider.minValue, mainLevelCSlider.maxValue, 0, 255);
#ifdef DEBUG_EEPROM_WRITE
showIndex(eeprom_value);
Serial.print(") Main Level C Slider = ");
Serial.println(mainLevelCSlider.value);
#endif
}
break;
case EEPROM_INDEX_MAIN_TUNING:
{
eeprom_value = (char)map(mainTuningSlider.value, mainTuningSlider.minValue, mainTuningSlider.maxValue, 0, 255);
#ifdef DEBUG_EEPROM_WRITE
showIndex(eeprom_value);
Serial.print(") Main Tuning Slider = ");
Serial.println(mainTuningSlider.value);
#endif
}
break;
case EEPROM_INDEX_MAIN_TUNING_A:
{
eeprom_value = (char)map(mainTuningASlider.value, mainTuningASlider.minValue, mainTuningASlider.maxValue, 0, 255);
#ifdef DEBUG_EEPROM_WRITE
showIndex(eeprom_value);
Serial.print(") Main Tuning A Slider = ");
Serial.println(mainTuningASlider.value);
#endif
}
break;
case EEPROM_INDEX_MAIN_TUNING_B:
{
eeprom_value = (char)map(mainTuningBSlider.value, mainTuningBSlider.minValue, mainTuningBSlider.maxValue, 0, 255);
#ifdef DEBUG_EEPROM_WRITE
showIndex(eeprom_value);
Serial.print(") Main Tuning B Slider = ");
Serial.println(mainTuningBSlider.value);
#endif
}
break;
case EEPROM_INDEX_MAIN_TUNING_C:
{
eeprom_value = (char)map(mainTuningCSlider.value, mainTuningCSlider.minValue, mainTuningCSlider.maxValue, 0, 255);
#ifdef DEBUG_EEPROM_WRITE
showIndex(eeprom_value);
Serial.print(") Main Tuning C Slider = ");
Serial.println(mainTuningCSlider.value);
#endif
}
break;
case EEPROM_INDEX_CHECKSUM:
{
eeprom_value = (char)(xor_result);
#ifdef DEBUG_EEPROM_WRITE
showIndex(eeprom_value);
Serial.print(") Calculated CHECKSUM = ");
showIndex(xor_result);
Serial.println("");
#endif
}
break;
case EEPROM_INDEX_INV_CHECKSUM:
{
eeprom_value = (char)(~xor_result);
#ifdef DEBUG_EEPROM_WRITE
showIndex(eeprom_value);
Serial.print(") Calculated INVERSE CHECKSUM = ");
showIndex((byte)~xor_result);
Serial.println("");
#endif
}
break;
default:
{
eeprom_value = eeprom_index;
#ifdef DEBUG_EEPROM_WRITE
showIndex(eeprom_value);
Serial.println(")");
#endif
}
break;
}
#ifndef DISABLE_EEPROM_WRITE_SETTINGS
EEPROM.update(eeprom_index, (byte)(eeprom_value));
#endif
if (eeprom_index < EEPROM_INDEX_CHECKSUM)
{
xor_result = (byte)(xor_result ^ eeprom_value);
}
}
} // saveSettings()
// one-time setup
void setup()
{
bool foundBegin = false;
bool foundEnd = false;
int indexCount = 0;
Serial.begin(57600);
while (!Serial && (millis() <= 1000));
Serial.println("=============================================");
Serial.print(" ");
Serial.println(VERSION1);
Serial.print(" ");
Serial.println(VERSION2);
Serial.println(VERSION3);
Serial.println("=============================================");
Serial.println("");
Serial.println("");
delay(500);
tft.begin();
tft.setRotation(1);
tft.setFrameBuffer(framebuf);
tft.useFrameBuffer(true);
delay(100);
ts.begin();
ts.setRotation(3);
tft.fillScreen(ILI9341_BLACK);
centerDrawText(VERSION1, 160, 100, ILI9341_GREEN, ILI9341_BLACK);
centerDrawText(VERSION2, 160, 120, ILI9341_YELLOW, ILI9341_BLACK);
centerDrawText(VERSION3, 160, 140, ILI9341_RED, ILI9341_BLACK);
tft.updateScreen();
delay(3000);
tft.fillScreen(ILI9341_BLACK);
centerDrawText('v', 280, 4, ILI9341_YELLOW, ILI9341_BLACK);
for(unsigned int i = 0; i < sizeof(VERSION2); i++)
{
if (!foundBegin)
{
if (VERSION2[i] == ' ')
{
foundBegin = true;
}
} else {
if (!foundEnd)
{
if (VERSION2[i] == ' ')
{
foundEnd = true;
} else {
centerDrawText((char)VERSION2[i], 280 + (6 * ++indexCount), 4, ILI9341_YELLOW, ILI9341_BLACK);
}
}
}
}
centerDrawText(VERSION1, 160, 4, ILI9341_GREEN, ILI9341_BLACK);
drawScreen();
tft.updateScreen();
// try to read the settings from EEPROM
readSettings();
drawScreen();
tft.updateScreen();
} // setup()
// show index of EEPROM reads/writes
void showIndex(int index)
{
if (index < 100)
{
Serial.print("0");
} else {
Serial.print((char)((index / 100) + 0x30));
}
if (index < 10)
{
Serial.print("0");
} else {
Serial.print((char)(((index / 10) % 10) + 0x30));
}
Serial.print((char)((index % 10) + 0x30));
} // showIndex()
// EOF placeholder
Last edited: