ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
pd.h
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <atomic>
5#include <cstddef>
6#include <cstdint>
7
8namespace esphome::fusb302b {
9
10static constexpr uint8_t PD_MAX_NUM_DATA_OBJECTS = 7;
11// Standard Power Range fixed supplies, which are the only ones this sink negotiates
12static constexpr uint8_t MIN_REQUEST_VOLTAGE = 5;
13static constexpr uint8_t MAX_REQUEST_VOLTAGE = 20;
14
20
21enum PdDataMsgType : uint8_t {
25};
26
39
46
57
63
64struct PdContract {
66 uint16_t max_v{0}; // 50 mV units
67 uint16_t max_i{0}; // 10 mA units
68
69 bool operator==(const PdContract &other) const {
70 return this->max_v == other.max_v && this->max_i == other.max_i && this->type == other.type;
71 }
72 bool operator!=(const PdContract &other) const { return !(*this == other); }
73};
74
75// Type-C default power: 5 V (100 x 50 mV) at 500 mA (50 x 10 mA)
76static constexpr PdContract DEFAULT_CONTRACT{PD_PDO_TYPE_FIXED_SUPPLY, 100, 50};
77
82
83 static PackedContract from(const PdContract &contract) {
84 return {(static_cast<uint32_t>(contract.max_v) << 16) | contract.max_i};
85 }
86 bool is_set() const { return this->value != 0; }
87 float voltage() const { return (this->value >> 16) * 0.05f; }
88 float current() const { return (this->value & 0xFFFF) * 0.01f; }
89};
90
91struct PdMsg {
92 uint8_t type{0};
94 uint8_t id{0};
95 uint8_t num_of_obj{0};
96 bool extended{false};
97 uint32_t data_objects[PD_MAX_NUM_DATA_OBJECTS]{};
98
99 void set_header(uint16_t header);
100 uint16_t get_coded_header() const;
101};
102
107 public:
108 void set_request_voltage(uint8_t voltage) {
109 this->request_voltage_ = std::clamp(voltage, MIN_REQUEST_VOLTAGE, MAX_REQUEST_VOLTAGE);
110 }
111 uint8_t get_request_voltage() const { return this->request_voltage_; }
112
113 PdState get_state() const { return this->state_; }
114 bool is_connected() const { return is_connected_state(this->state_); }
115
116 protected:
118 virtual bool send_message(const PdMsg &msg) = 0;
120 virtual void on_state_changed() = 0;
122 virtual void on_soft_reset_received() = 0;
124 virtual void on_source_caps_received() = 0;
127 virtual void on_transition_timeout() = 0;
130 virtual void on_request_failed() = 0;
131
132 void handle_message_(const PdMsg &msg);
135 void reset_protocol_();
137 void set_contract_(const PdContract &contract);
138 void clear_contract_();
141 void set_state_and_contract_(PdState state, const PdContract &contract);
142 void set_ams_(bool active);
145 bool check_ams_();
150
152 PdMsg make_data_msg_(PdDataMsgType type, const uint32_t *objects, uint8_t len) const;
153
154 // Shared with the main loop
156 std::atomic<uint32_t> contract_{0};
157 std::atomic<uint8_t> request_voltage_{5};
158
159 // PHY task only
163
164 private:
165 void handle_data_message_(const PdMsg &msg);
166 void handle_control_message_(const PdMsg &msg);
167 void handle_soft_reset_(const PdMsg &msg);
168 void respond_to_source_caps_(const PdMsg &msg);
169 bool send_request_();
170 void request_failed_();
171
172 PdContract requested_contract_{};
173 PdContract accepted_contract_{};
174 uint32_t last_rdo_{0};
175 bool active_ams_{false};
176 // Set by Accept; PS_RDY is only valid after the source accepted the request of the current sequence
177 bool ps_rdy_expected_{false};
178 uint8_t last_received_msg_id_{255};
179 uint8_t msg_counter_{0};
180 uint8_t wait_retries_{0};
181};
182
183} // namespace esphome::fusb302b
USB-PD sink protocol logic, independent of the PHY chip.
Definition pd.h:106
PdMsg make_control_msg_(PdControlMsgType type) const
Definition pd.cpp:55
virtual void on_source_caps_received()=0
Called when source capabilities arrive, before the request for them is sent.
void set_contract_(const PdContract &contract)
Definition pd.cpp:85
bool is_connected() const
Definition pd.h:114
std::atomic< uint8_t > request_voltage_
Definition pd.h:157
PdMsg make_data_msg_(PdDataMsgType type, const uint32_t *objects, uint8_t len) const
Definition pd.cpp:62
uint8_t get_request_voltage() const
Definition pd.h:111
void set_ams_(bool active)
Definition pd.cpp:108
PdState get_state() const
Definition pd.h:113
std::atomic< uint32_t > contract_
Definition pd.h:156
void set_state_(PdState state)
Definition pd.cpp:80
std::atomic< PdState > state_
Definition pd.h:155
void set_request_voltage(uint8_t voltage)
Definition pd.h:108
void handle_message_(const PdMsg &msg)
Definition pd.cpp:176
void check_request_retry_()
Sends the last request again once tSinkRequest has passed after the source answered Wait.
Definition pd.cpp:128
virtual void on_state_changed()=0
Called after state_ or contract_ changed, to let the main loop publish it.
virtual bool send_message(const PdMsg &msg)=0
Returns false when the message could not be handed to the chip; the PHY logs the failure.
void handle_transmit_failed_()
Called by the PHY when the chip gave up on a message after its retries without receiving a GoodCRC.
Definition pd.cpp:169
virtual void on_soft_reset_received()=0
Called after the source soft reset the protocol; it sends new source capabilities next.
virtual void on_request_failed()=0
Called when a request ended without a new contract: it was rejected, the source kept answering Wait o...
bool check_ams_()
Returns true while an atomic message sequence is in progress.
Definition pd.cpp:116
void set_state_and_contract_(PdState state, const PdContract &contract)
Stores both before calling on_state_changed() once, so the main loop never sees the new state with th...
Definition pd.cpp:98
void check_transition_timeout_()
Falls back to default power when the source accepted a request but did not report the new supply read...
Definition pd.cpp:160
virtual void on_transition_timeout()=0
Called after an accepted request was not followed by PS_RDY in time and the state fell back to defaul...
uint8_t type
bool state
Definition fan.h:2
@ PD_SPEC_REV_2
Definition pd.h:17
@ PD_SPEC_REV_3
Definition pd.h:18
@ PD_SPEC_REV_1
Definition pd.h:16
@ PD_DATA_SOURCE_CAP
Definition pd.h:22
@ PD_DATA_REQUEST
Definition pd.h:23
@ PD_DATA_SINK_CAP
Definition pd.h:24
@ PD_STATE_PD_TIMEOUT
Negotiation is over without a PD contract (no capabilities, or the request was not accepted); the sou...
@ PD_CNTRL_PING
Definition pd.h:31
@ PD_CNTRL_SOFT_RESET
Definition pd.h:36
@ PD_CNTRL_REJECT
Definition pd.h:30
@ PD_CNTRL_GOODCRC
Definition pd.h:28
@ PD_CNTRL_WAIT
Definition pd.h:35
@ PD_CNTRL_GET_SINK_CAP
Definition pd.h:34
@ PD_CNTRL_NOT_SUPPORTED
Definition pd.h:37
@ PD_CNTRL_ACCEPT
Definition pd.h:29
@ PD_CNTRL_GET_SOURCE_CAP
Definition pd.h:33
@ PD_CNTRL_PS_RDY
Definition pd.h:32
bool is_connected_state(PdState state)
Returns true for the states in which a source is attached and supplying power.
Definition pd.h:59
@ PD_PDO_TYPE_AUGMENTED
Definition pd.h:44
@ PD_PDO_TYPE_VARIABLE_SUPPLY
Definition pd.h:43
@ PD_PDO_TYPE_BATTERY
Definition pd.h:42
@ PD_PDO_TYPE_FIXED_SUPPLY
Definition pd.h:41
const void size_t len
Definition hal.h:68
static void uint32_t
A contract packed into one word so it can be shared between tasks as an atomic.
Definition pd.h:80
static PackedContract from(const PdContract &contract)
Definition pd.h:83
bool operator==(const PdContract &other) const
Definition pd.h:69
bool operator!=(const PdContract &other) const
Definition pd.h:72
PdSpecRevision spec_rev
Definition pd.h:93
uint8_t num_of_obj
Definition pd.h:95
void set_header(uint16_t header)
Definition pd.cpp:40
uint16_t get_coded_header() const
Definition pd.cpp:48
uint32_t data_objects[PD_MAX_NUM_DATA_OBJECTS]
Definition pd.h:97