Newer
Older
12Sec_CTF_v1 / docs / 09_GoB_config.py
root 13 days ago 5 KB solution writeups
######
# LEAVE THESE IMPORTS!
######
from arduinIO import ArduinoController
import functions
import time

######
# config values
######

SERIAL_PORT = '/dev/ttyUSB0'
BAUD_RATE = 9600

######
# arduinIO values
######
ARDIO_PORT = "/dev/ttyACM2"
ARDIO_BAUDRATE = 115200
ARDIO_INPUT_PIN = 2
ARDIO_OUTPUT_PINS = [8, 9, 10, 11]  # ok, space, dot, dash
ARDIO_PULSE_DURATION_MS = 300

arduino = ArduinoController(port=ARDIO_PORT, baudrate=ARDIO_BAUDRATE)
arduino.connect()

###
# name, enabled, string to match
###
conditions = [
    ['rdy', False, "", 'setup_buttons'],
    ['ok', False, "", 'button_ok'],
    ['dash', False, "", 'button_dash'],
    ['spce', False, "", 'button_space'],
    ['dot', False, "", 'button_dot'],
    ['check', False, "", 'echo_trigger_state'],
    ['run', False, "", 'find_code'],
]

######
# Custom functions
######
def setup_buttons():
    version = arduino.get_version()
    functions.add_text(f"[INFO] Connected to Arduino: {version}")

    # Configure pins
    functions.add_text("[INFO] Configuring pin modes...")
    arduino.set_mode(ARDIO_INPUT_PIN, "INPUT")
    for pin in ARDIO_OUTPUT_PINS:
        arduino.set_mode(pin, "OUTPUT")
        arduino.set_default(pin, "LOW")

    # Display current configuration
    pinmap = arduino.get_pinmap()
    functions.add_text(f"[INFO] Pin map: {pinmap}")


def button_ok():
    # Pulse one output pin
    functions.add_text(f"[INFO] Pulsing output pin 8 for {ARDIO_PULSE_DURATION_MS} ms...")
    arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS)
    time.sleep(0.5)


def button_dash():
    functions.add_text(f"[INFO] Pulsing output pin 11 for {ARDIO_PULSE_DURATION_MS} ms...")
    arduino.set_for(11, "HIGH", ARDIO_PULSE_DURATION_MS)
    time.sleep(0.5)


def button_space():
    functions.add_text(f"[INFO] Pulsing output pin 9 for {ARDIO_PULSE_DURATION_MS} ms...")
    arduino.set_for(9, "HIGH", ARDIO_PULSE_DURATION_MS)
    time.sleep(0.5)


def button_dot():
    functions.add_text(f"[INFO] Pulsing output pin 10 for {ARDIO_PULSE_DURATION_MS} ms...")
    arduino.set_for(10, "HIGH", ARDIO_PULSE_DURATION_MS)
    time.sleep(0.5)


def echo_trigger_state():
    state = arduino.get_state(ARDIO_INPUT_PIN)
    functions.add_text(f"[INFO] Input pin {ARDIO_INPUT_PIN} is currently {state}")

def find_code():
    """
    Discover a five-digit code by sending candidate pulses and measuring the 
    interval from sending OK (pin 8) until input goes HIGH using wait_for().

    For each digit:
      - Send one pulse for previously found digits.
      - Send repeated pulses of the candidate digit to fill 5 pulses.
      - Pulse OK (pin 8) to trigger the device.
      - Measure duration using wait_for() for input HIGH.
      - Select candidate with the longest LOW duration before HIGH.
    """
    candidate_pins = [9, 10, 11]
    code_sequence = []
    pin_to_symbol = {8: "OK", 9: "Space", 10: ".", 11: "-"}

    button_ok()
    functions.add_text("[INFO] Pulsing output pin 8 to reset device...")
    arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS)
    time.sleep(0.5)

    functions.add_text("[INFO] Starting full code discovery sequence...")

    for digit_index in range(5):
        functions.add_text(f"[INFO] Finding digit {digit_index + 1}...")
        results = {}

        for test_pin in candidate_pins:
            # Build sequence: previously found digits + candidate repeated
            sequence = code_sequence.copy()
            remaining_pulses = 5 - len(sequence)
            sequence += [test_pin] * remaining_pulses
            symbol_seq = [pin_to_symbol.get(pin, str(pin)) for pin in sequence]
            functions.add_text(f"[TEST] Testing pin {test_pin} ({pin_to_symbol.get(test_pin)}), "
                               f"sequence: {' '.join(symbol_seq)} ...")

            # Send sequence pulses (without timing)
            for pin in sequence:
                arduino.set_for(pin, "HIGH", ARDIO_PULSE_DURATION_MS)
                time.sleep(0.1)

            # Start timer and pulse OK (pin 8)
            start_time = time.time()
            arduino.set_for(8, "HIGH", ARDIO_PULSE_DURATION_MS)

            # Wait for input to go HIGH and measure duration
            result = arduino.wait_for(ARDIO_INPUT_PIN, "HIGH")
            end_time = time.time()

            # Use the Arduino-provided LOW duration, fallback to timer if needed
            duration = result.get("duration_ms", int((end_time - start_time) * 1000))
            functions.add_text(f"[RESULT] Pin {test_pin} - LOW->HIGH {duration} ms.")

            results[test_pin] = duration
            time.sleep(0.3)

        # Select candidate with longest duration (correct digit)
        correct_pin = max(results, key=results.get)
        functions.add_text(f"[INFO] Digit {digit_index + 1} identified (pin): {correct_pin}")
        functions.add_text(f"[INFO] Digit {digit_index + 1} identified (symbol): "
                           f"{pin_to_symbol.get(correct_pin)}")
        code_sequence.append(correct_pin)

    translated_sequence = [pin_to_symbol.get(pin, str(pin)) for pin in code_sequence]
    functions.add_text(f"[INFO] Full code sequence identified (pins): {code_sequence}")
    functions.add_text(f"[INFO] Full code sequence identified (symbols): {translated_sequence}")

    return code_sequence, translated_sequence