Skip to content

OLS data file format

Jan Willem Janssen edited this page Apr 24, 2015 · 3 revisions

OLS data file format

version 1.7: April 24th, 2015

For storing captured data to files, the OLS uses the data format as used by the original sump client. The format is plain text, and rather easy to parse.

If a line starts with a semicolon (;), it will be regarded as metadata/header. These headers contain information about the actual sample data, such as sample rate, capture length, and so on. If a line does not start with a semicolon, but contains only (hexa)decimal digits, and one at-sign (@), it will be regarded as sample data. All other lines (including empty lines) are to be ignored.

Note that the current data file format is forward compatible, meaning that data files produced by older versions of the client (or even the original SUMP-client) should be interpreted correctly by newer versions of the client. It is not guaranteed that data files written by newer versions of the client are be interpreted correctly by older versions of the client.

Headers

Headers start with a semicolon and are always a single line (so, terminated with carriage-return and/or line-feed). Headers contain of a key-value pair separated by a colon (:). The format of a header is:

;<name>: <value>

In which the <name> is a predefined header name (case sensitive!), and the <value> an arbritary value for that particular header.

The following headers are understood by the current client (bold face denotes the latest changes in semantics):

  • Size: (long integer, optional) defines the absolute number of samples the file contains. If provided, it will be used to check the number of samples in the file. If absent, this check will be omitted and the total number of samples will be used as size instead;
  • Rate: (integer, mandatory) defines the sample rate, in Hertz, at which the data was taken. A sample rate of -1 indicates that there is no sample rate present and that the sample numbers should be regarded as state-numbers instead of time-based numbers;
  • Channels: (integer, mandatory) defines the number of channels in the sample data, should be between 0 (inclusive) and 32 (inclusive);
  • EnabledChannels: (long integer, optional) defines the bit mask of which channel(group)s are enabled. If omitted, all channels are enabled;
  • Compressed: (boolean, optional) only for backward compatibility, should always be set to true;
  • AbsoluteLength: (long integer, optional) defines the maximum timestamp in the capture. If omitted, the value of the last seen sample timestamp will be used instead. Can be used together with the sample rate to determine the total capture time;
  • CursorEnabled: (boolean, optional) defines whether or not cursors are to be enabled, defaults to false (not enabled) if omitted;
  • Cursor0..Cursor9: (long integer, optional) defines the time values of the individual cursors (up to ten), their values should be between 0 (zero) and AbsoluteLength. A value of -1 means the cursor value is not used. Undefined cursors may also be omitted from the output;
  • CursorA is an alias for Cursor0, and is used for backward compatibility;
  • CursorB is an alias for Cursor1, and is used for backward compatibility;
  • TriggerPosition: (long integer, optional) defines the sample number at which the (last) trigger fired. Should be between 0 (zero) and AbsoluteLength. A value of -1 indicates that no trigger position is present.

Integer values are expected to be 32-bit signed values, while long integers are expected to be 64-bit signed values. Booleans are expected as true or false string values. Note that unless otherwise noted, all values are considered zero-based, that is, starting at zero.

Channels and enabled channels

A note on the correlation of channels and enabled channels: the value of channels indicates how many channels with data are to displayed. The enabled channels denotes the mapping between a 32-bit sample value and the actual channels, starting at the least-significant bit.

Examples

Some explanatory examples on the use of channels and enabled channels:

;channels: 8
;enabledChannels: 255

Denotes that there are 8 channels and that these channels should be mapped to the first 8 bits (= 255 = 0xFF) of each sample value. Another example:

;channels: 8
;enabledChannels: 65280

In the above example, there are still 8 channels, but those channels are mapped to the second 8 bits (= 65280 = 0xFF00) of each sample value.

;channels: 3
;enabledChannels: 21

In this example, there are only 3 channels, which are to be mapped to bits 1, 3 and 5 of each sample value.

Sample data

Sample data are always a single line (similar as headers) consisting of hexadecimal digits (0-9, a-f, A-F) and an at-sign (@). The format of sample data is:

<sample value>@<sample number>

In which the <sample number> is the decimal (base10) representation of the absolute sample number. The sample number correlates to the absolute time at which the sample was taken.
The <sample value> is the hexadecimal (base16) representation of the sample value itself and comprises of the bitwise-or of the channel levels at the moment the sample was taken.

The sample value is defined as a signed integer (32-bit), ranging from 0x0 to 0xffffffff (= 232-1). Note that the sign-bit of the integer is used store sample data as well! The sample number is defined as a signed long integer (64-bit), of which the sign-bit is always zero, ranging from 0x0 to 0x7fffffffffffffff (= 263-1).

Note that, if defined in the header, the Size header must match the total count of sample data.

Examples

Some examples on how to deal with the sample data in an OLS data file. Consider the following snippet:

;channels: 8
;enabledChannels: 255
1e@1
00@2
05@3
10@4

In this example, we have four samples. Each sample represents an 8-bit value. The four samples are to be interpreted as follows:

  1. The first sample represents a value of 0x1e (0b00011110), meaning that channel 0 is low, channels 1 through 4 are high, and channels 5, 6 and 7 are low;
  2. the second sample represents a value of 0x00, meaning that all 8 channels are low;
  3. the third sample represents a value of 0x05 (0b00000101), meaning that channels 0 and 2 are high while the other channels (1, 3, 4, 5, 6 and 7) are low;
  4. the last sample represents a value of 0x10 (0b00010000), meaning that only channel 4 is high.

Now, consider the following example:

;channels: 8
;enabledChannels: 65280
1e00@1
0000@2
0500@3
1000@4

Again, each sample represents an 8-bit value, but the enabled channels (65280 = 0xff00) tells us that the sample data is stored in the bit 8 through 15. We should interpret the sample data as follows:

  1. The first sample represents a value of 0x1e00, meaning that channel 8 is low, channels 9 through 12 are high, and channels 13, 14 and 15 are low;
  2. the second sample represents a value of 0x0000, meaning that channels 8 through 15 are low;
  3. the third sample represents a value of 0x0500, meaning that channels 8 and 10 are high while the other channels (9, 11, 12, 13, 14 and 15) are low;
  4. the last sample represents a value of 0x1000, meaning that only channel 12 is high.

Triggers, absolute and relative time

As mentioned, the sample numbers correlate to the absolute time of the sample. By dividing the sample number by the sample rate (in Hertz), the absolute time value of the sample can be determined:

tabs = sample# / Sr

In which tabs represents the absolute time, sample# the sample number and Sr the sample rate in Hertz.

When a trigger position is defined, that is, a value >= 0, we can use it to convert the absolute time values to relative time values and divide the timeline in two: the time before the trigger was raised, and the time at or after the trigger was raised. To convert an absolute time value to relative time, you simply subtract the trigger position from it:

trel = tabs - ( tp / Sr ) = ( sample# - tp ) / Sr

In which trel represents the relative time, tabs the absolute time, tp the trigger position and Sr the sample rate in Hertz.