1 // Copyright 2013 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <map>
6
7 #include "include/stationary_wiggle_filter_interpreter.h"
8
9 #include "include/gestures.h"
10 #include "include/interpreter.h"
11 #include "include/tracer.h"
12 #include "include/util.h"
13
14 namespace gestures {
15
PushFingerState(const FingerState & fs,const stime_t timestamp)16 void FingerEnergyHistory::PushFingerState(const FingerState &fs,
17 const stime_t timestamp) {
18
19 // Reset the history if there is no finger state received longer than
20 // time interval 'idle_time_'.
21 if (moving_ && timestamp - prev_ > idle_time_) {
22 moving_ = false;
23 head_ = size_ = 0;
24 }
25
26 // Insert current finger position into the queue
27 head_ = (head_ + max_size_ - 1) % max_size_;
28 history_[head_].x = fs.position_x;
29 history_[head_].y = fs.position_y;
30 size_ = std::min(size_ + 1, max_size_);
31
32 // Calculate average of original signal set, the average of original signal
33 // is considered as the offset.
34 float sum_x = 0.0;
35 float sum_y = 0.0;
36 for (size_t i = 0; i < size_; ++i) {
37 const FingerEnergy& fe = Get(i);
38 sum_x += fe.x;
39 sum_y += fe.y;
40 }
41 // Obtain the mixed signal strength
42 history_[head_].mixed_x = fs.position_x - sum_x / size_;
43 history_[head_].mixed_y = fs.position_y - sum_y / size_;
44
45
46 // Calculate the average of the mixed signal set, the average of mixed signal
47 // is considered as pure signal strength.
48 float psx = 0.0;
49 float psy = 0.0;
50 for (size_t i = 0; i < size_; ++i) {
51 const FingerEnergy& fe = Get(i);
52 psx += fe.mixed_x;
53 psy += fe.mixed_y;
54 }
55 psx /= size_;
56 psy /= size_;
57 // Calculate current pure signal energy
58 history_[head_].energy_x = psx * psx;
59 history_[head_].energy_y = psy * psy;
60
61 prev_ = timestamp;
62 }
63
Get(size_t offset) const64 const FingerEnergy& FingerEnergyHistory::Get(size_t offset) const {
65 if (offset >= size_) {
66 Err("Out of bounds access!");
67 // avoid returning null pointer
68 static FingerEnergy dummy_event = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
69 return dummy_event;
70 }
71 return history_[(head_ + offset) % max_size_];
72 }
73
IsFingerMoving(float threshold)74 bool FingerEnergyHistory::IsFingerMoving(float threshold) {
75 if (size_ < max_size_)
76 return false;
77
78 float sum_energy_x = 0.0;
79 float sum_energy_y = 0.0;
80 for (size_t i = 0; i < size_; i++) {
81 const FingerEnergy& fe = history_[i];
82 sum_energy_x += fe.energy_x;
83 sum_energy_y += fe.energy_y;
84 }
85 moving_ = (sum_energy_x > threshold || sum_energy_y > threshold);
86 return moving_;
87 }
88
operator ==(const FingerEnergyHistory & that) const89 bool FingerEnergyHistory::operator==(const FingerEnergyHistory& that) const {
90 for (size_t i = 0; i < size_; i++)
91 if (history_[i] != that.history_[i])
92 return false;
93 if (size_ != that.size_ || head_ != that.head_ || moving_ != that.moving_)
94 return false;
95 return true;
96 }
97
operator !=(const FingerEnergyHistory & that) const98 bool FingerEnergyHistory::operator!=(const FingerEnergyHistory& that) const {
99 return !(*this == that);
100 }
101
StationaryWiggleFilterInterpreter(PropRegistry * prop_reg,Interpreter * next,Tracer * tracer)102 StationaryWiggleFilterInterpreter::StationaryWiggleFilterInterpreter(
103 PropRegistry* prop_reg, Interpreter* next, Tracer* tracer)
104 : FilterInterpreter(nullptr, next, tracer, false),
105 enabled_(prop_reg, "Stationary Wiggle Filter Enabled", false),
106 threshold_(prop_reg, "Finger Moving Energy", 0.012),
107 hysteresis_(prop_reg, "Finger Moving Hysteresis", 0.006) {
108 InitName();
109 }
110
SyncInterpretImpl(HardwareState & hwstate,stime_t * timeout)111 void StationaryWiggleFilterInterpreter::SyncInterpretImpl(
112 HardwareState& hwstate, stime_t* timeout) {
113 const char name[] = "StationaryWiggleFilterInterpreter::SyncInterpretImpl";
114 LogHardwareStatePre(name, hwstate);
115
116 if (enabled_.val_)
117 UpdateStationaryFlags(hwstate);
118
119 LogHardwareStatePost(name, hwstate);
120 next_->SyncInterpret(hwstate, timeout);
121 }
122
UpdateStationaryFlags(HardwareState & hwstate)123 void StationaryWiggleFilterInterpreter::UpdateStationaryFlags(
124 HardwareState& hwstate) {
125
126 RemoveMissingIdsFromMap(&histories_, hwstate);
127
128 for (int i = 0; i < hwstate.finger_cnt; ++i) {
129 FingerState *fs = &hwstate.fingers[i];
130
131 // Create a new entry if it is a new finger
132 if (!MapContainsKey(histories_, fs->tracking_id)) {
133 histories_[fs->tracking_id] = FingerEnergyHistory();
134 histories_[fs->tracking_id].PushFingerState(*fs, hwstate.timestamp);
135 continue;
136 }
137
138 // Update the energy history and check if the finger is moving
139 FingerEnergyHistory& feh = histories_[fs->tracking_id];
140 feh.PushFingerState(*fs, hwstate.timestamp);
141 if (feh.HasEnoughSamples()) {
142 float threshold = feh.moving() ? hysteresis_.val_ : threshold_.val_;
143 if (!feh.IsFingerMoving(threshold))
144 fs->flags |= (GESTURES_FINGER_WARP_X | GESTURES_FINGER_WARP_Y);
145 else
146 fs->flags |= GESTURES_FINGER_INSTANTANEOUS_MOVING;
147 }
148 }
149 }
150
151 } // namespace gestures
152