Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7a53d3e9 authored by Chao Yan's avatar Chao Yan Committed by Android (Google) Code Review
Browse files

Merge "Added fake VHAL value generator based on JSON file" into pi-dev

parents 73bfa711 f63c2cad
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -62,6 +62,8 @@ cc_library_static {
        "impl/vhal_v2_0/VehicleEmulator.cpp",
        "impl/vhal_v2_0/PipeComm.cpp",
        "impl/vhal_v2_0/SocketComm.cpp",
        "impl/vhal_v2_0/LinearFakeValueGenerator.cpp",
        "impl/vhal_v2_0/JsonFakeValueGenerator.cpp",
    ],
    local_include_dirs: ["common/include/vhal_v2_0"],
    export_include_dirs: ["impl"],
@@ -71,6 +73,7 @@ cc_library_static {
        "libprotobuf-cpp-lite",
    ],
    static_libs: [
        "libjsoncpp",
        "libqemu_pipe",
        "android.hardware.automotive.vehicle@2.0-libproto-native",
    ],
@@ -107,6 +110,7 @@ cc_binary {
        "android.hardware.automotive.vehicle@2.0-manager-lib",
        "android.hardware.automotive.vehicle@2.0-default-impl-lib",
        "android.hardware.automotive.vehicle@2.0-libproto-native",
        "libjsoncpp",
        "libqemu_pipe",
    ],
}
+45 −17
Original line number Diff line number Diff line
@@ -42,38 +42,66 @@ constexpr int WHEEL_TICK = (int)VehicleProperty::WHEEL_TICK;
constexpr int ALL_WHEELS =
    (int)(Wheel::LEFT_FRONT | Wheel::RIGHT_FRONT | Wheel::LEFT_REAR | Wheel::RIGHT_REAR);

/*
 * This property is used for test purpose to generate fake events.
 *
 * It has the following format:
 *
 * int32Values[0] - command (see FakeDataCommand below for possible values)
 * int32Values[1] - VehicleProperty to which command applies
/**
 * This property is used for test purpose to generate fake events. Here is the test package that
 * is referencing this property definition: packages/services/Car/tests/vehiclehal_test
 */
const int32_t kGenerateFakeDataControllingProperty =
    0x0666 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;

/**
 * FakeDataCommand enum defines the supported command type for kGenerateFakeDataControllingProperty.
 * All those commands can be send independently with each other. And each will override the one sent
 * previously.
 *
 * The controlling property has the following format:
 *
 *     int32Values[0] - command enum defined in FakeDataCommand
 *
 * The format of the arguments is defined for each command type as below:
 */
enum class FakeDataCommand : int32_t {
    /** Stops generating of fake data that was triggered by Start command */
    Stop = 0,

    /**
     * Starts fake data generation.  Caller must provide additional data:
     * Starts linear fake data generation. Caller must provide additional data:
     *     int32Values[1] - VehicleProperty to which command applies
     *     int64Values[0] - periodic interval in nanoseconds
     *     floatValues[0] - initial value
     *     floatValues[1] - dispersion defines min and max range relative to initial value
     *     floatValues[1] - dispersion defines the min/max value relative to initial value, where
     *                      max = initial_value + dispersion, min = initial_value - dispersion.
     *                      Dispersion should be non-negative, otherwise the behavior is undefined.
     *     floatValues[2] - increment, with every timer tick the value will be incremented by this
     * amount
     *                      amount. When reaching to max value, the current value will be set to min.
     *                      It should be non-negative, otherwise the behavior is undefined.
     */
    StartLinear = 0,

    /** Stops generating of fake data that was triggered by Start commands.
     *     int32Values[1] - VehicleProperty to which command applies. VHAL will stop the
     *                      corresponding linear generation for that property.
     */
    StopLinear = 1,

    /**
     * Starts JSON-based fake data generation. Caller must provide a string value specifying
     * the path to fake value JSON file:
     *     stringValue    - path to the fake values JSON file
     */
    StartJson = 2,

    /**
     * Stops JSON-based fake data generation. No additional arguments needed.
     */
    Start = 1,
    StopJson = 3,

    /**
     * Injects key press event (HAL incorporates UP/DOWN acction and triggers 2 HAL events for every
     * key-press). Caller must provide the following data: int32Values[2] - Android key code
     * key-press). We set the enum with high number to leave space for future start/stop commands.
     * Caller must provide the following data:
     *     int32Values[2] - Android key code
     *     int32Values[3] - target display (0 - for main display, 1 - for instrument cluster, see
     *                      VehicleDisplay)
     */
    KeyPress = 2,
    KeyPress = 100,
};

const int32_t kHvacPowerProperties[] = {
+28 −52
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@
#include <android-base/macros.h>

#include "EmulatedVehicleHal.h"
#include "JsonFakeValueGenerator.h"
#include "LinearFakeValueGenerator.h"
#include "Obd2SensorStore.h"

namespace android {
@@ -88,10 +90,12 @@ static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame(size_t numVendorInt
EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore)
    : mPropStore(propStore),
      mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
      mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer,
                                  this, std::placeholders::_1)),
      mFakeValueGenerator(std::bind(&EmulatedVehicleHal::onFakeValueGenerated,
                                    this, std::placeholders::_1, std::placeholders::_2)) {
      mRecurrentTimer(
          std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)),
      mLinearFakeValueGenerator(std::make_unique<LinearFakeValueGenerator>(
          std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1))),
      mJsonFakeValueGenerator(std::make_unique<JsonFakeValueGenerator>(
          std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1))) {
    initStaticConfig();
    for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
        mPropStore->registerProperty(kVehicleProperties[i].config);
@@ -328,42 +332,29 @@ std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const {
StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
    ALOGI("%s", __func__);
    const auto& v = request.value;
    if (v.int32Values.size() < 2) {
        ALOGE("%s: expected at least 2 elements in int32Values, got: %zu", __func__,
                v.int32Values.size());
    if (!v.int32Values.size()) {
        ALOGE("%s: expected at least \"command\" field in int32Values", __func__);
        return StatusCode::INVALID_ARG;
    }

    FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);
    int32_t propId = v.int32Values[1];

    switch (command) {
        case FakeDataCommand::Start: {
            if (!v.int64Values.size()) {
                ALOGE("%s: interval is not provided in int64Values", __func__);
                return StatusCode::INVALID_ARG;
        case FakeDataCommand::StartLinear: {
            ALOGI("%s, FakeDataCommand::StartLinear", __func__);
            return mLinearFakeValueGenerator->start(request);
        }
            auto interval = std::chrono::nanoseconds(v.int64Values[0]);

            if (v.floatValues.size() < 3) {
                ALOGE("%s: expected at least 3 element sin floatValues, got: %zu", __func__,
                        v.floatValues.size());
                return StatusCode::INVALID_ARG;
        case FakeDataCommand::StartJson: {
            ALOGI("%s, FakeDataCommand::StartJson", __func__);
            return mJsonFakeValueGenerator->start(request);
        }
            float initialValue = v.floatValues[0];
            float dispersion = v.floatValues[1];
            float increment = v.floatValues[2];

            ALOGI("%s, propId: %d, initalValue: %f", __func__, propId, initialValue);
            mFakeValueGenerator.startGeneratingHalEvents(
                interval, propId, initialValue, dispersion, increment);

            break;
        case FakeDataCommand::StopLinear: {
            ALOGI("%s, FakeDataCommand::StopLinear", __func__);
            return mLinearFakeValueGenerator->stop(request);
        }
        case FakeDataCommand::Stop: {
            ALOGI("%s, FakeDataCommand::Stop", __func__);
            mFakeValueGenerator.stopGeneratingHalEvents(propId);
            break;
        case FakeDataCommand::StopJson: {
            ALOGI("%s, FakeDataCommand::StopJson", __func__);
            return mJsonFakeValueGenerator->stop(request);
        }
        case FakeDataCommand::KeyPress: {
            ALOGI("%s, FakeDataCommand::KeyPress", __func__);
@@ -374,7 +365,6 @@ StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropVa
            doHalEvent(createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display));
            break;
        }

        default: {
            ALOGE("%s: unexpected command: %d", __func__, command);
            return StatusCode::INVALID_ARG;
@@ -396,30 +386,16 @@ VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createHwInputKeyProp(
    return keyEvent;
}

void EmulatedVehicleHal::onFakeValueGenerated(int32_t propId, float value) {
void EmulatedVehicleHal::onFakeValueGenerated(const VehiclePropValue& value) {
    ALOGD("%s: %s", __func__, toString(value).c_str());
    static constexpr bool shouldUpdateStatus = false;

    VehiclePropValuePtr updatedPropValue {};
    switch (getPropType(propId)) {
        case VehiclePropertyType::FLOAT:
            updatedPropValue = getValuePool()->obtainFloat(value);
            break;
        case VehiclePropertyType::INT32:
            updatedPropValue = getValuePool()->obtainInt32(static_cast<int32_t>(value));
            break;
        default:
            ALOGE("%s: data type for property: 0x%x not supported", __func__, propId);
            return;

    }

    VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value);
    if (updatedPropValue) {
        updatedPropValue->prop = propId;
        updatedPropValue->areaId = 0;  // Add area support if necessary.
        updatedPropValue->timestamp = elapsedRealtimeNano();
        updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
        mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus);
        auto changeMode = mPropStore->getConfigOrDie(propId)->changeMode;
        auto changeMode = mPropStore->getConfigOrDie(value.prop)->changeMode;
        if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) {
            doHalEvent(move(updatedPropValue));
        }
+5 −3
Original line number Diff line number Diff line
@@ -30,9 +30,10 @@
#include "vhal_v2_0/VehiclePropertyStore.h"

#include "DefaultConfig.h"
#include "VehicleEmulator.h"
#include "FakeValueGenerator.h"

#include "VehicleEmulator.h"

namespace android {
namespace hardware {
namespace automotive {
@@ -66,7 +67,7 @@ private:
    }

    StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
    void onFakeValueGenerated(int32_t propId, float value);
    void onFakeValueGenerated(const VehiclePropValue& value);
    VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode,
                                             int32_t targetDisplay);

@@ -84,7 +85,8 @@ private:
    VehiclePropertyStore* mPropStore;
    std::unordered_set<int32_t> mHvacPowerProps;
    RecurrentTimer mRecurrentTimer;
    FakeValueGenerator mFakeValueGenerator;
    std::unique_ptr<FakeValueGenerator> mLinearFakeValueGenerator;
    std::unique_ptr<FakeValueGenerator> mJsonFakeValueGenerator;
};

}  // impl
+20 −88
Original line number Diff line number Diff line
@@ -14,15 +14,11 @@
 * limitations under the License.
 */

#ifndef android_hardware_automotive_vehicle_V2_0_impl_FakeHalEventGenerator_H_
#define android_hardware_automotive_vehicle_V2_0_impl_FakeHalEventGenerator_H_

#include <chrono>
#ifndef android_hardware_automotive_vehicle_V2_0_impl_FakeValueGenerator_H_
#define android_hardware_automotive_vehicle_V2_0_impl_FakeValueGenerator_H_

#include <android/hardware/automotive/vehicle/2.0/types.h>

#include <vhal_v2_0/RecurrentTimer.h>

namespace android {
namespace hardware {
namespace automotive {
@@ -31,89 +27,27 @@ namespace V2_0 {

namespace impl {

class FakeValueGenerator {
private:
    // In every timer tick we may want to generate new value based on initial value for debug
    // purpose. It's better to have sequential values to see if events gets delivered in order
    // to the client.

    struct GeneratorCfg {
        float initialValue;  //
        float currentValue;  //  Should be in range (initialValue +/- dispersion).
        float dispersion;    //  Defines minimum and maximum value based on initial value.
        float increment;     //  Value that we will be added to currentValue with each timer tick.
    };

public:
    using OnHalEvent = std::function<void(int32_t propId, float value)>;

    FakeValueGenerator(const OnHalEvent& onHalEvent) :
        mOnHalEvent(onHalEvent),
        mRecurrentTimer(std::bind(&FakeValueGenerator::onTimer, this,
                                  std::placeholders::_1))
    {}

    ~FakeValueGenerator() = default;


    void startGeneratingHalEvents(std::chrono::nanoseconds interval, int propId, float initialValue,
                                  float dispersion, float increment) {
        MuxGuard g(mLock);

        removeLocked(propId);

        mGenCfg.insert({propId, GeneratorCfg {
            .initialValue = initialValue,
            .currentValue = initialValue,
            .dispersion = dispersion,
            .increment = increment,
        }});

        mRecurrentTimer.registerRecurrentEvent(interval, propId);
    }

    void stopGeneratingHalEvents(int propId) {
        MuxGuard g(mLock);
        if (propId == 0) {
            // Remove all.
            for (auto&& it : mGenCfg) {
                removeLocked(it.first);
            }
        } else {
            removeLocked(propId);
        }
    }

private:
    void removeLocked(int propId) {
        if (mGenCfg.erase(propId)) {
            mRecurrentTimer.unregisterRecurrentEvent(propId);
        }
    }

    void onTimer(const std::vector<int32_t>& properties) {
        MuxGuard g(mLock);

        for (int32_t propId : properties) {
            auto& cfg = mGenCfg[propId];
            cfg.currentValue += cfg.increment;
            if (cfg.currentValue > cfg.initialValue + cfg.dispersion) {
                cfg.currentValue = cfg.initialValue - cfg.dispersion;
            }
            mOnHalEvent(propId, cfg.currentValue);
        }
    }

private:
using OnHalEvent = std::function<void(const VehiclePropValue& event)>;
using MuxGuard = std::lock_guard<std::mutex>;

    mutable std::mutex mLock;
    OnHalEvent mOnHalEvent;
    RecurrentTimer mRecurrentTimer;
    std::unordered_map<int32_t, GeneratorCfg> mGenCfg;
class FakeValueGenerator {
public:
    virtual ~FakeValueGenerator() = default;
    /**
     * Starts generating VHAL events
     *
     * @param request in VehiclePropValue with required information to start fake data generation
     * @return StatusCode of the start request
     */
    virtual StatusCode start(const VehiclePropValue& request) = 0;
    /**
     * Stops generating VHAL events
     * @param request in VehiclePropValue with required information to stop fake data generation
     * @return StatusCode of the stop request
     */
    virtual StatusCode stop(const VehiclePropValue& request) = 0;
};


}  // impl

}  // namespace V2_0
@@ -122,6 +56,4 @@ private:
}  // namespace hardware
}  // namespace android



#endif //android_hardware_automotive_vehicle_V2_0_impl_FakeHalEventGenerator_H_
#endif  // android_hardware_automotive_vehicle_V2_0_impl_FakeValueGenerator_H_
Loading