Files
Kill_LIFE/hardware/blocks/gen_i2s_dac.py
T
root e67fb754c2 feat: KiCad 10 native, QEMU simulation, compliance EU, firmware fixes
Session kxkm-ai 25-26 mars 2026 — 98/98 tâches TODO complétées.

Hardware:
- KiCad 10.0.0 native avec sym/fp-lib-table locales
- Nouveau block SPI (gen_spi_header.py), ERC clean
- Module partagé hardware/lib/kicad_gen.py (5 générateurs refactorisés)
- Pipeline export: tools/hw/hw_export.sh (ERC + SVG + PDF + netlist)
- KiBot 1.8.5 installé, .kibot.yaml configuré

Firmware:
- Fix I2S driver conflict: migration I2sMic vers nouvelle API i2s_channel_*
- Fix WDT risk: yield() dans CompletePushToTalk (voice_controller.cpp)
- Fix XSS wifi_manager.cpp: innerHTML → createElement/textContent
- Fix null check FwIsValidWavHeader
- Dead code supprimé: i2s_audio.cpp.bak, i2s_audio.h

Simulation MCU:
- QEMU ESP32-S3 v9.2.2 installé (tools/sim/)
- Script run_qemu_esp32s3.sh — boot OK vérifié
- [env:esp32s3_qemu] dans platformio.ini
- Wokwi CI: wokwi.toml + diagram.json + scenario.yaml
- SPICE bridge POC: tools/sim/spice_bridge.py (ngspice → ADC/brownout)

Compliance:
- Profil iot_wifi_eu validé (16 standards, 8 evidence)
- 4 evidence remplis: risk_assessment, security_architecture,
  test_plan_radio_emc, supply_chain_declarations
- plan.yaml complété avec données produit réelles

CI:
- Job hardware-export (KiCad 10 ERC + SVG + PDF + netlist)
- Job firmware-sim (Wokwi, conditionnel WOKWI_CLI_TOKEN)
- evidence_pack.yml enrichi avec exports hardware

Docs & RAG:
- specs/02_arch.md complet (481 lignes, 4 ADR, diagrammes)
- docs/SIMULATION.md (3 niveaux: native, QEMU, Wokwi)
- 6 chunks ingérés dans kb-kicad RAG
- Dataset HF: tools/generate_hf_dataset.py + datasets/kb_kicad_qa.jsonl
- Rapport analyse: docs/plans/ANALYSIS_REPORT_2026-03-25.md
- Recherche OSS: docs/research/oss_similar_projects.md

Infra:
- ZeroClaw 0.1.7 installé (cargo install)
- APIFY_API_KEY configurée, smoke OK
- Tests: 39/39 firmware + 26/26 Python stable

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 09:52:00 +01:00

166 lines
6.4 KiB
Python

#!/usr/bin/env python3
"""Generate i2s_dac.kicad_sch for KiCad 10 — ERC-clean.
Block: I2S DAC interface connector (Conn_01x06_Pin)
Pin 1: GND
Pin 2: +3V3 (net label)
Pin 3: I2S_BCK (net label)
Pin 4: I2S_WS (net label)
Pin 5: I2S_DOUT (net label)
Pin 6: I2S_DIN (net label)
Connector pin connection points (Conn_01x06_Pin, angle=0):
Pin "at" position in lib space IS the net node (not the visual tip).
Pin 1: at lib (5.08, 5.08, 180) → screen (SX+5.08, SY-5.08)
Pin 2: at lib (5.08, 2.54, 180) → screen (SX+5.08, SY-2.54)
Pin 3: at lib (5.08, 0.00, 180) → screen (SX+5.08, SY)
Pin 4: at lib (5.08, -2.54, 180) → screen (SX+5.08, SY+2.54)
Pin 5: at lib (5.08, -5.08, 180) → screen (SX+5.08, SY+5.08)
Pin 6: at lib (5.08, -7.62, 180) → screen (SX+5.08, SY+7.62)
All placements at multiples of 1.27 mm.
"""
import sys
import pathlib
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1] / "lib"))
from kicad_gen import (gen_uuid, pin_screen, extract_symbol, lib_sym_entry,
prop, sym_inst, power_sym, no_connect, text, net_lbl,
SYMLIB)
# ── Build schematic ──────────────────────────────────────────────────────────
def build(output: pathlib.Path):
print("Extracting symbols from KiCad 10 libraries...")
lib_symbols_entries = [
lib_sym_entry("power", "GND"),
lib_sym_entry("power", "PWR_FLAG"),
lib_sym_entry("Connector", "Conn_01x06_Pin"),
]
print(f" Extracted {len(lib_symbols_entries)} symbols.")
lib_symbols_block = "\t(lib_symbols\n" + "\n".join(lib_symbols_entries) + "\n\t)"
placements = []
pwr_syms = []
labels = []
pwr_n = [1]
def next_pwr():
n = pwr_n[0]
pwr_n[0] += 1
return n
placed_pwr_keys = set()
def add_pwr(lib_id, x, y):
key = (lib_id, round(x, 3), round(y, 3))
if key not in placed_pwr_keys:
placed_pwr_keys.add(key)
pwr_syms.append(power_sym(lib_id, x, y, next_pwr()))
# ── J1: Conn_01x06_Pin at (30.48, 63.50) ─────────────────────────────────
# Conn_01x06_Pin: 6 pins, all exit right side at x_lib=1.27, angle=0
# Pin 1 tip: lib (1.27, 5.08) → screen (SX+1.27, SY-5.08)
# Pin 2 tip: lib (1.27, 2.54) → screen (SX+1.27, SY-2.54)
# Pin 3 tip: lib (1.27, 0.00) → screen (SX+1.27, SY)
# Pin 4 tip: lib (1.27, -2.54) → screen (SX+1.27, SY+2.54)
# Pin 5 tip: lib (1.27, -5.08) → screen (SX+1.27, SY+5.08)
# Pin 6 tip: lib (1.27, -7.62) → screen (SX+1.27, SY+7.62)
J1X, J1Y = 30.48, 63.50
placements.append(sym_inst(
lib_id="Connector:Conn_01x06_Pin",
x=J1X, y=J1Y, angle=0,
ref="J1", value="I2S DAC",
footprint="Connector_PinHeader_2.54mm:PinHeader_1x06_P2.54mm_Vertical",
datasheet="~",
props_extra={"Pitch": "2.54mm", "Interface": "I2S"},
pin_numbers=["1", "2", "3", "4", "5", "6"],
))
# Connection points for Conn_01x06_Pin:
# In KiCad, the pin "at" position IS the electrical connection point.
# Library definition: (at 5.08, Y, 180)(length 3.81)
# The "at" coord (5.08, Y) in lib space is the net node.
# pin_screen(SX, SY, angle, 5.08, Y_lib) gives the screen connection point.
# Pin 1: at lib (5.08, 5.08, 180) → screen (SX+5.08, SY-5.08)
# Pin 2: at lib (5.08, 2.54, 180) → screen (SX+5.08, SY-2.54)
# Pin 3: at lib (5.08, 0.00, 180) → screen (SX+5.08, SY)
# Pin 4: at lib (5.08, -2.54, 180) → screen (SX+5.08, SY+2.54)
# Pin 5: at lib (5.08, -5.08, 180) → screen (SX+5.08, SY+5.08)
# Pin 6: at lib (5.08, -7.62, 180) → screen (SX+5.08, SY+7.62)
p1x, p1y = pin_screen(J1X, J1Y, 0, 5.08, 5.08) # Pin 1: GND
p2x, p2y = pin_screen(J1X, J1Y, 0, 5.08, 2.54) # Pin 2: +3V3
p3x, p3y = pin_screen(J1X, J1Y, 0, 5.08, 0.00) # Pin 3: I2S_BCK
p4x, p4y = pin_screen(J1X, J1Y, 0, 5.08, -2.54) # Pin 4: I2S_WS
p5x, p5y = pin_screen(J1X, J1Y, 0, 5.08, -5.08) # Pin 5: I2S_DOUT
p6x, p6y = pin_screen(J1X, J1Y, 0, 5.08, -7.62) # Pin 6: I2S_DIN
print(f"\nPin endpoints (screen coords, all on 1.27mm grid):")
print(f" J1 Pin 1 (GND) : ({p1x}, {p1y})")
print(f" J1 Pin 2 (+3V3) : ({p2x}, {p2y})")
print(f" J1 Pin 3 (I2S_BCK) : ({p3x}, {p3y})")
print(f" J1 Pin 4 (I2S_WS) : ({p4x}, {p4y})")
print(f" J1 Pin 5 (I2S_DOUT) : ({p5x}, {p5y})")
print(f" J1 Pin 6 (I2S_DIN) : ({p6x}, {p6y})")
# Pin 1: GND power symbol
add_pwr("power:GND", p1x, p1y)
# Add PWR_FLAG for GND net
add_pwr("power:PWR_FLAG", p1x, p1y)
# Pin 2: +3V3 net label (passive connector — net label connects to rail in parent)
labels.append(net_lbl("+3V3", p2x, p2y, 0))
# Pins 3-6: I2S signal net labels
labels.append(net_lbl("I2S_BCK", p3x, p3y, 0))
labels.append(net_lbl("I2S_WS", p4x, p4y, 0))
labels.append(net_lbl("I2S_DOUT", p5x, p5y, 0))
labels.append(net_lbl("I2S_DIN", p6x, p6y, 0))
annotations = [
text("Kill_LIFE I2S DAC Interface Block (6-pin 2.54mm)", 10, 6, size=1.5),
text("Pin 1: GND | Pin 2: +3V3 | Pin 3: I2S_BCK | Pin 4: I2S_WS", 10, 10, size=1.0),
text("Pin 5: I2S_DOUT (DAC data out) | Pin 6: I2S_DIN (ADC data in)", 10, 13, size=1.0),
text("Footprint: PinHeader_1x06_P2.54mm_Vertical", 10, 16, size=1.0),
]
all_elements = placements + pwr_syms + labels + annotations
body = "\n".join(all_elements)
sch = f"""(kicad_sch
\t(version 20260101)
\t(generator "kill_life_gen")
\t(generator_version "10.0")
\t(uuid "{gen_uuid()}")
\t(paper "A4")
\t(title_block
\t\t(title "Kill_LIFE I2S DAC Interface Block")
\t\t(date "2026-03-25")
\t\t(rev "1.0")
\t\t(company "Kill_LIFE")
\t\t(comment 1 "6-pin 2.54mm connector for I2S DAC/ADC interface")
\t\t(comment 2 "Pin 1 GND, Pin 2 +3V3, Pin 3 I2S_BCK, Pin 4 I2S_WS")
\t\t(comment 3 "Pin 5 I2S_DOUT (to DAC DIN), Pin 6 I2S_DIN (from ADC DOUT)")
\t)
{lib_symbols_block}
{body}
\t(sheet_instances
\t\t(path "/"
\t\t\t(page "1")
\t\t)
\t)
)
"""
output.write_text(sch)
print(f"\nWritten: {output} ({len(sch):,} bytes)")
if __name__ == "__main__":
out = pathlib.Path(sys.argv[1]) if len(sys.argv) > 1 else pathlib.Path("i2s_dac.kicad_sch")
build(out)