blob: 890eb33643c38fdd43299f71831898e882730d15 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "JsonFakeValueGenerator"
#include <fstream>
#include <type_traits>
#include <typeinfo>
#include <log/log.h>
#include <vhal_v2_0/VehicleUtils.h>
#include "JsonFakeValueGenerator.h"
namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {
namespace impl {
JsonFakeValueGenerator::JsonFakeValueGenerator(const VehiclePropValue& request) {
const auto& v = request.value;
const char* file = v.stringValue.c_str();
std::ifstream ifs(file);
if (!ifs) {
ALOGE("%s: couldn't open %s for parsing.", __func__, file);
}
mGenCfg = {
.index = 0,
.events = parseFakeValueJson(ifs),
};
// Iterate infinitely if repetition number is not provided
mNumOfIterations = v.int32Values.size() < 2 ? -1 : v.int32Values[1];
}
JsonFakeValueGenerator::JsonFakeValueGenerator(std::string path) {
std::ifstream ifs(path);
if (!ifs) {
ALOGE("%s: couldn't open %s for parsing.", __func__, path.c_str());
}
mGenCfg = {
.index = 0,
.events = parseFakeValueJson(ifs),
};
mNumOfIterations = mGenCfg.events.size();
}
std::vector<VehiclePropValue> JsonFakeValueGenerator::getAllEvents() {
return mGenCfg.events;
}
VehiclePropValue JsonFakeValueGenerator::nextEvent() {
VehiclePropValue generatedValue;
if (!hasNext()) {
return generatedValue;
}
TimePoint eventTime = Clock::now();
if (mGenCfg.index != 0) {
// All events (start from 2nd one) are supposed to happen in the future with a delay
// equals to the duration between previous and current event.
eventTime += Nanos(mGenCfg.events[mGenCfg.index].timestamp -
mGenCfg.events[mGenCfg.index - 1].timestamp);
}
generatedValue = mGenCfg.events[mGenCfg.index];
generatedValue.timestamp = eventTime.time_since_epoch().count();
mGenCfg.index++;
if (mGenCfg.index == mGenCfg.events.size()) {
mGenCfg.index = 0;
if (mNumOfIterations > 0) {
mNumOfIterations--;
}
}
return generatedValue;
}
bool JsonFakeValueGenerator::hasNext() {
return mNumOfIterations != 0 && mGenCfg.events.size() > 0;
}
std::vector<VehiclePropValue> JsonFakeValueGenerator::parseFakeValueJson(std::istream& is) {
std::vector<VehiclePropValue> fakeVhalEvents;
Json::Reader reader;
Json::Value rawEvents;
if (!reader.parse(is, rawEvents)) {
ALOGE("%s: Failed to parse fake data JSON file. Error: %s", __func__,
reader.getFormattedErrorMessages().c_str());
return fakeVhalEvents;
}
for (Json::Value::ArrayIndex i = 0; i < rawEvents.size(); i++) {
Json::Value rawEvent = rawEvents[i];
if (!rawEvent.isObject()) {
ALOGE("%s: VHAL JSON event should be an object, %s", __func__,
rawEvent.toStyledString().c_str());
continue;
}
if (rawEvent["prop"].empty() || rawEvent["areaId"].empty() || rawEvent["value"].empty() ||
rawEvent["timestamp"].empty()) {
ALOGE("%s: VHAL JSON event has missing fields, skip it, %s", __func__,
rawEvent.toStyledString().c_str());
continue;
}
VehiclePropValue event = {
.timestamp = rawEvent["timestamp"].asInt64(),
.areaId = rawEvent["areaId"].asInt(),
.prop = rawEvent["prop"].asInt(),
};
Json::Value rawEventValue = rawEvent["value"];
auto& value = event.value;
int32_t count;
switch (getPropType(event.prop)) {
case VehiclePropertyType::BOOLEAN:
case VehiclePropertyType::INT32:
value.int32Values.resize(1);
value.int32Values[0] = rawEventValue.asInt();
break;
case VehiclePropertyType::INT64:
value.int64Values.resize(1);
value.int64Values[0] = rawEventValue.asInt64();
break;
case VehiclePropertyType::FLOAT:
value.floatValues.resize(1);
value.floatValues[0] = rawEventValue.asFloat();
break;
case VehiclePropertyType::STRING:
value.stringValue = rawEventValue.asString();
break;
case VehiclePropertyType::INT32_VEC:
value.int32Values.resize(rawEventValue.size());
count = 0;
for (auto& it : rawEventValue) {
value.int32Values[count++] = it.asInt();
}
break;
case VehiclePropertyType::MIXED:
copyMixedValueJson(value, rawEventValue);
if (isDiagnosticProperty(event.prop)) {
value.bytes = generateDiagnosticBytes(value);
}
break;
default:
ALOGE("%s: unsupported type for property: 0x%x", __func__, event.prop);
continue;
}
fakeVhalEvents.push_back(event);
}
return fakeVhalEvents;
}
void JsonFakeValueGenerator::copyMixedValueJson(VehiclePropValue::RawValue& dest,
const Json::Value& jsonValue) {
copyJsonArray(dest.int32Values, jsonValue["int32Values"]);
copyJsonArray(dest.int64Values, jsonValue["int64Values"]);
copyJsonArray(dest.floatValues, jsonValue["floatValues"]);
dest.stringValue = jsonValue["stringValue"].asString();
}
template <typename T>
void JsonFakeValueGenerator::copyJsonArray(hidl_vec<T>& dest, const Json::Value& jsonArray) {
dest.resize(jsonArray.size());
for (Json::Value::ArrayIndex i = 0; i < jsonArray.size(); i++) {
if (std::is_same<T, int32_t>::value) {
dest[i] = jsonArray[i].asInt();
} else if (std::is_same<T, int64_t>::value) {
dest[i] = jsonArray[i].asInt64();
} else if (std::is_same<T, float>::value) {
dest[i] = jsonArray[i].asFloat();
}
}
}
bool JsonFakeValueGenerator::isDiagnosticProperty(int32_t prop) {
return prop == (int32_t)VehicleProperty::OBD2_LIVE_FRAME ||
prop == (int32_t)VehicleProperty::OBD2_FREEZE_FRAME;
}
hidl_vec<uint8_t> JsonFakeValueGenerator::generateDiagnosticBytes(
const VehiclePropValue::RawValue& diagnosticValue) {
size_t byteSize = ((size_t)DiagnosticIntegerSensorIndex::LAST_SYSTEM_INDEX +
(size_t)DiagnosticFloatSensorIndex::LAST_SYSTEM_INDEX + 2);
hidl_vec<uint8_t> bytes(byteSize % 8 == 0 ? byteSize / 8 : byteSize / 8 + 1);
auto& int32Values = diagnosticValue.int32Values;
for (size_t i = 0; i < int32Values.size(); i++) {
if (int32Values[i] != 0) {
setBit(bytes, i);
}
}
auto& floatValues = diagnosticValue.floatValues;
for (size_t i = 0; i < floatValues.size(); i++) {
if (floatValues[i] != 0.0) {
setBit(bytes, i + (size_t)DiagnosticIntegerSensorIndex::LAST_SYSTEM_INDEX + 1);
}
}
return bytes;
}
void JsonFakeValueGenerator::setBit(hidl_vec<uint8_t>& bytes, size_t idx) {
uint8_t mask = 1 << (idx % 8);
bytes[idx / 8] |= mask;
}
} // namespace impl
} // namespace V2_0
} // namespace vehicle
} // namespace automotive
} // namespace hardware
} // namespace android