Add timestamp filter interpreter
This CL lets the gesture library use time deltas from MSC_TIMESTAMP, if
these values are provided by the touchpad firmware.
MSC_TIMESTAMP will overflow after 36 minutes, but more importantly, it
is reset to 0 after 1 second of inactivity. It should also have more
accurate time deltas than CLOCK_MONOTONIC.
This CL modifies timestamps using the more accurate time deltas from
MSC_TIMESTAMP, but reports event times to Chrome browser using
CLOCK_MONOTONIC as a base.
BUG=b:65041115
TEST=Tested manually on lux and eve, using CL:938751, CL:817979 and CL:742488.
CQ-DEPEND=CL:938751
Change-Id: I9bdcd52ca34f556106a9d6c7697d03b3df0c8f10
Reviewed-on: https://chromium-review.googlesource.com/938851
Commit-Ready: Sean O'Brien <seobrien@chromium.org>
Tested-by: Sean O'Brien <seobrien@chromium.org>
Reviewed-by: Andrew de los Reyes <adlr@chromium.org>
diff --git a/Makefile b/Makefile
index f41864b..856887a 100644
--- a/Makefile
+++ b/Makefile
@@ -37,6 +37,7 @@
$(OBJDIR)/string_util.o \
$(OBJDIR)/stuck_button_inhibitor_filter_interpreter.o \
$(OBJDIR)/t5r2_correcting_filter_interpreter.o \
+ $(OBJDIR)/timestamp_filter_interpreter.o \
$(OBJDIR)/trace_marker.o \
$(OBJDIR)/tracer.o \
$(OBJDIR)/trend_classifying_filter_interpreter.o \
@@ -72,6 +73,7 @@
$(OBJDIR)/split_correcting_filter_interpreter_unittest.o \
$(OBJDIR)/stuck_button_inhibitor_filter_interpreter_unittest.o \
$(OBJDIR)/t5r2_correcting_filter_interpreter_unittest.o \
+ $(OBJDIR)/timestamp_filter_interpreter_unittest.o \
$(OBJDIR)/trace_marker_unittest.o \
$(OBJDIR)/tracer_unittest.o \
$(OBJDIR)/unittest_util.o \
diff --git a/include/timestamp_filter_interpreter.h b/include/timestamp_filter_interpreter.h
new file mode 100644
index 0000000..d4fbf25
--- /dev/null
+++ b/include/timestamp_filter_interpreter.h
@@ -0,0 +1,50 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gestures/include/filter_interpreter.h"
+#include "gestures/include/gestures.h"
+#include "gestures/include/tracer.h"
+
+#ifndef GESTURES_TIMESTAMP_FILTER_INTERPRETER_H_
+#define GESTURES_TIMESTAMP_FILTER_INTERPRETER_H_
+
+// This class fixes up the timestamp of the hardware state.
+// Before this filter is applied, there are two possibilities:
+// 1) hwstate->timestamp == CLOCK_MONOTONIC &&
+// hwstate->msc_timestamp == 0.0
+// - No changes are needed in this case
+// 2) hwstate->timestamp == CLOCK_MONOTONIC &&
+// hwstate->msc_timestamp == MSC_TIMESTAMP
+// - MSC_TIMESTAMP will be more accurate than CLOCK_MONOTONIC, so we want
+// to use it for time deltas in the gesture library. However,
+// MSC_TIMESTAMP will reset to 0.0 if there are no touch events for at
+// least 1 second. So whenever MSC_TIMESTAMP resets, we record the
+// offset between CLOCK_MONOTONIC and MSC_TIMESTAMP and add this offset
+// to subsequent events.
+// After this filter is applied:
+// - hwstate->timestamp uses CLOCK_MONOTONIC as the time base, possibly with
+// fine tuning provided by MSC_TIMESTAMP.
+// - hwstate->msc_timestamp should not be used.
+
+namespace gestures {
+
+class TimestampFilterInterpreter : public FilterInterpreter {
+ public:
+ // Takes ownership of |next|:
+ explicit TimestampFilterInterpreter(Interpreter* next, Tracer* tracer);
+ virtual ~TimestampFilterInterpreter() {}
+
+ protected:
+ virtual void SyncInterpretImpl(HardwareState* hwstate, stime_t* timeout);
+
+ private:
+ stime_t prev_msc_timestamp_;
+
+ // Difference between msc_timestamp and timestamp as of last timestamp reset.
+ stime_t msc_timestamp_offset_;
+};
+
+} // namespace gestures
+
+#endif // GESTURES_TIMESTAMP_FILTER_INTERPRETER_H_
diff --git a/src/gestures.cc b/src/gestures.cc
index 88db25f..b126d54 100644
--- a/src/gestures.cc
+++ b/src/gestures.cc
@@ -33,6 +33,7 @@
#include "gestures/include/string_util.h"
#include "gestures/include/stuck_button_inhibitor_filter_interpreter.h"
#include "gestures/include/t5r2_correcting_filter_interpreter.h"
+#include "gestures/include/timestamp_filter_interpreter.h"
#include "gestures/include/trace_marker.h"
#include "gestures/include/tracer.h"
#include "gestures/include/trend_classifying_filter_interpreter.h"
@@ -552,6 +553,7 @@
tracer_.get());
temp = new NonLinearityFilterInterpreter(prop_reg_.get(), temp,
tracer_.get());
+ temp = new TimestampFilterInterpreter(temp, tracer_.get());
temp = loggingFilter_ = new LoggingFilterInterpreter(prop_reg_.get(), temp,
tracer_.get());
interpreter_.reset(temp);
@@ -577,6 +579,7 @@
GESTURES_DEVCLASS_TOUCHPAD);
temp = new FingerMergeFilterInterpreter(prop_reg_.get(), temp, tracer_.get());
temp = new StuckButtonInhibitorFilterInterpreter(temp, tracer_.get());
+ temp = new TimestampFilterInterpreter(temp, tracer_.get());
temp = loggingFilter_ = new LoggingFilterInterpreter(prop_reg_.get(), temp,
tracer_.get());
interpreter_.reset(temp);
diff --git a/src/timestamp_filter_interpreter.cc b/src/timestamp_filter_interpreter.cc
new file mode 100644
index 0000000..046f9da
--- /dev/null
+++ b/src/timestamp_filter_interpreter.cc
@@ -0,0 +1,35 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gestures/include/timestamp_filter_interpreter.h"
+
+#include "gestures/include/logging.h"
+#include "gestures/include/tracer.h"
+
+namespace gestures {
+
+TimestampFilterInterpreter::TimestampFilterInterpreter(
+ Interpreter* next, Tracer* tracer)
+ : FilterInterpreter(NULL, next, tracer, false),
+ prev_msc_timestamp_(-1.0),
+ msc_timestamp_offset_(-1.0) {
+ InitName();
+}
+
+void TimestampFilterInterpreter::SyncInterpretImpl(
+ HardwareState* hwstate, stime_t* timeout) {
+
+ // Check if this is the first event or there has been a jump backwards.
+ if (prev_msc_timestamp_ < 0.0 ||
+ hwstate->msc_timestamp == 0.0 ||
+ hwstate->msc_timestamp < prev_msc_timestamp_) {
+ msc_timestamp_offset_ = hwstate->timestamp - hwstate->msc_timestamp;
+ }
+ prev_msc_timestamp_ = hwstate->msc_timestamp;
+ hwstate->timestamp = hwstate->msc_timestamp + msc_timestamp_offset_;
+ hwstate->msc_timestamp = 0.0;
+ next_->SyncInterpret(hwstate, timeout);
+}
+
+} // namespace gestures
diff --git a/src/timestamp_filter_interpreter_unittest.cc b/src/timestamp_filter_interpreter_unittest.cc
new file mode 100644
index 0000000..9c02f3e
--- /dev/null
+++ b/src/timestamp_filter_interpreter_unittest.cc
@@ -0,0 +1,89 @@
+// Copyright 2017 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <gtest/gtest.h>
+
+#include "gestures/include/gestures.h"
+#include "gestures/include/timestamp_filter_interpreter.h"
+#include "gestures/include/unittest_util.h"
+
+namespace gestures {
+
+class TimestampFilterInterpreterTest : public ::testing::Test {};
+
+class TimestampFilterInterpreterTestInterpreter : public Interpreter {
+ public:
+ TimestampFilterInterpreterTestInterpreter()
+ : Interpreter(NULL, NULL, false) {}
+};
+
+TEST(TimestampFilterInterpreterTest, SimpleTest) {
+ TimestampFilterInterpreterTestInterpreter* base_interpreter =
+ new TimestampFilterInterpreterTestInterpreter;
+ TimestampFilterInterpreter interpreter(base_interpreter, NULL);
+ TestInterpreterWrapper wrapper(&interpreter);
+
+ HardwareState hs[] = {
+ { 1.000, 0, 1, 1, NULL, 0, 0, 0, 0, 0.000 },
+ { 1.010, 0, 1, 1, NULL, 0, 0, 0, 0, 0.012 },
+ { 1.020, 0, 1, 1, NULL, 0, 0, 0, 0, 0.018 },
+ { 1.030, 0, 1, 1, NULL, 0, 0, 0, 0, 0.031 }
+ };
+
+ stime_t expected_timestamps[] = { 1.000, 1.012, 1.018, 1.031 };
+
+ for (size_t i = 0; i < arraysize(hs); i++) {
+ wrapper.SyncInterpret(&hs[i], NULL);
+ EXPECT_EQ(hs[i].timestamp, expected_timestamps[i]);
+ }
+}
+
+TEST(TimestampFilterInterpreterTest, NoMscTimestampTest) {
+ TimestampFilterInterpreterTestInterpreter* base_interpreter =
+ new TimestampFilterInterpreterTestInterpreter;
+ TimestampFilterInterpreter interpreter(base_interpreter, NULL);
+ TestInterpreterWrapper wrapper(&interpreter);
+
+ HardwareState hs[] = {
+ { 1.000, 0, 1, 1, NULL, 0, 0, 0, 0, 0.000 },
+ { 1.010, 0, 1, 1, NULL, 0, 0, 0, 0, 0.000 },
+ { 1.020, 0, 1, 1, NULL, 0, 0, 0, 0, 0.000 },
+ { 1.030, 0, 1, 1, NULL, 0, 0, 0, 0, 0.000 }
+ };
+
+ for (size_t i = 0; i < arraysize(hs); i++) {
+ stime_t expected_timestamp = hs[i].timestamp;
+ wrapper.SyncInterpret(&hs[i], NULL);
+ EXPECT_EQ(hs[i].timestamp, expected_timestamp);
+ }
+}
+
+TEST(TimestampFilterInterpreterTest, MscTimestampResetTest) {
+ TimestampFilterInterpreterTestInterpreter* base_interpreter =
+ new TimestampFilterInterpreterTestInterpreter;
+ TimestampFilterInterpreter interpreter(base_interpreter, NULL);
+ TestInterpreterWrapper wrapper(&interpreter);
+
+ HardwareState hs[] = {
+ { 1.000, 0, 1, 1, NULL, 0, 0, 0, 0, 0.000 },
+ { 1.010, 0, 1, 1, NULL, 0, 0, 0, 0, 0.012 },
+ { 1.020, 0, 1, 1, NULL, 0, 0, 0, 0, 0.018 },
+ { 1.030, 0, 1, 1, NULL, 0, 0, 0, 0, 0.031 },
+ { 3.000, 0, 1, 1, NULL, 0, 0, 0, 0, 0.000 }, //msc_timestamp reset to 0
+ { 3.010, 0, 1, 1, NULL, 0, 0, 0, 0, 0.008 },
+ { 3.020, 0, 1, 1, NULL, 0, 0, 0, 0, 0.020 },
+ { 3.030, 0, 1, 1, NULL, 0, 0, 0, 0, 0.035 }
+ };
+
+ stime_t expected_timestamps[] = {
+ 1.000, 1.012, 1.018, 1.031,
+ 3.000, 3.008, 3.020, 3.035
+ };
+
+ for (size_t i = 0; i < arraysize(hs); i++) {
+ wrapper.SyncInterpret(&hs[i], NULL);
+ EXPECT_EQ(hs[i].timestamp, expected_timestamps[i]);
+ }
+}
+} // namespace gestures