1 /*
2  * Copyright (c) 2016, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.car.hvac;
17 
18 import android.os.SystemClock;
19 import android.util.SparseArray;
20 import android.util.SparseBooleanArray;
21 import android.util.SparseIntArray;
22 import android.util.SparseLongArray;
23 
24 import java.util.concurrent.TimeUnit;
25 import javax.annotation.concurrent.GuardedBy;
26 
27 /**
28  * The hvac unit can be controller from two places, the ui and the hardware buttons. Each of these
29  * request updates to the current state from different threads. Moreover, there can be conditions
30  * where the hvac could send spurious updates so this class routes everything through and coalesces
31  * them, keeping the application's view of the world sane.
32  */
33 public class DataStore {
34     private static final long COALESCE_TIME_MS = TimeUnit.SECONDS.toMillis(2);
35 
36     @GuardedBy("mTemperature")
37     private SparseArray<Float> mTemperature = new SparseArray<Float>();
38     @GuardedBy("mFanSpeed")
39     private Integer mFanSpeed = 0;
40     @GuardedBy("mAirflow")
41     private SparseIntArray mAirflow = new SparseIntArray();
42     @GuardedBy("mDefrosterState")
43     private SparseBooleanArray mDefrosterState = new SparseBooleanArray();
44     @GuardedBy("mAcState")
45     private Boolean mAcState = false;
46     @GuardedBy("mSeatWarmerLevel")
47     private SparseIntArray mSeatWarmerLevel = new SparseIntArray();
48     @GuardedBy("mAirCirculationState")
49     private Boolean mAirCirculationState = false;
50     @GuardedBy("mAutoModeState")
51     private Boolean mAutoModeState = false;
52     @GuardedBy("mHvacPowerState")
53     private Boolean mHvacPowerState = false;
54 
55     @GuardedBy("mTemperature")
56     private SparseLongArray mLastTemperatureSet = new SparseLongArray();
57     @GuardedBy("mFanSpeed")
58     private long mLastFanSpeedSet;
59     @GuardedBy("mAirflow")
60     private SparseLongArray mLastAirflowSet = new SparseLongArray();
61     @GuardedBy("mDefrosterState")
62     private SparseLongArray mLastDefrosterSet = new SparseLongArray();
63     @GuardedBy("mAcState")
64     private long mLastAcSet;
65     @GuardedBy("mSeatWarmerLevel")
66     private SparseLongArray mLastSeatWarmerLevel = new SparseLongArray();
67     @GuardedBy("mAirCirculationState")
68     private long mAirCirculationLastSet;
69     @GuardedBy("mAutoModeState")
70     private long mAutoModeLastSet;
71     @GuardedBy("mHvacPowerState")
72     private long mHvacPowerLastSet;
73 
74 
getTemperature(int zone)75     public float getTemperature(int zone) {
76         synchronized (mTemperature) {
77             return mTemperature.get(zone);
78         }
79     }
80 
setTemperature(int zone, float temperature)81     public void setTemperature(int zone, float temperature) {
82         synchronized (mTemperature) {
83             mTemperature.put(zone, temperature);
84             mLastTemperatureSet.put(zone, SystemClock.uptimeMillis());
85         }
86     }
87 
shouldPropagateTempUpdate(int zone, float temperature)88     public boolean shouldPropagateTempUpdate(int zone, float temperature) {
89         synchronized (mTemperature) {
90             if (SystemClock.uptimeMillis() - mLastTemperatureSet.get(zone) < COALESCE_TIME_MS) {
91                 return false;
92             }
93             mTemperature.put(zone, temperature);
94         }
95         return true;
96     }
97 
getDefrosterState(int zone)98     public boolean getDefrosterState(int zone) {
99         synchronized (mDefrosterState) {
100             return mDefrosterState.get(zone);
101         }
102     }
103 
setDefrosterState(int zone, boolean state)104     public void setDefrosterState(int zone, boolean state) {
105         synchronized (mDefrosterState) {
106             mDefrosterState.put(zone, state);
107             mLastDefrosterSet.put(zone, SystemClock.uptimeMillis());
108         }
109     }
110 
shouldPropagateDefrosterUpdate(int zone, boolean defrosterState)111     public boolean shouldPropagateDefrosterUpdate(int zone, boolean defrosterState) {
112         synchronized (mDefrosterState) {
113             if (SystemClock.uptimeMillis() - mLastDefrosterSet.get(zone) < COALESCE_TIME_MS) {
114                 return false;
115             }
116             mDefrosterState.put(zone, defrosterState);
117         }
118         return true;
119     }
120 
getFanSpeed()121     public int getFanSpeed() {
122         synchronized (mFanSpeed) {
123             return mFanSpeed;
124         }
125     }
126 
setFanSpeed(int speed)127     public void setFanSpeed(int speed) {
128         synchronized (mFanSpeed) {
129             mFanSpeed = speed;
130             mLastFanSpeedSet = SystemClock.uptimeMillis();
131         }
132     }
133 
shouldPropagateFanSpeedUpdate(int zone, int speed)134     public boolean shouldPropagateFanSpeedUpdate(int zone, int speed) {
135         // TODO: We ignore fan speed zones for now because we dont have a multi zone car.
136         synchronized (mFanSpeed) {
137             if (SystemClock.uptimeMillis() - mLastFanSpeedSet < COALESCE_TIME_MS) {
138                 return false;
139             }
140             mFanSpeed = speed;
141         }
142         return true;
143     }
144 
getAcState()145     public boolean getAcState() {
146         synchronized (mAcState) {
147             return mAcState;
148         }
149     }
150 
setAcState(boolean acState)151     public void setAcState(boolean acState) {
152         synchronized (mAcState) {
153             mAcState = acState;
154             mLastAcSet = SystemClock.uptimeMillis();
155         }
156     }
157 
shouldPropagateAcUpdate(boolean acState)158     public boolean shouldPropagateAcUpdate(boolean acState) {
159         synchronized (mAcState) {
160             if (SystemClock.uptimeMillis() - mLastAcSet < COALESCE_TIME_MS) {
161                 return false;
162             }
163             mAcState = acState;
164         }
165         return true;
166     }
167 
getAirflow(int zone)168     public int getAirflow(int zone) {
169         synchronized (mAirflow) {
170             return mAirflow.get(zone);
171         }
172     }
173 
setAirflow(int zone, int index)174     public void setAirflow(int zone, int index) {
175         synchronized (mAirflow) {
176             mAirflow.put(zone, index);
177             mLastAirflowSet.put(zone, SystemClock.uptimeMillis());
178         }
179     }
180 
shouldPropagateFanPositionUpdate(int zone, int index)181     public boolean shouldPropagateFanPositionUpdate(int zone, int index) {
182         synchronized (mAirflow) {
183             if (SystemClock.uptimeMillis() - mLastAirflowSet.get(zone) < COALESCE_TIME_MS) {
184                 return false;
185             }
186             mAirflow.put(zone, index);
187         }
188         return true;
189     }
190 
getSeatWarmerLevel(int zone)191     public float getSeatWarmerLevel(int zone) {
192         synchronized (mSeatWarmerLevel) {
193             return mSeatWarmerLevel.get(zone);
194         }
195     }
196 
setSeatWarmerLevel(int zone, int level)197     public void setSeatWarmerLevel(int zone, int level) {
198         synchronized (mSeatWarmerLevel) {
199             mSeatWarmerLevel.put(zone, level);
200             mLastSeatWarmerLevel.put(zone, SystemClock.uptimeMillis());
201         }
202     }
203 
shouldPropagateSeatWarmerLevelUpdate(int zone, int level)204     public boolean shouldPropagateSeatWarmerLevelUpdate(int zone, int level) {
205         synchronized (mSeatWarmerLevel) {
206             if (SystemClock.uptimeMillis() - mLastSeatWarmerLevel.get(zone) < COALESCE_TIME_MS) {
207                 return false;
208             }
209             mSeatWarmerLevel.put(zone, level);
210         }
211         return true;
212     }
213 
getAirCirculationState()214     public boolean getAirCirculationState() {
215         synchronized (mAirCirculationState) {
216             return mAirCirculationState;
217         }
218     }
219 
setAirCirculationState(boolean airCirculationState)220     public void setAirCirculationState(boolean airCirculationState) {
221         synchronized (mAirCirculationState) {
222             mAirCirculationState = airCirculationState;
223             mAirCirculationLastSet = SystemClock.uptimeMillis();
224         }
225     }
226 
shouldPropagateAirCirculationUpdate(boolean airCirculationState)227     public boolean shouldPropagateAirCirculationUpdate(boolean airCirculationState) {
228         synchronized (mAirCirculationState) {
229             if (SystemClock.uptimeMillis() - mAirCirculationLastSet < COALESCE_TIME_MS) {
230                 return false;
231             }
232             mAcState = airCirculationState;
233         }
234         return true;
235     }
236 
getAutoModeState()237     public boolean getAutoModeState() {
238         synchronized (mAutoModeState) {
239             return mAutoModeState;
240         }
241     }
242 
setAutoModeState(boolean autoModeState)243     public void setAutoModeState(boolean autoModeState) {
244         synchronized (mAutoModeState) {
245             mAutoModeState = autoModeState;
246             mAutoModeLastSet = SystemClock.uptimeMillis();
247         }
248     }
249 
shouldPropagateAutoModeUpdate(boolean autoModeState)250     public boolean shouldPropagateAutoModeUpdate(boolean autoModeState) {
251         synchronized (mAutoModeState) {
252             if (SystemClock.uptimeMillis() - mAutoModeLastSet < COALESCE_TIME_MS) {
253                 return false;
254             }
255             mAcState = autoModeState;
256         }
257         return true;
258     }
259 
getHvacPowerState()260     public boolean getHvacPowerState() {
261         synchronized (mHvacPowerState) {
262             return mHvacPowerState;
263         }
264     }
265 
setHvacPowerState(boolean hvacPowerState)266     public void setHvacPowerState(boolean hvacPowerState) {
267         synchronized (mHvacPowerState) {
268             mHvacPowerState = hvacPowerState;
269             mHvacPowerLastSet = SystemClock.uptimeMillis();
270         }
271     }
272 
shouldPropagateHvacPowerUpdate(boolean hvacPowerState)273     public boolean shouldPropagateHvacPowerUpdate(boolean hvacPowerState) {
274         synchronized (mHvacPowerState) {
275             if (SystemClock.uptimeMillis() - mHvacPowerLastSet < COALESCE_TIME_MS) {
276                 return false;
277             }
278             mHvacPowerState = hvacPowerState;
279         }
280         return true;
281     }
282 }
283