Added a simple test for drills
This commit is contained in:
parent
d500178c24
commit
6873652433
|
|
@ -5,7 +5,7 @@
|
|||
(drawings 4)
|
||||
(tracks 0)
|
||||
(zones 0)
|
||||
(modules 3)
|
||||
(modules 4)
|
||||
(nets 1)
|
||||
)
|
||||
|
||||
|
|
@ -101,6 +101,25 @@
|
|||
(uvia_drill 0.1)
|
||||
)
|
||||
|
||||
(module MountingHole:MountingHole_2.1mm (layer F.Cu) (tedit 5B924765) (tstamp 5EBE1AA4)
|
||||
(at 120 29)
|
||||
(descr "Mounting Hole 2.1mm, no annular")
|
||||
(tags "mounting hole 2.1mm no annular")
|
||||
(attr virtual)
|
||||
(fp_text reference REF** (at 0 -3.2) (layer F.SilkS)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_text value MountingHole_2.1mm (at 0 3.2) (layer F.Fab)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(fp_circle (center 0 0) (end 2.35 0) (layer F.CrtYd) (width 0.05))
|
||||
(fp_circle (center 0 0) (end 2.1 0) (layer Cmts.User) (width 0.15))
|
||||
(fp_text user %R (at 0.3 0) (layer F.Fab)
|
||||
(effects (font (size 1 1) (thickness 0.15)))
|
||||
)
|
||||
(pad "" np_thru_hole circle (at 0 0) (size 2.1 2.1) (drill 2.1) (layers *.Cu *.Mask))
|
||||
)
|
||||
|
||||
(module Resistor_THT:R_Box_L13.0mm_W4.0mm_P9.00mm (layer F.Cu) (tedit 5AE5139B) (tstamp 5EA76EC0)
|
||||
(at 110 45)
|
||||
(descr "Resistor, Box series, Radial, pin pitch=9.00mm, 2W, length*width=13.0*4.0mm^2, http://www.produktinfo.conrad.com/datenblaetter/425000-449999/443860-da-01-de-METALLBAND_WIDERSTAND_0_1_OHM_5W_5Pr.pdf")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
"""
|
||||
Tests of drill files
|
||||
|
||||
The 3Rs.kicad_pcb has R1 on top, R2 on bottom and a thru-hole component R3 on top.
|
||||
We test:
|
||||
|
||||
For debug information use:
|
||||
pytest-3 --log-cli-level debug
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
# Look for the 'utils' module from where the script is running
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, os.path.dirname(script_dir))
|
||||
# Utils import
|
||||
from utils import context
|
||||
|
||||
DRILL_DIR = 'Drill'
|
||||
positions = {'R1': (105, 35, 'top'), 'R2': (110, 35, 'bottom'), 'R3': (110, 45, 'top')}
|
||||
|
||||
|
||||
def expect_position(ctx, file, comp, no_comp=[], inches=False):
|
||||
"""
|
||||
Check if a list of components are or aren't in the file
|
||||
"""
|
||||
# Components that must be found
|
||||
texts = []
|
||||
for k in comp:
|
||||
texts.append('^'+k+r'\s+\S+\s+\S+\s+([-\d\.]+)\s+([-\d\.]+)\s+([-\d\.]+)\s+(\S+)\s*$')
|
||||
res = ctx.search_in_file(file, texts)
|
||||
for k in comp:
|
||||
x, y, side = positions[k]
|
||||
if inches:
|
||||
x = x/25.4
|
||||
y = y/25.4
|
||||
matches = res.pop(0)
|
||||
assert(abs(float(x) - float(matches[0])) < 0.001)
|
||||
assert(abs(float(y) + float(matches[1])) < 0.001)
|
||||
assert(side == matches[3])
|
||||
|
||||
# Components that must not be found
|
||||
texts = []
|
||||
for k in no_comp:
|
||||
expr = '^'+k+r'\s+\S+\s+\S+\s+([-\d\.]+)\s+([-\d\.]+)\s+([-\d\.]+)\s+(\S+)\s*$'
|
||||
texts.append(expr)
|
||||
ctx.search_not_in_file(file, texts)
|
||||
|
||||
|
||||
def test_3Rs_drill():
|
||||
ctx = context.TestContext('3Rs_drill', '3Rs', 'drill', DRILL_DIR)
|
||||
ctx.run()
|
||||
# Check all outputs are there
|
||||
ctx.expect_out_file(os.path.join(DRILL_DIR, 'report.rpt'))
|
||||
pth_drl = ctx.get_pth_drl_filename()
|
||||
ctx.expect_out_file(pth_drl)
|
||||
npth_drl = ctx.get_npth_drl_filename()
|
||||
ctx.expect_out_file(npth_drl)
|
||||
pth_gbr_drl = ctx.get_pth_gbr_drl_filename()
|
||||
ctx.expect_out_file(pth_gbr_drl)
|
||||
npth_gbr_drl = ctx.get_npth_gbr_drl_filename()
|
||||
ctx.expect_out_file(npth_gbr_drl)
|
||||
pth_pdf_drl = ctx.get_pth_pdf_drl_filename()
|
||||
ctx.expect_out_file(pth_pdf_drl)
|
||||
npth_pdf_drl = ctx.get_npth_pdf_drl_filename()
|
||||
ctx.expect_out_file(npth_pdf_drl)
|
||||
# We have R3 at (110, 45) length is 9 mm on X, drill 1 mm
|
||||
ctx.search_in_file(pth_drl, ['X110.0Y-45.0', 'X119.0Y-45.0'])
|
||||
ctx.expect_gerber_flash_at(pth_gbr_drl, 6, (110, -45))
|
||||
ctx.expect_gerber_has_apertures(pth_gbr_drl, ['C,1.000000'])
|
||||
# We have a mounting hole at (120, 29) is 2.1 mm in diameter
|
||||
ctx.search_in_file(npth_drl, ['X120.0Y-29.0', 'T1C2.100'])
|
||||
ctx.expect_gerber_flash_at(npth_gbr_drl, 6, (120, -29))
|
||||
ctx.expect_gerber_has_apertures(npth_gbr_drl, ['C,2.100000'])
|
||||
ctx.clean_up()
|
||||
|
|
@ -53,10 +53,10 @@ def expect_position(ctx, file, comp, no_comp=[], inches=False):
|
|||
|
||||
|
||||
def test_3Rs_position():
|
||||
ctx = context.TestContext('3Rs_position', '3Rs', 'simple_position')
|
||||
ctx = context.TestContext('3Rs_position', '3Rs', 'simple_position', POS_DIR)
|
||||
ctx.run()
|
||||
pos_top = ctx.get_pos_top_filename(POS_DIR)
|
||||
pos_bot = ctx.get_pos_bot_filename(POS_DIR)
|
||||
pos_top = ctx.get_pos_top_filename()
|
||||
pos_bot = ctx.get_pos_bot_filename()
|
||||
ctx.expect_out_file(pos_top)
|
||||
ctx.expect_out_file(pos_bot)
|
||||
expect_position(ctx, pos_top, ['R1'], ['R2', 'R3'])
|
||||
|
|
@ -65,24 +65,24 @@ def test_3Rs_position():
|
|||
|
||||
|
||||
def test_3Rs_position_unified():
|
||||
ctx = context.TestContext('3Rs_position_unified', '3Rs', 'simple_position_unified')
|
||||
ctx = context.TestContext('3Rs_position_unified', '3Rs', 'simple_position_unified', POS_DIR)
|
||||
ctx.run()
|
||||
expect_position(ctx, ctx.get_pos_both_filename(POS_DIR), ['R1', 'R2'], ['R3'])
|
||||
expect_position(ctx, ctx.get_pos_both_filename(), ['R1', 'R2'], ['R3'])
|
||||
ctx.clean_up()
|
||||
|
||||
|
||||
def test_3Rs_position_unified_th():
|
||||
ctx = context.TestContext('3Rs_position_unified_th', '3Rs', 'simple_position_unified_th')
|
||||
ctx = context.TestContext('3Rs_position_unified_th', '3Rs', 'simple_position_unified_th', POS_DIR)
|
||||
ctx.run()
|
||||
expect_position(ctx, ctx.get_pos_both_filename(POS_DIR), ['R1', 'R2', 'R3'])
|
||||
expect_position(ctx, ctx.get_pos_both_filename(), ['R1', 'R2', 'R3'])
|
||||
ctx.clean_up()
|
||||
|
||||
|
||||
def test_3Rs_position_inches():
|
||||
ctx = context.TestContext('3Rs_position_inches', '3Rs', 'simple_position_inches')
|
||||
ctx = context.TestContext('3Rs_position_inches', '3Rs', 'simple_position_inches', POS_DIR)
|
||||
ctx.run()
|
||||
pos_top = ctx.get_pos_top_filename(POS_DIR)
|
||||
pos_bot = ctx.get_pos_bot_filename(POS_DIR)
|
||||
pos_top = ctx.get_pos_top_filename()
|
||||
pos_bot = ctx.get_pos_bot_filename()
|
||||
ctx.expect_out_file(pos_top)
|
||||
ctx.expect_out_file(pos_bot)
|
||||
expect_position(ctx, pos_top, ['R1'], ['R2', 'R3'], True)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ pytest-3 --log-cli-level debug
|
|||
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
# Look for the 'utils' module from where the script is running
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, os.path.dirname(script_dir))
|
||||
|
|
@ -16,49 +15,24 @@ sys.path.insert(0, os.path.dirname(script_dir))
|
|||
from utils import context
|
||||
|
||||
|
||||
def expect_gerber_has_apertures(ctx, file, ap_list):
|
||||
ap_matches = []
|
||||
for ap in ap_list:
|
||||
# find the circular aperture for the outline
|
||||
ap_matches.append(r'%AD(.*)'+ap+r'\*%')
|
||||
grps = ctx.search_in_file(file, ap_matches)
|
||||
aps = []
|
||||
for grp in grps:
|
||||
ap_no = grp[0]
|
||||
assert ap_no is not None
|
||||
# apertures from D10 to D999
|
||||
assert len(ap_no) in [2, 3]
|
||||
aps.append(ap_no)
|
||||
logging.debug("Found apertures {}".format(aps))
|
||||
return aps
|
||||
|
||||
|
||||
def expect_gerber_flash_at(ctx, file, pos):
|
||||
"""
|
||||
Check for a gerber flash at a given point
|
||||
(it's hard to check that aperture is right without a real gerber parser
|
||||
"""
|
||||
repat = r'^X{x}Y{y}D03\*$'.format(x=int(pos[0]*100000), y=int(pos[1]*100000))
|
||||
ctx.search_in_file(file, [repat])
|
||||
logging.debug("Gerber flash found: "+repat)
|
||||
GERBER_DIR = 'gerberdir'
|
||||
|
||||
|
||||
def test_2layer():
|
||||
prj = 'simple_2layer'
|
||||
ctx = context.TestContext('Simple_2_layer', prj, prj)
|
||||
ctx = context.TestContext('Simple_2_layer', prj, prj, GERBER_DIR)
|
||||
ctx.run()
|
||||
|
||||
g_dir = 'gerberdir'
|
||||
f_cu = ctx.get_gerber_filename(g_dir, 'F_Cu')
|
||||
f_cu = ctx.get_gerber_filename('F_Cu')
|
||||
ctx.expect_out_file(f_cu)
|
||||
ctx.expect_out_file(ctx.get_gerber_job_filename(g_dir))
|
||||
ctx.expect_out_file(ctx.get_gerber_job_filename())
|
||||
|
||||
expect_gerber_has_apertures(ctx, f_cu, [
|
||||
ctx.expect_gerber_has_apertures(f_cu, [
|
||||
r"C,0.200000",
|
||||
r"R,2.000000X2.000000",
|
||||
r"C,1.000000"])
|
||||
|
||||
# expect a flash for the square pad
|
||||
expect_gerber_flash_at(ctx, f_cu, (140, -100))
|
||||
ctx.expect_gerber_flash_at(f_cu, 5, (140, -100))
|
||||
|
||||
ctx.clean_up()
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ MODE_PCB = 0
|
|||
|
||||
class TestContext(object):
|
||||
|
||||
def __init__(self, test_name, board_name, yaml_name):
|
||||
def __init__(self, test_name, board_name, yaml_name, sub_dir):
|
||||
# We are using PCBs
|
||||
self.mode = MODE_PCB
|
||||
# The name used for the test output dirs and other logging
|
||||
|
|
@ -32,6 +32,8 @@ class TestContext(object):
|
|||
self._get_yaml_name(yaml_name)
|
||||
# The actual output dir for this run
|
||||
self._set_up_output_dir(pytest.config.getoption('test_dir'))
|
||||
# Where are we expecting to get the outputs (inside test_name)
|
||||
self.sub_dir = sub_dir
|
||||
# stdout and stderr from the run
|
||||
self.out = None
|
||||
self.err = None
|
||||
|
|
@ -77,20 +79,38 @@ class TestContext(object):
|
|||
def get_out_path(self, filename):
|
||||
return os.path.join(self.output_dir, filename)
|
||||
|
||||
def get_gerber_job_filename(self, dir):
|
||||
return os.path.join(dir, self.board_name+'-job.gbrjob')
|
||||
def get_gerber_job_filename(self):
|
||||
return os.path.join(self.sub_dir, self.board_name+'-job.gbrjob')
|
||||
|
||||
def get_gerber_filename(self, dir, layer_slug, ext='.gbr'):
|
||||
return os.path.join(dir, self.board_name+'-'+layer_slug+ext)
|
||||
def get_gerber_filename(self, layer_slug, ext='.gbr'):
|
||||
return os.path.join(self.sub_dir, self.board_name+'-'+layer_slug+ext)
|
||||
|
||||
def get_pos_top_filename(self, dir):
|
||||
return os.path.join(dir, self.board_name+'-top.pos')
|
||||
def get_pos_top_filename(self):
|
||||
return os.path.join(self.sub_dir, self.board_name+'-top.pos')
|
||||
|
||||
def get_pos_bot_filename(self, dir):
|
||||
return os.path.join(dir, self.board_name+'-bottom.pos')
|
||||
def get_pos_bot_filename(self):
|
||||
return os.path.join(self.sub_dir, self.board_name+'-bottom.pos')
|
||||
|
||||
def get_pos_both_filename(self, dir):
|
||||
return os.path.join(dir, self.board_name+'-both.pos')
|
||||
def get_pos_both_filename(self):
|
||||
return os.path.join(self.sub_dir, self.board_name+'-both.pos')
|
||||
|
||||
def get_pth_drl_filename(self):
|
||||
return os.path.join(self.sub_dir, self.board_name+'-PTH.drl')
|
||||
|
||||
def get_pth_gbr_drl_filename(self):
|
||||
return os.path.join(self.sub_dir, self.board_name+'-PTH-drl.gbr')
|
||||
|
||||
def get_pth_pdf_drl_filename(self):
|
||||
return os.path.join(self.sub_dir, self.board_name+'-PTH-drl_map.pdf')
|
||||
|
||||
def get_npth_drl_filename(self):
|
||||
return os.path.join(self.sub_dir, self.board_name+'-NPTH.drl')
|
||||
|
||||
def get_npth_gbr_drl_filename(self):
|
||||
return os.path.join(self.sub_dir, self.board_name+'-NPTH-drl.gbr')
|
||||
|
||||
def get_npth_pdf_drl_filename(self):
|
||||
return os.path.join(self.sub_dir, self.board_name+'-NPTH-drl_map.pdf')
|
||||
|
||||
def expect_out_file(self, filename):
|
||||
file = self.get_out_path(filename)
|
||||
|
|
@ -254,6 +274,35 @@ class TestContext(object):
|
|||
with open(fname, 'w') as f:
|
||||
f.write(re.sub(pattern, repl, txt))
|
||||
|
||||
def expect_gerber_flash_at(self, file, res, pos):
|
||||
"""
|
||||
Check for a gerber flash at a given point
|
||||
(it's hard to check that aperture is right without a real gerber parser
|
||||
"""
|
||||
if res == 6: # 4.6
|
||||
mult = 1000000
|
||||
else: # 4.5
|
||||
mult = 100000
|
||||
repat = r'^X{x}Y{y}D03\*$'.format(x=int(pos[0]*mult), y=int(pos[1]*mult))
|
||||
self.search_in_file(file, [repat])
|
||||
logging.debug("Gerber flash found: "+repat)
|
||||
|
||||
def expect_gerber_has_apertures(self, file, ap_list):
|
||||
ap_matches = []
|
||||
for ap in ap_list:
|
||||
# find the circular aperture for the outline
|
||||
ap_matches.append(r'%AD(.*)'+ap+r'\*%')
|
||||
grps = self.search_in_file(file, ap_matches)
|
||||
aps = []
|
||||
for grp in grps:
|
||||
ap_no = grp[0]
|
||||
assert ap_no is not None
|
||||
# apertures from D10 to D999
|
||||
assert len(ap_no) in [2, 3]
|
||||
aps.append(ap_no)
|
||||
logging.debug("Found apertures {}".format(aps))
|
||||
return aps
|
||||
|
||||
|
||||
class TestContextSCH(TestContext):
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
# Drills and Gerber drills
|
||||
kiplot:
|
||||
version: 1
|
||||
|
||||
outputs:
|
||||
|
||||
- name: excellon_drill
|
||||
comment: "Excellon drill files"
|
||||
type: excellon
|
||||
dir: Drill
|
||||
options:
|
||||
metric_units: true
|
||||
pth_and_npth_single_file: false
|
||||
use_aux_axis_as_origin: false
|
||||
minimal_header: false
|
||||
mirror_y_axis: false
|
||||
report:
|
||||
filename: 'report.rpt'
|
||||
map:
|
||||
type: 'pdf'
|
||||
|
||||
- name: gerber_drills
|
||||
comment: "Gerber drill files"
|
||||
type: gerb_drill
|
||||
dir: Drill
|
||||
options:
|
||||
use_aux_axis_as_origin: false
|
||||
|
||||
|
|
@ -35,12 +35,3 @@ outputs:
|
|||
- layer: F.SilkS
|
||||
suffix: F_SilkS
|
||||
|
||||
- name: 'position'
|
||||
comment: "Pick and place file"
|
||||
type: position
|
||||
dir: positiondir
|
||||
options:
|
||||
format: ASCII # CSV or ASCII format
|
||||
units: millimeters # millimeters or inches
|
||||
separate_files_for_front_and_back: true
|
||||
only_smd: true
|
||||
|
|
|
|||
Loading…
Reference in New Issue