Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wpiutil] DataLog: Add last value and change detection #6674

Merged
merged 8 commits into from
Jul 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

package edu.wpi.first.util.datalog;

import java.util.Arrays;

/** Log array of boolean values. */
public class BooleanArrayLogEntry extends DataLogEntry {
/** The data type for boolean array values. */
Expand Down Expand Up @@ -71,4 +73,79 @@ public void append(boolean[] value, long timestamp) {
public void append(boolean[] value) {
m_log.appendBooleanArray(m_entry, value, 0);
}

/**
* Updates the last value and appends a record to the log if it has changed.
*
* <p>Note: the last value is local to this class instance; using update() with two instances
* pointing to the same underlying log entry name will likely result in unexpected results.
*
* @param value Value to record
* @param timestamp Time stamp (0 to indicate now)
*/
public synchronized void update(boolean[] value, long timestamp) {
if (!equalsLast(value)) {
copyToLast(value);
append(value, timestamp);
}
}

/**
* Updates the last value and appends a record to the log if it has changed.
*
* <p>Note: the last value is local to this class instance; using update() with two instances
* pointing to the same underlying log entry name will likely result in unexpected results.
*
* @param value Value to record
*/
public void update(boolean[] value) {
update(value, 0);
}

/**
* Gets whether there is a last value.
*
* <p>Note: the last value is local to this class instance and updated only with update(), not
* append().
*
* @return True if last value exists, false otherwise.
*/
public synchronized boolean hasLastValue() {
return m_lastValue != null;
}

/**
* Gets the last value.
*
* <p>Note: the last value is local to this class instance and updated only with update(), not
* append().
*
* @return Last value, or null if none.
*/
@SuppressWarnings("PMD.ReturnEmptyCollectionRatherThanNull")
public synchronized boolean[] getLastValue() {
if (m_lastValue == null) {
return null;
}
return Arrays.copyOf(m_lastValue, m_lastValueLen);
}

private boolean equalsLast(boolean[] value) {
if (m_lastValue == null || m_lastValueLen != value.length) {
return false;
}
return Arrays.equals(m_lastValue, 0, value.length, value, 0, value.length);
}

private void copyToLast(boolean[] value) {
if (m_lastValue == null || m_lastValue.length < value.length) {
m_lastValue = Arrays.copyOf(value, value.length);
} else {
System.arraycopy(value, 0, m_lastValue, 0, value.length);
}
m_lastValueLen = value.length;
}

private boolean[] m_lastValue;
private int m_lastValueLen;
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,60 @@ public void append(boolean value, long timestamp) {
public void append(boolean value) {
m_log.appendBoolean(m_entry, value, 0);
}

/**
* Updates the last value and appends a record to the log if it has changed.
*
* <p>Note: the last value is local to this class instance; using update() with two instances
* pointing to the same underlying log entry name will likely result in unexpected results.
*
* @param value Value to record
* @param timestamp Time stamp (0 to indicate now)
*/
public synchronized void update(boolean value, long timestamp) {
if (!m_hasLastValue || m_lastValue != value) {
m_lastValue = value;
m_hasLastValue = true;
append(value, timestamp);
}
}

/**
* Updates the last value and appends a record to the log if it has changed.
*
* <p>Note: the last value is local to this class instance; using update() with two instances
* pointing to the same underlying log entry name will likely result in unexpected results.
*
* @param value Value to record
*/
public void update(boolean value) {
update(value, 0);
}

/**
* Gets whether there is a last value.
*
* <p>Note: the last value is local to this class instance and updated only with update(), not
* append().
*
* @return True if last value exists, false otherwise.
*/
public synchronized boolean hasLastValue() {
return m_hasLastValue;
}

/**
* Gets the last value.
*
* <p>Note: the last value is local to this class instance and updated only with update(), not
* append().
*
* @return Last value, or false if none.
*/
public synchronized boolean getLastValue() {
return m_lastValue;
}

private boolean m_hasLastValue;
private boolean m_lastValue;
}
12 changes: 6 additions & 6 deletions wpiutil/src/main/java/edu/wpi/first/util/datalog/DataLog.java
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,12 @@ public void setMetadata(int entry, String metadata) {
setMetadata(entry, metadata, 0);
}

@Override
public void close() {
DataLogJNI.close(m_impl);
m_impl = 0;
}

/**
* Appends a raw record to the log.
*
Expand Down Expand Up @@ -318,12 +324,6 @@ public void appendRaw(int entry, ByteBuffer data, int start, int len, long times
DataLogJNI.appendRaw(m_impl, entry, data, start, len, timestamp);
}

@Override
public void close() {
DataLogJNI.close(m_impl);
m_impl = 0;
}

/**
* Appends a boolean record to the log.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,31 @@ public class DataLogJNI extends WPIUtilJNI {
*/
static native long fgCreate(String filename, String extraHeader) throws IOException;

/**
* Create a new Data Log foreground writer to a memory buffer.
*
* @param extraHeader extra header data
* @return data log writer implementation handle
*/
static native long fgCreateMemory(String extraHeader);

/**
* Explicitly flushes the log data to disk.
*
* @param impl data log background writer implementation handle
*/
static native void flush(long impl);

/**
* Flushes the log data to a memory buffer (only valid with fgCreateMemory data logs).
*
* @param impl data log background writer implementation handle
* @param buf output data buffer
* @param pos position in write buffer to start copying from
* @return Number of bytes written to buffer; 0 if no more to copy
*/
static native int copyWriteBuffer(long impl, byte[] buf, int pos);

/**
* Pauses appending of data records to the log. While paused, no data records are saved (e.g.
* AppendX is a no-op). Has no effect on entry starts / finishes / metadata changes.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package edu.wpi.first.util.datalog;

import java.io.IOException;
import java.io.OutputStream;

/** A data log writer that flushes the data log to a file when flush() is called. */
public class DataLogWriter extends DataLog {
Expand All @@ -17,6 +18,8 @@ public class DataLogWriter extends DataLog {
*/
public DataLogWriter(String filename, String extraHeader) throws IOException {
super(DataLogJNI.fgCreate(filename, extraHeader));
m_os = null;
m_buf = null;
}

/**
Expand All @@ -28,4 +31,54 @@ public DataLogWriter(String filename, String extraHeader) throws IOException {
public DataLogWriter(String filename) throws IOException {
this(filename, "");
}

/**
* Construct a new Data Log with an output stream. Prefer the filename version if possible; this
* is much slower!
*
* @param os output stream
* @param extraHeader extra header data
*/
public DataLogWriter(OutputStream os, String extraHeader) {
super(DataLogJNI.fgCreateMemory(extraHeader));
m_os = os;
m_buf = new byte[kBufferSize];
}

/**
* Construct a new Data Log with an output stream.
*
* @param os output stream
*/
public DataLogWriter(OutputStream os) {
this(os, "");
}

/** Explicitly flushes the log data to disk. */
@Override
public void flush() {
DataLogJNI.flush(m_impl);
if (m_os == null) {
return;
}
try {
int pos = 0;
for (; ; ) {
int qty = DataLogJNI.copyWriteBuffer(m_impl, m_buf, pos);
if (qty == 0) {
break;
}
pos += qty;
m_os.write(m_buf, 0, qty);
}
m_os.flush();
} catch (IOException e) {
// ignore
}
}

private static final int kBufferSize = 16 * 1024;

private final OutputStream m_os;
private final byte[] m_buf;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

package edu.wpi.first.util.datalog;

import java.util.Arrays;

/** Log array of double values. */
public class DoubleArrayLogEntry extends DataLogEntry {
/** The data type for double array values. */
Expand Down Expand Up @@ -71,4 +73,79 @@ public void append(double[] value, long timestamp) {
public void append(double[] value) {
m_log.appendDoubleArray(m_entry, value, 0);
}

/**
* Updates the last value and appends a record to the log if it has changed.
*
* <p>Note: the last value is local to this class instance; using update() with two instances
* pointing to the same underlying log entry name will likely result in unexpected results.
*
* @param value Value to record
* @param timestamp Time stamp (0 to indicate now)
*/
public synchronized void update(double[] value, long timestamp) {
if (!equalsLast(value)) {
copyToLast(value);
append(value, timestamp);
}
}

/**
* Updates the last value and appends a record to the log if it has changed.
*
* <p>Note: the last value is local to this class instance; using update() with two instances
* pointing to the same underlying log entry name will likely result in unexpected results.
*
* @param value Value to record
*/
public void update(double[] value) {
update(value, 0);
}

/**
* Gets whether there is a last value.
*
* <p>Note: the last value is local to this class instance and updated only with update(), not
* append().
*
* @return True if last value exists, false otherwise.
*/
public synchronized boolean hasLastValue() {
return m_lastValue != null;
}

/**
* Gets the last value.
*
* <p>Note: the last value is local to this class instance and updated only with update(), not
* append().
*
* @return Last value, or false if none.
*/
@SuppressWarnings("PMD.ReturnEmptyCollectionRatherThanNull")
public synchronized double[] getLastValue() {
if (m_lastValue == null) {
return null;
}
return Arrays.copyOf(m_lastValue, m_lastValueLen);
}

private boolean equalsLast(double[] value) {
if (m_lastValue == null || m_lastValueLen != value.length) {
return false;
}
return Arrays.equals(m_lastValue, 0, value.length, value, 0, value.length);
}

private void copyToLast(double[] value) {
if (m_lastValue == null || m_lastValue.length < value.length) {
m_lastValue = Arrays.copyOf(value, value.length);
} else {
System.arraycopy(value, 0, m_lastValue, 0, value.length);
}
m_lastValueLen = value.length;
}

private double[] m_lastValue;
private int m_lastValueLen;
}
Loading
Loading