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

Commit 7bac03de authored by Pavel Maltsev's avatar Pavel Maltsev Committed by android-build-merger
Browse files

Merge "Adding a custom property to the default VHAL impl" into oc-dev

am: 69c42429

Change-Id: I56225b64b36d709e74e952ef9c918f475e15ee1a
parents 1369daa5 69c42429
Loading
Loading
Loading
Loading
+45 −0
Original line number Original line Diff line number Diff line
@@ -28,6 +28,25 @@ namespace V2_0 {


namespace impl {
namespace impl {


/*
 * This property is used for test purpose to generate fake events.
 *
 * It has the following format:
 *
 * int32Values[0] - command (1 - start fake data generation, 0 - stop)
 * int32Values[1] - VehicleProperty to which command applies
 *
 * For start command, additional data should be provided:
 *   int64Values[0] - periodic interval in nanoseconds
 *   floatValues[0] - initial value
 *   floatValues[1] - dispersion defines min and max range relative to initial value
 *   floatValues[2] - increment, with every timer tick the value will be incremented by this amount
 */
const int32_t kGenerateFakeDataControllingProperty = 0x0666
        | VehiclePropertyGroup::VENDOR
        | VehicleArea::GLOBAL
        | VehiclePropertyType::COMPLEX;

const int32_t kHvacPowerProperties[] = {
const int32_t kHvacPowerProperties[] = {
    toInt(VehicleProperty::HVAC_FAN_SPEED),
    toInt(VehicleProperty::HVAC_FAN_SPEED),
    toInt(VehicleProperty::HVAC_FAN_DIRECTION),
    toInt(VehicleProperty::HVAC_FAN_DIRECTION),
@@ -62,6 +81,24 @@ const ConfigDeclaration kVehicleProperties[] {
        .initialValue = { .floatValues = {0.0f} }
        .initialValue = { .floatValues = {0.0f} }
    },
    },


    {
        .config = {
            .prop = toInt(VehicleProperty::PERF_ODOMETER),
            .access = VehiclePropertyAccess::READ,
            .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
        },
        .initialValue = { .floatValues = {0.0f} }
    },

    {
        .config = {
            .prop = toInt(VehicleProperty::ENGINE_RPM),
            .access = VehiclePropertyAccess::READ,
            .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
        },
        .initialValue = { .floatValues = {0.0f} }
    },

    {
    {
        .config = {
        .config = {
            .prop = toInt(VehicleProperty::CURRENT_GEAR),
            .prop = toInt(VehicleProperty::CURRENT_GEAR),
@@ -284,6 +321,14 @@ const ConfigDeclaration kVehicleProperties[] {
            .maxSampleRate = 10,  // 10 Hz, every 100 ms
            .maxSampleRate = 10,  // 10 Hz, every 100 ms
        },
        },
        .initialValue = { .floatValues = {101.0f} }
        .initialValue = { .floatValues = {101.0f} }
    },

    {
        .config = {
            .prop = kGenerateFakeDataControllingProperty,
            .access = VehiclePropertyAccess::WRITE,
            .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
        },
    }
    }
};
};


+87 −1
Original line number Original line Diff line number Diff line
@@ -27,11 +27,18 @@ namespace V2_0 {


namespace impl {
namespace impl {


enum class FakeDataCommand : int32_t {
    Stop = 0,
    Start = 1,
};

EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore)
EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore)
    : mPropStore(propStore),
    : mPropStore(propStore),
      mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
      mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
      mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer,
      mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer,
                                  this, std::placeholders::_1)) {
                                  this, std::placeholders::_1)),
      mFakeValueGenerator(std::bind(&EmulatedVehicleHal::onFakeValueGenerated,
                                    this, std::placeholders::_1, std::placeholders::_2)) {


    for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
    for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
        mPropStore->registerProperty(kVehicleProperties[i].config);
        mPropStore->registerProperty(kVehicleProperties[i].config);
@@ -52,6 +59,10 @@ VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
}
}


StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
    if (propValue.prop == kGenerateFakeDataControllingProperty) {
        return handleGenerateFakeDataRequest(propValue);
    };

    if (mHvacPowerProps.count(propValue.prop)) {
    if (mHvacPowerProps.count(propValue.prop)) {
        auto hvacPowerOn = mPropStore->readValueOrNull(toInt(VehicleProperty::HVAC_POWER_ON),
        auto hvacPowerOn = mPropStore->readValueOrNull(toInt(VehicleProperty::HVAC_POWER_ON),
                                                      toInt(VehicleAreaZone::ROW_1));
                                                      toInt(VehicleAreaZone::ROW_1));
@@ -176,6 +187,81 @@ std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const {
    return mPropStore->readAllValues();
    return mPropStore->readAllValues();
}
}


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());
        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;
            }
            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;
            }
            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::Stop: {
            ALOGI("%s, FakeDataCommandStop", __func__);
            mFakeValueGenerator.stopGeneratingHalEvents(propId);
            break;
        }
        default: {
            ALOGE("%s: unexpected command: %d", __func__, command);
            return StatusCode::INVALID_ARG;
        }
    }
    return StatusCode::OK;
}

void EmulatedVehicleHal::onFakeValueGenerated(int32_t propId, float value) {
    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;

    }

    if (updatedPropValue) {
        updatedPropValue->prop = propId;
        updatedPropValue->areaId = 0;  // Add area support if necessary.
        updatedPropValue->timestamp = elapsedRealtimeNano();
        mPropStore->writeValue(*updatedPropValue);
        auto changeMode = mPropStore->getConfigOrDie(propId)->changeMode;
        if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) {
            doHalEvent(move(updatedPropValue));
        }
    }
}

}  // impl
}  // impl


}  // namespace V2_0
}  // namespace V2_0
+5 −0
Original line number Original line Diff line number Diff line
@@ -34,6 +34,7 @@
#include "DefaultConfig.h"
#include "DefaultConfig.h"
#include "VehicleHalProto.pb.h"
#include "VehicleHalProto.pb.h"
#include "VehicleEmulator.h"
#include "VehicleEmulator.h"
#include "FakeValueGenerator.h"


namespace android {
namespace android {
namespace hardware {
namespace hardware {
@@ -67,6 +68,9 @@ private:
        return std::chrono::nanoseconds(static_cast<int64_t>(1000000000L / hz));
        return std::chrono::nanoseconds(static_cast<int64_t>(1000000000L / hz));
    }
    }


    StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
    void onFakeValueGenerated(int32_t propId, float value);

    void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
    void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
    bool isContinuousProperty(int32_t propId) const;
    bool isContinuousProperty(int32_t propId) const;


@@ -74,6 +78,7 @@ private:
    VehiclePropertyStore* mPropStore;
    VehiclePropertyStore* mPropStore;
    std::unordered_set<int32_t> mHvacPowerProps;
    std::unordered_set<int32_t> mHvacPowerProps;
    RecurrentTimer mRecurrentTimer;
    RecurrentTimer mRecurrentTimer;
    FakeValueGenerator mFakeValueGenerator;
};
};


}  // impl
}  // impl
+127 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2017 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.
 */

#ifndef android_hardware_automotive_vehicle_V2_0_impl_FakeHalEventGenerator_H_
#define android_hardware_automotive_vehicle_V2_0_impl_FakeHalEventGenerator_H_

#include <chrono>

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

#include <vhal_v2_0/RecurrentTimer.h>

namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
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 MuxGuard = std::lock_guard<std::mutex>;

    mutable std::mutex mLock;
    OnHalEvent mOnHalEvent;
    RecurrentTimer mRecurrentTimer;
    std::unordered_map<int32_t, GeneratorCfg> mGenCfg;
};


}  // impl

}  // namespace V2_0
}  // namespace vehicle
}  // namespace automotive
}  // namespace hardware
}  // namespace android



#endif //android_hardware_automotive_vehicle_V2_0_impl_FakeHalEventGenerator_H_