Ejemplo n.º 1
0
        public void MapPortToNet(Tonka.SchematicModelPort port, Signal n)
        {
            // get the build port for this schematic domain port & store the net with the build port
            var buildPort = port != null &&
                CyPhyBuildVisitor.Ports.ContainsKey(port.ID) ?
                CyPhyBuildVisitor.Ports[port.ID] : null;

            // now remember this net with the spice-build port 
            // - we will use it when building the spice model
            if (buildPort != null && !portTraceMap.ContainsKey(buildPort))
                portTraceMap.Add(buildPort, n);

            if (CodeGenerator.verbose)
            {
                if (buildPort == null)
                    gmeLogger.WriteWarning("No Matching Build Port  for {0}, ignoring trace", port.Name);
                else
                    gmeLogger.WriteInfo("Mapping Build Port {0} to Net {1}", buildPort.Name, n.name);
            }

        }
Ejemplo n.º 2
0
        public LayoutGenerator(Eagle.schematic sch_obj, TestBench tb_obj, GMELogger inLogger)
        {
            this.Logger = inLogger;
            this.pkgPartMap = new Dictionary<Package, Eagle.part>();
            this.partPkgMap = new Dictionary<Eagle.part, Package>();
            this.preroutedPkgMap = new Dictionary<ComponentAssembly, Package>();

            boardLayout = new LayoutJson.Layout();
            var bw = tb_obj.Parameters.Where(p => p.Name.Equals("boardWidth")).FirstOrDefault();
            var bh = tb_obj.Parameters.Where(p => p.Name.Equals("boardHeight")).FirstOrDefault();

            try
            {
                boardLayout.boardWidth = (bw != null) ? Convert.ToDouble(bw.Value) : 40.0;
                boardLayout.boardHeight = (bh != null) ? Convert.ToDouble(bh.Value) : 40.0;
            }
            catch (FormatException ex)
            {
                Logger.WriteWarning("Exception while reading board dimensions: {0}", ex.Message);
            }
            boardLayout.numLayers = 2;
            {
                // Look to see if there is a PCB component in the top level assembly 
                var compImpl = tb_obj.ComponentAssemblies.SelectMany(c => c.ComponentInstances).Select(i => i.Impl)
                    .Where(j => (j as Tonka.Component).Attributes.Classifications
                        .Contains("pcb_board")).FirstOrDefault();
                // Look to see if it has a resource labeled 'BoardTemplate'
                var comp = (compImpl != null) ? compImpl as Tonka.Component : null;
                var btRes = (comp != null) ? comp.Children.ResourceCollection.Where(r =>
                    r.Name.ToUpper().Contains("BOARDTEMPLATE")).FirstOrDefault() : null;
                if (btRes != null)
                {
                    var btPath = Path.Combine(comp.Attributes.Path, btRes.Attributes.Path);
                    boardLayout.boardTemplate = Path.GetFileName(btPath);
                }
            }

            // the prior code looks up for a boardTemplate file associated with a PCB component
            // the users can override it with a boardTemplate file specified as a testbench parameter
            {
                var bt = tb_obj.Parameters.Where(p => p.Name.Equals("boardTemplate")).FirstOrDefault();
                // if its a file path - we only want to pass the file name to board synthesis
                if (bt != null)
                    try
                    {
                        boardLayout.boardTemplate = Path.GetFileName(bt.Value);
                    }
                    catch (System.ArgumentException ex)
                    {
                        CodeGenerator.Logger.WriteError("Error extracting boardTemplate filename: {0}", ex.Message);
                    }
            }
            // the users also can specify a designRule file as a testbench parameter
            {
                var dr = tb_obj.Parameters.Where(p => p.Name.Equals("designRules")).FirstOrDefault();
                if (dr != null)
                    try
                    {
                        boardLayout.designRules = Path.GetFileName(dr.Value);
                    }
                    catch (System.ArgumentException ex)
                    {
                        CodeGenerator.Logger.WriteError("Error extracting designRules filename: {0}", ex.Message);
                    }
            }

            boardLayout.packages = new List<Package>();
            int pkg_idx = 0;

            // we want to handle prerouted assemblies as follows
            // 1) all parts that are part of the pre-routed assembly are tagged with a 'virtual' spaceClaim part
            // 2) we add their absolute location (in the subckt frame of refernece) in the output json
            // 3) we create virtual spaceClaim parts for pre-routed subcircuits

            // 4) all nets belonging to the pre-routed subcircuit are tagged with the spaceClaim part
            // 5) these nets are added to json with absolute location (same as parts above)

            foreach (var ca in tb_obj.ComponentAssemblies)
            {
                pkg_idx = HandlePreRoutedAsm(ca, pkg_idx);
            }

            // compute part dimensions from 
            foreach (var part in sch_obj.parts.part)
            {
                var dev = sch_obj.libraries.library.Where(l => l.name.Equals(part.library)).
                    SelectMany(l => l.devicesets.deviceset).Where(ds => ds.name.Equals(part.deviceset)).
                    SelectMany(ds => ds.devices.device).Where(d => d.name.Equals(part.device)).FirstOrDefault();
                var spkg = (dev != null)
                           ? sch_obj.libraries.library.Where(l => l.name.Equals(part.library))
                                    .SelectMany(l => l.packages.package).Where(p => p.name.Equals(dev.package))
                                    .FirstOrDefault()
                           : null;

                Package pkg = new Package();
                pkg.name = part.name;
                pkg.pkg_idx = pkg_idx++;

                if (dev == null || spkg == null)
                {
                    // emit warning
                    Logger.WriteWarning("Unable to get package size for part - layout/chipfit results may be inaccurate: {0}", part.name);
                }
                else
                {
                    pkg.package = spkg.name;        // note that the eagle package information may be incomplete - should really have curated version from CyPhy

                    #region ComputePackageSize

                    var minX = Double.MaxValue;
                    var minY = Double.MaxValue;
                    var maxX = Double.MinValue;
                    var maxY = Double.MinValue;

                    foreach (Eagle.wire wire in spkg.Items.Where(s => s is Eagle.wire))
                    {
                        if (wire == null) continue;

                        if (!LayersForBoundingBoxComputation.Any(wire.layer.Contains))
                            continue;

                        var x1 = Convert.ToDouble(wire.x1);
                        var x2 = Convert.ToDouble(wire.x2);
                        var y1 = Convert.ToDouble(wire.y1);
                        var y2 = Convert.ToDouble(wire.y2);
                        if (x1 < minX) minX = x1;
                        if (x2 < minX) minX = x2;
                        if (x1 > maxX) maxX = x1;
                        if (x2 > maxX) maxX = x2;
                        if (y1 < minY) minY = y1;
                        if (y2 < minY) minY = y2;
                        if (y1 > maxY) maxY = y1;
                        if (y2 > maxY) maxY = y2;
                    }
                    foreach (Eagle.pad pad in spkg.Items.Where(s => s is Eagle.pad))
                    {
                        if (pad == null) continue;
                        var pad_num = pad.name;
                        var x = Convert.ToDouble(pad.x);
                        var y = Convert.ToDouble(pad.y);
                        var drill = Convert.ToDouble(pad.drill);
                        var dia = Convert.ToDouble(pad.diameter);
                        var shape = pad.shape;  // enum padShape {round, octagon, @long, offset}
                        var rot = pad.rot;      // { R90, R180, R270, ...}  
                        var r = 0.0;
                        if (dia == 0.0)  // JS: Workaround for no diameter present, estimate dia to be 2x drill size 
                        {
                            dia = drill * 2.0;
                        }

                        if (shape == Eagle.padShape.@long)
                        {
                            // TODO: consider PAD rotation; for now, consider long pads are 2x diameter.

                            dia *= 2.0;  // diameter value from package desc is for the "short" side, for max calc, consider long side is 2x (by inspection)
                        }
                        r = dia / 2.0;

                        if ((x - r) < minX) minX = x - r;
                        if ((x + r) > maxX) maxX = x + r;
                        if ((y - r) < minY) minY = y - r;
                        if ((y + r) > maxY) maxY = y + r;
                    }
                    foreach (Eagle.circle circle in spkg.Items.Where(s => s is Eagle.circle))
                    {
                        if (circle == null) continue;
                        var x = Convert.ToDouble(circle.x);
                        var y = Convert.ToDouble(circle.y);
                        var r = Convert.ToDouble(circle.radius);
                        if ((x - r) < minX) minX = x - r;
                        if ((x + r) > maxX) maxX = x + r;
                        if ((y - r) < minY) minY = y - r;
                        if ((y + r) > maxY) maxY = y + r;
                    }
                    foreach (Eagle.smd smd in spkg.Items.Where(s => s is Eagle.smd))
                    {
                        if (smd == null) continue;
                        // SKN: after intense research on eagle, it seems that the way SMD pads are placed is as follows
                        // dx - dy tells the length of the pad, while the x is the center point of the SMD pad

                        var x = Convert.ToDouble(smd.x);
                        var y = Convert.ToDouble(smd.y);
                        var ddx = Convert.ToDouble(smd.dx);
                        var ddy = Convert.ToDouble(smd.dy);
                        var dx = ddx;  // should be /2??
                        var dy = ddy;
                        if (smd.rot.Equals("R90") || smd.rot.Equals("R270"))
                        {       // flip dx and dy if there is rotation
                            dx = ddy;
                            dy = ddx;
                        }
                        var x1 = x - dx / 2.0;
                        var x2 = x + dx / 2.0;
                        var y1 = y - dy / 2.0;
                        var y2 = y + dy / 2.0;
                        if (x1 < minX) minX = x1;
                        if (x2 > maxX) maxX = x2;
                        if (y1 < minY) minY = y1;
                        if (y2 > maxY) maxY = y2;
                    }
                    pkg.width = maxX - minX;
                    pkg.height = maxY - minY;
                    pkg.originX = Math.Floor(10.0 * (maxX + minX) / 2.0) / 10.0;
                    pkg.originY = Math.Floor(10.0 * (maxY + minY) / 2.0) / 10.0;

                    #endregion

                    // emit component ID for locating components in CAD assembly
                    if (CodeGenerator.partComponentMap.ContainsKey(part))
                    {
                        var comp_obj = CodeGenerator.partComponentMap[part];
                        var comp = comp_obj.Impl as Tonka.Component;

                        // emit component ID for locating components in CAD assembly
                        pkg.ComponentID = comp.Attributes.InstanceGUID;

                        Boolean isMultiLayer = comp.Children.EDAModelCollection.
                            Any(e => e.Attributes.HasMultiLayerFootprint);
                        if (isMultiLayer)
                            pkg.multiLayer = true;

                        #region ExactConstraints
                        // exact constraints related to this part
                        var exactCons =
                            from conn in comp.SrcConnections.ApplyExactLayoutConstraintCollection
                            select conn.SrcEnds.ExactLayoutConstraint;

                        foreach (var c in exactCons)
                        {
                            var pcons = new ExactConstraint();
                            pcons.type = "exact";
                            if (!c.Attributes.X.Equals(""))
                                pcons.x = Convert.ToDouble(c.Attributes.X);
                            if (!c.Attributes.Y.Equals(""))
                                pcons.y = Convert.ToDouble(c.Attributes.Y);
                            if (!c.Attributes.Layer.Equals(""))
                                pcons.layer = Convert.ToInt32(c.Attributes.Layer);
                            if (!c.Attributes.Rotation.Equals(""))
                                pcons.rotation = Convert.ToInt32(c.Attributes.Rotation);
                            if (pkg.constraints == null)
                                pkg.constraints = new List<Constraint>();
                            pkg.constraints.Add(pcons);
                        }
                        #endregion

                        #region RangeConstraints
                        // range constraints related to this part
                        var rangeCons =
                            from conn in comp.SrcConnections.ApplyRangeLayoutConstraintCollection
                            select conn.SrcEnds.RangeLayoutConstraint;
                        foreach (var c in rangeCons)
                        {
                            var pcons = new RangeConstraint();
                            pcons.type = "range";
                            if (!c.Attributes.XRange.Equals(""))
                                pcons.x = c.Attributes.XRange;
                            if (!c.Attributes.YRange.Equals(""))
                                pcons.y = c.Attributes.YRange;
                            if (!c.Attributes.LayerRange.Equals(""))
                                pcons.layer = c.Attributes.LayerRange;
                            if (pkg.constraints == null)
                                pkg.constraints = new List<Constraint>();
                            pkg.constraints.Add(pcons);
                        }
                        #endregion

                        #region PreRoutedAssemblyPart
                        // now handle if this component is part of a pre-routed sub-ckt
                        if (CodeGenerator.preRouted.ContainsKey(comp_obj.Parent))
                        {
                            var layoutParser = CodeGenerator.preRouted[comp_obj.Parent];
                            var prePkg = layoutParser.componentPackageMap[comp_obj];
                            pkg.x = prePkg.x;
                            pkg.y = prePkg.y;
                            pkg.rotation = prePkg.rotation;
                            pkg.RelComponentID = (comp_obj.Parent.Impl.Impl as GME.MGA.MgaFCO)
                                .RegistryValue["Elaborator/InstanceGUID_Chain"];
                            pkg.doNotPlace = true;
                        }
                        #endregion
                    }
                }
                pkgPartMap.Add(pkg, part);  // add to map
                partPkgMap.Add(part, pkg);
                boardLayout.packages.Add(pkg);
            }



            #region AddSignalsToBoardLayout
            boardLayout.signals = new List<Signal>();
            foreach (var net in sch_obj.sheets.sheet.FirstOrDefault().nets.net)
            {
                // dump pre-routed signals to board file
                var sig = new Signal();
                sig.name = net.name;
                sig.pins = new List<Pin>();

                Signal preRouted = null;
                string preRoutedAsmID = null; // ID of the parent pre-routed assembly
                string preRoutedAsm = null; // name the parent pre-routed assembly
                bool onlyOnePreroute = true;

                foreach (var seg in net.segment.SelectMany(s => s.Items).Where(s => s is Eagle.pinref))
                {
                    bool isPrerouted = false;

                    var pr = seg as Eagle.pinref;
                    var pin = new Pin();
                    pin.name = pr.pin;
                    pin.gate = pr.gate;
                    pin.package = pr.part.ToUpper();

                    // find package and pad
                    var part = sch_obj.parts.part.Where(p => p.name.Equals(pr.part)).FirstOrDefault();

                    var dev = (part != null) ?
                        sch_obj.libraries.library.Where(l => l.name.Equals(part.library)).
                        SelectMany(l => l.devicesets.deviceset).Where(ds => ds.name.Equals(part.deviceset)).
                        SelectMany(ds => ds.devices.device).Where(d => d.name.Equals(part.device)).FirstOrDefault()
                        : null;
                    var pad = (dev != null) ?
                        dev.connects.connect.Where(c => c.gate.Equals(pr.gate) && c.pin.Equals(pr.pin)).Select(c => c.pad).FirstOrDefault()
                        : null;
                    if (pad != null)
                        pin.pad = pad;

                    // check for preroutes - all pins in this signal should be in the prerouted net, otherwise reject it
                    if (part != null && CodeGenerator.partComponentMap.ContainsKey(part))
                    {
                        var comp_obj = CodeGenerator.partComponentMap[part];
                        if (CodeGenerator.preRouted.ContainsKey(comp_obj.Parent)) // is the parent assembly prerouted
                        {
                            Logger.WriteDebug("Net {0} in Prerouted Asm {1}", net.name, comp_obj.Parent.Name);

                            var layoutParser = CodeGenerator.preRouted[comp_obj.Parent];
                            // find the name/gate matching port in schematic domain model
                            var sch = comp_obj.Impl.Children.SchematicModelCollection.FirstOrDefault();

                            var port = (sch != null) ?
                                sch.Children.SchematicModelPortCollection.
                                Where(p => p.Attributes.EDAGate == pin.gate && p.Name == pin.name).
                                FirstOrDefault()
                                : null;

                            // find the buildPort
                            var buildPort = port != null && CyPhyBuildVisitor.Ports.ContainsKey(port.ID) ?
                                CyPhyBuildVisitor.Ports[port.ID] : null;


                            if (buildPort != null && layoutParser.portTraceMap.ContainsKey(buildPort))
                            {
                                isPrerouted = true;
                                Logger.WriteDebug("Found build Port and Associated Trace");

                                if (preRouted == null)
                                {
                                    preRouted = layoutParser.portTraceMap[buildPort];
                                    preRoutedAsmID = (comp_obj.Parent.Impl.Impl as GME.MGA.MgaFCO)
                                        .RegistryValue["Elaborator/InstanceGUID_Chain"];
                                    preRoutedAsm = comp_obj.Parent.Name;
                                }
                                else if (preRouted != layoutParser.portTraceMap[buildPort])
                                    isPrerouted = false;
                            }
                        }
                    }

                    onlyOnePreroute = onlyOnePreroute && isPrerouted;

                    // add pin to list of pins for this signal
                    sig.pins.Add(pin);
                }

                // if pre-routed then copy wires 
                if (onlyOnePreroute && preRouted != null)
                {
                    Logger.WriteInfo("Prerouted net {0}, from assembly {1}, originally as {2}", net.name, preRoutedAsm, preRouted.name);
                    sig.wires = new List<Wire>();
                    sig.vias = new List<Via>();
                    sig.RelComponentID = preRoutedAsmID;
                    foreach (var w in preRouted.wires)
                        sig.wires.Add(w);
                    foreach (var v in preRouted.vias)
                        sig.vias.Add(v);
                }

                boardLayout.signals.Add(sig);
            }
            #endregion

            #region AddRelativeConstraintsToBoardLayout
            // now process relative constraints - they require that all parts be mapped to packages already
            for (int i = 0; i < boardLayout.packages.Count; i++)
            {
                var pkg = boardLayout.packages[i];
                if (!pkgPartMap.ContainsKey(pkg))
                    continue;

                var part = pkgPartMap[pkg];
                var comp = CodeGenerator.partComponentMap.ContainsKey(part) ?
                    CodeGenerator.partComponentMap[part] : null;
                var impl = comp != null ? comp.Impl as Tonka.Component : null;
                var relCons =
                    from conn in impl.SrcConnections.ApplyRelativeLayoutConstraintCollection
                    select conn.SrcEnds.RelativeLayoutConstraint;

                foreach (var c in relCons)
                {
                    var pcons = new RelativeConstraint();
                    pcons.type = "relative-pkg";
                    if (!c.Attributes.XOffset.Equals(""))
                        pcons.x = Convert.ToDouble(c.Attributes.XOffset);
                    if (!c.Attributes.YOffset.Equals(""))
                        pcons.y = Convert.ToDouble(c.Attributes.YOffset);
                    // find origin comp
                    var origCompImpl = (from conn in c.SrcConnections.RelativeLayoutConstraintOriginCollection
                                        select conn.SrcEnds.Component).FirstOrDefault();
                    var origComp =
                        ((origCompImpl != null) && CyPhyBuildVisitor.Components.ContainsKey(origCompImpl.ID)) ?
                        CyPhyBuildVisitor.Components[origCompImpl.ID] :
                        null;
                    var origPart =
                        ((origComp != null) && CodeGenerator.componentPartMap.ContainsKey(origComp)) ?
                        CodeGenerator.componentPartMap[origComp] :
                        null;
                    var origPkg = ((origPart != null) && partPkgMap.ContainsKey(origPart)) ?
                        partPkgMap[origPart] :
                        null;
                    pcons.pkg_idx = origPkg.pkg_idx.Value;
                    if (pkg.constraints == null)
                        pkg.constraints = new List<Constraint>();
                    pkg.constraints.Add(pcons);
                    boardLayout.packages[i] = pkg;
                }

            }
            #endregion

        }
