blob: 4529e42b500a7f739438d95330d53fc19d48c8f1 [file] [log] [blame]
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "adc-buttons.h"
#include <lib/ddk/metadata.h>
#include <lib/driver/compat/cpp/device_server.h>
#include <lib/driver/testing/cpp/fixtures/gtest_fixture.h>
#include <gtest/gtest.h>
namespace adc_buttons_device {
constexpr uint32_t kChannel = 2;
constexpr uint32_t kReleaseThreshold = 30;
constexpr uint32_t kPressThreshold = 10;
constexpr uint32_t kPollingRateUsec = 1'000;
class FakeAdcServer : public fidl::Server<fuchsia_hardware_adc::Device> {
public:
void set_resolution(uint8_t resolution) { resolution_ = resolution; }
void set_sample(uint32_t sample) { sample_ = sample; }
void set_normalized_sample(float normalized_sample) { normalized_sample_ = normalized_sample; }
void GetResolution(GetResolutionCompleter::Sync& completer) override {
completer.Reply(fit::ok(resolution_));
}
void GetSample(GetSampleCompleter::Sync& completer) override {
completer.Reply(fit::ok(sample_));
}
void GetNormalizedSample(GetNormalizedSampleCompleter::Sync& completer) override {
completer.Reply(fit::ok(normalized_sample_));
}
fuchsia_hardware_adc::Service::InstanceHandler GetInstanceHandler() {
return fuchsia_hardware_adc::Service::InstanceHandler({
.device = bindings_.CreateHandler(this, fdf::Dispatcher::GetCurrent()->async_dispatcher(),
fidl::kIgnoreBindingClosure),
});
}
private:
uint8_t resolution_ = 0;
uint32_t sample_ = 0;
float normalized_sample_ = 0;
fidl::ServerBindingGroup<fuchsia_hardware_adc::Device> bindings_;
};
class TestEnv : public fdf_testing::Environment {
public:
zx::result<> Serve(fdf::OutgoingDirectory& to_driver_vfs) override {
device_server_.Init(component::kDefaultInstance, "");
// Serve metadata.
auto func_types = std::vector<fuchsia_input_report::ConsumerControlButton>{
fuchsia_input_report::ConsumerControlButton::kFunction};
auto func_adc_config = fuchsia_buttons::AdcButtonConfig()
.channel_idx(kChannel)
.release_threshold(kReleaseThreshold)
.press_threshold(kPressThreshold);
auto func_config = fuchsia_buttons::ButtonConfig::WithAdc(std::move(func_adc_config));
auto func_button = fuchsia_buttons::Button()
.types(std::move(func_types))
.button_config(std::move(func_config));
std::vector<fuchsia_buttons::Button> buttons;
buttons.emplace_back(std::move(func_button));
auto metadata =
fuchsia_buttons::Metadata().polling_rate_usec(kPollingRateUsec).buttons(std::move(buttons));
fit::result metadata_bytes = fidl::Persist(metadata);
EXPECT_TRUE(metadata_bytes.is_ok());
auto status = device_server_.AddMetadata(DEVICE_METADATA_BUTTONS, metadata_bytes->data(),
metadata_bytes->size());
EXPECT_EQ(ZX_OK, status);
device_server_.Serve(fdf::Dispatcher::GetCurrent()->async_dispatcher(), &to_driver_vfs);
auto result = to_driver_vfs.AddService<fuchsia_hardware_adc::Service>(
fake_adc_server_.GetInstanceHandler(), "adc-2");
return result;
}
void FakeAdcSetSample(uint32_t sample) { fake_adc_server_.set_sample(sample); }
private:
compat::DeviceServer device_server_;
FakeAdcServer fake_adc_server_;
};
class TestConfig final {
public:
static constexpr bool kDriverOnForeground = false;
static constexpr bool kAutoStartDriver = true;
static constexpr bool kAutoStopDriver = true;
using DriverType = adc_buttons::AdcButtons;
using EnvironmentType = TestEnv;
};
class AdcButtonsDeviceTest : public fdf_testing::DriverTestFixture<TestConfig> {
public:
void SetUp() override {
// Connect to InputDevice.
auto connect_result =
RunInNodeContext<zx::result<zx::channel>>([](fdf_testing::TestNode& node) {
return node.children().at("adc-buttons").ConnectToDevice();
});
EXPECT_EQ(ZX_OK, connect_result.status_value());
client_.Bind(
fidl::ClientEnd<fuchsia_input_report::InputDevice>(std::move(connect_result.value())));
}
void FakeAdcSetSample(uint32_t sample) {
RunInEnvironmentTypeContext([sample](TestEnv& env) { env.FakeAdcSetSample(sample); });
}
void DrainInitialReport(fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>& reader) {
auto result = reader->ReadInputReports();
EXPECT_EQ(ZX_OK, result.status());
ASSERT_FALSE(result.value().is_error());
auto& reports = result.value().value()->reports;
ASSERT_EQ(1, reports.count());
auto report = reports[0];
ASSERT_TRUE(report.has_event_time());
ASSERT_TRUE(report.has_consumer_control());
auto& consumer_control = report.consumer_control();
ASSERT_TRUE(consumer_control.has_pressed_buttons());
}
fidl::WireSyncClient<fuchsia_input_report::InputDevice>& client() { return client_; }
private:
fidl::WireSyncClient<fuchsia_input_report::InputDevice> client_;
};
TEST_F(AdcButtonsDeviceTest, GetDescriptorTest) {
auto result = client()->GetDescriptor();
ASSERT_TRUE(result.ok());
EXPECT_FALSE(result->descriptor.has_keyboard());
EXPECT_FALSE(result->descriptor.has_mouse());
EXPECT_FALSE(result->descriptor.has_sensor());
EXPECT_FALSE(result->descriptor.has_touch());
ASSERT_TRUE(result->descriptor.has_device_information());
EXPECT_EQ(result->descriptor.device_information().vendor_id(),
static_cast<uint32_t>(fuchsia_input_report::wire::VendorId::kGoogle));
EXPECT_EQ(result->descriptor.device_information().product_id(),
static_cast<uint32_t>(fuchsia_input_report::wire::VendorGoogleProductId::kAdcButtons));
EXPECT_EQ(result->descriptor.device_information().polling_rate(), kPollingRateUsec);
ASSERT_TRUE(result->descriptor.has_consumer_control());
ASSERT_TRUE(result->descriptor.consumer_control().has_input());
ASSERT_TRUE(result->descriptor.consumer_control().input().has_buttons());
EXPECT_EQ(result->descriptor.consumer_control().input().buttons().count(), 1);
EXPECT_EQ(result->descriptor.consumer_control().input().buttons()[0],
fuchsia_input_report::wire::ConsumerControlButton::kFunction);
}
TEST_F(AdcButtonsDeviceTest, ReadInputReportsTest) {
auto endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
auto result = client()->GetInputReportsReader(std::move(endpoints.server));
ASSERT_TRUE(result.ok());
// Ensure that the reader has been registered with the client before moving on.
ASSERT_TRUE(client()->GetDescriptor().ok());
auto reader =
fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(std::move(endpoints.client));
EXPECT_TRUE(reader.is_valid());
DrainInitialReport(reader);
FakeAdcSetSample(20);
// Wait for the device to pick this up.
usleep(2 * kPollingRateUsec);
{
auto result = reader->ReadInputReports();
EXPECT_EQ(ZX_OK, result.status());
ASSERT_FALSE(result.value().is_error());
auto& reports = result.value().value()->reports;
ASSERT_EQ(1, reports.count());
auto report = reports[0];
ASSERT_TRUE(report.has_event_time());
ASSERT_TRUE(report.has_consumer_control());
auto& consumer_control = report.consumer_control();
ASSERT_TRUE(consumer_control.has_pressed_buttons());
EXPECT_EQ(consumer_control.pressed_buttons().count(), 1);
EXPECT_EQ(consumer_control.pressed_buttons()[0],
fuchsia_input_report::wire::ConsumerControlButton::kFunction);
};
FakeAdcSetSample(40);
// Wait for the device to pick this up.
usleep(2 * kPollingRateUsec);
{
auto result = reader->ReadInputReports();
EXPECT_EQ(ZX_OK, result.status());
ASSERT_FALSE(result.value().is_error());
auto& reports = result.value().value()->reports;
ASSERT_EQ(1, reports.count());
auto report = reports[0];
ASSERT_TRUE(report.has_event_time());
ASSERT_TRUE(report.has_consumer_control());
auto& consumer_control = report.consumer_control();
ASSERT_TRUE(consumer_control.has_pressed_buttons());
EXPECT_EQ(consumer_control.pressed_buttons().count(), 0);
};
}
} // namespace adc_buttons_device