Skip to content

fix: stop emitting NaN pin_number for non-numeric DSN pin names - #550

Closed
itzKLAUS wants to merge 5 commits into
tscircuit:mainfrom
itzKLAUS:fix/string-pin-numbers-nan
Closed

itzKLAUS wants to merge 5 commits into
tscircuit:mainfrom
itzKLAUS:fix/string-pin-numbers-nan

Conversation

@itzKLAUS

@itzKLAUS itzKLAUS commented Sep 8, 2026

Copy link
Copy Markdown

fix: stop emitting NaN pin_number for non-numeric DSN pin names

Problem

The smoothieboard DSN (#54) has 78 non-numeric pin names — EPAD,
GND, A, C, P$1, VIN0… convertDsnPcbComponentsToSourceComponentsAndPorts
ran Number(pin.pin_number) over every pin, producing 258 source_ports
with pin_number: NaN
in the converted circuit JSON.

Additionally, three pcb_smtpad_id templates embedded
Number(pin.pin_number) - 1, so string-named pads got ids like
pcb_smtpad_..._NaN.

Fix

  • source_port.pin_number is only set when the pin token is numeric;
    the raw token remains available via name and port_hints.
  • pcb_smtpad_id: numeric pins keep the historical 0-based index;
    string pins get a sanitized token suffix instead of NaN.

Test

New regression test string-pin-numbers: converts the full smoothieboard
DSN and asserts zero NaN pin_numbers and that an EPAD port is still
reachable. Fails on main (258 NaN ports), passes with this change.

Full suite: 57 pass / 0 fail / 1 skip.

Related: #54

- split test path on both / and \ so Windows doesn't produce an invalid
  debug-files path (ENOENT crash in two tests)
- write debug files synchronously: Bun.write promises were never awaited,
  so looksSame could read a partially-flushed SVG and throw
  ERR_BUFFER_OUT_OF_BOUNDS

Full suite now passes: 55 pass / 0 fail / 1 skip.
Pins like (pin Rect[T]Pad_1600x1400_um (rotate 90) A 1400 0) were parsed
with pin_number="rotate" — the rotate sublist was consumed as the pin
number, the rotation angle and pin name were dropped, and the padstack
name leaked into downstream Number(pin.pin_number) conversions as NaN.

processPin now:
- detects the optional (rotate <deg>) sublist and records it as pin.rotation
- reads the pin number from the correct index (Atom or single-child List)
- scans coordinates from the correct start index

The smoothieboard repro snapshot is updated: 92 rotated pins now carry
their real pin numbers and rotation instead of the corrupt "rotate"
token.
DSN placement lines carry a rotation (e.g. Q8 placed at 270° in the
smoothieboard file), but both converters destructured it and ignored it
— pad and pcb_port positions were computed as if every component were
placed at 0°.

- convertPadstacksToSmtPads: rotate each pin offset around the component
  origin by place.rotation (CCW in DSN space, y-up) before applying the
  unit transform
- convertDsnPcbComponentsToSourceComponentsAndPorts: same rotation for
  pcb_port centers so ports stay on their pads

Adds a focused regression test (place-rotation-applied) and updates the
smoothieboard repro snapshot: pads of rotated components now sit on
their rotated offsets.
The smoothieboard has 78 non-numeric pin names (EPAD, GND, A, C, P$1…).
convertDsnPcbComponentsToSourceComponentsAndPorts ran Number(pin.pin_number)
on all of them, producing 258 source_ports with pin_number: NaN.

- source_port.pin_number is now only set when the pin token is numeric;
  the raw token stays available in name and port_hints
- pcb_smtpad ids no longer contain "NaN": numeric pins keep the
  historical 0-based index, string pins get a sanitized token suffix

Adds string-pin-numbers regression test. Full suite: 57 pass / 0 fail.
@itzKLAUS itzKLAUS closed this by deleting the head repository Sep 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants