<refentry id="tutorial-c" revision="17 Jan 2008">
<refmeta>
    <refentrytitle>Tutorial for C</refentrytitle>
</refmeta>

<refnamediv>
    <refname>Tutorial for C</refname>
    <refpurpose>An example use case from start to finish in C</refpurpose>
</refnamediv>

<refsect1>
    <title>Introduction</title>
    <para>
    This tutorial will walk you through the main tasks for
    exchange messages between two applications:
    </para>
    <itemizedlist>
        <listitem>Create a type definition.</listitem>
        <listitem>Initialize LCM in your application.</listitem>
        <listitem>Publish an instance of the data.</listitem>
        <listitem>Subscribe to the data.</listitem>
    </itemizedlist>
    <para>
    This guide is intended for C users, although the type definition
    is the same for all languages.  If you haven't already, you should
    read the <xref linkend="intro"/> first to understand the basic theory
    of LCM's operation.
    </para>
</refsect1>

<refsect1>
    <title>Defining a data type</title>

    <para> When exchanging messages between two applications, you may have
    many different types of data.  LCM allows you to define these types in
    much the same way you would define a struct in C.  You can have multiple
    fields, each with its own type and name.  Some of these fields may be
    structs themselves, or arrays.  Basically, any data type you can imagine
    as a C struct can be used as an LCM message type.  Because LCM supports
    multiple languages, you have to define this type in a language-neutral
    specification that looks very similar to C.</para>
    
    <para>Let's define an example type called <type>example_t</type>.  Put it
    in a file called <filename>example_t.lcm</filename>.  (In general, the
    file name should match the type name, with the "lcm" extension added).
    This file can live in your primary source code directory.  .h and .c files
    will be automatically generated using the <command>lcm-gen</command> tool.
    </para>

    <para>Here are the contents of <filename>example_t.lcm</filename>:</para>

    <programlisting>
struct example_t
{
    int64_t  timestamp;
    double   position[3];
    double   orientation[4];
    int32_t  num_ranges;
    int16_t  ranges[num_ranges];
}</programlisting>
    
    <para>
    The predefined types available for use in the struct are: 
    <type>int8_t</type>, <type>int16_t</type>, <type>int32_t</type>,
    <type>int64_t</type>, <type>byte</type>, <type>float</type>,
    <type>double</type>, <type>string</type>, <type>boolean</type>.
    These are mostly self-explanatory.  In C, <type>byte</type> corresponds
    to the C type <type>uint8_t</type>.  string corresponds to
    <type>char *</type>, and is null-terminated.  Note that unsigned
    types are not defined, since there is no equivalent in Java.
    </para>

    <para>
    In addition, you can refer to any other LCM types in the definition
    of your struct, as long as the matching .lcm file for that type exists
    in the same directory.  In this way, you can create arrays of structs
    or nested structs.
    </para>

    <para>
    To generate the .h and .c files from the type definition, run
    <command>lcm-gen -c example_t.lcm</command>.  The -c argument could
    be replaced with -j or -p to generate Java or Python, respectively.
    </para>

</refsect1>

<refsect1>
    <title>Initializing LCM</title>

    <para>
    The first task for any application that uses LCM is to
    initialize the library.  Here's an example of that (and how to clean
    up after itself as well):
    </para>

    <programlisting>
#include &lt;lcm/lcm.h&gt;

