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