1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker * Copyright (C) 2021 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker * Android BPF library - public API
4*38e8c45fSAndroid Build Coastguard Worker *
5*38e8c45fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
6*38e8c45fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
7*38e8c45fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
8*38e8c45fSAndroid Build Coastguard Worker *
9*38e8c45fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
10*38e8c45fSAndroid Build Coastguard Worker *
11*38e8c45fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
12*38e8c45fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
13*38e8c45fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*38e8c45fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
15*38e8c45fSAndroid Build Coastguard Worker * limitations under the License.
16*38e8c45fSAndroid Build Coastguard Worker */
17*38e8c45fSAndroid Build Coastguard Worker
18*38e8c45fSAndroid Build Coastguard Worker #pragma once
19*38e8c45fSAndroid Build Coastguard Worker
20*38e8c45fSAndroid Build Coastguard Worker #include <inttypes.h>
21*38e8c45fSAndroid Build Coastguard Worker #include <log/log.h>
22*38e8c45fSAndroid Build Coastguard Worker #include <time.h>
23*38e8c45fSAndroid Build Coastguard Worker #include <sstream>
24*38e8c45fSAndroid Build Coastguard Worker #include <string>
25*38e8c45fSAndroid Build Coastguard Worker
26*38e8c45fSAndroid Build Coastguard Worker /**
27*38e8c45fSAndroid Build Coastguard Worker * An object that can track changes of some value over time, taking into account an additional
28*38e8c45fSAndroid Build Coastguard Worker * dimension: the object's state. As the tracked value changes, the deltas are distributed
29*38e8c45fSAndroid Build Coastguard Worker * among the object states in accordance with the time spent in those states.
30*38e8c45fSAndroid Build Coastguard Worker */
31*38e8c45fSAndroid Build Coastguard Worker namespace android {
32*38e8c45fSAndroid Build Coastguard Worker namespace battery {
33*38e8c45fSAndroid Build Coastguard Worker
34*38e8c45fSAndroid Build Coastguard Worker #define REPORTED_INVALID_TIMESTAMP_DELTA_MS 60000
35*38e8c45fSAndroid Build Coastguard Worker
36*38e8c45fSAndroid Build Coastguard Worker typedef uint16_t state_t;
37*38e8c45fSAndroid Build Coastguard Worker
38*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
39*38e8c45fSAndroid Build Coastguard Worker class MultiStateCounter {
40*38e8c45fSAndroid Build Coastguard Worker const uint16_t stateCount;
41*38e8c45fSAndroid Build Coastguard Worker const V emptyValue;
42*38e8c45fSAndroid Build Coastguard Worker state_t currentState;
43*38e8c45fSAndroid Build Coastguard Worker time_t lastStateChangeTimestamp;
44*38e8c45fSAndroid Build Coastguard Worker T lastValue;
45*38e8c45fSAndroid Build Coastguard Worker time_t lastUpdateTimestamp;
46*38e8c45fSAndroid Build Coastguard Worker T deltaValue;
47*38e8c45fSAndroid Build Coastguard Worker bool isEnabled;
48*38e8c45fSAndroid Build Coastguard Worker
49*38e8c45fSAndroid Build Coastguard Worker struct State {
50*38e8c45fSAndroid Build Coastguard Worker time_t timeInStateSinceUpdate;
51*38e8c45fSAndroid Build Coastguard Worker T counter;
52*38e8c45fSAndroid Build Coastguard Worker };
53*38e8c45fSAndroid Build Coastguard Worker
54*38e8c45fSAndroid Build Coastguard Worker State* states;
55*38e8c45fSAndroid Build Coastguard Worker
56*38e8c45fSAndroid Build Coastguard Worker public:
57*38e8c45fSAndroid Build Coastguard Worker MultiStateCounter(uint16_t stateCount, const V& emptyValue);
58*38e8c45fSAndroid Build Coastguard Worker
59*38e8c45fSAndroid Build Coastguard Worker virtual ~MultiStateCounter();
60*38e8c45fSAndroid Build Coastguard Worker
61*38e8c45fSAndroid Build Coastguard Worker void setEnabled(bool enabled, time_t timestamp);
62*38e8c45fSAndroid Build Coastguard Worker
63*38e8c45fSAndroid Build Coastguard Worker void setState(state_t state, time_t timestamp);
64*38e8c45fSAndroid Build Coastguard Worker
65*38e8c45fSAndroid Build Coastguard Worker /**
66*38e8c45fSAndroid Build Coastguard Worker * Copies the current state and accumulated times-in-state from the source. Resets
67*38e8c45fSAndroid Build Coastguard Worker * the accumulated value.
68*38e8c45fSAndroid Build Coastguard Worker */
69*38e8c45fSAndroid Build Coastguard Worker void copyStatesFrom(const MultiStateCounter<T, V> &source);
70*38e8c45fSAndroid Build Coastguard Worker
71*38e8c45fSAndroid Build Coastguard Worker void setValue(state_t state, const V& value);
72*38e8c45fSAndroid Build Coastguard Worker
73*38e8c45fSAndroid Build Coastguard Worker /**
74*38e8c45fSAndroid Build Coastguard Worker * Updates the value by distributing the delta from the previously set value
75*38e8c45fSAndroid Build Coastguard Worker * among states according to their respective time-in-state.
76*38e8c45fSAndroid Build Coastguard Worker * Returns the delta from the previously set value.
77*38e8c45fSAndroid Build Coastguard Worker */
78*38e8c45fSAndroid Build Coastguard Worker const V& updateValue(const V& value, time_t timestamp);
79*38e8c45fSAndroid Build Coastguard Worker
80*38e8c45fSAndroid Build Coastguard Worker /**
81*38e8c45fSAndroid Build Coastguard Worker * Updates the value by distributing the specified increment among states according
82*38e8c45fSAndroid Build Coastguard Worker * to their respective time-in-state.
83*38e8c45fSAndroid Build Coastguard Worker */
84*38e8c45fSAndroid Build Coastguard Worker void incrementValue(const V& increment, time_t timestamp);
85*38e8c45fSAndroid Build Coastguard Worker
86*38e8c45fSAndroid Build Coastguard Worker /**
87*38e8c45fSAndroid Build Coastguard Worker * Adds the specified increment to the value for the current state, without affecting
88*38e8c45fSAndroid Build Coastguard Worker * the last updated value or timestamp. Ignores partial time-in-state: the entirety of
89*38e8c45fSAndroid Build Coastguard Worker * the increment is given to the current state.
90*38e8c45fSAndroid Build Coastguard Worker */
91*38e8c45fSAndroid Build Coastguard Worker void addValue(const V& increment);
92*38e8c45fSAndroid Build Coastguard Worker
93*38e8c45fSAndroid Build Coastguard Worker void reset();
94*38e8c45fSAndroid Build Coastguard Worker
95*38e8c45fSAndroid Build Coastguard Worker uint16_t getStateCount();
96*38e8c45fSAndroid Build Coastguard Worker
97*38e8c45fSAndroid Build Coastguard Worker const V& getCount(state_t state);
98*38e8c45fSAndroid Build Coastguard Worker
99*38e8c45fSAndroid Build Coastguard Worker std::string toString();
100*38e8c45fSAndroid Build Coastguard Worker
101*38e8c45fSAndroid Build Coastguard Worker private:
102*38e8c45fSAndroid Build Coastguard Worker /**
103*38e8c45fSAndroid Build Coastguard Worker * Subtracts previousValue from newValue and returns the result in outValue.
104*38e8c45fSAndroid Build Coastguard Worker * Returns true iff the combination of previousValue and newValue is valid
105*38e8c45fSAndroid Build Coastguard Worker * (newValue >= prevValue)
106*38e8c45fSAndroid Build Coastguard Worker */
107*38e8c45fSAndroid Build Coastguard Worker bool delta(const T& previousValue, const V& newValue, T* outValue) const;
108*38e8c45fSAndroid Build Coastguard Worker
109*38e8c45fSAndroid Build Coastguard Worker /**
110*38e8c45fSAndroid Build Coastguard Worker * Adds value2 to value1 and stores the result in value1. Denominator is
111*38e8c45fSAndroid Build Coastguard Worker * guaranteed to be non-zero.
112*38e8c45fSAndroid Build Coastguard Worker */
113*38e8c45fSAndroid Build Coastguard Worker void add(T* value1, const V& value2, const uint64_t numerator,
114*38e8c45fSAndroid Build Coastguard Worker const uint64_t denominator) const;
115*38e8c45fSAndroid Build Coastguard Worker };
116*38e8c45fSAndroid Build Coastguard Worker
117*38e8c45fSAndroid Build Coastguard Worker // ---------------------- MultiStateCounter Implementation -------------------------
118*38e8c45fSAndroid Build Coastguard Worker // Since MultiStateCounter is a template, the implementation must be inlined.
119*38e8c45fSAndroid Build Coastguard Worker
120*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
MultiStateCounter(uint16_t stateCount,const V & emptyValue)121*38e8c45fSAndroid Build Coastguard Worker MultiStateCounter<T, V>::MultiStateCounter(uint16_t stateCount, const V& emptyValue)
122*38e8c45fSAndroid Build Coastguard Worker : stateCount(stateCount),
123*38e8c45fSAndroid Build Coastguard Worker emptyValue(emptyValue),
124*38e8c45fSAndroid Build Coastguard Worker currentState(0),
125*38e8c45fSAndroid Build Coastguard Worker lastStateChangeTimestamp(-1),
126*38e8c45fSAndroid Build Coastguard Worker lastValue(emptyValue),
127*38e8c45fSAndroid Build Coastguard Worker lastUpdateTimestamp(-1),
128*38e8c45fSAndroid Build Coastguard Worker deltaValue(emptyValue),
129*38e8c45fSAndroid Build Coastguard Worker isEnabled(true) {
130*38e8c45fSAndroid Build Coastguard Worker states = new State[stateCount];
131*38e8c45fSAndroid Build Coastguard Worker for (int i = 0; i < stateCount; i++) {
132*38e8c45fSAndroid Build Coastguard Worker states[i].timeInStateSinceUpdate = 0;
133*38e8c45fSAndroid Build Coastguard Worker states[i].counter = emptyValue;
134*38e8c45fSAndroid Build Coastguard Worker }
135*38e8c45fSAndroid Build Coastguard Worker }
136*38e8c45fSAndroid Build Coastguard Worker
137*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
~MultiStateCounter()138*38e8c45fSAndroid Build Coastguard Worker MultiStateCounter<T, V>::~MultiStateCounter() {
139*38e8c45fSAndroid Build Coastguard Worker delete[] states;
140*38e8c45fSAndroid Build Coastguard Worker };
141*38e8c45fSAndroid Build Coastguard Worker
142*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
setEnabled(bool enabled,time_t timestamp)143*38e8c45fSAndroid Build Coastguard Worker void MultiStateCounter<T, V>::setEnabled(bool enabled, time_t timestamp) {
144*38e8c45fSAndroid Build Coastguard Worker if (enabled == isEnabled) {
145*38e8c45fSAndroid Build Coastguard Worker return;
146*38e8c45fSAndroid Build Coastguard Worker }
147*38e8c45fSAndroid Build Coastguard Worker
148*38e8c45fSAndroid Build Coastguard Worker if (isEnabled) {
149*38e8c45fSAndroid Build Coastguard Worker // Confirm the current state for the side-effect of updating the time-in-state
150*38e8c45fSAndroid Build Coastguard Worker // counter for the current state.
151*38e8c45fSAndroid Build Coastguard Worker setState(currentState, timestamp);
152*38e8c45fSAndroid Build Coastguard Worker isEnabled = false;
153*38e8c45fSAndroid Build Coastguard Worker } else {
154*38e8c45fSAndroid Build Coastguard Worker // If the counter is being enabled with an out-of-order timestamp, just push back
155*38e8c45fSAndroid Build Coastguard Worker // the timestamp to avoid having the situation where
156*38e8c45fSAndroid Build Coastguard Worker // timeInStateSinceUpdate > timeSinceUpdate
157*38e8c45fSAndroid Build Coastguard Worker if (timestamp < lastUpdateTimestamp) {
158*38e8c45fSAndroid Build Coastguard Worker timestamp = lastUpdateTimestamp;
159*38e8c45fSAndroid Build Coastguard Worker }
160*38e8c45fSAndroid Build Coastguard Worker
161*38e8c45fSAndroid Build Coastguard Worker if (lastStateChangeTimestamp >= 0) {
162*38e8c45fSAndroid Build Coastguard Worker lastStateChangeTimestamp = timestamp;
163*38e8c45fSAndroid Build Coastguard Worker }
164*38e8c45fSAndroid Build Coastguard Worker isEnabled = true;
165*38e8c45fSAndroid Build Coastguard Worker }
166*38e8c45fSAndroid Build Coastguard Worker }
167*38e8c45fSAndroid Build Coastguard Worker
168*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
setState(state_t state,time_t timestamp)169*38e8c45fSAndroid Build Coastguard Worker void MultiStateCounter<T, V>::setState(state_t state, time_t timestamp) {
170*38e8c45fSAndroid Build Coastguard Worker if (isEnabled && lastStateChangeTimestamp >= 0 && lastUpdateTimestamp >= 0) {
171*38e8c45fSAndroid Build Coastguard Worker // If the update arrived out-of-order, just push back the timestamp to
172*38e8c45fSAndroid Build Coastguard Worker // avoid having the situation where timeInStateSinceUpdate > timeSinceUpdate
173*38e8c45fSAndroid Build Coastguard Worker if (timestamp < lastUpdateTimestamp) {
174*38e8c45fSAndroid Build Coastguard Worker timestamp = lastUpdateTimestamp;
175*38e8c45fSAndroid Build Coastguard Worker }
176*38e8c45fSAndroid Build Coastguard Worker
177*38e8c45fSAndroid Build Coastguard Worker if (timestamp >= lastStateChangeTimestamp) {
178*38e8c45fSAndroid Build Coastguard Worker states[currentState].timeInStateSinceUpdate += timestamp - lastStateChangeTimestamp;
179*38e8c45fSAndroid Build Coastguard Worker } else {
180*38e8c45fSAndroid Build Coastguard Worker if (timestamp < lastStateChangeTimestamp - REPORTED_INVALID_TIMESTAMP_DELTA_MS) {
181*38e8c45fSAndroid Build Coastguard Worker ALOGE("setState is called with an earlier timestamp: %lu, "
182*38e8c45fSAndroid Build Coastguard Worker "previous timestamp: %lu\n",
183*38e8c45fSAndroid Build Coastguard Worker (unsigned long)timestamp, (unsigned long)lastStateChangeTimestamp);
184*38e8c45fSAndroid Build Coastguard Worker }
185*38e8c45fSAndroid Build Coastguard Worker
186*38e8c45fSAndroid Build Coastguard Worker // The accumulated durations have become unreliable. For example, if the timestamp
187*38e8c45fSAndroid Build Coastguard Worker // sequence was 1000, 2000, 1000, 3000, if we accumulated the positive deltas,
188*38e8c45fSAndroid Build Coastguard Worker // we would get 4000, which is greater than (last - first). This could lead to
189*38e8c45fSAndroid Build Coastguard Worker // counts exceeding 100%.
190*38e8c45fSAndroid Build Coastguard Worker for (int i = 0; i < stateCount; i++) {
191*38e8c45fSAndroid Build Coastguard Worker states[i].timeInStateSinceUpdate = 0;
192*38e8c45fSAndroid Build Coastguard Worker }
193*38e8c45fSAndroid Build Coastguard Worker }
194*38e8c45fSAndroid Build Coastguard Worker }
195*38e8c45fSAndroid Build Coastguard Worker currentState = state;
196*38e8c45fSAndroid Build Coastguard Worker lastStateChangeTimestamp = timestamp;
197*38e8c45fSAndroid Build Coastguard Worker }
198*38e8c45fSAndroid Build Coastguard Worker
199*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
copyStatesFrom(const MultiStateCounter<T,V> & source)200*38e8c45fSAndroid Build Coastguard Worker void MultiStateCounter<T, V>::copyStatesFrom(const MultiStateCounter<T, V>& source) {
201*38e8c45fSAndroid Build Coastguard Worker if (stateCount != source.stateCount) {
202*38e8c45fSAndroid Build Coastguard Worker ALOGE("State count mismatch: %u vs. %u\n", stateCount, source.stateCount);
203*38e8c45fSAndroid Build Coastguard Worker return;
204*38e8c45fSAndroid Build Coastguard Worker }
205*38e8c45fSAndroid Build Coastguard Worker
206*38e8c45fSAndroid Build Coastguard Worker currentState = source.currentState;
207*38e8c45fSAndroid Build Coastguard Worker for (int i = 0; i < stateCount; i++) {
208*38e8c45fSAndroid Build Coastguard Worker states[i].timeInStateSinceUpdate = source.states[i].timeInStateSinceUpdate;
209*38e8c45fSAndroid Build Coastguard Worker states[i].counter = emptyValue;
210*38e8c45fSAndroid Build Coastguard Worker }
211*38e8c45fSAndroid Build Coastguard Worker lastStateChangeTimestamp = source.lastStateChangeTimestamp;
212*38e8c45fSAndroid Build Coastguard Worker lastUpdateTimestamp = source.lastUpdateTimestamp;
213*38e8c45fSAndroid Build Coastguard Worker }
214*38e8c45fSAndroid Build Coastguard Worker
215*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
setValue(state_t state,const V & value)216*38e8c45fSAndroid Build Coastguard Worker void MultiStateCounter<T, V>::setValue(state_t state, const V& value) {
217*38e8c45fSAndroid Build Coastguard Worker states[state].counter = value;
218*38e8c45fSAndroid Build Coastguard Worker }
219*38e8c45fSAndroid Build Coastguard Worker
220*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
updateValue(const V & value,time_t timestamp)221*38e8c45fSAndroid Build Coastguard Worker const V& MultiStateCounter<T, V>::updateValue(const V& value, time_t timestamp) {
222*38e8c45fSAndroid Build Coastguard Worker const V* returnValue = &emptyValue;
223*38e8c45fSAndroid Build Coastguard Worker
224*38e8c45fSAndroid Build Coastguard Worker // If the counter is disabled, we ignore the update, except when the counter got disabled after
225*38e8c45fSAndroid Build Coastguard Worker // the previous update, in which case we still need to pick up the residual delta.
226*38e8c45fSAndroid Build Coastguard Worker if (isEnabled || lastUpdateTimestamp < lastStateChangeTimestamp) {
227*38e8c45fSAndroid Build Coastguard Worker // If the update arrived out of order, just push back the timestamp to
228*38e8c45fSAndroid Build Coastguard Worker // avoid having the situation where timeInStateSinceUpdate > timeSinceUpdate
229*38e8c45fSAndroid Build Coastguard Worker if (timestamp < lastStateChangeTimestamp) {
230*38e8c45fSAndroid Build Coastguard Worker timestamp = lastStateChangeTimestamp;
231*38e8c45fSAndroid Build Coastguard Worker }
232*38e8c45fSAndroid Build Coastguard Worker
233*38e8c45fSAndroid Build Coastguard Worker // Confirm the current state for the side-effect of updating the time-in-state
234*38e8c45fSAndroid Build Coastguard Worker // counter for the current state.
235*38e8c45fSAndroid Build Coastguard Worker setState(currentState, timestamp);
236*38e8c45fSAndroid Build Coastguard Worker
237*38e8c45fSAndroid Build Coastguard Worker if (lastUpdateTimestamp >= 0) {
238*38e8c45fSAndroid Build Coastguard Worker if (timestamp > lastUpdateTimestamp) {
239*38e8c45fSAndroid Build Coastguard Worker if (delta(lastValue, value, &deltaValue)) {
240*38e8c45fSAndroid Build Coastguard Worker returnValue = &deltaValue;
241*38e8c45fSAndroid Build Coastguard Worker time_t timeSinceUpdate = timestamp - lastUpdateTimestamp;
242*38e8c45fSAndroid Build Coastguard Worker for (int i = 0; i < stateCount; i++) {
243*38e8c45fSAndroid Build Coastguard Worker time_t timeInState = states[i].timeInStateSinceUpdate;
244*38e8c45fSAndroid Build Coastguard Worker if (timeInState) {
245*38e8c45fSAndroid Build Coastguard Worker add(&states[i].counter, deltaValue, timeInState, timeSinceUpdate);
246*38e8c45fSAndroid Build Coastguard Worker states[i].timeInStateSinceUpdate = 0;
247*38e8c45fSAndroid Build Coastguard Worker }
248*38e8c45fSAndroid Build Coastguard Worker }
249*38e8c45fSAndroid Build Coastguard Worker } else {
250*38e8c45fSAndroid Build Coastguard Worker std::stringstream str;
251*38e8c45fSAndroid Build Coastguard Worker str << "updateValue is called with a value " << value
252*38e8c45fSAndroid Build Coastguard Worker << ", which is lower than the previous value " << lastValue
253*38e8c45fSAndroid Build Coastguard Worker << "\n";
254*38e8c45fSAndroid Build Coastguard Worker ALOGE("%s", str.str().c_str());
255*38e8c45fSAndroid Build Coastguard Worker
256*38e8c45fSAndroid Build Coastguard Worker for (int i = 0; i < stateCount; i++) {
257*38e8c45fSAndroid Build Coastguard Worker states[i].timeInStateSinceUpdate = 0;
258*38e8c45fSAndroid Build Coastguard Worker }
259*38e8c45fSAndroid Build Coastguard Worker }
260*38e8c45fSAndroid Build Coastguard Worker } else if (timestamp < lastUpdateTimestamp) {
261*38e8c45fSAndroid Build Coastguard Worker if (timestamp < lastUpdateTimestamp - REPORTED_INVALID_TIMESTAMP_DELTA_MS) {
262*38e8c45fSAndroid Build Coastguard Worker ALOGE("updateValue is called with an earlier timestamp: %lu, previous: %lu\n",
263*38e8c45fSAndroid Build Coastguard Worker (unsigned long)timestamp, (unsigned long)lastUpdateTimestamp);
264*38e8c45fSAndroid Build Coastguard Worker }
265*38e8c45fSAndroid Build Coastguard Worker
266*38e8c45fSAndroid Build Coastguard Worker for (int i = 0; i < stateCount; i++) {
267*38e8c45fSAndroid Build Coastguard Worker states[i].timeInStateSinceUpdate = 0;
268*38e8c45fSAndroid Build Coastguard Worker }
269*38e8c45fSAndroid Build Coastguard Worker }
270*38e8c45fSAndroid Build Coastguard Worker }
271*38e8c45fSAndroid Build Coastguard Worker }
272*38e8c45fSAndroid Build Coastguard Worker lastValue = value;
273*38e8c45fSAndroid Build Coastguard Worker lastUpdateTimestamp = timestamp;
274*38e8c45fSAndroid Build Coastguard Worker return *returnValue;
275*38e8c45fSAndroid Build Coastguard Worker }
276*38e8c45fSAndroid Build Coastguard Worker
277*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
incrementValue(const V & increment,time_t timestamp)278*38e8c45fSAndroid Build Coastguard Worker void MultiStateCounter<T, V>::incrementValue(const V& increment, time_t timestamp) {
279*38e8c45fSAndroid Build Coastguard Worker // T newValue;
280*38e8c45fSAndroid Build Coastguard Worker // newValue = lastValue; // Copy assignment, not initialization.
281*38e8c45fSAndroid Build Coastguard Worker T newValue = lastValue;
282*38e8c45fSAndroid Build Coastguard Worker add(&newValue, increment, 1 /* numerator */, 1 /* denominator */);
283*38e8c45fSAndroid Build Coastguard Worker updateValue(newValue, timestamp);
284*38e8c45fSAndroid Build Coastguard Worker }
285*38e8c45fSAndroid Build Coastguard Worker
286*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
addValue(const V & value)287*38e8c45fSAndroid Build Coastguard Worker void MultiStateCounter<T, V>::addValue(const V& value) {
288*38e8c45fSAndroid Build Coastguard Worker if (!isEnabled) {
289*38e8c45fSAndroid Build Coastguard Worker return;
290*38e8c45fSAndroid Build Coastguard Worker }
291*38e8c45fSAndroid Build Coastguard Worker add(&states[currentState].counter, value, 1 /* numerator */, 1 /* denominator */);
292*38e8c45fSAndroid Build Coastguard Worker }
293*38e8c45fSAndroid Build Coastguard Worker
294*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
reset()295*38e8c45fSAndroid Build Coastguard Worker void MultiStateCounter<T, V>::reset() {
296*38e8c45fSAndroid Build Coastguard Worker lastStateChangeTimestamp = -1;
297*38e8c45fSAndroid Build Coastguard Worker lastUpdateTimestamp = -1;
298*38e8c45fSAndroid Build Coastguard Worker for (int i = 0; i < stateCount; i++) {
299*38e8c45fSAndroid Build Coastguard Worker states[i].timeInStateSinceUpdate = 0;
300*38e8c45fSAndroid Build Coastguard Worker states[i].counter = emptyValue;
301*38e8c45fSAndroid Build Coastguard Worker }
302*38e8c45fSAndroid Build Coastguard Worker }
303*38e8c45fSAndroid Build Coastguard Worker
304*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
getStateCount()305*38e8c45fSAndroid Build Coastguard Worker uint16_t MultiStateCounter<T, V>::getStateCount() {
306*38e8c45fSAndroid Build Coastguard Worker return stateCount;
307*38e8c45fSAndroid Build Coastguard Worker }
308*38e8c45fSAndroid Build Coastguard Worker
309*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
getCount(state_t state)310*38e8c45fSAndroid Build Coastguard Worker const V& MultiStateCounter<T, V>::getCount(state_t state) {
311*38e8c45fSAndroid Build Coastguard Worker return states[state].counter;
312*38e8c45fSAndroid Build Coastguard Worker }
313*38e8c45fSAndroid Build Coastguard Worker
314*38e8c45fSAndroid Build Coastguard Worker template <class T, class V>
toString()315*38e8c45fSAndroid Build Coastguard Worker std::string MultiStateCounter<T, V>::toString() {
316*38e8c45fSAndroid Build Coastguard Worker std::stringstream str;
317*38e8c45fSAndroid Build Coastguard Worker // str << "LAST VALUE: " << valueToString(lastValue);
318*38e8c45fSAndroid Build Coastguard Worker str << "[";
319*38e8c45fSAndroid Build Coastguard Worker for (int i = 0; i < stateCount; i++) {
320*38e8c45fSAndroid Build Coastguard Worker if (i != 0) {
321*38e8c45fSAndroid Build Coastguard Worker str << ", ";
322*38e8c45fSAndroid Build Coastguard Worker }
323*38e8c45fSAndroid Build Coastguard Worker str << i << ": " << states[i].counter;
324*38e8c45fSAndroid Build Coastguard Worker if (states[i].timeInStateSinceUpdate > 0) {
325*38e8c45fSAndroid Build Coastguard Worker str << " timeInStateSinceUpdate: " << states[i].timeInStateSinceUpdate;
326*38e8c45fSAndroid Build Coastguard Worker }
327*38e8c45fSAndroid Build Coastguard Worker }
328*38e8c45fSAndroid Build Coastguard Worker str << "]";
329*38e8c45fSAndroid Build Coastguard Worker if (lastUpdateTimestamp >= 0) {
330*38e8c45fSAndroid Build Coastguard Worker str << " updated: " << lastUpdateTimestamp;
331*38e8c45fSAndroid Build Coastguard Worker }
332*38e8c45fSAndroid Build Coastguard Worker if (lastStateChangeTimestamp >= 0) {
333*38e8c45fSAndroid Build Coastguard Worker str << " currentState: " << currentState;
334*38e8c45fSAndroid Build Coastguard Worker if (lastStateChangeTimestamp > lastUpdateTimestamp) {
335*38e8c45fSAndroid Build Coastguard Worker str << " stateChanged: " << lastStateChangeTimestamp;
336*38e8c45fSAndroid Build Coastguard Worker }
337*38e8c45fSAndroid Build Coastguard Worker } else {
338*38e8c45fSAndroid Build Coastguard Worker str << " currentState: none";
339*38e8c45fSAndroid Build Coastguard Worker }
340*38e8c45fSAndroid Build Coastguard Worker if (!isEnabled) {
341*38e8c45fSAndroid Build Coastguard Worker str << " disabled";
342*38e8c45fSAndroid Build Coastguard Worker }
343*38e8c45fSAndroid Build Coastguard Worker return str.str();
344*38e8c45fSAndroid Build Coastguard Worker }
345*38e8c45fSAndroid Build Coastguard Worker
346*38e8c45fSAndroid Build Coastguard Worker } // namespace battery
347*38e8c45fSAndroid Build Coastguard Worker } // namespace android
348