require 'rake/clean' # ================= # project variables # ================= # main name used if filename target = "led-controller" # schema sch = "#{target}.sch" # pcb layout pcb = "#{target}.pcb" # project version, read from "version" file version = IO.read("version").chomp # current date for stamping output date = Time.now.strftime("%Y-%m-%d") # schematic revision, based on the number of schematic commits) sch_rev = `git log --pretty=oneline "#{sch}" | wc -l`.chomp.to_i # pcb layout revision, based on the number of pcb commits) pcb_rev = `git log --pretty=oneline "#{pcb}" | wc -l`.chomp.to_i # schema name with version and revition vsch = "#{target}_v#{version}.#{sch_rev.to_s.rjust(3,'0')}.sch" # pcb layout name with version and revition vpcb = "#{target}_v#{version}.#{pcb_rev.to_s.rjust(3,'0')}.pcb" # ========== # main tasks # ========== desc "main building task" task :default => [:version,:print,:notes,:photo,:gerber] desc "create release file" task :release => "hardware-release_v#{version}.tar.gz" CLOBBER.include("hardware-release_v#{version}.tar.gz") desc "set version in schematic and layout" task :version => [vsch,vpcb] CLEAN.include(vsch) CLEAN.include(vpcb) CLOBBER.include("#{target}_*.sch") CLOBBER.include("#{target}_*.pcb") desc "print schematic and layout (as pdf)" task :print => ["#{target}_schematic.pdf","#{target}_layout.pdf"] CLEAN.include("#{target}_schematic.pdf") CLEAN.include("#{target}_layout.pdf") desc "export notes from schematic" task :notes => "notes.txt" CLOBBER.include("notes.txt") desc "verify schematic attributes" task :verify => vsch do |t| ["value","footprint"].each do |attribute| bom2(t.prerequisites[0],attribute).each do |data| next unless data[attribute]=="unknown" puts "#{attribute}s not defined for #{data[:refdes]*','}" end end uniq = true numbered = true bom2(t.prerequisites[0],"refdes").each do |data| uniq &= data[:refdes].size==1 numbered &= !data["refdes"].include?("?") end puts "not all refdes uniq" unless uniq puts "not all refdes numbered" unless numbered end PHOTOS = ["#{target}_layout-top.png","#{target}_layout-bottom.png"] desc "render layout" task :photo => PHOTOS CLOBBER.include(PHOTOS) GERBERS = [".top.gbr",".topmask.gbr",".toppaste.gbr",".topsilk.gbr",".bottom.gbr",".bottommask.gbr",".bottompaste.gbr",".bottomsilk.gbr",".outline.gbr",".fab.gbr",".plated-drill.cnc",".unplated-drill.cnc"].collect{|suffix| target+suffix} desc "export gerber" task :gerber => GERBERS CLOBBER.include(GERBERS) desc "reformat gerber and drill output (some programs like LPKF CircuitPro have difficulties with gEDA pcb output)" task :reformat => GERBERS do GERBERS.each do |gerber| if gerber.end_with? ".gbr" then sh "gerbv --export=rs274x --output=#{gerber} #{gerber}" elsif gerber.end_with? ".cnc" then sh "gerbv --export=drill --output=#{gerber} #{gerber}" end end end # ================ # helper functions # ================ # generate gnetlist bom2 and parse them # arguments: schematic=schematic to usse, attributes=the attributs to use for generating bom2 # return [{:refdes => [refdes of component], => text of attributes}] def bom2(schematic, attributes) to_return = [] # force attributes to be an array attributes = case attributes.class when String [attributes] when Array attributes else [attributes.to_s] end # create gnetlist backend File.open("attribs","w") do |attribs| attributes.each do |attribute| attribs.puts attribute end end # generate bom2 list = `gnetlist -g bom2 -q -o - #{schematic}` # parse bom2 regex = /^(?(\w+,?)+):(?.*):(?\d+)$/ list.each_line do |line| next unless line =~ regex data = line.match regex hash = {refdes: data[:refdes].split(',')} attributes.each_index do |i| hash.merge!({attributes[i] => data[:attributes].split(':')[i]}) end to_return << hash end return to_return end CLEAN.include("attribs") # =============== # file generation # =============== desc "copy schematic to version it: include version, revision, and date" file vsch => sch do |t| sh "cp #{t.prerequisites.join(' ')} #{t.name}" # on \ is to prevent ruby interpreting it, th other is for sed # the version sh "sed -i 's/\\(version=\\)\\$Version\\$/\\1#{version}/' #{t.name}" # the date sh "sed -i 's/\\(date=\\)\\$Date\\$/\\1#{date}/' #{t.name}" # the revision sh "sed -i 's/\\(revision=\\)\\$Revision\\$/\\1#{sch_rev}/' #{t.name}" end desc "copy layout to version it: include version, date, and run teardrops when available" file vpcb => pcb do |t| sh "cp #{t.prerequisites.join(' ')} #{t.name}" # on \ is to prevent ruby interpreting it, th other is for sed # the version and revision version_revision = "v#{version}.#{pcb_rev.to_s.rjust(3,'0')}" sh "sed -i 's/\\$version\\$/#{version_revision}/' #{t.name}" # the date sh "sed -i 's/\\$date\\$/#{date}/' #{t.name}" # run teardrop for vias and pins if File.exist? "#{Dir.home}/.pcb/plugins/teardrops.so" then sh "pcb --action-string \"djopt(splitlines) Teardrops() s() q()\" #{t.name}" end end desc "generate printable version (PDF) of schematic" file "#{target}_schematic.pdf" => vsch do |t| sh "gaf export -f pdf -c -o #{t.name} #{t.prerequisites.join(' ')} 2> /dev/null" end desc "generate printable documentation (PDF) from layout" file "#{target}_layout.pdf" => vpcb do |t| sh "pcb -x ps --psfile #{t.name}.ps #{t.prerequisites.join(' ')} 2> /dev/null" sh "ps2pdf #{t.name}.ps #{t.name} 2> /dev/null" sh "rm #{t.name}.ps 2> /dev/null" end desc "generate note file from schematic, listing the 'note' attributes from elements" file "notes.txt" => vsch do |t| notes_data = bom2(t.prerequisites[0],"note") File.open(t.name,"w") do |notes_file| notes_data.each do |note| next if note["note"]=="unknown" notes_file.puts "#{note[:refdes]*','}:\n#{note["note"]}\n\n" end end end desc "generate photo realistic picture from layout (front side)" file "#{target}_layout-top.png" => vpcb do |t| # sh "pcb -x png --dpi 600 --format PNG --photo-mode --outfile #{target}_layout-top.png #{t.prerequisites.join(' ')}" sh "pcb -x png --format PNG --photo-mode --outfile #{target}_layout-top.png #{t.prerequisites.join(' ')}" end desc "generate photo realistic picture from layout (bottom side)" file "#{target}_layout-bottom.png" => vpcb do |t| # sh "pcb -x png --dpi 600 --format PNG --photo-mode --photo-flip-x --outfile #{target}_layout-bottom.png #{t.prerequisites.join(' ')}" sh "pcb -x png --format PNG --photo-mode --photo-flip-x --outfile #{target}_layout-bottom.png #{t.prerequisites.join(' ')}" end desc "export gerber (and drill) files from layout" GERBERS.each do |gerber| file gerber => vpcb do |t| puts "make #{t.name}" sh "pcb -x gerber --gerberfile #{target} --all-layers #{t.prerequisites.join(' ')}" end end ATTACHMENTS = ["cern_ohl_v_1_2_howto.pdf","CHANGES.txt","LICENSE.txt","PRODUCT.txt"] desc "create archive with release files" file "hardware-release_v#{version}.tar.gz" => ATTACHMENTS+["lib",vsch,vpcb,"notes.txt","#{target}_schematic.pdf","#{target}_layout.pdf","#{target}_layout-top.png","#{target}_layout-bottom.png"]+GERBERS do |t| sh "tar -acf '#{t.name}' #{t.prerequisites.join(' ')}" end