This commit is contained in:
2026-04-14 20:02:23 +02:00
parent b36d2602d4
commit ec97b915ed
39 changed files with 34391 additions and 167324 deletions
File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 134 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 134 KiB

Submodule converter/kicad-pycbnew added at b41837857d
+92 -63
View File
@@ -1,4 +1,5 @@
#!/bin/python
import math
import time
import os
import sys
@@ -23,40 +24,37 @@ from pycbnew.primitives.gr_elements import (
KGrLine,
KTable,
)
from pycbnew.primitives.segment import KSegment
import xml.etree.ElementTree as ET
# Constants / Global Variables set through argparse
SCALE = 1.0
TEXT_SPACING_MM = 12
NO_POWER_NETS = False
PCB_FILE = "trainmap.kicad_pcb"
# Global Variables set through argparse
LOG_LEVEL = logging.INFO
NO_POWER_NETS = False
NO_TEXT = False
NO_TRACES = False
SCALE = 1.0
PCB_FILE = "trainmap.kicad_pcb"
INPUT_XML = ""
MC_POS = Point(0, 0)
TITLE_FONTFACE = ""
FONTFACE = ""
MARGIN = {"left": 10, "top": 5}
TRACE_WIDTH_MM=0.5
CAP_DISTANCE_MM=5
TEXT_SPACING_MM=15
# Fonts
LINE_FONT = Font(size=(16, 16))
TITLE_FONTFACE = ""
FONTFACE = ""
LINE_FONT = Font(size=(12, 12))
LINE_FONT.face = FONTFACE
TITLE_FONT = Font(size=(28, 28))
TITLE_FONT.face = TITLE_FONTFACE
# Footprints
KFootprint.set_footprint_folders([f"{os.path.dirname(__file__)}/kicad_libs"])
FOOTPRINT_C = "Capacitor_SMD:C_0603_1608Metric"
FOOTPRINT_LED = "Dialight_587_1032_147F:587"
FOOTPRINT_MC = "DFR0654:MODULE_DFR0654"
# Mappings
TEXT_POS_MAPPING = {
"above": Vector(0, TEXT_SPACING_MM),
"right": Vector(TEXT_SPACING_MM, 0),
"below": Vector(0, -TEXT_SPACING_MM),
"left": Vector(-TEXT_SPACING_MM, 0),
}
MC_PADS = {
"GND": 30,
"GND1": 4,
@@ -69,7 +67,6 @@ LED_PADS = {"GND": 0, "VCC": 1, "DI": 2, "DO": 3}
NET_GND = KNet(1, "GND")
NET_VCC = KNet(2, "5V")
class Map:
title: str
lines: list
@@ -134,17 +131,20 @@ syntax:
</line>
</map>
"""
def parse_map(xml_file):
root = ET.parse(xml_file)
title = root.find("title").text
title_node = root.find("title")
title=""
if title_node != None:
title=title_node.text
map = Map(title)
logging.debug(f"map title: {title}")
width = 0
height = 0
id=0
for line in root.findall("line"):
line_name = line.get("name")
try:
@@ -156,20 +156,18 @@ def parse_map(xml_file):
logging.debug(f"Parsing line: {line_parsed}")
for station in line.findall("station"):
id = int(station.get("id"))
id=id+1
name = station.text
x = int(station.get("x"))
x = int(float(station.get("x")))
# search width
if x > width:
width = x
y = int(station.get("y"))
y = int(float(station.get("y")))
# search height
if y > height:
height = y
text_pos = station.get("textpos")
text_angle = int(station.get("angle"))
station_parsed = Station(id, name, x, y, text_angle, text_pos)
station_parsed = Station(id, name, x, y)
logging.debug(station_parsed)
line_parsed.add(station_parsed)
@@ -184,12 +182,13 @@ def parse_map(xml_file):
return map
"""
Creates a capacity between LED's VCC and GND
"""
def create_capacity(station):
cap_pos_index = ([*TEXT_POS_MAPPING].index(station.text_pos) + 2) % len(
TEXT_POS_MAPPING
)
cap_pos = [*TEXT_POS_MAPPING.values()][cap_pos_index]
cap_pos_x = CAP_DISTANCE_MM * math.sin(station.angle)
cap_pos_y = CAP_DISTANCE_MM * math.cos(station.angle)
cap_pos = Vector(cap_pos_x, cap_pos_y)
fp = KFootprint(FOOTPRINT_C, at=station.pos + cap_pos, angle=station.angle)
ref = fp.properties[KFootprintProperty.Type.Reference]
@@ -200,21 +199,26 @@ def create_capacity(station):
return fp
def calculate_angle(station1, station2):
vec = Vector(station2.pos.x, station2.pos.y) - Vector(station1.pos.x, station1.pos.y)
angle_rad = vec.self_angle()
return math.degrees(angle_rad)
"""
Creates the footprint for a station led
adds led, text and C
"""
def create_station_footprint(station):
fp = KFootprint(FOOTPRINT_LED, at=station.pos) # , angle=station.angle)
fp = KFootprint(FOOTPRINT_LED, at=station.pos, angle=station.angle)
# text
ref = fp.properties[KFootprintProperty.Type.Reference]
if NO_TEXT:
ref.layer = 'User.Comments'
ref.value = station.name
ref.angle = station.angle
ref.at = TEXT_POS_MAPPING[station.text_pos]
text_pos_x = TEXT_SPACING_MM * math.cos(station.angle)
text_pos_y = TEXT_SPACING_MM * math.sin(station.angle)
ref.at = Vector(text_pos_x, text_pos_y)
if not NO_POWER_NETS:
fp.pads[LED_PADS["GND"]].net = NET_GND
@@ -227,15 +231,27 @@ def create_station_footprint(station):
Creates a new net between station 1 out pad and station 2 in pad
Connects them on the PCB
"""
def connect_stations(board, station1, station2, fp1, fp2):
net = KNet(station1.id + 2, f"{station1.id}-{station2.id}")
board.add(net)
fp1.pads[LED_PADS["DO"]].net = net
fp2.pads[LED_PADS["DI"]].net = net
do = fp1.pads[LED_PADS["DO"]]
di = fp2.pads[LED_PADS["DI"]]
# connect the net
do.net = net
di.net = net
if NO_TRACES:
return
# do the trace
trace = KSegment(net=net, layer="F.Cu", point1=do.absolute_at, point2=di.absolute_at, width=TRACE_WIDTH_MM)
board.add(trace)
"""
Connects the line to the MC
"""
def connect_line(board, mc, line, station_fp):
if connect_line.gpio_ptr > len(MC_PADS["gpios"]):
logging.critical(
@@ -253,16 +269,12 @@ def connect_line(board, mc, line, station_fp):
station_fp.pads[LED_PADS["DI"]].net = net
connect_line.gpio_ptr += 1
connect_line.gpio_ptr = 0
"""
Adds the main microcontroller
"""
def add_mc(board):
mc = KFootprint(FOOTPRINT_MC, at=MC_POS)
@@ -278,22 +290,15 @@ def add_mc(board):
adds labels for the lines to the next position in the TEXT_POS_MAPPING list
from the position of the text label of the station (just a best estimate)
"""
def add_line_label(board, line, station):
text_pos_x = station.pos.x + TEXT_SPACING_MM * math.sin(-0.25*station.angle)
text_pos_y = station.pos.y + TEXT_SPACING_MM * math.cos(-0.25*station.angle)
# get next position
text_pos_index = ([*TEXT_POS_MAPPING].index(station.text_pos) + 1) % len(
TEXT_POS_MAPPING
)
text_pos = [*TEXT_POS_MAPPING.values()][text_pos_index]
line_pos = Point(station.pos.x + 2 * text_pos.x,
station.pos.y + 2 * text_pos.y)
text_pos = Vector(text_pos_x, text_pos_y)
text = KGrText(
layer="F.SilkS", text=f"{line.name}", at=line_pos, angle=station.angle
layer="F.SilkS", text=f"{line.name}", at=text_pos
)
text.font = LINE_FONT
#text.font = LINE_FONT
board.add(text)
@@ -301,9 +306,10 @@ def add_line_label(board, line, station):
"""
adds a board title top middle
"""
def add_title_label(board, map):
if NO_TEXT:
return
logging.debug(f"add map title: {map.title}")
text = KGrText(
layer="F.SilkS", text=f"{map.title}", at=Point(map.width / 2, MARGIN["top"])
@@ -316,8 +322,6 @@ def add_title_label(board, map):
"""
main pcb generation loop
"""
def generate_pcb(map):
board = KProject(PCB_FILE)
board.add(NET_GND)
@@ -330,7 +334,14 @@ def generate_pcb(map):
for line in map.lines:
prev_station = None
prev_led = None
if len(line.stations) == 0:
continue
for station in line.stations:
if prev_station is not None:
station.angle = calculate_angle(prev_station, station)
else:
station.angle = calculate_angle(station, line.stations[1])
logging.debug(f"angle between stations: {station.angle}")
led = create_station_footprint(station)
board.add(led)
cap = create_capacity(station)
@@ -374,7 +385,7 @@ def main():
def parse_arguments():
global SCALE, TEXT_SPACING_MM, NO_POWER_NETS, PCB_FILE, LOG_LEVEL, INPUT_XML
global SCALE, TEXT_SPACING_MM, NO_TEXT, NO_POWER_NETS, NO_TRACES, PCB_FILE, LOG_LEVEL, INPUT_XML
parser = argparse.ArgumentParser(
description="train map pcb generator",
@@ -393,10 +404,20 @@ def parse_arguments():
default=5,
help="spacing of the text from the center point of led (mm)",
)
parser.add_argument(
"--no-text",
action="store_true",
help="do not produce any text",
)
parser.add_argument(
"--no-power-nets",
action="store_true",
help="do not connect (easier visual debugging)",
help="do not connect GND and VCC (easier visual debugging)",
)
parser.add_argument(
"--no-traces",
action="store_true",
help="do not implement traces between leds",
)
parser.add_argument(
"--output",
@@ -418,7 +439,9 @@ def parse_arguments():
INPUT_XML = args.input
SCALE = args.scale
TEXT_SPACING_MM = args.text_space
NO_TEXT = args.no_text
NO_POWER_NETS = args.no_power_nets
NO_TRACES = args.no_traces
PCB_FILE = args.output
if args.verbose > 0:
@@ -429,9 +452,15 @@ def parse_arguments():
print(f"Warning: Output file '{
PCB_FILE}' does not have .kicad_pcb extension.")
if NO_TEXT:
print("Mode: No text")
if args.no_power_nets:
print("Mode: Power nets disabled.")
if NO_TRACES:
print("Mode: No traces")
if __name__ == "__main__":
main()
+227 -164
View File
@@ -1,184 +1,247 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
S-Bahn München Network Map Data
Extracted from Netzplan_S-Bahn_München.svg (Stand: Dezember 2024)
CC-BY-SA Zeno Heilmaier
Coordinate system: SVG viewBox 0 0 2400 1280
x/y = center of station marker circle (or midpoint between circles for multi-circle stations)
Diagonal X-marker stations: midpoint of the two crossing points
Each station listed once only, under its first-occurring line (S1 first, then S2…S8, S20)
-->
<map>
<title>Munich S</title>
<!-- ══════════════════════════════════════════
STAMMSTRECKE (central tunnel)
Shared by S1 S2 S3 S4 S6 S7 S8 S20
══════════════════════════════════════════ -->
<line name="Stammstrecke" color="None">
<station id="1" x="345" y="525" angle="0" textpos="below" lines="[S3,S4,S6,S8,S20]">Pasing</station>
<station id="2" x="385" y="525" angle="30" textpos="above" lines="[S1,S2,S3,S4,S6,S8]">Laim</station>
<station id="3" x="420" y="525" angle="90" textpos="above" lines="[S1,S2,S3,S4,S6,S8]">Hirschgarten</station>
<station id="4" x="455" y="525" angle="90" textpos="above" lines="[S1,S2,S3,S4,S6,S8,S7,S20]">Donnersbergerbrücke</station>
<station id="5" x="490" y="525" angle="90" textpos="above" lines="[S1,S2,S3,S4,S6,S8]">Hackerbrücke</station>
<station id="6" x="530" y="525" angle="90" textpos="above" lines="[S1,S2,S3,S4,S6,S8,S7]">Hauptbahnhof</station>
<station id="7" x="565" y="525" angle="90" textpos="above" lines="[S1,S2,S3,S4,S6,S8,S7]">Karlsplatz (Stachus)</station>
<station id="8" x="600" y="525" angle="90" textpos="above" lines="[S1,S2,S3,S4,S6,S8,S7]">Marienplatz</station>
<station id="9" x="635" y="525" angle="90" textpos="above" lines="[S1,S2,S3,S4,S6,S8,S7]">Isartor</station>
<station id="10" x="670" y="525" angle="90" textpos="above" lines="[S1,S2,S3,S4,S6,S8,S7]">Rosenheimer Platz</station>
<station id="11" x="710" y="525" angle="90" textpos="above" lines="[S1,S2,S3,S4,S6,S8,S7]">Ostbahnhof</station>
<station id="12" x="750" y="525" angle="90" textpos="above" lines="[S1,S2,S4,S6,S8]">Leuchtenbergring</station>
<station id="13" x="785" y="535" angle="90" textpos="below" lines="[S2,S4,S6]">Berg am Laim</station>
<station x="735" y="675" lines="[S1,S2,S3,S4,S6,S8,S20]">Pasing</station>
<station x="825" y="675" lines="[S1,S2,S3,S4,S6,S8]">Laim</station>
<station x="915" y="675" lines="[S1,S2,S3,S4,S6,S7,S8]">Donnersbergerbrücke</station>
<station x="1005" y="675" lines="[S1,S2,S3,S4,S6,S7,S8]">Hackerbrücke</station>
<station x="1095" y="675" lines="[S1,S2,S3,S4,S6,S7,S8]">Hauptbahnhof</station>
<station x="1185" y="675" lines="[S1,S2,S3,S4,S6,S7,S8]">Karlsplatz (Stachus)</station>
<station x="1275" y="675" lines="[S1,S2,S3,S4,S6,S7,S8]">Marienplatz</station>
<station x="1365" y="675" lines="[S1,S2,S3,S4,S6,S7,S8]">Isartor</station>
<station x="1455" y="675" lines="[S1,S2,S3,S4,S6,S7,S8]">Rosenheimer Platz</station>
<station x="1545" y="675" lines="[S1,S2,S3,S4,S6,S7,S8]">Ostbahnhof</station>
</line>
<line name="S1" color="cyan">
<station id="14" x="730" y="110" angle="0" textpos="left">Freising</station>
<station id="15" x="730" y="140" angle="0" textpos="left">Pulling</station>
<station id="16" x="690" y="230" angle="0" textpos="above">Neufahrn</station>
<station id="17" x="630" y="230" angle="0" textpos="above">Eching</station>
<station id="18" x="570" y="230" angle="0" textpos="above">Lohhof</station>
<station id="19" x="520" y="230" angle="0" textpos="above">Unterschleißheim</station>
<station id="20" x="460" y="230" angle="0" textpos="above">Oberschleißheim</station>
<station id="21" x="415" y="265" angle="0" textpos="right" lines="[S1,U2]">Feldmoching</station>
<station id="22" x="385" y="315" angle="0" textpos="right">Fasanerie</station>
<station id="23" x="355" y="365" angle="0" textpos="right" lines="[S1,U3]">Moosach</station>
<station id="24" x="795" y="170" angle="0" textpos="right">Flughafen München</station>
<station id="25" x="775" y="200" angle="0" textpos="right">Flughafen Besucherpark</station>
<!-- ══════════════════════════════════════════
S1 Freising / Flughafen München Erding
Color: #16bae7
══════════════════════════════════════════ -->
<line name="S1" color="#16bae7">
<station x="1725" y="150" lines="[S1]">Freising</station>
<station x="1725" y="225" lines="[S1,S8]">Pulling</station>
<!-- Airport branch -->
<station x="1820" y="285" lines="[S1]">Flughafen Besucherpark</station>
<station x="1885" y="220" lines="[S1,S8]">Flughafen München</station>
<!-- Shared S1/S8 section south of airport -->
<station x="1620" y="300" lines="[S1,S8]">Neufahrn</station>
<station x="1470" y="300" lines="[S1,S8]">Eching</station>
<station x="1320" y="300" lines="[S1,S8]">Lohhof</station>
<station x="1020" y="300" lines="[S1,S8]">Oberschleißheim</station>
<station x="1170" y="300" lines="[S1,S8]">Unterschleißheim</station>
<!-- East of Ostbahnhof -->
<station x="1725" y="675" lines="[S1,S2,S3,S4,S6]">Leuchtenbergring</station>
<station x="1815" y="675" lines="[S1,S2,S4]">Berg am Laim</station>
<station x="1905" y="615" lines="[S1,S2]">Riem</station>
<station x="1940" y="580" lines="[S1,S2]">Feldkirchen</station>
<station x="1975" y="545" lines="[S1,S2]">Heimstetten</station>
<station x="2010" y="510" lines="[S1,S2]">Grub</station>
<station x="2045" y="475" lines="[S1,S2]">Poing</station>
<station x="2080" y="440" lines="[S1,S2]">Markt Schwaben</station>
<station x="2090" y="395" lines="[S1]">Ottenhofen</station>
<station x="2090" y="350" lines="[S1]">St. Koloman</station>
<station x="2090" y="305" lines="[S1]">Aufhausen</station>
<station x="2090" y="260" lines="[S1]">Altenerding</station>
<station x="2090" y="215" lines="[S1]">Erding</station>
</line>
<line name="S2" color="lime">
<station id="26" x="120" y="70" angle="0" textpos="above">Altomünster</station>
<station id="27" x="145" y="70" angle="0" textpos="above">Kleinberghofen</station>
<station id="28" x="170" y="70" angle="0" textpos="above">Erdweg</station>
<station id="29" x="195" y="90" angle="0" textpos="left">Arnbach</station>
<station id="30" x="210" y="105" angle="0" textpos="left">Markt Indersdorf</station>
<station id="31" x="225" y="130" angle="0" textpos="left">Niederroth</station>
<station id="32" x="240" y="155" angle="0" textpos="left">Schwabhausen</station>
<station id="33" x="255" y="180" angle="0" textpos="left">Bachern</station>
<station id="34" x="270" y="205" angle="0" textpos="left">Dachau Stadt</station>
<station id="35" x="290" y="55" angle="0" textpos="right">Petershausen</station>
<station id="36" x="290" y="90" angle="0" textpos="right">Vierkirchen-Esterhofen</station>
<station id="37" x="290" y="135" angle="0" textpos="right">Röhrmoos</station>
<station id="38" x="290" y="175" angle="0" textpos="right">Hebertshausen</station>
<station id="39" x="290" y="250" angle="0" textpos="right">Dachau</station>
<station id="40" x="290" y="290" angle="0" textpos="right">Karlsfeld</station>
<station id="41" x="290" y="330" angle="0" textpos="right">Allach</station>
<station id="42" x="290" y="370" angle="0" textpos="right">Untermenzing</station>
<station id="43" x="290" y="410" angle="0" textpos="right">Obermenzing</station>
<station id="44" x="870" y="165" angle="0" textpos="right">Erding</station>
<station id="45" x="870" y="200" angle="0" textpos="right">Altenerding</station>
<station id="46" x="870" y="235" angle="0" textpos="right">Aufhausen</station>
<station id="47" x="870" y="270" angle="0" textpos="right">St. Koloman</station>
<station id="48" x="870" y="305" angle="0" textpos="right">Ottenhofen</station>
<station id="49" x="860" y="345" angle="45" textpos="right">Markt Schwaben</station>
<station id="50" x="850" y="365" angle="45" textpos="right">Poing</station>
<station id="51" x="840" y="385" angle="45" textpos="right">Grub</station>
<station id="52" x="830" y="405" angle="45" textpos="right">Heimstetten</station>
<station id="53" x="820" y="425" angle="45" textpos="right">Feldkirchen</station>
<station id="54" x="810" y="465" angle="45" textpos="right">Riem</station>
<!-- ══════════════════════════════════════════
S2 Petershausen / Altomünster Erding
Color: #76b82a
══════════════════════════════════════════ -->
<line name="S2" color="#76b82a">
<!-- NW branch: Petershausen -->
<station x="675" y="75" lines="[S2]">Petershausen</station>
<station x="675" y="125" lines="[S2]">Vierkirchen-Esterhofen</station>
<station x="675" y="175" lines="[S2]">Röhrmoos</station>
<station x="675" y="225" lines="[S2]">Hebertshausen</station>
<station x="675" y="325" lines="[S2,S3]">Dachau</station>
<station x="675" y="375" lines="[S2,S3]">Karlsfeld</station>
<station x="675" y="425" lines="[S2,S3]">Allach</station>
<station x="675" y="475" lines="[S2,S3]">Untermenzing</station>
<station x="695" y="541" lines="[S2,S3]">Obermenzing</station>
<station x="795" y="480" lines="[S2,S3]">Moosach</station>
<station x="870" y="405" lines="[S2,S3]">Fasanerie</station>
<station x="945" y="330" lines="[S2,S3]">Feldmoching</station>
<!-- NE branch: Altomünster -->
<station x="275" y="75" lines="[S2]">Altomünster</station>
<station x="350" y="75" lines="[S2]">Kleinberghofen</station>
<station x="425" y="75" lines="[S2]">Erdweg</station>
<station x="475" y="100" lines="[S2]">Arnbach</station>
<station x="510" y="135" lines="[S2]">Markt Indersdorf</station>
<station x="545" y="170" lines="[S2]">Niederroth</station>
<station x="580" y="205" lines="[S2]">Schwabhausen</station>
<station x="615" y="240" lines="[S2]">Bachern</station>
<station x="650" y="275" lines="[S2]">Dachau Stadt</station>
</line>
<line name="S3" color="purple">
<station id="55" x="160" y="255" angle="315" textpos="above">Mammendorf</station>
<station id="56" x="175" y="270" angle="315" textpos="above">Malching</station>
<station id="57" x="190" y="285" angle="315" textpos="above">Maisach</station>
<station id="58" x="205" y="300" angle="315" textpos="above">Gernlinden</station>
<station id="59" x="220" y="335" angle="315" textpos="above">Esting</station>
<station id="60" x="235" y="350" angle="315" textpos="above">Olching</station>
<station id="61" x="250" y="380" angle="315" textpos="above">Gröbenzell</station>
<station id="62" x="265" y="415" angle="315" textpos="above">Lochhausen</station>
<station id="63" x="280" y="455" angle="315" textpos="above">Langwied</station>
<station id="64" x="695" y="585" angle="0" textpos="right">St.-Martin-Straße</station>
<station id="65" x="650" y="630" angle="0" textpos="right" lines="[S3,S7,U2]">Giesing</station>
<station id="66" x="640" y="675" angle="0" textpos="left">Fasangarten</station>
<station id="67" x="640" y="710" angle="0" textpos="left">Fasanenpark</station>
<station id="68" x="640" y="745" angle="0" textpos="left">Unterhaching</station>
<station id="69" x="640" y="780" angle="0" textpos="left">Taufkirchen</station>
<station id="70" x="640" y="815" angle="0" textpos="left">Furth</station>
<station id="71" x="640" y="850" angle="0" textpos="left">Deisenhofen</station>
<station id="72" x="640" y="885" angle="0" textpos="left">Sauerlach</station>
<station id="73" x="640" y="920" angle="0" textpos="left">Otterfing</station>
<station id="74" x="640" y="955" angle="0" textpos="left">Holzkirchen</station>
<!-- ══════════════════════════════════════════
S3 Mammendorf Holzkirchen
Color: #ea516d
══════════════════════════════════════════ -->
<line name="S3" color="#ea516d">
<station x="350" y="335" lines="[S3]">Mammendorf</station>
<station x="385" y="370" lines="[S3]">Malching</station>
<station x="420" y="405" lines="[S3]">Maisach</station>
<station x="455" y="440" lines="[S3]">Gernlinden</station>
<station x="490" y="475" lines="[S3]">Esting</station>
<station x="525" y="510" lines="[S3]">Olching</station>
<station x="560" y="545" lines="[S3]">Gröbenzell</station>
<station x="595" y="580" lines="[S3]">Lochhausen</station>
<station x="630" y="615" lines="[S3,S4,S6,S8]">Langwied</station>
<!-- East via Ostbahnhof: Perlach, Giesing branch to Holzkirchen -->
<station x="1593" y="860" lines="[S3]">Perlach</station>
<station x="1545" y="815" lines="[S3]">St.-Martin-Straße</station>
<station x="1545" y="850" lines="[S3]">Giesing</station>
<station x="1520" y="871" lines="[S3]">Fasangarten</station>
<station x="1520" y="917" lines="[S3]">Fasanenpark</station>
<station x="1520" y="962" lines="[S3]">Unterhaching</station>
<station x="1520" y="1008" lines="[S3]">Taufkirchen</station>
<station x="1520" y="1053" lines="[S3]">Furth</station>
<station x="1520" y="1099" lines="[S3]">Deisenhofen</station>
<station x="1520" y="1144" lines="[S3]">Sauerlach</station>
<station x="1520" y="1190" lines="[S3]">Otterfing</station>
<station x="1520" y="1235" lines="[S3]">Holzkirchen</station>
</line>
<line name="S4" color="red">
<station id="75" x="60" y="685" angle="0" textpos="left">Geltendorf</station>
<station id="76" x="80" y="660" angle="315" textpos="above">Türkenfeld</station>
<station id="77" x="95" y="645" angle="315" textpos="above">Grafrath</station>
<station id="78" x="105" y="635" angle="315" textpos="above">Schöngeising</station>
<station id="79" x="115" y="625" angle="315" textpos="above">Buchenau</station>
<station id="80" x="135" y="595" angle="315" textpos="above">Fürstenfeldbruck</station>
<station id="81" x="155" y="550" angle="0" textpos="above">Eichenau</station>
<station id="82" x="195" y="550" angle="0" textpos="above">Puchheim</station>
<station id="83" x="225" y="550" angle="0" textpos="above">Aubing</station>
<station id="84" x="255" y="550" angle="0" textpos="above">Leienfelsstraße</station>
<station id="85" x="815" y="540" angle="0" textpos="below">Trudering</station>
<station id="86" x="840" y="550" angle="45" textpos="right">Gronsdorf</station>
<station id="87" x="850" y="565" angle="45" textpos="right">Haar</station>
<station id="88" x="860" y="580" angle="45" textpos="right">Vaterstetten</station>
<station id="89" x="870" y="595" angle="45" textpos="right">Baldham</station>
<station id="90" x="880" y="610" angle="45" textpos="right">Zorneding</station>
<station id="91" x="890" y="625" angle="45" textpos="right">Eglharting</station>
<station id="92" x="900" y="640" angle="45" textpos="right">Kirchseeon</station>
<station id="93" x="915" y="660" angle="45" textpos="right">Grafing Bahnhof</station>
<station id="94" x="925" y="685" angle="45" textpos="right">Grafing Stadt</station>
<station id="95" x="935" y="710" angle="45" textpos="right">Ebersberg</station>
<!-- ══════════════════════════════════════════
S4 Geltendorf Ebersberg
Color: #e3051b
══════════════════════════════════════════ -->
<line name="S4" color="#e3051b">
<station x="140" y="885" lines="[S4]">Geltendorf</station>
<station x="175" y="850" lines="[S4]">Türkenfeld</station>
<station x="210" y="815" lines="[S4]">Grafrath</station>
<station x="245" y="780" lines="[S4]">Schöngeising</station>
<station x="280" y="745" lines="[S4]">Buchenau</station>
<station x="315" y="710" lines="[S4]">Fürstenfeldbruck</station>
<station x="375" y="675" lines="[S4,S5,S6]">Eichenau</station>
<station x="450" y="675" lines="[S4,S5,S6]">Puchheim</station>
<station x="525" y="675" lines="[S4,S5,S6]">Aubing</station>
<station x="600" y="675" lines="[S4,S5,S6]">Leienfelsstraße</station>
<!-- East: Trudering → Ebersberg (shared with S6) -->
<station x="1905" y="682" lines="[S4,S6]">Trudering</station>
<station x="1970" y="700" lines="[S4,S6]">Gronsdorf</station>
<station x="2000" y="730" lines="[S4,S6]">Haar</station>
<station x="2030" y="760" lines="[S4,S6]">Vaterstetten</station>
<station x="2060" y="790" lines="[S4,S6]">Baldham</station>
<station x="2090" y="820" lines="[S4,S6]">Zorneding</station>
<station x="2120" y="850" lines="[S4,S6]">Eglharting</station>
<station x="2150" y="880" lines="[S4,S6]">Kirchseeon</station>
<station x="2180" y="910" lines="[S4,S6]">Grafing Bahnhof</station>
<station x="2210" y="940" lines="[S4]">Grafing Stadt</station>
<station x="2240" y="970" lines="[S4]">Ebersberg</station>
</line>
<line name="S6" color="forestgreen">
<station id="96" x="270" y="955" angle="0" textpos="right">Tutzing</station>
<station id="97" x="270" y="920" angle="0" textpos="right">Feldafing</station>
<station id="98" x="270" y="885" angle="0" textpos="right">Possenhofen</station>
<station id="99" x="270" y="850" angle="0" textpos="right">Starnberg</station>
<station id="100" x="270" y="815" angle="0" textpos="right">Starnberg Nord</station>
<station id="101" x="270" y="780" angle="0" textpos="right">Gauting</station>
<station id="102" x="270" y="745" angle="0" textpos="right">Stockdorf</station>
<station id="103" x="270" y="710" angle="0" textpos="right">Planegg</station>
<station id="104" x="270" y="675" angle="0" textpos="right">Gräfelfing</station>
<station id="105" x="270" y="630" angle="0" textpos="right">Lochham</station>
<station id="106" x="290" y="570" angle="45" textpos="left" lines="[S6,S8]">Westkreuz</station>
<!-- ══════════════════════════════════════════
S5 Herrsching Kreuzstraße
Color: #00547e
══════════════════════════════════════════ -->
<line name="S5" color="#00547e">
<station x="250" y="1120" lines="[S5]">Herrsching</station>
<station x="285" y="1085" lines="[S5]">Seefeld-Hechendorf</station>
<station x="320" y="1050" lines="[S5]">Steinebach</station>
<station x="340" y="1020" lines="[S5]">Weßling</station>
<station x="375" y="985" lines="[S5]">Neugilching</station>
<station x="410" y="950" lines="[S5]">Gilching-Argelsried</station>
<station x="445" y="915" lines="[S5]">Geisenbrunn</station>
<station x="470" y="875" lines="[S5]">Germering-Unterpfaffenhofen</station>
<station x="480" y="880" lines="[S5]">Harthaus</station>
<station x="515" y="845" lines="[S5]">Freiham</station>
<station x="550" y="810" lines="[S5]">Neuaubing</station>
<station x="590" y="770" lines="[S5,S6,S8]">Westkreuz</station>
<!-- East: Neuperlach Süd → Kreuzstraße -->
<station x="1645" y="890" lines="[S5]">Neuperlach Süd</station>
<station x="1645" y="925" lines="[S5]">Neubiberg</station>
<station x="1645" y="960" lines="[S5]">Ottobrunn</station>
<station x="1645" y="995" lines="[S5]">Hohenbrunn</station>
<station x="1645" y="1030" lines="[S5]">Wächterhof</station>
<station x="1645" y="1065" lines="[S5]">Höhenkirchen-Siegertsbrunn</station>
<station x="1645" y="1100" lines="[S5]">Dürrnhaar</station>
<station x="1645" y="1135" lines="[S5]">Aying</station>
<station x="1645" y="1165" lines="[S5]">Peiß</station>
<station x="1645" y="1200" lines="[S5]">Großhelfendorf</station>
<station x="1645" y="1235" lines="[S5]">Kreuzstraße</station>
</line>
<line name="S7" color="maroon">
<station id="107" x="400" y="955" angle="0" textpos="right">Wolfratshausen</station>
<station id="108" x="400" y="925" angle="0" textpos="right">Icking</station>
<station id="109" x="400" y="900" angle="0" textpos="right">Ebenhausen-Schäftlarn</station>
<station id="110" x="400" y="875" angle="0" textpos="right">Hohenschäftlarn</station>
<station id="111" x="400" y="850" angle="0" textpos="right">Baierbrunn</station>
<station id="112" x="400" y="825" angle="0" textpos="right">Buchenhain</station>
<station id="113" x="400" y="800" angle="0" textpos="right" lines="[S7,S20]">Höllriegelskreuth</station>
<station id="114" x="400" y="775" angle="0" textpos="right">Pullach</station>
<station id="115" x="400" y="750" angle="0" textpos="right">Großhesselohe Isartalbahnhof</station>
<station id="116" x="400" y="725" angle="0" textpos="right" lines="[S7,S20]">Solln</station>
<station id="117" x="400" y="695" angle="0" textpos="right" lines="[S7,S20]">Siemenswerke</station>
<station id="118" x="400" y="665" angle="0" textpos="right" lines="[S7,S20]">Mittersendling</station>
<station id="119" x="400" y="635" angle="0" textpos="right">Harras</station>
<station id="120" x="400" y="595" angle="0" textpos="right" lines="[S7,S20,U4,U5]">Heimeranplatz</station>
<station id="121" x="690" y="685" angle="0" textpos="right">Perlach</station>
<station id="122" x="690" y="705" angle="0" textpos="right">Neuperlach Süd</station>
<station id="123" x="690" y="725" angle="0" textpos="right">Neubiberg</station>
<station id="124" x="690" y="750" angle="0" textpos="right">Ottobrunn</station>
<station id="125" x="690" y="775" angle="0" textpos="right">Hohenbrunn</station>
<station id="126" x="690" y="800" angle="0" textpos="right">Wächterhof</station>
<station id="127" x="690" y="825" angle="0" textpos="right">Höhenkirchen-Siegertsbrunn</station>
<station id="128" x="690" y="850" angle="0" textpos="right">Dürrnhaar</station>
<station id="129" x="690" y="875" angle="0" textpos="right">Aying</station>
<station id="130" x="690" y="900" angle="0" textpos="right">Peiß</station>
<station id="131" x="690" y="925" angle="0" textpos="right">Großhelfendorf</station>
<station id="132" x="690" y="955" angle="0" textpos="right">Kreuzstraße</station>
<!-- ══════════════════════════════════════════
S6 Tutzing Ebersberg
Color: #008d58
══════════════════════════════════════════ -->
<line name="S6" color="#008d58">
<station x="635" y="1235" lines="[S6]">Tutzing</station>
<station x="635" y="1184" lines="[S6]">Feldafing</station>
<station x="635" y="1134" lines="[S6]">Possenhofen</station>
<station x="635" y="1083" lines="[S6]">Starnberg</station>
<station x="635" y="1033" lines="[S6]">Starnberg Nord</station>
<station x="635" y="982" lines="[S6]">Gauting</station>
<station x="635" y="932" lines="[S6]">Stockdorf</station>
<station x="635" y="881" lines="[S6]">Planegg</station>
<station x="635" y="831" lines="[S6]">Gräfelfing</station>
<station x="635" y="780" lines="[S6]">Lochham</station>
<!-- East stations shared with S4 listed under S4 -->
</line>
<line name="S8" color="black">
<station id="133" x="110" y="870" angle="0" textpos="left">Herrsching</station>
<station id="134" x="125" y="850" angle="45" textpos="left">Seefeld-Hechendorf</station>
<station id="135" x="135" y="835" angle="45" textpos="left">Steinebach</station>
<station id="136" x="145" y="810" angle="0" textpos="left">Weßling</station>
<station id="137" x="160" y="765" angle="45" textpos="left">Neugilching</station>
<station id="138" x="175" y="745" angle="45" textpos="left">Gilching-Argelsried</station>
<station id="139" x="190" y="725" angle="45" textpos="left">Geisenbrunn</station>
<station id="140" x="205" y="700" angle="45" textpos="left">Germering-Unterpfaffenhofen</station>
<station id="141" x="220" y="675" angle="45" textpos="left">Harthaus</station>
<station id="142" x="235" y="650" angle="45" textpos="left">Freiham</station>
<station id="143" x="250" y="615" angle="45" textpos="left">Neuaubing</station>
<!-- ══════════════════════════════════════════
S7 Wolfratshausen Ostbahnhof
Color: #892e23
══════════════════════════════════════════ -->
<line name="S7" color="#892e23">
<station x="965" y="1235" lines="[S7]">Wolfratshausen</station>
<station x="965" y="1200" lines="[S7]">Icking</station>
<station x="965" y="1165" lines="[S7]">Ebenhausen-Schäftlarn</station>
<station x="965" y="1130" lines="[S7]">Hohenschäftlarn</station>
<station x="965" y="1095" lines="[S7]">Baierbrunn</station>
<station x="965" y="1060" lines="[S7]">Buchenhain</station>
<station x="965" y="1025" lines="[S7,S20]">Höllriegelskreuth</station>
<station x="965" y="990" lines="[S7]">Pullach</station>
<station x="965" y="955" lines="[S7]">Großhesselohe Isartalbahnhof</station>
<station x="965" y="920" lines="[S7]">Solln</station>
<station x="965" y="885" lines="[S7]">Siemenswerke</station>
<station x="965" y="850" lines="[S7]">Mittersendling</station>
<station x="965" y="815" lines="[S7]">Harras</station>
<station x="965" y="780" lines="[S7,S20]">Heimeranplatz</station>
</line>
<station id="144" x="760" y="465" angle="0" textpos="right">Daglfing</station>
<station id="145" x="760" y="430" angle="0" textpos="right">Englschalking</station>
<station id="146" x="760" y="390" angle="0" textpos="right">Johanneskirchen</station>
<station id="147" x="760" y="350" angle="0" textpos="right">Unterföhring</station>
<station id="148" x="760" y="310" angle="0" textpos="right">Ismaning</station>
<station id="149" x="760" y="260" angle="0" textpos="right">Hallbergmoos</station>
<!-- ══════════════════════════════════════════
S8 Herrsching Flughafen München
Color: #f0ac32
(HerrschingWestkreuz shared with S5; Stammstrecke shared;
Berg am LaimDaglfing diverges northeast to airport)
══════════════════════════════════════════ -->
<line name="S8" color="#f0ac32">
<station x="1815" y="600" lines="[S8]">Daglfing</station>
<station x="1815" y="550" lines="[S8]">Englschalking</station>
<station x="1815" y="500" lines="[S8]">Johanneskirchen</station>
<station x="1815" y="450" lines="[S8]">Unterföhring</station>
<station x="1815" y="400" lines="[S8]">Ismaning</station>
<station x="1815" y="350" lines="[S8]">Hallbergmoos</station>
<!-- Flughafen München listed under S1 -->
</line>
<!-- ══════════════════════════════════════════
S20 Pasing Deisenhofen (orbital, limited service)
Color: #892e23
Shares Stammstrecke and S7 southern stations.
No unique-to-S20 stations beyond what is listed elsewhere.
══════════════════════════════════════════ -->
<line name="S20" color="#892e23">
<!-- All stations shared with Stammstrecke and S7; see those lines. -->
</line>
</map>
+182
View File
@@ -0,0 +1,182 @@
<map>
<line name="Stammstrecke" color="None">
<station x="725" y="725" lines="[S1,S2,S3,S4,S6,S8,S20]">Pasing</station>
<station x="825" y="630" lines="[S1,S2,S3,S4,S6,S8]">Laim</station>
<station x="915" y="630" lines="[S1,S2,S3,S4,S6,S7,S8]">Donnersbergerbrücke</station>
<station x="1005" y="630" lines="[S1,S2,S3,S4,S6,S7,S8]">Hackerbrücke</station>
<station x="1095" y="630" lines="[S1,S2,S3,S4,S6,S7,S8]">Hauptbahnhof</station>
<station x="1185" y="630" lines="[S1,S2,S3,S4,S6,S7,S8]">Karlsplatz (Stachus)</station>
<station x="1275" y="630" lines="[S1,S2,S3,S4,S6,S7,S8]">Marienplatz</station>
<station x="1365" y="630" lines="[S1,S2,S3,S4,S6,S7,S8]">Isartor</station>
<station x="1455" y="630" lines="[S1,S2,S3,S4,S6,S7,S8]">Rosenheimer Platz</station>
<station x="1545" y="725" lines="[S1,S2,S3,S4,S6,S8]">Ostbahnhof</station>
</line>
<line name="S1" color="#16bae7">
<station x="1725" y="150" lines="[S1]">Freising</station>
<station x="1725" y="195" lines="[S1]">Pulling</station>
<station x="1725" y="240" lines="[S1]">Neufahrn</station>
<station x="1879" y="214" lines="[S1,S8]">Flughafen München</station>
<station x="1824" y="269" lines="[S1,S8]">Besucherpark</station>
<station x="1635" y="240" lines="[S1]">Eching</station>
<station x="1545" y="240" lines="[S1]">Lohhof</station>
<station x="1455" y="240" lines="[S1]">Unterschleißheim</station>
<station x="1365" y="240" lines="[S1]">Oberschleißheim</station>
<station x="1235" y="370" lines="[S1]">Feldmoching</station>
<station x="1145" y="460" lines="[S1]">Fasanerie</station>
<station x="1055" y="550" lines="[S1]">Moosach</station>
</line>
<line name="S2" color="#76b82a">
<station x="275" y="75" lines="[S2]">Altomünster</station>
<station x="385" y="185" lines="[S2]">Kleinberghofen</station>
<station x="495" y="295" lines="[S2]">Erdweg</station>
<station x="605" y="405" lines="[S2]">Arnbach</station>
<station x="675" y="75" lines="[S2]">Petershausen</station>
<station x="675" y="120" lines="[S2]">Vierkirchen-Esterhofen</station>
<station x="675" y="165" lines="[S2]">Röhrmoos</station>
<station x="675" y="210" lines="[S2]">Hebertshausen</station>
<station x="675" y="325" lines="[S2]">Dachau</station>
<station x="675" y="370" lines="[S2]">Karlsfeld</station>
<station x="675" y="415" lines="[S2]">Allach</station>
<station x="675" y="460" lines="[S2]">Untermenzing</station>
<station x="675" y="505" lines="[S2]">Obermenzing</station>
<station x="1635" y="725" lines="[S2,S4,S6,S8]">Leuchtenbergring</station>
<station x="1725" y="725" lines="[S2,S4,S6]">Berg am Laim</station>
<station x="1815" y="725" lines="[S2]">Riem</station>
<station x="1905" y="725" lines="[S2]">Feldkirchen</station>
<station x="1995" y="725" lines="[S2]">Heimstetten</station>
<station x="2085" y="725" lines="[S2]">Grub</station>
<station x="2175" y="635" lines="[S2]">Poing</station>
<station x="2175" y="545" lines="[S2]">Markt Schwaben</station>
<station x="2090" y="440" lines="[S2]">Ottenhofen</station>
<station x="2090" y="395" lines="[S2]">St. Koloman</station>
<station x="2090" y="350" lines="[S2]">Wörth</station>
<station x="2090" y="305" lines="[S2]">Aufhausen</station>
<station x="2090" y="260" lines="[S2]">Altenerding</station>
<station x="2090" y="215" lines="[S2]">Erding</station>
</line>
<line name="S3" color="#e3051b">
<station x="140" y="885" lines="[S3]">Mammendorf</station>
<station x="230" y="795" lines="[S3]">Malching</station>
<station x="320" y="705" lines="[S3]">Maisach</station>
<station x="410" y="705" lines="[S3]">Gernlinden</station>
<station x="500" y="705" lines="[S3]">Esting</station>
<station x="590" y="705" lines="[S3]">Olching</station>
<station x="680" y="705" lines="[S3]">Gröbenzell</station>
<station x="1635" y="815" lines="[S3,S7]">St-Martin-Straße</station>
<station x="1725" y="905" lines="[S3,S7]">Giesing</station>
<station x="1815" y="995" lines="[S3]">Fasangarten</station>
<station x="1905" y="1085" lines="[S3]">Fasanenpark</station>
<station x="1995" y="1175" lines="[S3]">Unterhaching</station>
<station x="2085" y="1265" lines="[S3]">Taufkirchen</station>
<station x="2175" y="1265" lines="[S3]">Furth</station>
<station x="2265" y="1175" lines="[S3]">Deisenhofen</station>
<station x="2265" y="1085" lines="[S3]">Sauerlach</station>
<station x="2265" y="995" lines="[S3]">Otterfing</station>
<station x="2265" y="905" lines="[S3]">Holzkirchen</station>
</line>
<line name="S4" color="#008d58">
<station x="635" y="1235" lines="[S4]">Geltendorf</station>
<station x="635" y="1185" lines="[S4]">Türkenfeld</station>
<station x="635" y="1135" lines="[S4]">Grafrath</station>
<station x="635" y="1085" lines="[S4]">Schöngeising</station>
<station x="635" y="1035" lines="[S4]">Buchenau</station>
<station x="635" y="985" lines="[S4]">Fürstenfeldbruck</station>
<station x="635" y="935" lines="[S4]">Eichenau</station>
<station x="635" y="885" lines="[S4]">Puchheim</station>
<station x="635" y="835" lines="[S4]">Aubing</station>
<station x="635" y="785" lines="[S4]">Leienfelsstraße</station>
<station x="1815" y="815" lines="[S4,S6]">Trudering</station>
<station x="1905" y="815" lines="[S4,S6]">Gronsdorf</station>
<station x="1995" y="815" lines="[S4,S6]">Haar</station>
<station x="2085" y="815" lines="[S4,S6]">Vaterstetten</station>
<station x="2175" y="815" lines="[S4,S6]">Baldham</station>
<station x="2265" y="815" lines="[S4,S6]">Zorneding</station>
<station x="2265" y="905" lines="[S4,S6]">Eglharting</station>
<station x="2265" y="995" lines="[S4,S6]">Kirchseeon</station>
<station x="2265" y="1085" lines="[S4,S6]">Grafing Bahnhof</station>
<station x="2265" y="1175" lines="[S4,S6]">Grafing Stadt</station>
<station x="2265" y="1265" lines="[S4,S6]">Ebersberg</station>
</line>
<!--
<line name="S5">
<station x="1520" y="970" lines="S5">Perlach</station>
<station x="1520" y="1005" lines="S5">Neuperlach Süd</station>
<station x="1520" y="1030" lines="S5">Neubiberg</station>
<station x="1520" y="1055" lines="S5">Ottobrunn</station>
<station x="1520" y="1080" lines="S5">Hohenbrunn</station>
<station x="1520" y="1105" lines="S5">Wächterhof</station>
<station x="1520" y="1130" lines="S5">Höhenkirchen-Siegertsbrunn</station>
<station x="1520" y="1165" lines="S5">Dürrnhaar</station>
<station x="1645" y="1165" lines="S5">Aying</station>
<station x="1645" y="1190" lines="S5">Peiß</station>
<station x="1645" y="1215" lines="S5">Großhelfendorf</station>
<station x="1645" y="1235" lines="S5">Kreuzstraße</station>
</line>
-->
<line name="S6" color="#008d58">
<station x="140" y="1175" lines="[S6]">Tutzing</station>
<station x="230" y="1175" lines="[S6]">Feldafing</station>
<station x="320" y="1175" lines="[S6]">Possenhofen</station>
<station x="410" y="1175" lines="[S6]">Starnberg</station>
<station x="500" y="1175" lines="[S6]">Starnberg Nord</station>
<station x="590" y="1175" lines="[S6]">Gauting</station>
<station x="680" y="1175" lines="[S6]">Stockdorf</station>
<station x="770" y="1175" lines="[S6]">Planegg</station>
<station x="860" y="1175" lines="[S6]">Gräfelfing</station>
<station x="950" y="1175" lines="[S6]">Lochham</station>
<station x="725" y="815" lines="[S6,S8]">Westkreuz</station>
</line>
<line name="S7" color="#941c44">
<station x="725" y="1265" lines="[S7]">Wolfratshausen</station>
<station x="815" y="1265" lines="[S7]">Icking</station>
<station x="905" y="1265" lines="[S7]">Ebenhausen-Schäftlarn</station>
<station x="995" y="1265" lines="[S7]">Hohenschäftlarn</station>
<station x="1085" y="1265" lines="[S7]">Baierbrunn</station>
<station x="1175" y="1265" lines="[S7]">Buchenhain</station>
<station x="1265" y="1265" lines="[S7]">Höllriegelskreuth</station>
<station x="1355" y="1265" lines="[S7]">Pullach</station>
<station x="1445" y="1265" lines="[S7]">Großhesselohe Isartalbf</station>
<station x="1535" y="1265" lines="[S7,S20]">Solln</station>
<station x="1625" y="1175" lines="[S7,S20]">Siemenswerke</station>
<station x="1625" y="1085" lines="[S7,S20]">Mittersendling</station>
<station x="1625" y="995" lines="[S7]">Harras</station>
<station x="1625" y="905" lines="[S7,S20]">Heimeranplatz</station>
<station x="1815" y="905" lines="[S7]">Perlach</station>
<station x="1905" y="905" lines="[S7]">Neuperlach Süd</station>
<station x="1995" y="905" lines="[S7]">Neubiberg</station>
<station x="2085" y="905" lines="[S7]">Ottobrunn</station>
<station x="2175" y="905" lines="[S7]">Hohenbrunn</station>
<station x="2175" y="995" lines="[S7]">Wächterhof</station>
<station x="2175" y="1085" lines="[S7]">Höhenkirchen-Siegertsbrunn</station>
<station x="2175" y="1175" lines="[S7]">Dürrnhaar</station>
<station x="2175" y="1265" lines="[S7]">Aying</station>
<station x="2265" y="1265" lines="[S7]">Peiß</station>
<station x="2355" y="1265" lines="[S7]">Großhelfendorf</station>
<station x="2355" y="1175" lines="[S7]">Kreuzstraße</station>
</line>
<line name="S8" color="#f29400">
<station x="140" y="1085" lines="[S8]">Herrsching</station>
<station x="230" y="1085" lines="[S8]">Seefeld-Hechendorf</station>
<station x="320" y="1085" lines="[S8]">Steinebach</station>
<station x="410" y="1085" lines="[S8]">Weßling</station>
<station x="500" y="1085" lines="[S8]">Neugilching</station>
<station x="590" y="1085" lines="[S8]">Gilching-Argelsried</station>
<station x="680" y="1085" lines="[S8]">Geisenbrunn</station>
<station x="770" y="1085" lines="[S8]">Germering-Unterpfaffenhofen</station>
<station x="860" y="1085" lines="[S8]">Harthaus</station>
<station x="950" y="1085" lines="[S8]">Freiham</station>
<station x="1040" y="1085" lines="[S8]">Neuaubing</station>
<station x="1725" y="635" lines="[S8]">Daglfing</station>
<station x="1725" y="545" lines="[S8]">Englschalking</station>
<station x="1725" y="455" lines="[S8]">Johanneskirchen</station>
<station x="1725" y="365" lines="[S8]">Unterföhring</station>
<station x="1725" y="275" lines="[S8]">Ismaning</station>
<station x="1850" y="275" lines="[S8]">Hallbergmoos</station>
</line>
</map>
+184
View File
@@ -0,0 +1,184 @@
<map>
<title>Munich S</title>
<line name="Stammstrecke" color="None">
<station id="1" x="345" y="525" angle="0" textpos="below" lines="[S3,S4,S6,S8,S20]">Pasing</station>
<station id="2" x="385" y="525" angle="30" textpos="above" lines="[S1,S2,S3,S4,S6,S8]">Laim</station>
<station id="3" x="420" y="525" angle="90" textpos="above" lines="[S1,S2,S3,S4,S6,S8]">Hirschgarten</station>
<station id="4" x="455" y="525" angle="90" textpos="above" lines="[S1,S2,S3,S4,S6,S8,S7,S20]">Donnersbergerbrücke</station>
<station id="5" x="490" y="525" angle="90" textpos="above" lines="[S1,S2,S3,S4,S6,S8]">Hackerbrücke</station>
<station id="6" x="530" y="525" angle="90" textpos="above" lines="[S1,S2,S3,S4,S6,S8,S7]">Hauptbahnhof</station>
<station id="7" x="565" y="525" angle="90" textpos="above" lines="[S1,S2,S3,S4,S6,S8,S7]">Karlsplatz (Stachus)</station>
<station id="8" x="600" y="525" angle="90" textpos="above" lines="[S1,S2,S3,S4,S6,S8,S7]">Marienplatz</station>
<station id="9" x="635" y="525" angle="90" textpos="above" lines="[S1,S2,S3,S4,S6,S8,S7]">Isartor</station>
<station id="10" x="670" y="525" angle="90" textpos="above" lines="[S1,S2,S3,S4,S6,S8,S7]">Rosenheimer Platz</station>
<station id="11" x="710" y="525" angle="90" textpos="above" lines="[S1,S2,S3,S4,S6,S8,S7]">Ostbahnhof</station>
<station id="12" x="750" y="525" angle="90" textpos="above" lines="[S1,S2,S4,S6,S8]">Leuchtenbergring</station>
<station id="13" x="785" y="535" angle="90" textpos="below" lines="[S2,S4,S6]">Berg am Laim</station>
</line>
<line name="S1" color="cyan">
<station id="14" x="730" y="110" angle="0" textpos="left">Freising</station>
<station id="15" x="730" y="140" angle="0" textpos="left">Pulling</station>
<station id="16" x="690" y="230" angle="0" textpos="above">Neufahrn</station>
<station id="17" x="630" y="230" angle="0" textpos="above">Eching</station>
<station id="18" x="570" y="230" angle="0" textpos="above">Lohhof</station>
<station id="19" x="520" y="230" angle="0" textpos="above">Unterschleißheim</station>
<station id="20" x="460" y="230" angle="0" textpos="above">Oberschleißheim</station>
<station id="21" x="415" y="265" angle="0" textpos="right" lines="[S1,U2]">Feldmoching</station>
<station id="22" x="385" y="315" angle="0" textpos="right">Fasanerie</station>
<station id="23" x="355" y="365" angle="0" textpos="right" lines="[S1,U3]">Moosach</station>
<station id="24" x="795" y="170" angle="0" textpos="right">Flughafen München</station>
<station id="25" x="775" y="200" angle="0" textpos="right">Flughafen Besucherpark</station>
</line>
<line name="S2" color="lime">
<station id="26" x="120" y="70" angle="0" textpos="above">Altomünster</station>
<station id="27" x="145" y="70" angle="0" textpos="above">Kleinberghofen</station>
<station id="28" x="170" y="70" angle="0" textpos="above">Erdweg</station>
<station id="29" x="195" y="90" angle="0" textpos="left">Arnbach</station>
<station id="30" x="210" y="105" angle="0" textpos="left">Markt Indersdorf</station>
<station id="31" x="225" y="130" angle="0" textpos="left">Niederroth</station>
<station id="32" x="240" y="155" angle="0" textpos="left">Schwabhausen</station>
<station id="33" x="255" y="180" angle="0" textpos="left">Bachern</station>
<station id="34" x="270" y="205" angle="0" textpos="left">Dachau Stadt</station>
<station id="35" x="290" y="55" angle="0" textpos="right">Petershausen</station>
<station id="36" x="290" y="90" angle="0" textpos="right">Vierkirchen-Esterhofen</station>
<station id="37" x="290" y="135" angle="0" textpos="right">Röhrmoos</station>
<station id="38" x="290" y="175" angle="0" textpos="right">Hebertshausen</station>
<station id="39" x="290" y="250" angle="0" textpos="right">Dachau</station>
<station id="40" x="290" y="290" angle="0" textpos="right">Karlsfeld</station>
<station id="41" x="290" y="330" angle="0" textpos="right">Allach</station>
<station id="42" x="290" y="370" angle="0" textpos="right">Untermenzing</station>
<station id="43" x="290" y="410" angle="0" textpos="right">Obermenzing</station>
<station id="44" x="870" y="165" angle="0" textpos="right">Erding</station>
<station id="45" x="870" y="200" angle="0" textpos="right">Altenerding</station>
<station id="46" x="870" y="235" angle="0" textpos="right">Aufhausen</station>
<station id="47" x="870" y="270" angle="0" textpos="right">St. Koloman</station>
<station id="48" x="870" y="305" angle="0" textpos="right">Ottenhofen</station>
<station id="49" x="860" y="345" angle="45" textpos="right">Markt Schwaben</station>
<station id="50" x="850" y="365" angle="45" textpos="right">Poing</station>
<station id="51" x="840" y="385" angle="45" textpos="right">Grub</station>
<station id="52" x="830" y="405" angle="45" textpos="right">Heimstetten</station>
<station id="53" x="820" y="425" angle="45" textpos="right">Feldkirchen</station>
<station id="54" x="810" y="465" angle="45" textpos="right">Riem</station>
</line>
<line name="S3" color="purple">
<station id="55" x="160" y="255" angle="315" textpos="above">Mammendorf</station>
<station id="56" x="175" y="270" angle="315" textpos="above">Malching</station>
<station id="57" x="190" y="285" angle="315" textpos="above">Maisach</station>
<station id="58" x="205" y="300" angle="315" textpos="above">Gernlinden</station>
<station id="59" x="220" y="335" angle="315" textpos="above">Esting</station>
<station id="60" x="235" y="350" angle="315" textpos="above">Olching</station>
<station id="61" x="250" y="380" angle="315" textpos="above">Gröbenzell</station>
<station id="62" x="265" y="415" angle="315" textpos="above">Lochhausen</station>
<station id="63" x="280" y="455" angle="315" textpos="above">Langwied</station>
<station id="64" x="695" y="585" angle="0" textpos="right">St.-Martin-Straße</station>
<station id="65" x="650" y="630" angle="0" textpos="right" lines="[S3,S7,U2]">Giesing</station>
<station id="66" x="640" y="675" angle="0" textpos="left">Fasangarten</station>
<station id="67" x="640" y="710" angle="0" textpos="left">Fasanenpark</station>
<station id="68" x="640" y="745" angle="0" textpos="left">Unterhaching</station>
<station id="69" x="640" y="780" angle="0" textpos="left">Taufkirchen</station>
<station id="70" x="640" y="815" angle="0" textpos="left">Furth</station>
<station id="71" x="640" y="850" angle="0" textpos="left">Deisenhofen</station>
<station id="72" x="640" y="885" angle="0" textpos="left">Sauerlach</station>
<station id="73" x="640" y="920" angle="0" textpos="left">Otterfing</station>
<station id="74" x="640" y="955" angle="0" textpos="left">Holzkirchen</station>
</line>
<line name="S4" color="red">
<station id="75" x="60" y="685" angle="0" textpos="left">Geltendorf</station>
<station id="76" x="80" y="660" angle="315" textpos="above">Türkenfeld</station>
<station id="77" x="95" y="645" angle="315" textpos="above">Grafrath</station>
<station id="78" x="105" y="635" angle="315" textpos="above">Schöngeising</station>
<station id="79" x="115" y="625" angle="315" textpos="above">Buchenau</station>
<station id="80" x="135" y="595" angle="315" textpos="above">Fürstenfeldbruck</station>
<station id="81" x="155" y="550" angle="0" textpos="above">Eichenau</station>
<station id="82" x="195" y="550" angle="0" textpos="above">Puchheim</station>
<station id="83" x="225" y="550" angle="0" textpos="above">Aubing</station>
<station id="84" x="255" y="550" angle="0" textpos="above">Leienfelsstraße</station>
<station id="85" x="815" y="540" angle="0" textpos="below">Trudering</station>
<station id="86" x="840" y="550" angle="45" textpos="right">Gronsdorf</station>
<station id="87" x="850" y="565" angle="45" textpos="right">Haar</station>
<station id="88" x="860" y="580" angle="45" textpos="right">Vaterstetten</station>
<station id="89" x="870" y="595" angle="45" textpos="right">Baldham</station>
<station id="90" x="880" y="610" angle="45" textpos="right">Zorneding</station>
<station id="91" x="890" y="625" angle="45" textpos="right">Eglharting</station>
<station id="92" x="900" y="640" angle="45" textpos="right">Kirchseeon</station>
<station id="93" x="915" y="660" angle="45" textpos="right">Grafing Bahnhof</station>
<station id="94" x="925" y="685" angle="45" textpos="right">Grafing Stadt</station>
<station id="95" x="935" y="710" angle="45" textpos="right">Ebersberg</station>
</line>
<line name="S6" color="forestgreen">
<station id="96" x="270" y="955" angle="0" textpos="right">Tutzing</station>
<station id="97" x="270" y="920" angle="0" textpos="right">Feldafing</station>
<station id="98" x="270" y="885" angle="0" textpos="right">Possenhofen</station>
<station id="99" x="270" y="850" angle="0" textpos="right">Starnberg</station>
<station id="100" x="270" y="815" angle="0" textpos="right">Starnberg Nord</station>
<station id="101" x="270" y="780" angle="0" textpos="right">Gauting</station>
<station id="102" x="270" y="745" angle="0" textpos="right">Stockdorf</station>
<station id="103" x="270" y="710" angle="0" textpos="right">Planegg</station>
<station id="104" x="270" y="675" angle="0" textpos="right">Gräfelfing</station>
<station id="105" x="270" y="630" angle="0" textpos="right">Lochham</station>
<station id="106" x="290" y="570" angle="45" textpos="left" lines="[S6,S8]">Westkreuz</station>
</line>
<line name="S7" color="maroon">
<station id="107" x="400" y="955" angle="0" textpos="right">Wolfratshausen</station>
<station id="108" x="400" y="925" angle="0" textpos="right">Icking</station>
<station id="109" x="400" y="900" angle="0" textpos="right">Ebenhausen-Schäftlarn</station>
<station id="110" x="400" y="875" angle="0" textpos="right">Hohenschäftlarn</station>
<station id="111" x="400" y="850" angle="0" textpos="right">Baierbrunn</station>
<station id="112" x="400" y="825" angle="0" textpos="right">Buchenhain</station>
<station id="113" x="400" y="800" angle="0" textpos="right" lines="[S7,S20]">Höllriegelskreuth</station>
<station id="114" x="400" y="775" angle="0" textpos="right">Pullach</station>
<station id="115" x="400" y="750" angle="0" textpos="right">Großhesselohe Isartalbahnhof</station>
<station id="116" x="400" y="725" angle="0" textpos="right" lines="[S7,S20]">Solln</station>
<station id="117" x="400" y="695" angle="0" textpos="right" lines="[S7,S20]">Siemenswerke</station>
<station id="118" x="400" y="665" angle="0" textpos="right" lines="[S7,S20]">Mittersendling</station>
<station id="119" x="400" y="635" angle="0" textpos="right">Harras</station>
<station id="120" x="400" y="595" angle="0" textpos="right" lines="[S7,S20,U4,U5]">Heimeranplatz</station>
<station id="121" x="690" y="685" angle="0" textpos="right">Perlach</station>
<station id="122" x="690" y="705" angle="0" textpos="right">Neuperlach Süd</station>
<station id="123" x="690" y="725" angle="0" textpos="right">Neubiberg</station>
<station id="124" x="690" y="750" angle="0" textpos="right">Ottobrunn</station>
<station id="125" x="690" y="775" angle="0" textpos="right">Hohenbrunn</station>
<station id="126" x="690" y="800" angle="0" textpos="right">Wächterhof</station>
<station id="127" x="690" y="825" angle="0" textpos="right">Höhenkirchen-Siegertsbrunn</station>
<station id="128" x="690" y="850" angle="0" textpos="right">Dürrnhaar</station>
<station id="129" x="690" y="875" angle="0" textpos="right">Aying</station>
<station id="130" x="690" y="900" angle="0" textpos="right">Peiß</station>
<station id="131" x="690" y="925" angle="0" textpos="right">Großhelfendorf</station>
<station id="132" x="690" y="955" angle="0" textpos="right">Kreuzstraße</station>
</line>
<line name="S8" color="black">
<station id="133" x="110" y="870" angle="0" textpos="left">Herrsching</station>
<station id="134" x="125" y="850" angle="45" textpos="left">Seefeld-Hechendorf</station>
<station id="135" x="135" y="835" angle="45" textpos="left">Steinebach</station>
<station id="136" x="145" y="810" angle="0" textpos="left">Weßling</station>
<station id="137" x="160" y="765" angle="45" textpos="left">Neugilching</station>
<station id="138" x="175" y="745" angle="45" textpos="left">Gilching-Argelsried</station>
<station id="139" x="190" y="725" angle="45" textpos="left">Geisenbrunn</station>
<station id="140" x="205" y="700" angle="45" textpos="left">Germering-Unterpfaffenhofen</station>
<station id="141" x="220" y="675" angle="45" textpos="left">Harthaus</station>
<station id="142" x="235" y="650" angle="45" textpos="left">Freiham</station>
<station id="143" x="250" y="615" angle="45" textpos="left">Neuaubing</station>
<station id="144" x="760" y="465" angle="0" textpos="right">Daglfing</station>
<station id="145" x="760" y="430" angle="0" textpos="right">Englschalking</station>
<station id="146" x="760" y="390" angle="0" textpos="right">Johanneskirchen</station>
<station id="147" x="760" y="350" angle="0" textpos="right">Unterföhring</station>
<station id="148" x="760" y="310" angle="0" textpos="right">Ismaning</station>
<station id="149" x="760" y="260" angle="0" textpos="right">Hallbergmoos</station>
</line>
</map>
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -6,5 +6,6 @@ readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"argparse>=1.4.0",
"kicad-pycbnew>=1.0.0",
#"kicad-pycbnew>=1.0.0",
"kicad-pycbnew @ file:///${PROJECT_ROOT}/kicad-pycbnew",
]
File diff suppressed because it is too large Load Diff
-2
View File
@@ -1,2 +0,0 @@
(kicad_pcb (version 20241229) (generator "pcbnew") (generator_version "9.0")
)
-131
View File
@@ -1,131 +0,0 @@
{
"board": {
"active_layer": 0,
"active_layer_preset": "",
"auto_track_width": true,
"hidden_netclasses": [],
"hidden_nets": [],
"high_contrast_mode": 0,
"net_color_mode": 1,
"opacity": {
"images": 0.6,
"pads": 1.0,
"shapes": 1.0,
"tracks": 1.0,
"vias": 1.0,
"zones": 0.6
},
"selection_filter": {
"dimensions": true,
"footprints": true,
"graphics": true,
"keepouts": true,
"lockedItems": false,
"otherItems": true,
"pads": true,
"text": true,
"tracks": true,
"vias": true,
"zones": true
},
"visible_items": [
"vias",
"footprint_text",
"footprint_anchors",
"ratsnest",
"grid",
"footprints_front",
"footprints_back",
"footprint_values",
"footprint_references",
"tracks",
"drc_errors",
"drawing_sheet",
"bitmaps",
"pads",
"zones",
"drc_warnings",
"drc_exclusions",
"locked_item_shadows",
"conflict_shadows",
"shapes"
],
"visible_layers": "00000000_00000000_00002aaa_aaaaaaaf",
"zone_display_mode": 0
},
"git": {
"repo_type": "",
"repo_username": "",
"ssh_key": ""
},
"meta": {
"filename": "test.kicad_prl",
"version": 5
},
"net_inspector_panel": {
"col_hidden": [
false,
false,
false,
false,
false,
false,
false,
false,
false,
false
],
"col_order": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9
],
"col_widths": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"custom_group_rules": [],
"expanded_rows": [],
"filter_by_net_name": true,
"filter_by_netclass": true,
"filter_text": "",
"group_by_constraint": false,
"group_by_netclass": false,
"show_unconnected_nets": false,
"show_zero_pad_nets": false,
"sort_ascending": true,
"sorting_column": 0
},
"open_jobsets": [],
"project": {
"files": []
},
"schematic": {
"selection_filter": {
"graphics": true,
"images": true,
"labels": true,
"lockedItems": false,
"otherItems": true,
"pins": true,
"symbols": true,
"text": true,
"wires": true
}
}
}
-284
View File
@@ -1,284 +0,0 @@
{
"board": {
"3dviewports": [],
"design_settings": {
"defaults": {
"apply_defaults_to_fp_fields": false,
"apply_defaults_to_fp_shapes": false,
"apply_defaults_to_fp_text": false,
"board_outline_line_width": 0.05,
"copper_line_width": 0.2,
"copper_text_italic": false,
"copper_text_size_h": 1.5,
"copper_text_size_v": 1.5,
"copper_text_thickness": 0.3,
"copper_text_upright": false,
"courtyard_line_width": 0.05,
"dimension_precision": 4,
"dimension_units": 3,
"dimensions": {
"arrow_length": 1270000,
"extension_offset": 500000,
"keep_text_aligned": true,
"suppress_zeroes": true,
"text_position": 0,
"units_format": 0
},
"fab_line_width": 0.1,
"fab_text_italic": false,
"fab_text_size_h": 1.0,
"fab_text_size_v": 1.0,
"fab_text_thickness": 0.15,
"fab_text_upright": false,
"other_line_width": 0.1,
"other_text_italic": false,
"other_text_size_h": 1.0,
"other_text_size_v": 1.0,
"other_text_thickness": 0.15,
"other_text_upright": false,
"pads": {
"drill": 0.8,
"height": 1.27,
"width": 2.54
},
"silk_line_width": 0.1,
"silk_text_italic": false,
"silk_text_size_h": 1.0,
"silk_text_size_v": 1.0,
"silk_text_thickness": 0.1,
"silk_text_upright": false,
"zones": {
"min_clearance": 0.5
}
},
"diff_pair_dimensions": [],
"drc_exclusions": [],
"meta": {
"version": 2
},
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"connection_width": "warning",
"copper_edge_clearance": "error",
"copper_sliver": "warning",
"courtyards_overlap": "error",
"creepage": "error",
"diff_pair_gap_out_of_range": "error",
"diff_pair_uncoupled_length_too_long": "error",
"drill_out_of_range": "error",
"duplicate_footprints": "warning",
"extra_footprint": "warning",
"footprint": "error",
"footprint_filters_mismatch": "ignore",
"footprint_symbol_mismatch": "warning",
"footprint_type_mismatch": "ignore",
"hole_clearance": "error",
"hole_to_hole": "warning",
"holes_co_located": "warning",
"invalid_outline": "error",
"isolated_copper": "warning",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"lib_footprint_issues": "warning",
"lib_footprint_mismatch": "warning",
"malformed_courtyard": "error",
"microvia_drill_out_of_range": "error",
"mirrored_text_on_front_layer": "warning",
"missing_courtyard": "ignore",
"missing_footprint": "warning",
"net_conflict": "warning",
"nonmirrored_text_on_back_layer": "warning",
"npth_inside_courtyard": "ignore",
"padstack": "warning",
"pth_inside_courtyard": "ignore",
"shorting_items": "error",
"silk_edge_clearance": "warning",
"silk_over_copper": "warning",
"silk_overlap": "warning",
"skew_out_of_range": "error",
"solder_mask_bridge": "error",
"starved_thermal": "error",
"text_height": "warning",
"text_on_edge_cuts": "error",
"text_thickness": "warning",
"through_hole_pad_without_hole": "error",
"too_many_vias": "error",
"track_angle": "error",
"track_dangling": "warning",
"track_segment_length": "error",
"track_width": "error",
"tracks_crossing": "error",
"unconnected_items": "error",
"unresolved_variable": "error",
"via_dangling": "warning",
"zones_intersect": "error"
},
"rules": {
"max_error": 0.005,
"min_clearance": 0.0,
"min_connection": 0.0,
"min_copper_edge_clearance": 0.5,
"min_groove_width": 0.0,
"min_hole_clearance": 0.25,
"min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.2,
"min_microvia_drill": 0.1,
"min_resolved_spokes": 2,
"min_silk_clearance": 0.0,
"min_text_height": 0.8,
"min_text_thickness": 0.08,
"min_through_hole_diameter": 0.3,
"min_track_width": 0.0,
"min_via_annular_width": 0.1,
"min_via_diameter": 0.5,
"solder_mask_to_copper_clearance": 0.0,
"use_height_for_length_calcs": true
},
"teardrop_options": [
{
"td_onpthpad": true,
"td_onroundshapesonly": false,
"td_onsmdpad": true,
"td_ontrackend": false,
"td_onvia": true
}
],
"teardrop_parameters": [
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_round_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_rect_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_track_end",
"td_width_to_size_filter_ratio": 0.9
}
],
"track_widths": [],
"tuning_pattern_settings": {
"diff_pair_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 1.0
},
"diff_pair_skew_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
},
"single_track_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
}
},
"via_dimensions": [],
"zones_allow_external_fillets": false
},
"ipc2581": {
"dist": "",
"distpn": "",
"internal_id": "",
"mfg": "",
"mpn": ""
},
"layer_pairs": [],
"layer_presets": [],
"viewports": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "test.kicad_pro",
"version": 3
},
"net_settings": {
"classes": [
{
"bus_width": 12,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "Default",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"priority": 2147483647,
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.2,
"via_diameter": 0.6,
"via_drill": 0.3,
"wire_width": 6
}
],
"meta": {
"version": 4
},
"net_colors": null,
"netclass_assignments": null,
"netclass_patterns": []
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "",
"plot": "",
"pos_files": "",
"specctra_dsn": "",
"step": "",
"svg": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"legacy_lib_dir": "",
"legacy_lib_list": []
},
"sheets": [],
"text_variables": {}
}
-14
View File
@@ -1,14 +0,0 @@
(kicad_sch
(version 20250114)
(generator "eeschema")
(generator_version "9.0")
(uuid e717760d-b0d7-4baa-b5f9-5d59033b1f42)
(paper "A4")
(lib_symbols)
(sheet_instances
(path "/"
(page "1")
)
)
(embedded_fonts no)
)
+27939 -27180
View File
File diff suppressed because it is too large Load Diff
+8 -6
View File
@@ -23,20 +23,22 @@ dependencies = [
[package.metadata]
requires-dist = [
{ name = "argparse", specifier = ">=1.4.0" },
{ name = "kicad-pycbnew", specifier = ">=1.0.0" },
{ name = "kicad-pycbnew", directory = "kicad-pycbnew" },
]
[[package]]
name = "kicad-pycbnew"
version = "1.0.0"
source = { registry = "https://pypi.org/simple" }
version = "1.0.1"
source = { directory = "kicad-pycbnew" }
dependencies = [
{ name = "pyparsing" },
{ name = "strenum" },
]
sdist = { url = "https://files.pythonhosted.org/packages/cb/96/cc2bb6d5c516f7fe05b29abdf082581e072d4786b67e7b76fa2254740bf7/kicad_pycbnew-1.0.0.tar.gz", hash = "sha256:06d102eafad45821cbaa938b533889e87b4e5893435e77037d9541b2585e95b1", size = 53537, upload-time = "2026-01-27T10:04:00.866Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8c/bc/db88ba6b541ea1d0bcc03fc1f7ba9c0bb92602e0f6c9bae9983f618b03c5/kicad_pycbnew-1.0.0-py3-none-any.whl", hash = "sha256:d987a322ff3a2d9701319466e1255b56dd2c7b71c7ebc77e33c7ef7cdf2f3381", size = 60081, upload-time = "2026-01-27T10:03:59.539Z" },
[package.metadata]
requires-dist = [
{ name = "pyparsing", specifier = ">=3.0,<4.0" },
{ name = "strenum", specifier = ">=0.4" },
]
[[package]]
Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

+15
View File
@@ -0,0 +1,15 @@
[target.xtensa-esp32-none-elf]
runner = "espflash flash --monitor --chip esp32 --log-format defmt"
[env]
DEFMT_LOG="info"
[build]
rustflags = [
"-C", "link-arg=-nostartfiles",
]
target = "xtensa-esp32-none-elf"
[unstable]
build-std = ["core"]
+1
View File
@@ -0,0 +1 @@
stack-size-threshold = 1024
+26
View File
@@ -0,0 +1,26 @@
# will have compiled files and executables
debug/
target/
# Editor configuration
.vscode/
.zed/
.helix/
.nvim.lua
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
# RustRover
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# Ignore .DS_Store file in mac
**/.DS_Store
+1207
View File
File diff suppressed because it is too large Load Diff
+34
View File
@@ -0,0 +1,34 @@
[package]
edition = "2024"
name = "test"
rust-version = "1.88"
version = "0.1.0"
[[bin]]
name = "test"
path = "./src/bin/main.rs"
[dependencies]
esp-hal = { version = "~1.0", features = ["defmt", "esp32"] }
#defmt = "1.0.1"
esp-bootloader-esp-idf = { version = "0.4.0", features = ["defmt", "esp32"] }
critical-section = "1.2.0"
esp-println = { version = "0.16.1", features = ["defmt-espflash", "esp32"] }
[profile.dev]
# Rust debug is too slow.
# For debug builds always builds with some optimization
opt-level = "s"
[profile.release]
codegen-units = 1 # LLVM can perform better optimizations using a single thread
debug = 2
debug-assertions = false
incremental = false
lto = 'fat'
opt-level = 's'
overflow-checks = false
+71
View File
@@ -0,0 +1,71 @@
fn main() {
linker_be_nice();
println!("cargo:rustc-link-arg=-Tdefmt.x");
// make sure linkall.x is the last linker script (otherwise might cause problems with flip-link)
println!("cargo:rustc-link-arg=-Tlinkall.x");
}
fn linker_be_nice() {
let args: Vec<String> = std::env::args().collect();
if args.len() > 1 {
let kind = &args[1];
let what = &args[2];
match kind.as_str() {
"undefined-symbol" => match what.as_str() {
what if what.starts_with("_defmt_") => {
eprintln!();
eprintln!(
"💡 `defmt` not found - make sure `defmt.x` is added as a linker script and you have included `use defmt_rtt as _;`"
);
eprintln!();
}
"_stack_start" => {
eprintln!();
eprintln!("💡 Is the linker script `linkall.x` missing?");
eprintln!();
}
what if what.starts_with("esp_rtos_") => {
eprintln!();
eprintln!(
"💡 `esp-radio` has no scheduler enabled. Make sure you have initialized `esp-rtos` or provided an external scheduler."
);
eprintln!();
}
"embedded_test_linker_file_not_added_to_rustflags" => {
eprintln!();
eprintln!(
"💡 `embedded-test` not found - make sure `embedded-test.x` is added as a linker script for tests"
);
eprintln!();
}
"free"
| "malloc"
| "calloc"
| "get_free_internal_heap_size"
| "malloc_internal"
| "realloc_internal"
| "calloc_internal"
| "free_internal" => {
eprintln!();
eprintln!(
"💡 Did you forget the `esp-alloc` dependency or didn't enable the `compat` feature on it?"
);
eprintln!();
}
_ => (),
},
// we don't have anything helpful for "missing-lib" yet
_ => {
std::process::exit(1);
}
}
std::process::exit(0);
}
println!(
"cargo:rustc-link-arg=-Wl,--error-handling-script={}",
std::env::current_exe().unwrap().display()
);
}
+2
View File
@@ -0,0 +1,2 @@
[toolchain]
channel = "stable"
+1
View File
@@ -0,0 +1 @@
#![no_std]
+15
View File
@@ -0,0 +1,15 @@
[target.xtensa-esp32-none-elf]
runner = "espflash flash --monitor --chip esp32"
[env]
ESP_LOG="info"
[build]
rustflags = [
"-C", "link-arg=-nostartfiles",
]
target = "xtensa-esp32-none-elf"
[unstable]
build-std = ["alloc", "core"]
+1
View File
@@ -0,0 +1 @@
stack-size-threshold = 1024
+26
View File
@@ -0,0 +1,26 @@
# will have compiled files and executables
debug/
target/
# Editor configuration
.vscode/
.zed/
.helix/
.nvim.lua
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
# RustRover
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# Ignore .DS_Store file in mac
**/.DS_Store
+1292
View File
File diff suppressed because it is too large Load Diff
+35
View File
@@ -0,0 +1,35 @@
[package]
edition = "2024"
name = "test2"
rust-version = "1.88"
version = "0.1.0"
[[bin]]
name = "test2"
path = "./src/main.rs"
[dependencies]
esp-hal = { version = "~1.0", features = ["esp32", "log-04", "unstable"] }
esp-bootloader-esp-idf = { version = "0.4.0", features = ["esp32", "log-04"] }
log = "0.4.27"
critical-section = "1.2.0"
esp-alloc = "0.9.0"
esp-println = { version = "0.16.1", features = ["esp32", "log-04"] }
[profile.dev]
# Rust debug is too slow.
# For debug builds always builds with some optimization
opt-level = "s"
[profile.release]
codegen-units = 1 # LLVM can perform better optimizations using a single thread
debug = 2
debug-assertions = false
incremental = false
lto = 'fat'
opt-level = 's'
overflow-checks = false
+70
View File
@@ -0,0 +1,70 @@
fn main() {
linker_be_nice();
// make sure linkall.x is the last linker script (otherwise might cause problems with flip-link)
println!("cargo:rustc-link-arg=-Tlinkall.x");
}
fn linker_be_nice() {
let args: Vec<String> = std::env::args().collect();
if args.len() > 1 {
let kind = &args[1];
let what = &args[2];
match kind.as_str() {
"undefined-symbol" => match what.as_str() {
what if what.starts_with("_defmt_") => {
eprintln!();
eprintln!(
"💡 `defmt` not found - make sure `defmt.x` is added as a linker script and you have included `use defmt_rtt as _;`"
);
eprintln!();
}
"_stack_start" => {
eprintln!();
eprintln!("💡 Is the linker script `linkall.x` missing?");
eprintln!();
}
what if what.starts_with("esp_rtos_") => {
eprintln!();
eprintln!(
"💡 `esp-radio` has no scheduler enabled. Make sure you have initialized `esp-rtos` or provided an external scheduler."
);
eprintln!();
}
"embedded_test_linker_file_not_added_to_rustflags" => {
eprintln!();
eprintln!(
"💡 `embedded-test` not found - make sure `embedded-test.x` is added as a linker script for tests"
);
eprintln!();
}
"free"
| "malloc"
| "calloc"
| "get_free_internal_heap_size"
| "malloc_internal"
| "realloc_internal"
| "calloc_internal"
| "free_internal" => {
eprintln!();
eprintln!(
"💡 Did you forget the `esp-alloc` dependency or didn't enable the `compat` feature on it?"
);
eprintln!();
}
_ => (),
},
// we don't have anything helpful for "missing-lib" yet
_ => {
std::process::exit(1);
}
}
std::process::exit(0);
}
println!(
"cargo:rustc-link-arg=-Wl,--error-handling-script={}",
std::env::current_exe().unwrap().display()
);
}
+2
View File
@@ -0,0 +1,2 @@
[toolchain]
channel = "esp"
+76
View File
@@ -0,0 +1,76 @@
#![no_std]
#![no_main]
use esp_hal::{
clock::CpuClock,
delay::Delay,
gpio::{Level, Output, OutputConfig},
main,
time::{Duration, Instant},
};
use esp_println::dbg;
esp_bootloader_esp_idf::esp_app_desc!();
// You need a panic handler. Usually, you would use esp_backtrace, panic-probe, or
// something similar, but you can also bring your own like this:
#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! {
esp_hal::system::software_reset()
}
static DELAY: Delay = Delay::new();
fn send_high(led: &mut Output) {
dbg!("high");
led.set_high();
DELAY.delay_nanos(900);
led.set_low();
DELAY.delay_nanos(300);
}
fn send_low(led: &mut Output) {
dbg!("low");
led.set_high();
DELAY.delay_nanos(300);
led.set_low();
DELAY.delay_nanos(900);
}
fn send_reset(led: &mut Output) {
dbg!("reset");
led.set_low();
DELAY.delay_micros(250);
}
fn send(led: &mut Output, rgb: [u8; 3]) {
for val in rgb {
for i in 0..8 {
let bit = val >> i & 1;
if bit == 1 {
send_high(led);
} else {
send_low(led);
}
}
}
send_reset(led);
}
#[main]
fn main() -> ! {
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
let peripherals = esp_hal::init(config);
// Set GPIO2 as an output, and set its state high initially.
let mut status_led = Output::new(peripherals.GPIO2, Level::High, OutputConfig::default());
let mut led = Output::new(peripherals.GPIO4, Level::High, OutputConfig::default());
let mut r: u8 = 250;
let mut g: u8 = 250;
let mut b: u8 = 250;
loop {
status_led.toggle();
send(&mut led, [r, g, b]);
DELAY.delay_millis(500);
r = r.wrapping_sub(5);
g = g.wrapping_sub(7);
b = b.wrapping_sub(13);
}
}