ugh, this means a total rewrite of 1700 lines of code. dang it .
what would be a good general control structure to do a menu based system
i have googled this intensively over the last 3 weeks but i cant quite wrap my head around what i did find and i am not sure im googling the right thing. heres the whole code so that you have an idea how it works now, and i am definately sure its not the best i was just trying to rough draft it and make improvements later
// Example sketch to demonstrate the drawing of X BitMap (XBM)
// format image onto the display.
// Information on the X BitMap (XBM) format can be found here:
// https://en.wikipedia.org/wiki/X_BitMap
// This example is part of the TFT_eSPI library:
// https://github.com/Bodmer/TFT_eSPI
// Created by Bodmer 23/04/18
////////////////////////////////////////////////////////////////////////Headers
#include "xbm.h" // Sketch tab header for xbm images
#include "ico.h"
#include "var.h"
//////////////////////////////////////////////////////////////////////libraries
#include <TFT_eSPI.h> // Hardware-specific library
#include <PsxControllerBitBangFastProc.h>
#include <avr/pgmspace.h>
#include <SPI.h>
#include "printf.h"
#include <nRF24L01.h>
#include <RF24.h>
#include "VirtuinoCM.h"
#include "RPi_Pico_TimerInterrupt.h"
#include <Streaming.h>
#include "SdFat.h"
///////////////////////////////////////////////////////////////////////////Pin Definitions
//PSX Controller Pins
const byte PIN_PS2_CLK = 20;
const byte PIN_PS2_DAT = 22;
const byte PIN_PS2_CMD = 21;
const byte PIN_PS2_ATT = 26;
//NRF24l01 Pins
const byte PIN_NRF_CE = 17;
const byte PIN_NRF_CSN = 15;
/////////////////////////////////////////////////////////////////////invocations
TFT_eSPI tft = TFT_eSPI(); // Invoke library
PsxControllerBitBang<PIN_PS2_ATT, PIN_PS2_CMD, PIN_PS2_DAT, PIN_PS2_CLK> psx;
VirtuinoCM virtuino;
RF24 radio(PIN_NRF_CE, PIN_NRF_CSN); // CE, CSN// nRF24L01(+) radio attached using Getting Started board <<<<<<<set to board
RPI_PICO_Timer ITimer0(0); // timer that Checks controller
//RPI_PICO_Timer ITimer1(2); // timer that runs virtuino
//------------------------------------------------------------------------------
// SdCardFactory constructs and initializes the appropriate card.
SdCardFactory cardFactory;
// Pointer to generic SD card.
SdCard* m_card = nullptr;
////////////////////////////////////////////////////////////////////////SD Card
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 1
#if SD_FAT_TYPE == 0
SdFat sd;
SdFile file;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
File32 file;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile file;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile file;
#else // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif // SD_FAT_TYPE
//SdFat sd;
//SdFile file;
//////////////////////////////////////////////////////////////////////////////////////VARS
const char* const psxButtonNames[PSX_BUTTONS_NO] PROGMEM = {
buttonSelectName,
buttonL3Name,
buttonR3Name,
buttonStartName,
buttonUpName,
buttonRightName,
buttonDownName,
buttonLeftName,
buttonL2Name,
buttonR2Name,
buttonL1Name,
buttonR1Name,
buttonTriangleName,
buttonCircleName,
buttonCrossName,
buttonSquareName
};
const char* const controllerTypeStrings[PSCTRL_MAX + 1] PROGMEM = {
ctrlTypeUnknown,
ctrlTypeDualShock,
ctrlTypeDsWireless,
ctrlTypeGuitHero,
ctrlTypeOutOfBounds
};
void setup()
{
View_Intro();
View_Main();
}
void loop()
{
}
//////////////////////////////////////////////////////////////////////////////////////////////////////LCDViews
void View_Intro() {
int Step = 0;
static byte slx, sly, srx, sry;
int x = 0;//random(tft.width() - logoWidth);
int y = 0;//random(tft.height() - logoHeight);
int StatusY = 231;
tft.begin(); // Initialise the display
tft.fillScreen(TFT_BLACK); // Black screen fill
tft.setRotation(3);
tft.drawXBitmap(x, y, frametest, frametest_width, frametest_height, TFT_CYAN);
tft.setTextDatum(4);
tft.setTextColor(TFT_CYAN , TFT_BLACK);
tft.setTextPadding(320);
drawGauge1(Step);
///controllerinit <<<<<<<<<<<<<<<<<<<<<<<<<<<
InitController(true, StatusY);
haveController = true;
Step++;
drawGauge1(Step);
if (debug) {
Serial.begin(115200);
//while (!Serial) continue;
}
Step++;
drawGauge1(Step);
tft.drawString("Debug Terminal online", SCR_WD / 2, StatusY, 2);
delay (300);
Step++;
drawGauge1(Step);
String Stat1 = "System Init on " + String(PSTR_TO_F (BOARD_NAME));
tft.drawString(Stat1, SCR_WD / 2, StatusY, 2);
delay (300);
Step++;
drawGauge1(Step);
tft.drawString(RPI_PICO_TIMER_INTERRUPT_VERSION, SCR_WD / 2, StatusY, 2);
delay (300);
Step++;
drawGauge1(Step);
String Stat2 = "CPU Frequency = " + String(PSTR_TO_F (F_CPU / 1000000)) + " MHz";
tft.drawString(Stat2, SCR_WD / 2, StatusY, 2);
delay (300);
if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 300, TimerHandler0))
{
Step++;
drawGauge1(Step);
tft.drawString("Controller Timer Running", SCR_WD / 2, StatusY, 2);
delay (300);
}
else
tft.drawString("Cannot Start Timer", SCR_WD / 2, StatusY, 2);
delay (300);
if (!radio.begin()) {
tft.drawString("Radio hardware is not responding!", SCR_WD / 2, StatusY, 2);
delay (300);
} else {
Step++;
drawGauge1(Step);
tft.drawString("Radio hardware Online", SCR_WD / 2, StatusY, 2);
delay (300);
}
radio.openWritingPipe(addresses[1]); // 00002
Step++;
drawGauge1(Step);
tft.drawString("Radio Writing Pipe Open", SCR_WD / 2, StatusY, 2);
delay (300);
radio.openReadingPipe(1, addresses[0]); // 00001
Step++;
drawGauge1(Step);
tft.drawString("Radio Reading Pipe Open", SCR_WD / 2, StatusY, 2);
delay (300);
radio.setAutoAck(false);
Step++;
drawGauge1(Step);
tft.drawString("Radio Auto ACK off", SCR_WD / 2, StatusY, 2);
delay (300);
radio.setDataRate(RF24_1MBPS);
Step++;
drawGauge1(Step);
tft.drawString("Radio Data Rate to 1MBp/s", SCR_WD / 2, StatusY, 2);
delay (300);
radio.setPALevel(RF24_PA_MIN); // was RF24_PA_LOW
Step++;
drawGauge1(Step);
tft.drawString("Radio Power AmpLifier Min", SCR_WD / 2, StatusY, 2);
delay (300);
Serial1.begin(115200);
Serial1.setTimeout(100);
Step++;
drawGauge1(Step);
tft.drawString("Virtuino Serial Online", SCR_WD / 2, StatusY, 2);
delay (300);
virtuino.begin(onReceived, onRequested, 256); //Start Virtuino. Set the buffer to 256. With this buffer Virtuino can control about 28 pins (1 command = 9bytes) The T(text) commands with 20 characters need 20+6 bytes
//virtuino.key="1234"; //This is the Virtuino password. Only requests the start with this key are accepted from the library
Step++;
drawGauge1(Step);
tft.drawString("Virtuino ONLINE", SCR_WD / 2, StatusY, 2);
delay (300);
if (SDCardInit(50, false))
{
Step++;
drawGauge1(Step);
tft.setTextColor(TFT_GREEN , TFT_BLACK);
tft.drawString("SD Card Initialized", SCR_WD / 2, StatusY, 2);
tft.setTextColor(TFT_CYAN , TFT_BLACK);
delay (300);
}
else
{
tft.setTextColor(TFT_RED , TFT_BLACK);
tft.drawString("SD Card FAIL", SCR_WD / 2, StatusY, 2);
tft.setTextColor(TFT_CYAN , TFT_BLACK);
}
Step = 100;
drawGauge1(Step);
tft.drawString("System Online", SCR_WD / 2, StatusY, 2);
delay (3000);
}
void View_Main() {
bool ok = false;
int x = 0;//random(tft.width() - logoWidth);
int y = 0;//random(tft.height() - logoHeight);
tft.fillScreen(TFT_BLACK); // Black screen fill
tft.drawXBitmap(x, y, frametest, frametest_width, frametest_height, TFT_CYAN);
int StatusY = 231;
tft.setTextDatum(4);
tft.setTextColor(TFT_CYAN , TFT_BLACK);
tft.setTextPadding(150);
tft.setTextDatum(5);
tft.setTextPadding(tft.textWidth("A") * 9);
tft.drawString("Press ", ((SCR_WD / 2) - 1), tft.getViewportHeight() - (l3x32_height * 1.5), 1);
tft.setTextDatum(3);
tft.drawXBitmap((SCR_WD / 2) * 1, tft.getViewportHeight() - (l3x32_height * 2 + 5), l3x32, l3x32_width, l3x32_height, TFT_CYAN, TFT_BLACK );
tft.drawString(" for Menu", ((SCR_WD / 2) * 1 + l3x32_width), tft.getViewportHeight() - l3x32_height * 1.5, 1);
tft.setTextDatum(4);
tft.setTextPadding(tft.textWidth("A") * 80);
while (!ok) {//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////Main Control Structure
if (psx.buttonPressed(PSB_L3)) {
tft.drawXBitmap(15, 10, frametest2, frametest2_width, frametest2_height, TFT_CYAN, TFT_BLACK);
tft.setTextSize(2);
tft.setCursor(50, 25);
tft.println("Main Menu");
tft.setCursor(25, 60);
tft.setTextSize(2);
tft.println("X = Drive Controls");
tft.setCursor(25, 80);
tft.println("O = AHRS Information");
tft.setCursor(25, 100);
tft.println("S = Sub-System");
tft.setCursor(25, 120);
tft.println("T = Primary Weapon");
tft.setCursor(25, 140);
tft.println("L1 = Secondary Weapon");
tft.setCursor(25, 160);
tft.println("L2 = Power Subsystems");
tft.setCursor(25, 180);
tft.println("R1 = Sensor Subsystems");
tft.setCursor(25, 200);
tft.println("R2 = Diagnostic Menu");
tft.setCursor(25, 220);
tft.println("Start = Exit");
}
if (psx.buttonPressed(PSB_START)) {
View_Main();
}
if (psx.buttonPressed(PSB_CROSS)) {
View_ControllerDiag();
}
if (psx.buttonPressed(PSB_CIRCLE)) {
View_NRFDiag();
}
if (psx.buttonPressed(PSB_SQUARE)) {
View_SDDiag();
}
if (psx.buttonPressed(PSB_TRIANGLE)) {
View_Main();
}
if (psx.buttonPressed(PSB_L1)) {
View_Main();
}
if (psx.buttonPressed(PSB_L2)) {
View_Main();
}
if (psx.buttonPressed(PSB_R1)) {
View_Main();
}
if (psx.buttonPressed(PSB_R2)) {
tft.drawXBitmap(15, 10, frametest2, frametest2_width, frametest2_height, TFT_CYAN, TFT_BLACK);
tft.setTextSize(2);
tft.setCursor(50, 25);
tft.println("Diagnostics");
tft.setCursor(25, 60);
tft.setTextSize(2);
tft.println("X = Controller");
tft.setCursor(25, 80);
tft.println("O = NRF24L01");
tft.setCursor(25, 100);
tft.println("S = Virtuino");
tft.setCursor(25, 120);
tft.println("T = SD Card");
tft.setCursor(25, 140);
tft.println("L1 = Display");
tft.setCursor(25, 160);
tft.println("L2 = Settings");
tft.setCursor(25, 180);
tft.println("R1 = Terminal");
tft.setCursor(25, 200);
tft.println("R2 = Scope");
tft.setCursor(25, 220);
tft.println("Start = Exit");
while (!ok) {//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////Diagnostic Control Structure
if (psx.buttonPressed(PSB_L3)) {
}
if (psx.buttonPressed(PSB_START)) {
View_Main();
}
if (psx.buttonPressed(PSB_CROSS)) {
View_ControllerDiag();
ok = true;
}
if (psx.buttonPressed(PSB_CIRCLE)) {
View_NRFDiag();
}
if (psx.buttonPressed(PSB_SQUARE)) {
View_Main();
}
if (psx.buttonPressed(PSB_TRIANGLE)) {
View_SDDiag();
}
if (psx.buttonPressed(PSB_L1)) {
View_Main();
}
if (psx.buttonPressed(PSB_L2)) {
View_Main();
}
if (psx.buttonPressed(PSB_R1)) {
View_SerialTerminal();
}
if (psx.buttonPressed(PSB_R2)) {
}
}//////////////////////////////////////////////////////////////////////////////////////////////////////////////////control struct end
}
}//////////////////////////////////////////////////////////////////////////////////////////////////////////////////control struct end
}
void View_ControllerDiag() {
bool ok = false;
int x = 0;//random(tft.width() - logoWidth);
int y = 0;//random(tft.height() - logoHeight);
tft.fillScreen(TFT_BLACK); // Black screen fill
tft.drawXBitmap(x, y, logo, logoWidth, logoHeight, TFT_WHITE);
tft.setTextDatum(4);
tft.setTextColor(TFT_CYAN , TFT_BLACK);
tft.setTextPadding(320);
while (!ok) {
if (psx.buttonPressed(PSB_CROSS)) {
// Location Circle For X BUtton
tft.drawCircle(389, 184, 15, TFT_BLUE);
tft.drawCircle(389, 184, 16, TFT_BLUE);
tft.drawCircle(389, 184, 17, TFT_BLUE);
} else {
// Location Circle For X BUtton
tft.drawCircle(389, 184, 15, TFT_WHITE);
tft.drawCircle(389, 184, 16, TFT_WHITE);
tft.drawCircle(389, 184, 17, TFT_WHITE);
}
if (psx.buttonPressed(PSB_CIRCLE)) {
//Location Circle For Circle Button
tft.drawCircle(430, 148, 15, TFT_RED);
tft.drawCircle(430, 148, 16, TFT_RED);
tft.drawCircle(430, 148, 17, TFT_RED);
} else {
//Location Circle For Circle Button
tft.drawCircle(430, 148, 15, TFT_WHITE);
tft.drawCircle(430, 148, 16, TFT_WHITE);
tft.drawCircle(430, 148, 17, TFT_WHITE);
}
if (psx.buttonPressed(PSB_SQUARE)) {
//Location Circle For Square Button
tft.drawCircle(349, 148, 15, TFT_MAGENTA);
tft.drawCircle(349, 148, 16, TFT_MAGENTA);
tft.drawCircle(349, 148, 17, TFT_MAGENTA);
} else {
//Location Circle For Square Button
tft.drawCircle(349, 148, 15, TFT_WHITE);
tft.drawCircle(349, 148, 16, TFT_WHITE);
tft.drawCircle(349, 148, 17, TFT_WHITE);
}
if (psx.buttonPressed(PSB_TRIANGLE)) {
//Location Circle For triangle Button
tft.drawCircle(389, 112, 15, TFT_GREEN);
tft.drawCircle(389, 112, 16, TFT_GREEN);
tft.drawCircle(389, 112, 17, TFT_GREEN);
} else {
//Location Circle For triangle Button
tft.drawCircle(389, 112, 15, TFT_WHITE);
tft.drawCircle(389, 112, 16, TFT_WHITE);
tft.drawCircle(389, 112, 17, TFT_WHITE);
}
if (psx.buttonPressed(PSB_PAD_UP)) {
//Location indicator For up Button
tft.fillTriangle(93, 113, 112, 113, 103, 130, TFT_DARKCYAN);
} else {
//Location indicator For up Button
tft.fillTriangle(93, 113, 112, 113, 103, 130, TFT_WHITE);
}
if (psx.buttonPressed(PSB_PAD_DOWN)) {
//Location indicator For DOWN Button
tft.fillTriangle(93, 185, 112, 185, 103, 167, TFT_DARKGREEN);
} else {
//Location indicator For DOWN Button
tft.fillTriangle(93, 185, 112, 185, 103, 167, TFT_WHITE);
}
if (psx.buttonPressed(PSB_PAD_LEFT)) {
//Location indicator For left Button
tft.fillTriangle(67, 142, 67, 159, 85, 150, TFT_MAROON);
} else {
//Location indicator For left Button
tft.fillTriangle(67, 142, 67, 159, 85, 150, TFT_WHITE);
}
if (psx.buttonPressed(PSB_PAD_RIGHT)) {
//Location indicator For right Button
tft.fillTriangle(138, 142, 138, 159, 124, 150, TFT_PURPLE);
} else {
//Location indicator For right Button
tft.fillTriangle(138, 142, 138, 159, 124, 150, TFT_WHITE);
}
if (psx.buttonPressed(PSB_L1)) {
tft.fillRect(95, 15, 10, 10, TFT_CYAN);
} else {
tft.fillRect(95, 15, 10, 10, TFT_BLACK);
}
if (psx.buttonPressed(PSB_L2)) {
tft.fillRect(110, 15, 10, 10, TFT_CYAN);
} else {
tft.fillRect(110, 15, 10, 10, TFT_BLACK);
}
if (psx.buttonPressed(PSB_R1)) {
tft.fillRect(375, 15, 10, 10, TFT_CYAN);
} else {
tft.fillRect(375, 15, 10, 10, TFT_BLACK);
}
if (psx.buttonPressed(PSB_R2)) {
tft.fillRect(390, 15, 10, 10, TFT_CYAN);
} else {
tft.fillRect(390, 15, 10, 10, TFT_BLACK);
}
if (psx.buttonPressed(PSB_START)) {
//Location indicator For Start Button
tft.fillRect(280, 141, 10, 10, TFT_ORANGE);
} else {
//Location indicator For Start Button
tft.fillRect(280, 141, 10, 10, TFT_WHITE);
}
if (psx.buttonPressed(PSB_SELECT)) {
//Location indicator For select Button
tft.fillRect(197, 141, 10, 10, TFT_CYAN);
} else {
//Location indicator For select Button
tft.fillRect(197, 141, 10, 10, TFT_WHITE);
}
if (psx.buttonPressed(PSB_R3)) {
tft.fillRect(320, 275, 10, 10, TFT_CYAN);
} else {
tft.fillRect(320, 275, 10, 10, TFT_BLACK);
}
if (psx.buttonPressed(PSB_L3)) {
tft.fillRect(175, 275, 10, 10, TFT_CYAN);
} else {
tft.fillRect(175, 275, 10, 10, TFT_BLACK);
}
if (psx.buttonPressed(PSB_R3) && psx.buttonPressed(PSB_SELECT)) {
View_Main();
}
//Left Joy
tft.fillCircle(map(slx, 0, 255, 140, 210), map(sly, 0, 255, 185, 256), 4, TFT_GOLD);
tft.drawCircle(map(slx, 0, 255, 140, 210), map(sly, 0, 255, 185, 256), 5, TFT_BLACK);
tft.drawCircle(map(slx, 0, 255, 140, 210), map(sly, 0, 255, 185, 256), 6, TFT_BLACK);
tft.drawCircle(map(slx, 0, 255, 140, 210), map(sly, 0, 255, 185, 256), 7, TFT_BLACK);
//right Joy
tft.fillCircle(map(srx, 0, 255, 285, 350), map(sry, 0, 255, 185, 256), 4, TFT_SILVER);
tft.drawCircle(map(srx, 0, 255, 285, 350), map(sry, 0, 255, 185, 256), 5, TFT_BLACK);
tft.drawCircle(map(srx, 0, 255, 285, 350), map(sry, 0, 255, 185, 256), 6, TFT_BLACK);
tft.drawCircle(map(srx, 0, 255, 285, 350), map(sry, 0, 255, 185, 256), 7, TFT_BLACK);
}
}
void View_NRFDiag() {
bool ok = false;
int x = 0;//random(tft.width() - logoWidth);
int y = 0;//random(tft.height() - logoHeight);
tft.fillScreen(TFT_BLACK); // Black screen fill
tft.drawXBitmap(x, y, frametest, frametest_width, frametest_height, TFT_CYAN);
int StatusY = 231;
tft.setTextDatum(4);
tft.setTextColor(TFT_CYAN , TFT_BLACK);
tft.setTextPadding(320);
tft.drawString("NRF24L01 Diagnostic", SCR_WD / 2, 15, 2);
// For debugging info
char *debug_info = new char[870];
uint16_t str_len = radio.sprintfPrettyDetails(debug_info);
tft.setViewport(40, 40, 390, 270 );
//tft.frameViewport(TFT_CYAN, -4);
tft.setCursor(0, 0);
tft.setTextColor(TFT_CYAN , TFT_BLACK);
tft.setTextSize(1);
tft.println(debug_info);
tft.resetViewport();
}
void View_SDDiag() {
bool ok = false;
int x = 0;//random(tft.width() - logoWidth);
int y = 0;//random(tft.height() - logoHeight);
tft.fillScreen(TFT_BLACK); // Black screen fill
tft.drawXBitmap(x, y, SDFrame, SDFrame_width, SDFrame_height, TFT_CYAN);
int StatusY = 231;
tft.setTextDatum(4);
tft.setTextColor(TFT_CYAN , TFT_BLACK);
tft.setTextPadding(tft.textWidth("SD Card Info"));
tft.drawString("SD Card Info", SCR_WD / 2, 15, 2);
tft.setTextPadding(tft.textWidth("A") * 80);
tft.setViewport(9, 113, 318, 198 ); //tft print terminal space for SD diag
//tft.frameViewport(TFT_CYAN, -4);
tft.setCursor(0, 0);
tft.setTextColor(TFT_CYAN , TFT_BLACK);
tft.setTextSize(1);
////////////////////////////////////////////////////////////////////////////////////////////////core
tft.print("SS = "); tft.print(PIN_SD_SS);
tft.print(" SCK = "); tft.print(PIN_SD_SCK);
tft.print(" MOSI = "); tft.print(PIN_SD_MOSI);
tft.print(" MISO = "); tft.println(PIN_SD_MISO);
if (!SDStarted) {
SDCardInit(50, true);
}
tft.println("Determining Free Space...");
//tft.print(F("Volume is FAT")); tft.print(int(sd.vol()->fatType()));
tft.resetViewport();
tft.setTextPadding(0);
//------------------------information in Sd Card Icon
tft.drawString(("FAT" + String(int(sd.vol()->fatType()))), 32, 94, 1);
uint32_t size = sd.card()->sectorCount();
uint32_t sizeMB = 0.000512 * size + 0.5;
uint32_t freeSizeMB = 0.000512 * volFree * sd.vol()->sectorsPerCluster();
uint32_t usedSizeMB = sizeMB - freeSizeMB;
uint32_t sizeGB = sizeMB / 1024;
uint32_t volumesize = sd.vol()->sectorsPerCluster(); // clusters are collections of blocks
volumesize *= sd.vol()->clusterCount(); // we'll have a lot of clusters
tft.drawString((String(sizeGB) + "GB"), 32, 71, 1);
//57,50
tft.setTextDatum(0);
//43,11 ---------------- information location
tft.drawString(String(BOARD_NAME), 43, 11, 1);
tft.drawString(("SDFat Lib" + String(SD_FAT_VERSION_STR)), 43, 11 + tft.fontHeight() * 1, 1);
tft.drawString(("Used Space: " + String(usedSizeMB) + "MB"), 57, 50, 1);
tft.drawString(("Free Space: " + String(freeSizeMB) + "MB"), 57, 50 + tft.fontHeight(), 1);
tft.drawString(("Sectors: " + String(volumesize)), 57, 50 + tft.fontHeight() * 2, 1);
//tft.drawString(("Sectors: " + String(sd.maxSck)), 57, 50 + tft.fontHeight() * 2, 1);
//335,285 top left corner
//473,285 top right corner
//473,311 bottom right corner
//26H , 138W
//map(value, fromLow, fromHigh, toLow, toHigh)
for (int gridx = 0; gridx <= 138; gridx = gridx + 3) {
for (int gridy = 0; gridy <= 193; gridy = gridy + 4) {
tft.fillRect(335 + gridx, 80 + gridy, 2, 3, TFT_LIGHTGREY);
}
}
//sd.vol()->blocksPerCluster();
//bool Sd2Card::readBlock ( uint32_t blockNumber, uint8_t * dst )
int usedPercent = map(usedSizeMB, 0, sizeMB, 0, 100);
int freePercent = map(freeSizeMB, 0, sizeMB, 0, 100);
int freeWidth = (freePercent * 138) / 100;
int usedWidth = (usedPercent * 138) / 100;
tft.fillRectVGradient(335, 285, usedWidth, 26, TFT_RED, TFT_BLACK);
tft.fillRectVGradient(335 + usedWidth, 285, freeWidth, 26, TFT_GREEN, TFT_BLACK);
tft.setTextDatum(4);
tft.setViewport(9, 113, 318, 198 );
tft.setTextPadding(tft.textWidth("A") * 80);
//tft.println("\nFiles found on the card (name, date and size in bytes): ");
//root = SD.open("/");
//printDirectory(root, 0); -----------------------------------------------------------------------------------reeval
////////////////////////////////////////////////////////////////////////////////////////////////
tft.setTextDatum(3);
tft.setTextPadding(tft.textWidth("A") * 9);
tft.drawXBitmap((tft.getViewportWidth() / 7) * 1 - 25, tft.getViewportHeight() - (startb_height + 5), startb, cross_width, startb_height, TFT_CYAN, TFT_BLACK);
tft.drawString("Exit", ((tft.getViewportWidth() / 7) * 1 + startb_width - 25), (tft.getViewportHeight() - (startb_height / 2)), 1);
tft.drawXBitmap((tft.getViewportWidth() / 7) * 2 - 20, tft.getViewportHeight() - (cross_height + 5), cross, cross_width, cross_height, TFT_BLACK, TFT_CYAN);
tft.drawString("Init", ((tft.getViewportWidth() / 7) * 2 + cross_width - 20), (tft.getViewportHeight() - (cross_height / 2)), 1);
tft.drawXBitmap((tft.getViewportWidth() / 7) * 3 - 15, tft.getViewportHeight() - (square_height + 5), square, square_width, square_height, TFT_BLACK, TFT_CYAN);
tft.drawString("Format", ((tft.getViewportWidth() / 7) * 3 + square_width - 15), (tft.getViewportHeight() - (square_height / 2)), 1);
tft.drawXBitmap((tft.getViewportWidth() / 7) * 4, tft.getViewportHeight() - (triangle_height + 5), triangle, triangle_width, triangle_height, TFT_BLACK, TFT_CYAN);
tft.drawString("Test", ((tft.getViewportWidth() / 7) * 4 + triangle_width), (tft.getViewportHeight() - (triangle_height / 2)), 1);
tft.drawXBitmap((tft.getViewportWidth() / 7) * 5 + 5, tft.getViewportHeight() - (circle_height + 5), circle, circle_width, circle_height, TFT_BLACK, TFT_CYAN);
tft.drawString("Block Map", ((tft.getViewportWidth() / 7) * 5 + circle_width + 5), (tft.getViewportHeight() - (circle_height / 2)), 1);
tft.setTextDatum(4);
tft.setTextPadding(tft.textWidth("A") * 80);
//tft.println(debug_info);
while (!ok) {//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////Diagnostic Control Structure
if (psx.buttonPressed(PSB_L3)) {
}
if (psx.buttonPressed(PSB_START)) {
tft.resetViewport();
delay(3000);
View_Main();
}
if (psx.buttonPressed(PSB_CROSS)) {
tft.fillScreen(TFT_BLACK);
tft.setCursor(0, 0);
tft.setViewport(9, 113, 318, 198 );
SDCardInit(50, true);
tft.resetViewport();
}
if (psx.buttonPressed(PSB_CIRCLE)) {
tft.resetViewport();
tft.setTextPadding(0);
tft.setTextDatum(0);
tft.drawString("Calculating Block Map...", 57, 50 + tft.fontHeight() * 5, 1);
DoTimer = false;
//----------------------------------------------------------------------------------make block grid
//335,80 473,80 138W
//335,80 473,273 193T
//46 columns 48 rows 2208 visible blocks
uint8_t blk[512];
bool blkEpty[2209] = {0}; //each sector is 512 bytes
uint8_t blkEptyLoop = 0;
uint32_t blkPerBool = volumesize / 2208; //how many sectors are represented by a single color block.
uint32_t bitsPerBool = blkPerBool * 512; //how many loops it takes to verify 1 color block on lcd
uint32_t bitCount = 0;
uint32_t blockCount = 0;
//333,42 ------------- info space aboveblock map
tft.drawString(("Block = " + String(blkPerBool) + " Sectors"), 333, 42, 1);
tft.drawString(("Block = " + String(bitsPerBool) + " Bytes"), 333, 42 + tft.fontHeight() * 1, 1);
//replace number to count to with size variable to do entire disk
for (uint32_t tSector = 0; tSector <= 5000; tSector++) {
if ( tSector % 100 == 0 ) {
tft.drawString(("CYCLE: " + String(tSector) + " out of: " + String(size)), 57, 50 + tft.fontHeight() * 6, 1);
}
if (sd.card()->readSector(tSector, blk)) {
for (uint32_t tByte = 0; tByte <= 512; tByte++) {
if (blk[tByte] != 255 | blk[tByte] != 0) {
tByte = 513;
blkEpty[blockCount] = 1;
} else {
blkEpty[blockCount] = 0;
}
}
}
bitCount++;
if (bitCount >= bitsPerBool) {
blockCount++;
bitCount = 0;
}
}
tft.drawString("DONE!!! ", 57, 50 + tft.fontHeight() * 5, 1);
for (int gridy = 0; gridy <= 193; gridy = gridy + 4) {
for (int gridx = 0; gridx <= 138; gridx = gridx + 3) {
if (blkEpty[blkEptyLoop]) {
tft.fillRect(335 + gridx, 80 + gridy, 2, 3, TFT_RED);
} else {
tft.fillRect(335 + gridx, 80 + gridy, 2, 3, TFT_GREEN);
}
blkEptyLoop++;
}
}
haveController = false;
InitController(false, 0);
DoTimer = true;
tft.setTextDatum(4);
tft.setViewport(9, 113, 318, 198 );
}
if (psx.buttonPressed(PSB_SQUARE)) {
tft.setViewport(9, 113, 318, 158 ); //x,y,w,h
tft.fillScreen(TFT_BLACK);
tft.setCursor(0, 0);
SDFormat(true);
tft.resetViewport();
}
if (psx.buttonPressed(PSB_TRIANGLE)) {
tft.setViewport(9, 113, 318, 158 ); //x,y,w,h
tft.fillScreen(TFT_BLACK);
tft.setCursor(0, 0);
SDBenchMark(true);
tft.resetViewport();
}
if (psx.buttonPressed(PSB_L1)) {
View_Main();
}
if (psx.buttonPressed(PSB_L2)) {
View_Main();
}
if (psx.buttonPressed(PSB_R1)) {
View_Main();
}
if (psx.buttonPressed(PSB_R2)) {
}
}//////////////////////////////////////////////////////////////////////////////////////////////////////////////////control struct end
tft.resetViewport();
}
void View_SerialTerminal() {
bool ok = false;
int x = 0;//random(tft.width() - logoWidth);
int y = 0;//random(tft.height() - logoHeight);
tft.fillScreen(TFT_BLACK); // Black screen fill
tft.drawXBitmap(x, y, frametest, frametest_width, frametest_height, TFT_CYAN);
int StatusY = 231;
tft.setTextDatum(4);
tft.setTextColor(TFT_CYAN , TFT_BLACK);
tft.setTextPadding(tft.textWidth("A") * 80);
tft.drawString("Serial Console", SCR_WD / 2, 15, 2);
tft.setViewport(40, 40, 390, 270 );
//tft.frameViewport(TFT_CYAN, -4);
tft.setCursor(0, 0);
tft.setTextColor(TFT_CYAN , TFT_BLACK);
tft.setTextSize(1);
tft.setTextDatum(3);
tft.setTextPadding(tft.textWidth("A") * 9);
tft.drawXBitmap((tft.getViewportWidth() / 6) * 1, tft.getViewportHeight() - (cross_height + 5), cross, cross_width, cross_height, TFT_BLACK, TFT_CYAN);
tft.drawString("Exit", ((tft.getViewportWidth() / 6) * 1 + cross_width), (tft.getViewportHeight() - (cross_height / 2)), 1);
tft.drawXBitmap((tft.getViewportWidth() / 6) * 2, tft.getViewportHeight() - (circle_height + 5), circle, circle_width, circle_height, TFT_BLACK, TFT_CYAN);
tft.drawString("Cfg", ((tft.getViewportWidth() / 6) * 2 + circle_width), (tft.getViewportHeight() - (circle_height / 2)), 1);
tft.drawXBitmap((tft.getViewportWidth() / 6) * 3, tft.getViewportHeight() - (square_height + 5), square, square_width, square_height, TFT_BLACK, TFT_CYAN);
tft.drawString("Clear", ((tft.getViewportWidth() / 6) * 3 + square_width), (tft.getViewportHeight() - (square_height / 2)), 1);
tft.drawXBitmap((tft.getViewportWidth() / 6) * 4, tft.getViewportHeight() - (triangle_height + 5), triangle, triangle_width, triangle_height, TFT_BLACK, TFT_CYAN);
tft.drawString("???", ((tft.getViewportWidth() / 6) * 4 + triangle_width), (tft.getViewportHeight() - (triangle_height / 2)), 1);
tft.setTextDatum(4);
tft.setTextPadding(tft.textWidth("A") * 80);
//tft.println(debug_info);
while (!ok) {//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////Diagnostic Control Structure
Do_Terminal();
if (psx.buttonPressed(PSB_L3)) {
}
if (psx.buttonPressed(PSB_START)) {
tft.resetViewport();
View_Main();
}
if (psx.buttonPressed(PSB_CROSS)) {
tft.resetViewport();
}
if (psx.buttonPressed(PSB_CIRCLE)) {
View_NRFDiag();
}
if (psx.buttonPressed(PSB_SQUARE)) {
View_Main();
}
if (psx.buttonPressed(PSB_TRIANGLE)) {
View_SDDiag();
}
if (psx.buttonPressed(PSB_L1)) {
View_Main();
}
if (psx.buttonPressed(PSB_L2)) {
View_Main();
}
if (psx.buttonPressed(PSB_R1)) {
View_Main();
}
if (psx.buttonPressed(PSB_R2)) {
}
}//////////////////////////////////////////////////////////////////////////////////////////////////////////////////control struct end
tft.resetViewport();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////LCDFunctions
void drawGauge1(int level)
{
cx = SCR_WD / 2;
cy = SCR_HT / 2;
int rx0 = 40, ry0 = 40;
int rx1 = 63, ry1 = 63;
int mina = -75;
int maxa = 180 + 75;
for (int i = mina; i < maxa; i += 15) {
sx = fastCos(i - 180);
sy = fastSin(i - 180);
xs0 = cx + sx * rx0 / MAXSIN;
ys0 = cy + sy * ry0 / MAXSIN;
xe0 = cx + sx * rx1 / MAXSIN;
ye0 = cy + sy * ry1 / MAXSIN;
sx = fastCos(i - 180 + 10);
sy = fastSin(i - 180 + 10);
xs1 = cx + sx * rx0 / MAXSIN;
ys1 = cy + sy * ry0 / MAXSIN;
xe1 = cx + sx * rx1 / MAXSIN;
ye1 = cy + sy * ry1 / MAXSIN;
int l = 100 * (i - mina) / (maxa - mina);
if (l < level) {
tft.fillTriangle(xs0, ys0, xe0, ye0, xe1, ye1, TFT_GREENYELLOW);
tft.fillTriangle(xs1, ys1, xe1, ye1, xs0, ys0, TFT_GREENYELLOW);
} else {
tft.fillTriangle(xs0, ys0, xe0, ye0, xe1, ye1, TFT_LIGHTGREY);
tft.fillTriangle(xs1, ys1, xe1, ye1, xs0, ys0, TFT_LIGHTGREY);
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////Math Functions
int fastSin(int i)
{
while (i < 0) i += 360;
while (i >= 360) i -= 360;
if (i < 90) return (pgm_read_byte(&sinTab[i])); else if (i < 180) return (pgm_read_byte(&sinTab[180 - i])); else if (i < 270) return (-pgm_read_byte(&sinTab[i - 180])); else
return (-pgm_read_byte(&sinTab[360 - i]));
}
int fastCos(int i)
{
return fastSin(i + 90);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////PSX Functions
byte psxButtonToIndex (PsxButtons psxButtons) {
byte i;
for (i = 0; i < PSX_BUTTONS_NO; ++i) {
if (psxButtons & 0x01) {
break;
}
psxButtons >>= 1U;
}
return i;
}
FlashStr getButtonName (PsxButtons psxButton) {
FlashStr ret = F("");
byte b = psxButtonToIndex (psxButton);
if (b < PSX_BUTTONS_NO) {
PGM_BYTES_P bName = reinterpret_cast<PGM_BYTES_P> (pgm_read_ptr (&(psxButtonNames[b])));
ret = PSTR_TO_F (bName);
}
return ret;
}
void dumpButtons (PsxButtons psxButtons) {
static PsxButtons lastB = 0;
if (psxButtons != lastB) {
lastB = psxButtons; // Save it before we alter it
Serial.print (F("Pressed: "));
for (byte i = 0; i < PSX_BUTTONS_NO; ++i) {
byte b = psxButtonToIndex (psxButtons);
if (b < PSX_BUTTONS_NO) {
PGM_BYTES_P bName = reinterpret_cast<PGM_BYTES_P> (pgm_read_ptr (&(psxButtonNames[b])));
Serial.print (PSTR_TO_F (bName));
}
psxButtons &= ~(1 << b);
if (psxButtons != 0) {
Serial.print (F(", "));
}
}
Serial.println ();
}
}
void dumpAnalog (const char *str, const byte x, const byte y) {
Serial.print (str);
Serial.print (F(" analog: x = "));
Serial.print (x);
Serial.print (F(", y = "));
Serial.println (y);
}
void ReadController() {
if (psx.read()) {
//Serial.println("9-1");
byte lx, ly;
psx.getLeftAnalog (lx, ly);
if (lx != slx || ly != sly) {
slx = lx;
sly = ly;
}
byte rx, ry;
psx.getRightAnalog (rx, ry);
if (rx != srx || ry != sry) {
srx = rx;
sry = ry;
}
delay (1000 / 60);
} else {
haveController = false;
InitController(false, 0);
}
}
void InitController(bool debug, int StatusY) {
if (!haveController) {
if (psx.begin ()) {
if (debug) {
tft.drawString("Controller found!", SCR_WD / 2, StatusY, 2);
}
if (!psx.enterConfigMode ()) {
if (debug) {
tft.drawString("Cannot enter config mode", SCR_WD / 2, StatusY, 2);
}
} else {
PsxControllerType ctype = psx.getControllerType ();
PGM_BYTES_P cname = reinterpret_cast<PGM_BYTES_P> (pgm_read_ptr (&(controllerTypeStrings[ctype < PSCTRL_MAX ? static_cast<byte> (ctype) : PSCTRL_MAX])));
if (debug) {
tft.drawString(("Controller Type is: " + String(PSTR_TO_F (cname))), SCR_WD / 2, StatusY, 2);
}
//tft.drawString(PSTR_TO_F (cname), SCR_WD / 2, StatusY + 15, 2);
if (!psx.enableAnalogSticks ()) {
if (debug) {
tft.drawString("Cannot enable analog sticks", SCR_WD / 2, StatusY, 2);
}
}
//~ if (!psx.setAnalogMode (false)) {
//~ Serial.println (F("Cannot disable analog mode"));
//~ }
//~ delay (10);
if (!psx.enableAnalogButtons ()) {
if (debug) {
tft.drawString("Cannot enable analog buttons", SCR_WD / 2, StatusY, 2);
}
}
if (!psx.exitConfigMode ()) {
if (debug) {
tft.drawString("Cannot enable analog sticks", SCR_WD / 2, StatusY, 2);
}
}
}
}
}
delay (1000 / 60);
haveController = true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VIRTUINO
//============================================================== onCommandReceived
//==============================================================
/* This function is called every time Virtuino app sends a request to server to change a Pin value
The 'variableType' can be a character like V, T, O V=Virtual pin T=Text Pin O=PWM Pin
The 'variableIndex' is the pin number index of Virtuino app
The 'valueAsText' is the value that has sent from the app */
void onReceived(char variableType, uint8_t variableIndex, String valueAsText) {
if (variableType == 'V') {
float value = valueAsText.toFloat(); // convert the value to float. The valueAsText have to be numerical
if (variableIndex < V_memory_count) V[variableIndex] = value; // copy the received value to arduino V memory array
}
}
//==============================================================
/* This function is called every time Virtuino app requests to read a pin value*/
String onRequested(char variableType, uint8_t variableIndex) {
if (variableType == 'V') {
if (variableIndex < V_memory_count) return String(V[variableIndex]); // return the value of the arduino V memory array
}
return "";
}
//============================================================== virtuinoRun
void virtuinoRun() {
while (Serial1.available()) {
char tempChar = Serial1.read();
if (tempChar == CM_START_CHAR) { // a new command is starting...
virtuino.readBuffer = CM_START_CHAR; // copy the new command to the virtuino readBuffer
virtuino.readBuffer += Serial1.readStringUntil(CM_END_CHAR);
virtuino.readBuffer += CM_END_CHAR;
if (debug) Serial.println("\nCommand= " + virtuino.readBuffer);
String* response = virtuino.getResponse(); // get the text that has to be sent to Virtuino as reply. The library will check the inptuBuffer and it will create the response text
if (debug) Serial.println("Response : " + *response);
Serial1.print(*response);
break;
}
}
}
//============================================================== vDelay
void vDelay(int delayInMillis) {
long t = millis() + delayInMillis;
while (millis() < t) virtuinoRun();
}
void makeVirtuinoPayload() {
V[10] = 11;
V[11] = 10;
V[12] = slx;
V[13] = sly;
V[14] = psx.buttonPressed(PSB_L3);
V[15] = srx;
V[16] = sry;
V[17] = psx.buttonPressed(PSB_R3);
V[18] = psx.buttonPressed(PSB_SELECT);
V[19] = psx.buttonPressed(PSB_START);
V[20] = psx.buttonPressed(PSB_CROSS);
V[21] = psx.buttonPressed(PSB_CIRCLE);
V[22] = psx.buttonPressed(PSB_SQUARE);
V[23] = psx.buttonPressed(PSB_TRIANGLE);
V[24] = psx.buttonPressed(PSB_L1);
V[25] = psx.buttonPressed(PSB_L2);
V[26] = psx.buttonPressed(PSB_R1);
V[27] = psx.buttonPressed(PSB_R2);
V[28] = psx.buttonPressed(PSB_PAD_UP);
V[29] = psx.buttonPressed(PSB_PAD_DOWN);
V[30] = psx.buttonPressed(PSB_PAD_LEFT);
V[31] = psx.buttonPressed(PSB_PAD_RIGHT);
//V[32] = 0; //controller connected status
//V[33] = 0; //controller in config mode error
//V[34] = 0; //radio initialized
V[35] = 0;
V[36] = 0;
V[37] = 0;
V[38] = 0;
V[39] = 0;
V[40] = 0;
//Serial.println("99");
}
//////////////////////////////////////////////////////////////////////////////////////////////////////// timer
bool TimerHandler0(struct repeating_timer * t)
{
if (DoTimer) {
ReadController();
makeVirtuinoPayload();
virtuinoRun();
}
return true;
}
/*
bool TimerHandler1(struct repeating_timer * t)
{
Serial.print("ITimer1: millis() = "); Serial.println(millis());
makeVirtuinoPayload();
// virtuinoRun();
return true;
}*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////serial terminal
void Do_Terminal() { // Heavily Modified Version of >> TFT ILI9340 Serial Terminal Sketch by M. Ray Burnette ==> Public Domain 04/20/2014
String lBlank = "";
lDebug = true ;
int fh = tft.fontHeight();
int fw = tft.textWidth("A");
int lChar = tft.getViewportWidth() / fw;
int lNum = tft.getViewportHeight() / fh;
int viewPortMaxChars = lNum * lChar;
if ( ! lFlag ) // new line roll-over cleanup
{
nCol = 0 ; // align character pointer to "x" home
Tindex = int(nLCD / lChar) ; // character pointer to current-line to graphic "y" lookup of home character
//nRow = yCord[ Tindex ] ; // [0 - 14] ==> lines 1 - 15
nRow = fh * Tindex; // [0 - 14] ==> lines 1 - 15
if (lDebug)
{
Serial << "Inside flag routine! \n \r" ;
Serial << "nCol / nRow / nLCD = " << nCol << " / " << nRow << " / " << nLCD << "\n \r" ;
}
tft.setCursor (nCol, nRow) ; // restore cursor to home character of current line
//tft.print( sBlank ) ; // clear line
//tft.drawLine( x1, y1, x2, y2, color);
tft.fillRect( 0, nRow, 475, fh, TFT_BLACK);
tft.drawLine( 0, (nRow + fh), 390, (nRow + fh), TFT_YELLOW);
tft.setCursor (nCol, nRow) ; // restore cursor to home character of current line
lFlag = true ; // reset flag for normal operation
}
// read data from serial port
if (Serial.available())
{
char c = Serial.read() ;
if (c) // non-Null
{
if ( c > 31 && c < 127)
{
tft.print(c) ; // keep non-printables off LCD
++nLCD ; // increment character count
}
if ( c == 13 ) // carriage return?
{
c = 0 ;
//tft.print( sBlank ) ; // clear line from current position, may wrap
nRow = (nLCD / lChar) + 1 ; // next row (row == 0, 1, ... 14)
if ( nRow > lNum - 5 ) nRow = 0 ; // maintain boundary minus 3 lines at bottom for menu bar.
Tindex = nRow ; // array index for graphic "Y" position of first character
nCol = 0 ; // "X" Graphic coordinate
nRow = fh * Tindex; ; // Graphic "Y" coordinate via lookup
nLCD = Tindex * lChar ; // 26 characters per line (line = nRow +1)
tft.setCursor (nCol, nRow) ; // restore cursor to home character of current line
//lcd.print( sBlank ) ; // clear NEW line
//tft.setCursor (nCol, nRow) ; // restore cursor to home character of current line
if (lDebug)
{
Serial << "Return Pressed! " << "nCol / nRow / nLCD == " ;
Serial << nCol << " / " << nRow << " / " << nLCD << " / " << lNum << "\n \r" ;
}
}
if ( nLCD % lChar == 0 ) // just printed last character on line?
{
if (lDebug) Serial << "Last character of line printed! " ;
if ( nLCD == viewPortMaxChars) // last character of last line?
{
if (lDebug) Serial << "End of display! \n \r" ;
nLCD = 0 ;
c = 0 ;
lFlag = false ;
}
else
{
lFlag = false ; // activate clean-up routine
//nLCD++ ; // increment to 1st position next line
for (int i = 0; i <= nLCD % termLineW; i++) { //create variable that contains white space for line remainder chars
lBlank = lBlank + " "; //add number of blanks to line end variable
}
tft.print( lBlank ) ; // clear end of line and some of next //print the line blank
if (lDebug) Serial << "nCol / nRow / nLCD == " << nCol << " / " << nRow << " / " << nRow << "\n \r";
lBlank = ""; //reset the line blank varibale to nothing
}
}
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////SD Functions
// Initialize SD card
bool SDCardInit( uint32_t frequency, bool debug ) {
bool init = false;
SDStarted = false;
if (!SDfirstTry) {
if (debug) {
tft.print(F("\nRestarting SD Init\n"));
}
}
SDfirstTry = false;
if (debug) {
tft.print(F("SD_SSPIN: ")); tft.println(PIN_SD_SS);
}
if (DISABLE_CHIP_SELECT < 0) {
if (debug) {
tft.print("Assuming the SD is the only SPI device, Edit DISABLE_CHIP_SELECT to disable another device.\n");
}
} else {
if (debug) {
tft.print(F("Disabling SPI device on pin: ")); tft.println(DISABLE_CHIP_SELECT);
}
pinMode(DISABLE_CHIP_SELECT, OUTPUT);
digitalWrite(DISABLE_CHIP_SELECT, HIGH);
}
if (!sd.begin(PIN_SD_SS, SD_SCK_MHZ(frequency))) {
if (sd.card()->errorCode()) {
if (debug) {
tft.print(F(
"\nSD initialization failed.\n"
"Do not reformat the card!\n"
"Is the card correctly inserted?\n"
"Is chipSelect set to the correct value?\n"
"Does another SPI device need to be disabled?\n"
"Is there a wiring/soldering problem?\n"));
tft.print(F("\nerrorCode: "));
tft.print(int(sd.card()->errorCode()));
tft.print(F(", errorData: ")); tft.println(sd.card()->errorData());
}
return init;
}
if (debug) {
tft.println(F("Card successfully initialized."));
tft.println(int(sd.card()->type()));
switch (sd.card()->type()) { //0 - SD V1, 1 - SD V2, or 3 - SDHC.
case 0:
tft.println(F("Card Type is SD V1"));
break;
case 1:
tft.println(F("Card Type is SD V2"));
break;
case 2:
tft.println(F("Card Type is SDHC"));
break;
default:
tft.println(F("Unable to determine card Type"));
break;
}
}
if (sd.vol()->fatType() == 0) {
if (debug) {
tft.print(F("Can't find a valid FAT16/FAT32 partition.\n"));
tft.print(F("Try reformatting the card. For best results use\n"));
tft.print(F("the SdFormatter program in SdFat/examples or download\n"));
tft.print(F("and use SDFormatter from www.sdcard.org/downloads.\n"));
}
return init;
} else {
if (debug) {
switch (int(sd.vol()->fatType())) { //The FAT type of the volume. Values are 12, 16 or 32.
case 12:
tft.println(F("Volume Type is FAT12"));
break;
case 16:
tft.println(F("Volume Type is FAT16"));
break;
case 32:
tft.println(F("Volume Type is FAT32"));
break;
default:
tft.println(F("Unable to determine Volume Type"));
break;
}
}
}
if (debug) {
tft.println(F("Can't determine error type"));
}
return init;
}
if (debug) {
tft.println(F("Card successfully initialized."));
}
uint32_t size = sd.card()->sectorCount();
if (size == 0) {
if (debug) {
tft.print(F("Can't determine the card size.\n"));
tft.print(F("Try another SD card or reduce the SPI bus speed.\n"));
tft.print(F("Edit SPI_SPEED in this program to change it.\n"));
}
return init;
}
uint32_t sizeMB = 0.000512 * size + 0.5;
if (debug) {
tft.print(F("Card size: ")); tft.print(sizeMB);
tft.print(F(" MB (MB = 1,000,000 bytes)\n"));
tft.print(F("Volume is FAT")); tft.print(int(sd.vol()->fatType()));
tft.print(F(", Cluster size (bytes): ")); tft.println(sd.vol()->bytesPerCluster());
}
//cout << F("Files found (date time size name):\n");
//sd.ls(&tft, LS_R | LS_DATE | LS_SIZE);
////////////// sd.ls(&Serial, LS_R); DOIT
if ((sizeMB > 1100 && sd.vol()->sectorsPerCluster() < 64) || (sizeMB < 2200 && sd.vol()->fatType() == 32)) {
if (debug) {
tft.print(F("\nThis card should be reformatted for best performance.\n Use a cluster size of 32 KB for cards larger than 1 GB.\n Only cards larger than 2 GB should be formatted FAT32.\n"));
}
return init;
}
if (debug) {
tft.println(F("Success! SD Initialized."));
}
volFree = sd.vol()->freeClusterCount();
init = true;
SDStarted = true;
return init;
}
void SDFormat(bool debug) {
bool ok = false;
char c;
String msg = "";
file.close();
sd.end();
msg = (
"\n"
"This program can erase and/or format SD/SDHC/SDXC cards.\n"
"\n"
"Erase uses the card's fast flash erase command.\n"
"Flash erase sets all data to 0X00 for most cards\n"
"and 0XFF for a few vendor's cards.\n"
"\n"
"Cards up to 2 GiB (GiB = 2^30 bytes) will be formated FAT16.\n"
"Cards larger than 2 GiB and up to 32 GiB will be formatted\n"
"FAT32. Cards larger than 32 GiB will be formatted exFAT.\n"
"\n"
"Warning, all data on the card will be erased.\n"
"Press 'Start' to continue, Press 'Select' to Abort");
if (debug) {
tft.println(msg);
}
while (!ok) {//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////Diagnostic Control Structure
if (psx.buttonPressed(PSB_START)) {
ok = true;
tft.fillScreen(TFT_BLACK);
tft.setCursor(0, 0);
}
if (psx.buttonPressed(PSB_SELECT)) {
ok = true;
tft.fillScreen(TFT_BLACK);
tft.setCursor(0, 0);
msg = "Exitting Format utility";
if (debug) {
tft.println(msg);
}
return;
}
}//////////////////////////////////////////////////////////////////////////////////////////////////////////////////control struct end
// Select and initialize proper card driver.
m_card = cardFactory.newCard(SD_CONFIG);
if (!m_card || m_card->errorCode()) {
msg = "card init failed.";
if (debug) {
tft.println(msg);
}
delay(10000);
return;
}
cardSectorCount = m_card->sectorCount();
if (!cardSectorCount) {
msg = "Get sector count failed.";
if (debug) {
tft.println(msg);
}
delay(10000);
return;
}
msg = "\nCard size: " + String(cardSectorCount * 5.12e-7) + " GB (GB = 1E9 bytes)\n";
msg = msg + "Card size: " + String(cardSectorCount / 2097152.0) + " GiB (GiB = 2^30 bytes)\n";
if (debug) {
tft.println(msg);
}
msg = F("Card will be formated ");
if (cardSectorCount > 67108864) {
msg = msg + F("exFAT\n");
} else if (cardSectorCount > 4194304) {
msg = msg + F("FAT32\n");
} else {
msg = msg + F("FAT16\n");
}
if (debug) {
tft.println(msg);
}
msg = F(
"\n"
"Options are:\n"
"SELECT - erase the card and skip formatting.\n"
"START - erase and then format the card. (recommended)\n"
"X - quick format the card without erase.\n"
"TRIANGLE - EXIT utility\n"
"\n"
"Enter option: ");
if (debug) {
tft.println(msg);
}
while (!ok) {//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////Diagnostic Control Structure
if (psx.buttonPressed(PSB_SELECT)) {
//ok = true;
eraseCard(debug);
//return;
}
if (psx.buttonPressed(PSB_START)) {
//ok = true;
eraseCard(debug);
formatCard(debug);
//return;
}
if (psx.buttonPressed(PSB_CROSS)) {
formatCard(debug);
//ok = true;
//return;
}
if (psx.buttonPressed(PSB_TRIANGLE)) {
msg = "Exitting Format utility";
if (debug) {
tft.println(msg);
}
return;
}
}//////////////////////////////////////////////////////////////////////////////////////////////////////////////////control struct end
}
//------------------------------------------------------------------------------
// flash erase all data
void eraseCard(bool debug) {
String msg = "";
msg = F("Erasing\n");
if (debug) {
tft.println(msg);
}
uint32_t firstBlock = 0;
uint32_t lastBlock;
uint16_t n = 0;
do {
lastBlock = firstBlock + ERASE_SIZE - 1;
if (lastBlock >= cardSectorCount) {
lastBlock = cardSectorCount - 1;
}
if (!m_card->erase(firstBlock, lastBlock)) {
msg = F("erase failed");
if (debug) {
tft.println(msg);
}
return;
}
tft.print(".");
if ((n++) % 64 == 63) {
tft.println(".");
}
firstBlock += ERASE_SIZE;
} while (firstBlock < cardSectorCount);
if (!m_card->readSector(0, sectorBuffer)) {
msg = F("readBlock");
if (debug) {
tft.println(msg);
}
return;
}
msg = "All data set to " + String(int(sectorBuffer[0])) + "\n";
msg = msg + "Erase done\n";
if (debug) {
tft.println(msg);
}
}
//------------------------------------------------------------------------------
void formatCard(bool debug) {
String msg = "";
ExFatFormatter exFatFormatter;
FatFormatter fatFormatter;
// Format exFAT if larger than 32GB.
bool rtn = cardSectorCount > 67108864 ?
exFatFormatter.format(m_card, sectorBuffer, &Serial) :
fatFormatter.format(m_card, sectorBuffer, &Serial);
if (!rtn) {
msg = msg + F("Format Failed, Recommend use PC formatter.\n");
if (debug) {
tft.println(msg);
}
delay(10000);
return;
}
msg = msg + F("Format Succeeded!!!.\n");
if (debug) {
tft.println(msg);
}
delay(10000);
return;
}
//------------------------------------------------------------------------------
void SDInfo() {
}
// Unmount SD card
void SDBenchMark(bool debug) {
float s;
uint32_t t;
uint32_t maxLatency;
uint32_t minLatency;
uint32_t totalLatency;
bool skipLatency;
String msg = "";
#if HAS_UNUSED_STACK
if (debug) {
tft.print(F("FreeStack: ")); tft.println(FreeStack());
}
#endif // HAS_UNUSED_STACK
if (!SDStarted) {
if (debug) {
tft.println(F("Attempting to Init SD Card"));
}
if (!SDCardInit(50, debug )) {
if (debug) {
tft.println(F("FAILED to Init SD Card"));
}
return;
} else {
if (debug) {
tft.println(F("Init SD Card SUCCESS"));
}
}
}
if (sd.fatType() == FAT_TYPE_EXFAT) {
if (debug) {
tft.println(F("Type is exFAT"));
}
} else {
if (debug) {
tft.print(F("Type is FAT")); tft.println(int(sd.fatType()));
}
}
if (debug) {
tft.print(F("Card size: ")); tft.print(sd.card()->sectorCount() * 512E-9); tft.println(F(" GB (GB = 1E9 bytes)"));
}
if (!chipIDDmp(debug)) {
if (debug) {
tft.print(F("Chip ID Dump FAILED "));
}
}
// open or create file - truncate existing file.
if (!file.open("bench.dat", O_RDWR | O_CREAT | O_TRUNC)) {
if (debug) {
tft.print(F("File open FAILED "));
}
}
// fill buf with known data
if (BUF_SIZE > 1) {
for (size_t i = 0; i < (BUF_SIZE - 2); i++) {
buf[i] = 'A' + (i % 26);
}
buf[BUF_SIZE - 2] = '\r';
}
buf[BUF_SIZE - 1] = '\n';
msg = "\nFILE_SIZE_MB = " + String(FILE_SIZE_MB);
msg = msg + F("\nBUF_SIZE = ") + String(BUF_SIZE) + F(" bytes");
msg = msg + F("\nStarting write test, please wait.");
if (debug) {
tft.println(msg);
}
DoTimer = false;
// do write test
uint32_t n = FILE_SIZE / BUF_SIZE;
msg = F("\nWrite speed and latency");
msg = msg + F("\nSpeed,max,min,avg");
msg = msg + F("\nKB/Sec,usec,usec,usec");
if (debug) {
tft.println(msg);
}
for (uint8_t nTest = 0; nTest < WRITE_COUNT; nTest++) {
file.truncate(0);
if (PRE_ALLOCATE) {
if (!file.preAllocate(FILE_SIZE)) {
if (debug) {
tft.println("preAllocate failed");
}
return;
}
}
maxLatency = 0;
minLatency = 9999999;
totalLatency = 0;
skipLatency = SKIP_FIRST_LATENCY;
t = millis();
for (uint32_t i = 0; i < n; i++) {
uint32_t m = micros();
if (file.write(buf, BUF_SIZE) != BUF_SIZE) {
if (debug) {
tft.println("write failed");
}
return;
}
m = micros() - m;
totalLatency += m;
if (skipLatency) {
// Wait until first write to SD, not just a copy to the cache.
skipLatency = file.curPosition() < 512;
} else {
if (maxLatency < m) {
maxLatency = m;
}
if (minLatency > m) {
minLatency = m;
}
}
}
file.sync();
t = millis() - t;
s = file.fileSize();
msg = String(s / t) + F(",") + String(maxLatency) + F(",") + String(minLatency) + F(",") + String(totalLatency) + F("\n");
if (debug) {
tft.println(msg);
}
}
tft.fillScreen(TFT_BLACK);
tft.setCursor(0, 0);
msg = F("\nStarting read test, please wait.");
msg = msg + F("\nread speed and latency");
msg = msg + F("\nSpeed,max,min,avg");
msg = msg + F("\nKB/Sec,usec,usec,usec");
if (debug) {
tft.println(msg);
}
// do read test
for (uint8_t nTest = 0; nTest < READ_COUNT; nTest++) {
file.rewind();
maxLatency = 0;
minLatency = 9999999;
totalLatency = 0;
skipLatency = SKIP_FIRST_LATENCY;
t = millis();
for (uint32_t i = 0; i < n; i++) {
buf[BUF_SIZE - 1] = 0;
uint32_t m = micros();
int32_t nr = file.read(buf, BUF_SIZE);
if (nr != BUF_SIZE) {
if (debug) {
tft.println("read failed");
}
return;
}
m = micros() - m;
totalLatency += m;
if (buf[BUF_SIZE - 1] != '\n') {
if (debug) {
tft.println("data check error");
}
return;
}
if (skipLatency) {
skipLatency = false;
} else {
if (maxLatency < m) {
maxLatency = m;
}
if (minLatency > m) {
minLatency = m;
}
}
}
s = file.fileSize();
t = millis() - t;
msg = String(s / t) + F(",") + String(maxLatency) + F(",") + String(minLatency) + F(",") + String(totalLatency) + F("\n");
if (debug) {
tft.println(msg);
}
}
haveController = false;
InitController(false, 0);
DoTimer = true;
if (debug) {
tft.println(F("Done"));
}
file.close();
return;
}
bool chipIDDmp(bool debug) {
cid_t cid;
bool init = false;
String msg = "";
if (!sd.card()->readCID(&cid)) {
if (debug) {
tft.println(F("readCID failed"));
return init;
}
}
if (debug) {
msg = "\nManufacturer ID: " + String(cid.mid) + F("\nOEM ID: ") + String(cid.oid[0]) + String(cid.oid[1]) + F("\nProduct: ");
for (uint8_t i = 0; i < 5; i++) {
msg = msg + String(cid.pnm[i]);
}
msg = msg + "\nRevision: " + String(cid.prvN()) + F(".") + String(cid.prvM());
msg = msg + "\nSerial number: " + String(cid.psn());
msg = msg + "\nManufacturing date: " + String(cid.mdtMonth()) + F("/") + String(cid.mdtYear());
tft.println(msg);
}
init = true;
return init;
}
void SDCardUnmount() {
Serial.print( "Unmounting SD card..." );
file.close();
sd.end();
// Unmount SD card
//card.end();
// figure it ojut
Serial.println( "done." );
}