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.Log;
20 import android.util.SparseArray;
21 import android.util.SparseBooleanArray;
22 import android.util.SparseIntArray;
23 import android.util.SparseLongArray;
24 
25 import java.util.concurrent.TimeUnit;
26 import javax.annotation.concurrent.GuardedBy;
27 
28 /**
29  * The hvac unit can be controller from two places, the ui and the hardware buttons. Each of these
30  * request updates to the current state from different threads. Moreover, there can be conditions
31  * where the hvac could send spurious updates so this class routes everything through and coalesces
32  * them, keeping the application's view of the world sane.
33  */
34 public class DataStore {
35     private static final long COALESCE_TIME_MS = 0L;
36 
37     @GuardedBy("mTemperature")
38     private SparseArray<Float> mTemperature = new SparseArray<Float>();
39     @GuardedBy("mTemperatureAvailable")
40     private SparseBooleanArray mTemperatureAvailable = new SparseBooleanArray();
41     @GuardedBy("mFanSpeed")
42     private Integer mFanSpeed = 0;
43     @GuardedBy("mAirflow")
44     private SparseIntArray mAirflow = new SparseIntArray();
45     @GuardedBy("mDefrosterState")
46     private SparseBooleanArray mDefrosterState = new SparseBooleanArray();
47     @GuardedBy("mAcState")
48     private Boolean mAcState = false;
49     @GuardedBy("mSeatWarmerLevel")
50     private SparseIntArray mSeatWarmerLevel = new SparseIntArray();
51     @GuardedBy("mAirCirculationState")
52     private Boolean mAirCirculationState = false;
53     @GuardedBy("mAutoModeState")
54     private Boolean mAutoModeState = false;
55     @GuardedBy("mHvacPowerState")
56     private Boolean mHvacPowerState = false;
57 
58     @GuardedBy("mTemperature")
59     private SparseLongArray mLastTemperatureSet = new SparseLongArray();
60     @GuardedBy("mFanSpeed")
61     private long mLastFanSpeedSet;
62     @GuardedBy("mAirflow")
63     private SparseLongArray mLastAirflowSet = new SparseLongArray();
64     @GuardedBy("mDefrosterState")
65     private SparseLongArray mLastDefrosterSet = new SparseLongArray();
66     @GuardedBy("mAcState")
67     private long mLastAcSet;
68     @GuardedBy("mSeatWarmerLevel")
69     private SparseLongArray mLastSeatWarmerLevel = new SparseLongArray();
70     @GuardedBy("mAirCirculationState")
71     private long mAirCirculationLastSet;
72     @GuardedBy("mAutoModeState")
73     private long mAutoModeLastSet;
74     @GuardedBy("mHvacPowerState")
75     private long mHvacPowerLastSet;
76 
77 
getTemperature(int zone)78     public float getTemperature(int zone) {
79         synchronized (mTemperature) {
80             return mTemperature.get(zone);
81         }
82     }
83 
setTemperature(int zone, float temperature, boolean available)84     public void setTemperature(int zone, float temperature, boolean available) {
85         synchronized (mTemperature) {
86             synchronized (mTemperatureAvailable) {
87                 Log.d("HvacDataStore", "setTemperature(" + zone + ", " + temperature + ")");
88                 mTemperature.put(zone, temperature);
89                 mTemperatureAvailable.put(zone, available);
90                 mLastTemperatureSet.put(zone, SystemClock.uptimeMillis());
91             }
92         }
93     }
94 
shouldPropagateTempUpdate(int zone, float temperature, boolean available)95     public boolean shouldPropagateTempUpdate(int zone, float temperature, boolean available) {
96         synchronized (mTemperature) {
97             synchronized (mTemperatureAvailable) {
98                 if (SystemClock.uptimeMillis() - mLastTemperatureSet.get(zone) < COALESCE_TIME_MS) {
99                     if (available == mTemperatureAvailable.get(zone)) {
100                         return false;
101                     }
102                 }
103             }
104             setTemperature(zone, temperature, available);
105         }
106         return true;
107     }
108 
getDefrosterState(int zone)109     public boolean getDefrosterState(int zone) {
110         synchronized (mDefrosterState) {
111             return mDefrosterState.get(zone);
112         }
113     }
114 
setDefrosterState(int zone, boolean state)115     public void setDefrosterState(int zone, boolean state) {
116         synchronized (mDefrosterState) {
117             mDefrosterState.put(zone, state);
118             mLastDefrosterSet.put(zone, SystemClock.uptimeMillis());
119         }
120     }
121 
shouldPropagateDefrosterUpdate(int zone, boolean defrosterState)122     public boolean shouldPropagateDefrosterUpdate(int zone, boolean defrosterState) {
123         synchronized (mDefrosterState) {
124             if (SystemClock.uptimeMillis() - mLastDefrosterSet.get(zone) < COALESCE_TIME_MS) {
125                 return false;
126             }
127             mDefrosterState.put(zone, defrosterState);
128         }
129         return true;
130     }
131 
getFanSpeed()132     public int getFanSpeed() {
133         synchronized (mFanSpeed) {
134             return mFanSpeed;
135         }
136     }
137 
setFanSpeed(int speed)138     public void setFanSpeed(int speed) {
139         synchronized (mFanSpeed) {
140             mFanSpeed = speed;
141             mLastFanSpeedSet = SystemClock.uptimeMillis();
142         }
143     }
144 
shouldPropagateFanSpeedUpdate(int zone, int speed)145     public boolean shouldPropagateFanSpeedUpdate(int zone, int speed) {
146         // TODO: We ignore fan speed zones for now because we dont have a multi zone car.
147         synchronized (mFanSpeed) {
148             if (SystemClock.uptimeMillis() - mLastFanSpeedSet < COALESCE_TIME_MS) {
149                 return false;
150             }
151             mFanSpeed = speed;
152         }
153         return true;
154     }
155 
getAcState()156     public boolean getAcState() {
157         synchronized (mAcState) {
158             return mAcState;
159         }
160     }
161 
setAcState(boolean acState)162     public void setAcState(boolean acState) {
163         synchronized (mAcState) {
164             mAcState = acState;
165             mLastAcSet = SystemClock.uptimeMillis();
166         }
167     }
168 
shouldPropagateAcUpdate(boolean acState)169     public boolean shouldPropagateAcUpdate(boolean acState) {
170         synchronized (mAcState) {
171             if (SystemClock.uptimeMillis() - mLastAcSet < COALESCE_TIME_MS) {
172                 return false;
173             }
174             mAcState = acState;
175         }
176         return true;
177     }
178 
getAirflow(int zone)179     public int getAirflow(int zone) {
180         synchronized (mAirflow) {
181             return mAirflow.get(zone);
182         }
183     }
184 
setAirflow(int zone, int index)185     public void setAirflow(int zone, int index) {
186         synchronized (mAirflow) {
187             mAirflow.put(zone, index);
188             mLastAirflowSet.put(zone, SystemClock.uptimeMillis());
189         }
190     }
191 
shouldPropagateFanPositionUpdate(int zone, int index)192     public boolean shouldPropagateFanPositionUpdate(int zone, int index) {
193         synchronized (mAirflow) {
194             if (SystemClock.uptimeMillis() - mLastAirflowSet.get(zone) < COALESCE_TIME_MS) {
195                 return false;
196             }
197             mAirflow.put(zone, index);
198         }
199         return true;
200     }
201 
getSeatWarmerLevel(int zone)202     public float getSeatWarmerLevel(int zone) {
203         synchronized (mSeatWarmerLevel) {
204             return mSeatWarmerLevel.get(zone);
205         }
206     }
207 
setSeatWarmerLevel(int zone, int level)208     public void setSeatWarmerLevel(int zone, int level) {
209         synchronized (mSeatWarmerLevel) {
210             mSeatWarmerLevel.put(zone, level);
211             mLastSeatWarmerLevel.put(zone, SystemClock.uptimeMillis());
212         }
213     }
214 
shouldPropagateSeatWarmerLevelUpdate(int zone, int level)215     public boolean shouldPropagateSeatWarmerLevelUpdate(int zone, int level) {
216         synchronized (mSeatWarmerLevel) {
217             if (SystemClock.uptimeMillis() - mLastSeatWarmerLevel.get(zone) < COALESCE_TIME_MS) {
218                 return false;
219             }
220             mSeatWarmerLevel.put(zone, level);
221         }
222         return true;
223     }
224 
getAirCirculationState()225     public boolean getAirCirculationState() {
226         synchronized (mAirCirculationState) {
227             return mAirCirculationState;
228         }
229     }
230 
setAirCirculationState(boolean airCirculationState)231     public void setAirCirculationState(boolean airCirculationState) {
232         synchronized (mAirCirculationState) {
233             mAirCirculationState = airCirculationState;
234             mAirCirculationLastSet = SystemClock.uptimeMillis();
235         }
236     }
237 
shouldPropagateAirCirculationUpdate(boolean airCirculationState)238     public boolean shouldPropagateAirCirculationUpdate(boolean airCirculationState) {
239         synchronized (mAirCirculationState) {
240             if (SystemClock.uptimeMillis() - mAirCirculationLastSet < COALESCE_TIME_MS) {
241                 return false;
242             }
243             mAcState = airCirculationState;
244         }
245         return true;
246     }
247 
getAutoModeState()248     public boolean getAutoModeState() {
249         synchronized (mAutoModeState) {
250             return mAutoModeState;
251         }
252     }
253 
setAutoModeState(boolean autoModeState)254     public void setAutoModeState(boolean autoModeState) {
255         synchronized (mAutoModeState) {
256             mAutoModeState = autoModeState;
257             mAutoModeLastSet = SystemClock.uptimeMillis();
258         }
259     }
260 
shouldPropagateAutoModeUpdate(boolean autoModeState)261     public boolean shouldPropagateAutoModeUpdate(boolean autoModeState) {
262         synchronized (mAutoModeState) {
263             if (SystemClock.uptimeMillis() - mAutoModeLastSet < COALESCE_TIME_MS) {
264                 return false;
265             }
266             mAcState = autoModeState;
267         }
268         return true;
269     }
270 
getHvacPowerState()271     public boolean getHvacPowerState() {
272         synchronized (mHvacPowerState) {
273             return mHvacPowerState;
274         }
275     }
276 
setHvacPowerState(boolean hvacPowerState)277     public void setHvacPowerState(boolean hvacPowerState) {
278         synchronized (mHvacPowerState) {
279             mHvacPowerState = hvacPowerState;
280             mHvacPowerLastSet = SystemClock.uptimeMillis();
281         }
282     }
283 
shouldPropagateHvacPowerUpdate(boolean hvacPowerState)284     public boolean shouldPropagateHvacPowerUpdate(boolean hvacPowerState) {
285         synchronized (mHvacPowerState) {
286             if (SystemClock.uptimeMillis() - mHvacPowerLastSet < COALESCE_TIME_MS) {
287                 return false;
288             }
289             mHvacPowerState = hvacPowerState;
290         }
291         return true;
292     }
293 }
294