aboutsummaryrefslogtreecommitdiff
path: root/kicad/lib/tools
diff options
context:
space:
mode:
authorFriedrich Beckmann <friedrich.beckmann@tha.de>2026-11-08 18:14:54 +0100
committerFriedrich Beckmann <friedrich.beckmann@tha.de>2026-11-08 18:14:54 +0100
commit5129a5a5448012a53cb9ddae1349c2a2c8571339 (patch)
tree41d60bbce7fe0de57cdd92b232682831759de1a8 /kicad/lib/tools
parent9e4911662b81bad61183cca74b8c1905f84e60e4 (diff)
Add KiCad 9 schematic, project libraries and datasheetsHEADmaster
Schematic (kicad/), one sheet per function as on ULX3S: - power: TLV62569 bucks for +1V1 / +3V3, AP2112K LDO for +2V5 - usb: USB-C with PTC and TVS, CH347F for JTAG and UART - fpga_power, fpga_config, fpga_banks_01/23/67: ECP5 LFE5U-25F caBGA256 (pin compatible with the 45F), quad SPI flash, 50 MHz CLOCK_50, ball assignment as in PINPLAN.md - ethernet: RTL8211F gigabit PHY, HR911130A RJ45, shield via 1M || 1nF 2kV - sdram: 32 MB W9825G6KH-6 - hdmi: TMDS from the FPGA (LVCMOS33D), AC coupled, ESD protected - user_io: SW, KEY (debounced), LEDR, LEDG, HEX0-HEX3 with DE1 names - gpio: two DE1 compatible 2x20 headers (THDB-ADA on GPIO_0), Pmod A/B, ESD arrays - testpoints: bring-up pads, M3 mounting holes All parts have LCSC numbers, MPN and manufacturer for JLCPCB assembly; footprints are cross-checked against the EasyEDA data. Libraries: ECP5 symbols generated from the Lattice pinout CSVs (kipart), CH347F, RTL8211F, SM410561N symbols, HR911130A symbol and footprint from KiCad library merge requests, generator scripts in lib/tools/. Datasheets of all parts except resistors and capacitors in datasheets/ (manufacturer copyright, not covered by the project licenses).
Diffstat (limited to 'kicad/lib/tools')
-rw-r--r--kicad/lib/tools/RJ45_Hanrun_HR911130A_Horizontal.kicad_sym2875
-rw-r--r--kicad/lib/tools/ch347f.csv37
-rwxr-xr-xkicad/lib/tools/derive_symbol.py74
-rwxr-xr-xkicad/lib/tools/kicad_sym_grid.py44
-rwxr-xr-xkicad/lib/tools/lattice2kipart.py107
-rwxr-xr-xkicad/lib/tools/make_7seg_fp.py77
-rwxr-xr-xkicad/lib/tools/make_eboard_lib.sh62
-rwxr-xr-xkicad/lib/tools/make_ecp5_symbol.sh37
-rw-r--r--kicad/lib/tools/rtl8211f.csv49
-rw-r--r--kicad/lib/tools/sm410561n.csv18
10 files changed, 3380 insertions, 0 deletions
diff --git a/kicad/lib/tools/RJ45_Hanrun_HR911130A_Horizontal.kicad_sym b/kicad/lib/tools/RJ45_Hanrun_HR911130A_Horizontal.kicad_sym
new file mode 100644
index 0000000..4d25812
--- /dev/null
+++ b/kicad/lib/tools/RJ45_Hanrun_HR911130A_Horizontal.kicad_sym
@@ -0,0 +1,2875 @@
+(kicad_symbol_lib
+ (version 20241209)
+ (generator "kicad_symbol_editor")
+ (generator_version "9.0")
+ (symbol "RJ45_Hanrun_HR911130A_Horizontal"
+ (pin_names
+ (hide yes)
+ )
+ (exclude_from_sim no)
+ (in_bom yes)
+ (on_board yes)
+ (property "Reference" "J"
+ (at -8.89 19.05 0)
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (property "Value" "RJ45_Hanrun_HR911130A_Horizontal"
+ (at 13.97 19.05 0)
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (property "Footprint" "eboard:RJ45_Hanrun_HR911130A_Horizontal"
+ (at 0 1.27 0)
+ (hide yes)
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (property "Datasheet" "https://hrdzen.oss-cn-beijing.aliyuncs.com/202601/1ba07be89265140.pdf"
+ (at -7.366 -1.397 0)
+ (hide yes)
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ (justify left top)
+ )
+ )
+ (property "Description" "LAN Transformer Jack, RJ45, 10/100/1000 BaseT"
+ (at 0 -1.27 0)
+ (hide yes)
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (property "ki_keywords" "lan jack socket transformer ethernet gigabit 10 100 1000 baset"
+ (at 0 0 0)
+ (hide yes)
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (property "ki_fp_filters" "RJ45*Hanrun*HR911130A*"
+ (at 0 0 0)
+ (hide yes)
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (symbol "RJ45_Hanrun_HR911130A_Horizontal_0_0"
+ (circle
+ (center -5.08 0.762)
+ (radius 0.0001)
+ (stroke
+ (width 0.508)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (circle
+ (center -5.08 -6.858)
+ (radius 0.0001)
+ (stroke
+ (width 0.508)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (circle
+ (center -5.08 -14.478)
+ (radius 0.0001)
+ (stroke
+ (width 0.508)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -2.794 -14.478) (xy -5.08 -14.478)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -2.286 10.922) (xy -6.35 10.922)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -2.286 9.398) (xy -6.35 9.398)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -2.286 3.302) (xy -6.35 3.302)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -2.286 1.778) (xy -6.35 1.778)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -2.286 -4.318) (xy -6.35 -4.318)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -2.286 -5.842) (xy -6.35 -5.842)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -2.286 -11.938) (xy -6.35 -11.938)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -2.286 -13.462) (xy -6.35 -13.462)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -0.254 8.382) (xy 2.54 8.382) (xy 2.54 10.16) (xy 3.81 10.16)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -0.254 0.762) (xy 2.54 0.762) (xy 2.54 2.54) (xy 3.81 2.54)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -0.254 -6.858) (xy 2.54 -6.858) (xy 2.54 -5.08) (xy 3.81 -5.08)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -0.254 -14.478) (xy 2.54 -14.478) (xy 2.54 -12.7) (xy 3.81 -12.7)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 5.08 2.54) (xy 6.35 2.54)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 6.35 10.16) (xy 5.08 10.16)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (circle
+ (center 6.35 10.16)
+ (radius 0.0001)
+ (stroke
+ (width 0.508)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (circle
+ (center 6.35 2.54)
+ (radius 0.0001)
+ (stroke
+ (width 0.508)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 6.35 -5.08) (xy 5.08 -5.08)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (circle
+ (center 6.35 -5.08)
+ (radius 0.0001)
+ (stroke
+ (width 0.508)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (text "C1"
+ (at -7.62 11.43 0)
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (text "C2"
+ (at -7.62 9.144 0)
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (text "C3"
+ (at -7.62 3.556 0)
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (text "C6"
+ (at -7.62 1.524 0)
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (text "C4"
+ (at -7.62 -4.064 0)
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (text "C5"
+ (at -7.62 -6.096 0)
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (text "C7"
+ (at -7.62 -11.684 0)
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (text "C8"
+ (at -7.62 -13.716 0)
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (text "G"
+ (at -5.08 15.24 0)
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ )
+ (symbol "RJ45_Hanrun_HR911130A_Horizontal_0_1"
+ (rectangle
+ (start -10.16 17.78)
+ (end 10.16 -17.78)
+ (stroke
+ (width 0.254)
+ (type default)
+ )
+ (fill
+ (type background)
+ )
+ )
+ (rectangle
+ (start -8.89 12.446)
+ (end -6.35 -14.732)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -5.842 -16.002) (xy -4.318 -16.002)
+ )
+ (stroke
+ (width 0.3048)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -5.842 -16.51) (xy -4.318 -16.51)
+ )
+ (stroke
+ (width 0.3302)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -5.08 17.78) (xy -5.08 16.51) (xy -4.318 16.51)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -5.08 0.762) (xy -2.794 0.762)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -5.08 -16.002) (xy -5.08 8.382) (xy -2.794 8.382)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -5.08 -17.78) (xy -5.08 -15.24)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -3.556 15.494) (xy -3.556 15.24) (xy -3.81 15.24)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -3.556 15.24) (xy -4.064 15.748)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -3.302 17.018) (xy -3.302 16.002)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -3.302 16.51) (xy -4.318 17.018) (xy -4.318 16.002) (xy -3.302 16.51)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -3.048 15.494) (xy -3.048 15.24) (xy -3.302 15.24)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -3.048 15.24) (xy -3.556 15.748)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (rectangle
+ (start -2.794 7.874)
+ (end -0.254 8.89)
+ (stroke
+ (width 0.2032)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (rectangle
+ (start -2.794 0.254)
+ (end -0.254 1.27)
+ (stroke
+ (width 0.2032)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -2.794 -6.858) (xy -5.08 -6.858)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (rectangle
+ (start -2.794 -7.366)
+ (end -0.254 -6.35)
+ (stroke
+ (width 0.2032)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (rectangle
+ (start -2.794 -14.986)
+ (end -0.254 -13.97)
+ (stroke
+ (width 0.2032)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -2.54 17.78) (xy -2.54 16.51) (xy -3.302 16.51)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -2.286 9.906) (xy -0.254 9.906)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -2.286 2.286) (xy -0.254 2.286)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -2.286 -5.334) (xy -0.254 -5.334)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -2.286 -12.954) (xy -0.254 -12.954)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -1.778 10.922)
+ (mid -2.032 10.6691)
+ (end -2.286 10.922)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -2.286 9.398)
+ (mid -2.032 9.6509)
+ (end -1.778 9.398)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -1.778 3.302)
+ (mid -2.032 3.0491)
+ (end -2.286 3.302)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -2.286 1.778)
+ (mid -2.032 2.0309)
+ (end -1.778 1.778)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -1.778 -4.318)
+ (mid -2.032 -4.5709)
+ (end -2.286 -4.318)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -2.286 -5.842)
+ (mid -2.032 -5.5891)
+ (end -1.778 -5.842)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -1.778 -11.938)
+ (mid -2.032 -12.1909)
+ (end -2.286 -11.938)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -2.286 -13.462)
+ (mid -2.032 -13.2091)
+ (end -1.778 -13.462)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -1.27 10.922)
+ (mid -1.524 10.6691)
+ (end -1.778 10.922)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -1.778 9.398)
+ (mid -1.524 9.6509)
+ (end -1.27 9.398)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -1.27 3.302)
+ (mid -1.524 3.0491)
+ (end -1.778 3.302)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -1.778 1.778)
+ (mid -1.524 2.0309)
+ (end -1.27 1.778)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -1.27 -4.318)
+ (mid -1.524 -4.5709)
+ (end -1.778 -4.318)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -1.778 -5.842)
+ (mid -1.524 -5.5891)
+ (end -1.27 -5.842)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -1.27 -11.938)
+ (mid -1.524 -12.1909)
+ (end -1.778 -11.938)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -1.778 -13.462)
+ (mid -1.524 -13.2091)
+ (end -1.27 -13.462)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -0.762 10.922)
+ (mid -1.016 10.6691)
+ (end -1.27 10.922)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -1.27 9.398)
+ (mid -1.016 9.6509)
+ (end -0.762 9.398)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -0.762 3.302)
+ (mid -1.016 3.0491)
+ (end -1.27 3.302)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -1.27 1.778)
+ (mid -1.016 2.0309)
+ (end -0.762 1.778)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -0.762 -4.318)
+ (mid -1.016 -4.5709)
+ (end -1.27 -4.318)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -1.27 -5.842)
+ (mid -1.016 -5.5891)
+ (end -0.762 -5.842)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -0.762 -11.938)
+ (mid -1.016 -12.1909)
+ (end -1.27 -11.938)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -1.27 -13.462)
+ (mid -1.016 -13.2091)
+ (end -0.762 -13.462)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (circle
+ (center -0.508 10.9474)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (arc
+ (start -0.254 10.922)
+ (mid -0.508 10.6691)
+ (end -0.762 10.922)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -0.762 9.398)
+ (mid -0.508 9.6509)
+ (end -0.254 9.398)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (circle
+ (center -0.508 9.3726)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (circle
+ (center -0.508 3.3274)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (arc
+ (start -0.254 3.302)
+ (mid -0.508 3.0491)
+ (end -0.762 3.302)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -0.762 1.778)
+ (mid -0.508 2.0309)
+ (end -0.254 1.778)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (circle
+ (center -0.508 1.7526)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (circle
+ (center -0.508 -4.2926)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (arc
+ (start -0.254 -4.318)
+ (mid -0.508 -4.5709)
+ (end -0.762 -4.318)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -0.762 -5.842)
+ (mid -0.508 -5.5891)
+ (end -0.254 -5.842)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (circle
+ (center -0.508 -5.8674)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (circle
+ (center -0.508 -11.9126)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (arc
+ (start -0.254 -11.938)
+ (mid -0.508 -12.1909)
+ (end -0.762 -11.938)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start -0.762 -13.462)
+ (mid -0.508 -13.2091)
+ (end -0.254 -13.462)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (circle
+ (center -0.508 -13.4874)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (polyline
+ (pts
+ (xy -0.254 10.922) (xy 1.27 10.922) (xy 1.27 12.7) (xy 3.81 12.7) (xy 3.81 12.192)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -0.254 10.414) (xy -2.286 10.414)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -0.254 3.302) (xy 1.27 3.302) (xy 1.27 5.08) (xy 3.81 5.08) (xy 3.81 4.572)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -0.254 2.794) (xy -2.286 2.794)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -0.254 -4.318) (xy 1.27 -4.318) (xy 1.27 -2.54) (xy 3.81 -2.54) (xy 3.81 -3.048)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -0.254 -4.826) (xy -2.286 -4.826)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -0.254 -11.938) (xy 1.27 -11.938) (xy 1.27 -10.16) (xy 3.81 -10.16) (xy 3.81 -10.668)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy -0.254 -12.446) (xy -2.286 -12.446)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 2.54 17.78) (xy 2.54 16.51) (xy 3.302 16.51)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (circle
+ (center 3.7846 11.938)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (circle
+ (center 3.7846 9.906)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (circle
+ (center 3.7846 4.318)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (circle
+ (center 3.7846 2.286)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (circle
+ (center 3.7846 -3.302)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (circle
+ (center 3.7846 -5.334)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (circle
+ (center 3.7846 -10.922)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (circle
+ (center 3.7846 -12.954)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (arc
+ (start 3.81 12.192)
+ (mid 4.063 11.938)
+ (end 3.81 11.684)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 11.176)
+ (mid 4.063 10.922)
+ (end 3.81 10.668)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 10.668)
+ (mid 4.063 10.414)
+ (end 3.81 10.16)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 10.16)
+ (mid 4.063 9.906)
+ (end 3.81 9.652)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 9.652)
+ (mid 4.063 9.398)
+ (end 3.81 9.144)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 8.636)
+ (mid 4.063 8.382)
+ (end 3.81 8.128)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 4.572)
+ (mid 4.063 4.318)
+ (end 3.81 4.064)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 3.556)
+ (mid 4.063 3.302)
+ (end 3.81 3.048)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 3.048)
+ (mid 4.063 2.794)
+ (end 3.81 2.54)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 2.54)
+ (mid 4.063 2.286)
+ (end 3.81 2.032)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 2.032)
+ (mid 4.063 1.778)
+ (end 3.81 1.524)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 1.016)
+ (mid 4.063 0.762)
+ (end 3.81 0.508)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 -3.048)
+ (mid 4.063 -3.302)
+ (end 3.81 -3.556)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 -4.064)
+ (mid 4.063 -4.318)
+ (end 3.81 -4.572)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 -4.572)
+ (mid 4.063 -4.826)
+ (end 3.81 -5.08)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 -5.08)
+ (mid 4.063 -5.334)
+ (end 3.81 -5.588)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 -5.588)
+ (mid 4.063 -5.842)
+ (end 3.81 -6.096)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 -6.604)
+ (mid 4.063 -6.858)
+ (end 3.81 -7.112)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 -10.668)
+ (mid 4.063 -10.922)
+ (end 3.81 -11.176)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 -11.684)
+ (mid 4.063 -11.938)
+ (end 3.81 -12.192)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 -12.192)
+ (mid 4.063 -12.446)
+ (end 3.81 -12.7)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 -12.7)
+ (mid 4.063 -12.954)
+ (end 3.81 -13.208)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 -13.208)
+ (mid 4.063 -13.462)
+ (end 3.81 -13.716)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 -14.224)
+ (mid 4.063 -14.478)
+ (end 3.81 -14.732)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 11.684)
+ (mid 4.064 11.43)
+ (end 3.81 11.176)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 9.144)
+ (mid 4.064 8.89)
+ (end 3.81 8.636)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 3.81 8.128) (xy 3.81 7.62) (xy 1.27 7.62) (xy 1.27 9.398) (xy -0.254 9.398)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 4.064)
+ (mid 4.064 3.81)
+ (end 3.81 3.556)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 1.524)
+ (mid 4.064 1.27)
+ (end 3.81 1.016)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 3.81 0.508) (xy 3.81 0) (xy 1.27 0) (xy 1.27 1.778) (xy -0.254 1.778)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 -3.556)
+ (mid 4.064 -3.81)
+ (end 3.81 -4.064)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 -6.096)
+ (mid 4.064 -6.35)
+ (end 3.81 -6.604)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 3.81 -7.112) (xy 3.81 -7.62) (xy 1.27 -7.62) (xy 1.27 -5.842) (xy -0.254 -5.842)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 -11.176)
+ (mid 4.064 -11.43)
+ (end 3.81 -11.684)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 3.81 -13.716)
+ (mid 4.064 -13.97)
+ (end 3.81 -14.224)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 3.81 -14.732) (xy 3.81 -15.24) (xy 1.27 -15.24) (xy 1.27 -13.462) (xy -0.254 -13.462)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 4.064 15.494) (xy 4.064 15.24) (xy 3.81 15.24)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 4.064 15.24) (xy 3.556 15.748)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 4.318 17.018) (xy 4.318 16.002)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 4.318 16.51) (xy 3.302 17.018) (xy 3.302 16.002) (xy 4.318 16.51)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 4.318 12.192) (xy 4.318 8.128)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 4.318 4.572) (xy 4.318 0.508)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 4.318 -3.048) (xy 4.318 -7.112)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 4.318 -10.668) (xy 4.318 -14.732)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 4.572 15.494) (xy 4.572 15.24) (xy 4.318 15.24)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 4.572 15.24) (xy 4.064 15.748)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 4.572 8.128) (xy 4.572 12.192)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 4.572 0.508) (xy 4.572 4.572)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 4.572 -7.112) (xy 4.572 -3.048)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 4.572 -14.732) (xy 4.572 -10.668)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 5.08 17.78) (xy 5.08 16.51) (xy 4.318 16.51)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 5.08 12.192) (xy 5.08 12.7) (xy 10.16 12.7)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 11.176)
+ (mid 4.826 11.43)
+ (end 5.08 11.684)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 8.636)
+ (mid 4.826 8.89)
+ (end 5.08 9.144)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 5.08 8.128) (xy 5.08 7.62) (xy 10.16 7.62)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 5.08 4.572) (xy 5.08 5.08) (xy 10.16 5.08)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 3.556)
+ (mid 4.826 3.81)
+ (end 5.08 4.064)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 1.016)
+ (mid 4.826 1.27)
+ (end 5.08 1.524)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 5.08 0.508) (xy 5.08 0) (xy 10.16 0)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 5.08 -3.048) (xy 5.08 -2.54) (xy 10.16 -2.54)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 -4.064)
+ (mid 4.826 -3.81)
+ (end 5.08 -3.556)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 -6.604)
+ (mid 4.826 -6.35)
+ (end 5.08 -6.096)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 5.08 -7.112) (xy 5.08 -7.62) (xy 10.16 -7.62)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 5.08 -10.668) (xy 5.08 -10.16) (xy 10.16 -10.16)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 -11.684)
+ (mid 4.826 -11.43)
+ (end 5.08 -11.176)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 -14.224)
+ (mid 4.826 -13.97)
+ (end 5.08 -13.716)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (polyline
+ (pts
+ (xy 5.08 -14.732) (xy 5.08 -15.24) (xy 10.16 -15.24)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 11.684)
+ (mid 4.827 11.938)
+ (end 5.08 12.192)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 10.668)
+ (mid 4.827 10.922)
+ (end 5.08 11.176)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 10.16)
+ (mid 4.827 10.414)
+ (end 5.08 10.668)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 9.652)
+ (mid 4.827 9.906)
+ (end 5.08 10.16)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 9.144)
+ (mid 4.827 9.398)
+ (end 5.08 9.652)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 8.128)
+ (mid 4.827 8.382)
+ (end 5.08 8.636)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 4.064)
+ (mid 4.827 4.318)
+ (end 5.08 4.572)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 3.048)
+ (mid 4.827 3.302)
+ (end 5.08 3.556)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 2.54)
+ (mid 4.827 2.794)
+ (end 5.08 3.048)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 2.032)
+ (mid 4.827 2.286)
+ (end 5.08 2.54)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 1.524)
+ (mid 4.827 1.778)
+ (end 5.08 2.032)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 0.508)
+ (mid 4.827 0.762)
+ (end 5.08 1.016)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 -3.556)
+ (mid 4.827 -3.302)
+ (end 5.08 -3.048)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 -4.572)
+ (mid 4.827 -4.318)
+ (end 5.08 -4.064)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 -5.08)
+ (mid 4.827 -4.826)
+ (end 5.08 -4.572)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 -5.588)
+ (mid 4.827 -5.334)
+ (end 5.08 -5.08)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 -6.096)
+ (mid 4.827 -5.842)
+ (end 5.08 -5.588)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 -7.112)
+ (mid 4.827 -6.858)
+ (end 5.08 -6.604)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 -11.176)
+ (mid 4.827 -10.922)
+ (end 5.08 -10.668)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 -12.192)
+ (mid 4.827 -11.938)
+ (end 5.08 -11.684)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 -12.7)
+ (mid 4.827 -12.446)
+ (end 5.08 -12.192)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 -13.208)
+ (mid 4.827 -12.954)
+ (end 5.08 -12.7)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 -13.716)
+ (mid 4.827 -13.462)
+ (end 5.08 -13.208)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (arc
+ (start 5.08 -14.732)
+ (mid 4.827 -14.478)
+ (end 5.08 -14.224)
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (circle
+ (center 5.1054 11.938)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (circle
+ (center 5.1054 9.906)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (circle
+ (center 5.1054 4.318)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (circle
+ (center 5.1054 2.286)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (circle
+ (center 5.1054 -3.302)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (circle
+ (center 5.1054 -5.334)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (circle
+ (center 5.1054 -10.922)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (circle
+ (center 5.1054 -12.954)
+ (radius 0.0762)
+ (stroke
+ (width 0.0254)
+ (type default)
+ )
+ (fill
+ (type outline)
+ )
+ )
+ (polyline
+ (pts
+ (xy 10.16 15.24) (xy 6.35 15.24) (xy 6.35 -12.7) (xy 5.08 -12.7)
+ )
+ (stroke
+ (width 0)
+ (type default)
+ )
+ (fill
+ (type none)
+ )
+ )
+ (pin power_in line
+ (at -5.08 -20.32 90)
+ (length 2.54)
+ (name "GND"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (number "10"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ )
+ )
+ (symbol "RJ45_Hanrun_HR911130A_Horizontal_1_0"
+ (text "75"
+ (at -1.524 8.382 0)
+ (effects
+ (font
+ (size 0.508 0.508)
+ )
+ )
+ )
+ (text "75"
+ (at -1.524 0.762 0)
+ (effects
+ (font
+ (size 0.508 0.508)
+ )
+ )
+ )
+ (text "75"
+ (at -1.524 -6.858 0)
+ (effects
+ (font
+ (size 0.508 0.508)
+ )
+ )
+ )
+ (text "75"
+ (at -1.524 -14.478 0)
+ (effects
+ (font
+ (size 0.508 0.508)
+ )
+ )
+ )
+ )
+ (symbol "RJ45_Hanrun_HR911130A_Horizontal_1_1"
+ (text "1000pF 2kV"
+ (at -3.81 -16.256 0)
+ (effects
+ (font
+ (size 0.635 0.635)
+ )
+ (justify left)
+ )
+ )
+ (text "Y"
+ (at 2.54 15.24 0)
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (pin passive line
+ (at 12.7 15.24 180)
+ (length 2.54)
+ (name "CT"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (number "1"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ )
+ (pin passive line
+ (at 12.7 12.7 180)
+ (length 2.54)
+ (name "MDI0+"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (number "2"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ )
+ (pin passive line
+ (at 12.7 7.62 180)
+ (length 2.54)
+ (name "MDI0-"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (number "3"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ )
+ (pin passive line
+ (at 12.7 5.08 180)
+ (length 2.54)
+ (name "MDI1+"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (number "4"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ )
+ (pin passive line
+ (at 12.7 -2.54 180)
+ (length 2.54)
+ (name "MDI2+"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (number "5"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ )
+ (pin passive line
+ (at 12.7 -7.62 180)
+ (length 2.54)
+ (name "MDI2-"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (number "6"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ )
+ (pin passive line
+ (at 12.7 0 180)
+ (length 2.54)
+ (name "MDI1-"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (number "7"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ )
+ (pin passive line
+ (at 12.7 -10.16 180)
+ (length 2.54)
+ (name "MDI3+"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (number "8"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ )
+ (pin passive line
+ (at 12.7 -15.24 180)
+ (length 2.54)
+ (name "MDI3-"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (number "9"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ )
+ (pin passive line
+ (at -5.08 20.32 270)
+ (length 2.54)
+ (name "LGA"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (number "11"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ )
+ (pin passive line
+ (at -2.54 20.32 270)
+ (length 2.54)
+ (name "LGK"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (number "12"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ )
+ (pin passive line
+ (at 5.08 20.32 270)
+ (length 2.54)
+ (name "LYK"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (number "13"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ )
+ (pin passive line
+ (at 2.54 20.32 270)
+ (length 2.54)
+ (name "LYA"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (number "14"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ )
+ (pin passive line
+ (at 5.08 -20.32 90)
+ (length 2.54)
+ (name "SH"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ (number "SH"
+ (effects
+ (font
+ (size 1.27 1.27)
+ )
+ )
+ )
+ )
+ )
+ (embedded_fonts no)
+ )
+)
diff --git a/kicad/lib/tools/ch347f.csv b/kicad/lib/tools/ch347f.csv
new file mode 100644
index 0000000..ad27b48
--- /dev/null
+++ b/kicad/lib/tools/ch347f.csv
@@ -0,0 +1,37 @@
+CH347F
+Footprint:,Package_DFN_QFN:QFN-28-1EP_4x4mm_P0.4mm_EP2.4x2.4mm_ThermalVias
+Datasheet:,https://www.wch-ic.com/downloads/CH347DS1_PDF.html
+Description:,"High-speed USB 2.0 to dual UART, I2C, SPI, JTAG, SWD converter, VIO 1.8-3.3V, QFN-28 (datasheet pin 0 = EP = pad 29)"
+Source*:,"WCH CH347 datasheet V1.4 (CH347DS1): CH347F pins tables 4-1 to 4-7, pin names from the pinout figure (page 4); EP = datasheet pin 0 = pad 29"
+Keywords:,USB UART JTAG SPI I2C SWD converter WCH
+Filters:,QFN*28*1EP*4x4mm*P0.4mm*
+pin,name,type,side
+21,VCC,power_in,top
+6,VIO,power_in,top
+3,~{RST},input,left
+1,XI,input,left
+2,XO,output,left
+28,UD+,bidirectional,left
+27,UD-,bidirectional,left
+8,ACT/SRST,output,left
+20,GND,power_in,bottom
+29,GND,passive,bottom
+19,TXD0,output,right
+22,RXD0,input,right
+18,RTS0/GPIO1,bidirectional,right
+17,CTS0/GPIO0,bidirectional,right
+10,DTR0/TNOW0/GPIO2,bidirectional,right
+4,TXD1,output,right
+5,RXD1,input,right
+11,CTS1/SCL,bidirectional,right
+12,RTS1/SDA,bidirectional,right
+7,DTR1/TNOW1/SCS1,bidirectional,right
+14,SCK,output,right
+13,SCS0,output,right
+16,MOSI,output,right
+15,MISO,input,right
+23,TCK/SWDCLK/GPIO4,output,right
+26,TMS/SWDIO/GPIO7,bidirectional,right
+25,TDI/GPIO6,output,right
+24,TDO/GPIO5,input,right
+9,TRST/GPIO3,bidirectional,right
diff --git a/kicad/lib/tools/derive_symbol.py b/kicad/lib/tools/derive_symbol.py
new file mode 100755
index 0000000..1278128
--- /dev/null
+++ b/kicad/lib/tools/derive_symbol.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-3.0-or-later
+"""Add a pin-compatible variant of a symbol to a KiCad symbol library.
+
+The variant keeps the geometry of the base symbol (every pin number at the
+same position), so "Change symbol" in the schematic swaps the two without
+breaking wires. Pin names and the description come from the variant's kipart
+CSV (as written by lattice2kipart.py).
+
+ derive_symbol.py LIB.kicad_sym BASE_NAME VARIANT.csv > OUT.kicad_sym
+"""
+import csv
+import re
+import sys
+
+
+def match_paren(t, i):
+ depth = 0
+ j = i
+ while True:
+ c = t[j]
+ if c == '"':
+ j += 1
+ while t[j] != '"':
+ j += 2 if t[j] == "\\" else 1
+ elif c == "(":
+ depth += 1
+ elif c == ")":
+ depth -= 1
+ if depth == 0:
+ return j + 1
+ j += 1
+
+
+lib_path, base, var_csv = sys.argv[1:4]
+lib = open(lib_path).read()
+
+rows = list(csv.reader(open(var_csv, newline="")))
+variant = rows[0][0]
+props = {r[0][:-1].replace("*", ""): r[1] for r in rows[1:] if r and r[0].endswith(":")}
+hdr = next(i for i, r in enumerate(rows) if r and r[0] == "pin")
+cols = rows[hdr]
+pins = {r[cols.index("pin")]: (r[cols.index("name")], r[cols.index("type")])
+ for r in rows[hdr + 1:] if r and r[0]}
+
+m = re.search(r'\(symbol "' + re.escape(base) + r'"', lib)
+start = m.start()
+block = lib[start:match_paren(lib, start)]
+base_types = {n: t for t, n in re.findall(r'\(pin (\w+) \w+ .*?\(number "([^"]+)"', block, re.S)}
+
+new = block.replace(f'(symbol "{base}"', f'(symbol "{variant}"', 1)
+new = new.replace(f'(symbol "{base}_', f'(symbol "{variant}_')
+new = re.sub(r'(\(property "Value" )"[^"]*"', rf'\1"{variant}"', new, count=1)
+for key in ("Description", "Source"):
+ if key in props:
+ new = re.sub(r'(\(property "' + key + r'" )"[^"]*"', lambda mm: f'{mm.group(1)}"{props[key]}"',
+ new, count=1)
+
+
+def rename(mm):
+ num = mm.group(3)
+ name, typ = pins[num]
+ if typ != base_types[num] and not (base_types[num] == "passive"): # stacked pins are passive
+ sys.exit(f"pin {num}: type {typ} differs from {base_types[num]}")
+ return f'{mm.group(1)}(name "{name}"{mm.group(2)}(number "{num}"'
+
+
+new, n = re.subn(r'(\(pin [^\n]*\n(?:(?!\(pin ).)*?)\(name "[^"]*"(.*?)\(number "([^"]+)"',
+ rename, new, flags=re.S)
+if n != len(pins):
+ sys.exit(f"renamed {n} pins, variant has {len(pins)}")
+
+end = match_paren(lib, start)
+sys.stdout.write(lib[:end] + "\n " + new + lib[end:])
diff --git a/kicad/lib/tools/kicad_sym_grid.py b/kicad/lib/tools/kicad_sym_grid.py
new file mode 100755
index 0000000..de52a8e
--- /dev/null
+++ b/kicad/lib/tools/kicad_sym_grid.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-3.0-or-later
+"""Snap kipart symbol pins onto the 2.54 mm grid.
+
+kipart centres each pin column, which puts columns with an even pin count
+(and box edges) on a 1.27 mm half grid; it also writes float noise such as
+3.55e-15. Pins are moved by half a grid step along their column, and pins
+whose end point is off grid are lengthened so the symbol body stays put.
+
+ kicad_sym_grid.py IN.kicad_sym > OUT.kicad_sym
+"""
+import re
+import sys
+
+
+def on_grid(v):
+ return abs(v / 2.54 - round(v / 2.54)) < 0.004
+
+
+def fix(m):
+ kind, x, y, a = m.group(1), float(m.group(2)), float(m.group(3)), m.group(4)
+ length = float(m.group(5))
+ vertical = a in ("90", "270")
+ if vertical and not on_grid(x):
+ x += 1.27
+ if not vertical and not on_grid(y):
+ y += 1.27
+ if vertical and not on_grid(y):
+ y += 1.27 if y > 0 else -1.27
+ length += 1.27
+ if not vertical and not on_grid(x):
+ x += 1.27 if x > 0 else -1.27
+ length += 1.27
+
+ def f(v):
+ v = round(v, 4)
+ return "0" if v == 0 else f"{v:g}"
+ return f"(pin {kind} (at {f(x)} {f(y)} {a}) (length {f(length)})"
+
+
+text = open(sys.argv[1]).read()
+text = re.sub(r"\(pin ([\w ]+?)\s*\(at ([-\d.e+]+) ([-\d.e+]+) (\d+)\)\s*\(length ([\d.]+)\)",
+ fix, text)
+sys.stdout.write(text)
diff --git a/kicad/lib/tools/lattice2kipart.py b/kicad/lib/tools/lattice2kipart.py
new file mode 100755
index 0000000..3e10074
--- /dev/null
+++ b/kicad/lib/tools/lattice2kipart.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-3.0-or-later
+"""Convert a Lattice ECP5 pinout CSV into a kipart input CSV.
+
+Usage:
+ lattice2kipart.py PINOUT.csv PACKAGE PARTNAME FOOTPRINT LUTS > part.csv
+ kipart -b -o out.kicad_sym part.csv
+
+One unit per I/O bank, one unit for configuration/JTAG, one unit for
+core/aux power and ground. Dual functions are appended to the pin name
+(e.g. PL32A/PCLKT7_1) so clock and config pins are visible in the schematic.
+"""
+import csv
+import os
+import re
+import sys
+
+IO_RE = re.compile(r"P[TBLR]\d+[A-D]$")
+
+# Dedicated pins: name -> (kicad name, type, side, unit)
+DEDICATED = {
+ "PROGRAMN": ("~{PROGRAMN}", "input", "left", "Config"),
+ "INITN": ("~{INITN}", "open_collector", "left", "Config"),
+ "DONE": ("DONE", "open_collector", "left", "Config"),
+ "CCLK": ("CCLK", "bidirectional", "left", "Config"),
+ "CFG_0": ("CFG_0", "input", "left", "Config"),
+ "CFG_1": ("CFG_1", "input", "left", "Config"),
+ "CFG_2": ("CFG_2", "input", "left", "Config"),
+ "TCK": ("TCK", "input", "right", "Config"),
+ "TMS": ("TMS", "input", "right", "Config"),
+ "TDI": ("TDI", "input", "right", "Config"),
+ "TDO": ("TDO", "output", "right", "Config"),
+ "VCC": ("VCC", "power_in", "top", "Power"),
+ "VCCAUX": ("VCCAUX", "power_in", "top", "Power"),
+ "GND": ("GND", "power_in", "bottom", "Power"),
+}
+
+
+def main():
+ src, package, part, footprint, luts = sys.argv[1:6]
+ rows = [r for r in csv.reader(open(src, newline=""))
+ if r and any(c.strip() for c in r) and not r[0].startswith("#")]
+ header = rows[0]
+ pins = [dict(zip(header, r)) for r in rows[1:]]
+ if package not in header:
+ sys.exit(f"package {package} not in {header}")
+ pins = [p for p in pins if p[package].strip() not in ("", "-")]
+
+ # Split each bank's IOs: first half left side, second half right side.
+ banks = {}
+ for p in pins:
+ if IO_RE.match(p["Pin/Ball Function"]):
+ banks.setdefault(p["Bank"], []).append(p)
+ side_of = {}
+ for b, lst in banks.items():
+ half = (len(lst) + 1) // 2
+ for i, p in enumerate(lst):
+ side_of[id(p)] = "left" if i < half else "right"
+
+ out = csv.writer(sys.stdout)
+ out.writerow([part])
+ out.writerow(["Footprint:", footprint])
+ out.writerow(["Datasheet:",
+ "https://www.latticesemi.com/view_document?document_id=50461"])
+ out.writerow(["Description:",
+ f"ECP5 FPGA, {luts} LUTs, 1.1V core, {package}"])
+ out.writerow(["Source*:", f"Lattice pinout CSV {os.path.basename(src)}, package {package}"])
+ out.writerow(["Keywords:", "FPGA programmable logic Lattice ECP5"])
+ out.writerow(["Filters:", "BGA*256*14.0x14.0mm*P0.8mm*"])
+ out.writerow(["pin", "name", "type", "side", "unit"])
+
+ rows_out = []
+ seen = set()
+ for p in pins:
+ ball = p[package].strip()
+ if ball in seen:
+ sys.exit(f"duplicate ball {ball}")
+ seen.add(ball)
+ func = p["Pin/Ball Function"].strip()
+ dual = p["Dual Function"].strip()
+ bank = p["Bank"].strip()
+ if IO_RE.match(func):
+ name = func if dual in ("", "-") else f"{func}/{dual}"
+ rows_out.append([ball, name, "bidirectional", side_of[id(p)],
+ f"Bank{bank}"])
+ elif func.startswith("VCCIO"):
+ rows_out.append([ball, func, "power_in", "top", f"Bank{bank}"])
+ elif func in DEDICATED:
+ name, typ, side, unit = DEDICATED[func]
+ if func == "CCLK" and dual not in ("", "-"):
+ name = f"CCLK/{dual}"
+ rows_out.append([ball, name, typ, side, unit])
+ else:
+ sys.exit(f"unhandled pin {func} ({ball})")
+
+ # kipart numbers units in order of first appearance: banks ascending,
+ # then Config, then Power. Pin order inside a unit stays as in the CSV.
+ def unit_key(unit):
+ if unit.startswith("Bank"):
+ return (0, int(unit[4:]))
+ return (1, ["Config", "Power"].index(unit))
+ rows_out.sort(key=lambda r: unit_key(r[4]))
+ out.writerows(rows_out)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/kicad/lib/tools/make_7seg_fp.py b/kicad/lib/tools/make_7seg_fp.py
new file mode 100755
index 0000000..197bdc1
--- /dev/null
+++ b/kicad/lib/tools/make_7seg_fp.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-3.0-or-later
+"""Write the footprint for the ARKLED SM410561N 0.56" single digit display.
+
+Dimensions from the ARKLED specification, page 4/4: body 12.60 x 19.0 mm,
+2 x 5 pins on a 2.54 mm pitch, rows 15.24 mm apart, pin diameter 0.51 mm,
+pin 1 bottom left (digit upright), numbering counter-clockwise.
+Footprint origin = pin 1.
+
+ make_7seg_fp.py OUT.kicad_mod
+"""
+import sys
+import uuid
+
+NS = uuid.UUID("2f1b6f2e-9a77-4b8e-8f0e-5a3c7e1d2b44")
+OUT = sys.argv[1]
+W, H, PITCH, ROW = 12.60, 19.0, 2.54, 15.24
+CX, CY = 2 * PITCH, -ROW / 2 # body centre relative to pin 1
+
+
+def u(*a):
+ return str(uuid.uuid5(NS, "/".join(map(str, a))))
+
+
+def f(v):
+ v = round(v, 4)
+ return "0" if v == 0 else f"{v:g}"
+
+
+o = ['(footprint "7SegmentLED_0.56in_1Digit_SM410561N"\n\t(version 20241229)\n\t(generator "eboard")\n'
+ '\t(generator_version "9.0")\n\t(layer "F.Cu")\n'
+ '\t(descr "0.56 inch single digit 7-segment display, ARKLED SM410561N, '
+ 'https://www.lcsc.com/product-detail/C141368.html")\n'
+ '\t(tags "7 segment LED display 0.56 inch")\n']
+
+
+def prop(name, val, x, y, layer, hide=False):
+ o.append(f'\t(property "{name}" "{val}"\n\t\t(at {f(x)} {f(y)} 0)\n\t\t(layer "{layer}")\n'
+ + ('\t\t(hide yes)\n' if hide else '')
+ + f'\t\t(uuid "{u("p", name)}")\n\t\t(effects\n\t\t\t(font\n\t\t\t\t(size 1 1)\n'
+ '\t\t\t\t(thickness 0.15)\n\t\t\t)\n\t\t)\n\t)\n')
+
+
+def line(x1, y1, x2, y2, layer, w):
+ o.append(f'\t(fp_line\n\t\t(start {f(x1)} {f(y1)})\n\t\t(end {f(x2)} {f(y2)})\n\t\t(stroke\n'
+ f'\t\t\t(width {w})\n\t\t\t(type solid)\n\t\t)\n\t\t(layer "{layer}")\n'
+ f'\t\t(uuid "{u("l", layer, x1, y1, x2, y2)}")\n\t)\n')
+
+
+def rect(x1, y1, x2, y2, layer, w):
+ for a, b in (((x1, y1), (x2, y1)), ((x2, y1), (x2, y2)), ((x2, y2), (x1, y2)), ((x1, y2), (x1, y1))):
+ line(*a, *b, layer, w)
+
+
+x1, x2, y1, y2 = CX - W / 2, CX + W / 2, CY - H / 2, CY + H / 2
+prop("Reference", "REF**", CX, y1 - 1.5, "F.SilkS")
+prop("Value", "SM410561N", CX, y2 + 1.5, "F.Fab")
+prop("Datasheet", "https://www.lcsc.com/product-detail/C141368.html", 0, 0, "F.Fab", hide=True)
+prop("Description", "0.56 inch single digit 7-segment display", 0, 0, "F.Fab", hide=True)
+o.append('\t(attr through_hole)\n')
+rect(x1, y1, x2, y2, "F.Fab", 0.1)
+rect(x1 - 0.12, y1 - 0.12, x2 + 0.12, y2 + 0.12, "F.SilkS", 0.12)
+rect(x1 - 0.5, y1 - 0.5, x2 + 0.5, y2 + 0.5, "F.CrtYd", 0.05)
+line(x1 - 0.5, 1.2, x1 - 0.5, -1.2, "F.SilkS", 0.12) # pin 1 marker
+o.append(f'\t(fp_text user "${{REFERENCE}}"\n\t\t(at {f(CX)} {f(CY)} 0)\n\t\t(layer "F.Fab")\n'
+ f'\t\t(uuid "{u("t")}")\n\t\t(effects\n\t\t\t(font\n\t\t\t\t(size 1 1)\n'
+ '\t\t\t\t(thickness 0.15)\n\t\t\t)\n\t\t)\n\t)\n')
+pads = [(n, (n - 1) * PITCH, 0.0) for n in range(1, 6)] + \
+ [(n, (10 - n) * PITCH, -ROW) for n in range(6, 11)]
+for n, x, y in pads:
+ shape = "rect" if n == 1 else "circle"
+ o.append(f'\t(pad "{n}" thru_hole {shape}\n\t\t(at {f(x)} {f(y)})\n\t\t(size 1.5 1.5)\n'
+ f'\t\t(drill 0.8)\n\t\t(layers "*.Cu" "*.Mask")\n\t\t(remove_unused_layers no)\n'
+ f'\t\t(uuid "{u("pad", n)}")\n\t)\n')
+o.append('\t(embedded_fonts no)\n)\n')
+open(OUT, "w").write("".join(o))
+print("wrote", OUT)
diff --git a/kicad/lib/tools/make_eboard_lib.sh b/kicad/lib/tools/make_eboard_lib.sh
new file mode 100755
index 0000000..1399513
--- /dev/null
+++ b/kicad/lib/tools/make_eboard_lib.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-3.0-or-later
+# Build kicad/lib/eboard.kicad_sym:
+# - symbols generated by kipart from the CSV files in this folder,
+# - plus ready-made symbols from the *.kicad_sym files in this folder
+# (e.g. the HR911130A symbol from a KiCad library merge request).
+#
+# kicad/lib/tools/make_eboard_lib.sh
+#
+# Needs kipart (pipx install kipart).
+set -eu
+here=$(cd "$(dirname "$0")" && pwd)
+command -v kipart >/dev/null 2>&1 || {
+ echo "kipart not found; install it with: pipx install kipart" >&2
+ exit 1
+}
+out=$here/../eboard.kicad_sym
+tmp=$(mktemp -d)
+trap 'rm -rf "$tmp"' EXIT
+
+kipart -b --bundle-style none -w -o "$tmp/raw.kicad_sym" \
+ "$here"/ch347f.csv "$here"/rtl8211f.csv "$here"/sm410561n.csv
+python3 -I "$here/kicad_sym_grid.py" "$tmp/raw.kicad_sym" > "$tmp/grid.kicad_sym"
+
+# append the top-level symbols of the extra libraries
+python3 -I - "$tmp/grid.kicad_sym" "$here"/*.kicad_sym > "$out" <<'EOF'
+import re, sys
+
+
+def match_paren(t, i):
+ depth, j = 0, i
+ while True:
+ c = t[j]
+ if c == '"':
+ j += 1
+ while t[j] != '"':
+ j += 2 if t[j] == "\\" else 1
+ elif c == "(":
+ depth += 1
+ elif c == ")":
+ depth -= 1
+ if depth == 0:
+ return j + 1
+ j += 1
+
+
+base = open(sys.argv[1]).read()
+blocks = []
+for path in sys.argv[2:]:
+ t = open(path).read()
+ i = t.index("(", 1)
+ while True:
+ m = re.compile(r'\(symbol "').search(t, i)
+ if not m:
+ break
+ e = match_paren(t, m.start())
+ blocks.append(t[m.start():e])
+ i = e
+end = base.rstrip().rfind(")")
+sys.stdout.write(base[:end] + "".join(" " + b + "\n" for b in blocks) + ")\n")
+EOF
+echo "wrote $out"
diff --git a/kicad/lib/tools/make_ecp5_symbol.sh b/kicad/lib/tools/make_ecp5_symbol.sh
new file mode 100755
index 0000000..2495590
--- /dev/null
+++ b/kicad/lib/tools/make_ecp5_symbol.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-3.0-or-later
+# Generate the LFE5U-25F and LFE5U-45F caBGA256 symbols from the Lattice
+# pinout CSVs (FPGA-SC-02033 ECP5U-25, FPGA-SC-02034 ECP5U-45).
+#
+# kicad/lib/tools/make_ecp5_symbol.sh
+#
+# Needs kipart (pipx install kipart).
+#
+# Both parts have the same balls, banks and differential pairs in caBGA256;
+# only the pad names and the upper-corner PLL inputs (45F only) differ.
+# Writes kicad/lib/eboard_fpga.kicad_sym (overwritten).
+set -eu
+here=$(cd "$(dirname "$0")" && pwd)
+ds=$here/../../../datasheets
+command -v kipart >/dev/null 2>&1 || {
+ echo "kipart not found; install it with: pipx install kipart" >&2
+ exit 1
+}
+fp=Package_BGA:BGA-256_14.0x14.0mm_Layout16x16_P0.8mm_Ball0.45mm_Pad0.32mm_NSMD
+out=$here/../eboard_fpga.kicad_sym
+tmp=$(mktemp -d)
+trap 'rm -rf "$tmp"' EXIT
+
+python3 -I "$here/lattice2kipart.py" "$ds/FPGA-SC-02033-2-0-ECP5U-25-Pinout.csv" \
+ CABGA256 LFE5U-25F-xBG256x "$fp" 24K > "$tmp/lfe5u25.csv"
+python3 -I "$here/lattice2kipart.py" "$ds/FPGA-SC-02034-3-0-ECP5U-45-Pinout.csv" \
+ CABGA256 LFE5U-45F-xBG256x "$fp" 44K > "$tmp/lfe5u45.csv"
+# kipart names the units after the CSV unit column (Bank0 ... Bank8, Config, Power).
+kipart -b --bundle-style none -w -o "$tmp/raw.kicad_sym" "$tmp/lfe5u45.csv"
+# put all pin ends on the 2.54 mm grid
+python3 -I "$here/kicad_sym_grid.py" "$tmp/raw.kicad_sym" > "$tmp/lfe5u45.kicad_sym"
+# 25F: same geometry as the 45F symbol, pin names from the 25F pinout,
+# so "Change symbol" swaps the two parts without touching any wire.
+python3 -I "$here/derive_symbol.py" "$tmp/lfe5u45.kicad_sym" LFE5U-45F-xBG256x \
+ "$tmp/lfe5u25.csv" > "$out"
+echo "wrote $out"
diff --git a/kicad/lib/tools/rtl8211f.csv b/kicad/lib/tools/rtl8211f.csv
new file mode 100644
index 0000000..f25b3c3
--- /dev/null
+++ b/kicad/lib/tools/rtl8211f.csv
@@ -0,0 +1,49 @@
+RTL8211F-CG
+Footprint:,Package_DFN_QFN:QFN-40-1EP_5x5mm_P0.4mm_EP3.6x3.6mm_ThermalVias
+Datasheet:,https://www.realtek.com/Product/Index?id=3846
+Description:,"Integrated 10/100/1000M Ethernet transceiver, RGMII, internal 1.0V switching regulator, QFN-40 5x5mm"
+Source*:,"Realtek RTL8211F(I)-CG/RTL8211FD(I)-CG datasheet Rev. 1.4: pins section 6 tables 1-9, strap functions table 10; EP = pad 41 (GND)"
+Keywords:,Ethernet PHY gigabit RGMII Realtek
+Filters:,QFN*40*1EP*5x5mm*P0.4mm*
+pin,name,type,side
+20,TXC,input,left
+19,TXCTL,input,left
+18,TXD0,input,left
+17,TXD1,input,left
+16,TXD2,input,left
+15,TXD3,input,left
+27,RXC/PHYAD1,output,left
+26,RXCTL/PHYAD2,output,left
+25,RXD0/RXDLY,output,left
+24,RXD1/TXDLY,output,left
+23,RXD2/PLLOFF,output,left
+22,RXD3/PHYAD0,output,left
+13,MDC,input,left
+14,MDIO,bidirectional,left
+31,INTB/PMEB,open_collector,left
+12,~{PHYRSTB},input,left
+35,CLKOUT,output,left
+1,MDIP0,bidirectional,right
+2,MDIN0,bidirectional,right
+4,MDIP1,bidirectional,right
+5,MDIN1,bidirectional,right
+6,MDIP2,bidirectional,right
+7,MDIN2,bidirectional,right
+9,MDIP3,bidirectional,right
+10,MDIN3,bidirectional,right
+32,LED0/CFG_EXT,bidirectional,right
+33,LED1/CFG_LDO0,bidirectional,right
+34,LED2/CFG_LDO1,bidirectional,right
+36,XTAL_IN,input,right
+37,XTAL_OUT,output,right
+39,RSET,passive,right
+30,REG_OUT,power_out,right
+29,DVDD33,power_in,top
+28,DVDD_RG,power_in,top
+11,AVDD33,power_in,top
+40,AVDD33,power_in,top
+21,DVDD10,power_in,top
+3,AVDD10,power_in,top
+8,AVDD10,power_in,top
+38,AVDD10,power_in,top
+41,GND,power_in,bottom
diff --git a/kicad/lib/tools/sm410561n.csv b/kicad/lib/tools/sm410561n.csv
new file mode 100644
index 0000000..80aa2e8
--- /dev/null
+++ b/kicad/lib/tools/sm410561n.csv
@@ -0,0 +1,18 @@
+SM410561N
+Footprint:,eboard:7SegmentLED_0.56in_1Digit_SM410561N
+Datasheet:,https://www.lcsc.com/product-detail/C141368.html
+Description:,"0.56 inch single digit 7-segment LED display, common anode, red, through hole"
+Source*:,"ARKLED SM410561N specification (2011-12-08), page 4/4: segment pinout and dimensions"
+Keywords:,7 segment display LED common anode
+Filters:,7SegmentLED*0.56in*
+pin,name,type,side
+7,A,passive,left
+6,B,passive,left
+4,C,passive,left
+2,D,passive,left
+1,E,passive,left
+9,F,passive,left
+10,G,passive,left
+5,DP,passive,left
+3,CA,passive,top
+8,CA,passive,top