#include <Wire.h>
#include <WiFi.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <Adafruit_FT6206.h>
#include <Keypad.h>
// TFT display pins
#define TFT_CS 5
#define TFT_DC 2
#define TFT_RST 4
#define TFT_MOSI 23
#define TFT_CLK 18
#define TFT_MISO 19
bool aUpperCase = false; // Global variable to track capital mode
uint8_t keyPressCount[10] = {0}; // Global array to track key press counts
String inputText; // Declare inputText globally
// I2C pins for ESP32
#define SDA_PIN 21
#define SCL_PIN 22
bool isWiFiScannerActive = false; // Flag to indicate the current context
const byte ROWS = 4; // Four rows
const byte COLS = 3; // Three columns
// Keypad layout for a 3x4 keypad
char keys[ROWS][COLS] = {
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'},
{'*', '0', '#'}
};
// GPIO pins for rows and columns on the ESP32
byte rowPins[ROWS] = {32, 33, 25, 26}; // Row pins
byte colPins[COLS] = {27, 14, 12}; // Column pins
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// Screen dimensions
#define TFT_WIDTH 320
#define TFT_HEIGHT 240
// Menu configuration
const int MENU_ROWS = 2;
const int MENU_COLS = 3;
const int BOX_PADDING = 10; // Padding around each box
const int BOX_WIDTH = (TFT_WIDTH / MENU_COLS) - BOX_PADDING * 2;
const int BOX_HEIGHT = (TFT_HEIGHT / MENU_ROWS) - BOX_PADDING * 2;
char boxes[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'};
int currentMenuStart = 0;
int selectedBoxIndex = -1; // Start with no selection
bool isBoxSelected = false;
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
Adafruit_FT6206 ts = Adafruit_FT6206();
// Coordinates for the refresh button
#define REFRESH_BUTTON_X 10
#define REFRESH_BUTTON_Y 200
#define REFRESH_BUTTON_W 100
#define REFRESH_BUTTON_H 30
String inputBuffer = "";
String t9Buffer = "";
unsigned long lastKeyPressTime = 0;
const unsigned long keyPressDelay = 500; // 0.5 second delay
void setup() {
Serial.begin(115200);
// Initialize the TFT display
tft.begin();
// Start with lowercase mode
memset(keyPressCount, 0, sizeof(keyPressCount));
tft.setRotation(1);
tft.fillScreen(ILI9341_BLACK);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
Wire.begin();
// Initialize WiFi
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(100);
// Print header on TFT display
// Initialize the touch screen
if (!ts.begin(40)) {
Serial.println("Unable to start touchscreen.");
while (1);
}
// Display the initial menu
displayMenu();
}
void loop() {
if (ts.touched()) {
TS_Point p = ts.getPoint();
p.x = map(p.x, 0, 240, 240, 0);
if (!isBoxSelected) {
handleMenuTouch(p.x, p.y);
} else {
handleSelectedBoxTouch(p.x, p.y);
}
delay(200); // Debounce delay
}
if (selectedBoxIndex == 1) { // Only handle keypad input for option B
char key = keypad.getKey();
if (key) {
handleKeypadInput(key);
}
}
}
void displayMenu() {
tft.fillScreen(ILI9341_BLACK);
int index = 0;
for (int row = 0; row < MENU_ROWS; row++) {
for (int col = 0; col < MENU_COLS; col++) {
if (currentMenuStart + index < sizeof(boxes)) {
int x = col * (BOX_WIDTH + BOX_PADDING * 2) + BOX_PADDING;
int y = row * (BOX_HEIGHT + BOX_PADDING * 2) + BOX_PADDING;
tft.fillRect(x, y, BOX_WIDTH, BOX_HEIGHT, ILI9341_BLUE);
tft.setCursor(x + BOX_WIDTH / 2 - 10, y + BOX_HEIGHT / 2 - 10);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(3);
tft.print(boxes[currentMenuStart + index]);
index++;
}
}
}
}
void handleMenuTouch(int x, int y) {
// Calculate column and row indices without adjusting for padding
int col = y / (BOX_WIDTH + BOX_PADDING);
int row = x / (BOX_HEIGHT + BOX_PADDING);
// Calculate the index of the selected box
int index = currentMenuStart + (row * MENU_COLS + col);
// Check if the index is valid and within the bounds of the menu items
if (index >= 0 && index < sizeof(boxes) && currentMenuStart + index < sizeof(boxes)) {
selectedBoxIndex = index;
selectBox();
}
}
void handleSelectedBoxTouch(int x, int y) {
if (selectedBoxIndex == 1) { // Box 'B' selected
if (isWithinButton(x, y)) {
// Handle WiFi password input with T9 keypad logic
inputText = ""; // Clear input text initially
updateTextDisplay(); // Update the display
while (!isBoxSelected) {
char key = keypad.getKey(); // Get key from keypad
if (key != NO_KEY) {
handleKeypadInput(key); // Handle T9 keypad input
}
// Example: You might add a condition to exit the loop based on some user input or timeout
// For simplicity, this example uses a break condition to return to the menu.
}
// After input is complete, you can proceed with connecting to WiFi or other actions
// Example: Connect to WiFi using the entered password
// Once WiFi connection is established, you can return to the menu
backToMenu();
} else {
backToMenu(); // If outside the button, return to menu
}
} else {
backToMenu(); // If not box 'B', return to menu
}
}
bool isWithinButton(int x, int y) {
return (x >= REFRESH_BUTTON_X && x <= REFRESH_BUTTON_X + REFRESH_BUTTON_W &&
y >= REFRESH_BUTTON_Y && y <= REFRESH_BUTTON_Y + REFRESH_BUTTON_H);
}
void drawRefreshButton() {
tft.fillRect(REFRESH_BUTTON_X, REFRESH_BUTTON_Y, REFRESH_BUTTON_W, REFRESH_BUTTON_H, ILI9341_BLUE);
tft.setCursor(REFRESH_BUTTON_X + 10, REFRESH_BUTTON_Y + 7);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
tft.print("Refresh");
}
void selectBox() {
if(selectedBoxIndex ==0){
scanAndIdentifyI2CDevices() ;
}else if (selectedBoxIndex == 1) {
scanAndDisplayWiFiNetworks();
} else {
int selectedIndex = currentMenuStart + selectedBoxIndex;
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(110, 60);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(15);
tft.print(boxes[selectedIndex]);
isBoxSelected = true;
}
}
void backToMenu() {
if (isBoxSelected) {
isBoxSelected = false;
inputText = ""; // Clear input text when returning to menu
displayMenu();
}
}
void scanAndIdentifyI2CDevices() {
byte error, address;
int deviceCount = 0;
// Clear the screen and prepare for display
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(10, 10);
tft.setTextSize(3);
tft.print("Scanning I2C bus...");
delay(1000); // Delay for visibility
tft.fillScreen(ILI9341_BLACK);
// Known I2C addresses for specific devices
struct Device {
uint8_t address;
const char *name;
};
Device devices[] = {
{0x3C, "OLED Display"}, // OLED display
{0x27, "LCD Display"}, // LCD display with PCF8574 I/O expander
{0x50, "EEPROM (AT24C32)"}, // EEPROM memory
{0x68, "RTC Module"}, // RTC module
{0x76, "Barometric Sensor"}, // Barometric pressure sensor
{0x40, "Temperature Sensor"}, // Temperature sensor
{0x41, "Digital Potentiometer"},// Digital potentiometer
{0x48, "ADC (ADS1115)"}, // ADC (Analog-to-Digital Converter)
{0x60, "Accelerometer"}, // Accelerometer
{0x61, "Gyroscope"}, // Gyroscope
{0x68, "IMU (MPU6050)"}, // Inertial Measurement Unit
{0x70, "EEPROM (24AA02)"}, // EEPROM memory
{0x71, "IO Expander (MCP23017)"},// I/O Expander
{0x72, "IO Expander (MCP23008)"},// I/O Expander
{0x76, "Pressure Sensor (MS5611)"},// Pressure sensor
{0x77, "Pressure Sensor (BMP180)"},// Pressure sensor
{0x38, "TFT Display"},
{0x08, "Accelerometer (ADXL345)"}, // Accelerometer
{0x0C, "Gyroscope (L3GD20)"}, // Gyroscope
{0x18, "Temperature/Humidity Sensor (HTU21D)"}, // Temperature and Humidity Sensor
{0x1E, "Compass (HMC5883L)"}, // Magnetometer/Compass
{0x21, "Color Sensor (TCS34725)"}, // Color sensor
{0x23, "Lux Meter (TSL2561)"}, // Light sensor (Lux meter)
{0x29, "Ambient Light Sensor (LTR-559)"}, // Ambient light sensor
{0x39, "Ambient Light Sensor (VEML7700)"},// Ambient light sensor
{0x48, "ADC (ADS1115)"}, // Analog-to-Digital Converter
{0x50, "EEPROM (AT24C32)"}, // EEPROM memory
{0x57, "Proximity Sensor (VL6180X)"}, // Proximity sensor
{0x60, "Pressure Sensor (MS5611)"}, // Barometric pressure sensor
{0x68, "RTC Module (DS3231)"}, // Real-Time Clock module
{0x76, "Barometric Sensor (BMP280)"}, // Barometric pressure sensor
{0x77, "Pressure Sensor (BMP180)"}, // Pressure sensor
{0x78, "EEPROM (24AA02)"}, // EEPROM memory
{0x7A, "Temperature Sensor (TMP102)"}, // Temperature sensor
{0x7F, "IO Expander (PCF8574)"}, // I/O Expander
// Add more devices as needed
};
for (address = 1; address < 127; address++) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
// Device found, print address and name to TFT display
tft.setCursor(10, 10);
tft.setTextSize(3);
tft.print("Device Found");
tft.setCursor(10, 50 + deviceCount * 20);
tft.setTextSize(2);
tft.setTextColor(ILI9341_GREEN);
tft.print("0x");
if (address < 16) {
tft.print("0");
}
tft.print(address, HEX);
// Check if the found address matches known devices
bool identified = false;
for (int i = 0; i < sizeof(devices) / sizeof(devices[0]); i++) {
if (address == devices[i].address) {
tft.print(" - ");
tft.print(devices[i].name);
identified = true;
break;
}
}
if (!identified) {
tft.print(" - Unknown Device");
}
deviceCount++;
delay(500);
}
}
// Display message if no devices found
if (deviceCount == 0) {
tft.setCursor(10, 50);
tft.setTextSize(2);
tft.setTextColor(ILI9341_WHITE);
tft.print("No I2C devices found.");
}
// Draw the refresh button
drawRefreshButton();
}
void scanAndDisplayWiFiNetworks() {
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(10, 10);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(3);
tft.print("Scanning WiFi...");
// Perform WiFi scan
int numNetworks = WiFi.scanNetworks();
// Clear previous content before displaying results
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(10, 10);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
if (numNetworks == 0) {
tft.print("No networks found.");
} else {
tft.print("Networks found:");
for (int i = 0; i < numNetworks; ++i) {
tft.setCursor(10, 30 + (i * 20));
tft.print(i + 1);
tft.print(": ");
tft.print(WiFi.SSID(i));
tft.print(" (");
tft.print(WiFi.RSSI(i));
tft.print(")");
}
}
// Optional: Draw back button to return to the main menu
drawBackButton();
}
void drawBackButton() {
tft.fillRect(10, 200, 100, 30, ILI9341_BLUE);
tft.setCursor(20, 210);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
tft.print("Back");
}
bool isWithinBackButton(int x, int y) {
return (x >= 10 && x <= 110 && y >= 200 && y <= 230);
}
void handleKeypadInput(char key) {
unsigned long currentTime = millis();
switch (key) {
case '1':
aUpperCase = !aUpperCase; // Toggle uppercase mode
break;
case '*':
if (inputBuffer.length() > 0) {
inputBuffer.remove(inputBuffer.length() - 1); // Remove the last character
}
break;
case '#':
inputBuffer = ""; // Clear the input buffer
break;
case '0':
inputBuffer += ' '; // Add space character
break;
default:
if (currentTime - lastKeyPressTime < keyPressDelay) {
// Continue T9 typing on the same key
int keyIndex = key - '0';
char nextChar = getT9Character(keyIndex);
inputBuffer.remove(inputBuffer.length() - 1); // Remove the previous character
inputBuffer += nextChar; // Add the new character
} else {
// Start a new T9 typing sequence
int keyIndex = key - '0';
char initialChar = getT9Character(keyIndex);
inputBuffer += initialChar;
keyPressCount[keyIndex] = 1; // Reset key press count
}
lastKeyPressTime = currentTime; // Update the last key press time
break;
}
updateTextDisplay();
}
char getT9Character(int keyIndex) {
// T9 character sets for keys 0-9
const char *t9Chars[] = {
"0", // Key 0
"1", // Key 1
"2ABC", // Key 2
"3DEF", // Key 3
"4GHI", // Key 4
"5JKL", // Key 5
"6MNO", // Key 6
"7PQRS", // Key 7
"8TUV", // Key 8
"9WXYZ" // Key 9
};
int charSetLength = strlen(t9Chars[keyIndex]);
int charIndex = keyPressCount[keyIndex] % charSetLength;
char character = t9Chars[keyIndex][charIndex];
if (!aUpperCase) {
character = tolower(character); // Convert to lowercase if not in uppercase mode
}
keyPressCount[keyIndex]++;
return character;
}
void updateTextDisplay() {
tft.fillRect(0, 200, TFT_WIDTH, 60, ILI9341_BLACK); // Clear the previous text area
tft.setCursor(10, 200);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(3);
tft.print(inputBuffer); // Display the current input text
}