====== 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 [[http://hedmen.org/xorn/xorn-netlist-20150903.tar.gz|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 [[http://hedmen.org/xorn/doc/api/html/xornstorage_8h.html|libxornstorage API documentation]] ([[http://hedmen.org/xorn/doc/api/html/storage.html|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 [[http://hedmen.org/xorn/doc/api/html/namespacexorn_1_1storage.html|xorn.storage]] and [[http://hedmen.org/xorn/doc/api/html/namespacexorn_1_1geda.html|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
