This BACnet stack is service driven. It handles the services (BACnet requests
like WhoIs, I-Am, ReadProperty, etc) to/from the network layer to functions that
handle the application layer. There are a bunch of functions that facilitate
encoding and decoding to/from the network message data to/from something
meaningful in the program.

A BACnet device is supposed to support, at a minimum, ReadProperty service
(server) and a single Device Object. This even applies to a BACnet client on a
PC that is used for reading other BACnet devices.

There are a number of core files that you will need. Services such as
ReadProperty, I-Am, and Reject are consided core files. The following BACnet
services (messages) are provided by this BACnet stack files:

    * abort.c - BACnet Abort service encode/decode
    * bacerror.c - BACnet Error service encode/decode
    * reject.c - BACnet Reject service encode/decode
    * rp.c - BACnet ReadProperty service encode/decode
    * arf.c - AtomicReadFile service encode/decode
    * awf.c - AtomicWriteFile service encode/decode
    * rpm.c - ReadPropertyMultiple service encode/decode
    * iam.c - I-Am service encode/decode
    * whois.c - WhoIs service encode/decode
    * wp.c - WriteProperty service encode/decode
    * dcc.c - DeviceCommunicationControl service encode/decode
    * ihave.c - I-Have service encode/decode
    * rd.c - ReinitializedDevice service encode/decode
    * timesync.c - TimeSynchronization service encode/decode
    * whohas.c - WhoHas service encode/decode

Adding additional services is a matter of adding the encoding and decoding for
the service into/from meaningful data, and I like to add unit testing, a demo
handler and send function, as well as a demo command line example.

The BACnet stack also includes files for handling client functionality, which
requires Confirmed messages, and utilizes something called binding. Binding is a
way of acquiring a Device Object Instance's MAC address by sending a broadcast
Who-Is to that Device Object and waiting for the I-Am from that Device Object.
When the I-Am arrives, the MAC address can be stored and used to send unicast
messages to that Device Object and its member objects or properties. Here are
the files that handle BACnet binding:

    * address.c - This module is used to handle the address binding that occurs
in BACnet. A device id is bound to a MAC address. The normal method is using
Who-Is, and binding with the data from I-Am. This is needed for client
functionality.
    * tsm.c - Transaction State Machine handles resending messages if a timeout
occurs, and is needed for client functionality. The transaction state machine is
used for Confirmed messages and segmentation. For confirmed messages, it
automatically (via tsm_timer_milliseconds) handles the retries and the timeout.
It uses the InvokeID as the unique key (although officially it should be the
combination of InvokeID, DeviceID, and service). So if you tried to send a
confirmed request to a device that was taken offline, you would see the retry go
out after every apdu_timeout until apdu retries had completed. Then the
transaction would self-delete (free). The stack as it is written (and most
stacks are written this way) has a limited amount of transactions, and if you
are sending alot of confirmed data, it can be a bottleneck if they are not freed
in a timely manner.

This BACnet stack includes a number of example objects. The reason that they are
examples is because your device and its objects and their properties will
undoubtedly be unique to your product. The example objects in this BACnet stack
are the same and contiguous for each object represented - but this is not
required. This stack does not include an example of every type of BACnet object
or property - but have no fear! Adding a new object type is mostly just a matter
of adding all the data encoding/decoding for that object for each service and
property supported. When a new object is added, it must also add some API hooks
in the Device Object, since the Device Object contains an object list. The
example object files in the BACnet stack include:

    * demo/object/ai.c - analog input object demo
    * demo/object/ao.c - analog output object demo
    * demo/object/av.c - analog value object demo
    * demo/object/bacfile.c - File object demo
    * demo/object/device.c - device object demo
    * demo/object/bi.c - binary input object demo
    * demo/object/bo.c - binary output object demo
    * demo/object/bv.c - binary value object demo
    * demo/object/lsp.c - life safety point object demo
    * demo/object/lc.c - load control object demo

The BACnet stack includes a number of core files that handle the service packets
that come in from the datalink layer. The core files include:

    * apdu.c - handles dispatching the services to the proper handlers
    * bacdcode.c - primitive BACnet datatype encoding and decoding
    * bacstr.c - BACnet string encoding and decoding
    * bacint.c - BACnet integer encoding and decoding
    * bacreal.c - BACnet REAL encoding and decoding
    * npdu.c - handles dispatching of the network message to the apdu
        dispatcher. It would be where routing is handled if the
        stack supported more than one physical layer.

The DataLink Layer controls orderly access to the physical medium.
The framework is listed in the header file, and the code is nornally
located in the ports/x/ directory. The following files are used for
the datalink handling in this BACnet stack:

    * bip.c - BACnet/IP functionality - depends on bip_init.c in port/xx
    * dlmstp.h - MS/TP datalink layer (see also dlmstp.c,mstp.c,crc.c)
    * arcnet.h - ARCNET datalink layer functionality API
    * ethernet.h - BACnet Ethernet datalink layer functionality API

There are several demonstration applications in the demo directory, along with
several demonstation objects and handlers. All the demos accept command line
options and have been tested under Win32 and Linux. There is a makefile in the
respective demo directory for Linux and for Borland C++ compilers, and a master
makefile at the root level (Makefile=Linux, makefile.b32=Borland).
