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.hal;
17 
18 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_BOOLEAN;
19 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT;
20 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT_VEC2;
21 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT_VEC3;
22 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT_VEC4;
23 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_INT32;
24 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC2;
25 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC3;
26 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC4;
27 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_STRING;
28 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_BOOLEAN;
29 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_FLOAT;
30 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_FLOAT_VEC2;
31 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_FLOAT_VEC3;
32 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_FLOAT_VEC4;
33 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_INT32;
34 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_INT32_VEC2;
35 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_INT32_VEC3;
36 import static com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_INT32_VEC4;
37 import static com.android.car.vehiclenetwork.VehiclePropValueUtil.getVectorValueType;
38 import static java.lang.Integer.toHexString;
39 
40 import android.car.VehicleZoneUtil;
41 import android.car.VehicleAreaType;
42 import android.car.hardware.CarPropertyConfig;
43 import android.car.hardware.CarPropertyValue;
44 
45 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig;
46 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
47 
48 import java.util.List;
49 
50 /**
51  * Utility functions to work with {@link CarPropertyConfig} and {@link CarPropertyValue}
52  */
53 /*package*/ final class CarPropertyUtils {
54 
55     /* Utility class has no public constructor */
CarPropertyUtils()56     private CarPropertyUtils() {}
57 
58     /** Converts {@link VehiclePropValue} to {@link CarPropertyValue} */
toCarPropertyValue( VehiclePropValue halValue, int propertyId)59     static CarPropertyValue<?> toCarPropertyValue(
60             VehiclePropValue halValue, int propertyId) {
61         Class<?> clazz = getJavaClass(halValue.getValueType());
62         int areaId = halValue.getZone();
63         if (Boolean.class == clazz) {
64             return new CarPropertyValue<>(propertyId, areaId, halValue.getInt32Values(0) == 1);
65         } else if (String.class == clazz) {
66             return new CarPropertyValue<>(propertyId, areaId, halValue.getStringValue());
67         } else if (Long.class == clazz) {
68             return new CarPropertyValue<>(propertyId, areaId, halValue.getInt64Value());
69         } else /* All list properties */ {
70             Object[] values = getRawValueList(clazz, halValue).toArray();
71             return new CarPropertyValue<>(propertyId, areaId,
72                     values.length == 1 ? values[0] : values);
73         }
74     }
75 
76     /** Converts {@link CarPropertyValue} to {@link VehiclePropValue} */
toVehiclePropValue(CarPropertyValue hvacProp, int halPropId)77     static VehiclePropValue toVehiclePropValue(CarPropertyValue hvacProp, int halPropId) {
78         VehiclePropValue.Builder builder = VehiclePropValue.newBuilder();
79         builder.setProp(halPropId);
80 
81         if (hvacProp.getAreaId() != 0) {
82             builder.setZone(hvacProp.getAreaId());
83         }
84 
85         Object o = hvacProp.getValue();
86 
87         boolean hasArea = hvacProp.getAreaId() != 0;
88         int vectorLength = (o instanceof Object[] ? ((Object[]) o).length : 0);
89         int halType;
90         if (o instanceof Boolean) {
91             halType = hasArea ? VEHICLE_VALUE_TYPE_ZONED_BOOLEAN : VEHICLE_VALUE_TYPE_BOOLEAN;
92             builder.addInt32Values(((Boolean )o) ? 1 : 0);
93         } else if (o instanceof Integer) {
94             halType = hasArea ? VEHICLE_VALUE_TYPE_ZONED_INT32 : VEHICLE_VALUE_TYPE_INT32;
95             builder.addInt32Values((Integer) o);
96         } else if (o instanceof Float) {
97             halType = hasArea ? VEHICLE_VALUE_TYPE_ZONED_FLOAT : VEHICLE_VALUE_TYPE_FLOAT;
98             builder.addFloatValues((Float) o);
99         } else if (o instanceof Integer[]) {
100             halType = getVectorValueType(
101                     hasArea ? VEHICLE_VALUE_TYPE_ZONED_INT32 : VEHICLE_VALUE_TYPE_ZONED_INT32,
102                     vectorLength);
103             for (Integer i : (Integer[]) o) {
104                 builder.addInt32Values(i);
105             }
106         } else if (o instanceof Float[]) {
107             halType = getVectorValueType(
108                     hasArea ? VEHICLE_VALUE_TYPE_ZONED_FLOAT : VEHICLE_VALUE_TYPE_ZONED_FLOAT,
109                     vectorLength);
110             for (Float f : (Float[]) o) {
111                 builder.addFloatValues(f);
112             }
113         } else if (o instanceof String) {
114             halType = VEHICLE_VALUE_TYPE_STRING;
115             builder.setStringValue((String) o);
116         } else {
117             throw new IllegalArgumentException("Unexpected type in: " + hvacProp);
118         }
119         builder.setValueType(halType);
120         return builder.build();
121     }
122 
123     /**
124      * Converts {@link VehiclePropConfig} to {@link CarPropertyConfig}.
125      */
toCarPropertyConfig(VehiclePropConfig p, int propertyId)126     static CarPropertyConfig<?> toCarPropertyConfig(VehiclePropConfig p, int propertyId) {
127         int[] areas = VehicleZoneUtil.listAllZones(p.getZones());
128 
129         // TODO: handle other vehicle area types.
130         int areaType = areas.length == 0
131                 ? VehicleAreaType.VEHICLE_AREA_TYPE_NONE : VehicleAreaType.VEHICLE_AREA_TYPE_ZONE;
132 
133         Class<?> clazz = getJavaClass(p.getValueType());
134         if (clazz == Boolean.class) {
135             return CarPropertyConfig
136                     .newBuilder(clazz, propertyId, areaType, /* capacity */ 1)
137                     .addAreas(areas)
138                     .build();
139         } else {
140             List mins;
141             List maxs;
142             if (classMatched(Integer.class, clazz)) {
143                 mins = p.getInt32MinsList();
144                 maxs = p.getInt32MaxsList();
145             } else if (classMatched(Float.class, clazz)) {
146                 mins = p.getFloatMinsList();
147                 maxs = p.getFloatMaxsList();
148             } else {
149                 throw new IllegalArgumentException("Unexpected type: " + clazz);
150             }
151             CarPropertyConfig.Builder builder = CarPropertyConfig
152                     .newBuilder(clazz, propertyId, areaType, /* capacity */ mins.size());
153             for (int i = 0; i < mins.size(); i++) {
154                 int areaId = areas.length == 0 ? 0 : areas[i];
155                 builder.addAreaConfig(areaId, mins.get(i), maxs.get(i));
156             }
157             return builder.build();
158         }
159     }
160 
getJavaClass(int halType)161     private static Class<?> getJavaClass(int halType) {
162         switch (halType) {
163             case VEHICLE_VALUE_TYPE_BOOLEAN:
164             case VEHICLE_VALUE_TYPE_ZONED_BOOLEAN:
165                 return Boolean.class;
166             case VEHICLE_VALUE_TYPE_FLOAT:
167             case VEHICLE_VALUE_TYPE_ZONED_FLOAT:
168                 return Float.class;
169             case VEHICLE_VALUE_TYPE_INT32:
170             case VEHICLE_VALUE_TYPE_ZONED_INT32:
171                 return Integer.class;
172             case VEHICLE_VALUE_TYPE_INT32_VEC2:
173             case VEHICLE_VALUE_TYPE_INT32_VEC3:
174             case VEHICLE_VALUE_TYPE_INT32_VEC4:
175             case VEHICLE_VALUE_TYPE_ZONED_INT32_VEC2:
176             case VEHICLE_VALUE_TYPE_ZONED_INT32_VEC3:
177             case VEHICLE_VALUE_TYPE_ZONED_INT32_VEC4:
178                 return Integer[].class;
179             case VEHICLE_VALUE_TYPE_FLOAT_VEC2:
180             case VEHICLE_VALUE_TYPE_FLOAT_VEC3:
181             case VEHICLE_VALUE_TYPE_FLOAT_VEC4:
182             case VEHICLE_VALUE_TYPE_ZONED_FLOAT_VEC2:
183             case VEHICLE_VALUE_TYPE_ZONED_FLOAT_VEC3:
184             case VEHICLE_VALUE_TYPE_ZONED_FLOAT_VEC4:
185                 return Float[].class;
186             case VEHICLE_VALUE_TYPE_STRING:
187                 return String.class;
188             default:
189                 throw new IllegalArgumentException("Unexpected type: " + toHexString(halType));
190         }
191     }
192 
getRawValueList(Class<?> clazz, VehiclePropValue vehiclePropValue)193     private static List getRawValueList(Class<?> clazz, VehiclePropValue vehiclePropValue) {
194         if (classMatched(Float.class, clazz)) {
195             return vehiclePropValue.getFloatValuesList();
196         } else if (classMatched(Integer.class, clazz)) {
197             return vehiclePropValue.getInt32ValuesList();
198         } else {
199             throw new IllegalArgumentException("Unexpected type: " + clazz);
200         }
201     }
202 
classMatched(Class<?> class1, Class<?> class2)203     private static boolean classMatched(Class<?> class1, Class<?> class2) {
204         return class1 == class2 || class1.getComponentType() == class2;
205     }
206 }
207