blob: fa09978986993323eb02812c736d1953d7365a77 [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.
#ifndef SRC_DEVICES_POWER_DRIVERS_FUSB302_USB_PD_MESSAGE_OBJECTS_H_
#define SRC_DEVICES_POWER_DRIVERS_FUSB302_USB_PD_MESSAGE_OBJECTS_H_
// The comments in this file reference the USB Power Delivery Specification,
// downloadable at https://usb.org/document-library/usb-power-delivery
//
// usbpd3.1 is Revision 3.1, Version 1.7, published January 2023.
#include <zircon/assert.h>
#include <cstdint>
#include <hwreg/bitfields.h>
namespace usb_pd {
// Power supply type
//
// usbpd3.1 6.4.1 "Capabilities Message", Table 6-7 "Power Data Object"
enum class PowerSupplyType : uint8_t {
kFixedSupply = 0b00,
kBattery = 0b01,
kVariableSupply = 0b10,
kAugmentedPowerDataObject = 0b11, // APDO
};
// Precursor for all PDO (Power Data Object) types.
//
// Conceptually, the PDO in the USB PD spec is a sum type (like std::variant).
// Values have 32 bits, and the top 2 bits are used as the type discriminant.
// `PowerData` contains the logic for encoding and decoding the discriminant.
//
// This high-level representation is defined in the introduction of usbpd3.1
// usbpd3.1 6.4.1 "Capabilities Message". Subtypes are defined in the
// subsections of usbpd3.1 6.4.1.2 "Source_Capabilities Message" and of 6.4.1.3
// "Sink Capabilities Message"
struct PowerData {
public:
uint32_t bits;
// Discriminant for PDO (Powey Data Object) types.
DEF_ENUM_SUBFIELD(bits, PowerSupplyType, 31, 30, supply_type);
// Support explicit casting from uint32_t.
explicit PowerData(uint32_t bits) : bits(bits) {}
// Value type, copying is allowed.
PowerData(const PowerData&) = default;
PowerData& operator=(const PowerData&) = default;
// Trivially destructible.
~PowerData() = default;
// Support explicit casting to uint32_t.
explicit operator uint32_t() const { return bits; }
// In C++20, equality comparison can be defaulted.
bool operator==(const PowerData& other) const { return bits == other.bits; }
bool operator!=(const PowerData& other) const { return bits != other.bits; }
};
// A fixed power source's ability to briefly exceed the operating current.
//
// usbpd3.1 measures the Source's ability to handle spikes of three maximum
// durations (1ms / 2ms / 10ms) out of a 20ms duty cycle. In all cases, the
// current consumption over an entire duty cycle must still match the source's
// operating current. So, a spike must be compensated by lower current
// consumption during the rest of the duty cycle.
//
// usbpd3.1 6.4.1.2.2.8 "Peak Current"
enum class PeakCurrentSupport {
kNoOverload = 0b00,
// Overload limit: 150% for 1ms / 125% for 2ms / 110% for 10ms
kOverloadLevel1 = 0b01,
// Overload limit: 200% for 1ms / 150% for 2ms / 125% for 10ms
kOverloadLevel2 = 0b10,
// Overload limit: 200% for 1ms / 175% for 2ms / 150% for 10ms
kOverloadLevel3 = 0b11,
};
// Well-regulated power supply that maintains a fixed voltage.
//
// See `PowerData` for a general description of the PDO (Power Data Object)
// representation.
//
// Sink requirements for a well-regulated power supply are expressed via
// `SinkFixedPowerSupplyData` instances.
//
// usbpd3.1 6.4.1.2.2 "Fixed Supply Power Data Object"
class FixedPowerSupplyData {
private:
// Needed for the following to compile.
uint32_t bits_;
public:
// Indicates support for the PR_Swap message.
//
// Only used on the first PDO in a Source_Capabilities message.
DEF_SUBBIT(bits_, 29, supports_dual_role_power);
// Indicates whether the Sink must follow USB suspend rules.
//
// usbpd3.1 names this fieldĀ USB Suspend Supported, but it conveys
// requirements for the Sink. The requirements apply after a PD Contract is
// negotiated. 6.4.1.2.2 "USB Suspend Supported", states that a peripheral may
// draw up to 25 mW (pSnkSusp) and a hub may draw up to 125 mW (pHubSusp)
// during suspend, and defers to usb2, usb3.2 and usb4.
//
// Only used on the first PDO in a Source_Capabilities message.
DEF_SUBBIT(bits_, 28, requires_usb_suspend);
// True iff the Source draws power from an "unlimited" power source.
//
// Only used on the first PDO in a Source_Capabilities message.
DEF_SUBBIT(bits_, 27, has_unconstrained_power);
// Indicates if the Source can communicate over a USB data channel.
//
// The data channels are D+/- introduced in usb2.0 and SS Tx/Rx introduced in
// usb3.0.
//
// Only used on the first PDO in a Source_Capabilities message.
DEF_SUBBIT(bits_, 26, supports_usb_communications);
// Indicates support for the DR_Swap message.
//
// Only used on the first PDO in a Source_Capabilities message.
DEF_SUBBIT(bits_, 25, supports_dual_role_data);
// True iff the Port can receive messages with more than 26 data bytes.
//
// If true, the underlying BMC PHY must be designed to receive and transmit
// extended messages up to 260-bytes.
//
// Only used on the first PDO in a Source_Capabilities message.
DEF_SUBBIT(bits_, 24, supports_unchunked_extended_messages);
// True iff the Source supports EPR (Extended Power Range) messages.
//
// EPR power sources can supply more than 100 W.
//
// Only used on the first PDO in a Source_Capabilities message.
DEF_SUBBIT(bits_, 23, supports_extended_power_range);
// The power source's ability to briefly exceed the operating current.
DEF_ENUM_SUBFIELD(bits_, PeakCurrentSupport, 21, 20, peak_current);
// The power source's fixed voltage, in multiplies of 50 mV.
DEF_SUBFIELD(bits_, 19, 10, voltage_50mv);
// The maximum current offered by the source, in multiples of 10 mA.
DEF_SUBFIELD(bits_, 9, 0, maximum_current_10ma);
// The power source's fixed voltage, in mV (millivolts).
int32_t voltage_mv() const {
// The multiplication will not overflow (causing UB) because
// `voltage_50mv` is a 10-bit field. The maximum product is 51,150.
return static_cast<int32_t>(static_cast<int32_t>(voltage_50mv()) * 50);
}
FixedPowerSupplyData& set_voltage_mv(int32_t voltage_mv) {
return set_voltage_50mv(voltage_mv / 50);
}
// The maximum current offered by the source, in mA (milliamperes).
int32_t maximum_current_ma() const {
// The multiplication will not overflow (causing UB) because
// `maximum_current_10ma` is a 10-bit field. The maximum product is 10,240.
return static_cast<int32_t>(static_cast<int32_t>(maximum_current_10ma()) * 10);
}
FixedPowerSupplyData& set_maximum_current_ma(int32_t current_ma) {
return set_maximum_current_10ma(current_ma / 10);
}
// Debug-checked casting from PowerData.
explicit FixedPowerSupplyData(PowerData power_data) : bits_(power_data.bits) {
ZX_DEBUG_ASSERT(supply_type() == PowerSupplyType::kFixedSupply);
}
// Instance with all fields except for type set to zero.
//
// This is an invalid PDO (power data object). At a minimum, voltage and
// maximum current must be set before use in a PD message.
FixedPowerSupplyData()
: FixedPowerSupplyData(PowerData(0).set_supply_type(PowerSupplyType::kFixedSupply)) {}
// Value type, copying is allowed.
FixedPowerSupplyData(const FixedPowerSupplyData&) = default;
FixedPowerSupplyData& operator=(const FixedPowerSupplyData&) = default;
// Trivially destructible.
~FixedPowerSupplyData() = default;
// Support explicit casting to uint32_t.
explicit operator uint32_t() const { return bits_; }
// In C++20, equality comparison can be defaulted.
bool operator==(const FixedPowerSupplyData& other) const { return bits_ == other.bits_; }
bool operator!=(const FixedPowerSupplyData& other) const { return bits_ != other.bits_; }
private:
// Must be kFixedSupply.
DEF_ENUM_SUBFIELD(bits_, PowerSupplyType, 31, 30, supply_type);
};
// Power supply that lacks good voltage regulation, so its voltage may vary.
//
// See `PowerData` for a general description of the PDO (Power Data Object)
// representation.
//
// usbpd3.1 6.4.1.2.3 "Variable Supply (non-Battery) Power Data Object" and
// 6.4.1.3.2 "Variable Supply (non-Battery) Power Data Object".
class VariablePowerSupplyData {
private:
// Needed for the following to compile.
uint32_t bits_;
public:
// The power source's maximum voltage, in multiplies of 50 mV.
DEF_SUBFIELD(bits_, 29, 20, maximum_voltage_50mv);
// The power source's minimum voltage, in multiplies of 50 mV.
DEF_SUBFIELD(bits_, 19, 10, minimum_voltage_50mv);
// The maximum current offered by the source, in multiples of 10 mA.
DEF_SUBFIELD(bits_, 9, 0, maximum_current_10ma);
// The power source's maximum voltage, in mV (millivolts).
int32_t maximum_voltage_mv() const {
// The multiplication will not overflow (causing UB) because
// `maximum_voltage_50mv` is a 10-bit field. The maximum product is 51,150.
return static_cast<int32_t>(static_cast<int32_t>(maximum_voltage_50mv()) * 50);
}
VariablePowerSupplyData& set_maximum_voltage_mv(int32_t voltage_mv) {
return set_maximum_voltage_50mv(voltage_mv / 50);
}
// The power source's minimum voltage, in mV (millivolts).
int32_t minimum_voltage_mv() const {
return static_cast<int32_t>(static_cast<int32_t>(minimum_voltage_50mv()) * 50);
}
VariablePowerSupplyData& set_minimum_voltage_mv(int32_t voltage_mv) {
// The multiplication will not overflow (causing UB) because
// `minimum_voltage_50mv` is a 10-bit field. The maximum product is 51,150.
return set_minimum_voltage_50mv(voltage_mv / 50);
}
// The maximum current offered by the source, in mA (milliamperes).
int32_t maximum_current_ma() const {
// The multiplication will not overflow (causing UB) because
// `maximum_current_10ma` is a 10-bit field. The maximum product is 10,240.
return static_cast<int32_t>(static_cast<int32_t>(maximum_current_10ma()) * 10);
}
VariablePowerSupplyData& set_maximum_current_ma(int32_t current_ma) {
return set_maximum_current_10ma(current_ma / 10);
}
// Debug-checked casting from PowerData.
explicit VariablePowerSupplyData(PowerData power_data) : bits_(power_data.bits) {
ZX_DEBUG_ASSERT(supply_type() == PowerSupplyType::kVariableSupply);
}
// Instance with all fields except for type set to zero.
//
// This is an invalid PDO (power data object). At a minimum, voltage and
// maximum current must be set before use in a PD message.
VariablePowerSupplyData()
: VariablePowerSupplyData(PowerData(0).set_supply_type(PowerSupplyType::kVariableSupply)) {}
// Value type, copying is allowed.
VariablePowerSupplyData(const VariablePowerSupplyData&) = default;
VariablePowerSupplyData& operator=(const VariablePowerSupplyData&) = default;
// Trivially destructible.
~VariablePowerSupplyData() = default;
// Support explicit casting to uint32_t.
explicit operator uint32_t() const { return bits_; }
// In C++20, equality comparison can be defaulted.
bool operator==(const VariablePowerSupplyData& other) const { return bits_ == other.bits_; }
bool operator!=(const VariablePowerSupplyData& other) const { return bits_ != other.bits_; }
private:
// Must be kVariableSupply.
DEF_ENUM_SUBFIELD(bits_, PowerSupplyType, 31, 30, supply_type);
};
// Power supply that lacks good voltage regulation, so its voltage may vary.
//
// See `PowerData` for a general description of the PDO (Power Data Object)
// representation.
//
// usbpd3.1 6.4.1.2.4 "Variable Supply (non-Battery) Power Data Object" and
// 6.4.1.3.3 "Battery Supply Power Data Object"
class BatteryPowerSupplyData {
private:
// Needed for the following to compile.
uint32_t bits_;
public:
// The power source's maximum voltage, in multiplies of 50 mV.
DEF_SUBFIELD(bits_, 29, 20, maximum_voltage_50mv);
// The power source's minimum voltage, in multiplies of 50 mV.
DEF_SUBFIELD(bits_, 19, 10, minimum_voltage_50mv);
// The maximum power offered by the source, in multiples of 250 mW.
DEF_SUBFIELD(bits_, 9, 0, maximum_power_250mw);
// The power source's maximum voltage, in mV (millivolts).
int32_t maximum_voltage_mv() const {
// The multiplication will not overflow (causing UB) because
// `maximum_voltage_50mv` is a 10-bit field. The maximum product is 51,150.
return static_cast<int32_t>(static_cast<int32_t>(maximum_voltage_50mv()) * 50);
}
BatteryPowerSupplyData& set_maximum_voltage_mv(int32_t voltage_mv) {
return set_maximum_voltage_50mv(voltage_mv / 50);
}
// The power source's minimum voltage, in mV (millivolts).
int32_t minimum_voltage_mv() const {
// The multiplication will not overflow (causing UB) because
// `minimum_voltage_50mv` is a 10-bit field. The maximum product is 51,150.
return static_cast<int32_t>(static_cast<int32_t>(minimum_voltage_50mv()) * 50);
}
BatteryPowerSupplyData& set_minimum_voltage_mv(int32_t voltage_mv) {
return set_minimum_voltage_50mv(voltage_mv / 50);
}
// The maximum power offered by the source, in mW (milliwatts).
int32_t maximum_power_mw() const {
// The multiplication will not overflow (causing UB) because
// `maximum_power_250mw` is a 10-bit field. The maximum product is 255,750.
return static_cast<int32_t>(static_cast<int32_t>(maximum_power_250mw()) * 250);
}
BatteryPowerSupplyData& set_maximum_power_mw(int32_t power_ma) {
return set_maximum_power_250mw(power_ma / 250);
}
// Debug-checked casting from PowerData.
explicit BatteryPowerSupplyData(PowerData power_data) : bits_(power_data.bits) {
ZX_DEBUG_ASSERT(supply_type() == PowerSupplyType::kBattery);
}
// Instance with all fields except for type set to zero.
//
// This is an invalid PDO (power data object). At a minimum, voltage and
// maximum current must be set before use in a PD message.
BatteryPowerSupplyData()
: BatteryPowerSupplyData(PowerData(0).set_supply_type(PowerSupplyType::kBattery)) {}
// Value type, copying is allowed.
BatteryPowerSupplyData(const BatteryPowerSupplyData&) = default;
BatteryPowerSupplyData& operator=(const BatteryPowerSupplyData&) = default;
// Trivially destructible.
~BatteryPowerSupplyData() = default;
// Support explicit casting to uint32_t.
explicit operator uint32_t() const { return bits_; }
// In C++20, equality comparison can be defaulted.
bool operator==(const BatteryPowerSupplyData& other) const { return bits_ == other.bits_; }
bool operator!=(const BatteryPowerSupplyData& other) const { return bits_ != other.bits_; }
private:
// Must be kBattery.
DEF_ENUM_SUBFIELD(bits_, PowerSupplyType, 31, 30, supply_type);
};
// Values for `fast_swap_current_requirement` in SinkFixedPowerSupplyData.
//
// usbpd3.1 6.4.1.3.1 "Sink Fixed Supply Power Data Object", sub-table inside
// the "Fast Role Swap required USB Type-C Current" row
enum class FastSwapCurrentRequirement {
kNotSupported = 0b00,
kDefaultUsb = 0b01,
k1500mA = 0b10,
k3000mA = 0b11,
};
// Well-regulated power supply that maintains a fixed voltage.
//
// See `PowerData` for a general description of the PDO (Power Data Object)
// representation.
//
// Source capabilities for a well-regulated power supply are expressed via
// `FixedPowerSupplyData` instances.
//
// usbpd3.1 6.4.1.3.1 "Sink Fixed Supply Power Data Object"
class SinkFixedPowerSupplyData {
private:
// Needed for the following to compile.
uint32_t bits_;
public:
// Indicates support for the PR_Swap message.
//
// Only used on the first PDO in a Sink_Capabilities message.
DEF_SUBBIT(bits_, 29, supports_dual_role_power);
// True if the Sink needs more than vSafe5V for full functionality.
//
// Only used on the first PDO in a Sink_Capabilities message.
DEF_SUBBIT(bits_, 28, requires_more_than_5v);
// True iff the Sink draws power from an "unlimited" power source.
//
// Only used on the first PDO in a Sink_Capabilities message.
DEF_SUBBIT(bits_, 27, has_unconstrained_power);
// Indicates if the Sink can communicate over a USB data channel.
//
// The data channels are D+/- introduced in usb2.0 and SS Tx/Rx introduced in
// usb3.0.
//
// Only used on the first PDO in a Sink_Capabilities message.
DEF_SUBBIT(bits_, 26, supports_usb_communications);
// Indicates support for the DR_Swap message.
//
// Only used on the first PDO in a Sink_Capabilities message.
DEF_SUBBIT(bits_, 25, supports_dual_role_data);
// Current level needed by Sink after a Fast Role Swap.
//
// If the value is `kNotSupported`, the Source will not initiate a Fast Role
// Swap request.
//
// Only used on the first PDO in a Sink_Capabilities message.
DEF_ENUM_SUBFIELD(bits_, FastSwapCurrentRequirement, 24, 23, fast_swap_current_requirement);
// The power source's fixed voltage, in multiplies of 50 mV.
DEF_SUBFIELD(bits_, 19, 10, voltage_50mv);
// The maximum current offered by the source, in multiples of 10 mA.
DEF_SUBFIELD(bits_, 9, 0, maximum_current_10ma);
// The power source's fixed voltage, in mV (millivolts).
int32_t voltage_mv() const {
// The multiplication will not overflow (causing UB) because
// `voltage_50mv` is a 10-bit field. The maximum product is 51,150.
return static_cast<int32_t>(static_cast<int32_t>(voltage_50mv()) * 50);
}
SinkFixedPowerSupplyData& set_voltage_mv(int32_t voltage_mv) {
return set_voltage_50mv(voltage_mv / 50);
}
// The maximum current offered by the source, in mA (milliamperes).
int32_t maximum_current_ma() const {
// The multiplication will not overflow (causing UB) because
// `maximum_current_10ma` is a 10-bit field. The maximum product is 10,240.
return static_cast<int32_t>(static_cast<int32_t>(maximum_current_10ma()) * 10);
}
SinkFixedPowerSupplyData& set_maximum_current_ma(int32_t current_ma) {
return set_maximum_current_10ma(current_ma / 10);
}
// Debug-checked casting from PowerData.
explicit SinkFixedPowerSupplyData(PowerData power_data) : bits_(power_data.bits) {
ZX_DEBUG_ASSERT(supply_type() == PowerSupplyType::kFixedSupply);
}
// Instance with all fields except for type set to zero.
//
// This is an invalid PDO (power data object). At a minimum, voltage and
// maximum current must be set before use in a PD message.
SinkFixedPowerSupplyData()
: SinkFixedPowerSupplyData(PowerData(0).set_supply_type(PowerSupplyType::kFixedSupply)) {}
// Value type, copying is allowed.
SinkFixedPowerSupplyData(const SinkFixedPowerSupplyData&) = default;
SinkFixedPowerSupplyData& operator=(const SinkFixedPowerSupplyData&) = default;
// Trivially destructible.
~SinkFixedPowerSupplyData() = default;
// Support explicit casting to uint32_t.
explicit operator uint32_t() const { return bits_; }
// In C++20, equality comparison can be defaulted.
bool operator==(const SinkFixedPowerSupplyData& other) const { return bits_ == other.bits_; }
bool operator!=(const SinkFixedPowerSupplyData& other) const { return bits_ != other.bits_; }
private:
// Must be kFixedSupply.
DEF_ENUM_SUBFIELD(bits_, PowerSupplyType, 31, 30, supply_type);
};
// Fields common to all RDO (power Request Data Object) types.
//
// Conceptually, the RDO in the USB PD spec is a sum type (like std::variant).
// Values have 32 bits. The type discriminant is conveyed indirectly by the top
// 4 bits, which must be combined with out-of-band information. Concretely, the
// top 4 bits point to a PDO (Power Data Object) in a different message, and the
// PDO's type determines the RDO type.
//
// usbpd3.1 6.4.2 "Request Message" defines the high-level representation and
// the formats for all subtypes. Subsections define field semantics.
class PowerRequestData {
protected:
// Needed for the following to compile.
uint32_t bits_;
public:
// The position of the related PDO (Power Data Object) in a related message.
//
// Each RDO is based on a PDO in a message that lists power Source
// capabilities. The PDO subtype determines the RDO's subtype, and PDO fields
// set limits on the RDO fields. For example, an RDO based on a Fixed Supply
// PDO may not request more current than is advertised in the PDO.
//
// This field uses 1-based indexing, and the value 0 is reserved.
DEF_SUBFIELD(bits_, 31, 28, related_power_data_object_position);
// True if the Sink can honor GotoMin messages.
//
// If true, the Sink must react to GotoMin messages by reducing its power
// consumption to the minimum stated in the request object.
DEF_SUBBIT(bits_, 27, supports_power_give_back);
// True if the requested power is not sufficient for all the Sink's features.
//
// Sinks are required to submit a power Request even when the Source's
// capabilities are not sufficient for full operation. In that case, the Sink
// must request enough power for a subset of its features. The subset could be
// "do nothing" or "flash an LED indicating insufficient power".
//
// Sources may also alert the user when this bit is set. For example, some
// operating systems show insufficient power warnings.
DEF_SUBBIT(bits_, 26, capability_mismatch);
// Indicates if the Sink can communicate over a USB data channel.
//
// The data channels are D+/- introduced in usb2.0 and SS Tx/Rx introduced in
// usb3.0.
DEF_SUBBIT(bits_, 25, supports_usb_communications);
// If true, the Sink is asking the Source to waive USB Suspend requirements.
//
// This hint is meaningful when the related PDO (Power Data Object) has the
// `requires_usb_suspend` bit set. The Source may react to the hint by making
// a new offer (via a new Source_Capabilities message) that includes the same
// PDO without the `requires_usb_suspend` bit set.
//
// Setting this bit is not sufficient for the Sink to ignore USB Suspend
// requirements. The Sink is only free to disregard USB Suspend if it
// establishes a PD Contract based on a PDO without the `requires_usb_suspend`
// bit.
DEF_SUBBIT(bits_, 24, prefers_waiving_usb_suspend);
// True iff the Port can receive messages with more than 26 data bytes.
//
// If true, the underlying BMC PHY must be designed to receive and transmit
// extended messages up to 260-bytes.
DEF_SUBBIT(bits_, 23, supports_unchunked_extended_messages);
// True iff the Sink supports EPR (Extended Power Range) operation.
DEF_SUBBIT(bits_, 22, supports_extended_power_range);
// Used to decode the fields common to all RDOs.
explicit PowerRequestData(uint32_t bits) : bits_(bits) {
ZX_DEBUG_ASSERT(related_power_data_object_position() != 0);
}
// Value type, copying is allowed.
PowerRequestData(const PowerRequestData&) = default;
PowerRequestData& operator=(const PowerRequestData&) = default;
// Trivially destructible.
~PowerRequestData() = default;
// Support explicit casting to uint32_t.
explicit operator uint32_t() const { return bits_; }
protected:
// Distinguishes constructors that take a PDO position.
struct PositionTag {};
// Instance with all fields except for PDO position set to zero.
//
// This is most likely an invalid RDO. At a minimum, power consumption must be
// set before use in a PD message.
explicit PowerRequestData(int32_t related_power_data_object_position, PositionTag) : bits_(0) {
ZX_DEBUG_ASSERT(related_power_data_object_position > 0);
set_related_power_data_object_position(related_power_data_object_position);
}
};
// RDO based on a fixed or variable power supply PDO.
//
// See `PowerRequestData` for a general description of the RDO (power
// Request Data Object) representation.
//
// See `PowerData` for a general description of the PDO (Power Data Object)
// representation, `FixedPowerSupplyData` for fixed power supply PDOs, and
// `VariablePowerSupplyData` for variable power supply PDOs.
//
// usbpd3.1 6.4.2 "Request Message", Tables 6-21 "Fixed and Variable Request
// Data Object" and 6-22 "Fixed and Variable Request Data Object with GiveBack
// Support"
class FixedVariableSupplyPowerRequestData : public PowerRequestData {
public:
// The Sink's (estimated) current consumption, in multiples of 10 mA.
DEF_SUBFIELD(bits_, 19, 10, operating_current_10ma);
// The Sink's maximum or minimum current consumption, in multiples of 10 mA.
DEF_SUBFIELD(bits_, 9, 0, limit_current_10ma);
// The Sink's (estimated) current consumption, in mA (milliamps).
//
// The Source uses this estimate to manage its power reserve, and power
// distribution across multiple ports.
//
// The Sink is expected to send a new Request message when its estimated
// current consumption changes.
//
// This field must be at most `maximum_current_ma()` in the related
// FixedPowerSupplyData or VariablePowerSupplyData object.
int32_t operating_current_ma() const {
// The multiplication will not overflow (causing UB) because
// `operating_current_10ma` is a 10-bit field. The maximum product is
// 10,240.
return static_cast<int32_t>(static_cast<int32_t>(operating_current_10ma()) * 10);
}
FixedVariableSupplyPowerRequestData& set_operating_current_ma(int32_t current_ma) {
return set_operating_current_10ma(current_ma / 10);
}
// The Sink's maximum or minimum current consumption, in mA (milliamps).
//
// If `supports_power_give_back` is true, this is the Sink's minimum operating
// current, which can be requested via a GotoMin message.
//
// If `supports_power_give_back` is false, this is the maximum amount of
// current that the Sink may ever consume. `operating_current_ma()` must be
// below this value.
//
// If `capabilities_mismatch` is true, this field may exceed
// `maximum_current_ma()` in the related FixedPowerSupplyData or
// VariablePowerSupplyData object. If `capabilities_mismatch` is false, this
// field must be at most `maximum_current_ma()`.
int32_t limit_current_ma() const {
// The multiplication will not overflow (causing UB) because
// `limit_current_10ma` is a 10-bit field. The maximum product is 10,240.
return static_cast<int32_t>(static_cast<int32_t>(limit_current_10ma()) * 10);
}
FixedVariableSupplyPowerRequestData& set_limit_current_ma(int32_t current_ma) {
return set_limit_current_10ma(current_ma / 10);
}
static FixedVariableSupplyPowerRequestData CreateForPosition(
int32_t related_power_data_object_position) {
return FixedVariableSupplyPowerRequestData(related_power_data_object_position, PositionTag{});
}
explicit FixedVariableSupplyPowerRequestData(uint32_t bits) : PowerRequestData(bits) {}
explicit FixedVariableSupplyPowerRequestData(PowerRequestData request_data)
: PowerRequestData(static_cast<uint32_t>(request_data)) {}
// Instance with all fields except for PDO position set to zero.
//
// This is most likely an invalid RDO. At a minimum, power consumption must be
// set before use in a PD message.
explicit FixedVariableSupplyPowerRequestData(int32_t related_power_data_object_position,
PositionTag)
: PowerRequestData(related_power_data_object_position, PositionTag{}) {}
// Value type, copying is allowed.
FixedVariableSupplyPowerRequestData(const FixedVariableSupplyPowerRequestData&) = default;
FixedVariableSupplyPowerRequestData& operator=(const FixedVariableSupplyPowerRequestData&) =
default;
// In C++20, equality comparison can be defaulted.
bool operator==(const FixedVariableSupplyPowerRequestData& other) const {
return bits_ == other.bits_;
}
bool operator!=(const FixedVariableSupplyPowerRequestData& other) const {
return bits_ != other.bits_;
}
};
// RDO based on a battery power supply PDO.
//
// See `PowerRequestData` for a general description of the RDO (power
// Request Data Object) representation.
//
// See `PowerData` for a general description of the PDO (Power Data Object)
// representation, and `BatteryPowerSupplyData` for battery power supply PDOs.
//
// usbpd3.1 6.4.2 "Request Message", Tables 6-23 "Battery Request Data Object"
// and 6-24 "Battery Request Data Object with GiveBack Support"
class BatteryPowerRequestData : public PowerRequestData {
public:
// The Sink's (estimated) power consumption, in multiples of 250 mW.
DEF_SUBFIELD(bits_, 19, 10, operating_power_250mw);
// The Sink's maximum or minimum power consumption, in multiples of 250 mW.
DEF_SUBFIELD(bits_, 9, 0, limit_power_250mw);
// The Sink's (estimated) power consumption, in mW (millwatts).
//
// The Source uses this estimate to manage its power reserve, and power
// distribution across multiple ports.
//
// The Sink is expected to send a new Request message when its estimated
// current consumption changes.
//
// This field must be at most `maximum_power_mw()` in the related
// BatteryPowerSupplyData object.
int32_t operating_power_mw() const {
// The multiplication will not overflow (causing UB) because
// `operating_power_250mw` is a 10-bit field. The maximum product is
// 255,750.
return static_cast<int32_t>(static_cast<int32_t>(operating_power_250mw()) * 250);
}
BatteryPowerRequestData& set_operating_power_mw(int32_t power_mw) {
return set_operating_power_250mw(power_mw / 250);
}
// The Sink's maximum or minimum power consumption, in mW (milliwatts).
//
// If `supports_power_give_back` is true, this is the Sink's minimum operating
// power, which can be requested via a GotoMin message.
//
// If `supports_power_give_back` is false, this is the maximum amount of power
// that the Sink may ever consume. `operating_power_mw()` must be below this
// value.
//
// If `capabilities_mismatch` is true, this field may exceed
// `maximum_power_mw()` in the related BatteryPowerSupplyData object. If
// `capabilities_mismatch` is false, this field must be at most
// `maximum_power_mw()`.
int32_t limit_power_mw() const {
// The multiplication will not overflow (causing UB) because
// `limit_power_250mw` is a 10-bit field. The maximum product is 255,750.
return static_cast<int32_t>(static_cast<int32_t>(limit_power_250mw()) * 250);
}
BatteryPowerRequestData& set_limit_power_mw(int32_t power_mw) {
return set_limit_power_250mw(power_mw / 250);
}
static BatteryPowerRequestData CreateForPosition(int32_t related_power_data_object_position) {
return BatteryPowerRequestData(related_power_data_object_position, PositionTag{});
}
explicit BatteryPowerRequestData(uint32_t bits) : PowerRequestData(bits) {}
explicit BatteryPowerRequestData(PowerRequestData request_data)
: PowerRequestData(static_cast<uint32_t>(request_data)) {}
// Instance with all fields except for PDO position set to zero.
//
// This is most likely an invalid RDO. At a minimum, power consumption must be
// set before use in a PD message.
explicit BatteryPowerRequestData(int32_t related_power_data_object_position, PositionTag)
: PowerRequestData(related_power_data_object_position, PositionTag{}) {}
// Value type, copying is allowed.
BatteryPowerRequestData(const BatteryPowerRequestData&) = default;
BatteryPowerRequestData& operator=(const BatteryPowerRequestData&) = default;
// In C++20, equality comparison can be defaulted.
bool operator==(const BatteryPowerRequestData& other) const { return bits_ == other.bits_; }
bool operator!=(const BatteryPowerRequestData& other) const { return bits_ != other.bits_; }
};
} // namespace usb_pd
#endif // SRC_DEVICES_POWER_DRIVERS_FUSB302_USB_PD_MESSAGE_OBJECTS_H_