← back to davejharmon__murderhouse

Function bodies 456 total

All specs Real LLM only Function bodies
toggleLightMode function · javascript · L177-L183 (7 LOC)
client/src/pages/StringSheets.jsx
  function toggleLightMode() {
    setLightMode(prev => {
      const next = !prev
      try { localStorage.setItem('ss_light_mode', next ? '1' : '0') } catch {}
      return next
    })
  }
flash function · javascript · L185-L188 (4 LOC)
client/src/pages/StringSheets.jsx
  function flash(msg, type = 'ok') {
    setFeedback({ msg, type })
    setTimeout(() => setFeedback(null), 2500)
  }
handleChange function · javascript · L190-L202 (13 LOC)
client/src/pages/StringSheets.jsx
  function handleChange(entry, value) {
    const id = `${entry.cat}.${entry.key}`
    setOverrides(prev => {
      const next = { ...prev }
      if (value === entry.default) {
        delete next[id]
      } else {
        next[id] = value
      }
      saveOverrides(next)
      return next
    })
  }
handleReset function · javascript · L204-L213 (10 LOC)
client/src/pages/StringSheets.jsx
  function handleReset() {
    if (!confirm('Reset all values and tag edits to defaults? This clears localStorage.')) return
    localStorage.removeItem(LS_KEY)
    localStorage.removeItem(LS_TAGS_KEY)
    localStorage.removeItem(LS_TOKEN_KEY)
    setOverrides({})
    setTagOverrides({})
    setTokenExamples({})
    flash('Reset to defaults')
  }
handleExportCsv function · javascript · L215-L219 (5 LOC)
client/src/pages/StringSheets.jsx
  function handleExportCsv() {
    const csv = buildCsv(STRING_CATALOG, overrides)
    downloadFile(csv, 'game-strings.csv', 'text/csv;charset=utf-8;')
    flash('CSV downloaded')
  }
handleDownloadJs function · javascript · L221-L225 (5 LOC)
client/src/pages/StringSheets.jsx
  function handleDownloadJs() {
    const js = buildJsFile(STRING_CATALOG, overrides, tagOverrides)
    downloadFile(js, 'gameStrings.js', 'text/javascript')
    flash('gameStrings.js downloaded — replace the file in client/src/strings/')
  }
handleCopyJs function · javascript · L227-L230 (4 LOC)
client/src/pages/StringSheets.jsx
  function handleCopyJs() {
    const js = buildJsFile(STRING_CATALOG, overrides, tagOverrides)
    navigator.clipboard.writeText(js).then(() => flash('Copied to clipboard'))
  }
Repobility analyzer · published findings · https://repobility.com
handleApplyToSource function · javascript · L232-L253 (22 LOC)
client/src/pages/StringSheets.jsx
  async function handleApplyToSource() {
    const js = buildJsFile(STRING_CATALOG, overrides, tagOverrides)
    try {
      const res = await fetch('/dev/write-file', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ file: '../shared/strings/gameStrings.js', content: js }),
      })
      const data = await res.json()
      if (data.ok) {
        localStorage.removeItem(LS_KEY)
        localStorage.removeItem(LS_TAGS_KEY)
        setOverrides({})
        setTagOverrides({})
        flash('Applied — gameStrings.js updated')
      } else {
        flash(data.error || 'Write failed', 'err')
      }
    } catch {
      flash('Could not reach dev server', 'err')
    }
  }
handleImportClick function · javascript · L255-L257 (3 LOC)
client/src/pages/StringSheets.jsx
  function handleImportClick() {
    importRef.current?.click()
  }
