diff --git a/.gitignore b/.gitignore index bc78b01..055967e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,36 +1,34 @@ +# schematic lepton-EDA +*.sch + +# board layout pcb-rnd +*.lht *.lht.* -*.versioned.lht + +# KiCAD +*.kicad_prl +*.kicad_pro-bak +*.xml +fp-info-cache + +# temporary files *~ -*.versioned.sch +\#*\# + +# outputs *.svg +*.png *.pdf *.ps *.zip -*.brd.* -*.ast -*.g2l -*.g3l -*.gbl -*.gbo -*.gbp -*.gbs -*.gko -*.gtl -*.gto -*.gtp -*.gts -*.xln -*.tdx -\#*\# -*.notes.txt *.bom.csv -*.cost.csv *.cpl.csv +*.versioned.* +fabrication + +# scripts and utilities *.json *.rb -geda/footprints/ -*.kicad_prl -*.xml -fp-info-cache -fabrication +# panel files +panel.* diff --git a/JLCPCB_CORRECTION.csv b/JLCPCB_CORRECTION.csv new file mode 100644 index 0000000..05687b9 --- /dev/null +++ b/JLCPCB_CORRECTION.csv @@ -0,0 +1,4 @@ +package,x,y,rot +LEDC2012X80N,0,0,-90 +UC1608X55N,0,0,90 +SOT95P237X112-3N,0,0,180 diff --git a/Rakefile b/Rakefile index ea7f530..9660e52 100644 --- a/Rakefile +++ b/Rakefile @@ -3,7 +3,13 @@ =begin Rakefile to manage hardware projects -uses Lepton EDA for schematic and pcb-rnd for board layouts. +uses following tools: +- QEDA https://github.com/qeda/qeda +- PcbDraw https://github.com/yaqwsx/PcbDraw +- KiKit https://github.com/yaqwsx/KiKit +- KiAuto https://github.com/INTI-CMNB/KiAuto +- KiBoM https://github.com/SchrodingersGat/KiBoM + Rakefile instead of Makefile for better text file parsing capabilities. =end require 'rake/clean' @@ -14,39 +20,39 @@ require 'csv' # to export BOM and costs # ================= # common name used for file names -name = "template" +name = ENV["NAME"] || "template" # project version, read from "version" file raise "define project version in 'version' file" unless File.exist? "version" version = IO.read("version").split("\n")[0] # current date for stamping output date = Time.now.strftime("%Y-%m-%d") # revision based on number of changes on schematic or board layout and current git commit -changes = `git log --pretty=oneline "#{name}.sch" "#{name}.lht" | wc -l`.chomp.to_i +changes = `git log --pretty=oneline "#{name}.kicad_sch" "#{name}.kicad_pcb" | wc -l`.chomp.to_i commit = `git rev-parse --short HEAD`.chomp -revision = "#{changes} (#{commit})" +revision = "#{changes} #{commit}" # path to qeda" -qeda = "qeda" +qeda = "~/tmp/qeda/bin/qeda" # ========== # main tasks # ========== desc "main building task" -task :default => [:print, :fabrication, :bom, :pnp] +task :default => [:print, :fabrication, :bom] desc "print schematic and layout (as pdf)" -prints = [ "#{name}.sch.pdf", "#{name}.brd.pdf", "#{name}.brd-top.svg", "#{name}.brd-bottom.svg" ] +prints = [ "#{name}.sch.pdf", "#{name}.brd-top.png", "#{name}.brd-bot.png" ] task :print => prints -CLEAN.include([ "#{name}.versioned.sch", "#{name}.versioned.lht" ]) +CLEAN.include([ "#{name}.versioned.kicad_sch", "#{name}.versioned.kicad_pcb" ]) 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", "#{name}.brd.g2l", "#{name}.brd.g3l" ] -fab = [ "#{name}.brd.zip" ] -task :fabrication => fab -CLEAN.include(gerbers) -CLOBBER.include(fab) +desc "generate fabrication files (gerbers/drill/BoM/PnP)" +FABRICATION_DIR = "fabrication" +task :fabrication => [ "#{name}.versioned.kicad_sch", "#{name}.versioned.kicad_pcb" ] do |t| + sh "kikit fab jlcpcb --drc --assembly --missingError --schematic #{t.prerequisites[0]} #{t.prerequisites[1]} #{FABRICATION_DIR}" +end +CLEAN.include(FABRICATION_DIR) desc "generate symbols and footprints from parts" task :library do @@ -54,126 +60,49 @@ task :library do sh "#{qeda} generate mylib" end -desc "export BOMs from schematic" +desc "export Bill of Material (as CSV)" boms = [ "#{name}.bom.csv" ] task :bom => boms +CLEAN.include([ "#{name}.versioned.xml" ]) CLOBBER.include(boms) -desc "export PnP placement" -pnps = [ "#{name}.cpl.csv" ] -task :pnp => pnps -CLOBBER.include(pnps) - # =============== # file generation # =============== -desc "generate schematic with version information all symbols embedded" -rule ".versioned.sch" => ".sch" do |t| - sh "cp #{t.source} #{t.name}" - sh "lepton-embed --embed #{t.name} 2> /dev/null" - sh "sed --in-place 's/\\$version\\$/#{version}/' #{t.name}" - sh "sed --in-place 's/\\$date\\$/#{date}/' #{t.name}" - sh "sed --in-place 's/\\$revision\\$/#{revision}/' #{t.name}" -end - -desc "generate board layout with version information" -rule ".versioned.lht" => ".lht" do |t| - sh "cp #{t.source} #{t.name}" - sh "sed --in-place 's/\\$version\\$/#{version}/' #{t.name}" - sh "sed --in-place 's/\\$date\\$/#{date}/' #{t.name}" - sh "sed --in-place 's/\\$revision\\$/#{revision}/' #{t.name}" +desc "generate file with version information" +VERSIONED = [".kicad_sch", ".kicad_pcb", ".kicad_pro"] +VERSIONED.each do |ext| + rule ".versioned" + ext => ext do |t| + sh "cp #{t.source} #{t.name}" + sh "sed --in-place 's/\\$version\\$/#{version}/g' #{t.name}" + sh "sed --in-place 's/\\$date\\$/#{date}/g' #{t.name}" + sh "sed --in-place 's/\\$revision\\$/#{revision}/g' #{t.name}" + end end desc "generate printable version (PDF) of schematic" -rule ".sch.pdf" => ".versioned.sch" do |t| - sh "lepton-cli export --color --paper=iso_a4 --layout=landscape --output=#{t.name} #{t.source} 2> /dev/null" +rule ".sch.pdf" => [".versioned.kicad_sch", ".versioned.kicad_pro"] do |t| + sh "eeschema_do export #{t.prerequisites[0]} ." + sh "mv #{t.prerequisites[0].split('.kicad_sch')[0]}.pdf #{t.name}" end -desc "generate printable version (PostScript) of board layout" -rule ".brd.ps" => ".versioned.lht" do |t| - sh "pcb-rnd -x ps --ps-color --media A4 --psfile #{t.name} #{t.source} 2> /dev/null" +desc "generate render from layout (top side)" +rule ".brd-top.png" => ".versioned.kicad_pcb" do |t| + sh "pcbdraw --silent #{t.source} --dpi 600 #{t.name}" end -desc "generate printable version (PDF) of board layout" -rule ".brd.pdf" => ".brd.ps" do |t| - sh "ps2pdf -sPAPERSIZE=a4 -dEPSCrop #{t.source} #{t.name}" +desc "generate render from layout (bottom side)" +rule ".brd-bot.png" => ".versioned.kicad_pcb" do |t| + sh "pcbdraw --silent #{t.source} --dpi 600 --back #{t.name}" end -desc "generate photo realistic picture from layout (top side)" -rule ".brd-top.svg" => ".versioned.lht" do |t| - sh "pcb-rnd -x svg --photo-mode --outfile #{t.name} #{t.source} 1> /dev/null" +desc "generate netlist" +rule ".versioned.xml" => ".versioned.kicad_sch" do |t| + sh "eeschema_do bom_xml #{t.source} ." end -desc "generate photo realistic picture from layout (bottom side)" -rule ".brd-bottom.svg" => ".versioned.lht" do |t| - sh "pcb-rnd -x svg --photo-mode --flip --outfile #{t.name} #{t.source} 1> /dev/null" -end - -desc "archive gerbers" -rule ".brd.zip" => ".versioned.lht" do |t| - base = File.basename(t.source, ".versioned.lht") - dir = "fabrication" - sh "mkdir #{dir}" unless File.directory?(dir) - sh "pcb-rnd -x cam gerber:JLC_PCB --outfile #{dir}/#{base}.brd #{t.source} 2> /dev/null" - sh "zip --quiet #{t.name} #{dir}/*" -end - -desc "generate BOM file from schematic" -rule ".bom.csv" => ".sch" do |t| - attributes = ["device", "value", "description", "footprint", "manufacturer", "mpn", "datasheet", "lcsc", "digikey"] - bom_data = bom2(t.prerequisites[0], attributes) - CSV.open(t.name, "wb") do |csv| - all_attributes = ["refdes","qty"] + attributes - csv << all_attributes - bom_data.each do |line| - csv << all_attributes.collect{|attribute| line[attribute]} - end - end -end - -desc "generate pick-and-place file from board" -rule ".cpl.csv" => [".versioned.lht", "mass_prop.sh", "pnp_fab.tab"] do |t| - sh "./mass_prop.sh #{t.prerequisites[0]} pnp_fab.tab" # add fab placement offsets - sh "pcb-rnd -x XY --xyfile #{t.name} --xy-unit mm --format 'JLCPCB' --vendor jlcpcb #{t.prerequisites[0]}" # export XY file in JLCPCB format -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 = list.each_line {|l| '"' + l + '"' + '\n' } - list.gsub!(/^(.+)/, '"\1') - list.gsub!(/(.+)$/, '\1"') - list.gsub!(/(?!http):(?!\/\/)/, '\1":"\2') # protect the values between ':' (such as URLs) - # parse bom2 - csv = CSV.parse(list, col_sep: ":", quote_char: '"') - if csv.empty? then - $stderr.puts "no parts found for BOM" - return [] - end - 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 +desc "generate BOM" +rule ".bom.csv" => ".versioned.xml" do |t| + sh "kibom #{t.source} #{t.name}" end