Compare commits
13 Commits
0.1.0
...
feature/upload
| Author | SHA1 | Date | |
|---|---|---|---|
| 4c08e18ef9 | |||
| a39b65c94c | |||
| a6d1999839 | |||
| c7cc47718d | |||
| b801028d63 | |||
| 959c2110c9 | |||
| 54cdea9c33 | |||
| 08b6895ea3 | |||
| 647d8aaec2 | |||
| a84c8e4d83 | |||
| 966f96cf7e | |||
| f46f57d36d | |||
| 5fa84df594 |
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,19 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="ignoredErrors">
|
||||
<list>
|
||||
<option value="N801" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredIdentifiers">
|
||||
<list>
|
||||
<option value="bpy" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/KiCadJLCplugin.iml" filepath="$PROJECT_DIR$/.idea/KiCadJLCplugin.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="81624dc4-41ca-48ac-93b8-92da00936c57" name="Changes" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/plugins/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/plugins/__init__.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/plugins/config.py" beforeDir="false" afterPath="$PROJECT_DIR$/plugins/config.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/plugins/plugin.py" beforeDir="false" afterPath="$PROJECT_DIR$/plugins/plugin.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/plugins/result_event.py" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/plugins/thread.py" beforeDir="false" afterPath="$PROJECT_DIR$/plugins/thread.py" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectId" id="2C7tSUh2zYdb8tYB6kgwqDOifTc" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
||||
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
|
||||
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="81624dc4-41ca-48ac-93b8-92da00936c57" name="Changes" comment="" />
|
||||
<created>1658165450946</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1658165450946</updated>
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"Drilland",
|
||||
"EXCELLON",
|
||||
"FPID",
|
||||
"LCSC",
|
||||
"netlist",
|
||||
"pcbnew",
|
||||
"Plotfile",
|
||||
"Protel",
|
||||
"Soldermask"
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,12 @@
|
||||
# JLC PCB Plug-in for KiCad
|
||||
<img src="https://github.com/bennymeg/JLC-Plugin-for-KiCad/blob/master/assets/logo.svg?raw=true"
|
||||
style="display:block margin-left: auto; margin-right: auto;" alt="JLC PCB Plug-in for KiCad">
|
||||
|
||||
<div align="center">
|
||||
|
||||
| **JLC PCB Plug-in for KiCad** |
|
||||
|:-----:|
|
||||
|
||||
</div>
|
||||
|
||||
## Features
|
||||
1. Generates gerber files in correct format for production
|
||||
@@ -9,18 +17,26 @@
|
||||
## Installation
|
||||
|
||||
### Official Installation
|
||||
Open the "Plugin and Content Manager" from the KiCad main menu an install the "JLC Plugin for KiCad" plugin from the selection list.
|
||||
Open the "Plugin and Content Manager" from the KiCad main menu an install the "<ins>Fabrication Toolkit</ins>" plugin from the selection list.
|
||||
|
||||
### Manual installation
|
||||
Download the latest ZIP file from https://github.com/bennymeg/JLC-Plugin-for-KiCad. Open the "Plugin and Content Manager" from the KiCads main window and install the ZIP file via "Install from File".
|
||||
|
||||
## Options
|
||||
|
||||
### Component Part Number
|
||||
Add 'MPN' field with the LCSC component part number to the footprint component options.
|
||||
### Include Component Part Number in Production Files
|
||||
Add an 'MPN'* field with the LCSC component part number to the symbol's fields property.
|
||||
|
||||
<img src="https://github.com/bennymeg/JLC-Plugin-for-KiCad/blob/master/assets/mpn.png?raw=true" height=420>
|
||||
|
||||
#### Similar Fields*:
|
||||
|'mpn' | 'Mpn' | 'MPN' | 'JLC_MPN' | 'LCSC_MPN' | 'LCSC Part #' | 'JLC' | 'LCSC'|
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
|
||||
### Ignore Footprint in Production Files
|
||||
Select 'Exclude from position files' or 'Exclude from BOM' in the footprint component options to ignore te footprint from the relevant file.
|
||||
Select 'Exclude from position files' or 'Exclude from BOM' in the symbol's attributes property in order to ignore the footprint from the relevant file.
|
||||
|
||||
<img src="https://github.com/bennymeg/JLC-Plugin-for-KiCad/blob/master/assets/attributes.png?raw=true" height=420>
|
||||
|
||||
## Author
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 86 KiB |
@@ -0,0 +1,183 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="1300"
|
||||
height="136.763"
|
||||
id="svg3509"
|
||||
version="1.1"
|
||||
inkscape:version="1.2 (dc2aedaf03, 2022-05-15)"
|
||||
sodipodi:docname="Fabrication Toolkit Logo.svg"
|
||||
inkscape:export-filename="/home/fabrizio/Desktop/kicad_logo2.png"
|
||||
inkscape:export-xdpi="130.52866"
|
||||
inkscape:export-ydpi="130.52866"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs3511">
|
||||
<rect
|
||||
x="979.28571"
|
||||
y="180.33443"
|
||||
width="132.14286"
|
||||
height="193.57143"
|
||||
id="rect2617" />
|
||||
<rect
|
||||
x="590.71429"
|
||||
y="-28.951285"
|
||||
width="167.14286"
|
||||
height="187.85714"
|
||||
id="rect2611" />
|
||||
<rect
|
||||
x="176.42857"
|
||||
y="10.334429"
|
||||
width="1260.7143"
|
||||
height="265.71428"
|
||||
id="rect227" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.98994949"
|
||||
inkscape:cx="687.91388"
|
||||
inkscape:cy="158.08887"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="text225"
|
||||
showgrid="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1002"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-grids="false"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:snap-to-guides="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1" />
|
||||
<metadata
|
||||
id="metadata3514">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-40.547253,-883.62329)">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#314cb0;fill-opacity:1;fill-rule:nonzero;stroke:#1d2d68;stroke-width:4.85049;stroke-miterlimit:4;stroke-opacity:1"
|
||||
d="m 1056.9425,902.1018 h 114.392 c 0.5127,0 0.9255,0.43179 0.9255,0.96814 v 109.79556 c 0,0.5364 -0.4128,0.9682 -0.9255,0.9682 h -114.392 c -0.5128,0 -0.9255,-0.4318 -0.9255,-0.9682 V 903.06994 c 0,-0.53635 0.4127,-0.96814 0.9255,-0.96814 z"
|
||||
id="rect3438-4-1-6-9-8-4" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3008"
|
||||
style="font-style:normal;font-weight:normal;font-size:120.794px;line-height:122%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none"
|
||||
d="m 1085.5333,948.38598 16.9276,-21.41018 c 3.4602,-4.36453 5.1903,-7.62815 5.1904,-9.79088 -10e-5,-0.78633 -0.098,-1.41546 -0.2949,-1.8874 h 29.5495 c -2.2413,1.25835 -5.0528,3.91251 -8.4343,7.96246 -0.9044,1.06175 -2.4969,3.00812 -4.7774,5.83914 l -22.177,27.60321 26.4826,36.45038 c 1.6121,2.20197 3.6567,4.67918 6.134,7.43169 0.6684,0.7078 1.6318,1.5532 2.8901,2.5362 h -30.3163 c 0.2358,-0.9044 0.3538,-1.7105 0.3539,-2.4183 -10e-5,-2.16264 -1.4943,-5.28864 -4.4826,-9.37801 l -17.0456,-23.23859 v 23.5335 c 0,5.4656 1.101,9.2994 3.303,11.5014 h -27.7212 c 1.5335,-1.5335 2.5165,-3.28335 2.9491,-5.24939 0.2359,-1.10098 0.3538,-3.16532 0.3538,-6.19303 v -64.9383 c 0,-3.02763 -0.1179,-5.09197 -0.3538,-6.19303 -0.4326,-1.96596 -1.4156,-3.71573 -2.9491,-5.24933 h 27.7212 c -2.202,2.20205 -3.303,6.01617 -3.303,11.44236 v 21.6461" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3010"
|
||||
style="font-style:normal;font-weight:normal;font-size:120.794px;line-height:122%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none"
|
||||
d="m 1164.7451,938.5951 v 54.14474 c -1e-4,2.83111 0.079,4.67918 0.2359,5.54423 0.3145,1.76943 1.1403,3.38163 2.4772,4.83653 h -25.9517 c 1.3369,-1.4549 2.1626,-3.0671 2.4772,-4.83653 0.1573,-0.86505 0.2359,-2.71312 0.2359,-5.54423 v -43.88201 c 0,-2.83104 -0.079,-4.65946 -0.2359,-5.48526 -0.3146,-1.73005 -1.1207,-3.32254 -2.4182,-4.77747 h 23.1796 m -10.2628,-30.84717 c 3.2636,9e-5 6.0358,1.16006 8.3164,3.47989 2.3199,2.2807 3.4798,5.05281 3.4799,8.31635 -1e-4,3.34235 -1.1404,6.15378 -3.4209,8.43431 -2.2414,2.24136 -5.0331,3.362 -8.3754,3.36193 -3.2636,7e-5 -6.0554,-1.14023 -8.3753,-3.42091 -2.2806,-2.31985 -3.4209,-5.11162 -3.4209,-8.37533 0,-3.34218 1.1206,-6.13396 3.3619,-8.37533 2.2806,-2.28051 5.0921,-3.42082 8.4343,-3.42091" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#314cb0;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1140.5539,906.77745 h 28.3151 v 27.03082 h -28.3151 z"
|
||||
id="rect4352-5-1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ff7700;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1166.4321,902.13073 c 0,6.60244 -5.3681,11.95472 -11.9901,11.95472 -6.622,0 -11.9902,-5.35228 -11.9902,-11.95472 0,-6.60244 5.3682,-11.9548 11.9902,-11.9548 6.622,0 11.9901,5.35236 11.9901,11.9548 z"
|
||||
id="path3552-6-3-7" />
|
||||
<g
|
||||
aria-label="Fabrication Tool t"
|
||||
transform="translate(-30.187122,883.52127)"
|
||||
id="text225"
|
||||
style="font-size:120px;line-height:1.25;white-space:pre;shape-inside:url(#rect227);fill:#1b2b63">
|
||||
<path
|
||||
d="m 234.61133,51.200341 h -29.64844 v 20.625 h 27.24609 V 87.176904 H 204.96289 V 119.81362 H 186.03711 V 35.790185 h 48.57422 z"
|
||||
style="font-weight:bold;font-family:'Segoe UI';-inkscape-font-specification:'Segoe UI Bold'"
|
||||
id="path2671" />
|
||||
<path
|
||||
d="m 292.9707,119.81362 h -17.51953 v -8.61328 h -0.23437 q -6.03516,10.07813 -17.8711,10.07813 -8.73047,0 -13.76953,-4.92188 -4.98047,-4.98047 -4.98047,-13.24219 0,-17.460934 20.6836,-20.156246 l 16.28906,-2.167969 q 0,-9.84375 -10.66406,-9.84375 -10.72266,0 -20.39063,6.386719 V 63.387841 q 3.86719,-1.992187 10.54688,-3.515625 6.73828,-1.523437 12.24609,-1.523437 25.66406,0 25.66406,25.605468 z M 275.56836,95.438622 v -4.042968 l -10.89844,1.40625 q -9.02344,1.171875 -9.02344,8.144526 0,3.16407 2.16797,5.21485 2.22657,1.99219 5.97657,1.99219 5.21484,0 8.49609,-3.57422 3.28125,-3.63282 3.28125,-9.140628 z"
|
||||
style="font-weight:bold;font-family:'Segoe UI';-inkscape-font-specification:'Segoe UI Bold'"
|
||||
id="path2673" />
|
||||
<path
|
||||
d="m 326.36914,112.84097 h -0.23437 v 6.97265 H 307.61914 V 30.985497 h 18.51563 V 68.83706 h 0.23437 q 6.85547,-10.488281 19.51172,-10.488281 11.60156,0 17.87109,7.96875 6.26953,7.96875 6.26953,21.796875 0,14.999996 -7.32421,24.082026 -7.32422,9.08204 -19.57032,9.08204 -11.07422,0 -16.75781,-8.4375 z M 325.8418,87.528466 v 6.152344 q 0,5.800781 3.33984,9.60937 3.33984,3.8086 8.55469,3.8086 6.32812,0 9.78515,-4.86328 3.51563,-4.921878 3.51563,-13.886721 0,-7.441407 -3.22266,-11.601563 -3.16406,-4.21875 -9.08203,-4.21875 -5.5664,0 -9.25781,4.160156 -3.63281,4.160157 -3.63281,10.839844 z"
|
||||
style="font-weight:bold;font-family:'Segoe UI';-inkscape-font-specification:'Segoe UI Bold'"
|
||||
id="path2675" />
|
||||
<path
|
||||
d="m 421.17383,76.512841 q -3.33985,-1.816406 -7.79297,-1.816406 -6.03516,0 -9.43359,4.453125 -3.39844,4.394531 -3.39844,12.011719 V 119.81362 H 382.0332 V 59.813622 h 18.51563 v 11.132813 h 0.23437 q 4.39453,-12.1875 15.82032,-12.1875 2.92968,0 4.57031,0.703125 z"
|
||||
style="font-weight:bold;font-family:'Segoe UI';-inkscape-font-specification:'Segoe UI Bold'"
|
||||
id="path2677" />
|
||||
<path
|
||||
d="m 439.63086,50.321435 q -4.6875,0 -7.67578,-2.753906 -2.98828,-2.8125 -2.98828,-6.855469 0,-4.160156 2.98828,-6.796875 2.98828,-2.636719 7.67578,-2.636719 4.74609,0 7.67578,2.636719 2.98828,2.636719 2.98828,6.796875 0,4.21875 -2.98828,6.914062 -2.92969,2.695313 -7.67578,2.695313 z m 9.14062,69.492185 H 430.25586 V 59.813622 h 18.51562 z"
|
||||
style="font-weight:bold;font-family:'Segoe UI';-inkscape-font-specification:'Segoe UI Bold'"
|
||||
id="path2679" />
|
||||
<path
|
||||
d="m 509.82617,117.64565 q -6.26953,3.63282 -18.10547,3.63282 -13.82812,0 -22.38281,-8.37891 -8.55469,-8.37891 -8.55469,-21.621094 0,-15.292969 9.14063,-24.082031 9.19922,-8.847656 24.55078,-8.847656 10.60547,0 15.35156,2.8125 v 15.703125 q -5.80078,-4.335938 -12.94922,-4.335938 -7.96875,0 -12.65625,4.6875 -4.6289,4.628906 -4.6289,12.832031 0,7.96875 4.45312,12.539063 4.45313,4.51172 12.2461,4.51172 6.91406,0 13.53515,-4.33594 z"
|
||||
style="font-weight:bold;font-family:'Segoe UI';-inkscape-font-specification:'Segoe UI Bold'"
|
||||
id="path2681" />
|
||||
<path
|
||||
d="m 571.87695,119.81362 h -17.51953 v -8.61328 h -0.23437 q -6.03516,10.07813 -17.8711,10.07813 -8.73047,0 -13.76953,-4.92188 -4.98047,-4.98047 -4.98047,-13.24219 0,-17.460934 20.6836,-20.156246 l 16.28906,-2.167969 q 0,-9.84375 -10.66406,-9.84375 -10.72266,0 -20.39063,6.386719 V 63.387841 q 3.86719,-1.992187 10.54688,-3.515625 6.73828,-1.523437 12.24609,-1.523437 25.66406,0 25.66406,25.605468 z M 554.47461,95.438622 v -4.042968 l -10.89844,1.40625 q -9.02344,1.171875 -9.02344,8.144526 0,3.16407 2.16797,5.21485 2.22657,1.99219 5.97657,1.99219 5.21484,0 8.49609,-3.57422 3.28125,-3.63282 3.28125,-9.140628 z"
|
||||
id="path2683" />
|
||||
<path
|
||||
d="m 622.79492,119.1105 q -4.10156,2.16797 -12.36328,2.16797 -19.57031,0 -19.57031,-20.33204 V 73.465966 h -9.72656 V 59.813622 h 9.72656 V 46.864404 l 18.45703,-5.273438 v 18.222656 h 13.47656 v 13.652344 h -13.47656 v 24.257813 q 0,9.375001 7.44141,9.375001 2.92968,0 6.03515,-1.69922 z"
|
||||
id="path2685" />
|
||||
<path
|
||||
d="m 642.59961,50.321435 q -4.6875,0 -7.67578,-2.753906 -2.98828,-2.8125 -2.98828,-6.855469 0,-4.160156 2.98828,-6.796875 2.98828,-2.636719 7.67578,-2.636719 4.74609,0 7.67578,2.636719 2.98828,2.636719 2.98828,6.796875 0,4.21875 -2.98828,6.914062 -2.92969,2.695313 -7.67578,2.695313 z m 9.14062,69.492185 H 633.22461 V 59.813622 h 18.51562 z"
|
||||
id="path2687" />
|
||||
<path
|
||||
d="m 695.91992,121.27847 q -15,0 -23.61328,-8.37891 -8.55469,-8.4375 -8.55469,-22.851563 0,-14.882812 8.90625,-23.261718 8.90625,-8.4375 24.08203,-8.4375 14.94141,0 23.4375,8.4375 8.4961,8.378906 8.4961,22.207031 0,14.94141 -8.78906,23.61328 -8.73047,8.67188 -23.96485,8.67188 z m 0.46875,-48.750004 q -6.5625,0 -10.19531,4.511719 -3.63281,4.511719 -3.63281,12.773437 0,17.285158 13.94531,17.285158 13.30078,0 13.30078,-17.753908 0,-16.816406 -13.41797,-16.816406 z"
|
||||
id="path2689" />
|
||||
<path
|
||||
d="M 798.63477,119.81362 H 780.17773 V 86.473779 q 0,-13.945313 -9.96093,-13.945313 -4.80469,0 -7.91016,3.691406 -3.10547,3.691407 -3.10547,9.375 V 119.81362 H 740.68555 V 59.813622 h 18.51562 v 9.492188 h 0.23438 q 6.62109,-10.957031 19.27734,-10.957031 19.92188,0 19.92188,24.726562 z"
|
||||
id="path2691" />
|
||||
<path
|
||||
d="M 907.20898,51.200341 H 883.24414 V 119.81362 H 864.25977 V 51.200341 H 840.41211 V 35.790185 h 66.79687 z"
|
||||
id="path2693" />
|
||||
<path
|
||||
d="m 934.51367,121.27847 q -15,0 -23.61328,-8.37891 -8.55469,-8.4375 -8.55469,-22.851563 0,-14.882812 8.90625,-23.261718 8.90625,-8.4375 24.08203,-8.4375 14.94141,0 23.4375,8.4375 8.4961,8.378906 8.4961,22.207031 0,14.94141 -8.78906,23.61328 -8.73047,8.67188 -23.96485,8.67188 z m 0.46875,-48.750004 q -6.5625,0 -10.19531,4.511719 -3.63281,4.511719 -3.63281,12.773437 0,17.285158 13.94531,17.285158 13.30078,0 13.30078,-17.753908 0,-16.816406 -13.41797,-16.816406 z"
|
||||
id="path2695" />
|
||||
<path
|
||||
d="m 1007.873,121.27847 q -14.99995,0 -23.61323,-8.37891 -8.55469,-8.4375 -8.55469,-22.851563 0,-14.882812 8.90625,-23.261718 8.90625,-8.4375 24.08207,-8.4375 14.9414,0 23.4375,8.4375 8.4961,8.378906 8.4961,22.207031 0,14.94141 -8.7891,23.61328 -8.7305,8.67188 -23.9649,8.67188 z m 0.4688,-48.750004 q -6.5625,0 -10.19532,4.511719 -3.63281,4.511719 -3.63281,12.773437 0,17.285158 13.94533,17.285158 13.3008,0 13.3008,-17.753908 0,-16.816406 -13.418,-16.816406 z"
|
||||
id="path2697" />
|
||||
<path
|
||||
d="m 1071.1543,119.81362 h -18.5156 V 30.985497 h 18.5156 z"
|
||||
id="path2699" />
|
||||
<path
|
||||
d="m 1255.4316,119.1105 q -4.1015,2.16797 -12.3632,2.16797 -19.5704,0 -19.5704,-20.33204 V 73.465966 h -9.7265 V 59.813622 h 9.7265 V 46.864404 l 18.4571,-5.273438 v 18.222656 h 13.4765 v 13.652344 h -13.4765 v 24.257813 q 0,9.375001 7.4414,9.375001 2.9297,0 6.0351,-1.69922 z"
|
||||
id="path2701" />
|
||||
</g>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="translate(40.547253,883.62329)"
|
||||
id="text2609"
|
||||
style="fill:black;fill-opacity:1;line-height:1.25;stroke:none;font-family:sans-serif;font-style:normal;font-weight:normal;font-size:40px;white-space:pre;shape-inside:url(#rect2611)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="translate(40.547253,883.62329)"
|
||||
id="text2615"
|
||||
style="fill:black;fill-opacity:1;line-height:1.25;stroke:none;font-family:sans-serif;font-style:normal;font-weight:normal;font-size:40px;white-space:pre;shape-inside:url(#rect2617)" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 96 KiB |
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"$schema": "https://go.kicad.org/pcm/schemas/v1",
|
||||
"name": "JLC PCB Plugin for KiCad",
|
||||
"name": "Fabrication Toolkit",
|
||||
"description": "JLC PCB fabrication toolkit",
|
||||
"description_full": "Toolkit for automating PCB fabrication process with KiCad and JLC PCB",
|
||||
"description_full": "Toolkit for automating PCB fabrication process with KiCad and JLC PCB. \n\n OPTIONS: \n\u2022 Include Component Part Number in Production Files \n Add an 'MPN' field with the LCSC component part number to the footprint component options. \n\n\u2022 Ignore Footprint in Production Files \n Select 'Exclude from position files' or 'Exclude from BOM' in the footprint component options to in order ignore the footprint from the relevant file.",
|
||||
"identifier": "com.github.bennymeg.JLC-Plugin-for-KiCad",
|
||||
"type": "plugin",
|
||||
"author": {
|
||||
@@ -21,9 +21,15 @@
|
||||
"resources": {
|
||||
"homepage": "https://github.com/bennymeg/JLC-Plugin-for-KiCad"
|
||||
},
|
||||
"tags": [
|
||||
"jlc",
|
||||
"production",
|
||||
"fabrication",
|
||||
"toolkit"
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"version": "0.4.2",
|
||||
"status": "testing",
|
||||
"kicad_version": "6.00"
|
||||
}
|
||||
|
||||
@@ -4,5 +4,5 @@ try:
|
||||
plugin.register()
|
||||
except Exception as e:
|
||||
import logging
|
||||
root = logging.getLogger()
|
||||
root.debug(repr(e))
|
||||
logger = logging.getLogger()
|
||||
logger.debug(repr(e))
|
||||
|
||||
@@ -3,6 +3,7 @@ import pcbnew
|
||||
baseUrl = 'https://www.jlcpcb.com'
|
||||
|
||||
netlistFileName = 'netlist.ipc'
|
||||
designatorsFileName = 'designators.csv'
|
||||
placementFileName = 'positions.csv'
|
||||
bomFileName = 'bom.csv'
|
||||
gerberArchiveName = 'gerber.zip'
|
||||
@@ -13,6 +14,8 @@ plotPlan = [
|
||||
("B.Cu", pcbnew.B_Cu, "Bottom Layer"),
|
||||
("In1.Cu", pcbnew.In1_Cu, "Internal plane 1"),
|
||||
("In2.Cu", pcbnew.In2_Cu, "Internal plane 2"),
|
||||
("In3.Cu", pcbnew.In3_Cu, "Internal plane 3"),
|
||||
("In4.Cu", pcbnew.In4_Cu, "Internal plane 4"),
|
||||
("F.SilkS", pcbnew.F_SilkS, "Top Silkscreen"),
|
||||
("B.SilkS", pcbnew.B_SilkS, "Bottom Silkscreen"),
|
||||
("F.Mask", pcbnew.F_Mask, "Top Soldermask"),
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import wx
|
||||
|
||||
STATUS_EVENT_ID = wx.NewId()
|
||||
|
||||
|
||||
class StatusEvent(wx.PyEvent):
|
||||
def __init__(self, data):
|
||||
wx.PyEvent.__init__(self)
|
||||
self.SetEventType(STATUS_EVENT_ID)
|
||||
self.data = data
|
||||
|
||||
@staticmethod
|
||||
def invoke(window, function):
|
||||
window.Connect(-1, -1, STATUS_EVENT_ID, function)
|
||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.4 KiB |
@@ -1,10 +1,12 @@
|
||||
import os
|
||||
import wx
|
||||
import pcbnew
|
||||
|
||||
from .thread import *
|
||||
from .result_event import *
|
||||
from .thread import ProcessThread
|
||||
from .events import StatusEvent
|
||||
|
||||
|
||||
# WX GUI form that show the plugin progress
|
||||
class KiCadToJLCForm(wx.Frame):
|
||||
def __init__(self):
|
||||
wx.Dialog.__init__(
|
||||
@@ -32,9 +34,10 @@ class KiCadToJLCForm(wx.Frame):
|
||||
|
||||
self.Centre(wx.BOTH)
|
||||
|
||||
EVT_RESULT(self, self.updateDisplay)
|
||||
StatusEvent.invoke(self, self.updateDisplay)
|
||||
ProcessThread(self)
|
||||
|
||||
|
||||
def updateDisplay(self, status):
|
||||
if status.data == -1:
|
||||
pcbnew.Refresh()
|
||||
@@ -43,17 +46,16 @@ class KiCadToJLCForm(wx.Frame):
|
||||
self.m_gaugeStatus.SetValue(status.data)
|
||||
|
||||
|
||||
# Plugin definition
|
||||
class Plugin(pcbnew.ActionPlugin):
|
||||
def __init__(self):
|
||||
self.name = "JLC Plugin for KiCad"
|
||||
self.name = "Fabrication Toolkit"
|
||||
self.category = "Manufacturing"
|
||||
self.description = "Toolkit for automating PCB fabrication process with KiCad and JLC PCB"
|
||||
self.pcbnew_icon_support = hasattr(self, "show_toolbar_button")
|
||||
self.show_toolbar_button = True
|
||||
self.icon_file_name = os.path.join(
|
||||
os.path.dirname(__file__), 'icon.png')
|
||||
self.dark_icon_file_name = os.path.join(
|
||||
os.path.dirname(__file__), 'icon.png')
|
||||
self.icon_file_name = os.path.join(os.path.dirname(__file__), 'icon.png')
|
||||
self.dark_icon_file_name = os.path.join(os.path.dirname(__file__), 'icon.png')
|
||||
|
||||
def Run(self):
|
||||
KiCadToJLCForm().Show()
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
import json
|
||||
import requests
|
||||
import os
|
||||
import csv
|
||||
import shutil
|
||||
import pcbnew
|
||||
from collections import defaultdict
|
||||
from .config import *
|
||||
|
||||
|
||||
class ProcessManager:
|
||||
def __init__(self):
|
||||
self.board = pcbnew.GetBoard()
|
||||
self.bom = []
|
||||
self.components = []
|
||||
|
||||
def generate_gerber(self, temp_dir):
|
||||
settings = self.board.GetDesignSettings()
|
||||
settings.m_SolderMaskMargin = 0
|
||||
settings.m_SolderMaskMinWidth = 0
|
||||
|
||||
plot_controller = pcbnew.PLOT_CONTROLLER(self.board)
|
||||
|
||||
plot_options = plot_controller.GetPlotOptions()
|
||||
plot_options.SetOutputDirectory(temp_dir)
|
||||
plot_options.SetPlotFrameRef(False)
|
||||
plot_options.SetSketchPadLineWidth(pcbnew.FromMM(0.1))
|
||||
plot_options.SetAutoScale(False)
|
||||
plot_options.SetScale(1)
|
||||
plot_options.SetMirror(False)
|
||||
plot_options.SetUseGerberAttributes(True)
|
||||
plot_options.SetExcludeEdgeLayer(True)
|
||||
plot_options.SetUseGerberProtelExtensions(False)
|
||||
plot_options.SetUseAuxOrigin(True)
|
||||
plot_options.SetSubtractMaskFromSilk(False)
|
||||
plot_options.SetDrillMarksType(0) # NO_DRILL_SHAPE
|
||||
|
||||
for layer_info in plotPlan:
|
||||
if self.board.IsLayerEnabled(layer_info[1]):
|
||||
plot_controller.SetLayer(layer_info[1])
|
||||
plot_controller.OpenPlotfile(
|
||||
layer_info[0],
|
||||
pcbnew.PLOT_FORMAT_GERBER,
|
||||
layer_info[2])
|
||||
plot_controller.PlotLayer()
|
||||
|
||||
plot_controller.ClosePlot()
|
||||
|
||||
def generate_drills(self, temp_dir):
|
||||
drill_writer = pcbnew.EXCELLON_WRITER(self.board)
|
||||
|
||||
drill_writer.SetOptions(
|
||||
False,
|
||||
True,
|
||||
self.board.GetDesignSettings().GetAuxOrigin(),
|
||||
False)
|
||||
drill_writer.SetFormat(False)
|
||||
drill_writer.CreateDrillandMapFilesSet(temp_dir, True, False)
|
||||
|
||||
def generate_netlist(self, temp_dir):
|
||||
netlist_writer = pcbnew.IPC356D_WRITER(self.board)
|
||||
netlist_writer.Write(os.path.join(temp_dir, netlistFileName))
|
||||
|
||||
def generate_positions(self, temp_dir):
|
||||
if hasattr(self.board, 'GetModules'):
|
||||
footprints = list(self.board.GetModules())
|
||||
else:
|
||||
footprints = list(self.board.GetFootprints())
|
||||
|
||||
# unique designator dictionary
|
||||
footprint_designators = defaultdict(int)
|
||||
for i, footprint in enumerate(footprints):
|
||||
# count unique designators
|
||||
footprint_designators[footprint.GetReference()] += 1
|
||||
bom_designators = footprint_designators.copy()
|
||||
|
||||
with open((os.path.join(temp_dir, designatorsFileName)), 'w', encoding='utf-8') as f:
|
||||
for key, value in footprint_designators.items():
|
||||
f.write('%s:%s\n' % (key, value))
|
||||
|
||||
for i, footprint in enumerate(footprints):
|
||||
try:
|
||||
footprint_name = str(footprint.GetFPID().GetFootprintName())
|
||||
except AttributeError:
|
||||
footprint_name = str(footprint.GetFPID().GetLibItemName())
|
||||
|
||||
layer = {
|
||||
pcbnew.F_Cu: 'top',
|
||||
pcbnew.B_Cu: 'bottom',
|
||||
}.get(footprint.GetLayer())
|
||||
|
||||
# mount_type = {
|
||||
# 0: 'smt',
|
||||
# 1: 'tht',
|
||||
# 2: 'smt'
|
||||
# }.get(footprint.GetAttributes())
|
||||
|
||||
if not footprint.GetAttributes() & pcbnew.FP_EXCLUDE_FROM_POS_FILES:
|
||||
# append unique ID if duplicate footprint designator
|
||||
unique_id = ""
|
||||
if footprint_designators[footprint.GetReference()] > 1:
|
||||
unique_id = str(footprint_designators[footprint.GetReference()])
|
||||
footprint_designators[footprint.GetReference()] -= 1
|
||||
|
||||
self.components.append({
|
||||
'Designator': "{}{}{}".format(footprint.GetReference(), "" if unique_id == "" else "_", unique_id),
|
||||
'Mid X': (footprint.GetPosition()[0] - self.board.GetDesignSettings().GetAuxOrigin()[0]) / 1000000.0,
|
||||
'Mid Y': (footprint.GetPosition()[1] - self.board.GetDesignSettings().GetAuxOrigin()[1]) * -1.0 / 1000000.0,
|
||||
'Rotation': footprint.GetOrientation() / 10.0,
|
||||
'Layer': layer,
|
||||
})
|
||||
|
||||
if not footprint.GetAttributes() & pcbnew.FP_EXCLUDE_FROM_BOM:
|
||||
# append unique ID if we are dealing with duplicate bom designator
|
||||
unique_id = ""
|
||||
if bom_designators[footprint.GetReference()] > 1:
|
||||
unique_id = str(bom_designators[footprint.GetReference()])
|
||||
bom_designators[footprint.GetReference()] -= 1
|
||||
|
||||
# todo: merge similar parts into single entry
|
||||
|
||||
self.bom.append({
|
||||
'Designator': "{}{}{}".format(footprint.GetReference(), "" if unique_id == "" else "_", unique_id),
|
||||
'Footprint': footprint_name,
|
||||
'Quantity': 1,
|
||||
'Value': footprint.GetValue(),
|
||||
# 'Mount': mount_type,
|
||||
'LCSC Part #': self._getMpnFromFootprint(footprint),
|
||||
})
|
||||
|
||||
with open((os.path.join(temp_dir, placementFileName)), 'w', newline='', encoding='utf-8') as outfile:
|
||||
header = True
|
||||
csv_writer = csv.writer(outfile)
|
||||
|
||||
for component in self.components:
|
||||
if header:
|
||||
# writing headers of CSV file
|
||||
csv_writer.writerow(component.keys())
|
||||
header = False
|
||||
|
||||
# writing data of CSV file
|
||||
if ('**' not in component['Designator']):
|
||||
csv_writer.writerow(component.values())
|
||||
|
||||
def generate_bom(self, temp_dir):
|
||||
|
||||
with open((os.path.join(temp_dir, bomFileName)), 'w', newline='', encoding='utf-8') as outfile:
|
||||
header = True
|
||||
csv_writer = csv.writer(outfile)
|
||||
|
||||
for component in self.bom:
|
||||
if header:
|
||||
# writing headers of CSV file
|
||||
csv_writer.writerow(component.keys())
|
||||
header = False
|
||||
|
||||
# writing data of CSV file
|
||||
if ('**' not in component['Designator']):
|
||||
csv_writer.writerow(component.values())
|
||||
|
||||
def generate_archive(self, temp_dir, temp_file):
|
||||
temp_file = shutil.make_archive(temp_file, 'zip', temp_dir)
|
||||
temp_file = shutil.move(temp_file, temp_dir)
|
||||
|
||||
# remove non essential files
|
||||
for item in os.listdir(temp_dir):
|
||||
if not item.endswith(".zip") and not item.endswith(".csv") and not item.endswith(".ipc"):
|
||||
os.remove(os.path.join(temp_dir, item))
|
||||
|
||||
return temp_file
|
||||
|
||||
def upload_archive(self, temp_file):
|
||||
boardWidth = pcbnew.Iu2Millimeter(self.board.GetBoardEdgesBoundingBox().GetWidth())
|
||||
boardHeight = pcbnew.Iu2Millimeter(self.board.GetBoardEdgesBoundingBox().GetHeight())
|
||||
boardLayer = self.board.GetCopperLayerCount()
|
||||
|
||||
files = { 'upload[file]': open(temp_file, 'rb') }
|
||||
data = { 'boardWidth': boardWidth, 'boardHeight': boardHeight, 'boardLayer': boardLayer }
|
||||
upload_url = baseUrl + '/Common/KiCadUpFile/'
|
||||
|
||||
response = requests.post(upload_url, files=files, data=data)
|
||||
urls = json.loads(response.content)
|
||||
|
||||
def _getMpnFromFootprint(self, footprint):
|
||||
keys = ['mpn', 'Mpn', 'MPN', 'JLC_MPN', 'LCSC_MPN', 'LCSC Part #', 'JLC', 'LCSC']
|
||||
for key in keys:
|
||||
if footprint.HasProperty(key):
|
||||
return footprint.GetProperty(key)
|
||||
@@ -1,14 +0,0 @@
|
||||
import wx
|
||||
|
||||
EVT_RESULT_ID = wx.NewId()
|
||||
|
||||
|
||||
def EVT_RESULT(win, func):
|
||||
win.Connect(-1, -1, EVT_RESULT_ID, func)
|
||||
|
||||
|
||||
class ResultEvent(wx.PyEvent):
|
||||
def __init__(self, data):
|
||||
wx.PyEvent.__init__(self)
|
||||
self.SetEventType(EVT_RESULT_ID)
|
||||
self.data = data
|
||||
@@ -1,209 +1,83 @@
|
||||
# original copyright Aisler and licensed under the MIT license.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# from urllib import response
|
||||
# import json
|
||||
# import requests
|
||||
import os
|
||||
import wx
|
||||
import csv
|
||||
import shutil
|
||||
import tempfile
|
||||
import webbrowser
|
||||
from threading import Thread
|
||||
from .result_event import *
|
||||
from .events import StatusEvent
|
||||
from .process import ProcessManager
|
||||
from .config import *
|
||||
|
||||
|
||||
class ProcessThread(Thread):
|
||||
def __init__(self, wxObject):
|
||||
def __init__(self, wx):
|
||||
Thread.__init__(self)
|
||||
self.wxObject = wxObject
|
||||
|
||||
self.process_manager = ProcessManager()
|
||||
self.wx = wx
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
# initializing
|
||||
self.report(0)
|
||||
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
_, temp_file = tempfile.mkstemp()
|
||||
board = pcbnew.GetBoard()
|
||||
title_block = board.GetTitleBlock()
|
||||
project_directory = os.path.dirname(self.process_manager.board.GetFileName())
|
||||
output_path = os.path.join(project_directory, outputFolder)
|
||||
|
||||
# configure gerber
|
||||
# configure and generate gerber
|
||||
self.report(5)
|
||||
self.process_manager.generate_gerber(temp_dir)
|
||||
|
||||
settings = board.GetDesignSettings()
|
||||
settings.m_SolderMaskMargin = 0
|
||||
settings.m_SolderMaskMinWidth = 0
|
||||
|
||||
pctl = pcbnew.PLOT_CONTROLLER(board)
|
||||
|
||||
popt = pctl.GetPlotOptions()
|
||||
popt.SetOutputDirectory(temp_dir)
|
||||
popt.SetPlotFrameRef(False)
|
||||
popt.SetSketchPadLineWidth(pcbnew.FromMM(0.1))
|
||||
popt.SetAutoScale(False)
|
||||
popt.SetScale(1)
|
||||
popt.SetMirror(False)
|
||||
popt.SetUseGerberAttributes(True)
|
||||
popt.SetExcludeEdgeLayer(True)
|
||||
popt.SetUseGerberProtelExtensions(False)
|
||||
popt.SetUseAuxOrigin(True)
|
||||
popt.SetSubtractMaskFromSilk(False)
|
||||
popt.SetDrillMarksType(0) # NO_DRILL_SHAPE
|
||||
|
||||
# generate gerber
|
||||
self.report(10)
|
||||
for layer_info in plotPlan:
|
||||
if board.IsLayerEnabled(layer_info[1]):
|
||||
pctl.SetLayer(layer_info[1])
|
||||
pctl.OpenPlotfile(
|
||||
layer_info[0],
|
||||
pcbnew.PLOT_FORMAT_GERBER,
|
||||
layer_info[2])
|
||||
pctl.PlotLayer()
|
||||
|
||||
pctl.ClosePlot()
|
||||
|
||||
#generate drill file
|
||||
# generate drill file
|
||||
self.report(15)
|
||||
drlwriter = pcbnew.EXCELLON_WRITER(board)
|
||||
|
||||
drlwriter.SetOptions(
|
||||
False,
|
||||
True,
|
||||
board.GetDesignSettings().GetAuxOrigin(),
|
||||
False)
|
||||
drlwriter.SetFormat(False)
|
||||
drlwriter.CreateDrillandMapFilesSet(pctl.GetPlotDirName(), True, False)
|
||||
|
||||
self.process_manager.generate_drills(temp_dir)
|
||||
|
||||
# generate netlist
|
||||
self.report(25)
|
||||
netlist_writer = pcbnew.IPC356D_WRITER(board)
|
||||
netlist_writer.Write(os.path.join(temp_dir, netlistFileName))
|
||||
self.process_manager.generate_netlist(temp_dir)
|
||||
|
||||
# generate pick and place file
|
||||
self.report(40)
|
||||
components = []
|
||||
bom = []
|
||||
if hasattr(board, 'GetModules'):
|
||||
footprints = list(board.GetModules())
|
||||
else:
|
||||
footprints = list(board.GetFootprints())
|
||||
|
||||
for i, footprint in enumerate(footprints):
|
||||
try:
|
||||
footprint_name = str(footprint.GetFPID().GetFootprintName())
|
||||
except AttributeError:
|
||||
footprint_name = str(footprint.GetFPID().GetLibItemName())
|
||||
|
||||
layer = {
|
||||
pcbnew.F_Cu: 'top',
|
||||
pcbnew.B_Cu: 'bottom',
|
||||
}.get(footprint.GetLayer())
|
||||
|
||||
# mount_type = {
|
||||
# 0: 'smt',
|
||||
# 1: 'tht',
|
||||
# 2: 'smt'
|
||||
# }.get(footprint.GetAttributes())
|
||||
|
||||
if not footprint.GetAttributes() & pcbnew.FP_EXCLUDE_FROM_POS_FILES:
|
||||
components.append({
|
||||
'Designator': footprint.GetReference(),
|
||||
'Mid X': (footprint.GetPosition()[0] - board.GetDesignSettings().GetAuxOrigin()[0]) / 1000000.0,
|
||||
'Mid Y': (footprint.GetPosition()[1] - board.GetDesignSettings().GetAuxOrigin()[1]) * -1.0 / 1000000.0,
|
||||
'Rotation': footprint.GetOrientation() / 10.0,
|
||||
'Layer': layer,
|
||||
})
|
||||
|
||||
if not footprint.GetAttributes() & pcbnew.FP_EXCLUDE_FROM_BOM:
|
||||
bom.append({
|
||||
'Designator': footprint.GetReference(),
|
||||
'Footprint': footprint_name,
|
||||
'Quantity': 1,
|
||||
'Value': footprint.GetValue(),
|
||||
# 'Mount': mount_type,
|
||||
'LCSC Part #': self.getMpnFromFootprint(footprint),
|
||||
})
|
||||
|
||||
with open((os.path.join(temp_dir, placementFileName)), 'w', newline='') as outfile:
|
||||
header = True
|
||||
csv_writer = csv.writer(outfile)
|
||||
|
||||
for component in components:
|
||||
if header:
|
||||
# Writing headers of CSV file
|
||||
csv_writer.writerow(component.keys())
|
||||
header = False
|
||||
|
||||
# Writing data of CSV file
|
||||
if ('**' not in component['Designator']):
|
||||
csv_writer.writerow(component.values())
|
||||
self.process_manager.generate_positions(temp_dir)
|
||||
|
||||
# generate BOM file
|
||||
self.report(60)
|
||||
with open((os.path.join(temp_dir, bomFileName)), 'w', newline='') as outfile:
|
||||
header = True
|
||||
csv_writer = csv.writer(outfile)
|
||||
|
||||
for component in bom:
|
||||
if header:
|
||||
# Writing headers of CSV file
|
||||
csv_writer.writerow(component.keys())
|
||||
header = False
|
||||
|
||||
# Writing data of CSV file
|
||||
if ('**' not in component['Designator']):
|
||||
csv_writer.writerow(component.values())
|
||||
|
||||
self.process_manager.generate_bom(temp_dir)
|
||||
|
||||
# generate production archive
|
||||
self.report(75)
|
||||
temp_file = shutil.make_archive(temp_file, 'zip', temp_dir)
|
||||
temp_file = shutil.move(temp_file, temp_dir)
|
||||
|
||||
# remove non essential files
|
||||
for item in os.listdir(temp_dir):
|
||||
if not item.endswith(".zip") and not item.endswith(".csv") and not item.endswith(".ipc"):
|
||||
os.remove(os.path.join(temp_dir, item))
|
||||
temp_file = self.process_manager.generate_archive(temp_dir, temp_file)
|
||||
|
||||
# upload files
|
||||
self.report(87.5)
|
||||
boardWidth = pcbnew.Iu2Millimeter(board.GetBoardEdgesBoundingBox().GetWidth())
|
||||
boardHeight = pcbnew.Iu2Millimeter(board.GetBoardEdgesBoundingBox().GetHeight())
|
||||
boardLayer = board.GetCopperLayerCount()
|
||||
|
||||
# files = {'upload[file]': open(temp_file, 'rb')}
|
||||
# upload_url = baseUrl + '/Common/KiCadUpFile/'
|
||||
|
||||
# response = requests.post(
|
||||
# upload_url, files=files, data={'boardWidth':boardWidth,'boardHeight':boardHeight,'boardLayer':boardLayer})
|
||||
|
||||
# urls = json.loads(response.content)
|
||||
#self.report(87.5)
|
||||
#self.process_manager.upload_archive(temp_file)
|
||||
|
||||
readsofar = 0
|
||||
totalsize = os.path.getsize(temp_file)
|
||||
# progress bar done animation
|
||||
read_so_far = 0
|
||||
total_size = os.path.getsize(temp_file)
|
||||
with open(temp_file, 'rb') as file:
|
||||
while True:
|
||||
data = file.read(10)
|
||||
if not data:
|
||||
break
|
||||
readsofar += len(data)
|
||||
percent = readsofar * 1e2 / totalsize
|
||||
read_so_far += len(data)
|
||||
percent = read_so_far * 1e2 / total_size
|
||||
self.report(75 + percent / 8)
|
||||
|
||||
os.rename(temp_file, os.path.join(temp_dir, gerberArchiveName))
|
||||
|
||||
webbrowser.open(temp_dir)
|
||||
# webbrowser.open(urls['redirect'])
|
||||
try:
|
||||
if os.path.exists(output_path):
|
||||
shutil.rmtree(output_path)
|
||||
|
||||
shutil.copytree(temp_dir, output_path)
|
||||
webbrowser.open("file://%s" % (output_path))
|
||||
except Exception as e:
|
||||
webbrowser.open("file://%s" % (temp_dir))
|
||||
|
||||
self.report(-1)
|
||||
|
||||
def report(self, status):
|
||||
wx.PostEvent(self.wxObject, ResultEvent(status))
|
||||
|
||||
def getMpnFromFootprint(self, footprint):
|
||||
keys = ['mpn', 'MPN', 'Mpn', 'JLC_MPN', 'LCSC_MPN', 'LCSC Part #']
|
||||
for key in keys:
|
||||
if footprint.HasProperty(key):
|
||||
return footprint.GetProperty(key)
|
||||
|
||||
wx.PostEvent(self.wx, StatusEvent(status))
|
||||
|
||||
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 3.7 KiB |