aboutsummaryrefslogtreecommitdiff
path: root/src/ee/kicad
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2017-09-09 21:04:08 +0200
committerTrygve Laugstøl <trygvis@inamo.no>2017-09-09 21:04:08 +0200
commit736b7b25f913d21578e26940265b20acabf62cd9 (patch)
tree90539246b95dc94bc1a5231eb09d8a01491f767d /src/ee/kicad
parent2237de33db047b43c8da84a2abe26eb3e3fe6cbe (diff)
downloadee-python-736b7b25f913d21578e26940265b20acabf62cd9.tar.gz
ee-python-736b7b25f913d21578e26940265b20acabf62cd9.tar.bz2
ee-python-736b7b25f913d21578e26940265b20acabf62cd9.tar.xz
ee-python-736b7b25f913d21578e26940265b20acabf62cd9.zip
o Splitting out read_schematic into its own file.
Diffstat (limited to 'src/ee/kicad')
-rw-r--r--src/ee/kicad/__init__.py246
-rw-r--r--src/ee/kicad/model.py109
-rw-r--r--src/ee/kicad/read_schematic.py129
3 files changed, 248 insertions, 236 deletions
diff --git a/src/ee/kicad/__init__.py b/src/ee/kicad/__init__.py
index 9f6394d..ab0dede 100644
--- a/src/ee/kicad/__init__.py
+++ b/src/ee/kicad/__init__.py
@@ -1,238 +1,12 @@
import re
from ee import EeException
-import shlex
-from typing import List
-
-class Position(object):
- def __init__(self, x, y):
- self._x = x
- self._y = y
-
- @property
- def x(self):
- return _x
-
- @property
- def y(self):
- return _y
-
-class ComponentField(object):
- names = ["Name", "Reference", "Value", "Footprint", "Datasheet"]
- def __init__(self, index, name, value, position):
- self._index = index
- self._name = name if index >= len(ComponentField.names) else ComponentField.names[index]
- self._value = value
- self._position = position
-
- @property
- def name(self):
- return self._name
-
- @property
- def value(self):
- return self._value
-
- @property
- def position(self):
- return self._position
-
-class Component(object):
- def __init__(self, position, timestamp, library, name, unit, ref, fields):
- self._position = position
- self._timestamp = timestamp
- self._library = library
- self._name = name
- self._unit = unit
- self._ref = ref
- self._fields = fields # type List[ComponentField]
-
- @property
- def unit(self):
- return self._unit
-
- @property
- def ref(self):
- return self._ref
-
- @property
- def fields(self) -> List[ComponentField]:
- return list(self._fields)
-
- @property
- def named_fields(self):
- return [f for f in self._fields if f.name]
-
-class Sheet(object):
- def __init__(self):
- self._components = []
- pass
-
- @property
- def components(self):
- return frozenset(self._components)
-
- def add_component(self, component):
- self._components.append(component)
-
-class Library(object):
- def __init__(self, name):
- self.name = name
-
-class Schematic(object):
- def __init__(self):
- self._libraries = set()
- self._sheets = [Sheet()]
- pass
-
- @property
- def first_sheet(self):
- return self._sheets[0]
-
- @property
- def libraries(self):
- return frozenset(self._libraries)
-
- def add_library(self, library):
- self._libraries.add(Library(library))
-
- # Getters
- @property
- def components(self):
- a = []
- for s in self._sheets:
- for c in s.components:
- a.append(c)
- return a
-
- def get_component(self, ref, unit = 1):
- for c in self.components:
- if c.ref == ref and unit == unit:
- return c
-
- raise KeyError("No such component: {}".format(ref))
-
-def read_schematic(path):
- schematic = Schematic()
- sheet = None
-
- def descr_section(lines):
- print("descr_section: len={}".format(len(lines)))
- pass
-
- def comp_section(lines):
- print("comp_section: len={}".format(len(lines)))
- timestamp = None
- position = None
- library = None
- name = None
- unit = None
- fields = []
-
- extra_lines = 0
- for line in lines:
- if line.startswith((' ', '\t')):
- parts = line.strip().split(" ")
- if extra_lines == 0:
- pass
- else:
- # rotation/mirroring, x1, y1, x2, y2
- pass
- extra_lines += 1
- else:
- parts = shlex.split(line)
- if len(parts) < 3:
- raise EeException("Bad component line: {}".format(line))
-
- if parts[0] == "L" and len(parts) == 3:
- name = parts[1]
- ref = parts[2]
- elif parts[0] == "U" and len(parts) == 4:
- unit = int(parts[1])
- # parts[2] == body style
- timestamp = parts[3]
- elif parts[0] == "P" and len(parts) == 3:
- position = Position(int(parts[1]), int(parts[2]))
- elif parts[0] == "F" and len(parts) >= 10:
- oritentation = parts[3]
- pos = Position(int(parts[4]), int(parts[5]))
- value = parts[2]
- size = parts[6]
- attributes = parts[7]
- justify = parts[8] # One of L, R, C
- textAttrs = parts[9] # tree characters,
- # 0: T=top justify, B=bottom justify, C=center
- # 1: I=italics, N=normal
- # 2: B=bold, N=normal
- field_name = parts[10] if len(parts) > 10 else None
- idx = int(parts[1])
- if len(fields) != idx:
- raise EeException("Bad index: {}, expected={}. component={}, line={}".format(idx, len(fields), ref, line))
- fields.append(ComponentField(idx, field_name, value, pos))
- else:
- raise EeException("Bad component field: '{}'".format(line))
-
- sheet.add_component(Component(position, timestamp, library, name, unit, ref, fields))
-
- with open(path) as f:
- header = f.readline()
- if not "EESchema Schematic File Version" in header:
- raise EeException("Not a KiCAD schematic file.")
-
- sheet = schematic.first_sheet
-
- section_name = None
- section = []
-
- seen_end = False
- while not seen_end:
- line = f.readline()
- if not line:
- break
-
- line = line.rstrip()
-
- if section_name:
- if line.startswith("$End"):
- print("END SECTION: {}".format(section_name))
- if section_name == "$Comp":
- comp_section(section)
- elif section_name == "$Descr":
- descr_section(section)
- else:
- if line == "$EndSCHEMATIC":
- seen_end = True
- break
- section_name = None
- else:
- section.append(line)
- else:
- parts = line.split(" ")
- if line.startswith("EELAYER "):
- pass # Legacy, ignored
- elif line.startswith("LIBS:"):
- schematic.add_library(line[5:])
- elif line.startswith("$"):
- section_name = parts[0]
- print("SECTION: {}".format(section_name))
- section = []
- elif line == "Entry Wire Line":
- f.readline() # ignore the next line for now
- elif line.startswith("Text Label "):
- f.readline() # ignore the next line for now
- elif line.startswith("Text Notes "):
- f.readline() # ignore the next line for now
- elif line.startswith("NoConn "):
- pass
- elif parts[0:3] == ["Wire", "Notes", "Line"]:
- f.readline() # ignore the next line for now
- elif parts[0:3] == ["Wire", "Wire", "Line"]:
- f.readline() # ignore the next line for now
- elif parts[0:3] == ["Wire", "Bus", "Line"]:
- f.readline() # ignore the next line for now
- elif parts[0:2] == ["Connection", "~"]:
- pass
- else:
- print("line={}, len={}, wat={}".format(line, len(line), parts[0:3]))
- raise EeException("Bad line: {}".format(line))
-
- return schematic
+from ee.kicad.read_schematic import read_schematic
+from .model import *
+
+__all__ = [
+ "Position",
+ "ComponentField",
+ "Component",
+ "Schematic",
+ "read_schematic",
+]
diff --git a/src/ee/kicad/model.py b/src/ee/kicad/model.py
new file mode 100644
index 0000000..3c6001c
--- /dev/null
+++ b/src/ee/kicad/model.py
@@ -0,0 +1,109 @@
+from typing import List
+
+class Position(object):
+ def __init__(self, x, y):
+ self._x = x
+ self._y = y
+
+ @property
+ def x(self):
+ return _x
+
+ @property
+ def y(self):
+ return _y
+
+class ComponentField(object):
+ names = ["Name", "Reference", "Value", "Footprint", "Datasheet"]
+ def __init__(self, index, name, value, position):
+ self._index = index
+ self._name = name if index >= len(ComponentField.names) else ComponentField.names[index]
+ self._value = value
+ self._position = position
+
+ @property
+ def name(self):
+ return self._name
+
+ @property
+ def value(self):
+ return self._value
+
+ @property
+ def position(self):
+ return self._position
+
+class Component(object):
+ def __init__(self, position, timestamp, library, name, unit, ref, fields):
+ self._position = position
+ self._timestamp = timestamp
+ self._library = library
+ self._name = name
+ self._unit = unit
+ self._ref = ref
+ self._fields = fields # type List[ComponentField]
+
+ @property
+ def unit(self):
+ return self._unit
+
+ @property
+ def ref(self):
+ return self._ref
+
+ @property
+ def fields(self) -> List[ComponentField]:
+ return list(self._fields)
+
+ @property
+ def named_fields(self):
+ return [f for f in self._fields if f.name]
+
+class Sheet(object):
+ def __init__(self):
+ self._components = []
+ pass
+
+ @property
+ def components(self):
+ return frozenset(self._components)
+
+ def add_component(self, component):
+ self._components.append(component)
+
+class Library(object):
+ def __init__(self, name):
+ self.name = name
+
+class Schematic(object):
+ def __init__(self):
+ self._libraries = set()
+ self._sheets = [Sheet()]
+ pass
+
+ @property
+ def first_sheet(self):
+ return self._sheets[0]
+
+ @property
+ def libraries(self):
+ return frozenset(self._libraries)
+
+ def add_library(self, library):
+ self._libraries.add(Library(library))
+
+ # Getters
+ @property
+ def components(self):
+ a = []
+ for s in self._sheets:
+ for c in s.components:
+ a.append(c)
+ return a
+
+ def get_component(self, ref, unit = 1):
+ for c in self.components:
+ if c.ref == ref and unit == unit:
+ return c
+
+ raise KeyError("No such component: {}".format(ref))
diff --git a/src/ee/kicad/read_schematic.py b/src/ee/kicad/read_schematic.py
new file mode 100644
index 0000000..6fa9686
--- /dev/null
+++ b/src/ee/kicad/read_schematic.py
@@ -0,0 +1,129 @@
+import shlex
+from ee.kicad.model import *
+
+def read_schematic(path):
+ schematic = Schematic()
+ sheet = None
+
+ def descr_section(lines):
+ print("descr_section: len={}".format(len(lines)))
+ pass
+
+ def comp_section(lines):
+ print("comp_section: len={}".format(len(lines)))
+ timestamp = None
+ position = None
+ library = None
+ name = None
+ unit = None
+ fields = []
+
+ extra_lines = 0
+ for line in lines:
+ if line.startswith((' ', '\t')):
+ parts = line.strip().split(" ")
+ if extra_lines == 0:
+ pass
+ else:
+ # rotation/mirroring, x1, y1, x2, y2
+ pass
+ extra_lines += 1
+ else:
+ parts = shlex.split(line)
+ if len(parts) < 3:
+ raise EeException("Bad component line: {}".format(line))
+
+ if parts[0] == "L" and len(parts) == 3:
+ name = parts[1]
+ ref = parts[2]
+ elif parts[0] == "U" and len(parts) == 4:
+ unit = int(parts[1])
+ # parts[2] == body style
+ timestamp = parts[3]
+ elif parts[0] == "P" and len(parts) == 3:
+ position = Position(int(parts[1]), int(parts[2]))
+ elif parts[0] == "F" and len(parts) >= 10:
+ oritentation = parts[3]
+ pos = Position(int(parts[4]), int(parts[5]))
+ value = parts[2]
+ size = parts[6]
+ attributes = parts[7]
+ justify = parts[8] # One of L, R, C
+ textAttrs = parts[9] # tree characters,
+ # 0: T=top justify, B=bottom justify, C=center
+ # 1: I=italics, N=normal
+ # 2: B=bold, N=normal
+ field_name = parts[10] if len(parts) > 10 else None
+ idx = int(parts[1])
+ if len(fields) != idx:
+ raise EeException("Bad index: {}, expected={}. component={}, line={}".format(idx, len(fields), ref, line))
+ fields.append(ComponentField(idx, field_name, value, pos))
+ else:
+ raise EeException("Bad component field: '{}'".format(line))
+
+ sheet.add_component(Component(position, timestamp, library, name, unit, ref, fields))
+
+ with open(path) as f:
+ header = f.readline()
+ if not "EESchema Schematic File Version" in header:
+ raise EeException("Not a KiCAD schematic file.")
+
+ sheet = schematic.first_sheet
+
+ section_name = None
+ section = []
+
+ seen_end = False
+ while not seen_end:
+ line = f.readline()
+ if not line:
+ break
+
+ line = line.rstrip()
+
+ if section_name:
+ if line.startswith("$End"):
+ print("END SECTION: {}".format(section_name))
+ if section_name == "$Comp":
+ comp_section(section)
+ elif section_name == "$Descr":
+ descr_section(section)
+ else:
+ if line == "$EndSCHEMATIC":
+ seen_end = True
+ break
+ section_name = None
+ else:
+ section.append(line)
+ else:
+ parts = line.split(" ")
+ if line.startswith("EELAYER "):
+ pass # Legacy, ignored
+ elif line.startswith("LIBS:"):
+ schematic.add_library(line[5:])
+ elif line.startswith("$"):
+ section_name = parts[0]
+ print("SECTION: {}".format(section_name))
+ section = []
+ elif line == "Entry Wire Line":
+ f.readline() # ignore the next line for now
+ elif line.startswith("Text Label "):
+ f.readline() # ignore the next line for now
+ elif line.startswith("Text Notes "):
+ f.readline() # ignore the next line for now
+ elif line.startswith("NoConn "):
+ pass
+ elif parts[0:3] == ["Wire", "Notes", "Line"]:
+ f.readline() # ignore the next line for now
+ elif parts[0:3] == ["Wire", "Wire", "Line"]:
+ f.readline() # ignore the next line for now
+ elif parts[0:3] == ["Wire", "Bus", "Line"]:
+ f.readline() # ignore the next line for now
+ elif parts[0:2] == ["Connection", "~"]:
+ pass
+ else:
+ print("line={}, len={}, wat={}".format(line, len(line), parts[0:3]))
+ raise EeException("Bad line: {}".format(line))
+
+ return schematic
+