# Lego Ladder PLC Editor — Symbol Audit Report

**Date:** 2026-07-07
**Scope:** Complete audit of all ladder logic symbols across types, engine, UI rendering, toolbar, and exporter.

---

## 1. SYMBOL CATALOG — What's Currently Implemented

### 1.1 Types Defined (`src/engine/types.ts`)

| Symbol Category | Types/Values | Interface | Status |
|---|---|---|---|
| **Contact** | `NO` (Normally Open), `NC` (Normally Closed) | `Contact` | ✅ Defined |
| **Coil** | `OUTPUT`, `SET`, `RESET`, `TOGGLE` | `Coil` | ✅ Defined |
| **Timer** | `TON` (On-Delay), `TOF` (Off-Delay), `TP` (Pulse) | `Timer` | ✅ Defined |
| **Counter** | `CTU` (Count Up), `CTD` (Count Down), `CTUD` (Count Up/Down) | `Counter` | ✅ Defined |
| **Logic Gate** | `AND`, `OR`, `XOR`, `NOT`, `NAND`, `NOR` | `LogicGate` | ⚠️ Defined, NAND/NOR broken |
| **Branch** | `AND` (all paths true), `OR` (any path true) | `Branch` | ✅ Defined |
| **Math** | `ADD`, `SUB`, `MUL`, `DIV` | `MathElement` | ✅ Defined |
| **Comparison** | `==`, `!=`, `>`, `<`, `>=`, `<=` (on contacts) | `ComparisonCondition` | ✅ Defined |

**Total element types:** 7 | **Total sub-types:** 24

### 1.2 Engine Implementation (`src/engine/engine.ts`)

| Element Type | Engine Handler | Status | Notes |
|---|---|---|---|
| Contact (NO/NC) | `evaluateContact()` | ✅ Working | Supports comparison conditions |
| Coil (OUTPUT/SET/RESET/TOGGLE) | `activateCoil()` | ✅ Working | All 4 coil types evaluated |
| Timer (TON/TOF/TP) | `evaluateTimer()` | ✅ Working | Accumulation + preset logic |
| Counter (CTU/CTD/CTUD) | `evaluateCounter()` | ✅ Working | Rising-edge counting, reset support |
| Gate (AND/OR/XOR/NOT) | `evaluateGate()` | ✅ Working | 4 of 6 gate types |
| **Gate (NAND/NOR)** | `evaluateGate()` | ❌ **BUG** | Falls through to `default: return false` — always returns false |
| Branch (AND/OR) | `evaluateBranch()` | ✅ Working | Recursive path evaluation |
| Math (ADD/SUB/MUL/DIV) | `evaluateMath()` | ✅ Working | Writes to output or memory |

### 1.3 UI Rendering (`src/ui/components/Element.tsx`)

| Element | Visual Representation | Studio 5000 Fidelity | Notes |
|---|---|---|---|
| Contact | Two vertical lines with diagonal stroke | ⚠️ Basic | Diagonal direction distinguishes NO/NC. Missing tag labels between contact bars. |
| Coil | Circle | ⚠️ Basic | Standard IEC symbol. Missing OTL (latch/unlatch) symbols. |
| Timer | Rounded rectangle with type label | ✅ Standard | Standard function-block style, acceptable. |
| Counter | Rounded rectangle with type label | ✅ Standard | Same as timer — acceptable. |
| Gate | Hexagon | ⚠️ Non-standard | NOT a PLC ladder symbol. Logic gates don't appear as hexagons in Studio 5000. |
| Math | Rounded rectangle with operator | ⚠️ Non-standard | Acceptable abstraction but not native ladder. |
| Branch | Forked Y-lines | ⚠️ Non-standard | Branches are structural, not a symbol in ladder logic. |

### 1.4 Toolbar Palette (`src/ui/components/Toolbar.tsx`)

| Toolbar Item | Maps To | Category |
|---|---|---|
| NO Contact | `contact-no` → `Contact{NO}` | Inputs |
| NC Contact | `contact-nc` → `Contact{NC}` | Inputs |
| Output Coil | `coil-output` → `Coil{OUTPUT}` | Outputs |
| TON Timer | `timer-ton` → `Timer{TON}` | Timers |
| CTU Counter | `counter-ctu` → `Counter{CTU}` | Counters |
| AND Gate | `gate-and` → `LogicGate{AND}` | Logic |
| Math ADD | `math-add` → `MathElement{ADD}` | Math |
| Branch | `branch` → `Branch{AND}` | Control |

