Commits

Martin Vejnár committed 5157e6c

Added basic support for xml-based eagle drawings.

Comments (0)

Files changed (4)

         self.parse_name(o, entry[16:], 'value')
         o.library_id, o.deviceset_id, o.device_id, o.technology_id = unpack('<HHBB', entry[4:10])
 
-        c = self.pop_until(Schematic, Sheet)
-        c.parts.append(o)
-        self.ctx.append(o)
+        c = self.pop_until(Sheet)
+        for i in xrange(len(self.ctx)):
+            if (isinstance(self.ctx[-i], Schematic)):
+                sch = self.ctx[-i]
+                break
+
+        sch.parts.append(o)
 
     def instance(self, entry):
         o = Instance()
         o.smashed_part_count = ord(entry[2])
         o.smashed = (ord(entry[18]) & 0x01) != 0
 
-        c = self.pop_until(Part)
+        c = self.pop_until(Sheet)
+        for i in xrange(len(self.ctx)):
+            if (isinstance(self.ctx[-i], Schematic)):
+                sch = self.ctx[-i]
+                break
+
+        o.part_id = len(sch.parts)
+        o.part = sch.parts[-1].name
         c.instances.append(o)
         self.ctx.append(o)
 
         sch.layer_map[layer.number] = layer
 
 def parse_schematic(fin, **kw):
+    if fin.read(5) == '<?xml':
+        fin.seek(0)
+        import xml_parser
+        return xml_parser.parse_schematic(fin, **kw)
+
+    fin.seek(0)
     sch = Schematic()
     parser = _Parser(fin, sch, **kw)
     parser.parse_all()
 class Part(EagleObject):
     def __init__(self):
         self.attributes = []
-        self.instances = []
 
 class Sheet(EagleObject):
     def __init__(self):
         self.circles = []
         self.frames = []
         self.nets = []
-        self.parts = []
+        self.instances = []
         self.polygons = []
         self.rectangles = []
         self.texts = []
         for wire in seg.wires:
             self.print_wire(wire)
         for text in seg.texts:
-            self.print_part(texts)
+            self.print_text(text)
         for junc in seg.junctions:
             self.print_junction(junc)
         for label in seg.labels:
         for seg in net.segments:
             self.print_segment(net.name, seg)
 
-    def print_instance(self, lib, devset, part, inst):
+    def print_instance(self, inst):
         if not inst.visible:
             return
+
+        part = self.root.parts[inst.part_id-1]
+        lib = self.root.libraries[part.library_id-1]
+        devset = lib.devicesets[part.deviceset_id-1]
+
         gate = devset.gates[inst.gate_id-1]
         sym = lib.symbols[gate.symbol_id-1]
         device = devset.devices[part.device_id-1]
         self.out.append("""<rect x="%d" y="%d" width="%d" height="%d" fill="%s" />""" % (
             x, y, width, height, self.color_map[layer.color]))
 
-    def print_part(self, part):
-        lib = self.root.libraries[part.library_id-1]
-        devset = lib.devicesets[part.deviceset_id-1]
-        for instance in part.instances:
-            self.print_instance(lib, devset, part, instance)
-
     def print_bus(self, bus):
         for seg in bus.segments:
             self.print_segment(bus.name, seg)
     def print_sheet(self, sheet):
         for net in sheet.nets:
             self.print_net(net)
-        for part in sheet.parts:
-            self.print_part(part)
+        for instance in sheet.instances:
+            self.print_instance(instance)
         for text in sheet.texts:
             self.print_text(text)
         for poly in sheet.polygons:
