osmotoserial/hardware/Rakefile

254 lines
8.2 KiB
Ruby
Raw Normal View History

2014-03-02 18:40:00 +01:00
require 'rake/clean'
# =================
# project variables
# =================
# main names used for filenames
names = IO.read("name").split("\n").select {|target| !target.empty?}
raise "define project name(s) in 'name' file" if names.empty?
2014-03-02 18:40:00 +01:00
# project version, read from "version" file
version = IO.read("version").split("\n")[0]
raise "define project version in 'version' file" unless version
# current date for stamping output
date = Time.now.strftime("%Y-%m-%d")
# create targets for each name
targets = []
names.each do |name|
# schema
sch = "#{name}.sch"
# pcb layout
pcb = "#{name}.pcb"
# 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
2014-03-26 11:51:10 +01:00
pcb_rev = `git log --pretty=oneline "#{pcb}" | wc -l`.chomp.to_i
# schema name with version and revition
vsch = "#{name}_v#{version}.#{sch_rev.to_s.rjust(3,'0')}.sch"
# pcb layout name with version and revition
vpcb = "#{name}_v#{version}.#{pcb_rev.to_s.rjust(3,'0')}.pcb"
# add to targets
targets << { name: name, sch: sch, pcb: pcb, sch_rev: sch_rev, pcb_rev: pcb_rev, vsch: vsch, vpcb: vpcb }
end
2014-03-02 18:40:00 +01:00
# ==========
# main tasks
# ==========
desc "main building task"
task :default => [:version,:print,:notes,:photo,:gerber]
2014-03-02 18:40:00 +01:00
desc "create release file"
2014-03-26 12:08:17 +01:00
release = "hardware-release_v#{version}.tar.gz"
task :release => [:gerber,release]
2014-03-26 12:45:42 +01:00
CLOBBER.include(release)
2014-03-02 18:40:00 +01:00
desc "set version in schematic and layout"
2014-03-26 12:31:17 +01:00
versions = targets.collect{|target| [target[:vsch],target[:vpcb]]}.flatten
task :version => versions
2014-03-26 12:45:42 +01:00
CLEAN.include(versions)
targets.each do |target|
2014-03-26 12:45:42 +01:00
CLOBBER.include("#{target[:name]}_*.sch")
CLOBBER.include("#{target[:name]}_*.pcb")
end
2014-03-02 18:40:00 +01:00
desc "print schematic and layout (as pdf)"
2014-03-26 12:31:17 +01:00
prints = targets.collect{|target| ["#{target[:name]}_schematic.pdf","#{target[:name]}_layout.pdf"]}.flatten
task :print => prints
2014-03-26 12:45:42 +01:00
CLEAN.include(prints)
2014-03-02 18:40:00 +01:00
desc "export notes from schematic"
2014-03-26 12:31:17 +01:00
notes = targets.collect{|target| "#{target[:name]}_notes.txt"}
task :notes => notes
2014-03-26 12:45:42 +01:00
CLEAN.include(notes)
2014-03-02 18:40:00 +01:00
2014-03-26 12:31:17 +01:00
=begin
2014-03-02 18:40:00 +01:00
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
=end
2014-03-02 18:40:00 +01:00
desc "convert schematic to pcb layout"
task :sch2pcb do
targets.each do |target|
sh "gsch2pcb #{target[:sch]} --elements-dir #{File.dirname(__FILE__)}/lib/footprints --skip-m4 --output-name #{target[:name]}"
end
2014-03-02 18:40:00 +01:00
end
2014-03-26 16:54:57 +01:00
CLOBBER.include("*.net")
CLOBBER.include("*.new.pcb")
2014-03-02 18:40:00 +01:00
2014-03-26 12:45:42 +01:00
photos = targets.collect{|target| ["#{target[:name]}_layout-top.png","#{target[:name]}_layout-bottom.png"]}.flatten
2014-03-02 18:40:00 +01:00
desc "render layout"
2014-03-26 12:45:42 +01:00
task :photo => photos
CLOBBER.include(photos)
2014-03-02 18:40:00 +01:00
desc "export gerber"
2014-03-26 16:08:13 +01:00
task :gerber => :version do
targets.each do |target|
2014-03-26 16:08:13 +01:00
export = true # export only if the gerbers are all older than the layout
Dir.foreach(".") do |file|
next unless file.start_with? target[:name]
next unless file.end_with? ".gbr" or file.end_with? ".cnc"
export &= (File.ctime(target[:vpcb])>File.ctime(file))
end
sh "pcb -x gerber --gerberfile #{target[:name]} --all-layers #{target[:vpcb]}" if export
end
end
CLOBBER.include("*.gbr")
CLOBBER.include("*.cnc")
2014-03-02 18:40:00 +01:00
desc "reformat gerber and drill output (some programs like LPKF CircuitPro have difficulties with gEDA pcb output)"
task :reformat do
Dir.foreach(".") do |file|
next unless File.file? file
if file.end_with? ".gbr" then
sh "gerbv --export=rs274x --output=#{file} #{file}"
elsif file.end_with? ".cnc" then
sh "gerbv --export=drill --output=#{file} #{file}"
2014-03-02 18:40:00 +01:00
end
end
end
# ================
# helper functions
# ================
# generate gnetlist bom2 and parse them
2014-03-27 14:37:05 +01:00
# arguments: schematic=schematic to use, attributes=the attributes to use for generating bom2
2014-03-02 18:40:00 +01:00
# return [{:refdes => [refdes of component], <attributes> => 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 = /^(?<refdes>(\w+,?)+):(?<attributes>.*):(?<qty>\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
2014-03-26 12:45:42 +01:00
CLEAN.include("attribs")
2014-03-02 18:40:00 +01:00
# ===============
# file generation
# ===============
desc "copy schematic to version it: include version, revision, and date"
2014-03-26 11:54:06 +01:00
targets.each do |target|
2014-03-26 11:55:21 +01:00
file target[:vsch] => target[: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#{target[:sch_rev]}/' #{t.name}"
end
2014-03-02 18:40:00 +01:00
end
2014-03-26 11:54:46 +01:00
2014-03-02 18:40:00 +01:00
desc "copy layout to version it: include version, date, and run teardrops when available"
2014-03-26 11:54:46 +01:00
targets.each do |target|
2014-03-26 11:55:21 +01:00
file target[:vpcb] => target[: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
2014-03-26 11:58:17 +01:00
version_revision = "v#{version}.#{target[: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
2014-03-02 18:40:00 +01:00
end
end
2014-03-02 18:40:00 +01:00
desc "generate printable version (PDF) of schematic"
targets.each do |target|
file "#{target[:name]}_schematic.pdf" => target[:vsch] do |t|
sh "gaf export -f pdf -c -o #{t.name} #{t.prerequisites.join(' ')} 2> /dev/null"
end
2014-03-02 18:40:00 +01:00
end
desc "generate printable documentation (PDF) from layout"
targets.each do |target|
file "#{target[:name]}_layout.pdf" => target[: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
2014-03-02 18:40:00 +01:00
end
desc "generate note file from schematic, listing the 'note' attributes from elements"
2014-03-26 12:31:17 +01:00
targets.each do |target|
file "#{target[:name]}_notes.txt" => target[: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
2014-03-02 18:40:00 +01:00
end
end
end
desc "generate photo realistic picture from layout (front side)"
2014-03-26 12:45:42 +01:00
targets.each do |target|
file "#{target[:name]}_layout-top.png" => target[:vpcb] do |t|
sh "pcb -x png --dpi 600 --format PNG --photo-mode --outfile #{t.name} #{t.prerequisites.join(' ')}"
end
2014-03-02 18:40:00 +01:00
end
desc "generate photo realistic picture from layout (bottom side)"
2014-03-26 12:45:42 +01:00
targets.each do |target|
file "#{target[:name]}_layout-bottom.png" => target[:vpcb] do |t|
sh "pcb -x png --dpi 600 --format PNG --photo-mode --photo-flip-x --outfile #{t.name} #{t.prerequisites.join(' ')}"
end
2014-03-02 18:40:00 +01:00
end
desc "create archive with release files"
SOURCES = targets.collect{|target| [target[:sch],target[:pcb]]}.flatten
ATTACHMENTS = ["cern_ohl_v_1_2_howto.pdf","CHANGES.txt","LICENSE.txt","PRODUCT.txt"]
file release => SOURCES+prints+notes+photos+ATTACHMENTS do |t|
gerbers = Dir.entries(".").select{|file| file.end_with? ".gbr" or file.end_with? ".cnc"}
sh "tar -acf '#{t.name}' #{(t.prerequisites+gerbers).join(' ')}"
2014-03-02 18:40:00 +01:00
end