/**
ESP32s3 adaptation by Tyeth Gundry of Arduino version of
First demo for FT6206 Capactive Touch Screen on Wokwi. Enjoy!
https://wokwi.com/arduino/projects/311598148845830720
*/
/***************************************************
This is our touchscreen painting example for the Adafruit ILI9341
captouch shield
----> http://www.adafruit.com/products/1947
Check out the links above for our tutorials and wiring diagrams
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/
#include <Adafruit_GFX.h> // Core graphics library
#include <SPI.h> // this is needed for display
#include <Adafruit_ILI9341.h>
#include <Arduino.h> // this is needed for FT6206
#include <Adafruit_FT6206.h>
#include <FS.h>
#include <SD.h>
#define SPI_SPEED SD_SCK_MHZ(50)
// Declare SD card pins
#define SD_MOSI 40 // DI pin
#define SD_MISO 1 // DO pin
#define SD_SCLK 39 // SCK pin
#define SD_CS 38 // CS pin
File root;
int day = 1;
float mileage = 135.3;
const byte numChars = 10;
boolean newData = false;
char notes[numChars] = "";
String dataArray[100];
int dataIndex = 0;
// The FT6206 uses hardware I2C (SCL/SDA)
Adafruit_FT6206 ctp = Adafruit_FT6206();
// // The display also uses hardware SPI, plus #9 & #10
// #define TFT_CS 10
// #define TFT_DC 9
#define TFT_CS 10
#define TFT_DC 9
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// Size of the color selection boxes and the paintbrush size
#define BOXSIZE 40
#define PENRADIUS 3
int oldcolor, currentcolor;
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
Serial.printf("Listing directory: %s\n", dirname);
File root = fs.open(dirname);
if(!root){
Serial.println("Failed to open directory");
return;
}
if(!root.isDirectory()){
Serial.println("Not a directory");
return;
}
File file = root.openNextFile();
while(file){
if(file.isDirectory()){
Serial.print(" DIR : ");
Serial.println(file.name());
if(levels){
listDir(fs, file.path(), levels -1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void createDir(fs::FS &fs, const char * path){
Serial.printf("Creating Dir: %s\n", path);
if(fs.mkdir(path)){
Serial.println("Dir created");
} else {
Serial.println("mkdir failed");
}
}
void removeDir(fs::FS &fs, const char * path){
Serial.printf("Removing Dir: %s\n", path);
if(fs.rmdir(path)){
Serial.println("Dir removed");
} else {
Serial.println("rmdir failed");
}
}
void readFile(fs::FS &fs, const char * path){
Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if(!file){
Serial.println("Failed to open file for reading");
return;
}
Serial.println("Read from file: ");
while(file.available()){
Serial.write(file.read());
}
file.close();
}
void writeFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
if(file.print(message)){
Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}
void appendFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file){
Serial.println("Failed to open file for appending");
return;
}
if(file.print(message)){
Serial.println("Data appended");
} else {
Serial.println("Append failed");
}
file.close();
}
/*
void renameFile(fs::FS &fs, const char * path1, const char * path2){
Serial.printf("Renaming file %s to %s\n", path1, path2);
if (fs.rename(path1, path2)) {
Serial.println("File renamed");
} else {
Serial.println("Rename failed");
}
}
void deleteFile(fs::FS &fs, const char * path){
Serial.printf("Deleting file: %s\n", path);
if(fs.remove(path)){
Serial.println("File deleted");
} else {
Serial.println("Delete failed");
}
}
void testFileIO(fs::FS &fs, const char * path){
File file = fs.open(path);
static uint8_t buf[512];
size_t len = 0;
uint32_t start = millis();
uint32_t end = start;
if(file){
len = file.size();
size_t flen = len;
start = millis();
while(len){
size_t toRead = len;
if(toRead > 512){
toRead = 512;
}
file.read(buf, toRead);
len -= toRead;
}
end = millis() - start;
Serial.printf("%u bytes read for %u ms\n", flen, end);
file.close();
} else {
Serial.println("Failed to open file for reading");
}
file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
size_t i;
start = millis();
for(i=0; i<2048; i++){
file.write(buf, 512);
}
end = millis() - start;
Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
file.close();
}
*/
// Read Serial with endmarker '\n'
void recvWithEndMarker() {
boolean exceeded = false;
static byte ndx = 0;
char endMarker = '\n';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (rc != endMarker && ndx <= numChars-1 ) {
notes[ndx] = rc;
ndx++;
}
else if (ndx >= numChars){
ndx++;
exceeded = true;
}
else{
notes[ndx] = '\0'; // terminate the string
ndx = 0;
newData = true;
return;
}
} // end while
if (exceeded){
Serial.println("Number of characters exceeded. Please try again.");
Serial.println("Message till limit reached:");
Serial.println(notes);
ndx = 0;
exceeded = false;
return;
} // end if
}
/*
// Populates data from csv in struct
void read2struct(fs::FS &fs, const char * path){
Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if(!file){
Serial.println("Failed to open file for reading");
return;
}
while(file.available()){
// Read a line from the file
String line = file.readStringUntil('\n');
// Parse the CSV data
char* lineChar = &line[0u];
char* dateStr = strtok(lineChar, ",");
char* milesStr = strtok(NULL, ",");
char* noteStr = strtok(NULL, ",");
// Store the data in a struct
Data data;
data.date = String(dateStr);
data.miles = String(milesStr);
data.note = String(noteStr);
// Store the struct in the array
dataArray[dataIndex] = data;
dataIndex++;
// Now you can use data.date, data.data, and data.info
}
file.close();
}
*/
// Populates data from csv in array on a line by line basis
void read2array(fs::FS &fs, const char * path){
Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if(!file){
Serial.println("Failed to open file for reading");
return;
}
while(file.available()){
// Read a line from the file
String line = file.readStringUntil('\n');
// Store the line in the array
dataArray[dataIndex] = line;
dataIndex++;
}
file.close();
}
void setup(void) {
//while (!Serial); // used for leonardo debugging
Serial.begin(115200);
Serial.print("Initializing SD card...\n");
SPI.begin(SD_SCLK, SD_MISO, SD_MOSI, SD_CS);
if (!SD.begin(SD_CS)) {
Serial.println("Card initialization failed!");
while (true);
}
Serial.println("initialization done.");
uint32_t cardSize = SD.cardSize() / (1024 * 1024);
String str = "SDCard Size: " + String(cardSize) + "MB";
Serial.println(str);
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE) {
Serial.println("No SD card attached");
}
listDir(SD, "/", 0);
readFile(SD, "/wokwi.csv");
Serial.printf("\nTotal space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
Serial.println(F("Cap Touch Paint!"));
Wire.setPins(18, 8); // redefine first I2C port to be on pins 10/8
tft.begin();
if (! ctp.begin(40)) { // pass in 'sensitivity' coefficient
Serial.println("Couldn't start FT6206 touchscreen controller");
while (1);
}
Serial.println("Capacitive touchscreen started");
tft.fillScreen(ILI9341_BLACK);
// make the color selection boxes
tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED);
tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW);
tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN);
tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN);
tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE);
tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA);
// select the current color 'red'
tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
currentcolor = ILI9341_RED;
}
void loop() {
recvWithEndMarker();
// If data was received from serial
if (newData == true && strlen(notes) > 1) {
Serial.print("notes: ");
Serial.println(notes);
Serial.print("length: ");
Serial.println(strlen(notes));
// Build date string
// Initialize EMPTY character arrays
char dateString[13]="";
char buffer1[3]="";
// Convert int to strings
itoa(day,buffer1,10);
strcat(dateString, "10/");
strcat(dateString, buffer1);
strcat(dateString, "/2024");
day = day+1;
// Build mileage string
char mileageString[9]="";
dtostrf(mileage,-8,1,mileageString); // floatvalue, minimumwidth (includes . and - signs)(if negative, left justified, otherwise right justified), #decimalpoints, buffer
mileage = mileage + random(1000);
// Append separate strings to format for CSV file
char data[numChars+20]="";
strcat(data, "\n");
strcat(data,dateString);
strcat(data,",");
strcat(data,mileageString);
strcat(data,",");
strcat(data,notes);
// Save dataString to CSV file
appendFile(SD, "/wokwi.csv", data); // save to SD card
//// Delete out old message
//notes[0] = '\0';
// Update flag
newData = false;
readFile(SD, "/wokwi.csv"); // Show file
Serial.println("");
}
else if (newData == true && strlen(notes) == 1){
newData = false;
//read2struct(SD, "/wokwi.csv");
read2array(SD, "/wokwi.csv");
Serial.println(dataArray[0]);
Serial.println(dataArray[3]);
/*
// Access struct:
Serial.println(dataArray[0].date); // Arrays are 0-indexed, so index 1 is the second line
Serial.println(dataArray[0].miles); // Arrays are 0-indexed, so index 1 is the second line
Serial.println(dataArray[0].note); // Arrays are 0-indexed, so index 1 is the second line
Serial.println(dataArray[1].date); // Arrays are 0-indexed, so index 1 is the second line
Serial.println(dataArray[1].miles); // Arrays are 0-indexed, so index 1 is the second line
Serial.println(dataArray[1].note); // Arrays are 0-indexed, so index 1 is the second line
*/
}
delay(10);
// Wait for a touch
if (! ctp.touched()) {
return;
}
// Retrieve a point
TS_Point p = ctp.getPoint();
/*
// Print out raw data from screen touch controller
Serial.print("X = "); Serial.print(p.x);
Serial.print("\tY = "); Serial.print(p.y);
Serial.print(" -> ");
*/
// flip it around to match the screen.
p.x = map(p.x, 0, 240, 240, 0);
p.y = map(p.y, 0, 320, 320, 0);
// Print out the remapped (rotated) coordinates
Serial.print("("); Serial.print(p.x);
Serial.print(", "); Serial.print(p.y);
Serial.println(")");
if (p.y < BOXSIZE) {
oldcolor = currentcolor;
if (p.x < BOXSIZE) {
currentcolor = ILI9341_RED;
tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*2) {
currentcolor = ILI9341_YELLOW;
tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*3) {
currentcolor = ILI9341_GREEN;
tft.drawRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*4) {
currentcolor = ILI9341_CYAN;
tft.drawRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*5) {
currentcolor = ILI9341_BLUE;
tft.drawRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x <= BOXSIZE*6) {
currentcolor = ILI9341_MAGENTA;
tft.drawRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
}
if (oldcolor != currentcolor) {
if (oldcolor == ILI9341_RED)
tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED);
if (oldcolor == ILI9341_YELLOW)
tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW);
if (oldcolor == ILI9341_GREEN)
tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN);
if (oldcolor == ILI9341_CYAN)
tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN);
if (oldcolor == ILI9341_BLUE)
tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE);
if (oldcolor == ILI9341_MAGENTA)
tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA);
}
}
if (((p.y-PENRADIUS) > BOXSIZE) && ((p.y+PENRADIUS) < tft.height())) {
tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor);
}
}
////////////////////////////////////////////////////////////////////////////////////
// /*
// ESP32-S3 + ILI9341 TFT LCD Example
// https://wokwi.com/projects/343784047735997012
// */
// #include "SPI.h"
// #include "Adafruit_GFX.h"
// #include "Adafruit_ILI9341.h"
// #define TFT_DC 2
// #define TFT_CS 15
// Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// void setup() {
// Serial.begin(115200);
// Serial.println("Welcome to Wokwi, ESP32-S3");
// Wire.begin(10,8);
// tft.begin();
// tft.setCursor(44, 120);
// tft.setTextColor(ILI9341_RED);
// tft.setTextSize(3);
// tft.println("ESP32-S3");
// }
// const uint32_t colors[] = {
// ILI9341_GREEN,
// ILI9341_CYAN,
// ILI9341_MAGENTA,
// ILI9341_YELLOW,
// };
// uint8_t colorIndex = 0;
// void loop() {
// tft.setTextSize(2);
// tft.setCursor(26, 164);
// tft.setTextColor(colors[colorIndex++ % 4]);
// tft.println("Welcome to Wokwi!");
// delay(250);
// }