**Only 8 toolbar items** for 24 possible sub-types. Config panel lets users change types after placement, but the palette is limited.

### 1.5 Exporter (`src/engine/exporter.ts`)

| Element | Export Support | Status |
|---|---|---|
| Contact | ✅ Basic (digitalRead) | Simplified pin mapping |
| Coil | ✅ Basic (digitalWrite) | Simplified, SET/RESET/TOGGLE not handled |
| Gate | ⚠️ Stub (`true`) | Not actually implemented |
| Timer | ❌ Missing | Not exported |
| Counter | ❌ Missing | Not exported |
| Math | ❌ Missing | Not exported |
| Branch | ❌ Missing | Not exported |

---

## 2. VISUAL REPRESENTATION ASSESSMENT

### Issues Found

1. **NO/NC Contact symbol** — The diagonal line approach is a common textbook representation, but the standard IEC/ANSI contact uses parallel vertical bars with an optional diagonal or crossbar. The current implementation is *acceptable but simplified*. Missing: tag labels *between* the contact bars (Studio 5000 shows the tag name inline).

2. **Coil symbol** — Circle is the IEC standard for output coils. Acceptable. Missing: OTL (Output Latch) coil which uses an "L" in the circle.

3. **Timer/Counter** — Rounded rectangles with text labels. This is standard for instruction-based elements in ladder logic. Acceptable for both Studio 5000 and IEC 61131-3.

4. **Logic Gates as hexagons** — **NOT standard ladder logic**. In Studio 5000, logic operations are expressed through contacts/coils, not standalone gate symbols. If the goal is Studio 5000 fidelity, these should be replaced with contact/coil equivalents. If the goal is accessibility for non-PLC programmers (Lego Technic audience), hexagons are fine but misleading.

5. **Branch as forked lines** — In real ladder logic, branching is a structural feature of the rung (parallel rungs), not a discrete symbol. The current approach of making it a drag-and-drop element is a usability abstraction.

---

## 3. CONSISTENCY AUDIT

### Cross-Layer Consistency Matrix

| Symbol | Types ✅ | Engine ✅ | Render ✅ | Toolbar ✅ | Config ✅ | Export ✅ | Consistent? |
|---|---|---|---|---|---|---|---|
| Contact NO/NC | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ Yes |
| Coil OUTPUT/SET/RESET/TOGGLE | ✅ | ✅ | ✅ | ⚠️ OUTPUT only | ✅ | ⚠️ OUTPUT only | ⚠️ Partial |
| Timer TON/TOF/TP | ✅ | ✅ | ✅ | ⚠️ TON only | ✅ | ❌ | ❌ No |
| Counter CTU/CTD/CTUD | ✅ | ✅ | ✅ | ⚠️ CTU only | ✅ | ❌ | ❌ No |
| Gate AND/OR/XOR/NOT/NAND/NOR | ✅ | ⚠️ NAND/NOR broken | ✅ | ⚠️ AND only | ✅ | ⚠️ Stub | ❌ No |
| Branch AND/OR | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ⚠️ Partial |
| Math ADD/SUB/MUL/DIV | ✅ | ✅ | ✅ | ⚠️ ADD only | ✅ | ❌ | ❌ No |

**Consistency score: 2/7 fully consistent, 2/7 partial, 3/7 broken**

### Bugs Found

| # | Severity | Location | Description |
|---|---|---|---|
| 1 | **HIGH** | `engine.ts:483` | NAND/NOR gates fall through to `default: return false` — always evaluates to false regardless of inputs |
| 2 | MEDIUM | `exporter.ts` | Exporter doesn't handle SET/RESET/TOGGLE coils (only OUTPUT) |
| 3 | MEDIUM | `exporter.ts` | Gate export is stub (`true`) — not functional |
| 4 | LOW | `toolbar.tsx` | Only exposes subset of available types (users must drag then reconfigure) |
| 5 | LOW | `Element.tsx` | Timer/Counter don't render preset or accumulated values visually |

---

## 4. COMPLETENESS vs. ALLEN BRADLEY STUDIO 5000

### Studio 5000 Standard Instructions

