Snippets

John Peck Create a pipe table of drill diameters and uses from a PCB drill file

Created by John Peck last modified John Peck
#!/opt/ActiveTcl-8.6/bin/tclsh
# Hey Emacs, use -*- Tcl -*- mode

set scriptname [file rootname $argv0]


# ---------------------- Command line parsing -------------------------
package require cmdline
set usage "usage: [file tail $argv0] \[options] filename"
set options {
    {t.arg none "Comma separated list of tool codes for filled holes"}
}

try {
    array set params [::cmdline::getoptions argv $options $usage]
} trap {CMDLINE USAGE} {msg o} {
    # Trap the usage signal, print the message, and exit the application.
    # Note: Other errors are not caught and passed through to higher levels!
    puts $msg
    exit 1
}

# After cmdline is done, argv will point to the last argument
if {[llength $argv] == 1} {
    set datafile $argv
} else {
    puts [cmdline::usage $options $usage]
    exit 1
}


proc read_file {filename} {
    # Return a list of lines from an input file
    #
    # The file consists of capacitance measurements.
    if { [catch {open $filename r} fid] } {
	    puts "Could not open file $filename"
	return
    }
    set datafile_list [split [read $fid] "\n"]
    return $datafile_list
}


proc get_drill_diameters {raw_line_list} {
    # Returns a dictionary of (tool code) : (tool diameter)
    #
    # Arguments:
    #   raw_line_list -- List of lines from a NC drill file
    set tool_diameter_dict [dict create]
    foreach line $raw_line_list {
	if {[string first % $line] == 0} {
	    # This is the start of the data section
	    break
	}
	if {[string first T $line] == 0} {
	    # This is a tool code line
	    set linelist [split $line C]
	    set diameter [lindex $linelist 1]
	    # Altium has F and S fields in their tool lists
	    set toolstring [regexp -inline {T[0-9]*} $line]
	    # The tool code may contain leading zeros
	    set toolnum [regexp -inline {[1-9][0-9]*} $toolstring]
	    dict set tool_diameter_dict T$toolnum $diameter
	}
    }
    return $tool_diameter_dict
}

proc format_tool_code {tool_string} {
    # Returns a properly formatted tool code
    
}

proc get_drill_units {raw_line_list} {
    # Returns either inch or mm for the drill diameter units
    #
    # Arguments:
    #   raw_line_list -- List of lines from a NC drill file
    set units none
    foreach line $raw_line_list {
	if {[string first % $line] == 0} {
	    # This is the start of the data section
	    break
	}
	if {[string first INCH $line] == 0} {
	    # The dimensions are in inches
	    set units inch
	}
	if {[string first METRIC $line] == 0} {
	    # The dimensions are in mm
	    set units mm
	}
    }
    if {[string equal $units none]} {
	# We could not determine the units
	puts "Error -- could not determine drill diameter units"
	exit
    }
    return $units
}

proc init_drill_count_dict {drill_diameter_dict} {
    # Return an initialized dictionary of (tool code) : (tool count)
    #
    # Arguments:
    #   drill_diameter_dict -- Dictionary of (tool code) : (tool diameter)
    set drill_count_dict [dict create]
    foreach tool [dict keys $drill_diameter_dict] {
	dict set drill_count_dict $tool 0
    }
    return $drill_count_dict
}

proc update_drill_count {drill_count_dict raw_line_list} {
    # Return an updated dictionary of (tool code) : (tool count)
    #
    # Arguments:
    #   drill_count_dict -- Dictionary of (tool code) : (tool count)
    #   raw_line_list -- List of lines from a NC drill file
    set data_started false
    set current_tool none
    foreach line $raw_line_list {
	if {[string first % $line] == 0} {
	    # This is the start of the data section
	    set data_started true
	}
	if {[string first T $line] == 0 && $data_started} {
	    # This is the start of a new tool section
	    set current_tool T[regexp -inline {[1-9][0-9]*} $line]
	}
	if {[string first X $line] == 0 && ![string equal $current_tool none]} {
	    # This is a new drill location
	    dict incr drill_count_dict $current_tool
	}
    }
    return $drill_count_dict
}

proc get_total_drills {drill_count_dict} {
    # Return the total number of drills in the drill count dictionary
    #
    # Arguments:
    #   drill_count_dict -- Dictionary of (tool code) : (tool count)
    set total_drills 0
    foreach tool [dict keys $drill_count_dict] {
	incr total_drills [dict get $drill_count_dict $tool]
    }
    return $total_drills
}



proc write_drill_table {drill_diameter_dict drill_count_dict drill_units} {
    # Write a pipe-delimited drill table
    #
    # Arguments:
    #   drill_diameter_dict -- Dictionary of (tool code) : (tool diameter)
    #   drill_count_dict -- Dictionary of (tool code) : (tool count)
    #   drill_units -- Either inch or mm
    global params
    set drill_diameter_dict [lsort -stride 2 -index 1 -real $drill_diameter_dict]
    set tool_width 10
    set size_width 20
    set count_width 10
    set filled_width 10
    set total_width 7
    set separator [string repeat " " $total_width]
    append separator "|-[string repeat - $tool_width]-"
    append separator "+-[string repeat - $size_width]-"
    append separator "+-[string repeat - $count_width]-"
    append separator "+-[string repeat - $filled_width]-"
    append separator "|"
    puts $separator
    set header [string repeat " " $total_width]
    append header [format "| %-*s | %-*s | %-*s | %-*s | " \
		       $tool_width "Tool" \
		       $size_width "Hole size ($drill_units)" \
		       $count_width "Count" \
		       $filled_width "Filled?"
		  ]
    puts $header
    puts $separator
    foreach tool [dict keys $drill_diameter_dict] {
	set filled ""
	if {[string first $tool $params(t)] != -1} {
	    set filled x
	}
	set table_row [string repeat " " $total_width]
	append table_row [format "| %-*s | %-*s | %-*s | %-*s | " $tool_width $tool \
			      $size_width [dict get $drill_diameter_dict $tool] \
			      $count_width [dict get $drill_count_dict $tool] \
			      $filled_width $filled
			 ]
	puts $table_row
    }
    puts $separator
    set total_row [format "%-*s" $total_width "Total:"]
    append total_row [format "| %-*s | %-*s | %-*s | %-*s | " \
			  $tool_width [llength [dict keys $drill_diameter_dict]] \
			  $size_width "" \
			  $count_width [get_total_drills $drill_count_dict] \
			  $filled_width $filled
		     ]
    puts $total_row
    puts $separator
}

# Start processing the file
set raw_line_list [read_file $datafile]
set drill_diameter_dict [get_drill_diameters $raw_line_list]
set drill_count_dict [init_drill_count_dict $drill_diameter_dict]
set drill_units [get_drill_units $raw_line_list]
set drill_count_dict [update_drill_count $drill_count_dict $raw_line_list]
write_drill_table $drill_diameter_dict $drill_count_dict $drill_units

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.