mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-22 01:11:42 +00:00
[wpiutil] DataLog: Add last value and change detection (#6674)
Update() checks/updates the last value and appends only if changed. GetLastValue() gets the last value. Also add OutputStream support to Java DataLogWriter.
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "wpi/DataLog.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
@@ -618,6 +619,107 @@ void DataLog::AppendStringArray(int entry,
|
||||
}
|
||||
}
|
||||
|
||||
template <typename V1, typename V2>
|
||||
inline bool UpdateImpl(std::optional<std::vector<V1>>& lastValue,
|
||||
std::span<const V2> data) {
|
||||
if (!lastValue || !std::equal(data.begin(), data.end(), lastValue->begin(),
|
||||
lastValue->end())) {
|
||||
if (lastValue) {
|
||||
lastValue->assign(data.begin(), data.end());
|
||||
} else {
|
||||
lastValue = std::vector<V1>{data.begin(), data.end()};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename V1>
|
||||
inline bool UpdateImpl(std::optional<std::vector<V1>>& lastValue,
|
||||
std::span<const bool> data) {
|
||||
if (!lastValue || !std::equal(data.begin(), data.end(), lastValue->begin(),
|
||||
lastValue->end(), [](auto a, auto b) {
|
||||
return a == static_cast<bool>(b);
|
||||
})) {
|
||||
if (lastValue) {
|
||||
lastValue->assign(data.begin(), data.end());
|
||||
} else {
|
||||
lastValue = std::vector<V1>{data.begin(), data.end()};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RawLogEntry::Update(std::span<const uint8_t> data, int64_t timestamp) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (UpdateImpl(m_lastValue, data)) {
|
||||
Append(data, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
void BooleanArrayLogEntry::Update(std::span<const bool> arr,
|
||||
int64_t timestamp) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (UpdateImpl(m_lastValue, arr)) {
|
||||
Append(arr, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
void BooleanArrayLogEntry::Update(std::span<const int> arr, int64_t timestamp) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (UpdateImpl(m_lastValue, arr)) {
|
||||
Append(arr, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
void BooleanArrayLogEntry::Update(std::span<const uint8_t> arr,
|
||||
int64_t timestamp) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (UpdateImpl(m_lastValue, arr)) {
|
||||
Append(arr, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
void IntegerArrayLogEntry::Update(std::span<const int64_t> arr,
|
||||
int64_t timestamp) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (UpdateImpl(m_lastValue, arr)) {
|
||||
Append(arr, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
void FloatArrayLogEntry::Update(std::span<const float> arr, int64_t timestamp) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (UpdateImpl(m_lastValue, arr)) {
|
||||
Append(arr, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
void DoubleArrayLogEntry::Update(std::span<const double> arr,
|
||||
int64_t timestamp) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (UpdateImpl(m_lastValue, arr)) {
|
||||
Append(arr, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
void StringArrayLogEntry::Update(std::span<const std::string> arr,
|
||||
int64_t timestamp) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (UpdateImpl(m_lastValue, arr)) {
|
||||
Append(arr, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
void StringArrayLogEntry::Update(std::span<const std::string_view> arr,
|
||||
int64_t timestamp) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (UpdateImpl(m_lastValue, arr)) {
|
||||
Append(arr, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
void WPI_DataLog_Release(struct WPI_DataLog* datalog) {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
@@ -18,6 +19,18 @@
|
||||
using namespace wpi::java;
|
||||
using namespace wpi::log;
|
||||
|
||||
namespace {
|
||||
class buf_ostream : public wpi::raw_uvector_ostream {
|
||||
private:
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
public:
|
||||
buf_ostream() : raw_uvector_ostream{data} {}
|
||||
|
||||
void clear() { data.clear(); }
|
||||
};
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
/*
|
||||
@@ -96,6 +109,24 @@ Java_edu_wpi_first_util_datalog_DataLogJNI_fgCreate
|
||||
return reinterpret_cast<jlong>(writer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_util_datalog_DataLogJNI
|
||||
* Method: fgCreateMemory
|
||||
* Signature: (Ljava/lang/String;)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_edu_wpi_first_util_datalog_DataLogJNI_fgCreateMemory
|
||||
(JNIEnv* env, jclass, jstring extraHeader)
|
||||
{
|
||||
if (!extraHeader) {
|
||||
wpi::ThrowNullPointerException(env, "extraHeader is null");
|
||||
return 0;
|
||||
}
|
||||
auto writer = new DataLogWriter{std::make_unique<buf_ostream>(),
|
||||
JStringRef{env, extraHeader}};
|
||||
return reinterpret_cast<jlong>(writer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_util_datalog_DataLogJNI
|
||||
* Method: flush
|
||||
@@ -109,7 +140,34 @@ Java_edu_wpi_first_util_datalog_DataLogJNI_flush
|
||||
wpi::ThrowNullPointerException(env, "impl is null");
|
||||
return;
|
||||
}
|
||||
reinterpret_cast<DataLogBackgroundWriter*>(impl)->Flush();
|
||||
reinterpret_cast<DataLog*>(impl)->Flush();
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_util_datalog_DataLogJNI
|
||||
* Method: copyWriteBuffer
|
||||
* Signature: (J[BI)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_util_datalog_DataLogJNI_copyWriteBuffer
|
||||
(JNIEnv* env, jclass, jlong impl, jbyteArray buf, jint start)
|
||||
{
|
||||
if (impl == 0) {
|
||||
wpi::ThrowNullPointerException(env, "impl is null");
|
||||
return 0;
|
||||
}
|
||||
auto writer = reinterpret_cast<DataLogWriter*>(impl);
|
||||
writer->Flush();
|
||||
auto& stream = static_cast<buf_ostream&>(writer->GetStream());
|
||||
JSpan<jbyte> jbuf{env, buf};
|
||||
auto arr = stream.array();
|
||||
if (start < 0 || static_cast<size_t>(start) >= arr.size()) {
|
||||
stream.clear();
|
||||
return 0;
|
||||
}
|
||||
size_t qty = (std::min)(jbuf.size(), arr.size() - start);
|
||||
std::copy(arr.begin(), arr.begin() + qty, jbuf.begin());
|
||||
return qty;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -125,7 +183,7 @@ Java_edu_wpi_first_util_datalog_DataLogJNI_pause
|
||||
wpi::ThrowNullPointerException(env, "impl is null");
|
||||
return;
|
||||
}
|
||||
reinterpret_cast<DataLogBackgroundWriter*>(impl)->Pause();
|
||||
reinterpret_cast<DataLog*>(impl)->Pause();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -141,7 +199,7 @@ Java_edu_wpi_first_util_datalog_DataLogJNI_resume
|
||||
wpi::ThrowNullPointerException(env, "impl is null");
|
||||
return;
|
||||
}
|
||||
reinterpret_cast<DataLogBackgroundWriter*>(impl)->Resume();
|
||||
reinterpret_cast<DataLog*>(impl)->Resume();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -157,7 +215,7 @@ Java_edu_wpi_first_util_datalog_DataLogJNI_stop
|
||||
wpi::ThrowNullPointerException(env, "impl is null");
|
||||
return;
|
||||
}
|
||||
reinterpret_cast<DataLogBackgroundWriter*>(impl)->Stop();
|
||||
reinterpret_cast<DataLog*>(impl)->Stop();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user