| Instruction Category | Studio 5000 | Lego Ladder | Missing from Lego Ladder |
|---|---|---|---|
| **Boolean** | XIO, XIC, OTE, OTL, OTU, OTN, LBL, SBR, RES | XIC(NO), XIO(NC), OTE(OUTPUT), OTL→SET/RESET, no OTL latch/unlatch | OTL (Latch/Unlatch), LBL (Label), SBR (Subroutine), RES (Reset), ONS (One-Shot), OSC (Seal-In) |
| **Timers** | TON, TOF, RTO | TON, TOF, TP | RTO (Retain On-Delay) |
| **Counters** | CTU, CTD, CTUD | CTU, CTD, CTUD | ✅ All present |
| **Comparison** | EQU, NEQ, GRE, GRT, LES, LES | On-contact conditions | ✅ Present as contact conditions, but not standalone instructions |
| **Math** | ADD, SUB, MUL, DIV, SQRT, ABS, EXP, LOG, LN, SIN, COS, TAN, ATAN, NEG, MOV, SLC | ADD, SUB, MUL, DIV | MOV, SLC (Scale), SQRT, ABS, and all trig functions |
| **Data** | MOV, CMP, FLL | None | MOV (Move), CMP (Compare), FLL (Fill) |
| **Bit** | BSC, BSL, BSW | None | BSC (Bit Set/Clear), BSL (Bit Shift Left), BSW (Bit Swap) |
| **Sequencing** | SEQ, CSQ | None | Sequencer instructions |
| **Conversion** | CPT, CPD, CI, CU, DI, DP, DF, DU, F_DP, D_FP, D_I, D_S, D_U, F_I, F_S, F_U, I_D, I_S, I_U, S_D, S_I, S_U, U_D, U_S, U_I | None | All conversion instructions |
| **Communication** | MSG, CIP | None | CIP messaging |
| **Motion** | MC_Power, MC_Home, MC_Move | None | Motion Control instructions |
| **Control** | JMP, JSR, NOP, RSE, RSN, OSC, ONS | None | Jump, Subroutine, NOP, Rising/Falling Edge |

### Summary

**Coverage: ~15% of Studio 5000 instruction set.** The project implements the core boolean/timer/counter building blocks but is missing everything beyond that.

### Recommended Additions for "Industrial Shop" Audience

**Priority 1 (Essential):**
- OTL/OTU/OTN — Latch, Unlatch, Negative Latch coils (separate from SET/RESET)
- ONS — One-Shot Rising Edge contact (fires true for one scan only)
- Edge-detection contacts (Positive Edge, Negative Edge)
- MOV instruction — fundamental data movement
- Scale (SLC) instruction — essential for analog inputs
- RTO — Retain On-Delay timer

**Priority 2 (Important):**
- Compare instructions as standalone elements (EQU, GRE, LES, etc.)
- Additional math: ABS, SQRT, NEG, and trig functions
- Bit operations: BSC, BSL, BSW
- NOP (No Operation) — placeholder/separator

**Priority 3 (Advanced):**
- Sequencer (SEQ)
- Fill (FLL)
- Data conversion instructions
- Subroutine (JSR) / Jump (JMP)

---

## 5. LEGO TECHNIC / ESP32 RELEVANCE

### Useful for Lego Technic Projects

| Symbol | Relevance | Use Case |
|---|---|---|
| NO Contact | ⭐⭐⭐ Essential | Sensor state (touch, color, distance) |
| NC Contact | ⭐⭐⭐ Essential | Inverted sensor logic |
| OUTPUT Coil | ⭐⭐⭐ Essential | Motor/LED control |
| SET/RESET Coil | ⭐⭐⭐ Essential | Latching mechanisms (gearbox engagement) |
| TOGGLE Coil | ⭐⭐ High | Button toggling |
| TON Timer | ⭐⭐⭐ Essential | Delayed responses, startup sequences |
| TOF Timer | ⭐⭐ High | Hold-after-release behavior |
| TP Timer | ⭐⭐ High | Pulse generation for servos |
| CTU Counter | ⭐⭐ High | Event counting, RPM tracking |
| CTD Counter | ⭐ Medium | Countdown timers |
| CTUD Counter | ⭐ Low | Position tracking (rarely needed) |
| Comparison | ⭐⭐⭐ Essential | Threshold-based decisions (distance < 20cm) |
| ADD/SUB Math | ⭐⭐ High | Sensor offset, proportional control |
| MUL/DIV Math | ⭐ Medium | Scaling, ratio calculations |
| AND/OR Logic | ⭐ Medium | Compound conditions |
| XOR/NOT | ⭐ Low | Rarely needed for Lego projects |
| NAND/NOR | ⭐ None | Not relevant for Lego Technic |
| Branch | ⭐⭐ High | Parallel logic paths |