int main (int argc, char ** argv)
{
    lcm_t * lcm = lcm_create (NULL);

    if (!lcm)
        return 1;

    /* Your application goes here */

    lcm_destroy (lcm);
    return 0;
}
</programlisting>

    <para>
    The function <function><link
    linkend="lcm-create">lcm_create</link>()</function> allocates and
    initializes an instance of <structname><link
    linkend="lcm-t">lcm_t</link></structname>, which represents a
    connection to an LCM network.  The single
    argument to <function><link
    linkend="lcm-create">lcm_create</link></function> can be 
    <literal>NULL</literal> as shown above, to initialize a LCM context with
    default settings.  It can also be a string specifying a specific LCM
    <emphasis>provider</emphasis> and options for that provider.
    </para>

    <para>
    There are currently two types of LCM providers: a UDP Multicast provider
    and a file-based provider, both of which have different settings.  The
    former is the default, and transmits and receives messages via UDP
    Multicast.  The second, file-based provider, reads messages from an LCM
    log file to simulate live traffic, and is often useful for data analysis.
    </para>

    <para>
    When specified, the argument to <function><link
    linkend="lcm-create">lcm_create</link></function> should be a string of
    the form 
    "<literal>provider://network?option1=value1&amp;option2=value2&amp;...</literal>"  
    The reference manual for <function><link
    linkend="lcm-create">lcm_create</link></function> provides a list of the
    exact values that can be specified.  One usage might be to read 
    data from an LCM logfile (e.g., to post-process or analyze 
    previously collected data):

    <programlisting>
lcm_t * lcm = lcm_create ("file:///home/albert/path/to/logfile.log");
</programlisting>

    For a complete listing of the available providers, networks, and options,
    see the API reference for <function><link
    linkend="lcm-create">lcm_create</link></function>.
    </para>

</refsect1>

<refsect1>
    <title>Publishing LCM data</title>

    <para>When you create an LCM data type and generate C code with
    <command>lcm-gen</command>, that data type will then be available as
    a C struct with the same name.  For <type>example_t</type>, the C
    struct that gets generated looks like this:
    </para>

    <programlisting>
typedef struct _example_t example_t;
struct _example_t
{
    int64_t    timestamp;
    double     position[3];
    double     orientation[4];
    int32_t    num_ranges;
    int16_t    *ranges;
};
</programlisting>

    <para>Notice here that fixed-length arrays in LCM appear as fixed-length
    C arrays.  Variable length arrays appear as pointers in C.  More
    on that below.</para>
    
    <para>
    We can instantiate and then publish some sample data as follows:
    </para>

    <programlisting>
#include "example_t.h"

static void
send_message (lcm_t * lcm)
{
    example_t my_data = {
        .timestamp = 0,
        .position = { 1, 2, 3 },
        .orientation = { 1, 0, 0, 0 },
    };
    int16_t ranges[15];
    int i;
    for (i = 0; i &lt; 15; i++)
        ranges[i] = i;

    my_data.num_ranges = 15;
    my_data.ranges = ranges;

    example_t_publish (lcm, "EXAMPLE", &amp;my_data);
}
</programlisting>

    <para>Note that <varname>my_data.ranges</varname> refers to a variable
    length array defined by the <type>example_t</type> LCM type, and is
    represented by a pointer in the generated C struct.  It is up to the
    programmer to set this pointer to an array of the proper type, and set
    <varname>my_data.num_ranges</varname> to a value smaller or equal to the
    number of elements in that array.  When the data is marshalled,
    <varname>my_data.num_ranges</varname> determines how many elements will
    actually be read and transmitted from <varname>my_data.ranges</varname>.
    If <varname>my_data.num_ranges</varname> is set to 0, the value of
    <varname>my_data.ranges</varname> is ignored.</para>

    <para>The call to <function><link
    linkend="example-t-publish">example_t_publish</link>()</function>
    serializes the data into a byte stream and transmits the packet using LCM
    to any interested receivers.  The string <literal>"EXAMPLE"</literal> is
    the <emphasis>channel name</emphasis>, which is a string transmitted with
    each packet that identifies the contents to receivers.  Receivers
    subscribe to different channels using this identifier, allowing
    uninteresting data to be discarded quickly and efficiently.</para>

    <para>This full example is available in runnable form as
    <filename>examples/send_message.c</filename> in the LCM source
    distribution.</para>
</refsect1>

