189 lines
6.1 KiB
Ruby
189 lines
6.1 KiB
Ruby
# encoding: utf-8
|
|
# ruby: 2.1.0
|
|
=begin
|
|
Rakefile to manage hardware projects
|
|
|
|
uses Lepton EDA for schematic and pcb-rnd for board layouts.
|
|
Rakefile instead of Makefile for better text file parsing capabilities.
|
|
=end
|
|
require 'rake/clean'
|
|
require 'csv' # to export BOM and costs
|
|
|
|
# =================
|
|
# project variables
|
|
# =================
|
|
|
|
# common name used for file names
|
|
name = "usb_cable_tester"
|
|
# local QEDA parts
|
|
parts_local = []
|
|
parts_local << "ic_mcu_st_stm32f103xc@LQFP144"
|
|
parts_local << "connector_usb-a-3.0_fci_10117835"
|
|
parts_local << "connector_usb-b-3.0_amphenol_gsb4211"
|
|
parts_local << "connector_usb-mini-b_edac_690-005-299-043"
|
|
parts_local << "connector_usb-micro-b-3.0_gct_usb3110"
|
|
parts_local << "connector_usb-micro-b-2.0_ali_32910334970"
|
|
parts_local << "connector_usb-c_hro_type-c-31-m-04"
|
|
parts_local << "connector_lightning_iphone5"
|
|
parts_local << "vreg_ldo_torex_xc6206"
|
|
parts_local << "connector_battery_18650"
|
|
parts_local << "display_lcd_lcm1602"
|
|
parts_local << "display_lcd_i2cadapter"
|
|
parts_local << "display_oled_0.96in"
|
|
parts_local << "vreg_pmic_tpower_tp4056"
|
|
parts_local << "transistor_pmos_nxp_bss84"
|
|
parts_local << "mechanical_button_6mm"
|
|
parts_local << "connector_XH-2.54-2P"
|
|
# the corresponding files
|
|
library = parts_local.collect {|part| "library/#{part.split('@')[0].downcase}.yaml"}
|
|
# github QEDA parts
|
|
parts_github = []
|
|
parts_github << "ecs/csm-7"
|
|
parts_github << "capacitor/c0603"
|
|
parts_github << "resistor/r0603"
|
|
parts_github << "diode/led0603"
|
|
# path to qeda"
|
|
qeda = "../qeda/bin/qeda"
|
|
# ==========
|
|
# main tasks
|
|
# ==========
|
|
|
|
desc "main building task"
|
|
task :default => [:print, :fabrication]
|
|
|
|
desc "print schematic and layout (as pdf)"
|
|
prints = [ "#{name}.sch.pdf", "#{name}.brd.ps", "#{name}.brd-top.png", "#{name}.brd-bottom.png" ]
|
|
task :print => prints
|
|
CLOBBER.include(prints)
|
|
|
|
desc "generate fabrication gerbers (as archive)"
|
|
gerbers = [ "#{name}.brd.asb", "#{name}.brd.ast", "#{name}.brd.gbl", "#{name}.brd.gbo", "#{name}.brd.gbp", "#{name}.brd.gbs", "#{name}.brd.gko", "#{name}.brd.gtl", "#{name}.brd.gto", "#{name}.brd.gtp", "#{name}.brd.gts", "#{name}.brd.xln" ]
|
|
fab = [ "#{name}.brd.zip" ]
|
|
task :fabrication => fab
|
|
CLEAN.include(gerbers)
|
|
CLOBBER.include(fab)
|
|
|
|
desc "generate footprints from parts"
|
|
task :library => library do
|
|
# reset
|
|
sh "#{qeda} reset"
|
|
# configure
|
|
sh "#{qeda} config pattern.preferManufacturer false"
|
|
sh "#{qeda} config pattern.densityLevel M"
|
|
sh "#{qeda} config pattern.smoothPadCorners true"
|
|
# add local files
|
|
parts_local.each do |part|
|
|
sh "#{qeda} add #{part}"
|
|
end
|
|
# from github library
|
|
parts_github.each do |part|
|
|
sh "#{qeda} add #{part}"
|
|
end
|
|
# generate outputs
|
|
sh "#{qeda} config output geda"
|
|
sh "#{qeda} generate ."
|
|
sh "#{qeda} config output coraleda"
|
|
sh "#{qeda} generate ."
|
|
end
|
|
|
|
desc "export netlist from schematic"
|
|
net = [ "#{name}.tdx" ]
|
|
task :netlist => net
|
|
CLOBBER.include(net)
|
|
|
|
desc "export notes from schematic"
|
|
notes = [ "#{name}.notes.txt" ]
|
|
task :notes => notes
|
|
CLOBBER.include(notes)
|
|
|
|
# ===============
|
|
# file generation
|
|
# ===============
|
|
|
|
desc "generate printable version (PDF) of schematic"
|
|
rule ".sch.pdf" => ".standalone.sch" do |t|
|
|
sh "lepton-cli export --color --paper iso_a4 --layout landscape --color --output #{t.name} #{t.source} 2> /dev/null"
|
|
end
|
|
|
|
desc "generate printable version (PostScript) of board layout"
|
|
rule ".brd.ps" => ".lht" do |t|
|
|
sh "pcb-rnd -x ps --psfile #{t.name} #{t.source} 2> /dev/null"
|
|
end
|
|
|
|
desc "generate photo realistic picture from layout (top side)"
|
|
rule ".brd-top.png" => ".lht" do |t|
|
|
sh "pcb-rnd -x png --dpi 1200 --photo-mode --outfile #{t.name} #{t.source} 2> /dev/null"
|
|
end
|
|
|
|
desc "generate photo realistic picture from layout (bottom side)"
|
|
rule ".brd-bottom.png" => ".lht" do |t|
|
|
sh "pcb-rnd -x png --dpi 1200 --photo-mode --photo-flip-y --outfile #{t.name} #{t.source} 2> /dev/null"
|
|
end
|
|
|
|
desc "generate schematic with all symbols embedded"
|
|
rule ".standalone.sch" => ".sch" do |t|
|
|
sh "cp #{t.source} #{t.name}"
|
|
sh "lepton-embed --embed #{t.name} 2> /dev/null"
|
|
end
|
|
|
|
desc "archive gerbers"
|
|
rule ".brd.zip" => ".lht" do |t|
|
|
base = File.basename(t.source, ".lht")
|
|
sh "pcb-rnd -x cam gerber:JLC_PCB --outfile #{base}.brd #{t.source} 2> /dev/null"
|
|
gerbers = [ "#{base}.brd.asb", "#{base}.brd.ast", "#{base}.brd.gbl", "#{base}.brd.gbo", "#{base}.brd.gbp", "#{base}.brd.gbs", "#{base}.brd.gko", "#{base}.brd.gtl", "#{base}.brd.gto", "#{base}.brd.gtp", "#{base}.brd.gts", "#{base}.brd.xln" ]
|
|
fab = [ "#{name}.brd.zip" ]
|
|
sh "zip --quiet #{t.name} #{gerbers.join(' ')}"
|
|
end
|
|
|
|
desc "export netlist from schematic"
|
|
rule ".tdx" => ".sch" do |t|
|
|
sh "lepton-netlist -g tEDAx -o #{t.name} #{t.source} 2> /dev/null"
|
|
end
|
|
|
|
desc "generate note file from schematic, listing the 'note' attributes from elements"
|
|
rule ".notes.txt" => ".sch" do |t|
|
|
notes_data = bom2(t.prerequisites[0], ["note", "value"])
|
|
File.open(t.name,"w") do |notes_file|
|
|
notes_data.each do |note|
|
|
next unless note['note']
|
|
note['note'] = note['note'].gsub('. ',".\n").gsub(/\n+$/,'')
|
|
notes_file.puts "#{note['value']} (#{note['refdes']}):\n#{note['note']}\n\n"
|
|
end
|
|
end
|
|
end
|
|
|
|
# ================
|
|
# helper functions
|
|
# ================
|
|
|
|
# generate gnetlist bom2 and parse them
|
|
# arguments: schematic=schematic to use, attributes=attributes to use for generating bom2
|
|
# returns an array of hash. key is the attribute name, value is the attribute value
|
|
def bom2(schematic, attributes)
|
|
to_return = []
|
|
# force attributes to be an array
|
|
attributes = case attributes
|
|
when String
|
|
[attributes]
|
|
when Array
|
|
attributes
|
|
else
|
|
[attributes.to_s]
|
|
end
|
|
# generate bom2
|
|
list = `lepton-netlist --backend bom2 --backend-option attribs=#{attributes*','} --quiet --output - #{schematic} 2> /dev/null`
|
|
list.gsub!(/(\d[Mkmµ]?)\?/, '\1Ω') # UTF-8 characters like Ω are replaced with ? by gnetlist
|
|
list.gsub!(/(https?:\/\/[^:]*):/, '"\1":') # ':' (like in links) are not protected
|
|
# parse bom2
|
|
csv = CSV.parse(list,{:col_sep => ":"})
|
|
csv[1..-1].each do |row|
|
|
line = {}
|
|
row.each_index do |col|
|
|
line[csv[0][col]] = row[col] unless row[col] == "unknown"
|
|
end
|
|
to_return << line
|
|
end
|
|
return to_return
|
|
end
|
|
|