blob: 737d84ac91b4a6c7bde3d2c502695f0e1b88b15c [file] [log] [blame]
Tanmay Patilb2897b42020-06-08 17:55:02 -07001/*
2 * Copyright 2020 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
17#define LOG_TAG "IOModule"
18
19#include "CarModelConfigReader.h"
20#include "ConfigReaderUtil.h"
21#include "MathHelp.h"
22#include "core_lib.h"
23
24#include <android-base/logging.h>
25#include <tinyxml2.h>
26#include <sstream>
27#include <string>
28#include <utility>
29
30namespace android {
31namespace hardware {
32namespace automotive {
33namespace sv {
34namespace V1_0 {
35namespace implementation {
36
37// Macro returning IoStatus::ERROR_READ_ANIMATION if condition evaluates to false.
38#define RETURN_ERROR_STATUS_IF_FALSE(cond) \
39 do { \
40 if (!(cond)) { \
41 return IOStatus::ERROR_READ_ANIMATION; \
42 } \
43 } while (0)
44
45using tinyxml2::XML_SUCCESS;
46using tinyxml2::XMLDocument;
47using tinyxml2::XMLElement;
48
49namespace {
50
51bool ReadValueHex(const XMLElement* parent, const char* elementName, uint32_t* hex) {
52 const XMLElement* element = nullptr;
53 RETURN_IF_FALSE(GetElement(parent, elementName, &element));
54 RETURN_IF_FALSE(ElementHasText(element));
55 *hex = std::stoul(element->GetText(), nullptr, 16);
56 return true;
57}
58
59bool ReadValueList(const XMLElement* parent, const char* elementName,
60 std::vector<std::string>* valueList) {
61 valueList->clear();
62 for (const XMLElement* elem = parent->FirstChildElement(elementName); elem != nullptr;
63 elem = elem->NextSiblingElement(elementName)) {
64 RETURN_IF_FALSE(ElementHasText(elem));
65 valueList->push_back(std::string(elem->GetText()));
66 }
67 return true;
68}
69
70// ReadValue for SurroundView2dParams::BlendingType.
71bool ReadAnimationType(const XMLElement* parent, const char* elementName, AnimationType* type) {
72 const XMLElement* element = nullptr;
73 RETURN_IF_FALSE(GetElement(parent, elementName, &element));
74 RETURN_IF_FALSE(ElementHasText(element));
75 const std::string animationTypeStr(element->GetText());
76
77 if (animationTypeStr == "RotationAngle") {
78 *type = AnimationType::ROTATION_ANGLE;
79 } else if (animationTypeStr == "RotationSpeed") {
80 *type = AnimationType::ROTATION_SPEED;
81 } else if (animationTypeStr == "Translation") {
82 *type = AnimationType::TRANSLATION;
83 } else if (animationTypeStr == "SwitchTextureOnce") {
84 *type = AnimationType::SWITCH_TEXTURE_ONCE;
85 } else if (animationTypeStr == "AdjustGammaOnce") {
86 *type = AnimationType::ADJUST_GAMMA_ONCE;
87 } else if (animationTypeStr == "SwitchTextureRepeat") {
88 *type = AnimationType::SWITCH_TEXTURE_REPEAT;
89 } else if (animationTypeStr == "AdjustGammaRepeat") {
90 *type = AnimationType::ADJUST_GAMMA_REPEAT;
91 } else {
92 LOG(ERROR) << "Unknown AnimationType specified: " << animationTypeStr;
93 return false;
94 }
95 return true;
96}
97
98bool ReadRange(const XMLElement* parent, const char* elementName, Range* range) {
99 const XMLElement* rangeElem = nullptr;
100 RETURN_IF_FALSE(GetElement(parent, elementName, &rangeElem));
101 {
102 RETURN_IF_FALSE(ReadValue(rangeElem, "Start", &range->start));
103 RETURN_IF_FALSE(ReadValue(rangeElem, "End", &range->end));
104 }
105 return true;
106}
107
108bool ReadFloat3(const XMLElement* parent, const char* elementName, std::array<float, 3>* float3) {
109 const XMLElement* arrayElem = nullptr;
110 RETURN_IF_FALSE(GetElement(parent, elementName, &arrayElem));
111 {
112 RETURN_IF_FALSE(ReadValue(arrayElem, "X", &float3->at(0)));
113 RETURN_IF_FALSE(ReadValue(arrayElem, "Y", &float3->at(1)));
114 RETURN_IF_FALSE(ReadValue(arrayElem, "Z", &float3->at(2)));
115 }
116 return true;
117}
118
119// Generic template for reading a animation op, each op type must be specialized.
120template <typename OpType>
121bool ReadOp(const XMLElement* opElem, OpType* op) {
122 (void)opElem;
123 (void)op;
124 LOG(ERROR) << "Unexpected internal error: Op type in not supported.";
125 return false;
126}
127
128// Reads vhal property.
129bool ReadVhalProperty(const XMLElement* parent, const char* elementName, uint64_t* vhalProperty) {
130 const XMLElement* vhalPropElem = nullptr;
131 RETURN_IF_FALSE(GetElement(parent, elementName, &vhalPropElem));
132 {
133 uint32_t propertyId;
134 uint32_t areaId;
135 RETURN_IF_FALSE(ReadValueHex(vhalPropElem, "PropertyId", &propertyId));
136 RETURN_IF_FALSE(ReadValueHex(vhalPropElem, "AreaId", &areaId));
137 *vhalProperty = (static_cast<uint64_t>(propertyId) << 32) | areaId;
138 }
139 return true;
140}
141
142template <>
143bool ReadOp<RotationOp>(const XMLElement* rotationOpElem, RotationOp* rotationOp) {
144 RETURN_IF_FALSE(ReadVhalProperty(rotationOpElem, "VhalProperty", &rotationOp->vhalProperty));
145
146 RETURN_IF_FALSE(ReadAnimationType(rotationOpElem, "AnimationType", &rotationOp->type));
147
148 RETURN_IF_FALSE(ReadFloat3(rotationOpElem, "RotationAxis", &rotationOp->axis.axisVector));
149
150 RETURN_IF_FALSE(ReadFloat3(rotationOpElem, "RotationPoint", &rotationOp->axis.rotationPoint));
151
152 RETURN_IF_FALSE(
153 ReadValue(rotationOpElem, "DefaultRotationValue", &rotationOp->defaultRotationValue));
154
155 RETURN_IF_FALSE(ReadValue(rotationOpElem, "AnimationTimeMs", &rotationOp->animationTime));
156
157 RETURN_IF_FALSE(ReadRange(rotationOpElem, "RotationRange", &rotationOp->rotationRange));
158
159 RETURN_IF_FALSE(ReadRange(rotationOpElem, "VhalRange", &rotationOp->vhalRange));
160
161 return true;
162}
163
164template <>
165bool ReadOp<TranslationOp>(const XMLElement* translationOpElem, TranslationOp* translationOp) {
166 RETURN_IF_FALSE(
167 ReadVhalProperty(translationOpElem, "VhalProperty", &translationOp->vhalProperty));
168
169 RETURN_IF_FALSE(ReadAnimationType(translationOpElem, "AnimationType", &translationOp->type));
170
171 RETURN_IF_FALSE(ReadFloat3(translationOpElem, "Direction", &translationOp->direction));
172
173 RETURN_IF_FALSE(ReadValue(translationOpElem, "DefaultTranslationValue",
174 &translationOp->defaultTranslationValue));
175
176 RETURN_IF_FALSE(ReadValue(translationOpElem, "AnimationTimeMs", &translationOp->animationTime));
177
178 RETURN_IF_FALSE(
179 ReadRange(translationOpElem, "TranslationRange", &translationOp->translationRange));
180
181 RETURN_IF_FALSE(ReadRange(translationOpElem, "VhalRange", &translationOp->vhalRange));
182
183 return true;
184}
185
186template <>
187bool ReadOp<TextureOp>(const XMLElement* textureOpElem, TextureOp* textureOp) {
188 RETURN_IF_FALSE(ReadVhalProperty(textureOpElem, "VhalProperty", &textureOp->vhalProperty));
189
190 RETURN_IF_FALSE(ReadAnimationType(textureOpElem, "AnimationType", &textureOp->type));
191
192 RETURN_IF_FALSE(ReadValue(textureOpElem, "DefaultTexture", &textureOp->defaultTexture));
193
194 RETURN_IF_FALSE(ReadValue(textureOpElem, "AnimationTimeMs", &textureOp->animationTime));
195
196 RETURN_IF_FALSE(ReadRange(textureOpElem, "TextureRange", &textureOp->textureRange));
197
198 RETURN_IF_FALSE(ReadRange(textureOpElem, "VhalRange", &textureOp->vhalRange));
199
200 return true;
201}
202
203template <>
204bool ReadOp<GammaOp>(const XMLElement* gammaOpElem, GammaOp* gammaOp) {
205 RETURN_IF_FALSE(ReadVhalProperty(gammaOpElem, "VhalProperty", &gammaOp->vhalProperty));
206
207 RETURN_IF_FALSE(ReadAnimationType(gammaOpElem, "AnimationType", &gammaOp->type));
208
209 RETURN_IF_FALSE(ReadValue(gammaOpElem, "AnimationTimeMs", &gammaOp->animationTime));
210
211 RETURN_IF_FALSE(ReadRange(gammaOpElem, "GammaRange", &gammaOp->gammaRange));
212
213 RETURN_IF_FALSE(ReadRange(gammaOpElem, "VhalRange", &gammaOp->vhalRange));
214
215 return true;
216}
217
218template <typename OpType>
219bool ReadAllOps(const XMLElement* animationElem, const char* elemName,
220 std::map<uint64_t, std::vector<OpType>>* mapOps) {
221 for (const XMLElement* elem = animationElem->FirstChildElement(elemName); elem != nullptr;
222 elem = elem->NextSiblingElement(elemName)) {
223 OpType op;
224 RETURN_IF_FALSE(ReadOp(elem, &op));
225 if (mapOps->find(op.vhalProperty) == mapOps->end()) {
226 mapOps->emplace(op.vhalProperty, std::vector<OpType>());
227 }
228 mapOps->at(op.vhalProperty).push_back(op);
229 }
230 return true;
231}
232
233bool ReadAnimation(const XMLElement* animationElem, AnimationInfo* animationInfo) {
234 RETURN_IF_FALSE(ReadValue(animationElem, "PartId", &animationInfo->partId));
235 RETURN_IF_FALSE(ReadValue(animationElem, "ParentPartId", &animationInfo->parentId));
236
237 // Child Part Ids (Optional)
238 const XMLElement* childPartsElem = nullptr;
239 GetElement(animationElem, "ChildParts", &childPartsElem);
240 if (childPartsElem != nullptr) {
241 RETURN_IF_FALSE(ReadValueList(childPartsElem, "PartId", &animationInfo->childIds));
242 }
243
244 // Set to the default Identity.
245 animationInfo->pose = gMat4Identity;
246
247 // All animation operations.
248 RETURN_IF_FALSE(ReadAllOps(animationElem, "RotationOp", &animationInfo->rotationOpsMap));
249 RETURN_IF_FALSE(ReadAllOps(animationElem, "TranslationOp", &animationInfo->translationOpsMap));
250 RETURN_IF_FALSE(ReadAllOps(animationElem, "TextureOp", &animationInfo->textureOpsMap));
251 RETURN_IF_FALSE(ReadAllOps(animationElem, "GammaOp", &animationInfo->gammaOpsMap));
252 return true;
253}
254
255bool ReadAllAnimations(const XMLElement* rootElem, std::vector<AnimationInfo>* animations) {
256 animations->clear();
257 // Loop over animation elements.
258 for (const XMLElement* elem = rootElem->FirstChildElement("Animation"); elem != nullptr;
259 elem = elem->NextSiblingElement("Animation")) {
260 AnimationInfo animationInfo;
261 RETURN_IF_FALSE(ReadAnimation(elem, &animationInfo));
262 animations->push_back(animationInfo);
263 }
264 return true;
265}
266
267} // namespace
268
269IOStatus ReadCarModelConfig(const std::string& carModelConfigFile,
270 AnimationConfig* animationConfig) {
271 XMLDocument xmlDoc;
272
273 /* load and parse a configuration file */
274 xmlDoc.LoadFile(carModelConfigFile.c_str());
275 if (xmlDoc.ErrorID() != XML_SUCCESS) {
276 LOG(ERROR) << "Failed to load and/or parse a configuration file, " << xmlDoc.ErrorStr();
277 return IOStatus::ERROR_READ_ANIMATION;
278 }
279
280 const XMLElement* rootElem = xmlDoc.RootElement();
281 if (strcmp(rootElem->Name(), "SurroundViewCarModelConfig")) {
282 LOG(ERROR) << "A configuration file is not in the required format. "
283 << "See /etc/automotive/sv/sv_car_model_config.dtd";
284 return IOStatus::ERROR_READ_ANIMATION;
285 }
286
287 // version
288 RETURN_ERROR_STATUS_IF_FALSE(ReadValue(rootElem, "Version", &animationConfig->version));
289
290 // animations
291 RETURN_ERROR_STATUS_IF_FALSE(ReadAllAnimations(rootElem, &animationConfig->animations));
292
293 return IOStatus::OK;
294}
295
296} // namespace implementation
297} // namespace V1_0
298} // namespace sv
299} // namespace automotive
300} // namespace hardware
301} // namespace android