-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ID-707] First pass of BOM generation including Device Sheets for Altium projects. #182
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a test following the format in tests/test_utils.py
? You will have to create a repo in the https://hub.allspice.io/AllSpiceTests organization as a fixture.
Noting down some of the suggestions I made offline:
|
98ca0b5
to
e4c1164
Compare
e4c1164
to
aa1bd4e
Compare
Coverage SummaryTotal Project Coverage
Coverage by File
Diff CoverageDiff: origin/main...HEAD, staged and unstaged changes
Summary
Diff Coverage Detailsallspice/utils/list_components.pyLines 233-241 233 allspice_client.logger.info("Found %d SchDoc files", len(project_documents))
234 allspice_client.logger.info("Found %d Device Sheet files", len(device_sheets))
235
236 if not project_documents:
! 237 raise ValueError("No Project Documents found in the PrjPcb file.")
238
239 try:
240 annotations_data = _fetch_and_parse_annotation_file(repository, prjpcb_file, ref)
241 allspice_client.logger.info("Found annotations file, %d entries", len(annotations_data)) Lines 240-249 240 annotations_data = _fetch_and_parse_annotation_file(repository, prjpcb_file, ref)
241 allspice_client.logger.info("Found annotations file, %d entries", len(annotations_data))
242 except Exception as e:
243 if device_sheets:
! 244 allspice_client.logger.warning("Failed to fetch annotations file: %s", e)
! 245 allspice_client.logger.warning("Component designators may not be correct.")
246 annotations_data = {}
247
248 # Mapping of schdoc file paths from the project file to their JSON
249 schdoc_jsons: dict[str, dict] = {} Lines 978-986 978 designator = variation_details["Designator"]
979 unique_id = variation_details["UniqueId"]
980 kind = variation_details["Kind"]
981 except KeyError:
! 982 logger.warning(
983 "Designator, UniqueId, or Kind not found in details of variation "
984 f"{variation_details}; skipping this variation."
985 )
986 continue Lines 986-994 986 continue
987 try:
988 kind = VariationKind(int(variation_details["Kind"]))
989 except ValueError:
! 990 logger.warning(
991 f"Kind {variation_details['Kind']} of variation {variation_details} must be "
992 "either 0, 1 or 2; skipping this variation."
993 )
994 continue Lines 1006-1014 1006 except KeyError:
1007 # This can happen sometimes - Altium allows param variations
1008 # even when the component is not fitted, so we just log and
1009 # ignore.
! 1010 logger.warning(
1011 f"ParamVariation{variation_id} found for component {designator} either before "
1012 "the corresponding Variation or for a component that is not fitted.\n"
1013 "Ignoring this ParamVariation."
1014 ) Lines 1019-1027 1019 variation_details["ParameterName"],
1020 variation_details["VariantValue"],
1021 )
1022 except KeyError:
! 1023 logger.warning(
1024 f"ParameterName or VariantValue not found in ParamVariation{variation_id} "
1025 "details."
1026 )
1027 continue Lines 1103-1112 1103 ).casefold()
1104 project_repo_tree = _fetch_all_files_in_repo(project_repository)
1105 for filepath in project_repo_tree:
1106 if device_sheet_path_from_repo_root == filepath.casefold():
! 1107 logger.info("Found device sheet %s in project repository; using that.", device_sheet)
! 1108 return (
1109 project_repository,
1110 pathlib.PurePosixPath(filepath),
1111 ) Lines 1118-1126 1118 if device_sheet_name == file_path.name.casefold():
1119 matches.append((repo, file_path))
1120
1121 if len(matches) == 0:
! 1122 raise ValueError(
1123 f"No matching device sheet found for {device_sheet_path} in the design reuse "
1124 "repositories.",
1125 ) Lines 1185-1193 1185 raise Exception(
1186 f"Could not find annotation file {annotation_file_path} in repository {repository.url}."
1187 )
1188 if len(matches) > 1:
! 1189 raise Exception(
1190 f"Multiple matches found for annotation file {annotation_file_path} in repository "
1191 f"{repository.url} when checking case-insensitively: {matches}."
1192 ) Lines 1215-1224 1215 logical_designator = designator_manager_section[f"LogicalDesignator{change_number}"]
1216 physical_designator = designator_manager_section[f"PhysicalDesignator{change_number}"]
1217
1218 if unique_id in changes:
! 1219 repository.allspice_client.logger.warning("Multiple changes found for %s", unique_id)
! 1220 continue
1221
1222 changes[unique_id] = {"from": logical_designator, "to": physical_designator}
1223 change_number += 1 Lines 1262-1270 1262 annotation_for_component = None
1263 for id_to_test in ids_to_test:
1264 annotation_for_component = annotations_by_sheet.get(id_to_test)
1265 if annotation_for_component:
! 1266 break
1267
1268 if not annotation_for_component:
1269 logger.debug(
1270 "No annotation found for component %s by unique ID, trying by designator.", Lines 1357-1369 1357 """
1358
1359 try:
1360 annotate_section = prjpcb_ini["Annotate"]
! 1361 except KeyError:
! 1362 logger.warning(
1363 "Annotate section not found in PrjPcb; Designators of componets within Device Sheets may be incorrect."
1364 )
! 1365 return hierarchy
1366
1367 paths_to_documents: dict[str, list[str]] = {}
1368 document_index = 0 Lines 1422-1431 1422 for child in children:
1423 if child.kind == AltiumChildSheet.ChildSheetKind.DOCUMENT:
1424 # We don't need to change the IDs of documents - they're
1425 # already correct.
! 1426 final_children.append(child)
! 1427 continue
1428
1429 children_by_name.setdefault(child.name, []).append(child)
1430
1431 for child_name, children_of_name in children_by_name.items(): Lines 1434-1446 1434 child_name += ".SchDoc"
1435 paths_to_children = paths_to_documents.get(child_name, [])
1436
1437 if not paths_to_children:
! 1438 logger.warning(
1439 f"Could not find any paths for {child_name} in the PrjPcb file; skipping."
1440 )
! 1441 final_children.extend(children_of_name)
! 1442 continue
1443
1444 ids: set[str] = set()
1445 for path in paths_to_children:
1446 if not path.startswith(path_to_this_sheet): Lines 1449-1457 1449 path = path.removeprefix(path_to_this_sheet + "\\")
1450
1451 if "\\" in path:
1452 # This path is deeper in the hierarchy, we can't use it.
! 1453 continue
1454
1455 # Now the path is the UniqueID of the child sheet
1456 ids.add(path) |
61300211121,P2,Header_Male_1R_02P,1 | ||
61300211121,P5,Header_Male_1R_02P,1 | ||
LM2678SX-3.3,U1,CMP-0069-00188-2,1 | ||
SBR1045D1-13,D1,3c54d775813915f30481cfffa5e9369,1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one thing we might need to follow up on is that there are multiple "D1"s (for each of the sub-references).
Altium splits these definitions into "PhysicalDesignator" and "LogicalDesignator" (though it's not clear how this schema works to me).
This is probably fine for now, but we should add this to the list of things to come back to. Users might have issues.
Altium has an "Annotate Compiled Sheets" tool. I couldn't get it to work. @polypour is this what you were working with? Did you generate a BOM we can compare to?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is part of what @polypour was referring to when he mentioned that he wasn't able to re-number all the references. I can re-generate the BOM if/when we figure that out and see what we get!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, agreed. Unfortunately, I suspect that it's not going to be as simple as updating the reference designators in the Altium test design and having that produce the same BOM output as Altium.
Since the device sheets are shared between multiple "parent" projects, the designators in the sub-sheets can't be shared in all of those parent instances (there will always be the potential for collisions). EITHER, the designators are mapped from the sub-sheet to the parent sheet (which is what I think the .Annotation
file does) OR there is some suffix appended.
That seems to be indicated here: https://www.altium.com/documentation/altium-designer/device-sheets#annotating-compiled-device-sheets#annotating-compiled-device-sheets
As discussed, we need to continue with what we have to get some feedback on the initial implementation, but I'll create a ticket to come back to this.
Also, I suspect my inability to generate the annotation output is either a bug in Altium or because I'm running in parallels. I'm seeing other oddities too (like not being able to create and update a PCB). @polypour are you running on native Windows?
Also, tagging @McRaeAlex as a reviewer since I've also contributed to this PR. |
Missed this in my commit but |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some questions around case-sensitivity & variable names, but otherwise looks great to me.
Next steps:
- Can device sheets reference other device sheets? I expect so. Perhaps these needs to become recursive.
- We should update to allow reuse_repos to be defined in assemblies.yaml
- We should follow-up on designator generation using an
.annotations
file - Make similar capability work for DSN & sdax
Anything else?
allspice/utils/list_components.py
Outdated
@@ -368,57 +451,109 @@ def _resolve_prjpcb_relative_path(schdoc_path: str, prjpcb_path: str) -> str: | |||
|
|||
|
|||
def _build_schdoc_hierarchy( | |||
sheets_to_refs: dict[str, list[dict]], | |||
document_jsons: dict[str, dict], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We say document
here, but I since we are expecting these all to be schematics we should change schematic_jsons
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Device Sheets are also technically schematics, which is why the distinction is between Document
as in the project and DeviceSheet
as in the project, but I can rename these to be schematic_documents to make that clearer.
Re: the questions:
Yes, and this is handled - in the hierarchy building function we go through refs in the device sheets as well.
I brought this up when we were discussing the proposal too, and we need to think about how this is defined in generate-bom which also needs an update to handle this. I'll make that change when this is through.
This is non-trivial because we currently do not parse or export sheet references in DSN, so it will also take backend effort. |
Missed in the previous rounds. Co-authored-by: Kyle Dumont <[email protected]>
Avoids a breaking change in case of positional use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please update the PR description to be up to date, it seems some configuration stuff has been removed / changed.
for value in device_sheet_json.values() | ||
if isinstance(value, dict) and value.get("type") == "Component" | ||
] | ||
sheets_to_components[device_sheet_name] = device_sheet_components |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am unfamiliar with device sheets, is there every a situation where device_sheet_name may overwrite a schdoc_file in sheets_to_components?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There shouldn't be, because the schdoc files are paths while device sheets are names. Theoretically it is possible but in the same situation Altium would also have difficulty identifying which sheet it is using. Might be worth testing @polypour.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Note: we tested this out in Altium and Altium also chokes in this case - it thinks the project document is the device sheet of the same name. Given that this is unexpected behaviour, we're not supporting it.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shrik450 comment above is true. Altium identifies device sheets by name, primarily. I've tried including multiple folders with the same device sheets under different directory nestings with the same names and it only picks up the first copy seen.
This is required for later changes to support Annotations, as we need to know which component of which sheet has to be annotated. This change does not have any functional implications.
Currently does not work with Device Sheets, as sheet reference Unique IDs are changed for device sheets when used in a project.
In some cases, component IDs on device sheets are not unique for a project, so Altium re-maps their Unique IDs to something else. This mapping isn't clearly present in a single location, so this commit adds two levels of fallbacks for annotations: 1. A potential UniqueID from the PrjPcb's UniqueIDMapping section, which may not have all correct UniqueIDs for the component; and 2. The sheet ID and designator, where we fail if there are multiple possible annotations for a sheet ID x designator pairing
Self-approved to clear my request for changes - please ignore that! |
[ID-730] Parse and use .Annotation file for correct designators on Device Sheet Components
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
I've bumped the version and changelog in this repo so we can tag a release as soon as we merge this 👍 |
Reviewed by Shrikanth, Jack, Kyle, Gautam. Tested with .Annotations file support with repetitions and hierarchies, cross checking against UniqueIds.
Stress tested and validated locally and merged. Thank you @shrik450 and @kdumontnu. 🙏 |
Adds support for Device Sheets in Altium Projects when listing components or generating BOMs. Device Sheets are sheets external to the project that are references in it. The method for reading them involves either finding them in the given repo but outside the project (as in the case of a monorepo) or the user supplying a list of design reuse repositories which are scanned for the device sheet.
The components generated from device sheets usually have designators that are not very useful - the follow up PR #183 fixes that.
PR #183 was merged into this branch and this PR (#182) completes the Altium Device Sheet support for design reuse including the usage of board level annotations as applied by .Annotation files.
Outdated
Overall strategy for finding Device Sheets in an external repository: