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

Commit d91f1c3e authored by Tanmay Patil's avatar Tanmay Patil
Browse files

Add VTS for Ultrasonics to EVS 1.1

Bug: 148619310

Test:  atest VtsHalEvsV1_1TargetTest

Change-Id: If91bce64cf06fd374b3829b0f01804bdc375197d
parent b97cceb4
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -18,12 +18,16 @@ cc_test {
    name: "VtsHalEvsV1_1TargetTest",
    srcs: [
        "FrameHandler.cpp",
        "FrameHandlerUltrasonics.cpp",
        "VtsHalEvsV1_1TargetTest.cpp",
    ],
    defaults: ["VtsHalTargetTestDefaults"],
    shared_libs: [
        "libui",
        "libcamera_metadata",
        "libhidlmemory",
        "android.hidl.allocator@1.0",
        "android.hidl.memory@1.0",
    ],
    static_libs: [
        "android.hardware.automotive.evs@1.0",
@@ -34,7 +38,7 @@ cc_test {
        "android.hardware.graphics.common@1.2",
        "android.hardware.camera.device@3.2",
    ],
    test_suites: ["general-tests"],
    test_suites: ["vts-core"],
    cflags: [
        "-O0",
        "-g",
+169 −0
Original line number Diff line number Diff line
/*
 * Copyright 2020 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.
 */

#include "FrameHandlerUltrasonics.h"

#include <android-base/logging.h>
#include <hidlmemory/mapping.h>
#include <android/hidl/memory/1.0/IMemory.h>

using ::android::hidl::memory::V1_0::IMemory;
using ::android::hardware::Return;
using ::android::sp;

using ::android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArrayStream;
using ::android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArray;
using ::android::hardware::automotive::evs::V1_1::UltrasonicsDataFrameDesc;
using ::android::hardware::automotive::evs::V1_1::EvsEventDesc;
using ::android::hardware::automotive::evs::V1_1::EvsEventType;

FrameHandlerUltrasonics::FrameHandlerUltrasonics(sp<IEvsUltrasonicsArray> pEvsUltrasonicsArray) :
    mEvsUltrasonicsArray(pEvsUltrasonicsArray), mReceiveFramesCount(0) {
    // Nothing but member initialization
}

Return<void> FrameHandlerUltrasonics::notify(const EvsEventDesc& evsEvent) {
    switch (evsEvent.aType) {
        case EvsEventType::STREAM_STARTED:
        case EvsEventType::STREAM_STOPPED:
        case EvsEventType::FRAME_DROPPED:
        case EvsEventType::TIMEOUT:
            mReceivedEvents.emplace_back(evsEvent);
            break;
        default:
            LOG(ERROR) << "Received unexpected event";
    }

    return android::hardware::Void();
}

// Struct used by SerializeWaveformData().
struct WaveformData {
    uint8_t receiverId;
    std::vector<std::pair<float, float>> readings;
};

// De-serializes shared memory to vector of WaveformData.
// TODO(b/149950362): Add a common library for serialiazing and deserializing waveform data.
std::vector<WaveformData> DeSerializeWaveformData(std::vector<uint32_t> recvReadingsCountList,
        uint8_t* pData) {
    std::vector<WaveformData> waveformDataList(recvReadingsCountList.size());

    for (int i = 0; i < waveformDataList.size(); i++) {
        // Set Id
        memcpy(&waveformDataList[i].receiverId, pData, sizeof(uint8_t));
        pData += sizeof(uint8_t);

        waveformDataList[i].readings.resize(recvReadingsCountList[i]);

        for (auto& reading : waveformDataList[i].readings) {
            // Set the time of flight.
            memcpy(&reading.first, pData, sizeof(float));
            pData += sizeof(float);

            // Set the resonance.
            memcpy(&reading.second, pData, sizeof(float));
            pData += sizeof(float);
        }
    }
    return waveformDataList;
}

bool DataFrameValidator(const UltrasonicsDataFrameDesc& dataFrameDesc) {

    if (dataFrameDesc.receiversIdList.size() != dataFrameDesc.receiversReadingsCountList.size()) {
        LOG(ERROR) << "Size mismatch of receiversIdList and receiversReadingsCountList";
        return false;
    }

    if(!dataFrameDesc.waveformsData.valid()) {
        LOG(ERROR) << "Data frame does not valid hidl memory";
        return false;
    }

    // Check total bytes from dataFrameDesc are within the shared memory size.
    int totalWaveformDataBytesSize = 0;
    for (int i = 0; i < dataFrameDesc.receiversIdList.size(); i++) {
        totalWaveformDataBytesSize = 1 + (4 * 2 * dataFrameDesc.receiversReadingsCountList[i]);
    }
    if (totalWaveformDataBytesSize > dataFrameDesc.waveformsData.size()) {
        LOG(ERROR) << "Total waveform data bytes in desc exceed shared memory size";
        return false;
    }

    sp<IMemory> pIMemory = mapMemory(dataFrameDesc.waveformsData);
    if(pIMemory.get() == nullptr) {
        LOG(ERROR) << "Failed to map hidl memory";
        return false;
    }

    uint8_t* pData = (uint8_t*)((void*)pIMemory->getPointer());
    if(pData == nullptr) {
        LOG(ERROR) << "Failed getPointer from mapped shared memory";
        return false;
    }

    const std::vector<WaveformData> waveformDataList = DeSerializeWaveformData(
            dataFrameDesc.receiversReadingsCountList, pData);

    // Verify the waveforms data.
    for(int i = 0; i < waveformDataList.size(); i++) {
        if (waveformDataList[i].receiverId != dataFrameDesc.receiversIdList[i]) {
            LOG(ERROR) << "Receiver Id mismatch";
            return false;
        }
        for(auto& reading : waveformDataList[i].readings) {
            if (reading.second < 0.0f || reading.second > 1.0f) {
                LOG(ERROR) << "Resonance reading is not in range [0, 1]";
                return false;
            }
        }
    }
    return true;
}

Return<void> FrameHandlerUltrasonics::deliverDataFrame(
        const UltrasonicsDataFrameDesc& dataFrameDesc) {
    LOG(DEBUG) << "FrameHandlerUltrasonics::receiveFrames";

    mReceiveFramesCount++;
    mLastReceivedFrames = dataFrameDesc;

    if(!DataFrameValidator(dataFrameDesc)) {
        mAllFramesValid = false;
    }

    // Send done with data frame.
    mEvsUltrasonicsArray->doneWithDataFrame(dataFrameDesc);

    return android::hardware::Void();
}

bool FrameHandlerUltrasonics::checkEventReceived(EvsEventDesc evsEvent) {
    LOG(DEBUG) << "FrameHandlerUltrasonics::checkEventReceived";
    int size = mReceivedEvents.size(); // work around
    LOG(DEBUG) << "Received event number: " << size;
    auto iter = find(mReceivedEvents.begin(), mReceivedEvents.end(), evsEvent);
    return iter != mReceivedEvents.end();
}

int FrameHandlerUltrasonics::getReceiveFramesCount() {
    return mReceiveFramesCount;
}

bool FrameHandlerUltrasonics::areAllFramesValid() {
    return mAllFramesValid;
}
+53 −0
Original line number Diff line number Diff line
/*
 * Copyright 2020 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 FRAME_HANDLER_ULTRASONICS_H
#define FRAME_HANDLER_ULTRASONICS_H

#include <android/hardware/automotive/evs/1.1/types.h>
#include <android/hardware/automotive/evs/1.1/IEvsUltrasonicsArrayStream.h>
#include <android/hardware/automotive/evs/1.1/IEvsUltrasonicsArray.h>

#include <vector>

class FrameHandlerUltrasonics : public
        android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArrayStream {
public:
    FrameHandlerUltrasonics(
            android::sp<android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArray>
            pEvsUltrasonicsArray);

    // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArrayStream
    android::hardware::Return<void> notify(
            const android::hardware::automotive::evs::V1_1::EvsEventDesc& evsEvent) override;
    android::hardware::Return<void> deliverDataFrame(
            const android::hardware::automotive::evs::V1_1::UltrasonicsDataFrameDesc&
             dataFrameDesc) override;

    bool checkEventReceived(android::hardware::automotive::evs::V1_1::EvsEventDesc evsEvent);
    int getReceiveFramesCount();
    bool areAllFramesValid();

private:
    android::sp<android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArray>
            mEvsUltrasonicsArray;
    android::hardware::automotive::evs::V1_1::UltrasonicsDataFrameDesc mLastReceivedFrames;
    std::vector<android::hardware::automotive::evs::V1_1::EvsEventDesc> mReceivedEvents;
    int mReceiveFramesCount;
    bool mAllFramesValid = true;
};

#endif //FRAME_HANDLER_ULTRASONICS_H
+124 −2
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ static const float kNanoToSeconds = 0.000000001f;


#include "FrameHandler.h"
#include "FrameHandlerUltrasonics.h"

#include <cstdio>
#include <cstring>
@@ -151,9 +152,21 @@ protected:
                }
            }
        );
    }

    void loadUltrasonicsArrayList() {
        // SetUp() must run first!
        assert(pEnumerator != nullptr);

        // We insist on at least one camera for EVS to pass any camera tests
        ASSERT_GE(cameraInfo.size(), 1u);
        // Get the ultrasonics array list
        pEnumerator->getUltrasonicsArrayList([this](hidl_vec<UltrasonicsArrayDesc> ultraList) {
            ALOGI("Ultrasonics array list callback received %zu arrays", ultraList.size());
            ultrasonicsArraysInfo.reserve(ultraList.size());
            for (auto&& ultraArray : ultraList) {
                ALOGI("Found ultrasonics array %s", ultraArray.ultrasonicsArrayId.c_str());
                ultrasonicsArraysInfo.push_back(ultraArray);
            }
        });
    }

    bool isLogicalCamera(const camera_metadata_t *metadata) {
@@ -240,6 +253,11 @@ protected:
                                                   // is HW module implementation.
    std::deque<wp<IEvsCamera_1_1>>  activeCameras; // A list of active camera handles that are
                                                   // needed to be cleaned up.
    std::vector<UltrasonicsArrayDesc>
            ultrasonicsArraysInfo;                           // Empty unless/until
                                                             // loadUltrasonicsArrayList() is called
    std::deque<wp<IEvsCamera_1_1>> activeUltrasonicsArrays;  // A list of active ultrasonic array
                                                             // handles that are to be cleaned up.
};


@@ -2209,6 +2227,110 @@ TEST_F(EvsHidlTest, LogicalCameraMetadata) {
}


/*
 * UltrasonicsArrayOpenClean:
 * Opens each ultrasonics arrays reported by the enumerator and then explicitly closes it via a
 * call to closeUltrasonicsArray. Then repeats the test to ensure all ultrasonics arrays
 * can be reopened.
 */
TEST_F(EvsHidlTest, UltrasonicsArrayOpenClean) {
    ALOGI("Starting UltrasonicsArrayOpenClean test");

    // Get the ultrasonics array list
    loadUltrasonicsArrayList();

    // Open and close each ultrasonics array twice
    for (auto&& ultraInfo : ultrasonicsArraysInfo) {
        for (int pass = 0; pass < 2; pass++) {
            sp<IEvsUltrasonicsArray> pUltrasonicsArray =
                    pEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId);
            ASSERT_NE(pUltrasonicsArray, nullptr);

            // Verify that this ultrasonics array self-identifies correctly
            pUltrasonicsArray->getUltrasonicArrayInfo([&ultraInfo](UltrasonicsArrayDesc desc) {
                ALOGD("Found ultrasonics array %s", ultraInfo.ultrasonicsArrayId.c_str());
                EXPECT_EQ(ultraInfo.ultrasonicsArrayId, desc.ultrasonicsArrayId);
            });

            // Explicitly close the ultrasonics array so resources are released right away
            pEnumerator->closeUltrasonicsArray(pUltrasonicsArray);
        }
    }
}


// Starts a stream and verifies all data received is valid.
TEST_F(EvsHidlTest, UltrasonicsVerifyStreamData) {
    ALOGI("Starting UltrasonicsVerifyStreamData");

    // Get the ultrasonics array list
    loadUltrasonicsArrayList();

    // For each ultrasonics array.
    for (auto&& ultraInfo : ultrasonicsArraysInfo) {
        ALOGD("Testing ultrasonics array: %s", ultraInfo.ultrasonicsArrayId.c_str());

        sp<IEvsUltrasonicsArray> pUltrasonicsArray =
                pEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId);
        ASSERT_NE(pUltrasonicsArray, nullptr);

        sp<FrameHandlerUltrasonics> frameHandler = new FrameHandlerUltrasonics(pUltrasonicsArray);

        // Start stream.
        EvsResult result = pUltrasonicsArray->startStream(frameHandler);
        ASSERT_EQ(result, EvsResult::OK);

        // Wait 5 seconds to receive frames.
        sleep(5);

        // Stop stream.
        pUltrasonicsArray->stopStream();

        EXPECT_GT(frameHandler->getReceiveFramesCount(), 0);
        EXPECT_TRUE(frameHandler->areAllFramesValid());

        // Explicitly close the ultrasonics array so resources are released right away
        pEnumerator->closeUltrasonicsArray(pUltrasonicsArray);
    }
}


// Sets frames in flight before and after start of stream and verfies success.
TEST_F(EvsHidlTest, UltrasonicsSetFramesInFlight) {
    ALOGI("Starting UltrasonicsSetFramesInFlight");

    // Get the ultrasonics array list
    loadUltrasonicsArrayList();

    // For each ultrasonics array.
    for (auto&& ultraInfo : ultrasonicsArraysInfo) {
        ALOGD("Testing ultrasonics array: %s", ultraInfo.ultrasonicsArrayId.c_str());

        sp<IEvsUltrasonicsArray> pUltrasonicsArray =
                pEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId);
        ASSERT_NE(pUltrasonicsArray, nullptr);

        EvsResult result = pUltrasonicsArray->setMaxFramesInFlight(10);
        EXPECT_EQ(result, EvsResult::OK);

        sp<FrameHandlerUltrasonics> frameHandler = new FrameHandlerUltrasonics(pUltrasonicsArray);

        // Start stream.
        result = pUltrasonicsArray->startStream(frameHandler);
        ASSERT_EQ(result, EvsResult::OK);

        result = pUltrasonicsArray->setMaxFramesInFlight(5);
        EXPECT_EQ(result, EvsResult::OK);

        // Stop stream.
        pUltrasonicsArray->stopStream();

        // Explicitly close the ultrasonics array so resources are released right away
        pEnumerator->closeUltrasonicsArray(pUltrasonicsArray);
    }
}


int main(int argc, char** argv) {
    ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance());
    ::testing::InitGoogleTest(&argc, argv);