From b77822420a9d3669461d838060e4af61d645b749 Mon Sep 17 00:00:00 2001 From: "Salvador E. Tropea" Date: Tue, 10 Sep 2024 12:49:53 -0300 Subject: [PATCH] [Report][Added] Testpoints usage report See #638 --- kibot/out_report.py | 65 ++++++++++++++++++- .../Testpoints_by_attr.kibot.yaml | 9 +++ .../report_templates/report_testpoints.txt | 23 +++++++ .../report_testpoints_1.kibot.yaml | 11 ++++ 4 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 kibot/resources/report_templates/report_testpoints.txt create mode 100644 tests/yaml_samples/report_testpoints_1.kibot.yaml diff --git a/kibot/out_report.py b/kibot/out_report.py index 12206b3d..b43e8482 100644 --- a/kibot/out_report.py +++ b/kibot/out_report.py @@ -176,15 +176,20 @@ def list_nice(names): return res[2:] +class PadProperty(object): + pass + + class ReportOptions(VariantOptions): def __init__(self): with document: self.output = GS.def_global_output """ *Output file name (%i='report', %x='txt') """ self.template = 'full' - """ *Name for one of the internal templates (full, full_svg, simple) or a custom template file. + """ *[full,full_svg,simple,testpoints,*] Name for one of the internal templates or a custom template file. Environment variables and ~ are allowed. - Note: when converting to PDF PanDoc can fail on some Unicode values (use `simple_ASCII`) """ + Note: when converting to PDF PanDoc can fail on some Unicode values (use `simple_ASCII`). + Note: the testpoint variables uses the `testpoint` fabrication attribute of pads """ self.convert_from = 'markdown' """ Original format for the report conversion. Current templates are `markdown`. See `do_convert` """ self.convert_to = 'pdf' @@ -229,7 +234,7 @@ def config(self, parent): if self.template.endswith('_ASCII'): self.template = self.template[:-6] self.to_ascii = True - if self.template.lower() in ('full', 'simple', 'full_svg'): + if self.template.lower() in ('full', 'simple', 'full_svg', 'testpoints'): self.template = os.path.abspath(os.path.join(GS.get_resource_path('report_templates'), 'report_'+self.template.lower()+'.txt')) if not os.path.isabs(self.template): @@ -387,6 +392,34 @@ def _context_images(self, line, images): text += self.do_replacements(line, context) return text + def context_nets_without_testpoint(self, line): + """ Replace iterator for the `nets_without_testpoint` context """ + text = '' + for s in self._nets_without_testpoint: + context = {'net': s} + text += self.do_replacements(line, context) + return text + + def context_nets_with_one_testpoint(self, line): + """ Replace iterator for the `nets_with_one_testpoint` context """ + text = '' + for n, pads in self._nets_with_tp.items(): + if len(pads) > 1: + continue + context = {'net': n, 'pad': pads[0]} + text += self.do_replacements(line, context) + return text + + def context_nets_with_many_testpoints(self, line): + """ Replace iterator for the `nets_with_many_testpoints` context """ + text = '' + for n, pads in self._nets_with_tp.items(): + if len(pads) == 1: + continue + context = {'net': n, 'pads': ", ".join(pads)} + text += self.do_replacements(line, context) + return text + def context_layer_pdfs(self, line): """ Replace iterator for the `layer_pdfs` context """ return self._context_images(line, self._layer_pdfs) @@ -590,7 +623,9 @@ def collect_data(self, board): is_pure_smd, is_not_virtual = self.get_attr_tests() npth_attrib = 3 if GS.ki5 else pcbnew.PAD_ATTRIB_NPTH min_oar = GS.from_mm(0.1) + pad_properties = [] for m in modules: + ref = m.GetReference() layer = m.GetLayer() if layer == top_layer: if is_pure_smd(m): @@ -604,6 +639,13 @@ def collect_data(self, board): self.bot_tht += 1 pads = m.Pads() for pad in pads: + # Pad properties + if not GS.ki5: + p = PadProperty() + p.fab_property = pad.GetProperty() + p.net = pad.GetNetname() + p.name = ref+'.'+pad.GetNumber() + pad_properties.append(p) dr = pad.GetDrillSize() if not dr.x: continue @@ -821,6 +863,23 @@ def collect_data(self, board): self.paste_pads = self.paste_pads_front + self.paste_pads_bottom self.paste_pads_area = self.paste_pads_front_area + self.paste_pads_bottom_area self.solder_paste = self.solder_paste_front + self.solder_paste_bottom + ########################################################### + # Testpoints report + ########################################################### + nets = GS.board.GetNetsByName() + self.testpoint_pads = 0 + self.total_pads = len(pad_properties) + nets_with_tp = {} + for p in pad_properties: + if p.fab_property == pcbnew.PAD_PROP_TESTPOINT: + self.testpoint_pads += 1 + nets_with_tp[p.net] = nets_with_tp.get(p.net, [])+[p.name] + cnd = GS.board.GetConnectivity() + self.total_nets = cnd.GetNetCount() + self.nets_with_testpoint = len(nets_with_tp) + self.testpoint_coverage = (self.nets_with_testpoint/self.total_nets)*100 + self._nets_without_testpoint = [str(n) for n in nets.keys() if str(n) and str(n) not in nets_with_tp] + self._nets_with_tp = nets_with_tp def eval_conditional(self, line): context = {k: getattr(self, k) for k in dir(self) if k[0] != '_' and not callable(getattr(self, k))} diff --git a/kibot/resources/config_templates/Testpoints_by_attr.kibot.yaml b/kibot/resources/config_templates/Testpoints_by_attr.kibot.yaml index bb3f2fc6..9865fbfc 100644 --- a/kibot/resources/config_templates/Testpoints_by_attr.kibot.yaml +++ b/kibot/resources/config_templates/Testpoints_by_attr.kibot.yaml @@ -45,6 +45,15 @@ outputs: - field: Footprint Type name: Pad Type + - name: _testpoints_summary@_KIBOT_IMPORT_ID@ + comment: "Testpoints summary by fabrication attribute" + type: report + dir: @_KIBOT_IMPORT_DIR@ + output_id: _testpoints + options: + template: testpoints + + ... definitions: _KIBOT_IMPORT_ID: '' diff --git a/kibot/resources/report_templates/report_testpoints.txt b/kibot/resources/report_templates/report_testpoints.txt new file mode 100644 index 00000000..c702d867 --- /dev/null +++ b/kibot/resources/report_templates/report_testpoints.txt @@ -0,0 +1,23 @@ +# Testpoints + +Total pads: ${total_pads} +Total testpoints: ${testpoint_pads} +Total Nets: ${total_nets} + +- With testpoint: ${nets_with_testpoint} + +TestPoint coverage: ${%5.2f,testpoint_coverage} % + + +## Nets without testpoint + +#nets_without_testpoint:- ${net} + +## Nets with one testpoint + +#nets_with_one_testpoint:- ${net}: ${pad} + +## Nets with more than one testpoint + +#nets_with_many_testpoints:- ${net}: ${pads} + diff --git a/tests/yaml_samples/report_testpoints_1.kibot.yaml b/tests/yaml_samples/report_testpoints_1.kibot.yaml new file mode 100644 index 00000000..943689f5 --- /dev/null +++ b/tests/yaml_samples/report_testpoints_1.kibot.yaml @@ -0,0 +1,11 @@ +# Example KiBot config file +kibot: + version: 1 + +outputs: + - name: 'report_testpoints' + comment: "Report for the testpoints" + type: report + output_id: _testpoints + options: + template: testpoints