#include <Wire.h>
// You might need to manually add the SparkFun External EEPROM library to Wokwi
// or ensure it's included in the project's libraries.
#include "SparkFun_External_EEPROM.h" // Same library as Project 1
ExternalEEPROM myMem;
// --- Configuration ---
const int EEPROM_ADDR = 0x50; // Default I2C address for 24LC256 (can vary, check datasheet/module)
// Note: The library often handles the address internally based on capacity
const long SERIAL_BAUD = 115200;
const int I2C_SDA_PIN = 21; // Standard SDA pin for ESP32
const int I2C_SCL_PIN = 22; // Standard SCL pin for ESP32
const byte XOR_KEY = 0x5A; // Simple XOR encryption key
const int USER_DATA_START_ADDR = 200; // Starting address for user data
const int USER_DATA_MAX_LEN = 50; // Max length for user string (adjust as needed)
const String PASSWORD = "admin123"; // Password to read data
// --- End Configuration ---
String userDataBuffer = ""; // Buffer for user input
void setup() {
Serial.begin(SERIAL_BAUD);
while (!Serial); // Wait for Serial monitor to open (optional)
Serial.println("\nESP32 EEPROM Test Initializing...");
// Initialize I2C for ESP32, specifying pins
// Wire.begin() on ESP32 often defaults to 21(SDA), 22(SCL)
// But being explicit is good practice.
Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN);
// Configure EEPROM library
// The library uses page size based on capacity (256kbit = 32kByte -> page size might be 64 bytes)
myMem.setMemoryType(256); // 256 Kilobit -> 32 Kilobytes
// Check if EEPROM is connected
if (!myMem.begin()) {
Serial.println("EEPROM not detected! Please check wiring.");
while (1) delay(100); // Halt execution
}
Serial.println("EEPROM detected successfully.");
displayMenu();
}
void loop() {
if (Serial.available()) {
String choice = Serial.readStringUntil('\n');
choice.trim(); // Remove whitespace/newlines
if (choice == "1") {
writeEncryptedUserInput();
} else if (choice == "2") {
readAndDecryptUserInput();
} else if (choice == "3") {
dumpMemory(USER_DATA_START_ADDR, USER_DATA_START_ADDR + USER_DATA_MAX_LEN + 10); // Dump user area + a bit more
} else {
Serial.println("Invalid choice. Please try again.");
}
displayMenu(); // Show menu again after action
}
}
// --- Menu Function ---
void displayMenu() {
Serial.println("\n===== ESP32 EEPROM MENU =====");
Serial.println("1: Enter and Store Encrypted Text (User Input)");
Serial.println("2: Read and Decrypt Text (Password Protected)");
Serial.println("3: Dump EEPROM Memory (User Area)");
Serial.println("==============================");
Serial.print("Enter your choice: ");
}
// --- Core Functions ---
// Programme 2 & 1: Get user input, encrypt, and write to EEPROM
void writeEncryptedUserInput() {
Serial.println("Enter text to store (max " + String(USER_DATA_MAX_LEN) + " chars, end with Enter):");
// Wait for user input
while (!Serial.available()) {
delay(50); // Small delay to prevent busy-waiting
}
userDataBuffer = Serial.readStringUntil('\n');
userDataBuffer.trim();
if (userDataBuffer.length() > USER_DATA_MAX_LEN) {
Serial.println("Warning: Text too long, truncating.");
userDataBuffer = userDataBuffer.substring(0, USER_DATA_MAX_LEN);
}
Serial.println("Encrypting and writing to EEPROM...");
int currentAddr = USER_DATA_START_ADDR;
for (int i = 0; i < userDataBuffer.length(); i++) {
byte encryptedChar = userDataBuffer[i] ^ XOR_KEY; // Programme 1: Apply XOR encryption
myMem.write(currentAddr + i, encryptedChar);
// Optional: Add a small delay if experiencing write issues, though usually not needed for single bytes
// delay(5);
}
// Write null terminator (encrypted)
myMem.write(currentAddr + userDataBuffer.length(), (byte)0x00 ^ XOR_KEY);
// delay(5); // Ensure write completes
Serial.println("Text encrypted and stored successfully!");
}
// Programme 3 & 1: Verify password, read, decrypt, and display
void readAndDecryptUserInput() {
if (!verifyPassword()) {
Serial.println("Access Denied!");
return;
}
Serial.println("Password accepted. Reading and decrypting data...");
String decryptedText = "";
int currentAddr = USER_DATA_START_ADDR;
byte readByte;
byte decryptedChar;
while (true) {
readByte = myMem.read(currentAddr++);
decryptedChar = readByte ^ XOR_KEY; // Programme 1: Apply XOR decryption
if (decryptedChar == 0x00) { // Check for null terminator
break; // End of string
}
decryptedText += (char)decryptedChar;
// Safety break to prevent infinite loops if null terminator is missing
if (currentAddr >= USER_DATA_START_ADDR + USER_DATA_MAX_LEN + 5) {
Serial.println("\nWarning: Read exceeded expected length, possible data corruption or missing terminator.");
break;
}
}
Serial.print("Decrypted Text: ");
Serial.println(decryptedText);
}
// Programme 3: Password verification helper
bool verifyPassword() {
Serial.println("Enter password to read data:");
String enteredPassword = "";
// Wait for user input
while (!Serial.available()) {
delay(50);
}
enteredPassword = Serial.readStringUntil('\n');
enteredPassword.trim();
return (enteredPassword == PASSWORD);
}
// Helper Function to Dump Memory Contents (similar to Project 1)
void dumpMemory(int startAddr, int endAddr) {
Serial.println("\n--- Dumping EEPROM Memory from " + String(startAddr) + " to " + String(endAddr - 1) + " ---");
Serial.println("Address | 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F | ASCII");
Serial.println("---------|-------------------------------------------------|----------------");
char lineBuffer[17]; // Buffer for ASCII representation
lineBuffer[16] = '\0'; // Null terminate
for (int addr = startAddr; addr < endAddr; addr++) {
if (addr % 16 == 0) {
// Print previous line's ASCII buffer before starting a new line (if not the first line)
if (addr != startAddr) {
Serial.print("| ");
Serial.println(lineBuffer);
}
// Print current address
Serial.print("0x");
if (addr < 0x1000) Serial.print("0");
if (addr < 0x100) Serial.print("0");
if (addr < 0x10) Serial.print("0");
Serial.print(addr, HEX);
Serial.print(" | ");
memset(lineBuffer, '.', 16); // Reset ASCII buffer
}
byte b = myMem.read(addr);
if (b < 16) Serial.print('0'); // Pad with zero for single hex digits
Serial.print(b, HEX);
Serial.print(' ');
// Store printable characters in buffer, replace others with '.'
lineBuffer[addr % 16] = (b >= 32 && b <= 126) ? (char)b : '.';
// If this is the last address, print the remaining ASCII buffer
if (addr == endAddr - 1) {
// Pad spaces if the last line isn't full
for(int i = (addr % 16) + 1; i < 16; i++) {
Serial.print(" "); // 3 spaces for "XX "
}
Serial.print("| ");
Serial.println(lineBuffer);
}
}
Serial.println("--------------------------------------------------------------------------");
}