Tag Entry/Exit Server Protocol Source Code

The AngleID software distribution includes:

  • Code written in C# to implement the tag entry/exit protocol and to show how to write a simple command-line client.
  • A tree view showing recipes and the tags that match them.
  • An SQL Server client that maintains a table of recipe/tag matches.

You are free to use this code to:

  • Get a better understanding of the entry/exit protocol so that you can implement it yourself in another language, or
  • Take the DLL containing the protocol implementation and use it directly in your projects as a .NET API to AngleID, or
  • Treat the client programs as a debugging tool for your recipe definitions, or as a starting point for your applications, or
  • Do anything else you like, for any purpose, as long as you accept the following standard disclaimer for our protection.

    Disclaimer

Writing a Tag Entry/Exit Server

AngleID is designed to make it a very simple job to write a tag entry/exit server. In particular, the AngleID reader takes responsibility for managing the connection, detecting connection failure, re-establishing the connection, and re-establishing the state of the remote side. The device simply has to implement a server that accepts a TCP connection on the chosen port and implement the AngleID protocol over the resulting byte stream, falling back to accept a new connection if the protocol's byte stream fails.

Tag Entry/Exit Protocol

The tag/entry exit protocol is very simple. This section describes the essential parts to help you to understand the code so that you can insert it into your environment, or translate it into another language. You can find the code in the files IByteStream.cs and TagEntryExitProtocol.cs in the code distribution.

Socket Abstraction

The protocol is defined using an abstract byte stream that provides functions for reading into a buffer and writing out of it. These are available in any kind of socket interface, though in C the buffer, offset pair would usually be replaced by a character pointer.

The usual way to implement this (and the way it has been implemented in the example code) is to use a non-blocking socket, wait on a select call to block until the socket is readable, and then fail if the socket is no longer connected or if it turns out that there are no bytes to be read (although the select call said that the socket was readable).

Message Buffering and Sizing

The entry/exit protocol is guaranteed to fit every message into a 256-byte array, so you can implement it easily without requiring a big chunk of buffer. All messages have the same format:

  • Three ASCII characters representing the length of the whole message in bytes (in decimal).
  • One ASCII character representing the message type (in decimal).
  • Optionally, five ASCII characters representing the recipe's Id 1 (in decimal).
  • Optionally, five ASCII characters representing the recipe's Id 2 (in decimal).
  • Between zero and fifteen blocks of sixteen ASCII characters, each block representing a 64bit tag id (in hex).
  • A terminating zero byte.

Message Types

There are six message types represented by the decimal numbers 0 - 5:

  • 0: a tag exit message
  • 1: a tag entry message
  • 2: a keepalive message
  • 3: a 'session start' message
  • 4: a 'session stop' message
  • 5: an 'ack' message

Types 0 - 4 are sent by the reader side, and type 5 is sent by the other side. If the protocol is extended in future releases, protocol versioning information will be dealt with by adding extra data on the end of the 'session start' and 'ack' messages (and maintaining the property that the first three bytes encode the length of the whole message); this means that the protocol is extensible but we do not have to explicitly include versioning handshakes in this release of the protocol.

Protocol Logic

In English, the protocol logic works as follows:

  1. Read a message by getting the initial three byte length section, decoding it, using it to read the rest of the message into the buffer.
  2. Decode the message type byte into decimal.
  3. If the message type is 'exit' or 'entry', decode the rest of the message:

    1. Decode the five-byte recipe Id 1.
    2. Decode the five-byte recipe Id 2.
    3. Repeatedly decode all sixteen-byte tag ids that fit in the message (up to fifteen, depending on the message length).
    4. Raise a protocol event using the appropriate handler, according to the message type.
  4. If the message type is 'keepalive', 'session start', or 'session stop', no more decoding is required so raise a protocol event using the appropriate handler, according to the message type.
  5. Send an ack message.
  6. If the 'session stop' message was received, raise an exception to the server so it can shut down.
  7. Go back to step 1.

Protocol Events

If you are not familiar with C#, the delegate keyword just defines the signature of a function, and the event keyword provides a point for the user to register a function with the specified signature to be called when the event is invoked. So in C this would be done by registering a callback.

Decoding ASCII Text

For completeness, here are the functions that we use to decode parts of the buffer into decimal numbers and tag ids.