#

RBNB DataTurbine V2.0B2

# Simple API (SAPI)

# User Manual

## November 8, 2001

## Copyright Creare Inc.

## Table of Contents

> Introduction

> > Purpose
> > Source and Sink Clients
> > Channel Structures and Naming

> Common Fields and Methods

> > Constructors
> > Connections
> > Channel Lists
> > Data Types

> Source API

> > Define Channel List
> > Time Stamps
> > Specify Channel Data
> > Send Data
> > Example Source Code

> Sink API

> > Specify Channel List
> > Sink Modes
> > Get Data
> > Extract Data
> > Example Sink Code

## Introduction

### Purpose

This manual provides an overview of the RBNB Simple API (SAPI) for the V2.0 "RMap" based RBNB software. The SAPI is designed to provide maximum capability with minimum complexity. For a rigorous reference document, see the accompanying SAPI Reference Manual, generated directly from the source code with the javadoc utility.

The SAPI is implemented as a set of utility methods on top of the full RBNB Java API. Certain concessions are made to optimize portability, such as avoiding the use of overloaded methods.

Whereas this document most directly applies to the Java SAPI, the C/C++, Active X, Java Bean, and other APIs are directly layered on the Java SAPI. Thus, except for minor syntax differences, this documentation is generally applicable for these other APIs as well.

### Source and Sink Clients

An RBNB application is either a data Source or data Sink client (or both). A Source sends data to the RBNB Server. A Sink fetches data from an RBNB Server. There are separate Source and Sink classes associated with each type of client, but there are many common concepts and methods as well.

### Channel Structures and Naming

The underlying RMap data structures are hidden from the SAPI user, but their presence is felt in several ways.

For both Source and Sink clients, data channels are individually identified and "staged" using the `AddChannel` method prior to being transferred (`Fetch` or `Flush`). Behind the scenes, the SAPI incrementally builds up the corresponding RMap data structures.

Multi-tiered hierarchical channel structures can be created, requested, and referenced through a simple directory-like naming convention. A fully specified channel name consists of three main parts:

> `Server/Source/Channel`

Where:

> `Server: serverName assigned at Server startup (command line argument)`
> `Source: clientName given by Source via OpenRBNBConnection method`
> `Channel: channelName given by Source via AddChannel method`

Data Sources define channels (`AddChannel`) with the `Server` and `Source` parts implied. The channel name part may itself be multi-tiered, such as:

> `Chan0`
> `Test43/C0`
> `Test43/C1`
> `A/B/C`

Data Sinks request channels (`AddChannel`) using either relative or absolute (full-path) names. For example:

> `/Server/MySource/Test43/C2 # absolute path`
> `MySource/Test43/C2 # relative path`

Absolute paths start with a slash, and include the top level (parent) server all the way down to the channel name(s). Relative paths do not start with a slash, and begin with the Source name(s) on the local server.

For Sinks, and when requesting a list of available Server channels, wildcards can also be used, as in:

> `MySource/Test*/...`

Note: As of the current release, the default Server name is "Server".

The following Table summarizes the wildcard syntax available to the `AddChannel` (Sink-only) and `GetChannelList (Sink or Source)` methods.

Match String | Description
`"*"` | All channels at this level (one deep)
`"..."` | All channels this level and down (recursive depth). Must be last part of multi-tiered name.
more to come |
SAPI Channel Naming Wildcard Notation

Note: As of the current release, wildcards are not very well supported. The only supported use is the "..." notation used with the `GetChannelList` method.

## Common Fields and Methods

The SAPI Source and Sink Classes are self-contained, i.e. you can develop a Sink application with no reference to the methods of the Source class, and vice versa. These two classes do have some logically equivalent fields and methods, however, as described in common below.

### Constructors

#### `Source (int cacheSize, String archiveMode, int archiveSize)`

#### `Sink (int cacheSize, String archiveMode, int archiveSize)`

Both `Source` and `Sink` class constructors have a common set of arguments to set the ring buffer sizes and mode. The `cacheSize` and `archiveSize` parameters specify the sizes of the RAM and disk ring buffers (in frames), respectively. Each call to "Flush" by a Source constitutes one "frame".

The `archiveMode` parameter has one of the following values:

`"none" -` No archive is to be used (default)
`"load" -` Load the archive that matches this application `clientName`
`"create" -` Create a new archive, delete an existing one if one is present
`"append" -` Add to an existing archive, create a new one if necessary

For a `Source` client, these parameters have an obvious meaning and relate to the size and type of storage to be used for incoming source data.

By default, Sink clients have a single cache frame for storing its current data request. Note that even for Sinks, data requests are RMaps, and that multiple requests can be stored in sequence. This advanced sink request-buffer forms the foundation for future optimizations and the development of "Virtual RMaps".