handleImportFile function · javascript · L259-L292 (34 LOC)
client/src/pages/StringSheets.jsx
  function handleImportFile(e) {
    const file = e.target.files?.[0]
    if (!file) return
    const reader = new FileReader()
    reader.onload = (ev) => {
      try {
        const rows = parseCsv(ev.target.result)
        const next = { ...overrides }
        let count = 0
        for (const row of rows) {
          const cat = row.category?.trim()
          const key = row.key?.trim()
          const value = row.value?.trim()
          if (!cat || !key || value === undefined) continue
          const entry = STRING_CATALOG.find(e => e.cat === cat && e.key === key)
          if (!entry) continue
          const id = `${cat}.${key}`
          if (value === entry.default) {
            delete next[id]
          } else {
            next[id] = value
            count++
          }
        }
        saveOverrides(next)
        setOverrides(next)
        flash(`Imported — ${count} override${count !== 1 ? 's' : ''} applied`)
      } catch {
        flash('Import failed — check CSV format
getAutoTagId function · javascript · L297-L301 (5 LOC)
client/src/pages/StringSheets.jsx
  function getAutoTagId(entry) {
    const autoGroup = TAG_GROUPS.find(g => g.id === entry.cat)
    const prefix = entry.key.split('.')[0]
    return autoGroup?.tags.find(t => t.id === prefix)?.id ?? null
  }
getEntryTags function · javascript · L303-L307 (5 LOC)
client/src/pages/StringSheets.jsx
  function getEntryTags(entry) {
    const explicit = getEffectiveTags(entry, tagOverrides)
    const autoTagId = getAutoTagId(entry)
    return autoTagId ? [autoTagId, ...explicit] : explicit
  }
handleAddTag function · javascript · L309-L318 (10 LOC)
client/src/pages/StringSheets.jsx
  function handleAddTag(entry, tag) {
    const id = `${entry.cat}.${entry.key}`
    setTagOverrides(prev => {
      const current = prev[id] ?? entry.tags ?? []
      if (current.includes(tag)) return prev
      const next = { ...prev, [id]: [...current, tag] }
      saveTagOverrides(next)
      return next
    })
  }
handleRemoveTag function · javascript · L320-L336 (17 LOC)
client/src/pages/StringSheets.jsx
  function handleRemoveTag(entry, tag) {
    const id = `${entry.cat}.${entry.key}`
    setTagOverrides(prev => {
      const current = prev[id] ?? entry.tags ?? []
      const updated = current.filter(t => t !== tag)
      const next = { ...prev }
      // If the updated list equals the catalog default, remove the override
      const defaultTags = entry.tags ?? []
      if (updated.length === defaultTags.length && updated.every((t, i) => t === defaultTags[i])) {
        delete next[id]
      } else {
        next[id] = updated
      }
      saveTagOverrides(next)
      return next
    })
  }
handleTokenExample function · javascript · L338-L356 (19 LOC)
client/src/pages/StringSheets.jsx
  function handleTokenExample(entry, token, value) {
    const id = `${entry.cat}.${entry.key}`
    setTokenExamples(prev => {
      const entryTokens = { ...(prev[id] || {}) }
      if (value === '') {
        delete entryTokens[token]
      } else {
        entryTokens[token] = value
      }
      const next = { ...prev }
      if (Object.keys(entryTokens).length === 0) {
        delete next[id]
      } else {
        next[id] = entryTokens
      }
      saveTokenExamples(next)
      return next
    })
  }
Open data scored by Repobility · https://repobility.com
getStr function · javascript · L12-L20 (9 LOC)
client/src/strings/index.js
export function getStr(cat, key) {
  try {
    const raw = localStorage.getItem(LS_KEY)
    const overrides = raw ? JSON.parse(raw) : {}
    return overrides[`${cat}.${key}`] ?? defaults[`${cat}.${key}`] ?? key
  } catch {
    return defaults[`${cat}.${key}`] ?? key
  }
}
devWriteFilePlugin function · javascript · L8-L45 (38 LOC)
client/vite.config.js
function devWriteFilePlugin() {
  return {
    name: 'dev-write-file',
    configureServer(server) {
      server.middlewares.use('/dev/write-file', (req, res) => {
        if (req.method !== 'POST') {
          res.statusCode = 405;
          res.end('Method Not Allowed');
          return;
        }
        let body = '';
        req.on('data', chunk => { body += chunk; });
        req.on('end', () => {
          try {
            const { file, content } = JSON.parse(body);
            // Resolve from client/ dir; allow writes to src/ or ../shared/strings/
            const target = path.resolve(__dirname, file);
            const allowed = [
              path.resolve(__dirname, 'src'),
              path.resolve(__dirname, '../shared/strings'),
            ];
            if (!allowed.some(root => target.startsWith(root))) {
              res.statusCode = 403;
              res.end(JSON.stringify({ error: 'Path not in allowed write roots' }));
              return;
            }
   
displayInit function · cpp · L40-L50 (11 LOC)
esp32-terminal/src/display.cpp
void displayInit() {
    // Initialize SPI with ESP32-S3 pins
    SPI.begin(PIN_OLED_CLK, -1, PIN_OLED_MOSI, PIN_OLED_CS);

    // Initialize U8g2
    u8g2.begin();
    u8g2.setContrast(255);  // Max contrast for amber OLED
    u8g2.clearBuffer();
    u8g2.sendBuffer();
}
displayClear function · cpp · L51-L55 (5 LOC)
esp32-terminal/src/display.cpp
void displayClear() {
    u8g2.clearBuffer();
    u8g2.sendBuffer();
}
getStyleColor function · cpp · L59-L71 (13 LOC)
esp32-terminal/src/display.cpp
uint8_t getStyleColor(DisplayStyle style) {
    switch (style) {
        case DisplayStyle::LOCKED:
        case DisplayStyle::CRITICAL:
            return 255;  // Bright
        case DisplayStyle::ABSTAINED:
            return 128;  // Dim
        case DisplayStyle::WAITING:
            return 200;  // Slightly dim
        default:
            return 255;  // Normal = bright
    }
}
drawIconXBM function · cpp · L74-L78 (5 LOC)
esp32-terminal/src/display.cpp
static void drawIconXBM(const uint8_t* icon, int x, int y) {
    if (icon == nullptr) return;
    u8g2.setDrawColor(1);
    u8g2.drawXBMP(x, y, ICON_SIZE, ICON_SIZE, icon);
}
drawSelectionBar function · cpp · L81-L85 (5 LOC)
esp32-terminal/src/display.cpp
static void drawSelectionBar(int activeIndex) {
    if (activeIndex < 0 || activeIndex > 2) return;
    u8g2.setDrawColor(1);
    u8g2.drawBox(BAR_X, SLOT_Y[activeIndex], BAR_W, ICON_SLOT_H);
}
_renderOperator function · cpp · L90-L179 (90 LOC)
esp32-terminal/src/display.cpp
static void _renderOperator(const DisplayState& state) {
    static const int OP_Y[]    = {14, 34, 54};   // baselines for 3 evenly-spaced lines
    static const int MAX_CHARS = 37;              // max chars per line at 6px each

    // Build combined text
    String sentence = state.line1.left;
    String preview  = state.line2.text;
    String combined;
    if (sentence.length() > 0 && preview.length() > 0)
        combined = sentence + " " + preview;
    else if (sentence.length() > 0)
        combined = sentence;
    else
        combined = preview;

    // Word-wrap into 3 rows
    String rows[3] = {"", "", ""};
    int rowIdx = 0;
    int pos = 0;
    while (pos < (int)combined.length() && rowIdx < 3) {
        int sp = combined.indexOf(' ', pos);
        String word = (sp == -1) ? combined.substring(pos) : combined.substring(pos, sp);
        pos = (sp == -1) ? combined.length() : sp + 1;
        if (word.length() == 0) continue;
        String candidate = rows[rowIdx].length() 
Source: Repobility analyzer · https://repobility.com
_renderBuffer function · cpp · L182-L255 (74 LOC)
esp32-terminal/src/display.cpp
static void _renderBuffer(const DisplayState& state) {
    u8g2.clearBuffer();

    // Operator sentence mode uses completely different layout
    if (state.line2.style == DisplayStyle::OPERATOR) {
        _renderOperator(state);
        u8g2.sendBuffer();
        return;
    }

    // === ICON COLUMN ===
    for (int i = 0; i < 3; i++) {
        const uint8_t* bitmap = getIconBitmap(state.icons[i].id);
        drawIconXBM(bitmap, ICON_COL_X, ICON_Y[i]);
    }
    // Draw selection bar next to the active icon slot (only if 2+ icons visible)
    int visibleIcons = 0;
    for (int i = 0; i < 3; i++) {
        if (state.icons[i].id != "empty") visibleIcons++;
    }
    if (visibleIcons >= 2) {
        drawSelectionBar(state.idleScrollIndex);
    }

    // === LINE 1: Context (small, left and right aligned) ===
    u8g2.setFont(FONT_SMALL);
    u8g2.setDrawColor(1);

    u8g2.drawStr(MARGIN_X, LINE1_Y, state.line1.left.c_str());

    if (state.line1.right.length() > 0) {
        int rightW
displayRender function · cpp · L256-L283 (28 LOC)
esp32-terminal/src/display.cpp
void displayRender(const DisplayState& state) {
    // Operator mode renders once (inverted box provides the visual, no blink animation)
    if (state.line2.style == DisplayStyle::OPERATOR) {
        _renderBuffer(state);
        return;
    }

    // Critical content only flashes on first display — track seen text so
    // scrolling away and back does not re-trigger the blink animation.
    static String lastCriticalText = "";
    bool isCritical = state.line2.style == DisplayStyle::CRITICAL;
    bool isNewCritical = isCritical && state.line2.text != lastCriticalText;
    if (isCritical) lastCriticalText = state.line2.text;

    int blinkCycles = isNewCritical ? 3 : 1;

    for (int blink = 0; blink < blinkCycles; blink++) {
        if (blink > 0) {
            // Blank frame between blinks
            delay(150);
            u8g2.clearBuffer();
            u8g2.sendBuffer();
            delay(150);
        }
        _renderBuffer(state);
    }
}
displayMessage function · cpp · L284-L293 (10 LOC)
esp32-terminal/src/display.cpp
void displayMessage(const char* line1, const char* line2, const char* line3) {
    DisplayState state;
    state.line1.left = line1;
    state.line1.right = "";
    state.line2.text = line2;
    state.line2.style = DisplayStyle::NORMAL;
    state.line3.text = line3;
    displayRender(state);
}
displayPlayerSelect function · cpp · L294-L328 (35 LOC)
esp32-terminal/src/display.cpp
void displayPlayerSelect(uint8_t selectedPlayer) {
    u8g2.clearBuffer();

    // === LINE 1: Title ===
    u8g2.setFont(FONT_SMALL);
    u8g2.setDrawColor(1);
    char selectTitle[32];
    snprintf(selectTitle, sizeof(selectTitle), "%s > SELECT TERMINAL", FIRMWARE_VERSION);
    u8g2.drawStr(MARGIN_X, LINE1_Y, selectTitle);

    // === LINE 2: Selected player/operator (large, centered) ===
    u8g2.setFont(FONT_LARGE);
    char playerText[16];
    if (selectedPlayer == 0) {
        snprintf(playerText, sizeof(playerText), "OPERATOR");
    } else {
        snprintf(playerText, sizeof(playerText), "PLAYER %d", selectedPlayer);
    }
    int textWidth = u8g2.getStrWidth(playerText);
    int textX = (DISPLAY_WIDTH - textWidth) / 2;

    // Draw selection box
    u8g2.drawFrame(textX - 6, LINE2_Y - 18, textWidth + 12, 24);
    u8g2.drawStr(textX, LINE2_Y, playerText);

    // === LINE 3: Instructions ===
    u8g2.setFont(FONT_SMALL);
    const char* instructions = "DIAL select - YES confi
displayConnectionStatus function · cpp · L329-L390 (62 LOC)
esp32-terminal/src/display.cpp
void displayConnectionStatus(ConnectionState connState, const char* detail) {
    const char* line1 = "";
    const char* line2 = "";
    const char* line3 = "";

    switch (connState) {
        case ConnectionState::BOOT:
            line1 = "MURDERHOUSE";
            line2 = "BOOTING";
            line3 = "v" FIRMWARE_VERSION;
            break;

        case ConnectionState::PLAYER_SELECT:
            // Handled separately by displayPlayerSelect()
            return;

        case ConnectionState::WIFI_CONNECTING:
            line1 = "CONNECTING...";
            line2 = "WIFI";
            line3 = detail ? detail : "Searching for network...";
            break;

        case ConnectionState::DISCOVERING:
            line1 = "CONNECTING...";
            line2 = "SCANNING";
            line3 = detail ? detail : "Looking for server...";
            break;

        case ConnectionState::WS_CONNECTING:
            line1 = "CONNECTING...";
            line2 = "SERVER";
            line3
heartrateInit function · cpp · L39-L52 (14 LOC)
esp32-terminal/src/heartrate.cpp
void heartrateInit() {
    // AD8232 shutdown control — start in shutdown (HIGH = off)
    pinMode(PIN_AD8232_SDN, OUTPUT);
    digitalWrite(PIN_AD8232_SDN, HIGH);
    hrPowered = false;
    hrEnabled = false;

    // Red heartbeat LED
    pinMode(PIN_LED_HEARTBEAT, OUTPUT);
    digitalWrite(PIN_LED_HEARTBEAT, LOW);

    Serial.println("[HR] AD8232 initialized, SDN HIGH (shutdown)");
}
heartratePowerOn function · cpp · L53-L60 (8 LOC)
esp32-terminal/src/heartrate.cpp
void heartratePowerOn() {
    if (!hrPowered) {
        digitalWrite(PIN_AD8232_SDN, LOW);
        hrPowered = true;
        Serial.println("[HR] AD8232 powered on (warm-up)");
    }
}
heartratePowerOff function · cpp · L61-L71 (11 LOC)
esp32-terminal/src/heartrate.cpp
void heartratePowerOff() {
    if (hrPowered) {
        digitalWrite(PIN_AD8232_SDN, HIGH);
        digitalWrite(PIN_LED_HEARTBEAT, LOW);
        beatLedOn = false;
        hrPowered = false;
        hrEnabled = false;
        Serial.println("[HR] AD8232 powered off");
    }
}
Same scanner, your repo: https://repobility.com — Repobility
heartrateEnable function · cpp · L72-L79 (8 LOC)
esp32-terminal/src/heartrate.cpp
void heartrateEnable() {
    if (!hrEnabled) {
        heartratePowerOn(); // Ensure powered on
        hrEnabled = true;
        Serial.println("[HR] Reporting enabled");
    }
}
heartrateDisable function · cpp · L80-L88 (9 LOC)
esp32-terminal/src/heartrate.cpp
void heartrateDisable() {
    if (hrEnabled) {
        digitalWrite(PIN_LED_HEARTBEAT, LOW);
        beatLedOn = false;
        hrEnabled = false;
        Serial.println("[HR] Reporting disabled");
    }
}
heartrateUpdate function · cpp · L89-L154 (66 LOC)
esp32-terminal/src/heartrate.cpp
void heartrateUpdate() {
    if (!hrPowered) return;

    unsigned long now = millis();

    // Turn off beat LED after flash duration
    if (beatLedOn && (now - beatLedOnTime >= AD8232_BEAT_FLASH_MS)) {
        digitalWrite(PIN_LED_HEARTBEAT, LOW);
        beatLedOn = false;
    }

    // Sample at ~250 Hz
    if (now - lastSampleTime < AD8232_SAMPLE_MS) return;
    lastSampleTime = now;

    // Read analog signal
    int sample = analogRead(PIN_AD8232_OUT);

    // Update rolling min/max window
    if (now - windowStart > WINDOW_MS) {
        // Decay toward current sample to avoid stale extremes
        rollingMin = sample;
        rollingMax = sample;
        windowStart = now;
    } else {
        if (sample < rollingMin) rollingMin = sample;
        if (sample > rollingMax) rollingMax = sample;
    }

    int range = rollingMax - rollingMin;

    if (range < MIN_RANGE) return;  // Signal too weak or just noise, skip detection

    // Dynamic threshold
    int threshold = rollin
heartrateGetBPM function · cpp · L155-L170 (16 LOC)
esp32-terminal/src/heartrate.cpp
uint8_t heartrateGetBPM() {
    if (beatIntervalCount == 0) return 0;

    unsigned long sum = 0;
    int count = min(beatIntervalCount, BPM_BUFFER_SIZE);
    for (int i = 0; i < count; i++) {
        sum += beatIntervals[i];
    }
    unsigned long avgInterval = sum / count;
    if (avgInterval == 0) return 0;

    unsigned long bpm = 60000 / avgInterval;
    if (bpm > 220) bpm = 220;
    return (uint8_t)bpm;
}
heartrateIsActive function · cpp · L171-L174 (4 LOC)
esp32-terminal/src/heartrate.cpp
bool heartrateIsActive() {
    return (lastBeatTime > 0) && (millis() - lastBeatTime < ACTIVE_TIMEOUT_MS);
}
getIconBitmap function · c · L499-L523 (25 LOC)
esp32-terminal/src/icons.h
inline const uint8_t* getIconBitmap(const String& id) {
    if (id == "nobody") return ICON_NOBODY;
    if (id == "alpha") return ICON_ALPHA;
    if (id == "sleeper") return ICON_SLEEPER;
    if (id == "seeker") return ICON_SEEKER;
    if (id == "medic") return ICON_MEDIC;
    if (id == "hunter") return ICON_HUNTER;
    if (id == "vigilante") return ICON_VIGILANTE;
    if (id == "judge") return ICON_JUDGE;
    if (id == "cupid") return ICON_CUPID;
    if (id == "handler") return ICON_HANDLER;
    if (id == "fixer") return ICON_FIXER;
    if (id == "marked") return ICON_MARKED;
    if (id == "prospect") return ICON_PROSPECT;
    if (id == "chemist") return ICON_CHEMIST;
    if (id == "pistol") return ICON_PISTOL;
    if (id == "gavel") return ICON_GAVEL;
    if (id == "clue") return ICON_CRYSTAL_BALL;
    if (id == "coward") return ICON_COWARD;
    if (id == "hardened") return ICON_HARDENED;
    if (id == "skull") return ICON_SKULL;
    if (id == "empty") return ICON_EMPTY;
    if (id =
inputInit function · cpp · L27-L43 (17 LOC)
esp32-terminal/src/input.cpp
void inputInit() {
    // Configure button pins with internal pullup
    pinMode(PIN_BTN_YES, INPUT_PULLUP);
    pinMode(PIN_BTN_NO, INPUT_PULLUP);
    pinMode(PIN_ENCODER_SW, INPUT_PULLUP);

    // Initialize rotary encoder
    ESP32Encoder::useInternalWeakPullResistors = puType::up;
    encoder.attachFullQuad(PIN_ENCODER_A, PIN_ENCODER_B);
    encoder.clearCount();
    lastEncoderCount = 0;

    // Initialize button states
    lastYesState = digitalRead(PIN_BTN_YES);
    lastNoState = digitalRead(PIN_BTN_NO);
}
inputPoll function · cpp · L44-L123 (80 LOC)
esp32-terminal/src/input.cpp
InputEvent inputPoll() {
    unsigned long now = millis();

    // === Check YES button ===
    bool yesState = digitalRead(PIN_BTN_YES);
    if (yesState != lastYesState) {
        if (now - lastYesChange > DEBOUNCE_MS) {
            lastYesChange = now;
            lastYesState = yesState;

            if (yesState == LOW) {
                // Button pressed — start long press timer
                yesPressing = true;
                yesPressStart = now;
                yesLongFired = false;
            } else {
                // Button released — fire normal press if long press didn't already fire
                if (yesPressing && !yesLongFired) {
                    yesPressing = false;
                    return InputEvent::YES;
                }
                yesPressing = false;
            }
        }
    }

    // Check YES long press threshold while button is held
    if (yesPressing && !yesLongFired && (now - yesPressStart >= LONG_PRESS_MS)) {
        yesLongFired = tru
Repobility analyzer · published findings · https://repobility.com
inputGetRotaryPosition function · cpp · L124-L129 (6 LOC)
esp32-terminal/src/input.cpp
uint8_t inputGetRotaryPosition() {
    int32_t count = encoder.getCount() / ENCODER_PULSES_PER_DETENT;
    int pos = ((count % 8) + 8) % 8 + 1;
    return (uint8_t)pos;
}
getPulseBrightness function · cpp · L22-L25 (4 LOC)
esp32-terminal/src/leds.cpp
static float getPulseBrightness() {
    // Sine wave from 0.2 to 1.0
    return 0.2f + 0.8f * (0.5f + 0.5f * sin(pulsePhase));
}
applyLedState function · cpp · L28-L49 (22 LOC)
esp32-terminal/src/leds.cpp
static void applyLedState(uint8_t channel, LedState state) {
    uint8_t bright = (channel == PWM_CHANNEL_NO) ? LED_BRIGHT_NO : LED_BRIGHT;
    uint8_t brightness = LED_OFF;

    switch (state) {
        case LedState::OFF:
            brightness = LED_OFF;
            break;
        case LedState::DIM:
            brightness = LED_DIM;
            break;
        case LedState::BRIGHT:
            brightness = bright;
            break;
        case LedState::PULSE:
            // Treat pulse same as bright for button LEDs
            brightness = bright;
            break;
    }

    ledcWrite(channel, brightness);
}
ledsInit function · cpp · L50-L71 (22 LOC)
esp32-terminal/src/leds.cpp
void ledsInit() {
    // Initialize PWM for button LEDs
    ledcSetup(PWM_CHANNEL_YES, PWM_FREQ, PWM_RESOLUTION);
    ledcSetup(PWM_CHANNEL_NO, PWM_FREQ, PWM_RESOLUTION);
    ledcSetup(PWM_CHANNEL_POWER, PWM_FREQ, PWM_RESOLUTION);

    ledcAttachPin(PIN_LED_YES, PWM_CHANNEL_YES);
    ledcAttachPin(PIN_LED_NO, PWM_CHANNEL_NO);
    ledcAttachPin(PIN_LED_POWER, PWM_CHANNEL_POWER);

    // Start with LEDs off (power LED on at low brightness)
    ledcWrite(PWM_CHANNEL_YES, 0);
    ledcWrite(PWM_CHANNEL_NO, 0);
    ledcWrite(PWM_CHANNEL_POWER, LED_POWER_BRIGHT);

    // Initialize Neopixel
    neopixel.begin();
    neopixel.setBrightness(25);  // 25/255 brightness
    neopixel.clear();
    neopixel.show();
}
ledsUpdate function · cpp · L72-L97 (26 LOC)
esp32-terminal/src/leds.cpp
void ledsUpdate() {
    unsigned long now = millis();

    // Update pulse animation (~60 fps)
    if (now - lastPulseUpdate > 16) {
        lastPulseUpdate = now;

        // Advance pulse phase (complete cycle in LED_PULSE_MS)
        pulsePhase += (2.0f * PI * 16.0f) / LED_PULSE_MS;
        if (pulsePhase > 2.0f * PI) {
            pulsePhase -= 2.0f * PI;
        }

        // Update neopixel if pulsing
        if (statusPulse) {
            float brightness = getPulseBrightness();
            neopixel.setPixelColor(0, neopixel.Color(
                (uint8_t)(statusR * brightness),
                (uint8_t)(statusG * brightness),
                (uint8_t)(statusB * brightness)
            ));
            neopixel.show();
        }
    }
}
ledsSetYes function · cpp · L98-L102 (5 LOC)
esp32-terminal/src/leds.cpp
void ledsSetYes(LedState state) {
    yesLedState = state;
    applyLedState(PWM_CHANNEL_YES, state);
}
ledsSetNo function · cpp · L103-L107 (5 LOC)
esp32-terminal/src/leds.cpp
void ledsSetNo(LedState state) {
    noLedState = state;
    applyLedState(PWM_CHANNEL_NO, state);
}
ledsSetFromDisplay function · cpp · L108-L112 (5 LOC)
esp32-terminal/src/leds.cpp
void ledsSetFromDisplay(const DisplayState& state) {
    ledsSetYes(state.leds.yes);
    ledsSetNo(state.leds.no);
}
Open data scored by Repobility · https://repobility.com
ledsSetStatusColor function · cpp · L113-L122 (10 LOC)
esp32-terminal/src/leds.cpp
void ledsSetStatusColor(uint8_t r, uint8_t g, uint8_t b) {
    statusR = r;
    statusG = g;
    statusB = b;
    statusPulse = false;

    neopixel.setPixelColor(0, neopixel.Color(r, g, b));
    neopixel.show();
}
ledsSetStatus function · cpp · L123-L179 (57 LOC)
esp32-terminal/src/leds.cpp
void ledsSetStatus(ConnectionState state) {
    switch (state) {
        case ConnectionState::BOOT:
            // White - initializing
            statusR = 100; statusG = 100; statusB = 100;
            statusPulse = false;
            break;

        case ConnectionState::PLAYER_SELECT:
            // Purple - selecting player
            statusR = 150; statusG = 0; statusB = 255;
            statusPulse = true;
            break;

        case ConnectionState::WIFI_CONNECTING:
            // Blue - connecting to WiFi
            statusR = 0; statusG = 0; statusB = 255;
            statusPulse = true;
            break;

        case ConnectionState::WS_CONNECTING:
            // Yellow - connecting to WebSocket
            statusR = 255; statusG = 200; statusB = 0;
            statusPulse = true;
            break;

        case ConnectionState::JOINING:
            // Cyan - joining game
            statusR = 0; statusG = 255; statusB = 255;
            statusPulse = false;
    
ledsSetGameState function · cpp · L180-L232 (53 LOC)
esp32-terminal/src/leds.cpp
void ledsSetGameState(GameLedState state) {
    switch (state) {
        case GameLedState::NONE:
            // No game state - don't change neopixel
            return;

        case GameLedState::LOBBY:
            statusR = 100; statusG = 100; statusB = 100;
            statusPulse = false;
            break;

        case GameLedState::DAY:
            statusR = 0; statusG = 255; statusB = 0;
            statusPulse = false;
            break;

        case GameLedState::NIGHT:
            statusR = 0; statusG = 0; statusB = 255;
            statusPulse = false;
            break;

        case GameLedState::VOTING:
            statusR = 255; statusG = 200; statusB = 0;
            statusPulse = true;
            break;

        case GameLedState::LOCKED:
            statusR = 0; statusG = 255; statusB = 0;
            statusPulse = false;
            break;

        case GameLedState::ABSTAINED:
            statusR = 60; statusG = 60; statusB = 60;
            statusPulse = fals
‹ prevpage 3 / 10next ›