Skip to content

Commit

Permalink
Rename module to footprint everywhere
Browse files Browse the repository at this point in the history
This follows the respective change in KiCad API
Module never made much sense anyway.

Contains recent nightly compatibility fixes due to renaming.
  • Loading branch information
qu1ck committed Nov 19, 2020
1 parent df2f0dd commit 43e5034
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 104 deletions.
2 changes: 1 addition & 1 deletion DATAFORMAT.md
Expand Up @@ -31,7 +31,7 @@ pcbdata = {
// Describes footprints.
// See footprint structure description below.
// index of entry corresponds to component's numeric ID
"modules": [
"footprints": [
footprint1,
footprint2,
...
Expand Down
26 changes: 13 additions & 13 deletions InteractiveHtmlBom/core/ibom.py
Expand Up @@ -88,11 +88,11 @@ def skip_component(m, config, extra_data):
return False


def generate_bom(pcb_modules, config, extra_data):
def generate_bom(pcb_footprints, config, extra_data):
# type: (list, Config, dict) -> dict
"""
Generate BOM from pcb layout.
:param pcb_modules: list of modules on the pcb
:param pcb_footprints: list of footprints on the pcb
:param config: Config object
:param extra_data: Extra fields data
:return: dict of BOM tables (qty, value, footprint, refs) and dnp components
Expand All @@ -116,30 +116,30 @@ def natural_sort(l):
warning_shown = False
skipped_components = []
part_groups = {}
for i, m in enumerate(pcb_modules):
if skip_component(m, config, extra_data):
for i, f in enumerate(pcb_footprints):
if skip_component(f, config, extra_data):
skipped_components.append(i)
continue

# group part refs by value and footprint
norm_value = units.componentValue(m.val)
norm_value = units.componentValue(f.val)

extras = []
if config.extra_fields:
if m.ref in extra_data:
extras = [extra_data[m.ref].get(f, '')
if f.ref in extra_data:
extras = [extra_data[f.ref].get(f, '')
for f in config.extra_fields]
else:
# Some components are on pcb but not in schematic data.
# Show a warning about possibly outdated netlist/xml file.
log.warn(
'Component %s is missing from schematic data.' % m.ref)
'Component %s is missing from schematic data.' % f.ref)
warning_shown = True
extras = [''] * len(config.extra_fields)

group_key = (norm_value, tuple(extras), m.footprint, m.attr)
valrefs = part_groups.setdefault(group_key, [m.val, []])
valrefs[1].append((m.ref, i))
group_key = (norm_value, tuple(extras), f.footprint, f.attr)
valrefs = part_groups.setdefault(group_key, [f.val, []])
valrefs[1].append((f.ref, i))

if warning_shown:
log.warn('Netlist/xml file is likely out of date.')
Expand Down Expand Up @@ -174,7 +174,7 @@ def sort_func(row):
filtered_table = []
for row in bom_table:
filtered_refs = [ref for ref in row[3]
if pcb_modules[ref[1]].layer == layer]
if pcb_footprints[ref[1]].layer == layer]
if filtered_refs:
filtered_table.append((len(filtered_refs), row[1],
row[2], filtered_refs, row[4]))
Expand Down Expand Up @@ -300,7 +300,7 @@ def main(parser, config, logger):
extra_fields = extra_fields[1] if extra_fields else None

pcbdata, components = parser.parse()
if not pcbdata or not components:
if not pcbdata and not components:
raise ParsingException('Parsing failed.')

pcbdata["bom"] = generate_bom(components, config, extra_fields)
Expand Down
14 changes: 7 additions & 7 deletions InteractiveHtmlBom/ecad/easyeda.py
Expand Up @@ -363,7 +363,7 @@ def parse_lib(self, shape):
# if bounding box is not calculated yet set it to 100x100 mil square
bbox.add_rectangle(x, y, 10, 10, 0)

module_json = {
footprint_json = {
"ref": ref,
"center": [x, y],
"bbox": bbox.to_component_dict(),
Expand All @@ -374,11 +374,11 @@ def parse_lib(self, shape):

component = Component(ref, val, footprint, fp_layer)

return fp_layer, component, module_json, extra_drawings
return fp_layer, component, footprint_json, extra_drawings

def parse_shapes(self, shapes):
drawings = {}
modules = []
footprints = []
components = []

for shape_str in shapes:
Expand All @@ -400,10 +400,10 @@ def parse_shapes(self, shapes):
layer, component, json, extras = self.parse_lib(shape[1])
for drawing_layer, drawing in extras:
drawings.setdefault(drawing_layer, []).append(drawing)
modules.append(json)
footprints.append(json)
components.append(component)

return drawings, modules, components
return drawings, footprints, components

def get_metadata(self, pcb):
if hasattr(pcb, 'metadata'):
Expand All @@ -430,7 +430,7 @@ def parse(self):
' does not appear to be valid EasyEDA json file.')
return None, None

drawings, modules, components = self.parse_shapes(pcb['shape'])
drawings, footprints, components = self.parse_shapes(pcb['shape'])

board_outline_bbox = BoundingBox()
for drawing in drawings.get(self.BOARD_OUTLINE_LAYER, []):
Expand Down Expand Up @@ -459,7 +459,7 @@ def parse(self):
'F': drawings.get(self.TOP_ASSEMBLY_LAYER, []),
'B': drawings.get(self.BOT_ASSEMBLY_LAYER, []),
},
"modules": modules,
"footprints": footprints,
"metadata": self.get_metadata(pcb),
"bom": {},
"font_data": {}
Expand Down
77 changes: 43 additions & 34 deletions InteractiveHtmlBom/ecad/kicad.py
Expand Up @@ -17,6 +17,10 @@ def __init__(self, file_name, config, logger, board=None):
self.board = board
if self.board is None:
self.board = pcbnew.LoadBoard(self.file_name) # type: pcbnew.BOARD
if hasattr(self.board, 'GetModules'):
self.footprints = list(self.board.GetModules())
else:
self.footprints = list(self.board.GetFootprints())
self.font_parser = FontParser()
self.extra_data_func = parse_schematic_data

Expand Down Expand Up @@ -88,8 +92,12 @@ def parse_shape(self, d):
self.logger.info("Polygons not supported for KiCad 4, skipping")
return None
angle = 0
if d.GetParentModule() is not None:
angle = d.GetParentModule().GetOrientation() * 0.1,
if hasattr(d, 'GetParentModule'):
parent_footprint = d.GetParentModule()
else:
parent_footprint = d.GetParentFootprint()
if parent_footprint is not None:
angle = parent_footprint.GetOrientation() * 0.1,
return {
"type": shape,
"pos": start,
Expand Down Expand Up @@ -180,7 +188,7 @@ def parse_edges(self, pcb):
edges = []
drawings = list(pcb.GetDrawings())
bbox = None
for m in pcb.GetModules():
for m in self.footprints:
for g in m.GraphicalItems():
drawings.append(g)
for d in drawings:
Expand Down Expand Up @@ -220,7 +228,7 @@ def parse_drawings_on_layers(self, drawings, f_layer, b_layer):

def get_all_drawings(self):
drawings = [(d.GetClass(), d) for d in list(self.board.GetDrawings())]
for m in self.board.GetModules():
for m in self.footprints:
drawings.append(("ref", m.Reference()))
drawings.append(("val", m.Value()))
for d in m.GraphicalItems():
Expand Down Expand Up @@ -296,27 +304,30 @@ def parse_pad(self, pad):

return pad_dict

def parse_modules(self, pcb_modules):
def parse_footprints(self):
# type: (list) -> list
modules = []
for m in pcb_modules: # type: pcbnew.MODULE
ref = m.GetReference()
footprints = []
for f in self.footprints:
ref = f.GetReference()

# bounding box
m_copy = pcbnew.MODULE(m)
m_copy.SetOrientation(0)
m_copy.SetPosition(pcbnew.wxPoint(0, 0))
mrect = m_copy.GetFootprintRect()
if hasattr(pcbnew, 'MODULE'):
f_copy = pcbnew.MODULE(f)
else:
f_copy = pcbnew.FOOTPRINT(f)
f_copy.SetOrientation(0)
f_copy.SetPosition(pcbnew.wxPoint(0, 0))
mrect = f_copy.GetFootprintRect()
bbox = {
"pos": self.normalize(m.GetPosition()),
"pos": self.normalize(f.GetPosition()),
"relpos": self.normalize(mrect.GetPosition()),
"size": self.normalize(mrect.GetSize()),
"angle": m.GetOrientation() * 0.1,
"angle": f.GetOrientation() * 0.1,
}

# graphical drawings
drawings = []
for d in m.GraphicalItems():
for d in f.GraphicalItems():
# we only care about copper ones, silkscreen is taken care of
if d.GetLayer() not in [pcbnew.F_Cu, pcbnew.B_Cu]:
continue
Expand All @@ -330,7 +341,7 @@ def parse_modules(self, pcb_modules):

# footprint pads
pads = []
for p in m.Pads():
for p in f.Pads():
pad_dict = self.parse_pad(p)
if pad_dict is not None:
pads.append((p.GetPadName(), pad_dict))
Expand All @@ -350,19 +361,19 @@ def parse_modules(self, pcb_modules):

pads = [p[1] for p in pads]

# add module
modules.append({
# add footprint
footprints.append({
"ref": ref,
"bbox": bbox,
"pads": pads,
"drawings": drawings,
"layer": {
pcbnew.F_Cu: "F",
pcbnew.B_Cu: "B"
}.get(m.GetLayer())
}.get(f.GetLayer())
})

return modules
return footprints

def parse_tracks(self, tracks):
result = {pcbnew.F_Cu: [], pcbnew.B_Cu: []}
Expand Down Expand Up @@ -433,28 +444,27 @@ def parse_netlist(net_info):
return nets

@staticmethod
def module_to_component(module):
# type: (pcbnew.MODULE) -> Component
def footprint_to_component(footprint):
try:
footprint = str(module.GetFPID().GetFootprintName())
footprint_name = str(footprint.GetFPID().GetFootprintName())
except AttributeError:
footprint = str(module.GetFPID().GetLibItemName())
footprint_name = str(footprint.GetFPID().GetLibItemName())

attr = 'Normal'
if hasattr(pcbnew, 'MOD_EXCLUDE_FROM_BOM'):
if module.GetAttributes() & pcbnew.MOD_EXCLUDE_FROM_BOM:
if footprint.GetAttributes() & pcbnew.MOD_EXCLUDE_FROM_BOM:
attr = 'Virtual'
elif hasattr(pcbnew, 'MOD_VIRTUAL'):
if module.GetAttributes() == pcbnew.MOD_VIRTUAL:
if footprint.GetAttributes() == pcbnew.MOD_VIRTUAL:
attr = 'Virtual'
layer = {
pcbnew.F_Cu: 'F',
pcbnew.B_Cu: 'B',
}.get(module.GetLayer())
}.get(footprint.GetLayer())

return Component(module.GetReference(),
module.GetValue(),
footprint,
return Component(footprint.GetReference(),
footprint.GetValue(),
footprint_name,
layer,
attr)

Expand All @@ -473,7 +483,7 @@ def parse(self):
edges, bbox = self.parse_edges(self.board)
if bbox is None:
self.logger.error('Please draw pcb outline on the edges '
'layer on sheet or any module before '
'layer on sheet or any footprint before '
'generating BOM.')
return None, None
bbox = {
Expand All @@ -483,7 +493,6 @@ def parse(self):
"maxy": bbox.GetBottom() * 1e-6,
}

pcb_modules = list(self.board.GetModules())
drawings = self.get_all_drawings()

pcbdata = {
Expand All @@ -493,7 +502,7 @@ def parse(self):
drawings, pcbnew.F_SilkS, pcbnew.B_SilkS),
"fabrication": self.parse_drawings_on_layers(
drawings, pcbnew.F_Fab, pcbnew.B_Fab),
"modules": self.parse_modules(pcb_modules),
"footprints": self.parse_footprints(),
"metadata": {
"title": title,
"revision": title_block.GetRevision(),
Expand All @@ -512,7 +521,7 @@ def parse(self):
pcbdata["zones"] = {'F': [], 'B': []}
if self.config.include_nets and hasattr(self.board, "GetNetInfo"):
pcbdata["nets"] = self.parse_netlist(self.board.GetNetInfo())
components = [self.module_to_component(m) for m in pcb_modules]
components = [self.footprint_to_component(f) for f in self.footprints]

return pcbdata, components

Expand Down

0 comments on commit 43e5034

Please sign in to comment.