### Connections

Both `Source` and `Sink` classes have methods to open and close connections between the client application and an RBNB server.

#### `void OpenRBNBConnection(String serverAddress, String clientName, String userName, String password)`

To open a connection identify the server (`serverAddress`), and identify the client (`clientName`). The `clientName` is used for display in applications such as rbnbAdmin, and provides a handle for other applications to administer and access data from this client.

Clients optionally provide a `userName` and `password` as part of the connection process. If these are defaulted to NULL, there will be no user name by which you can be granted access to restricted data.

Note: As of the current release, `userName` and `password` authorization is not implemented.

#### `void CloseRBNBConnection(boolean keepCache, boolean keepArchive)`

Upon shutting down a connection, the client application can specify whether or not to maintain data in the cache and/or archive portions of the ring buffer. Specify `keepArchive=false` to delete the disk archive associated with this connection.

### Channel Lists

To efficiently specify the channels to `Fetch or Flush`, use the `AddChannel` method to build up a local channel reference list.

#### `int AddChannel(String channelName)`

Each call to `AddChannel` builds up the list of channels to be either sent or fetched by the Source or Sink, respectively. `AddChannel` returns an index that increments with the number of channels added. For Sources, this index can be used as the reference index for use in the `PutChannel` method. For Sinks, it is possible to get less or more channels than you specify (e.g. using wildcards), so you must inquire (with `channelName` or `channelIndex`) about which channels have been `Fetched`.

#### `int ChannelIndex(String channelName)`

This utility method provides a means to get the channel `index` given the `channelName`. For Sources, the return value of `addChannel` is a reliable channel index. For Sinks, you may need to use this method to determine the reference index of `Fetched` channels.

#### `String ChannelName(int index)`

This utility method provides a means to get the `channelName` given the channel `index`. For Sinks, you can use this method to discover which channels were successfully `Fetched`.

#### `void ClearChannels()`

This method clears out the channel list built by the `AddChannel` method, and frees associated memory. Use it when you want to build a new channel list from a "clean slate".

#### `String[] GetChannelList(String matchStr)`

Both Source and Sink clients can request a list of all data channels known to the connected RBNB server. This list is returned in the full API as an RMap hierarchy, but in the SAPI it is parsed into a convenient array of `Strings`. The `matchStr` parameter restricts the returned channel list per a wildcard matching scheme.

Note: The channel list may include channels from Sources other than the local application. I.e. this list can include more channels than those locally specified via the `AddChannel` method.

Memory allocation note for C/C++ programmers:
The data buffers returned by `ChannelName` and `GetChannelList` are automatically allocated by the API, but are then "owned" and should be released by the client application. A special C/C++ utility function, `rbnbFreeChannelList(clist, nchan)` is provided for this purpose.

### Data Types

Data sent and received from an RBNB Server (`PutChannel`, `ChannelType`) can be denoted as a particular primitive data type, per the following table.

Data Type Code | Description
`TYPE_FLOAT32` | Single precision (32 bit) floating point number
`TYPE_FLOAT64` | Double precision (64 bit) floating point number
`TYPE_INT8` | 8-bit integer (byte)
`TYPE_INT16` | 16-bit integer (short int)
`TYPE_INT32` | 32-bit integer (int)
`TYPE_INT64` | 64-bit integer (long)
`TYPE_STRING` | Variable length String (character array) object
`TYPE_UNKNOWN` | Unknown or unspecified (byte array)
SAPI Data Type Codes

When specifying a primitive Data Type with a word length greater than 8 bits (1 byte), the word order (MSB,LSB) is automatically set to match that of the local native CPU upon which the Source application runs.

## Source API

A data Source client has the following tasks, which may be repeated as desired:

> - Define a channel list
> - Set TimeStamp(s)
> - Specify data for channel(s)
> - Flush data to RBNB server

### Define Channel List

Per the discussion above, a Source channel list is defined by calls to the `AddChannel` method. The `AddChannel` method associates channel names with channel indices, which in turn are used for efficient, potentially repeated references in the `PutChannel` method.

### Time Stamps

A Source sets the timestamp for subsequent data transmittal using either a manual or automatic method.

#### `void SetTime(double start, double duration)`

This method manually sets the timestamp to the specified `start` time, with an interval of `duration`. Note that a `duration` of zero is legal, and indicates an "instantaneous" point in time for the associated data.

Each manual timestamp applies to the data specified by one or more subsequent calls to `PutChannel,` until a time-setting method is called again. Thus, you can choose to timestamp data point by point, channel by channel, or frame by frame depending on how you interleave your calls to `SetTime` and `PutChannel`.

RBNB timestamps must monotonically increase. Thus, if you are manually providing timestamps, be sure to always increase the value of the `start` time with each subsequent call to `SetTime`.

#### `void AutoTimeStamp(String timeMode)`

This method sets the timestamp for subsequent data transmittals using one of the following automatic modes:

`"next" -` increment timestamp by one (1) each time
`"timeofday" -` set timestamp to system time-of-day at the point of each transmittal

Automatic time stamps are updated once upon each data `Flush`. Thus, automatic timestamps are always frame by frame. Use the `SetTime method` to timestamp data channel by channel or point by point.

### Specify Channel Data

The `PutChannel` methods specify the channel data to send at the next call to the `Flush` method. These methods reference the channels by the index returned by `AddChannel`. They provide data either as a generic byte-array or as a particular data type.

`PutChannel` may be called multiple times per channel per `Flush`, building up a many-point-per-channel data frame in a piecemeal manner as may be convenient to the application. The SAPI has sophisticated "Deep CVT" logic which automatically consolidates and organizes data into efficient RMap structures. It will always be somewhat more efficient to handle fewer, larger data buffers, however.

Memory allocation note for C/C++ programmers:
The data buffers provided by a source to the API are "owned" by the client application. I.e. the client application is responsible to allocate and free its own data buffers.

#### `void PutChannel(int chanIndex, byte[] rawData, int typeID)`

The generic `PutChannel` method sets the data to be sent as a byte-array plus an associated `typeID`. The `typeID` is one of the Data Type Codes. Use the channel index from the associated `AddChannel` method, or use the `ChannelIndex` method.

Note: Mixing different Data Types in a single channel is not supported, and may cause difficulties for Sink applications that try to extract mixed-type data.

#### `void PutChannelAsXXX(int chanIndex, XXX[] data)`

The family of `PutChannelAsXXX` methods specifies the primitive type of the supplied data array, where XXX corresponds to one of the Data Type Codes. For example, `PutChannelAsFloat32` lets you directly send a floating point data array with no need to first convert it to a byte array. (Overloaded methods are not used to enhance portability of the SAPI).

Note: `PutChannelAsString` puts a single `String` object, which is considered to be an indivisible data word.

### Send Data

Once things are set up, send the data to the server.

#### `int Flush(boolean blockingIO)`

After staging information with the time setting (e.g. `SetTime`) and `PutChannel` methods, specified data channels are sent as a consolidated RMap with the `Flush` method.

Each call to `Flush` involves round-trip network communication, therefore staging larger data frames (with larger buffers and/or multiple calls to `PutChannel`) prior to flushing them may provide a significant performance advantage. Of course, you need to also consider the associated impact on memory use and latency when deciding how often to `Flush` your data.

If the `blockingIO` parameter is `true`, it will block until the data is sent. If there is no data to send, calling `Flush(true)` will synchronize your application with the server. It returns the number of channels sent.

Note: Only channels with new data (via `PutChannel`) since the previous call to `Flush` are actually sent, not necessarily the entire Channel List.

### Example Source Code

The following code opens a connection to a local RBNB server and sends a message string to it.

`Source mySource = new Source();` `mySource.OpenRBNBConnection("localhost", "mySource");` `int index = mySource.AddChannel("myChan");` `mySource.AutoTimeStamp("timeofday");` `mySource.PutChannelAsString(index, "Hello World!");` `mySource.Flush(true);` `.`
Example Source Code Snippet

## Sink API

A data Sink client has the following tasks, repeated as desired:

> - Specify a channel list to request
> - Select a sink mode
> - Fetch data from RBNB server
> - Extract data and time from API buffer(s)

### Specify Channel List

Per the discussion above, the Sink channel list is defined by calls to the `AddChannel` method.

### Sink Modes

There are three types of sink data fetch modes:

- `Subscribe -` All new data is to be streamed without gaps
- `Monitor -` "Current" up-to-date live information is to be sent best-effort.
- `Request -` A particular time-slice of data is requested

Each sink fetch mode applies to the group of channels specified by the current Channel List. The channel list must be specified prior to setting the Sink Mode, as these methods initiate the transfer of data from the server.

#### `void Subscribe()`

This is the simplest data fetch mode. It takes no arguments and returns no value. It initiates a streaming "push" of data (from server to client) for all specified channels starting at the time of this call, and proceeding into the future. A single call to `Subscribe` can be followed by repeated calls to `Fetch`, where the next frame of data is received. Note that the frame size is determined by the source application(s).

