| // 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 "src/devices/power/drivers/fusb302/usb-pd-sink-policy.h" |
| |
| #include <lib/driver/logging/cpp/logger.h> |
| #include <lib/stdcompat/span.h> |
| |
| #include <cstdint> |
| |
| #include <zxtest/zxtest.h> |
| |
| #include "src/devices/power/drivers/fusb302/usb-pd-defs.h" |
| #include "src/devices/power/drivers/fusb302/usb-pd-message-objects.h" |
| #include "src/devices/power/drivers/fusb302/usb-pd-message-type.h" |
| #include "src/devices/power/drivers/fusb302/usb-pd-message.h" |
| |
| namespace usb_pd { |
| |
| namespace { |
| |
| constexpr SinkPolicyInfo kVim3PolicyInfo = { |
| .min_voltage_mv = 3'000, |
| .max_voltage_mv = 12'000, |
| .max_power_mw = 24'000, |
| }; |
| |
| Message SourceCapabilitiesMessage(cpp20::span<const uint32_t> power_data_objects) { |
| return Message(MessageType::kSourceCapabilities, MessageId(0), PowerRole::kSource, |
| SpecRevision::kRev2, DataRole::kDownstreamFacingPort, power_data_objects); |
| } |
| |
| uint32_t FixedPowerSupply(int32_t voltage_mv, int32_t current_ma) { |
| return static_cast<uint32_t>( |
| FixedPowerSupplyData().set_voltage_mv(voltage_mv).set_maximum_current_ma(current_ma)); |
| } |
| |
| class SinkPolicyTest : public zxtest::Test { |
| public: |
| void SetUp() override { fdf::Logger::SetGlobalInstance(&logger_); } |
| |
| void TearDown() override { fdf::Logger::SetGlobalInstance(nullptr); } |
| |
| private: |
| fdf::Logger logger_{"usb-pd-sink-policy-test", FUCHSIA_LOG_DEBUG, zx::socket{}, |
| fidl::WireClient<fuchsia_logger::LogSink>()}; |
| }; |
| |
| TEST_F(SinkPolicyTest, GetPowerRequestCommonFields) { |
| SinkPolicy sink_policy(kVim3PolicyInfo); |
| |
| const uint32_t power_data_objects[] = { |
| FixedPowerSupply(5'000, 3'000), |
| }; |
| sink_policy.DidReceiveSourceCapabilities(SourceCapabilitiesMessage(power_data_objects)); |
| |
| FixedVariableSupplyPowerRequestData fixed_request_data(sink_policy.GetPowerRequest()); |
| |
| EXPECT_FALSE(fixed_request_data.supports_power_give_back()); |
| EXPECT_TRUE(fixed_request_data.supports_usb_communications()); |
| EXPECT_TRUE(fixed_request_data.prefers_waiving_usb_suspend()); |
| EXPECT_FALSE(fixed_request_data.supports_unchunked_extended_messages()); |
| EXPECT_FALSE(fixed_request_data.supports_extended_power_range()); |
| } |
| |
| TEST_F(SinkPolicyTest, GetPowerRequestOnePowerDataObject) { |
| SinkPolicy sink_policy(kVim3PolicyInfo); |
| |
| const uint32_t power_data_objects[] = { |
| FixedPowerSupply(5'000, 3'000), |
| }; |
| sink_policy.DidReceiveSourceCapabilities(SourceCapabilitiesMessage(power_data_objects)); |
| |
| FixedVariableSupplyPowerRequestData fixed_request_data(sink_policy.GetPowerRequest()); |
| |
| EXPECT_EQ(1u, fixed_request_data.related_power_data_object_position()); |
| EXPECT_EQ(3'000, fixed_request_data.limit_current_ma()); |
| EXPECT_EQ(3'000, fixed_request_data.operating_current_ma()); |
| EXPECT_FALSE(fixed_request_data.capability_mismatch()); |
| } |
| |
| TEST_F(SinkPolicyTest, GetPowerRequestHighestPowerWins) { |
| SinkPolicy sink_policy(kVim3PolicyInfo); |
| |
| const uint32_t power_data_objects[] = { |
| FixedPowerSupply(5'000, 2'000), |
| FixedPowerSupply(9'000, 2'000), |
| FixedPowerSupply(12'000, 2'000), |
| }; |
| sink_policy.DidReceiveSourceCapabilities(SourceCapabilitiesMessage(power_data_objects)); |
| |
| FixedVariableSupplyPowerRequestData fixed_request_data(sink_policy.GetPowerRequest()); |
| |
| EXPECT_EQ(3u, fixed_request_data.related_power_data_object_position()); |
| EXPECT_EQ(2'000, fixed_request_data.limit_current_ma()); |
| EXPECT_EQ(2'000, fixed_request_data.operating_current_ma()); |
| EXPECT_FALSE(fixed_request_data.capability_mismatch()); |
| } |
| |
| TEST_F(SinkPolicyTest, GetPowerRequestCurrentCappedToPowerConsumption) { |
| SinkPolicy sink_policy(kVim3PolicyInfo); |
| |
| const uint32_t power_data_objects[] = { |
| FixedPowerSupply(5'000, 2'500), |
| FixedPowerSupply(9'000, 2'500), |
| FixedPowerSupply(12'000, 2'500), |
| }; |
| sink_policy.DidReceiveSourceCapabilities(SourceCapabilitiesMessage(power_data_objects)); |
| |
| FixedVariableSupplyPowerRequestData fixed_request_data(sink_policy.GetPowerRequest()); |
| |
| EXPECT_EQ(3u, fixed_request_data.related_power_data_object_position()); |
| EXPECT_EQ(2'000, fixed_request_data.limit_current_ma()); |
| EXPECT_EQ(2'000, fixed_request_data.operating_current_ma()); |
| EXPECT_FALSE(fixed_request_data.capability_mismatch()); |
| } |
| |
| TEST_F(SinkPolicyTest, GetPowerRequestMinimumVoltageThatHitsPowerTarget) { |
| SinkPolicy sink_policy(kVim3PolicyInfo); |
| |
| const uint32_t power_data_objects[] = { |
| FixedPowerSupply(5'000, 3'000), |
| FixedPowerSupply(9'000, 3'000), |
| FixedPowerSupply(12'000, 3'000), |
| }; |
| sink_policy.DidReceiveSourceCapabilities(SourceCapabilitiesMessage(power_data_objects)); |
| |
| FixedVariableSupplyPowerRequestData fixed_request_data(sink_policy.GetPowerRequest()); |
| |
| EXPECT_EQ(2u, fixed_request_data.related_power_data_object_position()); |
| EXPECT_EQ(2'660, fixed_request_data.limit_current_ma()); |
| EXPECT_EQ(2'660, fixed_request_data.operating_current_ma()); |
| EXPECT_FALSE(fixed_request_data.capability_mismatch()); |
| } |
| |
| TEST_F(SinkPolicyTest, GetPowerRequestIgnoresUnknownTypes) { |
| SinkPolicy sink_policy(kVim3PolicyInfo); |
| |
| // From Anker 30W Nano 511 model A2337. |
| const uint32_t power_data_objects[] = { |
| FixedPowerSupply(5'000, 3'000), |
| FixedPowerSupply(9'000, 3'000), |
| FixedPowerSupply(12'000, 2'500), |
| FixedPowerSupply(15'000, 2'000), |
| FixedPowerSupply(20'000, 1'500), |
| 0xc8dc213c, // PPS 3.30-11.00 V @ 3.00 A |
| 0xc9402128, // PPS 3.30-16.00 V @ 2.00 A |
| }; |
| sink_policy.DidReceiveSourceCapabilities(SourceCapabilitiesMessage(power_data_objects)); |
| |
| FixedVariableSupplyPowerRequestData fixed_request_data(sink_policy.GetPowerRequest()); |
| |
| EXPECT_EQ(2u, fixed_request_data.related_power_data_object_position()); |
| EXPECT_EQ(2'660, fixed_request_data.limit_current_ma()); |
| EXPECT_EQ(2'660, fixed_request_data.operating_current_ma()); |
| EXPECT_FALSE(fixed_request_data.capability_mismatch()); |
| } |
| |
| TEST_F(SinkPolicyTest, GetSinkCapabilitiesMultipleObjects) { |
| SinkPolicy sink_policy(kVim3PolicyInfo); |
| |
| cpp20::span<const uint32_t> sink_capabilities = sink_policy.GetSinkCapabilities(); |
| ASSERT_EQ(3u, sink_capabilities.size()); |
| |
| PowerData first_capability(sink_capabilities[0]); |
| ASSERT_EQ(PowerSupplyType::kFixedSupply, first_capability.supply_type()); |
| FixedPowerSupplyData first_fixed_supply(first_capability); |
| EXPECT_EQ(5'000, first_fixed_supply.voltage_mv()); |
| EXPECT_EQ(4'800, first_fixed_supply.maximum_current_ma()); |
| |
| PowerData second_capability(sink_capabilities[1]); |
| ASSERT_EQ(PowerSupplyType::kFixedSupply, second_capability.supply_type()); |
| FixedPowerSupplyData second_fixed_supply(second_capability); |
| EXPECT_EQ(9'000, second_fixed_supply.voltage_mv()); |
| EXPECT_EQ(2'660, second_fixed_supply.maximum_current_ma()); |
| |
| PowerData third_capability(sink_capabilities[2]); |
| ASSERT_EQ(PowerSupplyType::kFixedSupply, third_capability.supply_type()); |
| FixedPowerSupplyData third_fixed_supply(third_capability); |
| EXPECT_EQ(12'000, third_fixed_supply.voltage_mv()); |
| EXPECT_EQ(2'000, third_fixed_supply.maximum_current_ma()); |
| } |
| |
| } // namespace |
| |
| } // namespace usb_pd |