| // Copyright 2019 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 "aml-light.h" |
| |
| #include <fidl/fuchsia.hardware.pwm/cpp/wire_test_base.h> |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/async-loop/default.h> |
| #include <lib/async/default.h> |
| #include <lib/async_patterns/testing/cpp/dispatcher_bound.h> |
| |
| #include <cmath> |
| #include <list> |
| |
| #include <fbl/alloc_checker.h> |
| #include <zxtest/zxtest.h> |
| |
| #include "src/devices/gpio/testing/fake-gpio/fake-gpio.h" |
| |
| bool operator==(const fuchsia_hardware_pwm::wire::PwmConfig& lhs, |
| const fuchsia_hardware_pwm::wire::PwmConfig& rhs) { |
| return (lhs.polarity == rhs.polarity) && (lhs.period_ns == rhs.period_ns) && |
| (lhs.duty_cycle == rhs.duty_cycle) && |
| (lhs.mode_config.count() == rhs.mode_config.count()) && |
| (reinterpret_cast<aml_pwm::mode_config*>(lhs.mode_config.data())->mode == |
| reinterpret_cast<aml_pwm::mode_config*>(rhs.mode_config.data())->mode); |
| } |
| |
| namespace aml_light { |
| class MockPwmServer final : public fidl::testing::WireTestBase<fuchsia_hardware_pwm::Pwm> { |
| public: |
| void SetConfig(SetConfigRequestView request, SetConfigCompleter::Sync& completer) override { |
| ASSERT_GT(expect_configs_.size(), 0); |
| auto expect_config = expect_configs_.front(); |
| |
| ASSERT_EQ(request->config, expect_config); |
| |
| expect_configs_.erase(expect_configs_.begin()); |
| mode_config_buffers_.pop_front(); |
| completer.ReplySuccess(); |
| } |
| void Enable(EnableCompleter::Sync& completer) override { |
| ASSERT_TRUE(expect_enable_); |
| expect_enable_ = false; |
| completer.ReplySuccess(); |
| } |
| |
| void ExpectEnable() { expect_enable_ = true; } |
| |
| void ExpectSetConfig(fuchsia_hardware_pwm::wire::PwmConfig config) { |
| std::unique_ptr<uint8_t[]>& mode_config = |
| mode_config_buffers_.emplace_back(std::make_unique<uint8_t[]>(config.mode_config.count())); |
| std::copy_n(config.mode_config.data(), config.mode_config.count(), mode_config.get()); |
| |
| config.mode_config = |
| fidl::VectorView<uint8_t>::FromExternal(mode_config.get(), config.mode_config.count()); |
| expect_configs_.push_back(config); |
| } |
| |
| void NotImplemented_(const std::string& name, ::fidl::CompleterBase& completer) override { |
| completer.Close(ZX_ERR_NOT_SUPPORTED); |
| } |
| |
| fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm> BindServer() { |
| zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_pwm::Pwm>(); |
| EXPECT_TRUE(endpoints.is_ok()); |
| fidl::BindServer(async_get_default_dispatcher(), std::move(endpoints->server), this); |
| return fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm>(std::move(endpoints->client)); |
| } |
| |
| void VerifyAndClear() { |
| ASSERT_EQ(expect_configs_.size(), 0); |
| ASSERT_EQ(mode_config_buffers_.size(), 0); |
| ASSERT_FALSE(expect_enable_); |
| } |
| |
| private: |
| std::list<fuchsia_hardware_pwm::wire::PwmConfig> expect_configs_; |
| std::list<std::unique_ptr<uint8_t[]>> mode_config_buffers_; |
| |
| bool expect_enable_ = false; |
| }; |
| |
| class FakeAmlLight : public AmlLight { |
| public: |
| static zx::result<std::unique_ptr<FakeAmlLight>> Create( |
| fidl::ClientEnd<fuchsia_hardware_gpio::Gpio> gpio, |
| std::optional<fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm>> pwm, |
| zx_duration_t pwm_period = 170'625) { |
| fbl::AllocChecker ac; |
| std::unique_ptr device = fbl::make_unique_checked<FakeAmlLight>(&ac); |
| if (!ac.check()) { |
| return zx::error(ZX_ERR_NO_MEMORY); |
| } |
| LightDevice& light = device->lights_.emplace_back( |
| "test", std::move(gpio), pwm.has_value() ? std::move(pwm) : std::nullopt, |
| zx::duration(pwm_period)); |
| if (zx_status_t status = light.Init(true); status != ZX_OK) { |
| return zx::error(status); |
| } |
| return zx::ok(std::move(device)); |
| } |
| |
| explicit FakeAmlLight() : AmlLight(nullptr) {} |
| }; |
| |
| namespace { |
| |
| class AmlLightTest : public zxtest::Test { |
| public: |
| void SetUp() override { EXPECT_OK(fidl_servers_loop_.StartThread("fidl-servers")); } |
| |
| void Init() { |
| loop_ = std::make_unique<async::Loop>(&kAsyncLoopConfigAttachToCurrentThread); |
| zx::result server = fidl::CreateEndpoints(&client_); |
| ASSERT_OK(server); |
| ASSERT_OK(loop_->StartThread("aml-light-test-loop")); |
| fidl::BindServer(loop_->dispatcher(), std::move(server.value()), light_.get()); |
| } |
| |
| void TearDown() override { |
| pwm_.SyncCall(&MockPwmServer::VerifyAndClear); |
| |
| loop_->Quit(); |
| loop_->JoinThreads(); |
| } |
| |
| protected: |
| friend class FakeAmlLight; |
| |
| std::unique_ptr<FakeAmlLight> light_; |
| |
| async::Loop fidl_servers_loop_{&kAsyncLoopConfigNoAttachToCurrentThread}; |
| async_patterns::TestDispatcherBound<MockPwmServer> pwm_{fidl_servers_loop_.dispatcher(), |
| std::in_place}; |
| async_patterns::TestDispatcherBound<fake_gpio::FakeGpio> gpio_{fidl_servers_loop_.dispatcher(), |
| std::in_place}; |
| |
| fidl::ClientEnd<fuchsia_hardware_light::Light> client_; |
| |
| private: |
| std::unique_ptr<async::Loop> loop_; |
| }; |
| |
| TEST_F(AmlLightTest, GetInfoTest1) { |
| pwm_.SyncCall(&MockPwmServer::ExpectEnable); |
| aml_pwm::mode_config regular = {aml_pwm::Mode::kOn, {}}; |
| fuchsia_hardware_pwm::wire::PwmConfig init_config = { |
| false, 170625, 100.0, |
| fidl::VectorView<uint8_t>::FromExternal(reinterpret_cast<uint8_t*>(®ular), |
| sizeof(regular))}; |
| pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, init_config); |
| |
| auto gpio_client = gpio_.SyncCall(&fake_gpio::FakeGpio::Connect); |
| auto pwm_client = pwm_.SyncCall(&MockPwmServer::BindServer); |
| zx::result light = FakeAmlLight::Create(std::move(gpio_client), std::move(pwm_client)); |
| ASSERT_OK(light); |
| light_ = std::move(light.value()); |
| Init(); |
| |
| fidl::WireSyncClient<fuchsia_hardware_light::Light> client(std::move(client_)); |
| auto result = client->GetInfo(0); |
| EXPECT_OK(result.status()); |
| EXPECT_FALSE(result->is_error()); |
| EXPECT_EQ(strcmp(result->value()->info.name.begin(), "test"), 0); |
| EXPECT_EQ(result->value()->info.capability, Capability::kBrightness); |
| } |
| |
| TEST_F(AmlLightTest, GetInfoTest2) { |
| gpio_.SyncCall(&fake_gpio::FakeGpio::SetCurrentState, |
| fake_gpio::State{.polarity = fuchsia_hardware_gpio::GpioPolarity::kHigh, |
| .sub_state = fake_gpio::WriteSubState{.value = 0}}); |
| auto gpio_client = gpio_.SyncCall(&fake_gpio::FakeGpio::Connect); |
| zx::result light = FakeAmlLight::Create(std::move(gpio_client), std::nullopt); |
| ASSERT_OK(light); |
| light_ = std::move(light.value()); |
| Init(); |
| EXPECT_EQ(1, gpio_.SyncCall(&fake_gpio::FakeGpio::GetWriteValue)); |
| |
| fidl::WireSyncClient<fuchsia_hardware_light::Light> client(std::move(client_)); |
| auto result = client->GetInfo(0); |
| EXPECT_OK(result.status()); |
| EXPECT_FALSE(result->is_error()); |
| EXPECT_EQ(strcmp(result->value()->info.name.begin(), "test"), 0); |
| EXPECT_EQ(result->value()->info.capability, Capability::kSimple); |
| } |
| |
| TEST_F(AmlLightTest, SetValueTest1) { |
| gpio_.SyncCall(&fake_gpio::FakeGpio::SetCurrentState, |
| fake_gpio::State{.polarity = fuchsia_hardware_gpio::GpioPolarity::kHigh, |
| .sub_state = fake_gpio::WriteSubState{.value = 0}}); |
| auto gpio_client = gpio_.SyncCall(&fake_gpio::FakeGpio::Connect); |
| zx::result light = FakeAmlLight::Create(std::move(gpio_client), std::nullopt); |
| ASSERT_OK(light); |
| light_ = std::move(light.value()); |
| Init(); |
| EXPECT_EQ(1, gpio_.SyncCall(&fake_gpio::FakeGpio::GetWriteValue)); |
| |
| fidl::WireSyncClient<fuchsia_hardware_light::Light> client(std::move(client_)); |
| { |
| auto get_result = client->GetCurrentSimpleValue(0); |
| EXPECT_OK(get_result.status()); |
| EXPECT_FALSE(get_result->is_error()); |
| EXPECT_EQ(get_result->value()->value, true); |
| } |
| { |
| auto get_result = client->GetCurrentSimpleValue(0); |
| EXPECT_OK(get_result.status()); |
| EXPECT_FALSE(get_result->is_error()); |
| EXPECT_EQ(get_result->value()->value, true); |
| } |
| { |
| auto set_result = client->SetSimpleValue(0, false); |
| EXPECT_EQ(0, gpio_.SyncCall(&fake_gpio::FakeGpio::GetWriteValue)); |
| EXPECT_OK(set_result.status()); |
| EXPECT_FALSE(set_result->is_error()); |
| } |
| { |
| auto get_result = client->GetCurrentSimpleValue(0); |
| EXPECT_OK(get_result.status()); |
| EXPECT_FALSE(get_result->is_error()); |
| EXPECT_EQ(get_result->value()->value, false); |
| } |
| { |
| auto set_result = client->SetSimpleValue(0, true); |
| EXPECT_EQ(1, gpio_.SyncCall(&fake_gpio::FakeGpio::GetWriteValue)); |
| EXPECT_OK(set_result.status()); |
| EXPECT_FALSE(set_result->is_error()); |
| } |
| { |
| auto set_result = client->SetSimpleValue(0, true); |
| EXPECT_EQ(1, gpio_.SyncCall(&fake_gpio::FakeGpio::GetWriteValue)); |
| EXPECT_OK(set_result.status()); |
| EXPECT_FALSE(set_result->is_error()); |
| } |
| { |
| auto get_result = client->GetCurrentSimpleValue(0); |
| EXPECT_OK(get_result.status()); |
| EXPECT_FALSE(get_result->is_error()); |
| EXPECT_EQ(get_result->value()->value, true); |
| } |
| } |
| |
| TEST_F(AmlLightTest, SetValueTest2) { |
| pwm_.SyncCall(&MockPwmServer::ExpectEnable); |
| aml_pwm::mode_config regular = {aml_pwm::Mode::kOn, {}}; |
| fuchsia_hardware_pwm::wire::PwmConfig config = { |
| false, 170625, 100.0, |
| fidl::VectorView<uint8_t>::FromExternal(reinterpret_cast<uint8_t*>(®ular), |
| sizeof(regular))}; |
| pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, config); |
| |
| auto gpio_client = gpio_.SyncCall(&fake_gpio::FakeGpio::Connect); |
| auto pwm_client = pwm_.SyncCall(&MockPwmServer::BindServer); |
| zx::result light = FakeAmlLight::Create(std::move(gpio_client), std::move(pwm_client)); |
| ASSERT_OK(light); |
| light_ = std::move(light.value()); |
| Init(); |
| |
| fidl::WireSyncClient<fuchsia_hardware_light::Light> client(std::move(client_)); |
| { |
| auto get_result = client->GetCurrentBrightnessValue(0); |
| EXPECT_OK(get_result.status()); |
| EXPECT_FALSE(get_result->is_error()); |
| EXPECT_EQ(get_result->value()->value, 1.0); |
| } |
| { |
| auto get_result = client->GetCurrentBrightnessValue(0); |
| EXPECT_OK(get_result.status()); |
| EXPECT_FALSE(get_result->is_error()); |
| EXPECT_EQ(get_result->value()->value, 1.0); |
| } |
| { |
| config.duty_cycle = 0; |
| pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, config); |
| auto set_result = client->SetBrightnessValue(0, 0.0); |
| EXPECT_OK(set_result.status()); |
| EXPECT_FALSE(set_result->is_error()); |
| } |
| { |
| auto get_result = client->GetCurrentBrightnessValue(0); |
| EXPECT_OK(get_result.status()); |
| EXPECT_FALSE(get_result->is_error()); |
| EXPECT_EQ(get_result->value()->value, 0.0); |
| } |
| { |
| config.duty_cycle = 20.0; |
| pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, config); |
| auto set_result = client->SetBrightnessValue(0, 0.2); |
| EXPECT_OK(set_result.status()); |
| EXPECT_FALSE(set_result->is_error()); |
| } |
| { |
| pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, config); |
| auto set_result = client->SetBrightnessValue(0, 0.2); |
| EXPECT_OK(set_result.status()); |
| EXPECT_FALSE(set_result->is_error()); |
| } |
| { |
| auto get_result = client->GetCurrentBrightnessValue(0); |
| EXPECT_OK(get_result.status()); |
| EXPECT_FALSE(get_result->is_error()); |
| EXPECT_EQ(get_result->value()->value, 0.2); |
| } |
| } |
| |
| TEST_F(AmlLightTest, SetInvalidValueTest) { |
| pwm_.SyncCall(&MockPwmServer::ExpectEnable); |
| aml_pwm::mode_config regular = {aml_pwm::Mode::kOn, {}}; |
| fuchsia_hardware_pwm::wire::PwmConfig config = { |
| false, 170625, 100.0, |
| fidl::VectorView<uint8_t>::FromExternal(reinterpret_cast<uint8_t*>(®ular), |
| sizeof(regular))}; |
| pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, config); |
| |
| auto gpio_client = gpio_.SyncCall(&fake_gpio::FakeGpio::Connect); |
| auto pwm_client = pwm_.SyncCall(&MockPwmServer::BindServer); |
| zx::result light = FakeAmlLight::Create(std::move(gpio_client), std::move(pwm_client)); |
| ASSERT_OK(light); |
| light_ = std::move(light.value()); |
| Init(); |
| |
| fidl::WireSyncClient<fuchsia_hardware_light::Light> client(std::move(client_)); |
| { |
| auto get_result = client->GetCurrentBrightnessValue(0); |
| EXPECT_OK(get_result.status()); |
| EXPECT_FALSE(get_result->is_error()); |
| EXPECT_EQ(get_result->value()->value, 1.0); |
| } |
| { |
| auto set_result = client->SetBrightnessValue(0, 3.2); |
| EXPECT_OK(set_result.status()); |
| EXPECT_TRUE(set_result->is_error()); |
| } |
| { |
| auto get_result = client->GetCurrentBrightnessValue(0); |
| EXPECT_OK(get_result.status()); |
| EXPECT_FALSE(get_result->is_error()); |
| EXPECT_EQ(get_result->value()->value, 1.0); |
| } |
| { |
| auto set_result = client->SetBrightnessValue(0, -0.225); |
| EXPECT_OK(set_result.status()); |
| EXPECT_TRUE(set_result->is_error()); |
| } |
| { |
| auto set_result = client->SetBrightnessValue(0, NAN); |
| EXPECT_OK(set_result.status()); |
| EXPECT_TRUE(set_result->is_error()); |
| } |
| { |
| auto get_result = client->GetCurrentBrightnessValue(0); |
| EXPECT_OK(get_result.status()); |
| EXPECT_FALSE(get_result->is_error()); |
| EXPECT_EQ(get_result->value()->value, 1.0); |
| } |
| } |
| |
| TEST_F(AmlLightTest, SetValueTestNelson) { |
| pwm_.SyncCall(&MockPwmServer::ExpectEnable); |
| aml_pwm::mode_config regular = {aml_pwm::Mode::kOn, {}}; |
| fuchsia_hardware_pwm::wire::PwmConfig config = { |
| false, 500'000, 100.0, |
| fidl::VectorView<uint8_t>::FromExternal(reinterpret_cast<uint8_t*>(®ular), |
| sizeof(regular))}; |
| pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, config); |
| |
| auto gpio_client = gpio_.SyncCall(&fake_gpio::FakeGpio::Connect); |
| auto pwm_client = pwm_.SyncCall(&MockPwmServer::BindServer); |
| zx::result light = FakeAmlLight::Create(std::move(gpio_client), std::move(pwm_client), 500'000); |
| ASSERT_OK(light); |
| light_ = std::move(light.value()); |
| Init(); |
| |
| fidl::WireSyncClient<fuchsia_hardware_light::Light> client(std::move(client_)); |
| |
| { |
| config.duty_cycle = 0; |
| pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, config); |
| auto set_result = client->SetBrightnessValue(0, 0.0); |
| EXPECT_OK(set_result.status()); |
| EXPECT_FALSE(set_result->is_error()); |
| } |
| { |
| config.duty_cycle = 20.0; |
| pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, config); |
| auto set_result = client->SetBrightnessValue(0, 0.2); |
| EXPECT_OK(set_result.status()); |
| EXPECT_FALSE(set_result->is_error()); |
| } |
| { |
| config.duty_cycle = 100.0; |
| pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, config); |
| auto set_result = client->SetBrightnessValue(0, 1.0); |
| EXPECT_OK(set_result.status()); |
| EXPECT_FALSE(set_result->is_error()); |
| } |
| } |
| |
| } // namespace |
| |
| } // namespace aml_light |