+import sys, math
+from structs import *
+from struct import unpack
+from xml.dom.minidom import parse
+
+__all__ = ['parse_schematic', 'parse_library']
+
+_lengths = { None: 0, '': 0, 'point': 0, 'short': 1, 'middle': 2, 'long': 3 }
+_directions = { 'pas': 1 }
+_rrots = { 'R0': 0, 'R90': 1, 'R180': 2, 'R270': 3 }
+
+def _att(elem, name, default=None):
+    if elem.hasAttribute(name):
+        return elem.getAttribute(name)
+    else:
+        return default
+
+def _rot(rot):
+    if rot is None:
+        return 0
+    mirror = (rot[0] == 'M')
+    if mirror:
+        rot = rot[1:]
+
+    return float(rot[1:]) * 0x400 / 90.0, mirror
+
+def _rotr(rot):
+    if rot is None:
+        return 0
+    mirror = (rot[0] == 'M')
+    if mirror:
+        rot = rot[1:]
+
+    return _rrots.get(rot), mirror
+
+def _print_b(s, canon=False, prefix='  '):
+    ss = ''.join(((ord(ch) > 0x20 and ord(ch) < 0x7f) and ch or '.' for ch in s))
+    return prefix + ':'.join(('%02x' % ord(ch) for ch in s)) + ('    ' + ss if canon else '')
+
+def _parse_multistring(data):
+    res = []
+    while True:
+        pos = data.find(chr(0))
+        if pos == -1:
+            raise RuntimeError('Failed to read multistring')
+        if pos == 0:
+            if len(data) != 1:
+                raise RuntimeError('Failed to read multistring')
+            return res
+        res.append(data[:pos])
+        data = data[pos+1:]
+
+def _parse_bool(s):
+    return s in ('yes', '1', 'true', 'on')
+
+def _getText(elem, subelemname=None, default=None):
+    if subelemname is not None:
+        elems = elem.getElementsByTagName(subelemname)
+        if not elems:
+            return default
+        e = elems[0].childNodes
+    else:
+        e = elem.childNodes
+
+    rc = []
+    for node in e:
+        if node.nodeType == node.TEXT_NODE:
+            rc.append(node.data)
+    return ''.join(rc)
+
+def _walk(parent, tag, fn, ctx):
+    for elem in parent.getElementsByTagName(tag):
+        fn(ctx, elem)
+
+
+class _Parser(object):
+    def __init__(self, fin, sch):
+        self.fin = fin
+        self.top = sch
+        self.part_map = {}
+        self.lib_map = {}
+
+    def parse_all(self):
+        self.doc = parse(self.fin)
+        root = self.doc.documentElement
+        for layer_elem in root.getElementsByTagName('layers')[0].getElementsByTagName('layer'):
+            self.layer(self.top.layers, layer_elem)
+        sch = root.getElementsByTagName('schematic')[0]
+        for library in sch.getElementsByTagName('libraries')[0].getElementsByTagName('library'):
+            self.library(self.top.libraries, library)
+        _walk(sch.getElementsByTagName('parts')[0], 'part', self.part, self.top.parts)
+        _walk(sch.getElementsByTagName('sheets')[0], 'sheet', self.sheet, self.top.sheets)
+
+        # resolve
+        sch = self.top
+        for lib in sch.libraries:
+            for devset in lib.devicesets:
+                for gate in devset.gates:
+                    gate.symbol_id = lib.symbol_map[gate.symbol]+1
+
+        for sheet in sch.sheets:
+            for inst in sheet.instances:
+                inst.part_id = self.part_map[inst.part]+1
+                part = sch.parts[inst.part_id-1]
+                part.library_id = self.lib_map[part.library]+1
+                part.deviceset_id = sch.libraries[part.library_id-1].deviceset_map[part.deviceset]+1
+                part.device_id = sch.libraries[part.library_id-1].devicesets[part.deviceset_id-1].device_map[part.device]+1
+                inst.gate_id = sch.libraries[part.library_id-1].devicesets[part.deviceset_id-1].gate_map[inst.gate]+1
+
+    def sheet(self, cont, elem):
+        o = Sheet()
+        _walk(elem.getElementsByTagName('instances')[0], 'instance', self.instance, o.instances)
+        #_walk(elem.getElementsByTagName('busses')[0], 'bus', self.bus, o.busses)
+        _walk(elem.getElementsByTagName('nets')[0], 'net', self.net, o.nets)
+        _walk(elem, 'circles', self.circle, o.circles)
+        _walk(elem, 'rectangle', self.rectangle, o.rectangles)
+        _walk(elem, 'polygon', self.polygon, o.polygons)
+        cont.append(o)
+
+    def polygon(self, cont, elem):
+        o = Polygon()
+        o.width = float(elem.getAttribute('width'))*10000/2
+        o.layer = int(elem.getAttribute('layer'))
+
+        vertices = elem.getElementsByTagName('vertex')
+        for i in xrange(len(vertices)):
+            if i == len(vertices)-1:
+                j = 0
+            else:
+                j = i + 1
+
+            v = Wire()
+            v.x1 = float(vertices[i].getAttribute('x'))*10000
+            v.y1 = float(vertices[i].getAttribute('y'))*10000
+            v.x2 = float(vertices[j].getAttribute('x'))*10000
+            v.y2 = float(vertices[j].getAttribute('y'))*10000
+            v.layer = o.layer
+            v.width = o.width
+            v.arc = None
+            o.wires.append(v)
+
+        cont.append(o)
+
+    def net(self, cont, elem):
+        o = Net()
+        o.name = elem.getAttribute('name')
+        o.cls = int(elem.getAttribute('class'))
+        _walk(elem, 'segment', self.segment, o.segments)
+        cont.append(o)
+
+    def segment(self, cont, elem):
+        o = Segment()
+        #_walk(elem, 'pinref', self.pinref, o.pinrefs)
+        _walk(elem, 'wire', self.wire, o.wires)
+        _walk(elem, 'junction', self.junction, o.junctions)
+        _walk(elem, 'text', self.text, o.texts)
+        #_walk(elem, 'labels', self.label, o.labels)
+        cont.append(o)
+
+    def junction(self, cont, elem):
+        o = Junction()
+        o.x = float(elem.getAttribute('x'))*10000
+        o.y = float(elem.getAttribute('y'))*10000
+        o.layer = 91
+        o.diameter = 5000
+        cont.append(o)
+
+    #def pinref(self, cont, elem):
+    #    o = Pinref()
+    #    cont.append(o)
+
+    def bus(self, cont, elem):
+        o = Bus() # XXX
+        cont.append(o)
+
+    def instance(self, cont, elem):
+        o = Instance()
+        o.visible = _parse_bool(_att(elem, 'visible', 'yes'))
+        o.part = elem.getAttribute('part')
+        o.gate = elem.getAttribute('gate')
+        o.x = float(elem.getAttribute('x'))*10000
+        o.y = float(elem.getAttribute('y'))*10000
+        o.smashed = False # XXX
+        o.angle, o.mirror = _rot(_att(elem, 'rot', 'R0'))
+        cont.append(o)
+
+    def part(self, cont, elem):
+        o = Part()
+        o.name = elem.getAttribute('name')
+        o.library = elem.getAttribute('library')
+        o.deviceset = elem.getAttribute('deviceset')
+        o.device = elem.getAttribute('device')
+        o.value = elem.getAttribute('value')
+        self.part_map[o.name] = len(cont)
+        cont.append(o)
+
+    def library(self, libs, elem):
+        lib = Library()
+        lib.name = elem.getAttribute('name')
+        lib.description = _getText(elem, 'description', '')
+        lib.deviceset_map = {}
+        lib.symbol_map = {}
+        _walk(elem.getElementsByTagName('packages')[0], 'package', self.package, lib.packages)
+        _walk(elem.getElementsByTagName('symbols')[0], 'symbol', self.symbol, lib)
+        _walk(elem.getElementsByTagName('devicesets')[0], 'deviceset', self.deviceset, lib)
+        self.lib_map[lib.name] = len(libs)
+        libs.append(lib)
+
+    def deviceset(self, lib, elem):
+        o = DeviceSet()
+        o.name = elem.getAttribute('name')
+        o.prefix = elem.getAttribute('prefix')
+        o.uservalue = _parse_bool(_att(elem, 'uservalue', 'no'))
+        o.description = _getText(elem, 'description', '')
+        o.device_map = {}
+        o.gate_map = {}
+        _walk(elem.getElementsByTagName('gates')[0], 'gate', self.gate, o)
+        _walk(elem.getElementsByTagName('devices')[0], 'device', self.device, o)
+        lib.deviceset_map[o.name] = len(lib.devicesets)
+        lib.devicesets.append(o)
+
+    def device(self, deviceset, elem):
+        o = Device()
+        o.name = elem.getAttribute('name')
+        o.package = elem.getAttribute('package')
+        #_walk(elem.getElementsByTagName('connects')[0], 'connect', self.connect, o)
+        def _tech(o, elem):
+            o.technologies.append(elem.getAttribute('name'))
+        _walk(elem.getElementsByTagName('technologies')[0], 'technology', _tech, o)
+        deviceset.device_map[o.name] = len(deviceset.devices)
+        deviceset.devices.append(o)
+
+    def gate(self, cont, elem):
+        o = Gate()
+        o.name = elem.getAttribute('name')
+        o.symbol = elem.getAttribute('symbol')
+        o.x = float(elem.getAttribute('x'))*10000
+        o.y = float(elem.getAttribute('y'))*10000
+        cont.gate_map[o.name] = len(cont.gates)
+        cont.gates.append(o)
+
+    def symbol(self, cont, elem):
+        o = Symbol()
+        o.name = elem.getAttribute('name')
+        _walk(elem, 'wire', self.wire, o.wires)
+        _walk(elem, 'text', self.text, o.texts)
+        _walk(elem, 'pin', self.pin, o.pins)
+        _walk(elem, 'circle', self.circle, o.circles)
+        _walk(elem, 'rectangle', self.rectangle, o.rectangles)
+        _walk(elem, 'polygon', self.polygon, o.polygons)
+        cont.symbol_map[o.name] = len(cont.symbols)
+        cont.symbols.append(o)
+
+    def circle(self, cont, elem):
+        o = Circle()
+        o.x = float(elem.getAttribute('x'))*10000
+        o.y = float(elem.getAttribute('y'))*10000
+        o.radius = float(elem.getAttribute('radius'))*10000
+        o.width = float(elem.getAttribute('width'))*10000/2
+        o.layer = int(elem.getAttribute('layer'))
+        cont.append(o)
+
+    def pin(self, cont, elem):
+        o = Pin()
+        o.name = elem.getAttribute('name')
+        o.x = float(elem.getAttribute('x'))*10000
+        o.y = float(elem.getAttribute('y'))*10000
+        o.visible = _parse_bool(elem.getAttribute('visible'))
+
+        o.length = _lengths[elem.getAttribute('length')]
+        o.direction = _directions.get(elem.getAttribute('direction'))
+        o.swaplevel = int(_att(elem, 'swaplevel', '0'))
+        o.angle, o.mirror = _rotr(_att(elem, 'rot', 'R0'))
+        o.function = 0 # XXX
+
+        cont.append(o)
+
+    def package(self, packages, elem):
+        package = Package()
+        package.name = elem.getAttribute('name')
+        package.description = _getText(elem, 'description', '')
+        _walk(elem, 'wire', self.wire, package.wires)
+        #_walk(elem, 'smd', self.smd, package.smds)
+        #_walk(elem, 'pad', self.smd, package.pad)
+        _walk(elem, 'text', self.text, package.texts)
+        _walk(elem, 'rectangle', self.rectangle, package.rectangles)
+        _walk(elem, 'circle', self.circle, package.circles)
+        _walk(elem, 'polygon', self.polygon, package.polygons)
+        packages.append(package)
+
+    def rectangle(self, cont, elem):
+        o = Rectangle()
+        o.x1 = float(elem.getAttribute('x1'))*10000
+        o.y1 = float(elem.getAttribute('y1'))*10000
+        o.x2 = float(elem.getAttribute('x2'))*10000
+        o.y2 = float(elem.getAttribute('y2'))*10000
+        o.layer = int(elem.getAttribute('layer'))
+        o.angle = float(_att(elem, 'angle', 0.0))
+        cont.append(o)
+
+    def text(self, texts, elem):
+        text = Text()
+        text.x = float(elem.getAttribute('x'))*10000
+        text.y = float(elem.getAttribute('y'))*10000
+        text.size = float(elem.getAttribute('size'))*10000/2
+        text.layer = int(elem.getAttribute('layer'))
+        text.value = _getText(elem)
+        text.font = None # XXX
+        text.ratio = None # XXX
+        text.angle, text.mirror = _rotr(_att(elem, 'rot', 'R0'))
+        texts.append(text)
+
+    def wire(self, wires, elem):
+        wire = Wire()
+        wire.x1 = float(elem.getAttribute('x1'))*10000
+        wire.y1 = float(elem.getAttribute('y1'))*10000
+        wire.x2 = float(elem.getAttribute('x2'))*10000
+        wire.y2 = float(elem.getAttribute('y2'))*10000
+        wire.width = float(elem.getAttribute('width'))*10000/2
+        wire.layer = int(elem.getAttribute('layer'))
+        wire.arc = None
+        wires.append(wire)
+
+    def layer(self, cont, elem):
+        layer = Layer()
+        layer.number = int(elem.getAttribute('number'))
+        layer.name = elem.getAttribute('name')
+        layer.color = int(elem.getAttribute('color'))
+        layer.fill = int(elem.getAttribute('fill'))
+        layer.visible = _parse_bool(elem.getAttribute('visible'))
+        layer.active = _parse_bool(elem.getAttribute('active'))
+        cont.append(layer)
+
+
+
+def _postprocess(sch):
+    sch.layer_map = {}
+    for layer in sch.layers:
+        sch.layer_map[layer.number] = layer
+
+def parse_schematic(fin, **kw):
+    sch = Schematic()
+    parser = _Parser(fin, sch)
+    parser.parse_all()
+    _postprocess(sch)
+    return sch
+
+def parse_library(fin, **kw):
+    sch = Library()
+    parser = _Parser(fin, sch, **kw)
+    parser.parse_all()
+    return sch