### Overkill for Lego Technic

- Logic gates as hexagons — contacts achieve the same thing
- NAND/NOR gates — not needed
- CTUD counter — position tracking is edge-case
- Advanced math (trig, sqrt) — not needed
- Data conversion instructions — not needed
- Motion control instructions — ESP32 + Lego doesn't use CIP
- Communication (MSG) — ESP32 uses MQTT/WiFi, not CIP

### Recommended Lego Technic Focus Set

For a "Lego Technic first" mode, the palette should highlight:
1. NO/NC Contact (with sensor-specific addressing: `DIST:1`, `COLOR:2`, `TOUCH:3`)
2. OUTPUT/SET/RESET/TOGGLE Coil (with actuator addressing: `MOTOR:A`, `SERVO:B`, `LED:1`)
3. TON/TOF Timer
4. CTU Counter
5. Comparison contact (`<`, `>`, `==`)
6. ADD/SUB/MUL math
7. Branch (OR)

---

## 6. SPECIFIC BUGS & FIXES

### Bug 1: NAND/NOR Gates Always Return False
**File:** `src/engine/engine.ts`, line 483
```typescript
// Current (broken):
case 'NOT': return !inputValues[0];
default: return false;  // ← NAND and NOR fall here!

// Fix:
case 'NOT': return !inputValues[0];
case 'NAND': return !inputValues.every(Boolean);
case 'NOR': return !inputValues.some(Boolean);
default: return false;
```

### Bug 2: Timer/Counter Not in Exporter
**File:** `src/engine/exporter.ts`
Timers and counters produce no Arduino code. They need cases in the switch statement.

### Bug 3: Gate Export is Stub
**File:** `src/engine/exporter.ts`, line 40
Gate evaluation outputs literal `true` instead of actual logic.

### Bug 4: Missing Coil Types in Exporter
**File:** `src/engine/exporter.ts`
SET/RESET/TOGGLE coils all export as `digitalWrite(..., rungX_state ? HIGH : LOW)` — they should handle latching logic.

---

## 7. RECOMMENDATIONS SUMMARY

### Quick Wins (Fix Existing)
1. **Fix NAND/NOR gate evaluation** — 2-line fix in `engine.ts`
2. **Add missing toolbar items** — Expand palette to expose TOF, TP, CTD, CTUD, XOR, NOT, SUB, MUL, DIV, SET coil, RESET coil, TOGGLE coil
3. **Fix exporter** — Complete timer, counter, and branch export paths
4. **Render accumulated/preset values** on timer/counter elements for runtime visibility

### Medium Effort (Improve Existing)
5. **Better contact/coil visuals** — Add inline tag labels between contact bars (Studio 5000 style)
6. **Edge-detection contacts** — Add ONS (one-shot) contact type
7. **MOV instruction** — Essential for both audiences
8. **Scale instruction** — Essential for analog sensor inputs

### Strategic Decisions
9. **Logic gates** — Decide: keep as accessibility feature for Lego Technic novices, or replace with standard ladder contacts/coils for Studio 5000 fidelity
10. **Audience split** — Consider a "Technic Mode" palette (simplified, sensor/actuator focused) vs. "PLC Mode" palette (full Studio 5000 instruction set)
11. **Remove or deprecate NAND/NOR** — Neither audience needs them

---

## 8. FILES AUDITED

| File | Lines | Purpose |
|---|---|---|
| `src/engine/types.ts` | 175 | Type definitions for all symbols |
| `src/engine/engine.ts` | 622 | Scan cycle evaluation engine |
| `src/engine/errors.ts` | 31 | Error classes |
| `src/engine/exporter.ts` | 62 | Arduino code export |
| `src/ui/components/Element.tsx` | 284 | SVG symbol rendering |
| `src/ui/components/Ladder.tsx` | 222 | Canvas with rails/wires |
| `src/ui/components/Toolbar.tsx` | 50 | Drag-and-drop palette |
| `src/ui/components/ConfigPanel.tsx` | 295 | Per-symbol configuration |
| `src/ui/App.tsx` | 200 | App wiring + element creation |
| `src/styles/components.css` | 447 | Visual styling |
| `src/engine/engine.test.ts` | 616 | Unit tests |
| `src/engine/edge_trigger.test.ts` | 165 | Edge-trigger tests |
