# Getting started with Xorn

1. Make sure that, in addition to the usual gEDA build dependencies, a C++ compiler (preferably `g++`) and Python 2.7 (including the development headers) are installed on your system.

2. Pull the latest gEDA sources, re-run `./autogen.sh`, and configure and build the package as usual. If you prefer downloading a tarball, you can pick up the Xorn sources from here. In either case, you don't need to install the package (but you can if you prefer to).

## Xorn as a command-line utility

3a. Invoke the "`xorn`" executable with the option "`--help`" to see a list of subcommands:

      xorn/src/command/xorn --help

(or "`src/command/xorn --help`" if you downloaded the Xorn tarball, or just "`xorn --help`" if you installed Xorn to your `PATH`)

3b. Run the subcommand "`xorn netlist`" with the options "`--help`" and "`--list-backends`" to print a list of options and available backends.

      xorn/src/command/xorn netlist --help
      xorn/src/command/xorn netlist --list-backends

3c. Process a schematic with "`xorn netlist`" (using the "`PCB`" backend as an example):

      xorn/src/command/xorn netlist \
        --symbol-library-search=/usr/share/gEDA/sym \
        -g PCB some-schematic.sch

## Interacting with Xorn in a C program

4. Write a C program using libxornstorage and link it against the library:

      $ cat > example.c
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <xornstorage.h>

      int main()
      {
          xorn_revision_t rev;
          xorn_object_t net_ob;
          struct xornsch_net net_data;
          xorn_object_t *objects;
          size_t count;

          rev = xorn_new_revision(NULL);

          memset(&net_data, 0, sizeof net_data);
          net_data.pos.x = 0;
          net_data.pos.y = 200;
          net_data.size.x = 100;
          net_data.size.y = 0;
          net_data.color = 4;
          net_ob = xornsch_add_net(rev, &net_data);

          xorn_finalize_revision(rev);

          xorn_get_objects(rev, &objects, &count);
          printf("%d object(s) found\n", count);
          free(objects);

          xorn_free_revision(rev);
          return 0;
      }
      ^D
      $ gcc -I xorn/include -c example.c
      $ ./libtool --mode=link gcc -o example \
          example.o xorn/src/storage/libxornstorage.la
      $ ./example
      1 object(s)

If you are using a separate build directory, replace "`-I xorn/include`" with the path to the subdirectory "`xorn/include`" in the source directory.

For more information, see the libxornstorage API documentation (overview).

## Using Xorn as a library

5. Run the Python 2.7 interpreter with the subdirectory "`xorn/built-packages`" added to the environment variable "`PYTHONPATH`".

      $ PYTHONPATH=xorn/built-packages python2.7
      Python 2.7.9 (default, Mar  1 2015, 18:22:53)
      [GCC 4.9.2] on linux2
      Type "help", "copyright", "credits" or "license" for more information.
      >>>

Import the module "`xorn.storage`" and experiment a bit with the API. Here is how to perform the operations equivalent to the C program above:

      >>> import xorn.storage
      >>> rev = xorn.storage.Revision()
      >>> net_data = xorn.storage.Net(
              x = 0, y = 200, width = 100, height = 0, color = 4)
      >>> net_ob = rev.add_object(net_data)
      >>> rev.finalize()
      >>> rev.get_objects()
      [<xorn.storage.Object object at ...>]

Import the module "`xorn.geda.read`" and load a schematic or symbol file:

      >>> import xorn.geda.read
      >>> rev = xorn.geda.read.read(
              '/usr/share/gEDA/sym/analog/resistor-1.sym')
      >>> for ob in rev.toplevel_objects():
      ...     data = ob.data()
      ...     if isinstance(data, xorn.storage.Text):
      ...         print data.text
      ...
      device=RESISTOR
      refdes=R?
      pins=2
      class=DISCRETE

For more information, see the API documentation of xorn.storage and xorn.geda.

6. Write and execute a Python program which uses the `xorn` package:

      $ cat > print-attributes.py
      #!/usr/bin/env python2
      import sys
      import xorn.storage
      import xorn.geda.read

      rev = xorn.geda.read.read(sys.argv[1])
      for ob in rev.toplevel_objects():
          data = ob.data()
          if isinstance(data, xorn.storage.Text):
              print data.text
      ^D
      $ chmod +x print-attributes.py
      $ PYTHONPATH=xorn/built-packages ./print-attributes.py \
          /usr/share/gEDA/sym/analog/resistor-1.sym
      device=RESISTOR
      refdes=R?
      pins=2
      class=DISCRETE

## Writing custom netlist backends

7. Invoke "`xorn netlist`" on your schematic as above, but instead of specifying a netlist backend, use the option "`-i`":

      $ xorn/src/command/xorn netlist \
          --symbol-library-search=/usr/share/gEDA/sym \
          -i some-schematic.sch
      Python 2.7.9 (default, Mar  1 2015, 18:22:53)
      [GCC 4.9.2] on linux2
      Type "help", "copyright", "credits" or "license" for more information.
      (InteractiveConsole)
      >>>

This option causes "`xorn netlist`" to enter interactive mode. You are now in an interactive Python interpreter session, just like above, but have the additional global variable "`netlist`" available which contains the netlist's contents.

      >>> netlist
      <xorn.geda.netlist.netlist.Netlist instance at ...>
      >>> netlist.nets
      [<xorn.geda.netlist.net.Net instance at ...>, ...]
      >>> [net.name for net in netlist.nets]
      [..., 'GND', ...]
      >>> netlist.nets_by_name['GND']
      <xorn.geda.netlist.net.Net instance at ...>
      >>> netlist.nets_by_name['GND'].name
      'GND'
      >>> netlist.nets_by_name['GND'].connections
      [<xorn.geda.netlist.package.PackagePin instance at ...>, ...]
      >>> netlist.nets_by_name['GND'].connections[0].package
      <xorn.geda.netlist.package.Package instance at ...>
      >>> netlist.nets_by_name['GND'].connections[0].package.refdes
      'U100'
      >>> netlist.nets_by_name['GND'].connections[0].number
      '7'

      >>> netlist.packages
      [<xorn.geda.netlist.package.Package instance at ...>]
      >>> netlist.packages_by_refdes
      {..., 'U100': <xorn.geda.netlist.package.Package instance at ...>, ...}
      >>> netlist.packages_by_refdes['U100'].get_attribute('device')
      ...
      >>> netlist.packages_by_refdes['U100'].pins
      [<xorn.geda.netlist.package.PackagePin instance at ...>, ...]
      >>> netlist.packages_by_refdes['U100'].pins_by_number
      {..., '7': <xorn.geda.netlist.package.PackagePin instance at ...>, ...}
      >>> netlist.packages_by_refdes['U100'].pins_by_number['7'].net
      <xorn.geda.netlist.net.Net instance at ...>
      >>> netlist.packages_by_refdes['U100'].pins_by_number['7'].net.name
      'GND'

8. Write a Python module whose name starts with "`gnet_`" and which contains a function "`run(f, netlist)`". Use this module as a netlist backend:

      $ cat > gnet_count.py
      def run(f, netlist):
          f.write("%d packages found\n" % len(netlist.packages))
          f.write("%d nets found\n" % len(netlist.nets))
      ^D
      $ xorn/src/command/xorn netlist \
          --symbol-library-search=/usr/share/gEDA/sym \
          -L . -g count some-schematic.sch
      1 packages found
      4 nets found