diff --git a/README.md b/README.md index 8c7475d..e588c2a 100644 --- a/README.md +++ b/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: ``` `name` is the unique identifier of this specific key. @@ -192,7 +194,7 @@ It defaults to a `_` 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.
@@ -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: anchor: - between: - - - - ... - params: + nets: + 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 + diff --git a/src/assert.js b/src/assert.js index cf064c6..111e0ba 100644 --- a/src/assert.js +++ b/src/assert.js @@ -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 } \ No newline at end of file diff --git a/src/footprints/diode.js b/src/footprints/diode.js new file mode 100644 index 0000000..7711e4c --- /dev/null +++ b/src/footprints/diode.js @@ -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) + ) + + ` + } \ No newline at end of file diff --git a/src/footprints/index.js b/src/footprints/index.js index 0874e71..8e74e60 100644 --- a/src/footprints/index.js +++ b/src/footprints/index.js @@ -1,4 +1,5 @@ module.exports = { mx: require('./mx'), + diode: require('./diode'), promicro: require('./promicro') } \ No newline at end of file diff --git a/src/footprints/mx.js b/src/footprints/mx.js index 6b0a7a8..7b5814b 100644 --- a/src/footprints/mx.js +++ b/src/footprints/mx.js @@ -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)) diff --git a/src/footprints/promicro.js b/src/footprints/promicro.js index 51f70fe..6731656 100644 --- a/src/footprints/promicro.js +++ b/src/footprints/promicro.js @@ -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) diff --git a/src/pcb.js b/src/pcb.js index 4f8da57..711aa79 100644 --- a/src/pcb.js +++ b/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} ` diff --git a/src/points.js b/src/points.js index ff0b180..69b7e4e 100644 --- a/src/points.js +++ b/src/points.js @@ -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 diff --git a/test/fixtures/absolem.yaml b/test/fixtures/absolem.yaml index 8282f5a..430c429 100644 --- a/test/fixtures/absolem.yaml +++ b/test/fixtures/absolem.yaml @@ -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