<refsect1>
    <title>Receiving LCM Messages</title>

    <para>As discussed above, each LCM message is transmitted with
    a <emphasis>channel name</emphasis> attached to it.  It is these channel
    names which are used to determine which LCM messages you will receive
    in a given application.  It is important for senders and receivers to
    agree on the channel names which will be used for each message type.
    It is theoretically possible to transmit messages having a different
    type using the same channel name.  However, doing so will produce
    undesirable results on the receiver because subscriptions are
    established with a single type in mind.  If a message of another type is
    received on that channel, a decode error will occur.</para>

    <para>Here is a sample program that sets up LCM and
    adds a subscription to the <literal>"EXAMPLE"</literal> channel.
    Whenever a message is received on this channel, its contents are
    printed out.  If messages on other channels are being transmitted over
    the network, this program will not see them because it only has a
    subscription to the <literal>"EXAMPLE"</literal> channel.
    A particular instance of LCM may have an unlimited number of
    subscriptions.</para>

    <programlisting>
<![CDATA[
#include <stdio.h>
#include <inttypes.h>
#include <lcm/lcm.h>
#include "example_t.h"

static void
my_handler (const lcm_recv_buf_t *rbuf, const char * channel, 
        const example_t * msg, void * user)
{
    int i;
    printf ("Received message on channel \"%s\":\n", channel);
    printf ("  timestamp   = %"PRId64"\n", msg->timestamp);
    printf ("  position    = (%f, %f, %f)\n",
            msg->position[0], msg->position[1], msg->position[2]);
    printf ("  orientaiton = (%f, %f, %f, %f)\n",
            msg->orientation[0], msg->orientation[1], msg->orientation[2],
            msg->orientation[3]);
    printf ("  ranges:");
    for (i = 0; i < msg->num_ranges; i++)
        printf (" %d", msg->ranges[i]);
    printf ("\n");
}

int
main (int argc, char ** argv)
{
    lcm_t * lcm;

    lcm = lcm_create (NULL);
    if (!lcm)
        return 1;

    example_t_subscription_t * sub =
        example_t_subscribe (lcm, "EXAMPLE", &my_handler, NULL);

    while (1)
        lcm_handle (lcm);

    example_t_unsubscribe (lcm, sub);
    lcm_destroy (lcm);
    return 0;
}
]]>
</programlisting>

    <para>A key design principal for this subscription code is that it is
    <emphasis>event driven</emphasis>.  The application supplies a callback
    with <function><link
    linkend="example-t-subscribe">example_t_subscribe</link></function> that
    is called whenever a message is available.  This happens inside a single
    thread without need for concurrency, since the callback is dispatched from
    within the <function><link
    linkend="lcm-handle">lcm_handle</link></function> function.</para>

    <para>It is important to call <function><link
    linkend="lcm-handle">lcm_handle</link></function> whenever work needs to
    be done by LCM.  If no work is needed, the function will block until there
    is.  For applications without another type of main loop, it is suitable to
    call <function><link linkend="lcm-handle">lcm_handle</link></function> in
    a loop as seen above.  However, most applications already use some type of
    main loop.  In these cases, it is best to monitor the LCM file descriptor,
    which can be obtained with <function><link
    linkend="lcm-get-fileno">lcm_get_fileno</link></function>.  Whenever this
    file descriptor becomes readable, the application should call
    <function><link linkend="lcm-handle">lcm_handle</link></function>, which
    is guaranteed to not block in such a situation.</para>

    <para>This full example is available in runnable form as
    <filename>examples/listener.c</filename> in the LCM source
    distribution.</para>
</refsect1>

<refsect1>
    <title>Conclusion</title>

    <para>You have now created an LCM type, a sender, and a receiver.
    To show it all working, you can run the <command>listener</command>
    example on the command line.  Then, each time you run
    <command>send-message</command>, you should see the listener
    print out the contents of the message.</para>

</refsect1>

</refentry>





