aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2018-07-17 12:23:58 +0200
committerTrygve Laugstøl <trygvis@inamo.no>2018-07-17 12:23:58 +0200
commita30b71772e7eb831e8d87759172a02e79f9673c4 (patch)
tree365d292e6ce73341055d888dd80f7e45b445beec /src
parentd72247b46519609fb0b373d34bcc5d5939d7b9c3 (diff)
downloadee-python-a30b71772e7eb831e8d87759172a02e79f9673c4.tar.gz
ee-python-a30b71772e7eb831e8d87759172a02e79f9673c4.tar.bz2
ee-python-a30b71772e7eb831e8d87759172a02e79f9673c4.tar.xz
ee-python-a30b71772e7eb831e8d87759172a02e79f9673c4.zip
wip. pcb.
Diffstat (limited to 'src')
-rw-r--r--src/ee/fact/__init__.py50
-rw-r--r--src/ee/kicad/doit.py97
-rw-r--r--src/ee/kicad/pcb/__init__.py40
3 files changed, 120 insertions, 67 deletions
diff --git a/src/ee/fact/__init__.py b/src/ee/fact/__init__.py
index 959e755..1bdef0d 100644
--- a/src/ee/fact/__init__.py
+++ b/src/ee/fact/__init__.py
@@ -1,12 +1,13 @@
-from typing import Optional, Mapping, List
import configparser
+import logging
import os
-from pathlib import Path
from functools import total_ordering
-import logging
+from pathlib import Path
+from typing import MutableMapping, Optional, Mapping, List
logger = logging.getLogger(__name__)
+
@total_ordering
class ObjectType(object):
def __init__(self, name: str):
@@ -14,28 +15,20 @@ class ObjectType(object):
self._fields = []
self._objects = {}
- def __eq__(self, o: object) -> bool:
- other = o # type ObjectType
+ def __eq__(self, o) -> bool:
+ other = o # type: ObjectType
return isinstance(o, ObjectType) and self._name == other._name
def __lt__(self, o: object) -> bool:
if not isinstance(o, ObjectType):
return True
- other = o # type ObjectType
- return (self._name) < (self._name)
+ other = o # type: ObjectType
+ return self._name < other._name
def __hash__(self) -> int:
return self._name.__hash__()
- def by_key(self, key: str) -> "Object":
- try:
- return self._objects[key]
- except ValueError:
- o = Object(self, key, {}, {})
- self._objects[key] = o
- return o
-
@property
def name(self):
return self._name
@@ -54,6 +47,7 @@ class ObjectType(object):
self._fields.append(field)
return len(self._fields) - 1
+
class Object(object):
def __init__(self, ds: "DataSet", ot: ObjectType, key: str):
self._ds = ds
@@ -81,13 +75,14 @@ class Object(object):
def get(self, key: str) -> Optional[str]:
idx = self._ot.index_of(key)
- return self._data[idx]
+ return self._data[idx] if idx < len(self._data) else None
+
class DataSet(object):
def __init__(self, name):
self._name = name
self._object_types = {}
- self._objects_by_type = {} # type: Mapping[str, Mapping[str, Object]]
+ self._objects_by_type = {} # type: MutableMapping[str, Mapping[str, Object]]
self._frozen = False
self._changed = False
@@ -146,6 +141,7 @@ class DataSet(object):
return ds
+
class DataSetManager(object):
def __init__(self, basedir: Path):
self._basedir = Path(basedir)
@@ -181,7 +177,7 @@ class DataSetManager(object):
ini = self._load_ini(o_path)
o = ds.get_object(ot, key)
for k, v in ini.items("values"):
- o.set(k, v)
+ o.set(k, v)
if freeze:
ds.freeze()
@@ -212,11 +208,13 @@ class DataSetManager(object):
ini.add_section("values")
for k in ot.fields:
v = o.get(k)
- ini.set("values", k, v)
+ if v:
+ ini.set("values", k, str(v))
self._store_ini(ini, ot_dir / "{}.ini".format(key))
- def _blank_ini(self):
- return configparser.ConfigParser(interpolation = None)
+ @staticmethod
+ def _blank_ini():
+ return configparser.ConfigParser(interpolation=None)
def _load_ini(self, path: Path):
ini = self._blank_ini()
@@ -224,10 +222,12 @@ class DataSetManager(object):
raise IOError("Could not load ini file: {}".format(path))
return ini
- def _store_ini(self, ini, path):
+ @staticmethod
+ def _store_ini(ini, path):
with open(path, "w") as f:
ini.write(f)
+
class LazyDataSet(object):
def __init__(self, dsm: DataSetManager, name, inputs):
self._dsm = dsm
@@ -235,7 +235,7 @@ class LazyDataSet(object):
self._inputs = inputs
def __enter__(self):
-# logger.info("enter: name={}, inputs={}".format(self._name, self._inputs))
+ # logger.info("enter: name={}, inputs={}".format(self._name, self._inputs))
ds = DataSet(self._name)
for name in self._inputs:
ds = ds.merge(self._dsm.load(name, freeze=True))
@@ -243,7 +243,7 @@ class LazyDataSet(object):
return self._ds
def __exit__(self, *args):
-# logger.info("exit: name={}, inputs={}".format(self._name, self._inputs))
-# logger.info("ds.size={}".format(len(self._ds.items())))
+ # logger.info("exit: name={}, inputs={}".format(self._name, self._inputs))
+ # logger.info("ds.size={}".format(len(self._ds.items())))
self._dsm.store(self._ds)
return False
diff --git a/src/ee/kicad/doit.py b/src/ee/kicad/doit.py
index 10de885..fcbcaef 100644
--- a/src/ee/kicad/doit.py
+++ b/src/ee/kicad/doit.py
@@ -1,13 +1,14 @@
+import logging
import os.path
-from doit.exceptions import TaskFailed
-from doit.tools import check_timestamp_unchanged
-from configclass import Config
from typing import List
+
+from configclass import Config
+
from ee.fact import DataSetManager
-import logging
logger = logging.getLogger(__name__)
+
class KicadDoitTasks(object):
config = Config({
"sch": None,
@@ -15,7 +16,7 @@ class KicadDoitTasks(object):
"gerber_dir": None,
"gerber_zip": None,
"data_set_dir": None,
- })
+ })
def __init__(self, *args, **kwargs):
self.config = self.config.make(kwargs)
@@ -24,7 +25,6 @@ class KicadDoitTasks(object):
logger.info("_task: args={}, kwars={}".format(args, kwargs))
def tasks(self, *args, **kwargs):
- import ee.kicad
kicad_pcb = self.config["kicad_pcb"]
sch = self.config["sch"]
tasks = []
@@ -32,24 +32,32 @@ class KicadDoitTasks(object):
dsm = DataSetManager(self.config["data_set_dir"])
gerber_dir = self.config["gerber_dir"]
- if gerber_dir:
- tasks.append(task_kicad_gerber())
+ gerber_zip = self.config["gerber_zip"]
+ if kicad_pcb and gerber_dir:
+ tasks.append(task_kicad_gerber(kicad_pcb, gerber_dir, gerber_zip))
- sch_ds = task_kicad_sch_to_data_set(dsm, sch, \
- in_data_sets=[], \
- out_data_set="kicad-sch-data-set") \
- if sch else None
+ sch_ds = task_kicad_sch_to_data_set(dsm, sch,
+ in_data_sets=[],
+ out_data_set="kicad-sch-data-set") \
+ if sch else None
- component_ds = task_kicad_create_component_data_set(dsm, \
- in_data_sets=sch_ds["targets"], \
- out_data_set="raw-component") \
- if sch_ds else None
+ component_ds = task_kicad_create_component_data_set(dsm,
+ in_data_sets=sch_ds["targets"],
+ out_data_set="raw-component") \
+ if sch_ds else None
- return (t for t in [sch_ds, component_ds] if t is not None)
+ pcb_ds = task_kicad_pcb_to_data_set(dsm, kicad_pcb, in_data_sets=[], out_data_set="kicad-pcb") \
+ if kicad_pcb else None
-def task_kicad_gerber(name="kicad-gerber"):
- gerber_zip = self.config["gerber_zip"] or "{}.zip".format(gerber_dir)
- #logger.info("gerber_zip={}".format(gerber_zip))
+ tasks = [sch_ds, component_ds, pcb_ds]
+ return (t for t in tasks if t)
+
+
+def task_kicad_gerber(kicad_pcb: str, gerber_dir: str, gerber_zip: str, name="kicad-gerber"):
+ import ee.kicad
+
+ gerber_zip = len(gerber_zip) or "{}.zip".format(gerber_dir)
+ # logger.info("gerber_zip={}".format(gerber_zip))
eg = next((p for p in (os.path.join(p, "export_gerber.py") for p in ee.kicad.__path__) if os.path.isfile(p)), None)
if not eg:
@@ -63,6 +71,7 @@ def task_kicad_gerber(name="kicad-gerber"):
"--output-directory", gerber_dir,
"--protel-extensions",
])
+
def make_zip():
import zipfile
from pathlib import Path
@@ -79,12 +88,12 @@ def task_kicad_gerber(name="kicad-gerber"):
"file_dep": [kicad_pcb],
}
-def task_kicad_sch_to_data_set(dsm: DataSetManager, sch, in_data_sets: List[str], out_data_set, name="kicad-sch-to-data-set"):
+
+def task_kicad_sch_to_data_set(dsm: DataSetManager, sch, in_data_sets: List[str], out_data_set,
+ name="kicad-sch-to-data-set"):
def action():
import ee.kicad
- from ee.kicad.model import Component, ComponentField
- import csv
- import configparser
+ from ee.kicad.model import ComponentField
with dsm.create_rw(out_data_set, inputs=in_data_sets) as ds:
schematics = ee.kicad.read_schematics(sch)
@@ -109,10 +118,46 @@ def task_kicad_sch_to_data_set(dsm: DataSetManager, sch, in_data_sets: List[str]
"targets": [dsm.metafile_for_ds(out_data_set)],
}
-def task_kicad_create_component_data_set(dsm: DataSetManager, in_data_sets: List[str], out_data_set, name="kicad-create-component-data-set"):
+
+def task_kicad_pcb_to_data_set(dsm: DataSetManager, pcb_path, in_data_sets: List[str], out_data_set,
+ name="kicad-pcb-to-data-set"):
+ def action():
+ import ee.kicad.pcb
+ from ee.kicad.pcb import FpText
+
+ with dsm.create_rw(out_data_set, inputs=in_data_sets) as ds:
+ # [ds.delete(o) for o in ds.items(object_type="kicad-pcb-component")]
+
+ pcb: ee.kicad.pcb.KicadPcb = ee.kicad.pcb.parse(pcb_path)
+ for _m in pcb.modules:
+ m: ee.kicad.pcb.Module = _m
+ logger.info("attrs")
+ for s in dir(m):
+ logger.info(s)
+
+ o = ds.get_object("kicad-pcb-component", m.tstamp)
+
+ ref_text: FpText = next((t for t in m.fp_texts if t.kind == "reference"), None)
+ o.set("reference", ref_text.value)
+
+ x, y, rot = m.at
+ o.set("at-x", x)
+ o.set("at-y", y)
+ o.set("at-rot", rot)
+ o.set("layer", m.layer)
+
+ return {
+ "name": name,
+ "file_dep": [pcb_path] + [dsm.metafile_for_ds(ds) for ds in in_data_sets],
+ "actions": [action],
+ "targets": [dsm.metafile_for_ds(out_data_set)],
+ }
+
+
+def task_kicad_create_component_data_set(dsm: DataSetManager, in_data_sets: List[str], out_data_set,
+ name="kicad-create-component-data-set"):
def action(*args, **kwargs):
logger.info("args={}, kwargs={}".format(args, kwargs))
- import ee.fact as fact
with dsm.create_rw(out_data_set, inputs=in_data_sets) as ds:
items = ds.items()
diff --git a/src/ee/kicad/pcb/__init__.py b/src/ee/kicad/pcb/__init__.py
index 79987e6..25689ef 100644
--- a/src/ee/kicad/pcb/__init__.py
+++ b/src/ee/kicad/pcb/__init__.py
@@ -49,18 +49,21 @@ class Pad(object):
@auto_str
class FpText(object):
def __init__(self, **kwargs):
+ self.kind = None # type: str
+ self.value = None # type: str
for k, v in kwargs.items():
setattr(self, k, v)
-def parse(path):
+
+def parse(path) -> KicadPcb:
count = 0
p = sexpr.parse(path)
#p = sexpr.logging_parser(p)
- (event, token) = next(p)
- assert event == sexpr.EVENT_LPAREN
+ (e, t) = next(p)
+ assert e == sexpr.EVENT_LPAREN
- (event, token) = next(p)
- assert event == sexpr.EVENT_TEXT and token == "kicad_pcb"
+ (e, t) = next(p)
+ assert e == sexpr.EVENT_TEXT and t == "kicad_pcb"
idx = 0
def _consume():
@@ -134,10 +137,14 @@ def parse(path):
pads = []
fp_texts = []
- args = {}
- args["footprint"] = _parse_text()
- args["pads"] = pads
- args["fp_texts"] = fp_texts
+ args = {
+ "footprint": _parse_text(),
+ "pads": pads,
+ "fp_texts": fp_texts,
+ "layer": None,
+ "tedit": None,
+ "tstamp": None,
+ }
(event, token) = next(p)
while event == sexpr.EVENT_TEXT:
@@ -145,12 +152,12 @@ def parse(path):
while event == sexpr.EVENT_LPAREN:
(event, token) = next(p)
- if token == "layer":
- args[token] = _parse_text(rparen = True)
+ if token in ["layer", "tedit", "tstamp"]:
+ args[token] = _parse_text(rparen=True)
elif token == "at":
args[token] = _parse_at()
elif token == "attr":
- args[token] = [_parse_text(rparen = True)]
+ args[token] = [_parse_text(rparen=True)]
elif token == "pad":
pads.append(_parse_pad())
elif token == "fp_text":
@@ -163,8 +170,9 @@ def parse(path):
def _parse_pad():
texts = []
- args = {}
- args["footprint"] = _parse_text()
+ args = {
+ "footprint": _parse_text()
+ }
(event, token) = next(p)
while event == sexpr.EVENT_TEXT:
@@ -182,7 +190,7 @@ def parse(path):
return Pad(**args)
- def _parse_fp_text():
+ def _parse_fp_text() -> FpText:
args = {
"kind": _parse_text(),
"value": _parse_text(),
@@ -202,7 +210,7 @@ def parse(path):
x = _parse_text(to=float)
y = _parse_text(to=float)
rot = _parse_text(to=float, optional = True, rparen = True)
- return (x, y, rot or 0)
+ return x, y, rot or 0
kicad_pcb = _parse_kicad_pcb()
assert next(p, None) == None