• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(NULL, 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   if (enabled_.val_)
114     UpdateStationaryFlags(hwstate);
115   next_->SyncInterpret(hwstate, timeout);
116 }
117 
UpdateStationaryFlags(HardwareState * hwstate)118 void StationaryWiggleFilterInterpreter::UpdateStationaryFlags(
119     HardwareState* hwstate) {
120 
121   RemoveMissingIdsFromMap(&histories_, *hwstate);
122 
123   for (int i = 0; i < hwstate->finger_cnt; ++i) {
124     FingerState *fs = &hwstate->fingers[i];
125 
126     // Create a new entry if it is a new finger
127     if (!MapContainsKey(histories_, fs->tracking_id)) {
128       histories_[fs->tracking_id] = FingerEnergyHistory();
129       histories_[fs->tracking_id].PushFingerState(*fs, hwstate->timestamp);
130       continue;
131     }
132 
133     // Update the energy history and check if the finger is moving
134     FingerEnergyHistory& feh = histories_[fs->tracking_id];
135     feh.PushFingerState(*fs, hwstate->timestamp);
136     if (feh.HasEnoughSamples()) {
137       float threshold = feh.moving() ? hysteresis_.val_ : threshold_.val_;
138       if (!feh.IsFingerMoving(threshold))
139         fs->flags |= (GESTURES_FINGER_WARP_X | GESTURES_FINGER_WARP_Y);
140       else
141         fs->flags |= GESTURES_FINGER_INSTANTANEOUS_MOVING;
142     }
143   }
144 }
145 
146 }  // namespace gestures
147