Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/fn/bga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type {
} from "circuit-json"
import { rectpad } from "../helpers/rectpad"
import { circlepad } from "../helpers/circlepad"
import { ALPHABET } from "../helpers/zod/ALPHABET"
import { ALPHABET, bgaRowLabel } from "../helpers/zod/ALPHABET"
import { z } from "zod"
import { base_def } from "../helpers/zod/base_def"
import { length, distance } from "circuit-json"
Expand Down Expand Up @@ -153,8 +153,7 @@ export const bga = (
}
pin_num -= missing_pins_passed

// TODO handle >26 rows
const portHints = [pin_num, `${ALPHABET[pin_y]}${pin_x + 1}`]
const portHints = [pin_num, `${bgaRowLabel(pin_y)}${pin_x + 1}`]
pads.push(
parameters.circularpads
? circlepad(portHints, {
Expand Down
22 changes: 22 additions & 0 deletions src/helpers/zod/ALPHABET.ts
Original file line number Diff line number Diff line change
@@ -1 +1,23 @@
export const ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

/**
* Return a row label for a zero-based row index, extending beyond Z
* with double letters (AA, AB, …, AZ, BA, …).
*
* Rows 0–25 → A … Z (single letter, same as ALPHABET)
* Rows 26–51 → AA … AZ
* Rows 52–77 → BA … BZ
* … and so on.
*
* This keeps backwards compatibility with the existing A–Z labeling
* while supporting large BGA packages (>26 rows).
*/
export function bgaRowLabel(row: number): string {
if (row < 26) {
return ALPHABET[row]!
}

const groupIndex = Math.floor((row - 26) / 26)
const letterIndex = (row - 26) % 26
return `${ALPHABET[groupIndex]}${ALPHABET[letterIndex]}`
}
1 change: 1 addition & 0 deletions tests/__snapshots__/bga_30x30_large_grid.snap.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions tests/bga-large-grid-row-labels.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { test, expect } from "bun:test"
import type { PcbSmtPad } from "circuit-json"
import { convertCircuitJsonToPcbSvg } from "circuit-to-svg"
import { fp } from "../src/footprinter"

test("bga 30x30 grid has valid row labels beyond Z", () => {
const soup = fp.string("bga900_grid30x30_p0.5").circuitJson()
const pads = soup.filter((el): el is PcbSmtPad => el.type === "pcb_smtpad")

expect(pads).toHaveLength(900)

// No pad should have "undefined" in its label
for (const pad of pads) {
expect(pad.port_hints?.[1]).not.toContain("undefined")
}

// Row 0 = A, Row 25 = Z (single letters)
const pinA1 = pads.find((p) => p.port_hints?.[0] === "1")
expect(pinA1?.port_hints?.[1]).toBe("A1")

const pinZ1 = pads.find((p) => p.port_hints?.[1] === "Z1")
expect(pinZ1).toBeDefined()

// Row 26 = AA, Row 27 = AB (double letters)
const pinAA1 = pads.find((p) => p.port_hints?.[1] === "AA1")
expect(pinAA1).toBeDefined()

const pinAB1 = pads.find((p) => p.port_hints?.[1] === "AB1")
expect(pinAB1).toBeDefined()

// Row 29 = AD (last row of a 30x30 grid)
const pinAD1 = pads.find((p) => p.port_hints?.[1] === "AD1")
expect(pinAD1).toBeDefined()

const svgContent = convertCircuitJsonToPcbSvg(soup)
expect(svgContent).toMatchSvgSnapshot(
import.meta.path,
"bga_30x30_large_grid",
)
})
8 changes: 8 additions & 0 deletions tests/bga-row-label-helper.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { test, expect } from "bun:test"
import { bgaRowLabel, ALPHABET } from "../src/helpers/zod/ALPHABET"

test("bgaRowLabel matches ALPHABET for rows 0-25", () => {
for (let i = 0; i < 26; i++) {
expect(bgaRowLabel(i)).toBe(ALPHABET[i])
}
})
11 changes: 11 additions & 0 deletions tests/bga-row-label-helper2.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { test, expect } from "bun:test"
import { bgaRowLabel } from "../src/helpers/zod/ALPHABET"

test("bgaRowLabel produces double letters after Z", () => {
expect(bgaRowLabel(26)).toBe("AA")
expect(bgaRowLabel(27)).toBe("AB")
expect(bgaRowLabel(51)).toBe("AZ")
expect(bgaRowLabel(52)).toBe("BA")
expect(bgaRowLabel(77)).toBe("BZ")
expect(bgaRowLabel(78)).toBe("CA")
})
Loading