WiP PPS
This commit is contained in:
@@ -15,4 +15,5 @@ enum Orientation { ORIENTATION_LEFT_HAND = 0, ORIENTATION_RIGHT_HAND = 1, ORIENT
|
||||
#define TICKS_SECOND configTICK_RATE_HZ
|
||||
#define TICKS_MIN (60 * TICKS_SECOND)
|
||||
#define TICKS_100MS (TICKS_SECOND / 10)
|
||||
#define TICKS_10MS (TICKS_100MS / 10)
|
||||
#endif /* BSP_DEFINES_H_ */
|
||||
|
||||
@@ -12,6 +12,7 @@ bool FUSB302_present = false;
|
||||
void power_check() {
|
||||
#ifdef POW_PD
|
||||
if (FUSB302_present) {
|
||||
PolicyEngine::PPSTimerCallback();
|
||||
// Cant start QC until either PD works or fails
|
||||
if (PolicyEngine::setupCompleteOrTimedOut() == false) {
|
||||
return;
|
||||
|
||||
@@ -12,6 +12,7 @@ bool FUSB302_present = false;
|
||||
void power_check() {
|
||||
#ifdef POW_PD
|
||||
if (FUSB302_present) {
|
||||
PolicyEngine::PPSTimerCallback();
|
||||
// Cant start QC until either PD works or fails
|
||||
if (PolicyEngine::setupCompleteOrTimedOut() == false) {
|
||||
return;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "policy_engine.h"
|
||||
#include "Defines.h"
|
||||
#include "fusb302b.h"
|
||||
#include "int_n.h"
|
||||
#include "protocol_tx.h"
|
||||
@@ -31,7 +32,6 @@ bool PolicyEngine::_explicit_contract;
|
||||
int8_t PolicyEngine::_hard_reset_counter;
|
||||
int8_t PolicyEngine::_old_tcc_match;
|
||||
uint8_t PolicyEngine::_pps_index;
|
||||
uint8_t PolicyEngine::_last_pps;
|
||||
osThreadId PolicyEngine::TaskHandle = NULL;
|
||||
uint32_t PolicyEngine::TaskBuffer[PolicyEngine::TaskStackSize];
|
||||
osStaticThreadDef_t PolicyEngine::TaskControlBlock;
|
||||
@@ -43,6 +43,8 @@ uint8_t PolicyEngine::ucQueueStorageArea[PDB_MSG_POOL_
|
||||
QueueHandle_t PolicyEngine::messagesWaiting = NULL;
|
||||
EventGroupHandle_t PolicyEngine::xEventGroupHandle = NULL;
|
||||
StaticEventGroup_t PolicyEngine::xCreatedEventGroup;
|
||||
bool PolicyEngine::PPSTimerEnabled = false;
|
||||
TickType_t PolicyEngine::PPSTimeLastEvent = 0;
|
||||
void PolicyEngine::init() {
|
||||
messagesWaiting = xQueueCreateStatic(PDB_MSG_POOL_SIZE, sizeof(union pd_msg), ucQueueStorageArea, &xStaticQueue);
|
||||
// Create static thread at PDB_PRIO_PE priority
|
||||
@@ -64,9 +66,7 @@ void PolicyEngine::pe_task(const void *arg) {
|
||||
/* Initialize the old_tcc_match */
|
||||
_old_tcc_match = -1;
|
||||
/* Initialize the pps_index */
|
||||
_pps_index = 8;
|
||||
/* Initialize the last_pps */
|
||||
_last_pps = 8;
|
||||
_pps_index = 0xFF;
|
||||
|
||||
for (;;) {
|
||||
// Loop based on state
|
||||
@@ -133,7 +133,7 @@ void PolicyEngine::pe_task(const void *arg) {
|
||||
PolicyEngine::policy_engine_state PolicyEngine::pe_sink_startup() {
|
||||
/* We don't have an explicit contract currently */
|
||||
_explicit_contract = false;
|
||||
|
||||
PPSTimerEnabled = false;
|
||||
// If desired could send an alert that PD is starting
|
||||
|
||||
/* No need to reset the protocol layer here. There are two ways into this
|
||||
@@ -211,7 +211,9 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_eval_cap() {
|
||||
* PE_SNK_Select_Cap. */
|
||||
/* Start by assuming we won't find a PPS APDO (set the index greater
|
||||
* than the maximum possible) */
|
||||
_pps_index = 8;
|
||||
_pps_index = 0xFF;
|
||||
/* New capabilities also means we can't be making a request from the
|
||||
* same PPS APDO */
|
||||
/* Search for the first PPS APDO */
|
||||
for (int i = 0; i < PD_NUMOBJ_GET(&tempMessage); i++) {
|
||||
if ((tempMessage.obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_AUGMENTED && (tempMessage.obj[i] & PD_APDO_TYPE) == PD_APDO_TYPE_PPS) {
|
||||
@@ -219,13 +221,9 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_eval_cap() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* New capabilities also means we can't be making a request from the
|
||||
* same PPS APDO */
|
||||
_last_pps = 8;
|
||||
|
||||
/* Ask the DPM what to request */
|
||||
if (pdbs_dpm_evaluate_capability(&tempMessage, &_last_dpm_request)) {
|
||||
|
||||
return PESinkSelectCap;
|
||||
}
|
||||
|
||||
@@ -248,6 +246,18 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_select_cap() {
|
||||
if ((evt & PDB_EVT_PE_TX_ERR) == PDB_EVT_PE_TX_ERR) {
|
||||
return PESinkHardReset;
|
||||
}
|
||||
/* If we're using PD 3.0 */
|
||||
if ((hdr_template & PD_HDR_SPECREV) == PD_SPECREV_3_0) {
|
||||
/* If the request was for a PPS APDO, start time callbacks if not started */
|
||||
if (PD_RDO_OBJPOS_GET(&_last_dpm_request) >= _pps_index) {
|
||||
if (PPSTimerEnabled == false) {
|
||||
PPSTimerEnabled = true;
|
||||
PPSTimeLastEvent = xTaskGetTickCount();
|
||||
}
|
||||
} else {
|
||||
PPSTimerEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for a response */
|
||||
evt = waitForEvent(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET, PD_T_SENDER_RESPONSE);
|
||||
@@ -265,7 +275,6 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_select_cap() {
|
||||
readMessage();
|
||||
/* If the source accepted our request, wait for the new power */
|
||||
if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_ACCEPT && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||
|
||||
return PESinkTransitionSink;
|
||||
/* If the message was a Soft_Reset, do the soft reset procedure */
|
||||
} else if (PD_MSGTYPE_GET(&tempMessage) == PD_MSGTYPE_SOFT_RESET && PD_NUMOBJ_GET(&tempMessage) == 0) {
|
||||
@@ -280,7 +289,7 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_select_cap() {
|
||||
return PESinkReady;
|
||||
}
|
||||
} else {
|
||||
return PESinkSendSoftReset;
|
||||
return PESinkSelectCap;
|
||||
}
|
||||
}
|
||||
return PESinkHardReset;
|
||||
@@ -306,15 +315,12 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_transition_sink() {
|
||||
/* We just finished negotiating an explicit contract */
|
||||
_explicit_contract = true;
|
||||
|
||||
/* Set the output appropriately */
|
||||
/* Negotiation finished */
|
||||
pdbs_dpm_transition_requested();
|
||||
|
||||
return PESinkReady;
|
||||
/* If there was a protocol error, send a hard reset */
|
||||
} else {
|
||||
/* Turn off the power output before this hard reset to make sure we
|
||||
* don't supply an incorrect voltage to the device we're powering.
|
||||
*/
|
||||
pdbs_dpm_transition_default();
|
||||
|
||||
return PESinkHardReset;
|
||||
@@ -328,7 +334,7 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_ready() {
|
||||
eventmask_t evt;
|
||||
|
||||
/* Wait for an event */
|
||||
evt = waitForEvent(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET | PDB_EVT_PE_I_OVRTEMP);
|
||||
evt = waitForEvent(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET | PDB_EVT_PE_I_OVRTEMP | PDB_EVT_PE_PPS_REQUEST);
|
||||
|
||||
/* If we got reset signaling, transition to default */
|
||||
if (evt & PDB_EVT_PE_RESET) {
|
||||
@@ -340,6 +346,12 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_ready() {
|
||||
return PESinkHardReset;
|
||||
}
|
||||
|
||||
/* If SinkPPSPeriodicTimer ran out, send a new request */
|
||||
if (evt & PDB_EVT_PE_PPS_REQUEST) {
|
||||
/* Tell the protocol layer we're starting an AMS */
|
||||
ProtocolTransmit::notify(ProtocolTransmit::Notifications::PDB_EVT_PRLTX_START_AMS);
|
||||
return PESinkSelectCap;
|
||||
}
|
||||
/* If we received a message */
|
||||
if (evt & PDB_EVT_PE_MSG_RX) {
|
||||
if (messageWaiting()) {
|
||||
@@ -631,3 +643,14 @@ PolicyEngine::policy_engine_state PolicyEngine::pe_sink_source_unresponsive() {
|
||||
uint32_t PolicyEngine::waitForEvent(uint32_t mask, TickType_t ticksToWait) { return xEventGroupWaitBits(xEventGroupHandle, mask, mask, pdFALSE, ticksToWait); }
|
||||
|
||||
bool PolicyEngine::isPD3_0() { return (hdr_template & PD_HDR_SPECREV) == PD_SPECREV_3_0; }
|
||||
|
||||
void PolicyEngine::PPSTimerCallback() {
|
||||
|
||||
if (PPSTimerEnabled) {
|
||||
if (xTaskGetTickCount() - PPSTimeLastEvent > TICKS_100MS) {
|
||||
// Send a new PPS message
|
||||
PPSTimeLastEvent = xTaskGetTickCount();
|
||||
notify(PDB_EVT_PE_PPS_REQUEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
#define PDB_EVT_PE_TX_ERR EVENT_MASK(3)
|
||||
#define PDB_EVT_PE_HARD_SENT EVENT_MASK(4)
|
||||
#define PDB_EVT_PE_I_OVRTEMP EVENT_MASK(5)
|
||||
#define PDB_EVT_PE_PPS_REQUEST EVENT_MASK(6)
|
||||
#define PDB_EVT_PE_MSG_RX_PEND EVENT_MASK(7) /* Never SEND THIS DIRECTLY*/
|
||||
|
||||
class PolicyEngine {
|
||||
public:
|
||||
// Sets up internal state and registers the thread
|
||||
@@ -55,6 +55,8 @@ public:
|
||||
// Has pd negotiation completed
|
||||
static bool pdHasNegotiated() { return pdNegotiationComplete; }
|
||||
|
||||
static void PPSTimerCallback();
|
||||
|
||||
private:
|
||||
static bool pdNegotiationComplete;
|
||||
static int current_voltage_mv; // The current voltage PD is expecting
|
||||
@@ -72,9 +74,8 @@ private:
|
||||
static int8_t _old_tcc_match;
|
||||
/* The index of the first PPS APDO */
|
||||
static uint8_t _pps_index;
|
||||
/* The index of the just-requested PPS APDO */
|
||||
static uint8_t _last_pps;
|
||||
static void pe_task(const void *arg);
|
||||
|
||||
static void pe_task(const void *arg);
|
||||
enum policy_engine_state {
|
||||
PESinkStartup,
|
||||
PESinkDiscovery,
|
||||
@@ -130,7 +131,9 @@ private:
|
||||
static QueueHandle_t messagesWaiting;
|
||||
static bool messageWaiting();
|
||||
// Read a pending message into the temp message
|
||||
static bool readMessage();
|
||||
static bool readMessage();
|
||||
static bool PPSTimerEnabled;
|
||||
static TickType_t PPSTimeLastEvent;
|
||||
|
||||
// These callbacks are called to implement the logic for the iron to select the desired voltage
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ bool PolicyEngine::pdbs_dpm_evaluate_capability(const union pd_msg *capabilities
|
||||
uint8_t bestIndex = 0xFF;
|
||||
int bestIndexVoltage = 0;
|
||||
int bestIndexCurrent = 0;
|
||||
bool bestIsPPS = false;
|
||||
for (uint8_t i = 0; i < numobj; i++) {
|
||||
/* If we have a fixed PDO, its V equals our desired V, and its I is
|
||||
* at least our desired I */
|
||||
@@ -83,15 +84,37 @@ bool PolicyEngine::pdbs_dpm_evaluate_capability(const union pd_msg *capabilities
|
||||
bestIndexVoltage = voltage_mv;
|
||||
bestIndexCurrent = current_a_x100;
|
||||
}
|
||||
if ((capabilities->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_AUGMENTED && (capabilities->obj[i] & PD_APDO_TYPE) == PD_APDO_TYPE_PPS) {
|
||||
// If this is a PPS slot, calculate the max voltage in the PPS range that can we be used and maintain
|
||||
uint16_t max_voltage = PD_PAV2MV(PD_APDO_PPS_MAX_VOLTAGE_GET(capabilities->obj[i]));
|
||||
// uint16_t min_voltage = PD_PAV2MV(PD_APDO_PPS_MIN_VOLTAGE_GET(capabilities->obj[i]));
|
||||
uint16_t max_current = PD_PAI2CA(PD_APDO_PPS_CURRENT_GET(capabilities->obj[i])); // max current in 10mA units
|
||||
// Using the current and tip resistance, calculate the ideal max voltage
|
||||
// if this is range, then we will work with this voltage
|
||||
// if this is not in range; then max_voltage can be safely selected
|
||||
int ideal_voltage_mv = (tipResistance * max_current);
|
||||
if (ideal_voltage_mv > max_voltage) {
|
||||
ideal_voltage_mv = max_voltage; // constrain
|
||||
}
|
||||
if (ideal_voltage_mv > (USB_PD_VMAX * 1000)) {
|
||||
ideal_voltage_mv = (USB_PD_VMAX * 1000); // constrain to model max
|
||||
}
|
||||
if (ideal_voltage_mv > bestIndexVoltage) {
|
||||
bestIndex = i;
|
||||
bestIndexVoltage = ideal_voltage_mv;
|
||||
bestIndexCurrent = max_current;
|
||||
bestIsPPS = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bestIndex != 0xFF) {
|
||||
/* We got what we wanted, so build a request for that */
|
||||
request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1);
|
||||
|
||||
/* GiveBack disabled */
|
||||
request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(bestIndexCurrent) | PD_RDO_FV_CURRENT_SET(bestIndexCurrent) | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(bestIndex + 1);
|
||||
if (bestIsPPS) {
|
||||
request->obj[0] = PD_RDO_PROG_CURRENT_SET(PD_CA2PAI(bestIndexCurrent)) | PD_RDO_PROG_VOLTAGE_SET(PD_MV2PRV(bestIndexVoltage)) | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(bestIndex + 1);
|
||||
} else {
|
||||
request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(bestIndexCurrent) | PD_RDO_FV_CURRENT_SET(bestIndexCurrent) | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(bestIndex + 1);
|
||||
}
|
||||
// We support usb comms (ish)
|
||||
request->obj[0] |= PD_RDO_USB_COMMS;
|
||||
|
||||
@@ -103,8 +126,7 @@ bool PolicyEngine::pdbs_dpm_evaluate_capability(const union pd_msg *capabilities
|
||||
/* Nothing matched (or no configuration), so get 5 V at low current */
|
||||
request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1);
|
||||
request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(DPM_MIN_CURRENT) | PD_RDO_FV_CURRENT_SET(DPM_MIN_CURRENT) | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(1);
|
||||
/* If the output is enabled and we got here, it must be a capability
|
||||
* mismatch. */
|
||||
/* If the output is enabled and we got here, it must be a capability mismatch. */
|
||||
if (pdNegotiationComplete) {
|
||||
request->obj[0] |= PD_RDO_CAP_MISMATCH;
|
||||
}
|
||||
@@ -162,6 +184,11 @@ void PolicyEngine::pdbs_dpm_get_sink_capability(union pd_msg *cap) {
|
||||
cap->obj[2] ^= cap->obj[1];
|
||||
cap->obj[1] ^= cap->obj[2];
|
||||
}
|
||||
/* If we're using PD 3.0, add a PPS APDO for our desired voltage */
|
||||
if ((hdr_template & PD_HDR_SPECREV) >= PD_SPECREV_3_0) {
|
||||
cap->obj[numobj++]
|
||||
= PD_PDO_TYPE_AUGMENTED | PD_APDO_TYPE_PPS | PD_APDO_PPS_MAX_VOLTAGE_SET(PD_MV2PAV(voltage)) | PD_APDO_PPS_MIN_VOLTAGE_SET(PD_MV2PAV(voltage)) | PD_APDO_PPS_CURRENT_SET(PD_CA2PAI(current));
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the unconstrained power flag. */
|
||||
|
||||
Reference in New Issue
Block a user