More PCB progress
This commit is contained in:
parent
05a33d00ec
commit
55d60ba599
9 changed files with 231 additions and 100 deletions
40
README.md
40
README.md
|
@ -115,6 +115,7 @@ points:
|
|||
|
||||
`anchors` are used to, well, anchor the zone to something.
|
||||
It's the `[0, 0]` origin with a 0 degree orientation by default, but it can be changed to any other pre-existing point.(Consequently, the first zone can't use a ref, because there isn't any yet.)
|
||||
The `ref` field can also be an array of references, in which case their average is used -- mostly useful for anchoring to the center, by averaging a key and its mirror; see later.
|
||||
This initial position can then be changed with the `rotate` and `shift` options, adding extra rotation and translation, respectively.
|
||||
|
||||
Once we know _where_ to start, we can describe the `columns` of our layout.
|
||||
|
@ -184,6 +185,7 @@ rotate: num # default = 0
|
|||
padding: num # default = 19
|
||||
skip: boolean # default = false
|
||||
asym: left | right | both # default = both
|
||||
mirror: <arbitrary key-level data>
|
||||
```
|
||||
|
||||
`name` is the unique identifier of this specific key.
|
||||
|
@ -192,7 +194,7 @@ It defaults to a `<row>_<column>` format, but can be overridden if necessary.
|
|||
Then we leave `padding` amount of vertical space before moving on to the next key in the column.
|
||||
`skip` signals that the point is just a "helper" and should not be included in the output.
|
||||
This can happen when a _real_ point is more easily calculable through a "stepping stone", but then we don't actually want the stepping stone to be a key itself.
|
||||
Finally, `asym` relates to mirroring, which we'll cover in a second.
|
||||
Finally, `asym` and `mirror` relate to mirroring, which we'll cover in a second.
|
||||
|
||||
<hr />
|
||||
|
||||
|
@ -221,6 +223,9 @@ If it's set as `left`, mirroring will simply skip this key.
|
|||
If it's `right`, mirroring will "move" the point instead of copying it.
|
||||
The default `both` assumes symmetry.
|
||||
|
||||
Using the _key-level_ `mirror` key (not to be confused with the global `mirror` setting we just discussed above), we can set additional data for the mirrored version of the key.
|
||||
It will use the same extension mechanism as it did for the 5 levels before.
|
||||
|
||||
And this concludes point definitions.
|
||||
This should be generic enough to describe any ergo layout, yet easy enough so that you'll appreciate not having to work in raw CAD.
|
||||
|
||||
|
@ -575,9 +580,8 @@ Footprints can be specified at the key-level (under the `points` section, like w
|
|||
The differences between the two footprint types are:
|
||||
|
||||
- an omitted `ref` in the anchor means the current key for key-level declarations, while here it defaults to `[0, 0]`
|
||||
- a parameter starting with an exclamation point is an indirect reference to an eponymous key-level attribute -- so, for example, `from = !col_wire` would mean that the key's `col_wire` attribute is read there.
|
||||
- a parameter starting with an exclamation point is an indirect reference to an eponymous key-level attribute -- so, for example, `from = !column_net` would mean that the key's `column_net` attribute is read there.
|
||||
|
||||
Another alternative to `anchor` here (here being under the `pcb` declaration) is to use the `between` key and place the footprint at the average of multiple anchors -- mostly useful for anchoring to the center, by averaging a key and its mirror.
|
||||
Additionally, the edge cut of the PCB can be specified using a previously defined outline name under the `edge` key.
|
||||
|
||||
```yaml
|
||||
|
@ -586,36 +590,44 @@ pcb:
|
|||
footprints:
|
||||
- type: <footprint type>
|
||||
anchor: <anchor declaration>
|
||||
between:
|
||||
- <anchor declaration>
|
||||
- ...
|
||||
params: <type-specific footprint params>
|
||||
nets: <type-specific net params>
|
||||
params: <type-specific (non-net) footprint params>
|
||||
- ...
|
||||
```
|
||||
|
||||
Currently, the following footprint types are supported:
|
||||
|
||||
- **`mx`**, **`alps`**, **`choc`**: mechanical switch footprints. Common parameters:
|
||||
- **`mx`**, **`alps`**, **`choc`**: mechanical switch footprints. Common nets:
|
||||
- `from`, `to`: nets to connect
|
||||
|
||||
- **`diode`**: a combined THT+SMD diode footprint. Parameters:
|
||||
- **`diode`**: a combined THT+SMD diode footprint. Nets:
|
||||
- `from`, `to`: nets to connect
|
||||
|
||||
- **`promicro`**: a controller to drive the keyboard. Available pins are `RAW`, `VCC`, `GND`, `RST`, and 18 GPIOs `P01` through `P18`. No parameters.
|
||||
- **`promicro`**: a controller to drive the keyboard. Available pins are `RAW`, `VCC`, `GND`, `RST`, and 18 GPIOs `P01` through `P18`. No Nets.
|
||||
|
||||
- **`slider`**: an SMD slider switch (part no. here), ideal for on/off operation. Parameters:
|
||||
- **`slider`**: an SMD slider switch (part no. here), ideal for on/off operation. Nets:
|
||||
- `from`, `to`: nets to connect
|
||||
|
||||
- **`button`**: an SMD button (part no. here), ideal for momentary toggles (like a reset switch). Parameters:
|
||||
- **`button`**: an SMD button (part no. here), ideal for momentary toggles (like a reset switch). Nets:
|
||||
- `from`, `to`: nets to connect
|
||||
|
||||
- **`rgb`**: an RGB led (part no. here), for per-key illumination, underglow, or feedback. Parameters:
|
||||
- **`rgb`**: an RGB led (part no. here), for per-key illumination, underglow, or feedback. Nets:
|
||||
- `din`, `dout`: input and output nets of the data line
|
||||
- VCC and GND nets are assumed to be called `VCC` and `GND`...
|
||||
|
||||
- **`jstph`**: a two-pin JST-PH battery header footprint. Parameters:
|
||||
- **`jstph`**: a two-pin JST-PH battery header footprint. Nets:
|
||||
- `pos`, `neg`: nets to connect to the positive and negative terminals, respectively.
|
||||
|
||||
- **`pin`**: a single pin.
|
||||
- Nets:
|
||||
- `net`: the net it should connect to
|
||||
- Parameters:
|
||||
- `diameter`: the larger diameter of the hole, including the copper ring
|
||||
- `drill`: the smaller diameter of the actual hole
|
||||
|
||||
- **`hole`**: a simple circular hole. Parameters:
|
||||
- `diameter`: the diameter of the (non-plated!) hole
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -52,17 +52,38 @@ exports.trbl = (raw, name) => {
|
|||
|
||||
exports.anchor = (raw, name, points={}, check_unexpected=true, default_point=new Point()) => {
|
||||
if (check_unexpected) detect_unexpected(raw, name, ['ref', 'shift', 'rotate'])
|
||||
let a = default_point.clone()
|
||||
let point = default_point.clone()
|
||||
if (raw.ref !== undefined) {
|
||||
if (type(raw.ref) == 'array') {
|
||||
// averaging multiple anchors
|
||||
let x = 0, y = 0, r = 0
|
||||
const len = raw.ref.length
|
||||
for (const ref of raw.ref) {
|
||||
assert(points[ref], `Unknown point reference "${ref}" in anchor "${name}"!`)
|
||||
const resolved = points[ref]
|
||||
x += resolved.x
|
||||
y += resolved.y
|
||||
r += resolved.r
|
||||
}
|
||||
point = new Point(x / len, y / len, r / len)
|
||||
} else {
|
||||
assert(points[raw.ref], `Unknown point reference "${raw.ref}" in anchor "${name}"!`)
|
||||
a = points[raw.ref].clone()
|
||||
point = points[raw.ref].clone()
|
||||
}
|
||||
}
|
||||
if (raw.shift !== undefined) {
|
||||
let xyval = wh(raw.shift || [0, 0], name + '.shift')
|
||||
a.shift(xyval, true)
|
||||
if (point.meta.mirrored) {
|
||||
xyval[0] = -xyval[0]
|
||||
}
|
||||
point.shift(xyval, true)
|
||||
}
|
||||
if (raw.rotate !== undefined) {
|
||||
a.r += sane(raw.rotate || 0, name + '.rotate', 'number')
|
||||
let rot = sane(raw.rotate || 0, name + '.rotate', 'number')
|
||||
if (point.meta.mirrored) {
|
||||
rot = -rot
|
||||
}
|
||||
return a
|
||||
point.r += rot
|
||||
}
|
||||
return point
|
||||
}
|
43
src/footprints/diode.js
Normal file
43
src/footprints/diode.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
module.exports = {
|
||||
nets: ['from', 'to'],
|
||||
body: `
|
||||
|
||||
(module ComboDiode (layer F.Cu) (tedit 5B24D78E)
|
||||
|
||||
|
||||
${''/* parametric position */}
|
||||
__AT
|
||||
|
||||
${''/* diode symbols */}
|
||||
(fp_line (start 0.25 0) (end 0.75 0) (layer F.SilkS) (width 0.1))
|
||||
(fp_line (start 0.25 0.4) (end -0.35 0) (layer F.SilkS) (width 0.1))
|
||||
(fp_line (start 0.25 -0.4) (end 0.25 0.4) (layer F.SilkS) (width 0.1))
|
||||
(fp_line (start -0.35 0) (end 0.25 -0.4) (layer F.SilkS) (width 0.1))
|
||||
(fp_line (start -0.35 0) (end -0.35 0.55) (layer F.SilkS) (width 0.1))
|
||||
(fp_line (start -0.35 0) (end -0.35 -0.55) (layer F.SilkS) (width 0.1))
|
||||
(fp_line (start -0.75 0) (end -0.35 0) (layer F.SilkS) (width 0.1))
|
||||
(fp_line (start 0.25 0) (end 0.75 0) (layer B.SilkS) (width 0.1))
|
||||
(fp_line (start 0.25 0.4) (end -0.35 0) (layer B.SilkS) (width 0.1))
|
||||
(fp_line (start 0.25 -0.4) (end 0.25 0.4) (layer B.SilkS) (width 0.1))
|
||||
(fp_line (start -0.35 0) (end 0.25 -0.4) (layer B.SilkS) (width 0.1))
|
||||
(fp_line (start -0.35 0) (end -0.35 0.55) (layer B.SilkS) (width 0.1))
|
||||
(fp_line (start -0.35 0) (end -0.35 -0.55) (layer B.SilkS) (width 0.1))
|
||||
(fp_line (start -0.75 0) (end -0.35 0) (layer B.SilkS) (width 0.1))
|
||||
|
||||
${''/* extra direction bars */}
|
||||
(fp_line (start -2.5 -0.9) (end -2.5 0.9) (layer F.SilkS) (width 0.12))
|
||||
(fp_line (start -2.5 -0.9) (end -2.5 0.9) (layer B.SilkS) (width 0.12))
|
||||
|
||||
${''/* SMD pads on both sides */}
|
||||
(pad 1 smd rect (at -1.65 0 __ROT(0)) (size 0.9 1.2) (layers F.Cu F.Paste F.Mask) __NET_TO)
|
||||
(pad 2 smd rect (at 1.65 0 __ROT(0)) (size 0.9 1.2) (layers B.Cu B.Paste B.Mask) __NET_FROM)
|
||||
(pad 1 smd rect (at -1.65 0 __ROT(0)) (size 0.9 1.2) (layers B.Cu B.Paste B.Mask) __NET_TO)
|
||||
(pad 2 smd rect (at 1.65 0 __ROT(0)) (size 0.9 1.2) (layers F.Cu F.Paste F.Mask) __NET_FROM)
|
||||
|
||||
${''/* THT terminals */}
|
||||
(pad 1 thru_hole rect (at -3.81 0 __ROT(0)) (size 1.778 1.778) (drill 0.9906) (layers *.Cu *.Mask) __NET_TO)
|
||||
(pad 2 thru_hole circle (at 3.81 0 __ROT(0)) (size 1.905 1.905) (drill 0.9906) (layers *.Cu *.Mask) __NET_FROM)
|
||||
)
|
||||
|
||||
`
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
module.exports = {
|
||||
mx: require('./mx'),
|
||||
diode: require('./diode'),
|
||||
promicro: require('./promicro')
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
module.exports = {
|
||||
params: ['from', 'to'],
|
||||
nets: ['from', 'to'],
|
||||
body: `
|
||||
|
||||
(module MX (layer F.Cu) (tedit 5DD4F656)
|
||||
|
@ -18,8 +18,8 @@ module.exports = {
|
|||
(fp_line (start 7 -7) (end 7 -6) (layer F.SilkS) (width 0.15))
|
||||
|
||||
${''/* pins */}
|
||||
(pad 1 thru_hole circle (at 2.54 -5.08) (size 2.286 2.286) (drill 1.4986) (layers *.Cu *.Mask) __PARAM_FROM)
|
||||
(pad 2 thru_hole circle (at -3.81 -2.54) (size 2.286 2.286) (drill 1.4986) (layers *.Cu *.Mask) __PARAM_TO)
|
||||
(pad 1 thru_hole circle (at 2.54 -5.08) (size 2.286 2.286) (drill 1.4986) (layers *.Cu *.Mask) __NET_FROM)
|
||||
(pad 2 thru_hole circle (at -3.81 -2.54) (size 2.286 2.286) (drill 1.4986) (layers *.Cu *.Mask) __NET_TO)
|
||||
|
||||
${''/* middle shaft */}
|
||||
(pad "" np_thru_hole circle (at 0 0) (size 3.9878 3.9878) (drill 3.9878) (layers *.Cu *.Mask))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
module.exports = {
|
||||
nets: [
|
||||
static_nets: [
|
||||
'RAW', 'GND', 'RST', 'VCC',
|
||||
'P21', 'P20', 'P19', 'P18',
|
||||
'P15', 'P14', 'P16', 'P10',
|
||||
|
@ -31,34 +31,34 @@ module.exports = {
|
|||
(fp_line (start -12.7 6.35) (end -12.7 8.89) (layer F.SilkS) (width 0.381))
|
||||
|
||||
${''/* pin names */}
|
||||
(fp_text user RAW (at -13.97 5.0) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user GND (at -11.43 5.0) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user RST (at -8.89 5.0) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user VCC (at -6.35 5.0) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 21 (at -3.81 5.461) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 20 (at -1.27 5.461) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 19 (at 1.27 5.461) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 18 (at 3.81 5.461) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 15 (at 6.35 5.461) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 14 (at 8.89 5.461) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 16 (at 11.43 5.461) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 10 (at 13.97 5.461) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user RAW (at -13.97 5.0 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user GND (at -11.43 5.0 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user RST (at -8.89 5.0 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user VCC (at -6.35 5.0 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 21 (at -3.81 5.461 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 20 (at -1.27 5.461 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 19 (at 1.27 5.461 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 18 (at 3.81 5.461 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 15 (at 6.35 5.461 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 14 (at 8.89 5.461 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 16 (at 11.43 5.461 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 10 (at 13.97 5.461 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
|
||||
(fp_text user 1 (at -13.97 -5.461) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 0 (at -11.43 -5.461) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user GND (at -8.89 -5.0) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user GND (at -6.35 -5.0) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 2 (at -3.81 -5.461) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 3 (at -1.27 -5.461) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 4 (at 1.27 -5.461) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 5 (at 3.81 -5.461) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 6 (at 6.35 -5.461) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 7 (at 8.89 -5.461) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 8 (at 11.43 -5.461) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 9 (at 13.97 -5.461) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 1 (at -13.97 -5.461 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 0 (at -11.43 -5.461 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user GND (at -8.89 -5.0 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user GND (at -6.35 -5.0 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 2 (at -3.81 -5.461 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 3 (at -1.27 -5.461 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 4 (at 1.27 -5.461 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 5 (at 3.81 -5.461 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 6 (at 6.35 -5.461 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 7 (at 8.89 -5.461 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 8 (at 11.43 -5.461 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
(fp_text user 9 (at 13.97 -5.461 __ROT(90)) (layer F.SilkS) (effects (font (size 0.8 0.8) (thickness 0.15))))
|
||||
|
||||
${''/* and now the actual pins */}
|
||||
(pad 1 thru_hole rect (at -13.97 7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) __NET_RAW)
|
||||
(pad 1 thru_hole rect (at -13.97 7.62 __ROT(0)) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) __NET_RAW)
|
||||
(pad 2 thru_hole circle (at -11.43 7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) __NET_GND)
|
||||
(pad 3 thru_hole circle (at -8.89 7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) __NET_RST)
|
||||
(pad 4 thru_hole circle (at -6.35 7.62 0) (size 1.7526 1.7526) (drill 1.0922) (layers *.Cu *.SilkS *.Mask) __NET_VCC)
|
||||
|
|
86
src/pcb.js
86
src/pcb.js
|
@ -116,7 +116,7 @@ const kicad_netclass = `
|
|||
|
||||
const makerjs2kicad = exports._makerjs2kicad = (model, layer='Edge.Cuts') => {
|
||||
const grs = []
|
||||
const xy = val => `${val[0]} ${val[1]}`
|
||||
const xy = val => `${val[0]} ${-val[1]}`
|
||||
m.model.walk(model, {
|
||||
onPath: wp => {
|
||||
const p = wp.pathContext
|
||||
|
@ -129,7 +129,7 @@ const makerjs2kicad = exports._makerjs2kicad = (model, layer='Edge.Cuts') => {
|
|||
const angle_start = p.startAngle > p.endAngle ? p.startAngle - 360 : p.startAngle
|
||||
const angle_diff = Math.abs(p.endAngle - angle_start)
|
||||
const end = m.point.rotate(m.point.add(center, [p.radius, 0]), angle_start, center)
|
||||
grs.push(`(gr_arc (start ${xy(center)}) (end ${xy(end)}) (angle ${angle_diff}) (layer ${layer}) (width 0.15))`)
|
||||
grs.push(`(gr_arc (start ${xy(center)}) (end ${xy(end)}) (angle ${-angle_diff}) (layer ${layer}) (width 0.15))`)
|
||||
break
|
||||
case 'circle':
|
||||
break
|
||||
|
@ -138,52 +138,63 @@ const makerjs2kicad = exports._makerjs2kicad = (model, layer='Edge.Cuts') => {
|
|||
}
|
||||
}
|
||||
})
|
||||
return grs
|
||||
return grs.join('\n')
|
||||
}
|
||||
|
||||
const footprint_types = require('./footprints')
|
||||
const footprint = exports._footprint = (config, name, points, net_indexer, default_anchor) => {
|
||||
const footprint = exports._footprint = (config, name, points, net_indexer, point) => {
|
||||
|
||||
// config sanitization
|
||||
a.detect_unexpected(config, name, ['type', 'anchor', 'between', 'params'])
|
||||
a.detect_unexpected(config, name, ['type', 'anchor', 'nets', 'params'])
|
||||
const type = a.in(config.type, `${name}.type`, Object.keys(footprint_types))
|
||||
let anchor = a.anchor(config.anchor, `${name}.anchor`, points, true, default_anchor)
|
||||
const params = a.sane(config.params, `${name}.params`, 'object')
|
||||
|
||||
// averaging multiple anchors, if necessary
|
||||
if (config.between) {
|
||||
const between = a.sane(config.between, `${name}.between`, 'array')
|
||||
let x = 0, y = 0, r = 0, bi = 0
|
||||
const len = between.length
|
||||
for (const b of between) {
|
||||
ba = a.anchor(b, `${name}.between[${++bi}]`, points, true)
|
||||
x += ba.x
|
||||
y += ba.y
|
||||
r += ba.r
|
||||
}
|
||||
anchor = new Point(x / len, y / len, r / len)
|
||||
}
|
||||
let anchor = a.anchor(config.anchor || {}, `${name}.anchor`, points, true, point)
|
||||
const nets = a.sane(config.nets || {}, `${name}.nets`, 'object')
|
||||
const params = a.sane(config.params || {}, `${name}.params`, 'object')
|
||||
|
||||
// basic setup
|
||||
const fp = footprint_types[type]
|
||||
let result = fp.body
|
||||
|
||||
// footprint positioning
|
||||
const at = `(at ${anchor.x} ${anchor.y} ${anchor.r})`
|
||||
result = result.replace('__AT', at)
|
||||
const at = `(at ${anchor.x} ${-anchor.y} ${anchor.r})`
|
||||
result = result.replace(new RegExp('__AT', 'g'), at)
|
||||
// fix rotations within footprints
|
||||
const rot_regex = /__ROT\((\d+)\)/g
|
||||
const matches = [...result.matchAll(rot_regex)]
|
||||
for (const match of matches) {
|
||||
const angle = parseFloat(match[1])
|
||||
result = result.replace(match[0], (anchor.r + angle) + '')
|
||||
}
|
||||
|
||||
// connecting static nets
|
||||
for (const net of (fp.nets || [])) {
|
||||
for (const net of (fp.static_nets || [])) {
|
||||
const index = net_indexer(net)
|
||||
result = result.replace('__NET_' + net.toUpperCase(), `(net ${index} "${net}")`)
|
||||
result = result.replace(new RegExp('__NET_' + net.toUpperCase(), 'g'), `(net ${index} "${net}")`)
|
||||
}
|
||||
|
||||
// connecting parametric nets
|
||||
for (const param of (fp.params || [])) {
|
||||
const net = params[param]
|
||||
a.sane(net, `${name}.params.${param}`, 'string')
|
||||
for (const net_ref of (fp.nets || [])) {
|
||||
let net = nets[net_ref]
|
||||
a.sane(net, `${name}.nets.${net_ref}`, 'string')
|
||||
if (net.startsWith('!') && point) {
|
||||
const indirect = net.substring(1)
|
||||
net = point.meta[indirect]
|
||||
a.sane(net, `${name}.nets.${net_ref} --> ${point.meta.name}.${indirect}`, 'string')
|
||||
}
|
||||
const index = net_indexer(net)
|
||||
result = result.replace('__PARAM_' + net.toUpperCase(), `(net ${index} "${net}")`)
|
||||
result = result.replace(new RegExp('__NET_' + net_ref.toUpperCase(), 'g'), `(net ${index} "${net}")`)
|
||||
}
|
||||
|
||||
// connecting other, non-net parameters
|
||||
for (const param of (fp.params || [])) {
|
||||
let value = params[param]
|
||||
if (value === undefined) throw new Error(`Field "${name}.params.${param}" is missing!`)
|
||||
if (a.type(value) == 'string' && value.startsWith('!') && point) {
|
||||
const indirect = value.substring(1)
|
||||
value = point.meta[indirect]
|
||||
if (value === undefined) throw new Error(`Field "${name}.params.${param} --> ${point.meta.name}.${indirect}" is missing!`)
|
||||
}
|
||||
result = result.replace(new RegExp('__PARAM_' + param.toUpperCase(), 'g'), value)
|
||||
}
|
||||
|
||||
return result
|
||||
|
@ -200,9 +211,9 @@ exports.parse = (config, points, outlines) => {
|
|||
const kicad_edge = makerjs2kicad(edge)
|
||||
|
||||
// making a global net index registry
|
||||
const nets = {}
|
||||
const nets = {"": 0}
|
||||
const net_indexer = net => {
|
||||
if (nets[net]) return nets[net]
|
||||
if (nets[net] !== undefined) return nets[net]
|
||||
const index = Object.keys(nets).length
|
||||
return nets[net] = index
|
||||
}
|
||||
|
@ -211,17 +222,15 @@ exports.parse = (config, points, outlines) => {
|
|||
|
||||
// key-level footprints
|
||||
for (const [pname, point] of Object.entries(points)) {
|
||||
let f_index = 0
|
||||
for (const f of (point.meta.footprints || [])) {
|
||||
footprints.push(footprint(f, `${pname}.footprints[${++f_index}]`, points, net_indexer, point))
|
||||
for (const [f_name, f] of Object.entries(point.meta.footprints || {})) {
|
||||
footprints.push(footprint(f, `${pname}.footprints.${f_name}`, points, net_indexer, point))
|
||||
}
|
||||
}
|
||||
|
||||
// global one-off footprints
|
||||
const global_footprints = a.sane(config.footprints || [], 'pcb.footprints', 'array')
|
||||
let gf_index = 0
|
||||
for (const gf of global_footprints) {
|
||||
footprints.push(footprint(gf, `pcb.footprints[${++gf_index}]`, points, net_indexer))
|
||||
const global_footprints = a.sane(config.footprints || {}, 'pcb.footprints', 'object')
|
||||
for (const [gf_name, gf] of Object.entries(global_footprints)) {
|
||||
footprints.push(footprint(gf, `pcb.footprints.${gf_name}`, points, net_indexer))
|
||||
}
|
||||
|
||||
// finalizing nets
|
||||
|
@ -241,6 +250,7 @@ exports.parse = (config, points, outlines) => {
|
|||
${nets_text}
|
||||
${netclass}
|
||||
${footprint_text}
|
||||
${kicad_edge}
|
||||
${kicad_suffix}
|
||||
|
||||
`
|
||||
|
|
|
@ -238,8 +238,8 @@ exports.parse = (config = {}) => {
|
|||
for (const [name, p] of Object.entries(points)) {
|
||||
if (p.meta.asym == 'left') continue
|
||||
const mp = p.clone().mirror(axis)
|
||||
mp.meta = extend(mp.meta, mp.meta.mirror || {})
|
||||
mp.meta.mirrored = true
|
||||
delete mp.meta.asym
|
||||
mirrored_points[`mirror_${name}`] = mp
|
||||
if (p.meta.asym == 'right') {
|
||||
p.meta.skip = true
|
||||
|
|
68
test/fixtures/absolem.yaml
vendored
68
test/fixtures/absolem.yaml
vendored
|
@ -13,6 +13,8 @@ points:
|
|||
bind: [,10]
|
||||
top:
|
||||
bind: [,10]
|
||||
key:
|
||||
column_net: P1
|
||||
ring:
|
||||
stagger: 12
|
||||
rows:
|
||||
|
@ -22,6 +24,8 @@ points:
|
|||
bind: [,10]
|
||||
top:
|
||||
bind: [,10]
|
||||
key:
|
||||
column_net: P0
|
||||
middle:
|
||||
stagger: 5
|
||||
rows:
|
||||
|
@ -30,6 +34,8 @@ points:
|
|||
home:
|
||||
bind: [,10,,10]
|
||||
top:
|
||||
key:
|
||||
column_net: P2
|
||||
index:
|
||||
stagger: -6
|
||||
rows:
|
||||
|
@ -39,6 +45,8 @@ points:
|
|||
bind: [,,,10]
|
||||
top:
|
||||
bind: [,,,10]
|
||||
key:
|
||||
column_net: P3
|
||||
inner:
|
||||
stagger: -2
|
||||
rows:
|
||||
|
@ -48,16 +56,23 @@ points:
|
|||
bind: [,,,10]
|
||||
top:
|
||||
bind: [,,,10]
|
||||
key:
|
||||
column_net: P4
|
||||
rows:
|
||||
bottom:
|
||||
bind: [10]
|
||||
row_net: P7
|
||||
mirror:
|
||||
row_net: P16
|
||||
home:
|
||||
bind: [10]
|
||||
row_net: P6
|
||||
mirror:
|
||||
row_net: P14
|
||||
top:
|
||||
key:
|
||||
footprints:
|
||||
- type: mx
|
||||
|
||||
row_net: P5
|
||||
mirror:
|
||||
row_net: P15
|
||||
thumbfan:
|
||||
anchor:
|
||||
ref: inner_bottom
|
||||
|
@ -70,6 +85,8 @@ points:
|
|||
rows:
|
||||
thumb:
|
||||
bind: [10,1,,]
|
||||
key:
|
||||
column_net: P2
|
||||
home:
|
||||
spread: 21.25
|
||||
rotate: -28
|
||||
|
@ -77,12 +94,35 @@ points:
|
|||
rows:
|
||||
thumb:
|
||||
bind: [,10,,15]
|
||||
key:
|
||||
column_net: P3
|
||||
far:
|
||||
rows:
|
||||
thumb:
|
||||
bind: [-1,,,5]
|
||||
key:
|
||||
bind: [0, 0, 0, 0]
|
||||
column_net: P4
|
||||
rows:
|
||||
thumb:
|
||||
row_net: P8
|
||||
mirror:
|
||||
row_net: P10
|
||||
key:
|
||||
bind: [0,0,0,0]
|
||||
footprints:
|
||||
mx:
|
||||
type: mx
|
||||
nets:
|
||||
from: '!column_net'
|
||||
to: '!name'
|
||||
diode:
|
||||
type: diode
|
||||
anchor:
|
||||
rotate: 90
|
||||
shift: [-8, 0]
|
||||
nets:
|
||||
from: '!name'
|
||||
to: '!row_net'
|
||||
rotate: -20
|
||||
mirror:
|
||||
ref: pinky_home
|
||||
|
@ -103,7 +143,7 @@ outline:
|
|||
rotate: 90
|
||||
right:
|
||||
ref: mirror_far_thumb
|
||||
shift: [-0.5, 0]
|
||||
shift: [0.5, 0]
|
||||
rotate: 90
|
||||
waypoints:
|
||||
- percent: 50
|
||||
|
@ -134,11 +174,11 @@ outline:
|
|||
- type: rectangle
|
||||
size: [25, 5]
|
||||
ref: far_thumb
|
||||
shift: [-25, 12]
|
||||
shift: [25, 12]
|
||||
- type: rectangle
|
||||
size: [25, 5]
|
||||
ref: mirror_home_thumb
|
||||
shift: [-25, 12]
|
||||
shift: [25, 12]
|
||||
- type: rectangle
|
||||
size: [25, 5]
|
||||
ref: mirror_far_thumb
|
||||
|
@ -158,7 +198,11 @@ outline:
|
|||
pcb:
|
||||
edge: outline
|
||||
footprints:
|
||||
- type: promicro
|
||||
between:
|
||||
- ref: inner_top
|
||||
- ref: mirror_inner_top
|
||||
mcu:
|
||||
type: promicro
|
||||
anchor:
|
||||
ref:
|
||||
- inner_top
|
||||
- mirror_inner_top
|
||||
shift: [0, -20]
|
||||
rotate: 270
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue