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}