Skip to content
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

Automating library inspections and extracting information from them #3

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/scripts/README.md.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Altium-library

| Statistics | Libraries | Components |
|---|---|---|
| Schematic | {{libraries['schlibs']|length}} | {{libraries['schlibs']|get_total_comp}} |
| Pcb | {{libraries['pcblibs']|length}} | {{libraries['pcblibs']|get_total_comp}} |

## [Browse Libraries](https://{{get_webpage_subdomain()}}.github.io/{{get_webpage_path()}})
131 changes: 131 additions & 0 deletions .github/scripts/altium_lib_inspector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import os
from pathlib import Path
import json
import glob
import olefile
from jinja2 import Environment, FileSystemLoader, select_autoescape


def schlib_parse(input):
fullPath = input
ole = olefile.OleFileIO(fullPath)
components = []
for entry in ole.listdir(streams=True, storages=False):
if "Data" in entry:
stream = ole.openstream(entry)
params = stream.read()[5:-1]
pairs = params.split(b"|")
component = {}
model = {}
for pair in pairs:
data = pair.split(b"=")
keyword = data[0].decode("utf-8", "ignore").upper()
if keyword in [
"LIBREFERENCE",
"COMPONENTDESCRIPTION",
"MODELNAME",
"DESCRIPTION",
]:
if keyword in ["MODELNAME", "DESCRIPTION"]:
if "Models" not in component:
component["Models"] = []
if data[0].decode() in model:
component["Models"].append(dict(reversed(model.items())))
model.clear()
model[data[0].decode()] = data[1].decode("utf-8", "ignore")
else:
component[data[0].decode()] = data[1].decode("utf-8", "ignore")
if bool(model):
component["Models"].append(dict(reversed(model.items())))
components.append(component)
return components


def pcblib_parse(input):
fullPath = input
ole = olefile.OleFileIO(fullPath)
components = []
for entry in ole.listdir(streams=True, storages=False):
if "PARAMETERS" in [e.upper() for e in entry]:
stream = ole.openstream(entry)
params = stream.read()[5:-1]
pairs = params.split(b"|")
component = {}
for pair in pairs:
data = pair.split(b"=")
component[data[0].decode()] = data[1].decode("utf-8", "ignore")
components.append(component)
return components


def inspect_libraries():
libraries = {}
libraries["schlibs"] = {}
libraries["pcblibs"] = {}
schlib_path = "AltiumSCHLIB/"
for filepath in glob.iglob(schlib_path + "**/*.??????", recursive=True):
filename = Path(filepath).stem
if Path(filepath).suffix.lower() == ".schlib":
libraries["schlibs"][filename] = schlib_parse(filepath)
pcblib_path = "AltiumPCBLIB/"
for filepath in glob.iglob(pcblib_path + "**/*.??????", recursive=True):
filename = Path(filepath).stem
if Path(filepath).suffix.lower() == ".pcblib":
libraries["pcblibs"][filename] = pcblib_parse(filepath)
return libraries


def generate_json(libraries):
json_file = open("inspect_result.json", "w")
json.dump(libraries, json_file, indent=4)


def get_total_comp(libs):
sum = 0
for comps in libs.values():
sum = sum + len(comps)
return sum


def get_webpage_subdomain():
return os.environ["BROWSING_WEBPAGE_SUBDOMAIN"]


def get_webpage_path():
return os.environ["BROWSING_WEBPAGE_PATH"]


def render_template(libraries, file_path):
env = Environment(loader=FileSystemLoader("."), autoescape=select_autoescape())
env.filters["get_total_comp"] = get_total_comp
env.globals["get_webpage_subdomain"] = get_webpage_subdomain
env.globals["get_webpage_path"] = get_webpage_path
template_dir_path = (
Path(__file__).resolve().parent.relative_to(Path.cwd().as_posix()).as_posix()
+ "/"
)
template_file = env.get_template(template_dir_path + file_path)
return template_file.render(libraries=libraries)


def generate_readme(libraries):
readme = render_template(libraries, "README.md.template")
with open("README.md", "w") as readme_fhdl:
readme_fhdl.write(readme)


def generate_browsing_webpage(libraries):
browsing_webpage = render_template(libraries, "index.html.template")
with open("index.html", "w") as browsing_webpage_fhdl:
browsing_webpage_fhdl.write(browsing_webpage)


def main():
libraries = inspect_libraries()
generate_json(libraries)
generate_readme(libraries)
generate_browsing_webpage(libraries)


if __name__ == "__main__":
main()
108 changes: 108 additions & 0 deletions .github/scripts/index.html.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
ul, #CustomUL {
list-style-type: none;
}

#CustomUL {
margin: 0;
padding: 0;
}

.color_text{
color:blue;
}

