/*
 * 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.
 */
#define LOG_TAG "HidRawDeviceTest"

#include "HidRawDevice.h"
#include "HidRawSensor.h"
#include "HidSensorDef.h"
#include "SensorEventCallback.h"
#include "Utils.h"
#include "HidLog.h"
#include "StreamIoUtil.h"

namespace android {
namespace SensorHalExt {

/*
 * Host test that verifies HidRawDevice and HidRawSensor works correctly.
 */
class HidRawDeviceTest {
public:
    static void test(const char *devicePath) {
        using namespace Hid::Sensor::SensorTypeUsage;
        using HidUtil::hexdumpToStream;

        std::unordered_set<unsigned int> interestedUsage{
                ACCELEROMETER_3D, GYROMETER_3D, COMPASS_3D, CUSTOM};

        SP(HidRawDevice) device =
                std::make_shared<HidRawDevice>(std::string(devicePath), interestedUsage);
        const HidDevice::HidDeviceInfo &info = device->getDeviceInfo();

        LOG_V << "Sizeof descriptor: " << info.descriptor.size() << LOG_ENDL;
        LOG_V << "Descriptor: " << LOG_ENDL;
        hexdumpToStream(LOG_V, info.descriptor.begin(), info.descriptor.end());

        if (!device->isValid()) {
            LOG_E << "invalid device" << LOG_ENDL;
            return;
        }

        LOG_V << "Digest: " << LOG_ENDL;
        LOG_V << device->mDigestVector;

        std::vector<uint8_t> buffer;
        // Dump first few feature ID to help debugging.
        // If device does not implement all these features, it will show error messages.
        for (int featureId = 0; featureId <= 5; ++featureId) {
            if (!device->getFeature(featureId, &buffer)) {
                LOG_E << "cannot get feature " << featureId << LOG_ENDL;
            } else {
                LOG_V << "Dump of feature " << featureId << LOG_ENDL;
                hexdumpToStream(LOG_V, buffer.begin(), buffer.end());
            }
        }
        //
        // use HidRawSensor to operate the device, pick first digest
        //
        auto &reportDigest = device->mDigestVector[0];
        SP(HidRawSensor) sensor = std::make_shared<HidRawSensor>(
                device, reportDigest.fullUsage, reportDigest.packets);

        if (!sensor->isValid()) {
            LOG_E << "Sensor is not valid " << LOG_ENDL;
            return;
        }

        const sensor_t *s = sensor->getSensor();
        LOG_V << "Sensor name: " << s->name << ", vendor: " << s->vendor << LOG_ENDL;
        LOG_V << sensor->dump() << LOG_ENDL;

        class Callback : public SensorEventCallback {
            virtual int submitEvent(SP(BaseSensorObject) /*sensor*/, const sensors_event_t &e) {
                LOG_V << "sensor: " << e.sensor << ", type: " << e.type << ", ts: " << e.timestamp
                      << ", values (" << e.data[0] << ", " << e.data[1] << ", " << e.data[2] << ")"
                      << LOG_ENDL;
                return 1;
            }
        };
        Callback callback;
        sensor->setEventCallback(&callback);

        // Request sensor samples at to 10Hz (100ms)
        sensor->batch(100LL*1000*1000 /*ns*/, 0);
        sensor->enable(true);

        // get a couple of events
        for (size_t i = 0; i < 100; ++i) {
            uint8_t id;
            if (!device->receiveReport(&id, &buffer)) {
                LOG_E << "Receive report error" << LOG_ENDL;
                continue;
            }
            sensor->handleInput(id, buffer);
        }

        // clean up
        sensor->enable(false);

        LOG_V << "Done!" << LOG_ENDL;
    }
};
} //namespace SensorHalExt
} //namespace android

int main(int argc, char* argv[]) {
    if (argc != 2) {
        LOG_E << "Usage: " << argv[0] << " hidraw-dev-path" << LOG_ENDL;
        return -1;
    }
    android::SensorHalExt::HidRawDeviceTest::test(argv[1]);
    return 0;
}