Subscribe is the most efficient mode in that data frames are streamed from the server without waiting for acknowledgment from the sink client. If the client does not keep up, the data delivered will fall further and further behind until it falls off the beginning (oldest) data in the source ring buffer, at which point the stream aborts.

#### `void Monitor(int gapControl)`

This provides a variation on the subscribe mode. It initiates a stream of "current" data that will skip-forward as necessary to stay up to date. Full source frames are returned each Fetch. The `gapControl` argument specifies how many frames behind it can get before it will jump ahead (and miss data) in order to stay current.

When`Monitor` mode keeps up, it is much like `Subscribe`, except that there is more round-trip traffic between the client and server for `Monitor` mode (to establish the `gapControl` criterion). Unlike `Subscribe` mode, the stream will not abort if the client doesn't keep up; but data can be dropped with resulting gaps.

#### `void Request(double start, double duration, String timeRef)`

The basic `Request` mode asks for a time-slice of data beginning at `start` and running for a `duration` amount thereafter. The `timeRef` argument specifies the time-reference for `start` to be absolute, oldest, or newest.

When dealing with a `timeRef` of newest, there are some special notes:

- To get the most recent time-slice of existing data, use zero `start` and negative `duration`.
- A `duration` of zero is a special case that returns a single "current value" for each channel.

#### `void Request(double start, double duration, String timeRef, int fetchRepeat, double fetchInterval, boolean fetchByFrame)`

The optional form of `Request` includes additional `fetch` parameters. You can specify the `Request` to be automatically repeated `fetchRepeat` times, with the timestamp `start` advanced by `fetchInterval` amount each request.

Normally (with the default `fetchByFrame=false` ), a single `Request` results in a single consolidated `Fetch` response. Set `fetchByFrame=true` to cause the data returned by `Fetch` to be on a source frame-by-frame basis. This means the size of the data per `Fetch` matches the frame-size set by the respective Source. Thus, a single `Request` can require multiple calls to `Fetch`. Requesting data by frame may be more efficient or convenient, for example with indivisible video frames.

### Get Data

After building the Channel List and setting the Sink Mode (in that order), get the RBNB data using the `Fetch` method.

#### `int Fetch(boolean blockingIO)`

This method reads the data from the RBNB server for all channels in the current local Channel List (built by `AddChannel`). It returns the number of channels retrieved.

If the `blockingIO` parameter is `true`, it will block until the data is retrieved. Otherwise, it will either return a positive integer indicating data was ready and has been read, or a zero (0) indicating no data was yet available.

### Extract Data

Fetched `data` is stored in buffers that are accessed via the Extract methods.

The `ChannelData` and `ChannelTime` methods return the data associated with the given channel. Channels are denoted by `chanIndex`, which always runs from `0` to `(N-1)`, where `N` is the return value of `Fetch`. The channel name can be determined from the channel index via the channelName method. Or, knowing the name, the chanIndex can be derived from the channel name via the `ChannelIndex` method.

Memory allocation note for C/C++ programmers:
The data buffers for the fetched data are automatically allocated by the API, but are then "owned" by the client application. I.e. the client application is responsible to free the extracted data and time buffers, using the standard system `free()` function.

#### `byte[] ChannelData(int chanIndex)`

This generic extract data method gets data as a byte-array.

#### `XXX[] ChannelDataAsXXX(int chanIndex)`

The family of `ChannelAsXXX` methods specifies the primitive data type of the returned data array, where XXX corresponds to one of the Data Type Codes. For example, `ChannelDataAsFloat32` lets you retrieve a floating point data array with no need to convert it from a byte array. If the fetched data does not match the type, an exception will be thrown. You can check the type using the `ChannelType` method.

Note: `ChannelDataAsString` gets an array of `String` objects, where each `String` is considered to be an indivisible, individually time-stamped, variable-length data word.

#### `double[] ChannelTimes(chanIndex)`

This method returns an array of double precision RBNB time values for the specified channel index. There will be one time point per data point.

If necessary, the point times will be linearly interpolated from the underlying start time and duration of the corresponding data array. See `SetTime`.

#### `int ChannelType(int chanIndex)`

This method returns a Data Type Code for the primitive data type of the fetched data for a given channel. It can be used to determine which of the `ChannelDataAsXXX` methods to call.

### Example Sink Code

The following code snippet will fetch the message sent to the local RBNB Server by the Example Source Code.

`Sink mySink = new Sink();` `mySink.OpenRBNBConnection("localhost", "mySink");` `mySink.AddChannel("mySource/myChan");` `mySink.Request(0., 1., "oldest");` `mySink.Fetch(true);` `System.out.println( mySink.ChannelName(0) ": " + mySink.ChannelDataAsString(0)[0] );` `.`
Example Sink Code Snippet