.caret {
cursor: pointer;
-webkit-user-select: none; /* Safari 3.1+ */
-moz-user-select: none; /* Firefox 2+ */
-ms-user-select: none; /* IE 10+ */
user-select: none;
}

.caret::before {
content: "\25B6";
color: black;
display: inline-block;
margin-right: 6px;
}

.caret-down::before {
-ms-transform: rotate(90deg); /* IE 9 */
-webkit-transform: rotate(90deg); /* Safari */'
transform: rotate(90deg);
}

.nested {
display: none;
}

.active {
display: block;
}
</style>
</head>
<body>

<h2>Altium Libraries</h2>

{%for libType, libs in libraries.items() %}
{%if libType == 'schlibs' -%}
<ul id="CustomUL">
<li><span class="caret">Schematic libraries [ <code class="color_text">#libraries: {{libs|length}}</code> , <code class="color_text">#components : {{libs|get_total_comp}}</code> ]</span>
{% else -%}
<ul id="CustomUL">
<li><span class="caret">Pcb libraries [ <code class="color_text">#libraries: {{libs|length}}</code> , <code class="color_text">#components : {{libs|get_total_comp}}</code> ]</span>
{% endif -%}
<ul class="nested">
{%for libname, comps in libs.items() -%}
<li><span class="caret">{{libname}} [ <code class="color_text">#components : {{comps|length}}</code> ]</span>
<ul class="nested">
{%for comp in comps -%}
<li><span class="caret">{{ comp.values()|first }}</span>
<ul class="nested">
{%for comp_lbl, comp_val in comp.items() -%}
{%if loop.index > 1 -%}
{%if comp_lbl == 'Models' and comp_val.__class__.__name__ == 'list' -%}
<li><span class="caret">Models [ <code class="color_text">#models : {{comp_val|length}}</code> ]</span>
<ul class="nested">
{%for model in comp_val -%}
{%for model_lbl, model_val in model.items() -%}
<li>{{model_lbl}} : <code>{{model_val}}</code></li>
{% endfor -%}
{% endfor -%}
</ul>
</li>
{% else -%}
<li>{{comp_lbl}} : <code>{{comp_val}}</code></li>
{% endif -%}
{% endif -%}
{% endfor -%}
</ul>
</li>
{% endfor -%}
</ul>
</li>
{% endfor -%}
</ul>
</li>
{% endfor -%}

<script>
var toggler = document.getElementsByClassName("caret");
var i;

for (i = 0; i < toggler.length; i++) {
toggler[i].addEventListener("click", function() {
this.parentElement.querySelector(".nested").classList.toggle("active");
this.classList.toggle("caret-down");
});
}
</script>

</body>
</html>
2 changes: 2 additions & 0 deletions .github/scripts/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
olefile==0.46
Jinja2==3.1.4
42 changes: 42 additions & 0 deletions .github/workflows/altium_lib_inspector.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Altium Library Inspector

on:
push:
branches: ["main"]
pull_request:
branches: ["main"]

permissions:
contents: write

jobs:
build:
runs-on: ubuntu-latest
env:
BROWSING_WEBPAGE_SUBDOMAIN: ${{ github.repository_owner }}
BROWSING_WEBPAGE_REPO: ${{ github.repository }}
ACTIONS_ALLOW_UNSECURE_COMMANDS: "true"
steps:
- run: echo ::set-env name=BROWSING_WEBPAGE_PATH::$(echo $BROWSING_WEBPAGE_REPO | awk -F / '{print $2}')
shell: bash
- uses: actions/checkout@v4
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r .github/scripts/requirements.txt
- name: Run Altium Library Inspector
run: |
python .github/scripts/altium_lib_inspector.py
- name: Update README.md
run: |
if [[ "$(git status --porcelain)" != "" ]]; then
git config user.name "GitHub Action"
git config user.email "action@github.com"
git add .
git commit -m "Auto-update README.md"
git push
fi
37 changes: 8 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,8 @@
# Altium-Library
| Part name | Descrpition | Manufacturer | Part number | Parameters |
|-----------|-------------|--------------|-------------|------------|
|7SEG_1DIGIT_CA_GRN_7MM |7SEGMENT, 1DIGIT, common ANODE |Kingbright | ACSA02-41SGWA-F01 |20mA, 2.2v, -40~85oC
|7SEG_1DIGIT_CA_RED_5INCH |7SEGMENT, 1DIGIT, common ANODE |Kingbright | SA50-31SRWA, SA50-21EWA, SNS-50101BSR |20mA, -40~85oC 18.5~25VF
|7SEG_1DIGIT_CA_RED_7MM |7SEGMENT, 1DIGIT, common ANODE |Kingbright | ACSC02-41SURKWA-F01, ACSA02-41SURKWA-F01, ACSA02-41EWA-F01|30mA, 2v, -40~85oC
|7SEG_1DIGIT_CA_YLW_7MM |7SEGMENT, 1DIGIT, common ANODE |Kingbright | ACSA02-41YWA-F01 |20mA, 2.2v, -40~85oC
|7SEG_1DIGIT_CC_0.4INCH |7SEGMENT, 1DIGIT, common cathode |manf | manf_p# |
|7SEG_1DIGIT_CC_5611 |7SEGMENT, 1DIGIT, common cathode |manf | manf_p# |
|7SEG_1DIGIT_CC_GRN_7MM |7SEGMENT, 1DIGIT, common cathode |Kingbright | ACSC02-41SGWA-F01, ACSC02-41CGKWA-F01 |20mA, 2.2v, -40~85oC
|7SEG_2DIGIT_CA_BLU_0.2INCH |7SEGMENT, 2DIGIT, common Anode |Kingbright | ACDA02-41PBWA/A-F01 |20mA, 3.2V, -40~85oC
|7SEG_2DIGIT_CA_BLU_0.3INCH |7SEGMENT, 2DIGIT, common Anode |Kingbright | ACDA03-41PBWA/A-F01 |10~20mA, 2~2.2V, -40~85oC
|7SEG_2DIGIT_CA_GRN_0.2INCH |7SEGMENT, 2DIGIT, common Anode |Kingbright | ACDA02-41SGWA-F01 |10~20mA, 2~2.2V, -40~85oC
|7SEG_2DIGIT_CA_GRN_0.3INCH |7SEGMENT, 2DIGIT, common Anode |Kingbright | ACDA03-41SGWA-F01 |10~20mA, 2~2.2V, -40~85oC
|7SEG_2DIGIT_CA_GRN_0.3INCH_10 |7SEGMENT, 2DIGIT, common cathode |Kingbright | DA03-11GWA |10~20mA, 2~2.2V, -40~85oC
|7SEG_2DIGIT_CA_GRN_0.56inch |7SEGMENT, 2DIGIT, common Anode |Broadcom, Avago, Lite-On, Kingbright | HDSP-521G, LTD-6410G, DA56-11GWA |10~20mA, 2~2.2V, -35~85oC
|7SEG_2DIGIT_CA_RED_0.2INCH |7SEGMENT, 2DIGIT, common cathode |Kingbright | ACDA02-41EWA-F01, ACDA02-41SURKWA-F01 |10~20mA, 2~2.2V, -40~85oC
|7SEG_2DIGIT_CA_RED_0.3INCH |7SEGMENT, 2DIGIT, common Anode |Kingbright | ACDA03-41EWA-F01 |10~20mA, 2~2.2V, -40~85oC
|7SEG_2DIGIT_CA_RED_0.56inch |7SEGMENT, 2DIGIT, common Anode |Broadcom, Avago, Lite-On | HDSP-521E, LTD-6910HR, LTD-6710P |10~20mA, 2~2.2V, -35~85oC
|7SEG_2DIGIT_CA_YLW_0.3INCH |7SEGMENT, 2DIGIT, common Anode |Kingbright | ACDA03-41YWA-F01 |10~20mA, 2~2.2V, -40~85oC
|7SEG_2DIGIT_CC |7SEGMENT, 2DIGIT, common cathode |manf | manf_p# |
|7SEG_2DIGIT_CC_GRN_0.2INCH |7SEGMENT, 2DIGIT, common cathode |Kingbright | ACDC02-41SGWA-F01 |10~20mA, 2~2.2V, -40~85oC
|7SEG_2DIGIT_CC_GRN_0.56inch |7SEGMENT, 2DIGIT, common cathode |Broadcom, Avago | HDSP-523G |10~20mA, 2~2.2V, -35~85oC
|7SEG_2DIGIT_CC_RED_0.2INCH |7SEGMENT, 2DIGIT, common cathode |Kingbright | ACDC02-41SURKWA-F01 |10~20mA, 2~2.2V, -40~85oC
|7SEG_2DIGIT_CC_RED_0.3INCH_10 |7SEGMENT, 2DIGIT, common cathode |Kingbright | DC03-11EWA |10~20mA, 2~2.2V, -40~85oC
|7SEG_2DIGIT_CC_RED_0.56inch |7SEGMENT, 2DIGIT, common cathode |Broadcom, Avago | HDSP-523E |10~20mA, 2~2.2V, -35~85oC
|7SEG_3DIGIT_CC |7SEGMENT, 3DIGIT, common cathode |manf | manf_p# |
|7SEG_4DIGIT_CC |7SEGMENT, 4DIGIT, common cathode 5641 |manf | DPY-4CK |
|LED_MATRIX8X8 | |manf | manf_p# |
# Altium-library

| Statistics | Libraries | Components |
|---|---|---|
| Schematic | 205 | 5709 |
| Pcb | 96 | 3504 |

## [Browse Libraries](https://s0hey1.github.io/Altium-Library)
Loading