diff --git a/README.md b/README.md index ebb2e60..c3c8900 100644 --- a/README.md +++ b/README.md @@ -570,3 +570,57 @@ If we only want to use an object as a building block for further objects, we can Everything should be ready for a handwire, but if you'd like the design to be more accessible and easily replicable, you probably want a PCB as well. To help you get started, the necessary footprints and an edge cut can be automatically positioned so that all you need to do manually is the routing. + +Footprints can be specified at the key-level (under the `points` section, like we discussed above), or here with manually given anchors. +The only difference between the two footprint types is that an omitted `ref` in the anchor means the current key for key-level declarations, while here it defaults to `[0, 0]`. +Additionally, the edge cut of the PCB can be specified using a previously defined outline name under the `edge` key. + +```yaml +pcb: + edge: + footprints: + - type: + anchor: + params: + - ... +``` + +Currently, the following footprint types are supported: + +- **`mx`**, **`alps`**, **`choc`**: mechanical switch footprints. Common parameters: + - `from`, `to`: nets to connect + +- **`diode`**: a combined THT+SMD diode footprint. Parameters: + - `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. + +- **`slider`**: an SMD slider switch (part no. here), ideal for on/off operation. Parameters: + - `from`, `to`: nets to connect + +- **`button`**: an SMD button (part no. here), ideal for momentary toggles (like a reset switch). Parameters: + - `from`, `to`: nets to connect + +- **`rgb`**: an RGB led (part no. here), for per-key illumination, underglow, or feedback. Parameters: + - `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: + - `pos`, `neg`: nets to connect to the positive and negative terminals, respectively. + + + + + + + + + + + + + + + +## A concrete PCB example + diff --git a/src/cli.js b/src/cli.js index 19e23ee..80af408 100644 --- a/src/cli.js +++ b/src/cli.js @@ -13,6 +13,7 @@ const u = require('./utils') const io = require('./io') const points_lib = require('./points') const outline_lib = require('./outline') +const pcb_lib = require('./pcb') // command line args @@ -67,6 +68,12 @@ for (const [name, outline] of Object.entries(outlines)) { io.dump_model(outline, path.join(args.o, `outline/${name}`), args.debug) } +// pcb + +console.log('Scaffolding PCB...') +const pcb = pcb_lib.parse(config.pcb, points, outlines) +fs.writeFileSync(path.join(args.o, `pcb/pcb.kicad_pcb`, pcb)) + // goodbye console.log('Done.') diff --git a/src/outline.js b/src/outline.js index f47fb36..cce3a3e 100644 --- a/src/outline.js +++ b/src/outline.js @@ -249,6 +249,8 @@ exports.parse = (config = {}, points = {}) => { result = op(result, arg) } + m.model.originate(result) + m.model.simplify(result) outlines[key] = result } diff --git a/src/pcb.js b/src/pcb.js new file mode 100644 index 0000000..7e4981b --- /dev/null +++ b/src/pcb.js @@ -0,0 +1,42 @@ +const m = require('makerjs') +const u = require('./utils') +const a = require('./assert') + +const makerjs2kicad = exports._makerjs2kicad = model => { + const grs = [] + const xy = val => `${val[0]} ${val[1]}` + m.model.walk(model, { + onPath: wp => { + const p = wp.pathContext + switch (p.type) { + case 'line': + grs.push(`(gr_line (start ${xy(p.origin)}) (end ${xy(p.end)}) (angle 90) (layer Edge.Cuts) (width 0.15))`) + break + case 'arc': + // console.log(require('util').inspect(p, false, 200)) + // throw 2 + const center = p.origin + const angle_start = Math.min(p.startAngle, p.endAngle) + const angle_diff = Math.abs(p.endAngle - p.startAngle) + 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 Edge.Cuts) (width 0.15))`) + break + case 'circle': + break + default: + throw new Error(`Can't convert path type "${p.type}" to kicad!`) + } + } + }) + return grs +} + +exports.parse = (config, points, outlines) => { + a.detect_unexpected(config, 'pcb', ['edge', 'footprints']) + const edge = outlines[config.edge] + if (!edge) throw new Error(`Field "pcb.edge" doesn't name a valid outline!`) + const kicad_edge = makerjs2kicad(edge) + + console.log(kicad_edge.join('\n')) + throw 28 +} \ No newline at end of file diff --git a/test/fixtures/absolem.yaml b/test/fixtures/absolem.yaml index c65e75d..af42ec8 100644 --- a/test/fixtures/absolem.yaml +++ b/test/fixtures/absolem.yaml @@ -150,4 +150,6 @@ outline: operation: stack - type: ref name: middle - operation: stack \ No newline at end of file + operation: stack +pcb: + edge: outline \ No newline at end of file