blob: 9fd6f6f9809cc6e318c6531369d91d6432db9bcb [file] [log] [blame]
James Kuszmaulcf324122023-01-14 14:07:17 -08001= WPILib Data Log File Format Specification, Version 1.0
2WPILib Developers <wpilib@wpi.edu>
3Revision 1.0 (0x0100), 1/2/2022
4:toc:
5:toc-placement: preamble
6:sectanchors:
7
8A simple binary logging format designed for high speed logging of timestamped data values (e.g. numeric sensor values).
9
10[[motivation]]
11== Motivation
12
13FRC robots generate a lot of real-time data of various data types (most typically numeric values, but also strings and more complex data such as camera images). While there is good support in the WPILib software ecosystem for real-time display of this data on dashboards (via NetworkTables), there is no current standard for logging of timestamped data values for offline analysis. In the absence of a standard, teams have developed various ad-hoc solutions, including CSV files.
14
15Similar to how the NetworkTables standard protocol enabled ecosystem development of multiple dashboards, it is expected that a standard format for data logging, in combination with built-in library support for easy on-robot logging of robot data, will facilitate ecosystem development of offline data analysis tools.
16
17Standard logging facilities currently available (e.g. in Java) are generally designed for string messages, not for binary data. As a binary format, this will be faster with less overhead for the typical data (e.g. numbers) coming from a robot in real time (at least dozens, if not hundreds, of data points every ~20 ms). String formatting is significantly more expensive than just copying the binary number, and is more difficult to read back into analysis tools. Latency of the actual logging to the main program is also critical in the FRC application. WPILib also needs a common logging format and implementation across both C++ and Java.
18
19[[references]]
20== References
21
22[[rfc7159,RFC7159,JSON]]
23* RFC 7159, The JavaScript Object Notation (JSON) Data Interchange Format, https://tools.ietf.org/html/rfc7159
24
25[[definitions]]
26== Definitions
27
28[[def-entry]]
29Entry:: A data channel identified by an integer ID and a string name. Entries have a specified type and may have associated metadata.
30
31[[def-entry-id]]
32Entry ID:: An unsigned 4-byte ID by which records in the log refer to an Entry, instead of using the full string key for the Entry. Entry ID 0 is reserved for control records.
33
34[[def-record]]
35Record:: Storage of a single timestamped data item in the log. A record consists of the entry ID, the data length, a 64-bit integer timestamp, and the data contents.
36
37[[def-timestamp]]
38Timestamp:: 64-bit integer microseconds. The zero time is not specified by the data format, but on an FRC robot is typically the time the robot program started.
39
40[[design]]
41== Design
42
43A data log starts with an 8-byte header, followed by 0 or more records. There is no padding between records. Each record in the file has an arbitrary length payload, is timestamped, and is associated to a particular entry (via its entry ID).
44
45Entries in the log are started using a <<control-start,Start>> control record to associate an entry ID with its name, <<data-types,type>>, and <<metadata,metadata>>. Following the Start control record, records referencing that entry ID can follow in any order (and can be mixed with records with other entry IDs). A <<control-finish,Finish>> control record may be used to indicate no further records with that entry ID will follow. Following a Finish control record, an entry ID may be reused by another Start control record. Multiple Start control records for a single entry ID without an intervening Finish control record have unspecified behavior.
46
47Entry metadata may be updated with a <<control-set-metadata,Set Metadata>> control record. This control record is only valid for a particular entry ID in between Start and Finish control records for that entry ID. The Set Metadata control record should be interpreted as completely replacing the entry's metadata contents.
48
49There is no timestamp ordering requirement for records. This is true for control records as well--a Start control record with a later timestamp may be followed by data records for that entry with earlier timestamps.
50
51Duplicate entry names should be avoided, but there is nothing in the data format itself that requires this.
52
53All values are stored in little endian order.
54
55[[header]]
56=== Header
57
58The header consists of:
59
60* 6-byte ASCII string, containing "WPILOG"
61* 2-byte (16-bit) version number
62* 4-byte (32-bit) length of extra header string
63* extra header string (arbitrary length)
64
65The most significant byte of the version indicates the major version and the least significant byte indicates the minor version. For this version of the data format, the value is thus 0x0100, indicating version 1.0.
66
67The extra header string has arbitrary contents (e.g. the contents are set by the application that wrote the data log) but it must be UTF-8 encoded.
68
69The entire header for a version 1.0 file with no extra header string will be `57 50 49 4c 4f 47 00 01 00 00 00 00`.
70
71[[record]]
72=== Records
73
74Each record consists of:
75
76* 1-byte header length bitfield
77* 1 to 4-byte (32-bit) entry ID
78* 1 to 4-byte (32-bit) payload size (in bytes)
79* 1 to 8-byte (64-bit) timestamp (in integer microseconds)
80* payload data (arbitrary length)
81
82The header length bitfield encodes the length of each header field as follows (starting from the least significant bit):
83
84* 2-bit entry ID length (00 = 1 byte, 01 = 2 bytes, 10 = 3 bytes, 11 = 4 bytes)
85* 2-bit payload size length (00 = 1 byte, to 11 = 4 bytes)
86* 3-bit timestamp length (000 = 1 byte, to 111 = 8 bytes)
87* 1-bit spare (zero)
88
89An example record for a integer entry (ID=1) value 3 at timestamp 1 second would be 14 bytes in total length:
90
91* `20` (ID length = 1 byte, payload size length = 1 byte, timestamp length = 3 bytes)
92* `01` (entry ID = 1)
93* `08` (payload size = 8 bytes)
94* `40 42 0f` (timestamp = 1,000,000 us)
95* `03 00 00 00 00 00 00 00` (value = 3)
96
97[[control-record]]
98=== Control Records
99
100Entry ID 0 is used to indicate a record is a control record. There are 3 control record types: Start, Finish, and Set metadata. The first 4 bytes of the payload data indicates the control record type.
101
102[[control-start]]
103==== Start
104
105The Start control record provides information about the specified entry ID. It must appear prior to any records using that entry ID. The format of the Start control record's payload data is as follows:
106
107* 1-byte control record type (0 for Start control records)
108* 4-byte (32-bit) entry ID of entry being started
109* 4-byte (32-bit) length of entry name string
110* entry name UTF-8 string data (arbitrary length)
111* 4-byte (32-bit) length of entry type string
112* entry <<data-types,type>> UTF-8 string data (arbitrary length)
113* 4-byte (32-bit) length of entry metadata string
114* entry <<metadata,metadata>> UTF-8 string data (arbitrary length)
115
116An example start control record for an integer entry named `test` with ID=1 is 32 bytes:
117
118* `20` (ID length = 1 byte, payload size length = 1 byte, timestamp length = 3 bytes)
119* `00` (entry ID = 0)
120* `1a` (payload size = 26 bytes)
121* `40 42 0f` (timestamp = 1,000,000 us)
122* `00` (control record type = Start (0))
123* `01 00 00 00` (entry ID 1 being started)
124* `04 00 00 00` (length of name string = 4)
125* `74 65 73 74` (entry name = `test`)
126* `05 00 00 00` (length of type string = 5)
127* `69 6e 74 66 64` (type string = `int64`)
128* `00 00 00 00` (length of metadata string = 0)
129
130[[control-finish]]
131==== Finish
132
133The Finish control record indicates the entry ID is no longer valid. The format of the Finish control record's payload data is as follows:
134
135* 1-byte control record type (1 for Finish control records)
136* 4-byte (32-bit) entry ID of entry being completed
137
138An example finish control record for ID=1 is 11 bytes:
139
140* `20` (ID length = 1 byte, payload size length = 1 byte, timestamp length = 3 bytes)
141* `00` (entry ID = 0)
142* `05` (payload size = 5 bytes)
143* `40 42 0f` (timestamp = 1,000,000 us)
144* `01` (control record type = Finish (1))
145* `01 00 00 00` (entry ID 1 being finished)
146
147[[control-set-metadata]]
148==== Set Metadata
149
150The Set metadata control record updates the <<metadata,metadata>> for an entry. The format of the record's payload data is as follows:
151
152* 1-byte control record type (2 for Set metadata control records)
153* 4-byte (32-bit) entry ID of entry whose metadata is being updated
154* 4-byte (32-bit) length of entry metadata string
155* entry metadata string data (arbitrary length)
156
157An example set metadata control record to set metadata for ID=1 is 30 bytes:
158
159* `20` (ID length = 1 byte, payload size length = 1 byte, timestamp length = 3 bytes)
160* `00` (entry ID = 0)
161* `18` (payload size = 24 bytes)
162* `40 42 0f` (timestamp = 1,000,000 us)
163* `02` (control record type = Set Metadata (2))
164* `01 00 00 00` (setting metadata for entry ID 1)
165* `0f 00 00 00` (length of metadata string = 15)
166* `7b 22 73 6f 75 72 63 65 22 3a 22 4e 54 22 7d` (metadata string = `{"source":"NT"}`)
167
168[[data-types]]
169=== Data Types
170
171Each entry's data type is an arbitrary string. The following data types are standard and should be supported by all implementations, but other data type strings are allowed and may be supported by some implementations.
172
173[cols="1,1,3", options="header"]
174|===
175|Type String|Description|Payload Data Contents
176|`raw`|raw data|the raw data
177|`boolean`|boolean|single byte (0=false, 1=true)
178|`int64`|integer|8-byte (64-bit) signed value
179|`float`|float|4-byte (32-bit) IEEE-754 value
180|`double`|double|8-byte (64-bit) IEEE-754 value
181|`string`|string|UTF-8 encoded string data
182|`boolean[]`|array of boolean|a single byte (0=false, 1=true) for each entry in the arrayfootnote:arraylength[the array length is not stored, but is instead determined by the payload length]
183|`int64[]`|array of integer|8-byte (64-bit) signed value for each entry in the arrayfootnote:arraylength[]
184|`float[]`|array of float|4-byte (32-bit) value for each entry in the arrayfootnote:arraylength[]
185|`double[]`|array of double|8-byte (64-bit) value for each entry in the arrayfootnote:arraylength[]
186|`string[]`|array of strings|Starts with a 4-byte (32-bit) array length. Each string is stored as a 4-byte (32-bit) length followed by the UTF-8 string data
187|===
188
189[[metadata]]
190=== Metadata
191
192Each entry has an associated metadata string. If not blank, the metadata should be <<JSON,JSON>>, but may be arbitrary text. Metadata is intended to convey additional information about the entry beyond what the type conveys--for example the source of the data.