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