001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package org.wpilib.datalog; 006 007import java.io.IOException; 008import java.nio.ByteBuffer; 009import java.util.concurrent.atomic.AtomicBoolean; 010import org.wpilib.util.runtime.RuntimeLoader; 011 012/** 013 * DataLog JNI Functions. 014 * 015 * @see "wpi/datalog/DataLog.hpp" 016 */ 017public class DataLogJNI { 018 static boolean libraryLoaded = false; 019 020 /** Sets whether JNI should be loaded in the static block. */ 021 public static class Helper { 022 private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true); 023 024 /** 025 * Returns true if the JNI should be loaded in the static block. 026 * 027 * @return True if the JNI should be loaded in the static block. 028 */ 029 public static boolean getExtractOnStaticLoad() { 030 return extractOnStaticLoad.get(); 031 } 032 033 /** 034 * Sets whether the JNI should be loaded in the static block. 035 * 036 * @param load Whether the JNI should be loaded in the static block. 037 */ 038 public static void setExtractOnStaticLoad(boolean load) { 039 extractOnStaticLoad.set(load); 040 } 041 042 /** Utility class. */ 043 private Helper() {} 044 } 045 046 static { 047 if (Helper.getExtractOnStaticLoad()) { 048 try { 049 RuntimeLoader.loadLibrary("datalogjni"); 050 } catch (Exception ex) { 051 ex.printStackTrace(); 052 System.exit(1); 053 } 054 libraryLoaded = true; 055 } 056 } 057 058 /** 059 * Force load the library. 060 * 061 * @throws IOException if the library failed to load 062 */ 063 public static synchronized void forceLoad() throws IOException { 064 if (libraryLoaded) { 065 return; 066 } 067 RuntimeLoader.loadLibrary("datalogjni"); 068 libraryLoaded = true; 069 } 070 071 /** 072 * Create a new Data Log background writer. The log will be initially created with a temporary 073 * filename. 074 * 075 * @param dir directory to store the log 076 * @param filename filename to use; if none provided, a random filename is generated of the form 077 * "wpilog_{}.wpilog" 078 * @param period time between automatic flushes to disk, in seconds; this is a time/storage 079 * tradeoff 080 * @param extraHeader extra header data 081 * @return data log background writer implementation handle 082 */ 083 static native long bgCreate(String dir, String filename, double period, String extraHeader); 084 085 /** 086 * Change log filename. 087 * 088 * @param impl data log background writer implementation handle 089 * @param filename filename 090 */ 091 static native void bgSetFilename(long impl, String filename); 092 093 /** 094 * Create a new Data Log foreground writer. 095 * 096 * @param filename filename to use 097 * @param extraHeader extra header data 098 * @return data log writer implementation handle 099 * @throws IOException if file cannot be opened 100 */ 101 static native long fgCreate(String filename, String extraHeader) throws IOException; 102 103 /** 104 * Create a new Data Log foreground writer to a memory buffer. 105 * 106 * @param extraHeader extra header data 107 * @return data log writer implementation handle 108 */ 109 static native long fgCreateMemory(String extraHeader); 110 111 /** 112 * Explicitly flushes the log data to disk. 113 * 114 * @param impl data log background writer implementation handle 115 */ 116 static native void flush(long impl); 117 118 /** 119 * Flushes the log data to a memory buffer (only valid with fgCreateMemory data logs). 120 * 121 * @param impl data log background writer implementation handle 122 * @param buf output data buffer 123 * @param pos position in write buffer to start copying from 124 * @return Number of bytes written to buffer; 0 if no more to copy 125 */ 126 static native int copyWriteBuffer(long impl, byte[] buf, int pos); 127 128 /** 129 * Pauses appending of data records to the log. While paused, no data records are saved (e.g. 130 * AppendX is a no-op). Has no effect on entry starts / finishes / metadata changes. 131 * 132 * @param impl data log background writer implementation handle 133 */ 134 static native void pause(long impl); 135 136 /** 137 * Resumes appending of data records to the log. If called after Stop(), opens a new file (with 138 * random name if SetFilename was not called after Stop()) and appends Start records and schema 139 * data values for all previously started entries and schemas. 140 * 141 * @param impl data log background writer implementation handle 142 */ 143 static native void resume(long impl); 144 145 /** 146 * Stops appending all records to the log, and closes the log file. 147 * 148 * @param impl data log background writer implementation handle 149 */ 150 static native void stop(long impl); 151 152 /** 153 * Registers a data schema. Data schemas provide information for how a certain data type string 154 * can be decoded. The type string of a data schema indicates the type of the schema itself (e.g. 155 * "protobuf" for protobuf schemas, "struct" for struct schemas, etc). In the data log, schemas 156 * are saved just like normal records, with the name being generated from the provided name: 157 * "/.schema/<name>". Duplicate calls to this function with the same name are silently 158 * ignored. 159 * 160 * @param impl data log implementation handle 161 * @param name Name (the string passed as the data type for records using this schema) 162 * @param type Type of schema (e.g. "protobuf", "struct", etc) 163 * @param schema Schema data 164 * @param timestamp Time stamp (may be 0 to indicate now) 165 */ 166 static native void addSchema(long impl, String name, String type, byte[] schema, long timestamp); 167 168 static native void addSchemaString( 169 long impl, String name, String type, String schema, long timestamp); 170 171 /** 172 * Start an entry. Duplicate names are allowed (with the same type), and result in the same index 173 * being returned (Start/Finish are reference counted). A duplicate name with a different type 174 * will result in an error message being printed to the console and 0 being returned (which will 175 * be ignored by the Append functions). 176 * 177 * @param impl data log implementation handle 178 * @param name Name 179 * @param type Data type 180 * @param metadata Initial metadata (e.g. data properties) 181 * @param timestamp Time stamp (may be 0 to indicate now) 182 * @return Entry index 183 */ 184 static native int start(long impl, String name, String type, String metadata, long timestamp); 185 186 /** 187 * Finish an entry. 188 * 189 * @param impl data log implementation handle 190 * @param entry Entry index 191 * @param timestamp Time stamp (may be 0 to indicate now) 192 */ 193 static native void finish(long impl, int entry, long timestamp); 194 195 /** 196 * Updates the metadata for an entry. 197 * 198 * @param impl data log implementation handle 199 * @param entry Entry index 200 * @param metadata New metadata for the entry 201 * @param timestamp Time stamp (may be 0 to indicate now) 202 */ 203 static native void setMetadata(long impl, int entry, String metadata, long timestamp); 204 205 /** 206 * Closes the data log implementation handle. 207 * 208 * @param impl data log implementation handle 209 */ 210 static native void close(long impl); 211 212 /** 213 * Appends a raw record to the log. 214 * 215 * @param impl data log implementation handle 216 * @param entry Entry index, as returned by WPI_DataLog_Start() 217 * @param data Byte array to record 218 * @param len Length of byte array 219 * @param timestamp Time stamp (may be 0 to indicate now) 220 */ 221 static native void appendRaw( 222 long impl, int entry, byte[] data, int start, int len, long timestamp); 223 224 /** 225 * Appends a raw record to the log. 226 * 227 * @param impl data log implementation handle 228 * @param entry Entry index, as returned by WPI_DataLog_Start() 229 * @param data ByteBuffer to record 230 * @param len Length of byte array 231 * @param timestamp Time stamp (may be 0 to indicate now) 232 */ 233 static void appendRaw(long impl, int entry, ByteBuffer data, int start, int len, long timestamp) { 234 if (data.isDirect()) { 235 if (start < 0) { 236 throw new IndexOutOfBoundsException("start must be >= 0"); 237 } 238 if (len < 0) { 239 throw new IndexOutOfBoundsException("len must be >= 0"); 240 } 241 if ((start + len) > data.capacity()) { 242 throw new IndexOutOfBoundsException("start + len must be smaller than buffer capacity"); 243 } 244 appendRawBuffer(impl, entry, data, start, len, timestamp); 245 } else if (data.hasArray()) { 246 appendRaw(impl, entry, data.array(), data.arrayOffset() + start, len, timestamp); 247 } else { 248 throw new UnsupportedOperationException("ByteBuffer must be direct or have a backing array"); 249 } 250 } 251 252 private static native void appendRawBuffer( 253 long impl, int entry, ByteBuffer data, int start, int len, long timestamp); 254 255 /** 256 * Appends a boolean record to the log. 257 * 258 * @param impl data log implementation handle 259 * @param entry Entry index, as returned by Start() 260 * @param value Boolean value to record 261 * @param timestamp Time stamp (may be 0 to indicate now) 262 */ 263 static native void appendBoolean(long impl, int entry, boolean value, long timestamp); 264 265 /** 266 * Appends an integer record to the log. 267 * 268 * @param impl data log implementation handle 269 * @param entry Entry index, as returned by Start() 270 * @param value Integer value to record 271 * @param timestamp Time stamp (may be 0 to indicate now) 272 */ 273 static native void appendInteger(long impl, int entry, long value, long timestamp); 274 275 /** 276 * Appends a float record to the log. 277 * 278 * @param impl data log implementation handle 279 * @param entry Entry index, as returned by Start() 280 * @param value Float value to record 281 * @param timestamp Time stamp (may be 0 to indicate now) 282 */ 283 static native void appendFloat(long impl, int entry, float value, long timestamp); 284 285 /** 286 * Appends a double record to the log. 287 * 288 * @param impl data log implementation handle 289 * @param entry Entry index, as returned by Start() 290 * @param value Double value to record 291 * @param timestamp Time stamp (may be 0 to indicate now) 292 */ 293 static native void appendDouble(long impl, int entry, double value, long timestamp); 294 295 /** 296 * Appends a string record to the log. 297 * 298 * @param impl data log implementation handle 299 * @param entry Entry index, as returned by Start() 300 * @param value String value to record 301 * @param timestamp Time stamp (may be 0 to indicate now) 302 */ 303 static native void appendString(long impl, int entry, String value, long timestamp); 304 305 /** 306 * Appends a boolean array record to the log. 307 * 308 * @param impl data log implementation handle 309 * @param entry Entry index, as returned by Start() 310 * @param value Boolean array to record 311 * @param timestamp Time stamp (may be 0 to indicate now) 312 */ 313 static native void appendBooleanArray(long impl, int entry, boolean[] value, long timestamp); 314 315 /** 316 * Appends an integer array record to the log. 317 * 318 * @param impl data log implementation handle 319 * @param entry Entry index, as returned by Start() 320 * @param value Integer array to record 321 * @param timestamp Time stamp (may be 0 to indicate now) 322 */ 323 static native void appendIntegerArray(long impl, int entry, long[] value, long timestamp); 324 325 /** 326 * Appends a float array record to the log. 327 * 328 * @param impl data log implementation handle 329 * @param entry Entry index, as returned by Start() 330 * @param value Float array to record 331 * @param timestamp Time stamp (may be 0 to indicate now) 332 */ 333 static native void appendFloatArray(long impl, int entry, float[] value, long timestamp); 334 335 /** 336 * Appends a double array record to the log. 337 * 338 * @param impl data log implementation handle 339 * @param entry Entry index, as returned by Start() 340 * @param value Double array to record 341 * @param timestamp Time stamp (may be 0 to indicate now) 342 */ 343 static native void appendDoubleArray(long impl, int entry, double[] value, long timestamp); 344 345 /** 346 * Appends a string array record to the log. 347 * 348 * @param impl data log implementation handle 349 * @param entry Entry index, as returned by Start() 350 * @param value String array to record 351 * @param timestamp Time stamp (may be 0 to indicate now) 352 */ 353 static native void appendStringArray(long impl, int entry, String[] value, long timestamp); 354 355 /** 356 * Create a native FileLogger. When the specified file is modified, appended data will be appended 357 * to the specified data log. 358 * 359 * @param file path to the file 360 * @param log data log implementation handle 361 * @param key log key to append data to 362 * @return The FileLogger handle. 363 */ 364 public static native long createFileLogger(String file, long log, String key); 365 366 /** 367 * Free a native FileLogger. This causes the FileLogger to stop appending data to the log. 368 * 369 * @param fileTail The FileLogger handle. 370 */ 371 public static native void freeFileLogger(long fileTail); 372 373 /** Utility class. */ 374 private DataLogJNI() {} 375}