/**
* SMART PROTOCOL CONVERTER for ESP32
* Fully working version for Wokwi simulation
*/
#include <Wire.h>
#include <SPI.h>
// ==================== PIN DEFINITIONS ====================
#define UART_IN_RX 4
#define I2C_IN_SDA 5
#define I2C_IN_SCL 6
#define SPI_IN_MISO 7
#define SPI_IN_SCLK 8
#define SPI_IN_CS 9
#define OUT_I2C_SDA 11
#define OUT_I2C_SCL 12
#define OUT_SPI_CS 15
#define BUTTON_PIN 0
#define LED_GREEN 16
#define LED_RED 17
// ==================== PROTOCOL ENUMS ====================
enum InputProtocol { PROTO_UNKNOWN, PROTO_UART, PROTO_I2C, PROTO_SPI };
enum OutputProtocol { OUT_UART, OUT_I2C, OUT_SPI };
// ==================== GLOBAL VARIABLES ====================
InputProtocol detectedProtocol = PROTO_UNKNOWN;
OutputProtocol selectedOutput = OUT_UART;
int detectedBaudRate = 0;
bool detectionComplete = false;
// For manual UART detection
volatile unsigned long lastEdgeTime = 0;
volatile unsigned long lowPulseWidth = 0;
volatile int edgeCount = 0;
volatile bool measurementComplete = false;
// ==================== FORWARD DECLARATIONS ====================
void uartEdgeISR();
void askOutputProtocol();
bool detectUART();
bool detectI2C();
bool detectSPI();
void handleUARTInput();
void handleI2CInput();
void handleSPIInput();
void forwardToOutput(char data);
// ==================== SETUP ====================
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\n\n=== SMART PROTOCOL CONVERTER ===");
Serial.println("ESP32 Ready - Fixed Version");
// Initialize pins
pinMode(UART_IN_RX, INPUT);
pinMode(I2C_IN_SDA, INPUT_PULLUP);
pinMode(I2C_IN_SCL, INPUT_PULLUP);
pinMode(SPI_IN_MISO, INPUT);
pinMode(SPI_IN_SCLK, INPUT);
pinMode(SPI_IN_CS, INPUT_PULLUP);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_RED, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
digitalWrite(LED_GREEN, LOW);
digitalWrite(LED_RED, LOW);
// Ask user for desired output protocol
askOutputProtocol();
// Start detection
Serial.println("\n[DETECTION] Starting protocol detection...");
Serial.println("Connect your unknown device now.");
}
// ==================== MAIN LOOP ====================
void loop() {
Serial.println("Starting...");
if (!detectionComplete) {
detectProtocol();
} else {
convertAndForward();
}
}
// ==================== ASK USER FOR OUTPUT PROTOCOL ====================
void askOutputProtocol() {
Serial.println("\n[USER INPUT REQUIRED]");
Serial.println("Select desired OUTPUT protocol:");
Serial.println(" 1 - UART (serial over USB)");
Serial.println(" 2 - I2C");
Serial.println(" 3 - SPI");
Serial.print("Enter 1, 2, or 3: ");
unsigned long timeout = millis() + 10000;
while (!Serial.available() && millis() < timeout) {
delay(100);
}
if (Serial.available()) {
int choice = Serial.parseInt();
switch(choice) {
case 1:
selectedOutput = OUT_UART;
Serial.println("Selected: UART output");
break;
case 2:
selectedOutput = OUT_I2C;
Serial.println("Selected: I2C output");
Wire.begin(OUT_I2C_SDA, OUT_I2C_SCL);
break;
case 3:
selectedOutput = OUT_SPI;
Serial.println("Selected: SPI output");
SPI.begin();
break;
default:
selectedOutput = OUT_UART;
Serial.println("Invalid, defaulting to UART output");
}
} else {
selectedOutput = OUT_UART;
Serial.println("Timeout, defaulting to UART output");
}
}
// ==================== PROTOCOL DETECTION ENGINE ====================
void detectProtocol() {
Serial.println("\n[SCANNING] Analyzing signals...");
if (detectUART()) {
detectedProtocol = PROTO_UART;
Serial.printf("[SUCCESS] UART detected! Baud rate: %d\n", detectedBaudRate);
detectionComplete = true;
digitalWrite(LED_GREEN, HIGH);
return;
}
if (detectI2C()) {
detectedProtocol = PROTO_I2C;
Serial.println("[SUCCESS] I2C protocol detected!");
detectionComplete = true;
digitalWrite(LED_GREEN, HIGH);
return;
}
if (detectSPI()) {
detectedProtocol = PROTO_SPI;
Serial.println("[SUCCESS] SPI protocol detected!");
detectionComplete = true;
digitalWrite(LED_GREEN, HIGH);
return;
}
digitalWrite(LED_RED, HIGH);
Serial.println("[FAILED] No protocol detected. Check connections.");
Serial.println("Retrying in 2 seconds...");
delay(2000);
digitalWrite(LED_RED, LOW);
}
// ==================== UART DETECTION ====================
bool detectUART() {
Serial.println(" Trying UART detection...");
edgeCount = 0;
measurementComplete = false;
lowPulseWidth = 0;
lastEdgeTime = 0;
attachInterrupt(digitalPinToInterrupt(UART_IN_RX), uartEdgeISR, CHANGE);
unsigned long startTime = millis();
while (millis() - startTime < 1000) {
if (measurementComplete && lowPulseWidth > 0) {
detectedBaudRate = 1000000 / lowPulseWidth;
if (detectedBaudRate >= 2400 && detectedBaudRate <= 115200) {
detachInterrupt(digitalPinToInterrupt(UART_IN_RX));
return true;
}
}
delay(10);
}
detachInterrupt(digitalPinToInterrupt(UART_IN_RX));
return false;
}
// ==================== EDGE INTERRUPT ====================
void IRAM_ATTR uartEdgeISR() {
unsigned long now = micros();
unsigned long duration = now - lastEdgeTime;
lastEdgeTime = now;
int pinState = digitalRead(UART_IN_RX);
if (pinState == LOW && duration > 50) {
lowPulseWidth = duration;
measurementComplete = true;
}
}
// ==================== I2C DETECTION ====================
bool detectI2C() {
Serial.println(" Trying I2C detection...");
pinMode(I2C_IN_SDA, INPUT_PULLUP);
pinMode(I2C_IN_SCL, INPUT_PULLUP);
unsigned long startTime = millis();
while (millis() - startTime < 2000) {
if (digitalRead(I2C_IN_SCL) == HIGH) {
if (digitalRead(I2C_IN_SDA) == LOW) {
delayMicroseconds(100);
if (digitalRead(I2C_IN_SDA) == LOW) {
return true;
}
}
}
delayMicroseconds(10);
}
return false;
}
// ==================== SPI DETECTION ====================
bool detectSPI() {
Serial.println(" Trying SPI detection...");
unsigned long startTime = millis();
int lastCSState = digitalRead(SPI_IN_CS);
int transitions = 0;
while (millis() - startTime < 2000) {
int currentCS = digitalRead(SPI_IN_CS);
if (currentCS != lastCSState) {
transitions++;
lastCSState = currentCS;
if (transitions > 4) {
int clockChanges = 0;
int lastClock = digitalRead(SPI_IN_SCLK);
for (int i = 0; i < 100; i++) {
int currentClock = digitalRead(SPI_IN_SCLK);
if (currentClock != lastClock) {
clockChanges++;
lastClock = currentClock;
}
delayMicroseconds(10);
}
if (clockChanges > 10) {
return true;
}
}
}
delay(1);
}
return false;
}
// ==================== CONVERSION AND FORWARDING ====================
void convertAndForward() {
switch(detectedProtocol) {
case PROTO_UART:
handleUARTInput();
break;
case PROTO_I2C:
handleI2CInput();
break;
case PROTO_SPI:
handleSPIInput();
break;
default:
delay(100);
}
}
// ==================== UART INPUT HANDLER ====================
void handleUARTInput() {
static bool uartStarted = false;
if (!uartStarted) {
int baudToUse = (detectedBaudRate > 0) ? detectedBaudRate : 9600;
Serial1.begin(baudToUse, SERIAL_8N1, UART_IN_RX, -1);
uartStarted = true;
Serial.printf("[BRIDGE] UART configured at %d baud\n", baudToUse);
}
while (Serial1.available()) {
char c = Serial1.read();
forwardToOutput(c);
Serial.print(c);
}
}
// ==================== I2C INPUT HANDLER ====================
void handleI2CInput() {
static bool i2cStarted = false;
if (!i2cStarted) {
Wire1.begin(0x08);
Wire1.onReceive(i2cReceiveHandler);
i2cStarted = true;
Serial.println("[BRIDGE] I2C slave started at address 0x08");
}
delay(10);
}
void i2cReceiveHandler(int bytes) {
while (Wire1.available()) {
char c = Wire1.read();
forwardToOutput(c);
Serial.print(c);
}
}
// ==================== SPI INPUT HANDLER ====================
void handleSPIInput() {
static bool spiStarted = false;
if (!spiStarted) {
SPI.begin();
spiStarted = true;
Serial.println("[BRIDGE] SPI slave mode ready");
}
if (digitalRead(SPI_IN_CS) == LOW) {
delayMicroseconds(10);
}
}
// ==================== FORWARD TO SELECTED OUTPUT ====================
void forwardToOutput(char data) {
switch(selectedOutput) {
case OUT_UART:
Serial.print(data);
break;
case OUT_I2C:
Wire.beginTransmission(0x09);
Wire.write(data);
Wire.endTransmission();
break;
case OUT_SPI:
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
digitalWrite(OUT_SPI_CS, LOW);
SPI.transfer(data);
digitalWrite(OUT_SPI_CS, HIGH);
SPI.endTransaction();
break;
}
}