1
0

More PCB progress

This commit is contained in:
Bán Dénes 2020-07-14 23:03:44 +02:00
parent 05a33d00ec
commit 55d60ba599
9 changed files with 231 additions and 100 deletions

View File

@ -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

View File

@ -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) {
assert(points[raw.ref], `Unknown point reference "${raw.ref}" in anchor "${name}"!`)
a = points[raw.ref].clone()
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}"!`)
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
}
point.r += rot
}
return a
return point
}

43
src/footprints/diode.js Normal file
View 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)
)
`
}

View File

@ -1,4 +1,5 @@
module.exports = {
mx: require('./mx'),
diode: require('./diode'),
promicro: require('./promicro')
}

View File

@ -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))

View File

@ -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)

View File

@ -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}
`

View File

@ -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

View File

@ -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:
column_net: P4
rows:
thumb:
row_net: P8
mirror:
row_net: P10
key:
bind: [0, 0, 0, 0]
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