/*
 * Pin Discovery Tool for Toy PCB Brain Transplant
 * 
 * Upload this to the XIAO nRF52840, then connect one breakout pin 
 * at a time to the PROBE_PIN. Open Serial Monitor at 115200 baud.
 * 
 * The tool will tell you:
 *   - Resting voltage (VCC, GND, floating, pulled up/down)
 *   - Whether it responds to button presses
 *   - Whether it looks like an analog resistor ladder
 *   - Suggested function (power, button, output, NC)
 * 
 * Workflow:
 *   1. Desolder original MCU, solder SOP-16 breakout adapter
 *   2. Install batteries in toy
 *   3. Connect XIAO GND to toy GND (battery negative)
 *   4. For each breakout pin, connect it to PROBE_PIN with a jumper
 *   5. Type the pin number in Serial Monitor and press Enter
 *   6. Follow prompts (press buttons when asked, etc.)
 *   7. Tool builds a pin map as you go
 */

#include <Arduino.h>

#define PROBE_PIN       A0    // Connect test jumper here
#define NUM_MCU_PINS    16    // SOP-16

// Storage for discovered pin map
struct PinInfo {
    char label[20];
    float voltage;
    bool discovered;
};

PinInfo pinMap[NUM_MCU_PINS + 1]; // 1-indexed

void setup() {
    Serial.begin(115200);
    while (!Serial) delay(10);
    
    memset(pinMap, 0, sizeof(pinMap));
    
    Serial.println("╔══════════════════════════════════════════╗");
    Serial.println("║   Toy PCB Pin Discovery Tool v1.0        ║");
    Serial.println("║   Connect XIAO GND to toy battery GND    ║");
    Serial.println("║   Connect one SOP pin at a time to A0    ║");
    Serial.println("╚══════════════════════════════════════════╝");
    Serial.println();
    Serial.println("Commands:");
    Serial.println("  1-16  = Probe that SOP pin number");
    Serial.println("  map   = Show current pin map");
    Serial.println("  auto  = Auto-detect VCC and GND pins");
    Serial.println("  btn   = Button detection mode (tests all states)");
    Serial.println("  ladder = Resistor ladder detection");
    Serial.println();
    Serial.print("> ");
}

// Read voltage on probe pin (0-3.3V range)
float readVoltage() {
    analogReadResolution(12);  // nRF52840 supports 12-bit ADC
    delay(10);  // settle
    
    // Average multiple readings
    uint32_t sum = 0;
    for (int i = 0; i < 16; i++) {
        sum += analogRead(PROBE_PIN);
        delayMicroseconds(500);
    }
    float raw = sum / 16.0;
    return (raw / 4095.0) * 3.3;  // Convert to voltage
}

// Check if pin is actively being driven or floating
String classifyVoltage(float v) {
    if (v < 0.1)       return "GND (hard low)";
    if (v < 0.4)       return "Weak pulldown or low output";
    if (v > 3.1)       return "VCC (hard high)";
    if (v > 2.5)       return "Weak pullup (~3V)";
    if (v > 1.4 && v < 1.9) return "Floating (~mid-rail)";
    return "Unknown voltage";
}

// Test if the pin changes state (button detection)
void testButton(int sopPin) {
    Serial.println("\n--- Button Detection ---");
    Serial.println("Watch the voltage while pressing each toy button.");
    Serial.println("Monitoring for 10 seconds...");
    Serial.println();
    
    float baseline = readVoltage();
    Serial.print("Baseline: ");
    Serial.print(baseline, 3);
    Serial.println("V");
    
    float minV = baseline, maxV = baseline;
    unsigned long start = millis();
    int changes = 0;
    float lastV = baseline;
    
    while (millis() - start < 10000) {
        float v = readVoltage();
        
        if (v < minV) minV = v;
        if (v > maxV) maxV = v;
        
        // Detect transitions
        if (abs(v - lastV) > 0.3) {
            changes++;
            Serial.print("  Change detected! ");
            Serial.print(lastV, 2);
            Serial.print("V → ");
            Serial.print(v, 2);
            Serial.print("V at t=");
            Serial.print((millis() - start) / 1000.0, 1);
            Serial.println("s");
        }
        lastV = v;
        delay(20);
    }
    
    Serial.println();
    Serial.print("Range: ");
    Serial.print(minV, 3);
    Serial.print("V to ");
    Serial.print(maxV, 3);
    Serial.println("V");
    Serial.print("Transitions detected: ");
    Serial.println(changes);
    
    if (changes > 0 && maxV - minV > 1.0) {
        Serial.println("→ LIKELY A BUTTON PIN (digital, active low)");
        if (sopPin > 0) {
            snprintf(pinMap[sopPin].label, sizeof(pinMap[sopPin].label), "Button");
            pinMap[sopPin].voltage = baseline;
            pinMap[sopPin].discovered = true;
        }
    } else if (changes > 0 && maxV - minV > 0.2) {
        Serial.println("→ POSSIBLE ANALOG INPUT or RESISTOR LADDER");
    } else {
        Serial.println("→ No button activity detected on this pin");
    }
}

// Detect resistor ladder (multiple buttons on one analog pin)
void testResistorLadder() {
    Serial.println("\n--- Resistor Ladder Detection ---");
    Serial.println("Press each button ONE AT A TIME when prompted.");
    Serial.println("Press Enter after pressing each button.");
    Serial.println("Type 'done' when finished.");
    Serial.println();
    
    float voltages[10];
    String names[10];
    int count = 0;
    
    float baseline = readVoltage();
    Serial.print("Baseline (no button): ");
    Serial.print(baseline, 3);
    Serial.println("V");
    
    while (count < 10) {
        Serial.print("\nPress button #");
        Serial.print(count + 1);
        Serial.println(" and type its name (or 'done'):");
        Serial.print("> ");
        
        while (!Serial.available()) delay(10);
        String input = Serial.readStringUntil('\n');
        input.trim();
        
        if (input.equalsIgnoreCase("done")) break;
        
        float v = readVoltage();
        voltages[count] = v;
        names[count] = input;
        
        Serial.print("  ");
        Serial.print(input);
        Serial.print(": ");
        Serial.print(v, 3);
        Serial.println("V");
        
        count++;
        
        Serial.println("  Release button now.");
        delay(500);
    }
    
    if (count > 1) {
        Serial.println("\n--- Ladder Summary ---");
        Serial.print("Baseline: ");
        Serial.print(baseline, 3);
        Serial.println("V");
        
        for (int i = 0; i < count; i++) {
            Serial.print("  ");
            Serial.print(names[i]);
            Serial.print(": ");
            Serial.print(voltages[i], 3);
            Serial.print("V (ADC ~");
            Serial.print((int)(voltages[i] / 3.3 * 4095));
            Serial.println(")");
        }
        
        // Check if voltages are distinct enough
        bool isLadder = true;
        for (int i = 0; i < count - 1; i++) {
            for (int j = i + 1; j < count; j++) {
                if (abs(voltages[i] - voltages[j]) < 0.15) {
                    isLadder = false;
                }
            }
        }
        
        if (isLadder && count >= 2) {
            Serial.println("\n→ THIS IS A RESISTOR LADDER");
            Serial.println("  Use analogRead() with thresholds to detect buttons.");
            Serial.println("  Suggested thresholds (midpoints between readings):");
            
            // Sort by voltage
            for (int i = 0; i < count - 1; i++) {
                for (int j = i + 1; j < count; j++) {
                    if (voltages[j] < voltages[i]) {
                        float tv = voltages[i]; voltages[i] = voltages[j]; voltages[j] = tv;
                        String ts = names[i]; names[i] = names[j]; names[j] = ts;
                    }
                }
            }
            
            for (int i = 0; i < count; i++) {
                float lo = (i == 0) ? 0 : (voltages[i-1] + voltages[i]) / 2;
                float hi = (i == count-1) ? 3.3 : (voltages[i] + voltages[i+1]) / 2;
                Serial.print("  ");
                Serial.print(names[i]);
                Serial.print(": ");
                Serial.print(lo, 2);
                Serial.print("V - ");
                Serial.print(hi, 2);
                Serial.println("V");
            }
        } else {
            Serial.println("\n→ Doesn't look like a resistor ladder");
            Serial.println("  (Voltages too close together or too few buttons)");
        }
    }
}

// Full probe of one pin
void probePin(int sopPin) {
    Serial.print("\n═══ Probing SOP-16 Pin ");
    Serial.print(sopPin);
    Serial.println(" ═══");
    
    // First read as analog input (high impedance)
    pinMode(PROBE_PIN, INPUT);
    delay(50);
    float v_floating = readVoltage();
    
    Serial.print("Floating voltage: ");
    Serial.print(v_floating, 3);
    Serial.print("V → ");
    Serial.println(classifyVoltage(v_floating));
    
    // Classify
    if (v_floating < 0.1) {
        Serial.println("→ This is a GND pin");
        snprintf(pinMap[sopPin].label, sizeof(pinMap[sopPin].label), "GND");
        pinMap[sopPin].voltage = v_floating;
        pinMap[sopPin].discovered = true;
    }
    else if (v_floating > 2.8) {
        // Could be VCC or a pulled-up button pin
        // Try briefly enabling internal pulldown to see if it drops
        pinMode(PROBE_PIN, INPUT_PULLDOWN);
        delay(50);
        float v_pulldown = readVoltage();
        pinMode(PROBE_PIN, INPUT);
        
        if (v_pulldown > 2.5) {
            Serial.print("With pulldown: ");
            Serial.print(v_pulldown, 3);
            Serial.println("V — Still high → VCC (power) pin");
            snprintf(pinMap[sopPin].label, sizeof(pinMap[sopPin].label), "VCC");
            pinMap[sopPin].voltage = v_floating;
            pinMap[sopPin].discovered = true;
        } else {
            Serial.print("With pulldown: ");
            Serial.print(v_pulldown, 3);
            Serial.println("V — Dropped → Weak pullup (likely button input)");
            Serial.println("→ Try pressing buttons to confirm. Running button test...");
            testButton(sopPin);
        }
    }
    else if (v_floating > 0.4 && v_floating < 2.5) {
        Serial.println("Mid-range voltage. Could be:");
        Serial.println("  - Floating (not connected)");
        Serial.println("  - Part of a resistor ladder");
        Serial.println("  - An analog output");
        Serial.println("→ Try pressing buttons to see if it changes...");
        testButton(sopPin);
    }
    else {
        Serial.println("Low but not GND. Could be pulled-down output.");
        testButton(sopPin);
    }
    
    Serial.println();
}

// Print the current pin map
void showMap() {
    Serial.println("\n╔════════════════════════════════════╗");
    Serial.println("║       Current Pin Map              ║");
    Serial.println("╠════════════════════════════════════╣");
    
    for (int i = 1; i <= NUM_MCU_PINS; i++) {
        Serial.print("║  Pin ");
        if (i < 10) Serial.print(" ");
        Serial.print(i);
        Serial.print(": ");
        
        if (pinMap[i].discovered) {
            Serial.print(pinMap[i].label);
            // Pad to align
            for (int j = strlen(pinMap[i].label); j < 12; j++) Serial.print(" ");
            Serial.print("(");
            Serial.print(pinMap[i].voltage, 2);
            Serial.print("V)");
        } else {
            Serial.print("-- not probed --     ");
        }
        Serial.println("  ║");
    }
    
    Serial.println("╚════════════════════════════════════╝");
    
    // Count discovered
    int found = 0;
    for (int i = 1; i <= NUM_MCU_PINS; i++) {
        if (pinMap[i].discovered) found++;
    }
    Serial.print("Discovered: ");
    Serial.print(found);
    Serial.print("/");
    Serial.println(NUM_MCU_PINS);
}

void loop() {
    if (Serial.available()) {
        String input = Serial.readStringUntil('\n');
        input.trim();
        
        if (input.equalsIgnoreCase("map")) {
            showMap();
        }
        else if (input.equalsIgnoreCase("btn")) {
            Serial.println("Connect the pin you want to test to A0, then:");
            testButton(0);
        }
        else if (input.equalsIgnoreCase("ladder")) {
            testResistorLadder();
        }
        else if (input.equalsIgnoreCase("auto")) {
            Serial.println("\n--- Auto-detect mode ---");
            Serial.println("Connect each pin to A0 one at a time.");
            Serial.println("Press Enter after connecting each pin.");
            for (int pin = 1; pin <= NUM_MCU_PINS; pin++) {
                Serial.print("\nConnect SOP pin ");
                Serial.print(pin);
                Serial.println(" to A0, then press Enter");
                Serial.print("> ");
                while (!Serial.available()) delay(10);
                Serial.readStringUntil('\n');
                probePin(pin);
            }
            showMap();
        }
        else {
            int pin = input.toInt();
            if (pin >= 1 && pin <= NUM_MCU_PINS) {
                probePin(pin);
            } else {
                Serial.println("Unknown command. Use 1-16, map, auto, btn, or ladder");
            }
        }
        
        Serial.print("\n> ");
    }
}