Ejemplo n.º 3
0
        static void Main(string[] args)
        {
            #region ProcessArguments
            // need schematic input file / layout json input file name / output board file name as command line args
            if (args.Length < 2)
            {
                Console.WriteLine("usage: BoardSynthesis <schema.sch> <layout.json> [-r]");
                Console.WriteLine("     Input: <schema.sch>, <layout.json>;  Output: <schema.brd>");
                Console.WriteLine("[-r] Input: <schema.sch> (implicit schema.brd), <layout.json>; Output: <layout.json>");
                return;
            }
            var schematicFile = args[0];
            var layoutFile = args[1];
            var boardFile = schematicFile.Replace(".sch", ".brd");
            var programMode = 0;   // forward
            if (args.Length == 3 && args[2].CompareTo("-r") == 0)
            {
                programMode = 1;
            }
            #endregion

            #region LoadSchematic
            // load schematic file
            Eagle.eagle schematic = null;
            try
            {
                schematic = Eagle.eagle.LoadFromFile(schematicFile);
                Console.WriteLine("Parsed Schematic File : " + schematicFile);
            }
            catch (Exception e)
            {
                Console.WriteLine("ERROR Reading Schematic XML: " + e.Message);
                System.Environment.Exit(-1);
            }
            #endregion

            #region LoadLayout
            // load layout file
            Layout boardLayout = null;
            Dictionary<string, Package> packageMap = new Dictionary<string, Package>
                (StringComparer.InvariantCultureIgnoreCase);
            Dictionary<string, Signal> signalMap = new Dictionary<string, Signal>
                (StringComparer.InvariantCultureIgnoreCase);

            try
            {
                string sjson = "{}";
                using (StreamReader reader = new StreamReader(layoutFile))
                {
                    sjson = reader.ReadToEnd();
                    boardLayout = JsonConvert.DeserializeObject<Layout>(sjson);
                    reader.Close();
                }
                foreach (var pkg in boardLayout.packages)
                {
                    packageMap[pkg.name] = pkg;
                    packageMap[pkg.ComponentID] = pkg;  // for ID search
                }
                if (boardLayout.signals == null) boardLayout.signals = new List<Signal>();
                foreach (var sig in boardLayout.signals)
                {
                    signalMap[sig.name] = sig;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("ERROR Reading Layout File: " + e.Message);
                System.Environment.Exit(-1);
            }
            #endregion

            Eagle.eagle eagle = null;

            #region LoadBoardTemplate
            // load board template file 
            // if there is a user-defined load that one, 
            // otherwise, load the one bundled as a project resource
            if (boardLayout.boardTemplate != null && boardLayout.boardTemplate != "")
            {
                try
                {
                    eagle = Eagle.eagle.LoadFromFile(boardLayout.boardTemplate);
                    Console.WriteLine("Parsed Eagle Board Template File {0}: " + eagle.version, boardLayout.boardTemplate);
                }
                catch (Exception e)
                {
                    Console.WriteLine("ERROR: Unable to load Board Template XML: " + e.Message);
                }
            }

            if (eagle == null)  // unable 
            {
                try
                {
                    var brdTempl = Properties.Resources.boardTemplate;
                    eagle = Eagle.eagle.Deserialize(brdTempl);
                    Console.WriteLine("Parsed Eagle Library schema version: " + eagle.version);
                }
                catch (Exception e)
                {
                    Console.WriteLine("ERROR: Failed parsing default board Template XML: " + e.Message);
                    System.Environment.Exit(-1);
                }
            }
            #endregion

            #region Layout2Board
            if (programMode == 0)   // forward mode: layout --> board
            {
                // Create Board File
                {
                    // Mark board boundaries
                    var plain = (eagle.drawing.Item as Eagle.board).plain;
                    AddBoundary(boardLayout, plain);

                    // Design Rules
                    if (boardLayout.designRules != null || boardLayout.designRules != "")
                        CopyDesignRules(boardLayout.designRules, (eagle.drawing.Item as Eagle.board).designrules);

                    // Copy Libraries
                    var srcLib = (schematic.drawing.Item as Eagle.schematic).libraries;
                    var dstLib = (eagle.drawing.Item as Eagle.board).libraries;
                    foreach (var lib in srcLib.library)
                    {
                        dstLib.library.Add(lib);
                    }

                    // Add Elements with Position
                    var parts = (schematic.drawing.Item as Eagle.schematic).parts;
                    var elements = (eagle.drawing.Item as Eagle.board).elements;
                    AddElements(parts, packageMap, dstLib, elements);

                    // Add Signals 
                    var nets = (schematic.drawing.Item as Eagle.schematic).sheets.sheet.Select(s => s.nets).FirstOrDefault();
                    var signals = (eagle.drawing.Item as Eagle.board).signals;
                    AddSignals(nets, parts, signalMap, packageMap, dstLib, signals);
                }

                eagle.SaveToFile(boardFile);
            }
            #endregion

            #region Board2Layout
            else if (programMode == 1)  // reverse mode: board --> layout
            {
                try
                {
                    eagle = Eagle.eagle.LoadFromFile(boardFile);
                    Console.WriteLine("Parsed Board File : " + boardFile);
                }
                catch (Exception e)
                {
                    Console.WriteLine("ERROR Reading Board XML: " + e.Message);
                    System.Environment.Exit(-1);
                }

                Dictionary<string, Eagle.element> elementMap = new Dictionary<string, Eagle.element>();

                var elements = (eagle.drawing.Item as Eagle.board).elements;
                foreach (var element in elements.element)
                {
                    if (packageMap.ContainsKey(element.name))
                    {
                        var pkg = packageMap[element.name];
                        if (element.rot.Contains("R90"))
                            pkg.rotation = 1;
                        else if (element.rot.Contains("R180"))
                            pkg.rotation = 2;
                        else if (element.rot.Contains("R270"))
                            pkg.rotation = 3;
                        if (element.rot.Contains("M"))
                            pkg.layer = 1;
                        double x = Convert.ToDouble(element.x) -
                            ((pkg.rotation == 1 || pkg.rotation == 3) ? pkg.height/2.0 : pkg.width/2.0);
                        double y = Convert.ToDouble(element.y) - 
                            ((pkg.rotation == 1 || pkg.rotation == 3) ? pkg.width/2.0 : pkg.height/2.0);
                        pkg.x = Math.Ceiling(x * 10.0) / 10.0;      // ceil to compensate for floor that we do in forward operation
                        pkg.y = Math.Ceiling(y * 10.0) / 10.0;      // ceil to compensate for floor that we do in forward operation
                    }
                    else
                    {
                        Console.WriteLine("WARNING: part {0} not found in layout file", element.name);
                    }
                    elementMap.Add(element.name, element);
                }

                var signals = (eagle.drawing.Item as Eagle.board).signals;
                foreach (var signal in signals.signal)
                {
                    Signal jsig = null;
                    bool update = true;
                    if (signalMap.ContainsKey(signal.name))
                        jsig = signalMap[signal.name];
                    else
                    {
                        jsig = new Signal();
                        jsig.name = signal.name;
                        update = false;
                    }
                    jsig.pins = new List<Pin>();
                    jsig.wires = new List<Wire>();
                    jsig.vias = new List<Via>();
                    double traceLength = 0.0;
                    Dictionary<string, Pin> pinMap = new Dictionary<string,Pin>();
                    foreach (var item in signal.Items)
                    {
                        if (item is Eagle.contactref)
                        {
                            var cref = item as Eagle.contactref;
                            var pin = new Pin();
                            var element = elementMap.ContainsKey(cref.element) ? elementMap[cref.element] : null;
                            if (element != null)
                            {
                                var lib = (schematic.drawing.Item as Eagle.schematic).libraries.library.Where(l => l.name.Equals(element.library)).FirstOrDefault();
                                var dev = (lib != null) ? lib.devicesets.deviceset.SelectMany(ds => ds.devices.device).Where(d => d.package.Equals(element.package)).FirstOrDefault() : null;
                                var connect = (dev != null) ? dev.connects.connect.Where(c => c.pad.Equals(cref.pad)).FirstOrDefault() : null;
                                pin.name = (connect != null) ? connect.pin : cref.pad;
                                pin.pad = (connect != null) ? connect.pad : cref.pad;
                                pin.gate = (connect != null) ? connect.gate : null;
                            }
                            pin.package = cref.element;
                            var pinName = string.Format("{0}.{1}", pin.package, pin.name);
                            // prevent creation of duplicate pins from the same package
                            if (!pinMap.ContainsKey(pinName))
                            {
                                jsig.pins.Add(pin);
                                pinMap[pinName] = pin;
                            }
                        }
                        else if (item is Eagle.wire)
                        {
                            var wire = item as Eagle.wire;
                            var jwire = new Wire();
                            jwire.x1 = Convert.ToDouble(wire.x1);
                            jwire.x2 = Convert.ToDouble(wire.x2);
                            jwire.y1 = Convert.ToDouble(wire.y1);
                            jwire.y2 = Convert.ToDouble(wire.y2);
                            jwire.width = Convert.ToDouble(wire.width);
                            jwire.layer = Convert.ToInt32(wire.layer);
                            jsig.wires.Add(jwire);
                            double w = jwire.x2 - jwire.x1;
                            double h = jwire.y2 - jwire.y1;
                            double l = Math.Sqrt(w * w + h * h);
                            traceLength += l;
                        }
                        else if (item is Eagle.via)
                        {
                            var via = item as Eagle.via;
                            var jvia = new Via();
                            jvia.x = Convert.ToDouble(via.x);
                            jvia.y = Convert.ToDouble(via.y);
                            jvia.drill = Convert.ToDouble(via.drill);
                            string[] layerRange = via.extent.Split('-');
                            if (layerRange.Count() >= 2)
                            {
                                jvia.layerBegin = Convert.ToInt32(layerRange[0]);
                                jvia.layerEnd = Convert.ToInt32(layerRange[1]);
                            }
                            jsig.vias.Add(jvia);
                        }
                        jsig.length = traceLength;
                        jsig.bends = jsig.wires.Count + jsig.vias.Count - 1;
                    }
                    if (!update)
                        boardLayout.signals.Add(jsig);
                }
                Console.WriteLine("Writing Output to {0}", layoutFile);
                var sjson = JsonConvert.SerializeObject(boardLayout, Formatting.Indented);
                StreamWriter writer = new StreamWriter(layoutFile);
                writer.Write(sjson);
                writer.Close();
            }
            #endregion
        }