MCUXpresso_MIMXRT1021xxxxx/middleware/usb/pd/usb_pd_policy.c
Yilin Sun 1cf36afbfa
Updated to SDK v2.14.0
Signed-off-by: Yilin Sun <imi415@imi.moe>
2023-08-31 23:30:31 +08:00

9274 lines
383 KiB
C

/*
* Copyright 2015 - 2017 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
#include "usb_pd_config.h"
#include "usb_pd.h"
#include "usb_pd_phy.h"
#include "usb_pd_timer.h"
#include "usb_pd_interface.h"
#if (defined PD_CONFIG_ALT_MODE_SUPPORT) && (PD_CONFIG_ALT_MODE_SUPPORT)
#include "usb_pd_alt_mode.h"
#endif
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
#include "usb_pd_auto_policy.h"
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY_LOG) && (PD_CONFIG_ENABLE_AUTO_POLICY_LOG)
#include "fsl_debug_console.h"
#endif
#endif
/*******************************************************************************
* Definitions
******************************************************************************/
#if defined(PD_CONFIG_SRC_AUTO_DISCOVER_CABLE_PLUG) && (PD_CONFIG_SRC_AUTO_DISCOVER_CABLE_PLUG)
#undef PD_CONFIG_CABLE_COMMUNICATION_ENABLE
#define PD_CONFIG_CABLE_COMMUNICATION_ENABLE (1)
#endif
#if (defined(PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE))
#undef PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE
#define PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE (1)
#endif
#define N_CAPS_COUNT (50U)
#define N_HARD_RESET_COUNT (2U)
#define N_DISCOVER_IDENTITY_COUNTER (20U)
#define N_DPM_COMMAND_RETRY_COUNTER (20U)
#define PD_EXTENDED_SRC_CAP_DATA_LENGTH (23U)
#define PD_EXTENDED_STATUS_MSG_DATA_LENGTH (3U)
#define PD_EXTENDED_BATTERY_CAP_MSG_DATA_LENGTH (9U)
#define PD_EXTENDED_PPS_STATUS_MSG_DATA_LENGTH (4U)
#define MSG_DATA_BUFFER ((uint32_t *)(&(pdInstance->receivedData[1])))
#define MSG_DATA_HEADER (pdInstance->receivedData[0] >> 16)
#define PD_NOT_SUPPORT_REPLY_MSG ((pdInstance->revision >= PD_SPEC_REVISION_30) ? kPD_MsgNotSupported : kPD_MsgReject)
#define VDM_ID_HEADER_VDO_PASSIVE_CABLE_VAL (0x03U)
#define VDM_ID_HEADER_VDO_ACTIVE_CABLE_VAL (0x04U)
typedef enum _trigger_event
{
PSM_TRIGGER_NONE,
PSM_TRIGGER_NON_START,
PSM_TRIGGER_DPM_MSG,
PSM_TRIGGER_PD_MSG,
PSM_TRIGGER_RECEIVE_HARD_RESET,
} trigger_event_t;
typedef struct _psm_trigger_info
{
uint32_t *pdMsgDataBuffer;
uint32_t pdExtMsgLength;
pd_structured_vdm_header_t vdmHeader;
pd_msg_header_t msgHeader;
pd_command_t dpmMsg;
start_of_packet_t pdMsgSop;
message_type_t pdMsgType;
trigger_event_t triggerEvent;
uint8_t vdmMsgType;
uint8_t pdMsgDataLength; /*!< the count of Number Data Object */
} psm_trigger_info_t;
typedef enum _pd_state_machine_state
{
kSM_None = 0,
kSM_Continue,
kSM_WaitEvent,
kSM_ErrorRecovery,
kSM_Detach,
} pd_state_machine_state_t;
/*******************************************************************************
* Prototypes
******************************************************************************/
static void PD_PsmTransitionOnMsgSendError(pd_instance_t *pdInstance,
pd_psm_state_t interruptedState,
pd_psm_state_t errorState);
static uint8_t PD_MsgSendMsgCommonTransition(pd_instance_t *pdInstance,
start_of_packet_t sop,
message_type_t msgType,
uint32_t dataLength,
uint8_t *dataBuffer,
pd_psm_state_t successNextState,
pd_psm_state_t interruptedState,
pd_psm_state_t errorState);
static inline uint8_t PD_MsgSendDataTransition(pd_instance_t *pdInstance,
message_type_t msgType,
uint32_t doCount,
uint32_t *dos,
pd_psm_state_t successNextState,
pd_psm_state_t interruptedState,
pd_psm_state_t errorState);
static inline uint8_t PD_MsgSendControlTransition(pd_instance_t *pdInstance,
message_type_t msgType,
pd_psm_state_t successNextState,
pd_psm_state_t interruptedState,
pd_psm_state_t errorState);
#if defined(PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
static inline uint8_t PD_MsgSendExtTransition(pd_instance_t *pdInstance,
start_of_packet_t sop,
message_type_t msgType,
uint32_t dataLength,
uint8_t *dataBuffer,
pd_psm_state_t successNextState,
pd_psm_state_t interruptedState,
pd_psm_state_t errorState);
#endif
static inline uint8_t PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(pd_instance_t *pdInstance,
message_type_t msgType,
pd_psm_state_t successNextState);
#if defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
static inline uint8_t PD_PsmSendControlTransitionWithErrorRecovery(pd_instance_t *pdInstance,
message_type_t msgType,
pd_psm_state_t successNextState);
#endif
static inline uint8_t PD_PsmSendControlTransitionWithHardReset(pd_instance_t *pdInstance,
message_type_t msgType,
pd_psm_state_t successNextState);
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
static uint8_t PD_PsmSendControlTransitionWithTry(pd_instance_t *pdInstance,
message_type_t msgType,
pd_psm_state_t successNextState,
pd_psm_state_t interruptedState,
pd_psm_state_t errorState);
#endif
static uint8_t PD_PsmSendControlTransitionWithSendResponserTimeOut(pd_instance_t *pdInstance,
message_type_t msgType,
pd_psm_state_t successNextState,
pd_psm_state_t interruptedState,
pd_psm_state_t errorState);
static void PD_FRSControl(pd_instance_t *pdInstance, uint8_t enable);
static void PD_PsmReset(pd_instance_t *pdInstance);
static void PD_PsmSetNormalPower(pd_instance_t *pdInstance);
static void PD_PsmCheckRevision(pd_instance_t *pdInstance, pd_msg_header_t msgHeader);
#if (defined PD_CONFIG_PD3_PPS_ENABLE) && (PD_CONFIG_PD3_PPS_ENABLE)
static uint8_t PD_PsmSinkIsPPSRDO(pd_instance_t *pdInstance);
static uint8_t PD_PsmSourceIsPPSRDO(pd_instance_t *pdInstance);
#endif
#if ((defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)) || \
((defined PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE))
static uint8_t PD_PsmIsDualRole(pd_instance_t *pdInstance);
#endif
#if (defined PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
static uint32_t *PD_PsmGetSourcePDOs(pd_instance_t *pdInstance);
#endif
#if (defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)
static uint32_t *PD_PsmGetSinkPDOs(pd_instance_t *pdInstance);
#endif
static void PD_PsmClearStateFlags(pd_instance_t *pdInstance);
static void PD_PsmDisconnect(pd_instance_t *pdInstance);
static void PD_PsmConnect(pd_instance_t *pdInstance);
static pd_state_machine_state_t PD_PsmDisconnectCheck(pd_instance_t *pdInstance, pd_state_machine_state_t state);
#if (defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
static uint8_t PD_PsmCheckLessOrEqualVsafe5v(pd_instance_t *pdInstance);
static void PD_PsmCheckFRS5V(pd_instance_t *pdInstance);
#endif
static uint8_t PD_DpmGetMsg(pd_instance_t *pdInstance);
static void PD_DpmClearMsg(pd_instance_t *pdInstance, pd_command_t id);
static void PD_DpmSendMsg(pd_handle pdHandle, uint8_t id);
#if ((defined PD_CONFIG_EXTENDED_CHUNK_LAYER_SUPPORT) && (PD_CONFIG_EXTENDED_CHUNK_LAYER_SUPPORT))
static void PD_MsgChunkingLayerResetFlags(pd_instance_t *pdInstance);
static uint8_t PD_PsmChunkingLayerRXTimerWaiting(pd_instance_t *pdInstance);
static uint8_t PD_PsmChunkingLayerRXStateMachine(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo);
#if 0
static uint8_t PD_PsmChunkingLayerCheckSentDone(pd_instance_t *pdInstance);
static pd_status_t PD_PsmChunkingLayerTXStateMachine(pd_instance_t *pdInstance,
start_of_packet_t sop,
message_type_t msgType,
uint8_t *dataBuffer,
uint32_t dataLength,
psm_trigger_info_t *triggerInfo);
#endif
#endif
#if (defined PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
static uint8_t PD_PsmCheckInAltMode(pd_instance_t *pdInstance, start_of_packet_t sop);
#endif
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY_LOG) && (PD_CONFIG_ENABLE_AUTO_POLICY_LOG)
static void PD_PsmPrintAutoPolicyReplySwapRequestLog(pd_instance_t *pdInstance, uint8_t message);
static void PD_PsmPrintAutoPolicyStartSwapLog(pd_instance_t *pdInstance, uint8_t message);
#endif
#if (defined PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
static uint8_t PD_PsmAutoRequestVconnSwap(pd_instance_t *pdInstance);
#endif
#if (defined PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
static uint8_t PD_PsmAutoRequestDataSwap(pd_instance_t *pdInstance);
#endif
#if (defined PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
static uint8_t PD_PsmAutoRequestPowerSwap(pd_instance_t *pdInstance);
#endif
static void PD_PsmSetAutoPolicyState(pd_instance_t *pdInstance, pd_auto_policy_state_t newState);
static uint8_t PD_PsmGetExternalPowerState(pd_instance_t *pdInstance);
static uint8_t PD_PsmReadyAutoPolicyProcess(pd_instance_t *pdInstance);
static void PD_PsmReadyAutoPolicyResult(pd_instance_t *pdInstance, pd_command_result_t result);
static void PD_PsmExternalPowerChange(pd_instance_t *pdInstance);
#endif
#if (defined PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
static void PD_StateWaitReplyExtDataProcess(pd_instance_t *pdInstance,
psm_trigger_info_t *triggerInfo,
message_type_t requiredMsg,
pd_dpm_callback_event_t successCallbackEvent,
pd_dpm_callback_event_t failCallbackEvent,
uint8_t *didNothingStepB);
#endif
static uint8_t PD_PsmStartCommand(pd_instance_t *pdInstance, pd_command_t command, uint8_t isInitiator);
static void PD_PsmCommandFail(pd_instance_t *pdInstance, pd_command_t command);
static uint8_t PD_PsmPrimaryStateProcessDpmMsg(pd_instance_t *pdInstance,
pd_psm_state_t *returnNewState,
psm_trigger_info_t *triggerInfo);
static pd_psm_state_t PD_PsmSinkHardResetfunction(pd_instance_t *pdInstance);
static uint8_t PD_PsmPrimaryStateProcessPdMsg(pd_instance_t *pdInstance,
pd_psm_state_t *returnNewState,
psm_trigger_info_t *triggerInfo);
static void PD_PsmEndCommand(pd_instance_t *pdInstance);
static void PD_PsmSinkAndSourceRdyProcessDpmMessage(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo);
#if (defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)
static void PD_PsmSinkRdyProcessDpmMessage(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo);
#endif
#if (defined PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
static void PD_PsmSourceRdyProcessDpmMessage(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo);
#endif
static void PD_PsmRdyProcessPdMessage(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo);
static uint8_t PD_PsmCanPendingReceive(pd_instance_t *pdInstance);
static void PD_PsmProcessImportEventBeforeNextStateMachine(pd_instance_t *pdInstance);
static uint8_t PD_PsmNoResponseHardResetCountCheck(pd_instance_t *pdInstance);
#if (defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)) || \
(defined(PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)) || \
(defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT))
static void PD_PsmStateWaitReply(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo, uint8_t *didNothingStepB);
static void PD_PsmEvaluateSwap(pd_instance_t *pdInstance,
pd_dpm_callback_event_t requestEvent,
pd_psm_state_t acceptState,
pd_psm_state_t rejectState);
#endif
#if defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
static void PD_PsmPowerSwapSinkSourceTransitionOff(pd_instance_t *pdInstance,
psm_trigger_info_t *triggerInfo,
pd_psm_state_t newState,
uint8_t *didNothingStepB);
static void PD_PsmPowerSwapSinkOpenVbus(pd_instance_t *pdInstance, pd_dpm_callback_event_t callbackEvent);
#endif
#if defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
static void PD_PsmPowerSwapAssertRdRp(pd_instance_t *pdInstance, pd_power_role_t powerRole, pd_psm_state_t nextState);
#endif
#if (defined(PD_CONFIG_VBUS_ALARM_SUPPORT) && (PD_CONFIG_VBUS_ALARM_SUPPORT)) || \
(defined(PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE))
static inline void PD_PsmSetVbusAlarmAndSinkDisconnect(pd_instance_t *pdInstance);
#endif
static void PD_PsmResetStateWhenEnterReadyState(pd_instance_t *pdInstance);
#if defined(PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
static void PD_StateSendReplyExtDataTransition(pd_instance_t *pdInstance, message_type_t msgType);
#endif
static void PD_PsmCheckChunkedFeature(pd_instance_t *pdInstance, pd_rdo_t rdo);
#if (defined PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
static void PD_PsmTurnOffVconnAndVbus(pd_instance_t *pdInstance, pd_vbus_power_progress_t powerState);
#endif
static inline void PD_PsmEnterIdleState(pd_instance_t *pdInstance);
static inline void PD_PsmEnterHardResetState(pd_instance_t *pdInstance);
static inline void PD_PsmEnterSendSoftResetState(pd_instance_t *pdInstance);
#if (defined PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
static inline void PD_PsmEnterSrcStartUpState(pd_instance_t *pdInstance);
static inline void PD_PsmEnterImplicitCableDiscoveryState(pd_instance_t *pdInstance);
static inline void PD_PsmEnterImplicitCableDiscoveryState(pd_instance_t *pdInstance);
static inline void PD_PsmEnterSrcSendCapsState(pd_instance_t *pdInstance);
static inline void PD_PsmEnterSrcNegotiateCapState(pd_instance_t *pdInstance);
static inline void PD_PsmEnterSrcTransitionSupplyState(pd_instance_t *pdInstance);
static inline void PD_PsmEnterSrcCapResponseState(pd_instance_t *pdInstance);
static inline void PD_PsmEnterSrcTransitionToDefaultState(pd_instance_t *pdInstance);
static inline void PD_PsmEnterGiveSrcCapState(pd_instance_t *pdInstance);
#endif
static inline void PD_PsmEnterGetSinkOrSourceCapState(pd_instance_t *pdInstance, pd_psm_state_t prevState);
#if (defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)) || \
((defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE))
static inline void PD_PsmEnterGiveSinkCapState(pd_instance_t *pdInstance);
#endif
#if (defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)
static inline void PD_PsmEnterSnkStartUpState(pd_instance_t *pdInstance);
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
void PD_AutoSinkNegotiation(pd_instance_t *pdInstance, pd_rdo_t *rdoRequest);
#endif
static inline void PD_PsmEnterSnkEvaluateCapState(pd_instance_t *pdInstance);
static inline void PD_PsmEnterSnkReadyState(pd_instance_t *pdInstance);
static inline void PD_PsmEnterSnkTransitionToDefaultState(pd_instance_t *pdInstance);
#endif
static pd_state_machine_state_t PD_PsmEnterState(pd_instance_t *pdInstance);
static pd_state_machine_state_t PD_PsmGetNewestEvent(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo);
static uint8_t PD_PsmCheckTimeOutHardReset(pd_instance_t *pdInstance);
static uint8_t PD_PsmProcessHardResetState(pd_instance_t *pdInstance);
static uint8_t PD_PsmProcessSendSoftResetState(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo);
static void PD_PsmCheckUnexpectedReceivedMsg(pd_instance_t *pdInstance,
trigger_event_t triggerEvent,
uint8_t *didNothingStepB);
static uint8_t PD_PsmProcessReadyState(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo);
#if (defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)) || \
((defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE))
static inline uint8_t PD_PsmGetTypeCCurrent(pd_instance_t *pdInstance);
#endif
static pd_state_machine_state_t PD_PsmProcessState(pd_instance_t *pdInstance);
#if ((defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE)) || \
(defined(PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE))
static void PD_PsmEndVdmCommand(pd_instance_t *pdInstance, pd_psm_state_t secondState);
#endif
#if (defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE)
static pd_psm_state_t PD_PsmVdmCheckkVDMBusyTimer(pd_instance_t *pdInstance, pd_psm_state_t newState);
static pd_psm_state_t PD_PsmVdmIdleProcessDpmMessage(pd_instance_t *pdInstance,
start_of_packet_t statIndex,
psm_trigger_info_t *triggerInfo);
#if 0
static uint8_t PDPsmVdmEnterExitModePdMsgProcess(pd_instance_t *pdInstance,
uint8_t statIndex,
psm_trigger_info_t *triggerInfo,
pd_svdm_command_request_t *commandVdmRequest);
#endif
static void PD_PsmVdmIdleProcessPdMessage(pd_instance_t *pdInstance,
start_of_packet_t statIndex,
psm_trigger_info_t *triggerInfo);
#endif
#if (defined(PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE)) || \
(defined(PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE))
static pd_psm_state_t PD_PsmStructuredVdmInitiatorRequest(pd_instance_t *pdInstance,
start_of_packet_t sopIndex,
uint16_t svid,
uint8_t position,
pd_vdm_command_t command,
uint8_t vdo_count,
uint32_t *vdos);
static pd_psm_state_t PD_PsmVdmResponseHandler(pd_instance_t *pdInstance,
start_of_packet_t sop,
uint8_t vdmMsgType,
psm_trigger_info_t *triggerInfo,
tTimer_t timr,
pd_psm_state_t ackState,
pd_psm_state_t nakState);
#if defined(PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)
static void PD_PsmSecondaryStateHandlerTerminate(pd_instance_t *pdInstance, start_of_packet_t sop);
#endif
static uint8_t PD_PsmSecondaryStateHandler(pd_instance_t *pdInstance,
start_of_packet_t statIndex,
psm_trigger_info_t *triggerInfo);
#endif
#if (defined PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
static uint8_t PD_CheckWhetherInitiateCableDiscoveryIdentityOrNot(pd_instance_t *pdInstance);
#endif
static pd_state_machine_state_t PD_PsmStateMachine(pd_instance_t *pdInstance);
#if defined(PD_CONFIG_PHY_LOW_POWER_LEVEL) && (PD_CONFIG_PHY_LOW_POWER_LEVEL)
static void PD_LowPowerTransition(pd_instance_t *pdInstance);
#endif
static pd_status_t PD_InitiateAmsCheck(pd_instance_t *pdInstance, pd_command_t command);
static pd_status_t PD_DpmAppCallback(pd_instance_t *pdInstance,
pd_dpm_callback_event_t event,
void *param,
uint8_t done);
/*******************************************************************************
* Variables
******************************************************************************/
/*******************************************************************************
* Code
******************************************************************************/
/*! ***************************************************************************
Send message transition functions
******************************************************************************/
static void PD_PsmTransitionOnMsgSendError(pd_instance_t *pdInstance,
pd_psm_state_t interruptedState,
pd_psm_state_t errorState)
{
#if ((defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE)) || \
((defined PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT))
/* MISRA C:2012 Rule 14.3 */
if (
#if ((defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE))
((PD_MsgRecvPending(pdInstance) != 0U) &&
((pdInstance->receivedSop == kPD_MsgSOP) &&
(((MSG_DATA_HEADER & PD_MSG_HEADER_MESSAGE_TYPE_MASK) >> PD_MSG_HEADER_MESSAGE_TYPE_POS) ==
((uint8_t)kPD_MsgVendorDefined & PD_MSG_TYPE_VALUE_MASK))))
#if ((defined PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT))
||
#endif
#endif
#if ((defined PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT))
((PD_MsgRecvPending(pdInstance) != 0U) && (pdInstance->receivedSop == kPD_MsgSOP) &&
((MSG_DATA_HEADER & PD_MSG_HEADER_EXTENDED_MASK) != 0U))
#endif
)
{
/* re-execute the psmCurState */
if (pdInstance->psmCurState != PSM_INTERRUPTED_REQUEST)
{
pdInstance->psmInterruptedState = pdInstance->psmCurState;
pdInstance->psmCurState = PSM_INTERRUPTED_REQUEST;
}
pdInstance->psmNewState = PSM_INTERRUPTED_REQUEST;
}
#endif
if (PD_MsgRecvPending(pdInstance) != 0U)
{
pdInstance->psmNewState = interruptedState;
}
else
{
pdInstance->psmNewState = errorState;
}
return;
}
static uint8_t PD_MsgSendMsgCommonTransition(pd_instance_t *pdInstance,
start_of_packet_t sop,
message_type_t msgType,
uint32_t dataLength,
uint8_t *dataBuffer,
pd_psm_state_t successNextState,
pd_psm_state_t interruptedState,
pd_psm_state_t errorState)
{
pd_status_t result = kStatus_PD_Error;
#if defined(PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
if ((((uint8_t)msgType & PD_MSG_TYPE_BITS_MASK) == PD_MSG_CONTROL_TYPE_MASK) ||
(((uint8_t)msgType & PD_MSG_TYPE_BITS_MASK) == PD_MSG_DATA_TYPE_MASK))
#endif
{
result = PD_MsgSend(pdInstance, sop, msgType, 2U + (dataLength * 4U), (uint8_t *)dataBuffer);
}
#if defined(PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
else
{
/* dataSize for an unchunked message and only one chunked message equals to dataLength */
result = PD_MsgSendExtendedMsg(pdInstance, sop, msgType, dataLength, dataBuffer, (uint16_t)dataLength, 0, 0);
}
#endif
if (result == kStatus_PD_Success)
{
if (successNextState != PE_PSM_STATE_NO_CHANGE)
{
pdInstance->psmNewState = successNextState;
}
return 1; /* success */
}
PD_PsmTransitionOnMsgSendError(pdInstance, interruptedState, errorState);
return 0; /* fail */
}
static inline uint8_t PD_MsgSendDataTransition(pd_instance_t *pdInstance,
message_type_t msgType,
uint32_t doCount,
uint32_t *dos,
pd_psm_state_t successNextState,
pd_psm_state_t interruptedState,
pd_psm_state_t errorState)
{
return PD_MsgSendMsgCommonTransition(pdInstance, kPD_MsgSOP, msgType, doCount, (uint8_t *)dos, successNextState,
interruptedState, errorState);
}
static inline uint8_t PD_MsgSendControlTransition(pd_instance_t *pdInstance,
message_type_t msgType,
pd_psm_state_t successNextState,
pd_psm_state_t interruptedState,
pd_psm_state_t errorState)
{
return PD_MsgSendMsgCommonTransition(pdInstance, kPD_MsgSOP, msgType, 0, NULL, successNextState, interruptedState,
errorState);
}
#if defined(PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
static inline uint8_t PD_MsgSendExtTransition(pd_instance_t *pdInstance,
start_of_packet_t sop,
message_type_t msgType,
uint32_t dataLength,
uint8_t *dataBuffer,
pd_psm_state_t successNextState,
pd_psm_state_t interruptedState,
pd_psm_state_t errorState)
{
return PD_MsgSendMsgCommonTransition(pdInstance, sop, msgType, dataLength, dataBuffer, successNextState,
interruptedState, errorState);
}
#endif
static inline uint8_t PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(pd_instance_t *pdInstance,
message_type_t msgType,
pd_psm_state_t successNextState)
{
return PD_MsgSendControlTransition(pdInstance, msgType, successNextState, PSM_CHECK_ASYNC_RX, PSM_SEND_SOFT_RESET);
}
#if defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
static inline uint8_t PD_PsmSendControlTransitionWithErrorRecovery(pd_instance_t *pdInstance,
message_type_t msgType,
pd_psm_state_t successNextState)
{
return PD_MsgSendControlTransition(pdInstance, msgType, successNextState, PSM_EXIT_TO_ERROR_RECOVERY_WITH_DELAY,
PSM_EXIT_TO_ERROR_RECOVERY_WITH_DELAY);
}
#endif
static inline uint8_t PD_PsmSendControlTransitionWithHardReset(pd_instance_t *pdInstance,
message_type_t msgType,
pd_psm_state_t successNextState)
{
return PD_MsgSendControlTransition(pdInstance, msgType, successNextState, PSM_HARD_RESET, PSM_HARD_RESET);
}
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
/* 0 - fail; 1 -success */
static uint8_t PD_PsmSendControlTransitionWithTry(pd_instance_t *pdInstance,
message_type_t msgType,
pd_psm_state_t successNextState,
pd_psm_state_t interruptedState,
pd_psm_state_t errorState)
{
uint8_t retryCount = 5;
do
{
if (PD_MsgSend(pdInstance, kPD_MsgSOP, msgType, 2, NULL) == kStatus_PD_Success)
{
break; /* success */
}
} while (--retryCount > 0U);
if (retryCount == 0U)
{
PD_PsmTransitionOnMsgSendError(pdInstance, interruptedState, errorState);
return 0;
}
else
{
pdInstance->psmNewState = successNextState;
}
return 1;
}
#endif
static uint8_t PD_PsmSendControlTransitionWithSendResponserTimeOut(pd_instance_t *pdInstance,
message_type_t msgType,
pd_psm_state_t successNextState,
pd_psm_state_t interruptedState,
pd_psm_state_t errorState)
{
if (PD_MsgSendControlTransition(pdInstance, msgType, successNextState, interruptedState, errorState) != 0U)
{
(void)PD_TimerStart(pdInstance, tSenderResponseTimer, T_SENDER_RESPONSE);
return 1;
}
return 0;
}
/*! ***************************************************************************
Other small functions
******************************************************************************/
static void PD_FRSControl(pd_instance_t *pdInstance, uint8_t enable)
{
uint8_t control;
#if (defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
if (enable != 0U)
{
if (pdInstance->revision >= PD_SPEC_REVISION_30)
{
control = 1;
(void)PD_PhyControl(pdInstance, PD_PHY_CONTROL_FR_SWAP, &control);
}
}
else
#endif
{
control = 0;
(void)PD_PhyControl(pdInstance, PD_PHY_CONTROL_FR_SWAP, &control);
}
}
static void PD_PsmReset(pd_instance_t *pdInstance)
{
#if (defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE)
uint8_t uint8Tmp;
#endif
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
pdInstance->vconnSwapResult = kCommandResult_None;
pdInstance->drSwapResult = kCommandResult_None;
pdInstance->swapToSnkSrcCapReceived = 0;
pdInstance->portPartnerDrSwapToUFPRejected = 0;
pdInstance->portPartnerDrSwapToDFPRejected = 0;
pdInstance->portPartnerPrSwapToSinkRejected = 0;
pdInstance->portPartnerPrSwapToSourceRejected = 0;
pdInstance->portPartnerVconnSwapToOnRejected = 0;
pdInstance->portPartnerVconnSwapToOffRejected = 0;
#endif
pdInstance->revision = PD_CONFIG_REVISION;
pdInstance->psmGotoMinTx = 0;
pdInstance->psmGotoMinRx = 0;
pdInstance->psmHardResetNeedsVSafe0V = 0;
pdInstance->psmPresentlyPdConnected = 0;
pdInstance->psmCablePlugResetNeeded = 0;
pdInstance->commandEvaluateResult = kCommandResult_None;
#if defined(PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE) && (PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE)
pdInstance->commandSrcOwner = 0;
#endif
#if (defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE)
pdInstance->psmVdmActiveModeValidMask = 0;
for (uint8Tmp = 0; uint8Tmp < PSM_SECONDARY_STATE_COUNT; uint8Tmp++)
{
pdInstance->psmSecondaryState[uint8Tmp] = PSM_IDLE;
pdInstance->psmNewSecondaryState[uint8Tmp] = PSM_UNKNOWN;
}
#endif
PD_FRSControl(pdInstance, 0);
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
pdInstance->frsEnabled = 0;
pdInstance->frSignaledWaitFrSwap = 0;
#endif
PD_TimerCancelAllTimers(pdInstance, tSenderResponseTimer, _tMaxPSMTimer);
}
static void PD_PsmSetNormalPower(pd_instance_t *pdInstance)
{
switch (pdInstance->psmCurState)
{
/* the follow state is stable state (may stay long time) */
case PSM_PE_SRC_READY:
case PSM_PE_SNK_READY:
case PSM_PE_SNK_WAIT_FOR_CAPABILITIES:
case PSM_PE_SRC_SEND_CAPABILITIES:
case PSM_PE_SRC_DISABLED:
case PSM_EXIT_TO_ERROR_RECOVERY:
case PSM_EXIT_TO_ERROR_RECOVERY_WITH_DELAY:
#if (defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
if (pdInstance->inProgress != kVbusPower_InFRSwap)
#endif
{
PD_ConnectSetPowerProgress(pdInstance, kVbusPower_Stable);
}
break;
default:
/* No action required. */
break;
}
}
static void PD_PsmCheckRevision(pd_instance_t *pdInstance, pd_msg_header_t msgHeader)
{
if (pdInstance->revision > msgHeader.bitFields.specRevision)
{
pdInstance->revision = (uint8_t)msgHeader.bitFields.specRevision;
(void)PD_PhyControl(pdInstance, PD_PHY_SET_MSG_HEADER_INFO, NULL);
}
}
#if (defined PD_CONFIG_PD3_PPS_ENABLE) && (PD_CONFIG_PD3_PPS_ENABLE)
/* for sink */
static uint8_t PD_PsmSinkIsPPSRDO(pd_instance_t *pdInstance)
{
uint8_t rdoIndex = (uint8_t)pdInstance->rdoRequest.bitFields.objectPosition - 1U;
if (rdoIndex < pdInstance->partnerSourcePDOsCount)
{
if ((pdInstance->partnerSourcePDOs[rdoIndex].commonPDO.pdoType == (uint8_t)kPDO_APDO) &&
(pdInstance->partnerSourcePDOs[rdoIndex].apdoPDO.APDOType == (uint8_t)kAPDO_PPS))
{
return 1;
}
}
return 0;
}
/* for source */
static uint8_t PD_PsmSourceIsPPSRDO(pd_instance_t *pdInstance)
{
uint8_t rdoIndex = (uint8_t)pdInstance->partnerRdoRequest.bitFields.objectPosition - 1U;
if (rdoIndex < pdInstance->pdPowerPortConfig->sourceCapCount)
{
pd_source_pdo_t sourcePDO;
sourcePDO.PDOValue = pdInstance->pdPowerPortConfig->sourceCaps[rdoIndex];
if ((sourcePDO.commonPDO.pdoType == (uint8_t)kPDO_APDO) && (sourcePDO.apdoPDO.APDOType == (uint8_t)kAPDO_PPS))
{
return 1;
}
}
return 0;
}
#endif
#if ((defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)) || \
((defined PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE))
static uint8_t PD_PsmIsDualRole(pd_instance_t *pdInstance)
{
if ((pdInstance->pdPowerPortConfig->typecRole == (uint8_t)kPowerConfig_SinkDefault) ||
(pdInstance->pdPowerPortConfig->typecRole == (uint8_t)kPowerConfig_SourceDefault) ||
(pdInstance->pdPowerPortConfig->typecRole == (uint8_t)kPowerConfig_DRPToggling) ||
(pdInstance->pdPowerPortConfig->typecRole == (uint8_t)kPowerConfig_DRPSourcingDevice) ||
(pdInstance->pdPowerPortConfig->typecRole == (uint8_t)kPowerConfig_DRPSinkingHost))
{
return 1;
}
return 0;
}
#endif
#if (defined PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
static uint32_t *PD_PsmGetSourcePDOs(pd_instance_t *pdInstance)
{
uint8_t index;
pd_source_pdo_t *pdo;
pd_source_pdo_t *destPdo;
#if defined(PD_CONFIG_EXTERNAL_POWER_DETECTION_SUPPORT) && (PD_CONFIG_EXTERNAL_POWER_DETECTION_SUPPORT)
uint8_t externalPowerState = 0;
#endif
for (index = 0; index < pdInstance->pdPowerPortConfig->sourceCapCount; ++index)
{
pdo = (pd_source_pdo_t *)((void *)&pdInstance->pdPowerPortConfig->sourceCaps[index]);
destPdo = (pd_source_pdo_t *)((void *)&pdInstance->sendingData[index + 1U]);
destPdo->PDOValue = pdo->PDOValue;
switch ((pd_pdo_type_t)pdo->commonPDO.pdoType)
{
case kPDO_Fixed:
{
if (pdo->fixedPDO.maxCurrent > pdInstance->dpmCableMaxCurrent)
{
destPdo->fixedPDO.maxCurrent = pdInstance->dpmCableMaxCurrent;
}
break;
}
case kPDO_Variable:
{
if (pdo->variablePDO.maxCurrent > pdInstance->dpmCableMaxCurrent)
{
destPdo->variablePDO.maxCurrent = pdInstance->dpmCableMaxCurrent;
}
break;
}
case kPDO_Battery:
{
if ((pdo->batteryPDO.maxAllowPower * 500U / pdo->batteryPDO.minVoltage) >
pdInstance->dpmCableMaxCurrent)
{
destPdo->batteryPDO.maxAllowPower = (uint32_t)pdInstance->dpmCableMaxCurrent * 10U *
(pdo->batteryPDO.minVoltage * 50U / 1000U) / 250U;
}
break;
}
default:
/* No action required. */
break;
}
}
destPdo = (pd_source_pdo_t *)((void *)&pdInstance->sendingData[1]);
#if defined(PD_CONFIG_EXTERNAL_POWER_DETECTION_SUPPORT) && (PD_CONFIG_EXTERNAL_POWER_DETECTION_SUPPORT)
(void)pdInstance->pdCallback(pdInstance->callbackParam, PD_DPM_GET_EXTERNAL_POWER_STATE, &externalPowerState);
destPdo->fixedPDO.externalPowered = externalPowerState;
#endif
if (pdInstance->revision < PD_SPEC_REVISION_30)
{
destPdo->fixedPDO.unchunkedSupported = 0;
}
return (uint32_t *)&(pdInstance->sendingData[1]);
}
#endif
#if (defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)
static uint32_t *PD_PsmGetSinkPDOs(pd_instance_t *pdInstance)
{
uint8_t index;
pd_sink_fixed_pdo_t *pdo = (pd_sink_fixed_pdo_t *)((void *)&pdInstance->sendingData[1]);
#if defined(PD_CONFIG_EXTERNAL_POWER_DETECTION_SUPPORT) && (PD_CONFIG_EXTERNAL_POWER_DETECTION_SUPPORT)
uint8_t externalPowerState = 0;
#endif
for (index = 0; index < pdInstance->pdPowerPortConfig->sinkCapCount; ++index)
{
pdInstance->sendingData[index + 1U] = pdInstance->pdPowerPortConfig->sinkCaps[index];
}
#if defined(PD_CONFIG_EXTERNAL_POWER_DETECTION_SUPPORT) && (PD_CONFIG_EXTERNAL_POWER_DETECTION_SUPPORT)
(void)pdInstance->pdCallback(pdInstance->callbackParam, PD_DPM_GET_EXTERNAL_POWER_STATE, &externalPowerState);
pdo->externalPowered = externalPowerState;
#endif
if (pdInstance->revision < PD_SPEC_REVISION_30)
{
pdo->frSwapRequiredCurrent = 0;
}
return (uint32_t *)&(pdInstance->sendingData[1]);
}
#endif
static void PD_PsmClearStateFlags(pd_instance_t *pdInstance)
{
/* Initialise static flags */
PD_PsmReset(pdInstance);
pdInstance->psmCurState = PSM_UNKNOWN;
pdInstance->psmNewState = PSM_UNKNOWN;
pdInstance->dpmStateMachine = 0;
pdInstance->psmPresentlyPdConnected = 0;
pdInstance->psmPreviouslyPdConnected = 0;
pdInstance->psmExplicitContractExisted = 0;
pdInstance->unchunkedFeature = 0;
pdInstance->commandProcessing = PD_DPM_INVALID;
pdInstance->dpmMsgBits = 0;
pdInstance->taskWaitTime = PD_WAIT_EVENT_TIME;
pdInstance->asmHardResetSnkProcessing = 0;
pdInstance->hardResetReceived = 0;
pdInstance->psmCableIdentitiesDataCount = 0;
#if (defined(PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)) && \
(defined(PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE) && (PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE))
pdInstance->commandRetryCount = 0;
#endif
#if ((defined PD_CONFIG_EXTENDED_CHUNK_LAYER_SUPPORT) && (PD_CONFIG_EXTENDED_CHUNK_LAYER_SUPPORT))
PD_MsgChunkingLayerResetFlags(pdInstance);
#endif
}
static void PD_PsmDisconnect(pd_instance_t *pdInstance)
{
#if defined(PD_CONFIG_VBUS_ALARM_SUPPORT) && (PD_CONFIG_VBUS_ALARM_SUPPORT)
uint8_t enable = 0;
#endif
#if defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
pdInstance->psmPresentlyVconnSource = kPD_VconnNone;
#endif
pdInstance->connectState = kTYPEC_ConnectNone;
PD_PsmClearStateFlags(pdInstance);
/* disconnect message layer */
(void)PD_PhyControl(pdInstance, PD_PHY_RESET_MSG_FUNCTION, NULL);
#if defined(PD_CONFIG_VBUS_ALARM_SUPPORT) && (PD_CONFIG_VBUS_ALARM_SUPPORT)
(void)PD_PhyControl(pdInstance, PD_PHY_CONTROL_VBUS_ALARM, &enable);
#endif
}
static void PD_PsmConnect(pd_instance_t *pdInstance)
{
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
pdInstance->portPartnerSinkPDO1.PDOValue = 0;
#endif
(void)PD_PhyControl(pdInstance, PD_PHY_SET_MSG_HEADER_INFO, NULL);
pdInstance->dpmCableMaxCurrent = 3000 / 10; /* 3A */
PD_PsmClearStateFlags(pdInstance);
}
static pd_state_machine_state_t PD_PsmDisconnectCheck(pd_instance_t *pdInstance, pd_state_machine_state_t state)
{
if ((state != kSM_ErrorRecovery) && (state != kSM_Detach))
{
if (PD_ConnectCheck(pdInstance) == kConnectState_Disconnected)
{
state = kSM_Detach;
}
}
return state;
}
/* internal function */
#if (defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
static uint8_t PD_PsmCheckLessOrEqualVsafe5v(pd_instance_t *pdInstance)
{
uint8_t powerState =
(PD_VBUS_POWER_STATE_VSAFE5V_MASK | PD_VBUS_POWER_STATE_VBUS_MASK | PD_VBUS_POWER_STATE_VSAFE0V_MASK);
(void)PD_PhyControl(pdInstance, PD_PHY_GET_VBUS_POWER_STATE, &powerState);
if ((powerState & PD_VBUS_POWER_STATE_VSAFE5V_MASK) != 0U)
{
return 1;
}
if ((powerState & PD_VBUS_POWER_STATE_VSAFE0V_MASK) != 0U)
{
return 1;
}
if (((powerState & PD_VBUS_POWER_STATE_VSAFE5V_MASK) == 0U) && ((powerState & PD_VBUS_POWER_STATE_VBUS_MASK) == 0U))
{
return 1;
}
return 0;
}
static void PD_PsmCheckFRS5V(pd_instance_t *pdInstance)
{
if (pdInstance->fr5VOpened == 0U)
{
if (PD_PsmCheckLessOrEqualVsafe5v(pdInstance) != 0U)
{
(void)pdInstance->callbackFns->PD_SrcTurnOnTypeCVbus(pdInstance->callbackParam, kVbusPower_InFRSwap);
pdInstance->fr5VOpened = 1;
}
}
}
#endif /* PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE */
static uint8_t PD_DpmGetMsg(pd_instance_t *pdInstance)
{
uint8_t reVal = 0;
uint8_t commandIndex;
if (pdInstance->dpmMsgBits != 0U)
{
for (commandIndex = (uint8_t)PD_DPM_CONTROL_POWER_NEGOTIATION; commandIndex < (uint8_t)PD_DPM_CONTROL_COUNT;
++commandIndex)
{
if ((pdInstance->dpmMsgBits & ((uint32_t)0x01U << commandIndex)) != 0U)
{
reVal = commandIndex;
break;
}
}
}
return reVal;
}
static void PD_DpmClearMsg(pd_instance_t *pdInstance, pd_command_t id)
{
OSA_SR_ALLOC();
OSA_ENTER_CRITICAL();
if ((pdInstance->dpmMsgBits & ((uint32_t)0x01U << (uint8_t)id)) != 0U)
{
pdInstance->dpmMsgBits &= (~((uint32_t)0x01U << (uint8_t)id));
}
OSA_EXIT_CRITICAL();
}
static void PD_DpmSendMsg(pd_handle pdHandle, uint8_t id)
{
pd_instance_t *pdInstance = (pd_instance_t *)pdHandle;
OSA_SR_ALLOC();
OSA_ENTER_CRITICAL();
pdInstance->dpmMsgBits |= ((uint32_t)0x01U << id);
#if (defined(PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)) && \
(defined(PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE) && (PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE))
pdInstance->commandRetryCount = N_DPM_COMMAND_RETRY_COUNTER;
#endif
OSA_EXIT_CRITICAL();
PD_StackSetEvent(pdInstance, PD_TASK_EVENT_DPM_MSG);
}
/*! ***************************************************************************
command flow and message flow and state machine related functions
******************************************************************************/
#if ((defined PD_CONFIG_EXTENDED_CHUNK_LAYER_SUPPORT) && (PD_CONFIG_EXTENDED_CHUNK_LAYER_SUPPORT))
static void PD_MsgChunkingLayerResetFlags(pd_instance_t *pdInstance)
{
pdInstance->chunkingRXState = RCH_Wait_For_Message_From_Protocol_Layer;
pdInstance->chunkingTXState = TCH_Wait_For_Message_Request_From_Policy_Engine;
}
static uint8_t PD_PsmChunkingLayerRXTimerWaiting(pd_instance_t *pdInstance)
{
return (RCH_Waiting_Chunk == pdInstance->chunkingRXState) ? 1U : 0U;
}
static uint8_t PD_PsmChunkingLayerRXStateMachine(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo)
{
pd_chunking_layer_state_t prevState = pdInstance->chunkingRXState;
pd_extended_msg_header_t extHeader;
if (triggerInfo->pdMsgDataBuffer != NULL)
{
extHeader.extendedMsgHeaderVal =
USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(((uint8_t *)triggerInfo->pdMsgDataBuffer));
}
else
{
extHeader.extendedMsgHeaderVal = 0;
}
/* state not change */
switch (pdInstance->chunkingRXState)
{
case RCH_Wait_For_Message_From_Protocol_Layer: /* B */
{
if ((triggerInfo->triggerEvent == PSM_TRIGGER_PD_MSG) &&
((triggerInfo->msgHeader.bitFields.extended == 0U) ||
((extHeader.bitFields.chunked == 0U) && (pdInstance->unchunkedFeature != 0U))))
{
pdInstance->chunkingRXState = RCH_Pass_Up_Message;
}
else if ((triggerInfo->triggerEvent == PSM_TRIGGER_PD_MSG) &&
(triggerInfo->msgHeader.bitFields.extended != 0U) && (extHeader.bitFields.chunked != 0U))
{
pdInstance->chunkingRXState = RCH_Processing_Extended_Message;
}
else if (pdInstance->unchunkedFeature == extHeader.bitFields.chunked)
{
pdInstance->chunkingRXState = RCH_Report_Error;
}
else
{
/* No action required. */
}
break;
}
case RCH_Waiting_Chunk: /* B */
if ((triggerInfo->triggerEvent == PSM_TRIGGER_PD_MSG) &&
(triggerInfo->msgHeader.bitFields.extended != 0U) && (extHeader.bitFields.chunked != 0U) &&
(pdInstance->chunkNumberExpected == extHeader.bitFields.chunkNumber))
{
pdInstance->chunkingRXState = RCH_Processing_Extended_Message;
}
else if ((PD_TimerCheckInvalidOrTimeOut(pdInstance, timrChunkSenderResponseTimer) != 0U) ||
(triggerInfo->triggerEvent == PSM_TRIGGER_PD_MSG))
{
pdInstance->chunkingRXState = RCH_Report_Error;
}
else
{
/* No action required. */
}
break;
default:
/* Any Message Received and not in state RCH_Waiting_Chunk or RCH_Wait_For_Message_From_Protocol_Layer */
pdInstance->chunkingRXState = RCH_Report_Error;
break;
}
while (prevState != pdInstance->chunkingRXState)
{
prevState = pdInstance->chunkingRXState;
switch (pdInstance->chunkingRXState)
{
case RCH_Wait_For_Message_From_Protocol_Layer: /* C */
/* pdInstance->abortFlag = 0; */
/* TODO: clear extended Rx Buffer */
break;
case RCH_Pass_Up_Message: /* C */
pdInstance->chunkingRXState = RCH_Wait_For_Message_From_Protocol_Layer;
break;
case RCH_Processing_Extended_Message: /* C */
if (extHeader.bitFields.chunkNumber == 0U)
{
pdInstance->chunkNumberExpected = 0;
pdInstance->chunkNumBytesReceived = 0;
}
if (extHeader.bitFields.chunkNumber == pdInstance->chunkNumberExpected)
{
pdInstance->chunkNumBytesReceived += (triggerInfo->msgHeader.bitFields.NumOfDataObjs * 4U - 2U);
pdInstance->chunkNumberExpected++;
/* TODO: copy data to buff */
}
else if (extHeader.bitFields.chunkNumber != pdInstance->chunkNumberExpected)
{
pdInstance->chunkingRXState = RCH_Report_Error;
}
else
{
/* No action required. */
}
#if 0
if (pdInstance->abortFlag)
{
pdInstance->chunkingRXState = RCH_Wait_For_Message_From_Protocol_Layer;
}
else
#endif
if ((extHeader.bitFields.chunkNumber * 26U +
(triggerInfo->msgHeader.bitFields.NumOfDataObjs * 4U - 2U)) >= extHeader.bitFields.dataSize)
{
pdInstance->chunkingRXState = RCH_Pass_Up_Message;
}
else
{
/* message is not completeed */
pdInstance->chunkingRXState = RCH_Requesting_Chunk;
}
break;
case RCH_Requesting_Chunk: /* C */
/* dataSize = 0, requestChunk = 1 */
if (PD_MsgSendExtendedMsg(pdInstance, triggerInfo->pdMsgSop, triggerInfo->pdMsgType, 0, NULL, 0, 1,
pdInstance->chunkNumberExpected) == kStatus_PD_Success)
{
pdInstance->chunkingRXState = RCH_Waiting_Chunk;
}
else
{
pdInstance->chunkingRXState = RCH_Report_Error;
}
break;
case RCH_Waiting_Chunk: /* C */
(void)PD_TimerStart(pdInstance, timrChunkSenderResponseTimer, T_CHUNK_SENDER_RESPONSE);
break;
case RCH_Report_Error: /* C */
/* TODO: report error to policy engine */
pdInstance->chunkingRXState = RCH_Wait_For_Message_From_Protocol_Layer;
break;
default:
/* No action required. */
break;
}
}
return (pdInstance->chunkingRXState == RCH_Wait_For_Message_From_Protocol_Layer) ? 1U : 0U;
}
#if 0 /* comments it temparily for the warning (declared but never referenced) */
static uint8_t PD_PsmChunkingLayerCheckSentDone(pd_instance_t *pdInstance)
{
return pdInstance->chunkSentDone;
}
static pd_status_t PD_PsmChunkingLayerTXStateMachine(pd_instance_t *pdInstance, start_of_packet_t sop, message_type_t msgType, uint8_t *dataBuffer, uint32_t dataLength, psm_trigger_info_t *triggerInfo)
{
pd_chunking_layer_state_t prevState = pdInstance->chunkingTXState;
pd_status_t status = kStatus_PD_Success;
/* state not change */
switch (pdInstance->chunkingTXState)
{
case TCH_Wait_For_Message_Request_From_Policy_Engine: /* B */
if (pdInstance->chunkingRXState != RCH_Wait_For_Message_From_Protocol_Layer)
{
pdInstance->chunkingTXState = TCH_Report_Error;
}
else
{
/* only chunking msg is passed to this function */
pdInstance->chunkingTXState = TCH_Prepare_To_Send_Chunked_Message;
}
break;
case TCH_Wait_Chunk_Request: /* B */
{
pd_extended_msg_header_t extHeader;
extHeader.extendedMsgHeaderVal = USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(((uint8_t *)triggerInfo->pdMsgDataBuffer));
if ((triggerInfo != NULL) && (triggerInfo->triggerEvent == PSM_TRIGGER_PD_MSG) && (triggerInfo->msgHeader.bitFields.extended != 0U) &&
(extHeader.bitFields.chunked != 0U) && (pdInstance->chunkNumberToSend == extHeader.bitFields.chunkNumber))
{
pdInstance->chunkingTXState = TCH_Sending_Chunked_Message;
}
else if ((triggerInfo != NULL) && (triggerInfo->triggerEvent == PSM_TRIGGER_PD_MSG))
{
status = kStatus_PD_Error;
pdInstance->chunkingTXState = TCH_Wait_For_Message_Request_From_Policy_Engine;
}
else if (PD_TimerCheckInvalidOrTimeOut(pdInstance, timrChunkSenderResponseTimer) != 0U)
{
/* still think success */
pdInstance->chunkingTXState = TCH_Message_Sent;
}
else
{
/* No action required. */
}
break;
}
}
while (prevState != pdInstance->chunkingTXState)
{
prevState = pdInstance->chunkingTXState;
switch (pdInstance->chunkingTXState)
{
case TCH_Report_Error: /* C */
status = kStatus_PD_Error;
pdInstance->chunkingTXState = TCH_Wait_For_Message_Request_From_Policy_Engine;
break;
case TCH_Prepare_To_Send_Chunked_Message: /* C */
pdInstance->chunkNumberToSend = 0;
pdInstance->chunkSentDone = 0;
pdInstance->chunkingTXState = TCH_Sending_Chunked_Message;
break;
case TCH_Sending_Chunked_Message: /* C */
{
uint32_t sendLength = (dataLength - pdInstance->chunkNumberToSend * 26);
if (sendLength > 26)
{
sendLength = 26;
}
/* dataSize = dataLength, requestChunk = 0 */
if (PD_MsgSendExtendedMsg(pdInstance, sop, msgType, sendLength, dataBuffer,
(uint16_t)dataLength, 0, pdInstance->chunkNumberToSend) == kStatus_PD_Success)
{
if (pdInstance->chunkNumberToSend == ((dataLength + 25) / 26))
{
pdInstance->chunkingTXState = TCH_Message_Sent;
}
else
{
pdInstance->chunkingTXState = TCH_Wait_Chunk_Request;
}
}
else
{
pdInstance->chunkingTXState = TCH_Report_Error;
}
break;
}
case TCH_Wait_Chunk_Request: /* C */
pdInstance->chunkNumberToSend++;
(void)PD_TimerStart(pdInstance, timrChunkSenderRequestTimer, T_CHUNK_SENDER_REQUEST);
break;
case TCH_Message_Sent: /* C */
pdInstance->chunkSentDone = 1;
pdInstance->chunkingTXState = TCH_Wait_For_Message_Request_From_Policy_Engine;
break;
case TCH_Wait_For_Message_Request_From_Policy_Engine: /* C */
pdInstance->chunkSentDone = 1;
break;
default:
/* No action required. */
break;
}
}
return status;
}
#endif
#endif
#if (defined PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
static uint8_t PD_PsmCheckInAltMode(pd_instance_t *pdInstance, start_of_packet_t sop)
{
#if (defined PD_CONFIG_ALT_MODE_SUPPORT) && (PD_CONFIG_ALT_MODE_SUPPORT)
uint8_t altModeState = 0;
if ((PD_AltModeState(pdInstance, &altModeState) == kStatus_PD_Success) && (altModeState != 0U))
{
return 1;
}
#endif
#if (defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE)
if (pdInstance->psmVdmActiveModeValidMask != 0U)
{
return 1;
}
#endif
return 0;
}
#endif
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY_LOG) && (PD_CONFIG_ENABLE_AUTO_POLICY_LOG)
static void PD_PsmPrintAutoPolicyReplySwapRequestLog(pd_instance_t *pdInstance, uint8_t message)
{
(void)PRINTF("auto reply ");
if (pdInstance->commandEvaluateResult == kCommandResult_Accept)
{
(void)PRINTF("accept");
}
else if (pdInstance->commandEvaluateResult == kCommandResult_Reject)
{
(void)PRINTF("reject");
}
else if (pdInstance->commandEvaluateResult == kCommandResult_Wait)
{
(void)PRINTF("wait");
}
else
{
/* No action required. */
}
(void)PRINTF(" for ");
switch ((message_type_t)message)
{
case kPD_MsgPrSwap:
(void)PRINTF("pr");
break;
case kPD_MsgDrSwap:
(void)PRINTF("dr");
break;
case kPD_MsgVconnSwap:
default:
(void)PRINTF("vconn");
break;
}
(void)PRINTF(" swap\r\n");
}
static void PD_PsmPrintAutoPolicyStartSwapLog(pd_instance_t *pdInstance, uint8_t message)
{
(void)PRINTF("start auto request ");
switch ((message_type_t)message)
{
case kPD_MsgPrSwap:
(void)PRINTF("pr");
break;
case kPD_MsgDrSwap:
(void)PRINTF("dr");
break;
case kPD_MsgVconnSwap:
default:
(void)PRINTF("vconn");
break;
}
(void)PRINTF(" swap\r\n");
}
#endif /* PD_CONFIG_ENABLE_AUTO_POLICY_LOG */
#if (defined PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
static uint8_t PD_PsmAutoRequestVconnSwap(pd_instance_t *pdInstance)
{
pd_vconn_role_t autoSwap = (pd_vconn_role_t)PD_POLICY_GET_AUTO_REQUEST_VCONNSWAP(pdInstance);
if ((!PD_POLICY_SUPPORT(pdInstance)) || (autoSwap == kPD_VconnNone))
{
return 0;
}
if ((pdInstance->pdPowerPortConfig->vconnSupported != 0U) && (pdInstance->vconnSwapResult == kCommandResult_None) &&
(autoSwap != pdInstance->psmPresentlyVconnSource))
{
if ((pdInstance->portPartnerVconnSwapToOffRejected == 0U) && (autoSwap == kPD_NotVconnSource))
{
return 1;
}
if ((pdInstance->portPartnerVconnSwapToOnRejected == 0U) && (autoSwap == kPD_IsVconnSource))
{
return 1;
}
}
return 0;
}
#endif
#if (defined PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
static uint8_t PD_PsmAutoRequestDataSwap(pd_instance_t *pdInstance)
{
pd_data_role_t autoSwap = (pd_data_role_t)PD_POLICY_GET_AUTO_REQUEST_DRSWAP(pdInstance);
if ((!PD_POLICY_SUPPORT(pdInstance)) || (autoSwap == kPD_DataRoleNone))
{
return 0;
}
/* Only auto-swap if there has been no previous activity
* Do not auto-swap if we are already in an alternate mode
*/
if ((PD_PsmCheckInAltMode(pdInstance, kPD_MsgSOP) == 0U) &&
(pdInstance->pdPowerPortConfig->dataFunction == (uint8_t)kDataConfig_DRD) &&
(pdInstance->drSwapResult == kCommandResult_None) && (autoSwap != pdInstance->curDataRole))
{
if ((pdInstance->portPartnerDrSwapToDFPRejected == 0U) && (autoSwap == kPD_DataRoleDFP))
{
return 1;
}
if ((pdInstance->portPartnerDrSwapToUFPRejected == 0U) && (autoSwap == kPD_DataRoleUFP))
{
return 1;
}
}
return 0;
}
#endif
#if (defined PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
static uint8_t PD_PsmAutoRequestPowerSwap(pd_instance_t *pdInstance)
{
if ((!PD_POLICY_SUPPORT(pdInstance)) || ((PD_POLICY_GET_AUTO_REQUEST_PRSWAP_AS_SOURCE(pdInstance) == 0U) &&
(PD_POLICY_GET_AUTO_REQUEST_PRSWAP_AS_SINK(pdInstance) == 0U)))
{
return 0;
}
if (PD_PsmIsDualRole(pdInstance) != 0U)
{
if ((pdInstance->curPowerRole == kPD_PowerRoleSource) && (pdInstance->portPartnerPrSwapToSinkRejected == 0U) &&
(PD_POLICY_GET_AUTO_REQUEST_PRSWAP_AS_SOURCE(pdInstance) != 0U))
{
return 1;
}
if ((pdInstance->curPowerRole == kPD_PowerRoleSink) && (pdInstance->portPartnerPrSwapToSourceRejected == 0U) &&
(PD_POLICY_GET_AUTO_REQUEST_PRSWAP_AS_SINK(pdInstance) != 0U))
{
return 1;
}
}
return 0;
}
#endif
static void PD_PsmSetAutoPolicyState(pd_instance_t *pdInstance, pd_auto_policy_state_t newState)
{
if (pdInstance->autoPolicyState == newState)
{
return;
}
pdInstance->autoPolicyState = newState;
if (((uint8_t)newState & (uint8_t)PSM_RDY_DELAY_FLAG) != 0U)
{
if (pdInstance->curPowerRole == kPD_PowerRoleSource)
{
(void)PD_TimerStart(pdInstance, timrPsmRdyEvalDelayTimer, T_PSM_SRC_RDY_EVAL_DELAY);
}
else
{
(void)PD_TimerStart(pdInstance, timrPsmRdyEvalDelayTimer, T_PSM_SNK_RDY_EVAL_DELAY);
}
}
}
static uint8_t PD_PsmGetExternalPowerState(pd_instance_t *pdInstance)
{
uint8_t externalPowerState;
#if defined(PD_CONFIG_EXTERNAL_POWER_DETECTION_SUPPORT) && (PD_CONFIG_EXTERNAL_POWER_DETECTION_SUPPORT)
if (pdInstance->pdCallback(pdInstance->callbackParam, PD_DPM_GET_EXTERNAL_POWER_STATE, &externalPowerState) !=
kStatus_PD_Success)
#endif
{
if ((pdInstance->curPowerRole == kPD_PowerRoleSource) &&
(pdInstance->pdPowerPortConfig->sourceCapCount != 0U) &&
(pdInstance->pdPowerPortConfig->sourceCaps != NULL))
{
pd_source_pdo_t sourcePDO;
sourcePDO.PDOValue = pdInstance->pdPowerPortConfig->sourceCaps[0];
externalPowerState = (uint8_t)sourcePDO.fixedPDO.externalPowered;
}
else if ((pdInstance->curPowerRole == kPD_PowerRoleSink) &&
(pdInstance->pdPowerPortConfig->sinkCapCount != 0U) &&
(pdInstance->pdPowerPortConfig->sinkCaps != NULL))
{
pd_sink_pdo_t sinkPDO;
sinkPDO.PDOValue = pdInstance->pdPowerPortConfig->sinkCaps[0];
externalPowerState = (uint8_t)sinkPDO.fixedPDO.externalPowered;
}
else
{
externalPowerState = 0;
}
}
return externalPowerState;
}
/* this function is called in rdy state */
static uint8_t PD_PsmReadyAutoPolicyProcess(pd_instance_t *pdInstance)
{
pd_auto_policy_state_t newAutoPolicySate;
uint8_t didNothing = 0;
if (((uint8_t)pdInstance->autoPolicyState & (uint8_t)PSM_RDY_DELAY_FLAG) != 0U)
{
if (PD_TimerCheckInvalidOrTimeOut(pdInstance, timrPsmRdyEvalDelayTimer) != 0U)
{
uint8_t tmpAutoPolicyState = ((uint8_t)pdInstance->autoPolicyState) & (~((uint8_t)PSM_RDY_DELAY_FLAG));
pdInstance->autoPolicyState = (pd_auto_policy_state_t)tmpAutoPolicyState;
}
else
{
return 1;
}
}
(void)OSA_EventClear(pdInstance->taskEventHandle, PD_TASK_EVENT_EXTERNAL_POWER_CHANGE);
newAutoPolicySate = pdInstance->autoPolicyState;
switch (pdInstance->autoPolicyState)
{
case PSM_RDY_EVAL_INIT:
{
/* Update whether we have seen external power, so we don't get into an idle loop */
pdInstance->rdySeenExtPower = PD_PsmGetExternalPowerState(pdInstance);
/* default enter into idle state */
newAutoPolicySate = PSM_RDY_EVAL_IDLE;
#if (defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)) || \
(defined(PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)) || \
(defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE))
/* MISRA C:2012 Rule 14.3 */
if (
#if (defined PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
(PD_PsmAutoRequestDataSwap(pdInstance) != 0U)
#if (defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)) || \
(defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE))
||
#endif
#endif
#if defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
(PD_PsmAutoRequestVconnSwap(pdInstance) != 0U)
#if defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
||
#endif
#endif
#if defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
(PD_PsmAutoRequestPowerSwap(pdInstance) != 0U)
/* Need to also check get partner capabilities to evaluate swap requests
(ConfigGetDualRolePower(CLPCfgTblPtr) && ConfigGetAutoAcceptPrSwap(CLPCfgTblPtr)) || */
#endif
)
{
#if defined(PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
if (pdInstance->curPowerRole == kPD_PowerRoleSource)
{
newAutoPolicySate =
(pd_auto_policy_state_t)((uint8_t)PSM_RDY_DELAY_FLAG | (uint8_t)PSM_RDY_EVAL_GET_SNK_CAP);
}
else
#endif
#if defined(PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)
if (pdInstance->curPowerRole == kPD_PowerRoleSink)
{
newAutoPolicySate =
(pd_auto_policy_state_t)((uint8_t)PSM_RDY_DELAY_FLAG | (uint8_t)PSM_RDY_EVAL_CHECK_PARTNER_CAP);
}
else
#endif
{
/* No action required. */
}
}
#endif
break;
}
#if defined(PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
case PSM_RDY_EVAL_GET_SNK_CAP:
if (PD_PsmStartCommand(pdInstance, PD_DPM_CONTROL_GET_PARTNER_SINK_CAPABILITIES, 1) != 0U)
{
/* On return to PSM_SRC_READY check the result */
newAutoPolicySate = PSM_RDY_EVAL_CHECK_PARTNER_CAP;
/* Get the sink capabilities, on return to READY state */
pdInstance->psmNewState = PSM_PE_SRC_GET_SINK_CAP;
pdInstance->dumpResponse = 1;
}
else
{
/* Fail, retry */
newAutoPolicySate =
(pd_auto_policy_state_t)((uint8_t)PSM_RDY_DELAY_FLAG | (uint8_t)PSM_RDY_EVAL_GET_SNK_CAP);
}
break;
#endif
#if (defined(PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)) || \
(defined(PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE))
case PSM_RDY_EVAL_CHECK_PARTNER_CAP:
pdInstance->rdySeenExtPower = PD_PsmGetExternalPowerState(pdInstance);
#if (defined PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
if (PD_PsmAutoRequestVconnSwap(pdInstance) != 0U)
{
/* Attempt to vconn swap */
newAutoPolicySate =
(pd_auto_policy_state_t)((uint8_t)PSM_RDY_DELAY_FLAG | (uint8_t)PSM_RDY_EVAL_VCONN_SWAP);
}
else
#endif
#if (defined PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
if ((PD_PsmAutoRequestDataSwap(pdInstance) != 0U) &&
(((pdInstance->curPowerRole == kPD_PowerRoleSource) &&
(pdInstance->portPartnerSinkPDO1.fixedPDO.dualRoleData != 0U)) ||
((pdInstance->curPowerRole == kPD_PowerRoleSink) &&
(pdInstance->selfOrPartnerFirstSourcePDO.fixedPDO.dualRoleData != 0U))))
{
/* Attempt to data role swap */
newAutoPolicySate =
(pd_auto_policy_state_t)((uint8_t)PSM_RDY_DELAY_FLAG | (uint8_t)PSM_RDY_EVAL_DR_SWAP);
}
else
#endif
#if (defined PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
/* auto request swap as sink && self is not external powered && partner is external powered */
if ((PD_PsmAutoRequestPowerSwap(pdInstance) != 0U) && (pdInstance->rdySeenExtPower == 0U) &&
(pdInstance->curPowerRole == kPD_PowerRoleSource) &&
/* #if !defined(USBPD_ENABLE_IMMEDIATE_SWAP_TO_SINK_ON_POWER_LOSS) ||
(!USBPD_ENABLE_IMMEDIATE_SWAP_TO_SINK_ON_POWER_LOSS) */
(pdInstance->portPartnerSinkPDO1.fixedPDO.externalPowered != 0U) &&
/* #endif */
(pdInstance->portPartnerSinkPDO1.fixedPDO.dualRolePower != 0U))
{
/* Attempt to swap to sink */
newAutoPolicySate =
(pd_auto_policy_state_t)((uint8_t)PSM_RDY_EVAL_SWAP_TO_SNK | (uint8_t)PSM_RDY_DELAY_FLAG);
#if 0
#if !defined(USBPD_ENABLE_IMMEDIATE_SWAP_TO_SINK_ON_POWER_LOSS) || (!USBPD_ENABLE_IMMEDIATE_SWAP_TO_SINK_ON_POWER_LOSS)
PSM_RDY_DELAY_FLAG;
#else
0;
#endif
#endif
}
/* auto request swap as source && self is external powered && partner is not external powered. */
else if ((PD_PsmAutoRequestPowerSwap(pdInstance) != 0U) && (pdInstance->rdySeenExtPower != 0U) &&
(pdInstance->curPowerRole == kPD_PowerRoleSink) &&
(pdInstance->selfOrPartnerFirstSourcePDO.fixedPDO.externalPowered == 0U) &&
(pdInstance->selfOrPartnerFirstSourcePDO.fixedPDO.dualRolePower != 0U))
{
/* Attempt to swap to source */
newAutoPolicySate =
(pd_auto_policy_state_t)((uint8_t)PSM_RDY_DELAY_FLAG | (uint8_t)PSM_RDY_EVAL_SWAP_TO_SRC);
}
else
#endif
{
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY_LOG) && (PD_CONFIG_ENABLE_AUTO_POLICY_LOG)
if ((PD_PsmAutoRequestPowerSwap(pdInstance) != 0U) &&
(pdInstance->curPowerRole == kPD_PowerRoleSource) &&
(pdInstance->portPartnerSinkPDO1.fixedPDO.externalPowered != 0U) &&
(pdInstance->portPartnerSinkPDO1.fixedPDO.dualRolePower != 0U))
{
(void)PRINTF("don't do auto request pr swap to sink when self is external powered\r\n");
}
else if ((PD_PsmAutoRequestPowerSwap(pdInstance) != 0U) &&
(pdInstance->curPowerRole == kPD_PowerRoleSink) &&
(pdInstance->selfOrPartnerFirstSourcePDO.fixedPDO.externalPowered == 0U) &&
(pdInstance->selfOrPartnerFirstSourcePDO.fixedPDO.dualRolePower != 0U))
{
(void)PRINTF("don't do auto request pr swap to source when self is not external powered\r\n");
}
else
{
/* No action required. */
}
#endif
newAutoPolicySate = (pd_auto_policy_state_t)((uint8_t)PSM_RDY_DELAY_FLAG | (uint8_t)PSM_RDY_EVAL_IDLE);
}
break;
#endif
#if (defined PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
case PSM_RDY_EVAL_SWAP_TO_SNK:
if ((PD_PsmAutoRequestPowerSwap(pdInstance) != 0U) &&
/* Check for a change in the externally powered status since last we saw it */
(pdInstance->rdySeenExtPower == PD_PsmGetExternalPowerState(pdInstance)))
{
if (PD_PsmStartCommand(pdInstance, PD_DPM_CONTROL_PR_SWAP, 1) != 0U)
{
newAutoPolicySate = PSM_RDY_EVAL_CHECK_SWAP_TO_SNK;
pdInstance->psmNewState = PSM_PE_PRS_SRC_SNK_SEND_PR_SWAP;
}
else
{
/* Fail, retry */
newAutoPolicySate =
(pd_auto_policy_state_t)((uint8_t)PSM_RDY_DELAY_FLAG | (uint8_t)PSM_RDY_EVAL_SWAP_TO_SNK);
}
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY_LOG) && (PD_CONFIG_ENABLE_AUTO_POLICY_LOG)
PD_PsmPrintAutoPolicyStartSwapLog(pdInstance, (uint8_t)kPD_MsgPrSwap);
#endif
}
else
{
newAutoPolicySate = PSM_RDY_EVAL_INIT;
}
break;
case PSM_RDY_EVAL_SWAP_TO_SRC:
if ((PD_PsmAutoRequestPowerSwap(pdInstance) != 0U) &&
/* Check for a change in the externally powered status since last we saw it */
(pdInstance->rdySeenExtPower == PD_PsmGetExternalPowerState(pdInstance)))
{
if (PD_PsmStartCommand(pdInstance, PD_DPM_CONTROL_PR_SWAP, 1) != 0U)
{
newAutoPolicySate = PSM_RDY_EVAL_CHECK_SWAP_TO_SRC;
pdInstance->psmNewState = PSM_PE_PRS_SNK_SRC_SEND_PR_SWAP;
}
else
{
/* Fail, retry */
newAutoPolicySate =
(pd_auto_policy_state_t)((uint8_t)PSM_RDY_DELAY_FLAG | (uint8_t)PSM_RDY_EVAL_SWAP_TO_SRC);
}
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY_LOG) && (PD_CONFIG_ENABLE_AUTO_POLICY_LOG)
PD_PsmPrintAutoPolicyStartSwapLog(pdInstance, (uint8_t)kPD_MsgPrSwap);
#endif
}
else
{
newAutoPolicySate = PSM_RDY_EVAL_INIT;
}
break;
#endif
#if (defined PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
case PSM_RDY_EVAL_DR_SWAP:
if (PD_PsmAutoRequestDataSwap(pdInstance) != 0U)
{
if (PD_PsmStartCommand(pdInstance, PD_DPM_CONTROL_DR_SWAP, 1) != 0U)
{
newAutoPolicySate = PSM_RDY_EVAL_CHECK_DR_SWAP;
pdInstance->psmNewState = PSM_PE_DRS_SEND_DR_SWAP;
}
else
{
/* Fail, retry */
newAutoPolicySate =
(pd_auto_policy_state_t)((uint8_t)PSM_RDY_DELAY_FLAG | (uint8_t)PSM_RDY_EVAL_DR_SWAP);
}
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY_LOG) && (PD_CONFIG_ENABLE_AUTO_POLICY_LOG)
PD_PsmPrintAutoPolicyStartSwapLog(pdInstance, (uint8_t)kPD_MsgDrSwap);
#endif
}
else
{
newAutoPolicySate = PSM_RDY_EVAL_INIT;
}
break;
#endif
#if defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
case PSM_RDY_EVAL_VCONN_SWAP:
if (PD_PsmAutoRequestVconnSwap(pdInstance) != 0U)
{
if (PD_PsmStartCommand(pdInstance, PD_DPM_CONTROL_VCONN_SWAP, 1) == 0U)
{
/* Fail, retry */
newAutoPolicySate =
(pd_auto_policy_state_t)((uint8_t)PSM_RDY_DELAY_FLAG | (uint8_t)PSM_RDY_EVAL_VCONN_SWAP);
}
else
{
newAutoPolicySate = PSM_RDY_EVAL_CHECK_VCONN_SWAP;
pdInstance->psmNewState = PSM_PE_VCS_SEND_SWAP;
}
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY_LOG) && (PD_CONFIG_ENABLE_AUTO_POLICY_LOG)
PD_PsmPrintAutoPolicyStartSwapLog(pdInstance, (uint8_t)kPD_MsgVconnSwap);
#endif
}
else
{
newAutoPolicySate = PSM_RDY_EVAL_INIT;
}
break;
#endif
case PSM_RDY_EVAL_IDLE:
/* Check for a change in the externally powered status since last we saw it */
if (pdInstance->rdySeenExtPower != PD_PsmGetExternalPowerState(pdInstance))
{
newAutoPolicySate = PSM_RDY_EVAL_INIT;
}
else
{
/* No further action required until something changes */
didNothing = 1;
}
break;
default:
didNothing = 1;
break;
}
PD_PsmSetAutoPolicyState(pdInstance, newAutoPolicySate);
return didNothing;
}
static void PD_PsmReadyAutoPolicyResult(pd_instance_t *pdInstance, pd_command_result_t result)
{
pd_auto_policy_state_t newAutoPolicySate = pdInstance->autoPolicyState;
switch (result)
{
/* If far end accepts, then we will be reset to PSM_RDY_EVAL_INIT at swap
For reject we move to check the conditions again after a short delay
For wait we return to try the same thing again. */
case kCommandResult_Reject:
switch (newAutoPolicySate)
{
#if (defined PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
case PSM_RDY_EVAL_CHECK_SWAP_TO_SNK:
pdInstance->portPartnerPrSwapToSinkRejected = 1;
break;
case PSM_RDY_EVAL_CHECK_SWAP_TO_SRC:
pdInstance->portPartnerPrSwapToSourceRejected = 1;
break;
#endif
#if (defined PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
case PSM_RDY_EVAL_CHECK_DR_SWAP:
if (pdInstance->curDataRole == kPD_DataRoleDFP)
{
pdInstance->portPartnerDrSwapToUFPRejected = 1;
}
else
{
pdInstance->portPartnerDrSwapToDFPRejected = 1;
}
break;
#endif
#if defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
case PSM_RDY_EVAL_CHECK_VCONN_SWAP:
if (pdInstance->psmPresentlyVconnSource == kPD_IsVconnSource)
{
pdInstance->portPartnerVconnSwapToOffRejected = 1;
}
else
{
pdInstance->portPartnerVconnSwapToOnRejected = 1;
}
break;
#endif
default:
/* No action required. */
break;
}
newAutoPolicySate = (pd_auto_policy_state_t)((uint8_t)PSM_RDY_DELAY_FLAG | (uint8_t)PSM_RDY_EVAL_INIT);
break;
case kCommandResult_Error:
case kCommandResult_Timeout:
newAutoPolicySate = (pd_auto_policy_state_t)((uint8_t)PSM_RDY_DELAY_FLAG | (uint8_t)PSM_RDY_EVAL_INIT);
break;
case kCommandResult_Wait:
switch (newAutoPolicySate)
{
#if (defined PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
case PSM_RDY_EVAL_CHECK_SWAP_TO_SNK:
newAutoPolicySate =
(pd_auto_policy_state_t)((uint8_t)PSM_RDY_DELAY_FLAG | (uint8_t)PSM_RDY_EVAL_SWAP_TO_SNK);
break;
case PSM_RDY_EVAL_CHECK_SWAP_TO_SRC:
newAutoPolicySate =
(pd_auto_policy_state_t)((uint8_t)PSM_RDY_DELAY_FLAG | (uint8_t)PSM_RDY_EVAL_SWAP_TO_SRC);
break;
#endif
#if (defined PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
case PSM_RDY_EVAL_CHECK_DR_SWAP:
newAutoPolicySate =
(pd_auto_policy_state_t)((uint8_t)PSM_RDY_DELAY_FLAG | (uint8_t)PSM_RDY_EVAL_DR_SWAP);
break;
#endif
#if defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
case PSM_RDY_EVAL_CHECK_VCONN_SWAP:
newAutoPolicySate =
(pd_auto_policy_state_t)((uint8_t)PSM_RDY_DELAY_FLAG | (uint8_t)PSM_RDY_EVAL_VCONN_SWAP);
break;
#endif
default:
/* No action required. */
break;
}
break;
default:
/* No action required. */
break;
}
PD_PsmSetAutoPolicyState(pdInstance, newAutoPolicySate);
}
static void PD_PsmExternalPowerChange(pd_instance_t *pdInstance)
{
#if defined(PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
if (pdInstance->curPowerRole == kPD_PowerRoleSink)
{
PD_StackSetEvent(pdInstance, PD_TASK_EVENT_EXTERNAL_POWER_CHANGE);
}
#if 0
else
{
#if defined(USBPD_ENABLE_IMMEDIATE_SWAP_TO_SINK_ON_POWER_LOSS) && (USBPD_ENABLE_IMMEDIATE_SWAP_TO_SINK_ON_POWER_LOSS)
if (pdInstance->externalPoweredState == 0U)
{
PD_PsmSetAutoPolicyState(pdInstance, PSM_RDY_EVAL_CHECK_PARTNER_CAP);
}
else
#endif /* USBPD_ENABLE_IMMEDIATE_SWAP_TO_SINK_ON_POWER_LOSS */
{
/* A source must immediately send new capabilities */
(void)PD_Command(pdInstance, (uint32_t)PD_DPM_CONTROL_POWER_NEGOTIATION, NULL);
}
}
#endif /* 0 */
#endif /* PD_CONFIG_SOURCE_ROLE_ENABLE */
}
#endif /* PD_CONFIG_ENABLE_AUTO_POLICY */
#if (defined PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
static void PD_StateWaitReplyExtDataProcess(pd_instance_t *pdInstance,
psm_trigger_info_t *triggerInfo,
message_type_t requiredMsg,
pd_dpm_callback_event_t successCallbackEvent,
pd_dpm_callback_event_t failCallbackEvent,
uint8_t *didNothingStepB)
{
pd_command_result_t commandResultCallback;
if (triggerInfo->triggerEvent == PSM_TRIGGER_PD_MSG)
{
pdInstance->psmNewState = PE_PSM_STATE_ROLE_RDY_STATE;
if (triggerInfo->pdMsgType == requiredMsg)
{
pd_command_data_param_t extMsgParam;
(void)PD_TimerClear(pdInstance, tSenderResponseTimer);
/* the fixed 23 bytes length */
if (requiredMsg == kPD_MsgBatteryStatus)
{
extMsgParam.dataBuffer = (uint8_t *)triggerInfo->pdMsgDataBuffer;
}
else
{
extMsgParam.dataBuffer = (uint8_t *)triggerInfo->pdMsgDataBuffer + 2U;
}
if ((requiredMsg == kPD_MsgSourceCapExtended) &&
(triggerInfo->pdExtMsgLength) >= PD_EXTENDED_SRC_CAP_DATA_LENGTH)
{
extMsgParam.dataLength = PD_EXTENDED_SRC_CAP_DATA_LENGTH;
}
else if ((requiredMsg == kPD_MsgStatus) &&
((triggerInfo->pdExtMsgLength) >= PD_EXTENDED_STATUS_MSG_DATA_LENGTH))
{
extMsgParam.dataLength = PD_EXTENDED_STATUS_MSG_DATA_LENGTH;
}
else if ((requiredMsg == kPD_MsgBatteryCapabilities) &&
((triggerInfo->pdExtMsgLength) >= PD_EXTENDED_BATTERY_CAP_MSG_DATA_LENGTH))
{
extMsgParam.dataLength = PD_EXTENDED_BATTERY_CAP_MSG_DATA_LENGTH;
}
#if (defined PD_CONFIG_PD3_PPS_ENABLE) && (PD_CONFIG_PD3_PPS_ENABLE)
else if ((requiredMsg == kPD_MsgPpsStatus) &&
((triggerInfo->pdExtMsgLength) >= PD_EXTENDED_PPS_STATUS_MSG_DATA_LENGTH))
{
extMsgParam.dataLength = PD_EXTENDED_PPS_STATUS_MSG_DATA_LENGTH;
}
#endif
else
{
extMsgParam.dataLength = triggerInfo->pdExtMsgLength;
}
(void)PD_DpmAppCallback(pdInstance, successCallbackEvent, &extMsgParam, 1);
}
else if ((triggerInfo->msgHeader.bitFields.NumOfDataObjs == 0U) &&
(triggerInfo->msgHeader.bitFields.messageType == (uint8_t)kPD_MsgNotSupported))
{
(void)PD_TimerClear(pdInstance, tSenderResponseTimer);
commandResultCallback = kCommandResult_NotSupported;
(void)PD_DpmAppCallback(pdInstance, failCallbackEvent, &commandResultCallback, 1);
}
else
{
pdInstance->psmNewState = PSM_SEND_SOFT_RESET;
}
}
else if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tSenderResponseTimer) != 0U)
{
commandResultCallback = kCommandResult_Error;
(void)PD_DpmAppCallback(pdInstance, failCallbackEvent, &commandResultCallback, 1);
pdInstance->psmNewState = PE_PSM_STATE_ROLE_RDY_STATE;
}
else
{
*didNothingStepB = 1;
}
}
#endif
/* return 0 wait, 1 start */
static uint8_t PD_PsmStartCommand(pd_instance_t *pdInstance, pd_command_t command, uint8_t isInitiator)
{
#if defined(PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE) && (PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE)
uint8_t start = 1;
if (pdInstance->revision >= PD_SPEC_REVISION_30)
{
if (isInitiator != 0U)
{
if (pdInstance->curPowerRole == kPD_PowerRoleSource)
{
start = PD_MsgSrcStartCommand(pdInstance);
}
else
{
start = PD_MsgSnkCheckStartCommand(pdInstance, command);
}
}
}
if (start != 0U)
{
#endif
pdInstance->commandProcessing = command;
pdInstance->commandIsInitiator = isInitiator;
#if defined(PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE) && (PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE)
}
return start;
#else
return 1;
#endif
}
static void PD_PsmCommandFail(pd_instance_t *pdInstance, pd_command_t command)
{
pd_command_result_t commandResultCallback = kCommandResult_Error;
pd_dpm_callback_event_t event = PD_DPM_EVENT_INVALID;
switch (command)
{
case PD_DPM_CONTROL_POWER_NEGOTIATION:
{
event = PD_DPM_SRC_RDO_FAIL;
break;
}
case PD_DPM_CONTROL_REQUEST:
{
if (pdInstance->curPowerRole == kPD_PowerRoleSink)
{
event = PD_DPM_SNK_RDO_FAIL;
}
else
{
event = PD_DPM_SRC_RDO_FAIL;
}
break;
}
case PD_DPM_CONTROL_GOTO_MIN:
{
if (pdInstance->commandIsInitiator != 0U)
{
event = PD_DPM_SRC_GOTOMIN_FAIL;
}
else
{
event = PD_DPM_SNK_GOTOMIN_FAIL;
}
break;
}
case PD_DPM_CONTROL_SOFT_RESET:
{
event = PD_DPM_SOFT_RESET_FAIL;
break;
}
case PD_DPM_CONTROL_HARD_RESET:
{
/* hard reset will always success */
break;
}
#if (defined PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
case PD_DPM_CONTROL_PR_SWAP:
{
event = PD_DPM_PR_SWAP_FAIL;
break;
}
#endif
#if (defined PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
case PD_DPM_CONTROL_DR_SWAP:
{
event = PD_DPM_DR_SWAP_FAIL;
break;
}
#endif
#if (defined PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
case PD_DPM_CONTROL_VCONN_SWAP:
{
event = PD_DPM_VCONN_SWAP_FAIL;
break;
}
#endif
case PD_DPM_CONTROL_GET_PARTNER_SOURCE_CAPABILITIES:
{
event = PD_DPM_GET_PARTNER_SRC_CAP_FAIL;
break;
}
case PD_DPM_CONTROL_GET_PARTNER_SINK_CAPABILITIES:
{
event = PD_DPM_GET_PARTNER_SNK_CAP_FAIL;
break;
}
#if (defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE)
case PD_DPM_CONTROL_DISCOVERY_IDENTITY:
case PD_DPM_CONTROL_DISCOVERY_SVIDS:
case PD_DPM_CONTROL_DISCOVERY_MODES:
case PD_DPM_CONTROL_ENTER_MODE:
case PD_DPM_CONTROL_EXIT_MODE:
case PD_DPM_CONTROL_SEND_ATTENTION:
case PD_DPM_SEND_VENDOR_STRUCTURED_VDM:
{
event = PD_DPM_STRUCTURED_VDM_FAIL;
break;
}
case PD_DPM_SEND_UNSTRUCTURED_VDM:
{
event = PD_DPM_SEND_UNSTRUCTURED_VDM_FAIL;
break;
}
#endif
#if (defined PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
case PD_DPM_CONTROL_CABLE_RESET:
{
break;
}
#endif
#if (defined PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
case PD_DPM_GET_SRC_EXT_CAP:
{
event = PD_DPM_GET_SRC_EXT_CAP_FAIL;
break;
}
case PD_DPM_GET_STATUS:
{
event = PD_DPM_GET_STATUS_FAIL;
break;
}
#if (defined PD_CONFIG_PD3_PPS_ENABLE) && (PD_CONFIG_PD3_PPS_ENABLE)
case PD_DPM_GET_PPS_STATUS:
{
event = PD_DPM_GET_PPS_STATUS_FAIL;
break;
}
#endif
case PD_DPM_GET_BATTERY_CAP:
{
event = PD_DPM_GET_BATTERY_CAP_FAIL;
break;
}
case PD_DPM_GET_BATTERY_STATUS:
{
event = PD_DPM_GET_BATTERY_STATUS_FAIL;
break;
}
case PD_DPM_GET_MANUFACTURER_INFO:
{
event = PD_DPM_GET_MANUFACTURER_INFO_FAIL;
break;
}
#if 0
case PD_DPM_SECURITY_REQUEST:
{
event = PD_DPM_SECURITY_REQUEST_FAIL;
break;
}
case PD_DPM_FIRMWARE_UPDATE_REQUEST:
{
break;
}
#endif
case PD_DPM_ALERT:
{
event = PD_DPM_SEND_ALERT_FAIL;
break;
}
#endif
#if (defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
case PD_DPM_FAST_ROLE_SWAP:
{
event = PD_DPM_FR_SWAP_FAIL;
break;
}
#endif
default:
/* No action required. */
break;
}
if (event != PD_DPM_EVENT_INVALID)
{
#if (defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE)
if (event == PD_DPM_STRUCTURED_VDM_FAIL)
{
pd_svdm_command_result_t commandVdmResult;
commandVdmResult.vdmCommandResult = (uint8_t)kCommandResult_Error;
commandVdmResult.vdmCommand =
(uint8_t)pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.command;
commandVdmResult.vdoData = NULL;
commandVdmResult.vdoCount = 0;
commandVdmResult.vdmSVID = (uint16_t)pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.SVID;
(void)PD_DpmAppCallback(pdInstance, event, &commandVdmResult, 1);
}
else
#endif
{
(void)PD_DpmAppCallback(pdInstance, event, &commandResultCallback, 1);
}
}
}
/* process the primary pd commands that don't must require snkRdy or srcRdy */
static uint8_t PD_PsmPrimaryStateProcessDpmMsg(pd_instance_t *pdInstance,
pd_psm_state_t *returnNewState,
psm_trigger_info_t *triggerInfo)
{
pd_psm_state_t newStateTmp = PSM_UNKNOWN;
uint8_t didNothing = 1;
/* assume the message is processed */
triggerInfo->triggerEvent = PSM_TRIGGER_NONE;
switch (triggerInfo->dpmMsg)
{
case PD_DPM_CONTROL_HARD_RESET:
newStateTmp = PSM_HARD_RESET;
didNothing = 0;
break;
case PD_DPM_CONTROL_SOFT_RESET:
if (PD_PsmStartCommand(pdInstance, PD_DPM_CONTROL_SOFT_RESET, 1) != 0U)
{
newStateTmp = PSM_SEND_SOFT_RESET;
didNothing = 0;
}
else
{
PD_PsmCommandFail(pdInstance, PD_DPM_CONTROL_SOFT_RESET);
}
break;
#if 0
case PD_DPM_CONTROL_EXIT_MODE:
pdInstance->vdmExitReceived[pdInstance->structuredVdmCommandParameter.vdmSop] = 1;
break;
#endif
#if (defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
case PD_DPM_FAST_ROLE_SWAP:
if (PD_PsmStartCommand(pdInstance, PD_DPM_FAST_ROLE_SWAP, 0) != 0U)
{
/* need enter the PE_FRS_SRC_SNK_CC_Signal to wait the fr_swap msg */
if (pdInstance->frSignaledWaitFrSwap != 0U)
{
pdInstance->psmNewState = PE_FRS_SRC_SNK_CC_Signal;
}
}
break;
#endif
default:
/* the event is not processed */
triggerInfo->triggerEvent = PSM_TRIGGER_DPM_MSG;
break;
}
if (newStateTmp != PSM_UNKNOWN)
{
*returnNewState = newStateTmp;
}
return didNothing;
}
static pd_psm_state_t PD_PsmSinkHardResetfunction(pd_instance_t *pdInstance)
{
(void)pdInstance->callbackFns->PD_SnkStopDrawVbus(pdInstance->callbackParam, kVbusPower_InHardReset);
pdInstance->asmHardResetSnkProcessing = 1;
return PSM_PE_SNK_TRANSITION_TO_DEFAULT;
}
/* process the primary pd message */
static uint8_t PD_PsmPrimaryStateProcessPdMsg(pd_instance_t *pdInstance,
pd_psm_state_t *returnNewState,
psm_trigger_info_t *triggerInfo)
{
pd_psm_state_t newStateTmp = PSM_UNKNOWN;
uint8_t didNothing = 1;
if (triggerInfo->triggerEvent == PSM_TRIGGER_RECEIVE_HARD_RESET)
{
triggerInfo->triggerEvent = PSM_TRIGGER_NONE;
if (pdInstance->psmCurState == PSM_PE_BIST_TEST_DATA_MODE)
{
/* From the IAS: There is no exit from this test mode except some chip level reset.
Reset the protocol layer to exit carrier mode */
(void)PD_PhyControl(pdInstance, PD_PHY_EXIT_BIST, NULL);
}
/* Exit any active alternate mode */
/* All timers and secondary states are reset during this call */
PD_PsmReset(pdInstance);
/* Receiving hard reset will discard other command in progress. */
PD_PsmCommandFail(pdInstance, pdInstance->commandProcessing);
PD_ConnectSetPowerProgress(pdInstance, kVbusPower_InHardReset);
/* The reason to uncomment the function is that here the command is started
but nowhere to end this command. */
/* (void)PD_PsmStartCommand(pdInstance, PD_DPM_CONTROL_HARD_RESET, 0); */
if (pdInstance->curPowerRole == kPD_PowerRoleSource)
{
/* source receive hard_reset, 1. start tPSHardReset */
(void)PD_TimerStart(pdInstance, tPSHardResetTimer, T_PS_HARD_RESET);
newStateTmp = PSM_PE_SRC_HARD_RESET_RECEIVED;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SRC_HARD_RESET_REQUEST, NULL, 0);
}
else if (pdInstance->curPowerRole == kPD_PowerRoleSink)
{
newStateTmp = PD_PsmSinkHardResetfunction(pdInstance);
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SNK_HARD_RESET_REQUEST, NULL, 0);
}
else
{
/* No action required. */
}
didNothing = 0;
}
else if ((triggerInfo->triggerEvent == PSM_TRIGGER_PD_MSG) && (triggerInfo->pdMsgType == kPD_MsgBIST))
{
#if (defined PD_CONFIG_COMPLIANCE_TEST_ENABLE) && (PD_CONFIG_COMPLIANCE_TEST_ENABLE)
pd_bist_object_t bistObj;
/* it the power > 5V, cannot do bist test */
if (((pdInstance->curDataRole == kPD_DataRoleDFP) &&
(pdInstance->partnerRdoRequest.bitFields.objectPosition > 1U)) ||
((pdInstance->curDataRole == kPD_DataRoleUFP) && (pdInstance->rdoRequest.bitFields.objectPosition > 1U)))
{
return didNothing;
}
bistObj.objVal = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(((uint8_t *)triggerInfo->pdMsgDataBuffer));
if (bistObj.bitFields.testMode == (uint8_t)kBIST_TestData)
{
/* Do nothing, the HW does not have a mode for kBIST_TestData */
pd_bist_mst_t bistMode = kBIST_TestData;
(void)PD_PhyControl(pdInstance, PD_PHY_ENTER_BIST, &bistMode);
newStateTmp = PSM_PE_BIST_TEST_DATA_MODE;
}
else
{
(void)PD_TimerClear(pdInstance, tNoResponseTimer);
newStateTmp = PSM_PE_BIST_CARRIER_MODE_2;
}
#endif
triggerInfo->triggerEvent = PSM_TRIGGER_NONE;
}
else if ((triggerInfo->triggerEvent == PSM_TRIGGER_PD_MSG) && (triggerInfo->pdMsgType == kPD_MsgSoftReset))
{
triggerInfo->triggerEvent = PSM_TRIGGER_NONE;
/* Soft reset is ignored when in BIST carrier mode */
/* Soft reset is ignored during fast role swap signalling */
if ((pdInstance->psmCurState != PSM_PE_BIST_CARRIER_MODE_2) &&
(pdInstance->psmCurState != PE_FRS_SRC_SNK_CC_Signal))
{
(void)PD_PsmStartCommand(pdInstance, PD_DPM_CONTROL_SOFT_RESET, 0);
newStateTmp = PSM_SOFT_RESET;
didNothing = 0;
}
}
/* The received message's data role is not right */
else if (((uint16_t)pdInstance->curDataRole == triggerInfo->msgHeader.bitFields.portDataRole) &&
(triggerInfo->pdMsgType != kPD_MsgGoodCRC))
{
triggerInfo->triggerEvent = PSM_TRIGGER_NON_START;
newStateTmp = PSM_EXIT_TO_ERROR_RECOVERY_WITH_DELAY;
didNothing = 0;
}
/* received source_capabilities */
else if ((pdInstance->psmCurState != PSM_PE_SNK_DISCOVERY) && (triggerInfo->pdMsgType == kPD_MsgSourceCapabilities))
{
triggerInfo->triggerEvent = PSM_TRIGGER_NONE;
if (pdInstance->pdPowerPortConfig->typecRole == (uint8_t)kPowerConfig_SourceOnly)
{
(void)PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(pdInstance, PD_NOT_SUPPORT_REPLY_MSG,
pdInstance->psmCurState);
}
else
{
switch (pdInstance->psmCurState)
{
#if (defined PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
case PSM_PE_SRC_DISCOVERY:
case PSM_PE_SRC_SEND_CAPABILITIES:
case PSM_PE_SRC_TRANSITION_SUPPLY:
case PSM_PE_SRC_READY:
case PSM_PE_SRC_GET_SINK_CAP:
{
newStateTmp = PSM_SEND_SOFT_RESET;
}
break;
#if defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
case PSM_PE_PRS_SRC_SNK_TRANSITION_TO_OFF:
case PSM_PE_PRS_SRC_SNK_WAIT_SOURCE_ON:
case PSM_PE_PRS_SRC_SNK_SEND_PR_SWAP:
case PSM_PE_PRS_SNK_SRC_SOURCE_ON:
{
/* A protocol error during power role swap triggers a Hard Reset */
newStateTmp = PSM_HARD_RESET;
}
break;
#endif
#endif
/* Source state, message expected */
#if defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
case PSM_PE_DR_SRC_GET_SOURCE_CAP:
case PSM_PE_SNK_GET_SOURCE_CAP:
{
uint32_t u32Tmp;
pd_capabilities_t sourceCapa;
(void)PD_TimerClear(pdInstance, tSenderResponseTimer);
/* Clear any pending message now that we have the latest */
(void)PD_DpmClearMsg(pdInstance, PD_DPM_CONTROL_GET_PARTNER_SOURCE_CAPABILITIES);
sourceCapa.capabilities = triggerInfo->pdMsgDataBuffer;
sourceCapa.capabilitiesCount = triggerInfo->pdMsgDataLength;
pdInstance->partnerSourcePDOsCount = sourceCapa.capabilitiesCount;
for (u32Tmp = 0; u32Tmp < sourceCapa.capabilitiesCount; ++u32Tmp)
{
pdInstance->partnerSourcePDOs[u32Tmp].PDOValue = sourceCapa.capabilities[u32Tmp];
}
if (pdInstance->psmCurState == PSM_PE_SNK_GET_SOURCE_CAP)
{
newStateTmp = PSM_PE_SNK_READY;
}
else
{
newStateTmp = PSM_PE_SRC_READY;
#if defined(PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
if (pdInstance->dumpResponse != 0U)
{
pdInstance->swapToSnkSrcCapReceived = 1;
}
#endif
}
(void)PD_DpmAppCallback(pdInstance, PD_DPM_GET_PARTNER_SRC_CAP_SUCCESS, &sourceCapa, 1);
break;
}
#endif
/* Sink states, message accepted: */
#if (defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)
case PSM_PE_SNK_WAIT_FOR_CAPABILITIES:
case PSM_PE_SNK_SELECT_CAPABILITY:
case PSM_PE_SNK_TRANSITION_SINK:
case PSM_PE_SNK_READY:
case PSM_PE_SNK_GIVE_SINK_CAP:
#if defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
case PSM_PE_PRS_SNK_SRC_TRANSITION_TO_OFF:
case PSM_PE_PRS_SNK_SRC_SEND_PR_SWAP:
case PSM_PE_DR_SNK_GET_SINK_CAP:
#endif
{
uint32_t u32Tmp;
pd_capabilities_t sourceCapa;
PD_PsmCheckRevision(pdInstance, triggerInfo->msgHeader);
(void)PD_TimerClear(pdInstance, tSinkWaitCapTimer);
pdInstance->psmPresentlyPdConnected = 1;
pdInstance->psmPreviouslyPdConnected = 1;
/* Update the PDOs for the EC and send interrupt */
sourceCapa.capabilities = triggerInfo->pdMsgDataBuffer;
sourceCapa.capabilitiesCount = triggerInfo->pdMsgDataLength;
pdInstance->selfOrPartnerFirstSourcePDO.PDOValue = sourceCapa.capabilities[0];
pdInstance->partnerSourcePDOsCount = sourceCapa.capabilitiesCount;
for (u32Tmp = 0; u32Tmp < sourceCapa.capabilitiesCount; ++u32Tmp)
{
pdInstance->partnerSourcePDOs[u32Tmp].PDOValue = sourceCapa.capabilities[u32Tmp];
}
if (pdInstance->commandProcessing == PD_DPM_CONTROL_GET_PARTNER_SOURCE_CAPABILITIES)
{
pdInstance->commandProcessing = PD_DPM_INVALID;
}
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SNK_RECEIVE_PARTNER_SRC_CAP, &sourceCapa, 0);
#if (defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE)
/* Ensure secondary state machine does not transition primary state machine */
PD_PsmSecondaryStateHandlerTerminate(pdInstance, kPD_MsgSOPInvalid);
#endif
newStateTmp = PSM_PE_SNK_EVALUATE_CAPABILITY;
}
break;
#endif
default:
/* No action required. */
break;
}
}
didNothing = 0;
}
#if (defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE)
else if ((triggerInfo->triggerEvent == PSM_TRIGGER_PD_MSG) && (triggerInfo->pdMsgType == kPD_MsgVendorDefined) &&
(triggerInfo->vdmHeader.bitFields.command == (uint8_t)kVDM_ExitMode) &&
(triggerInfo->vdmHeader.bitFields.commandType == (uint8_t)kVDM_Initiator))
{
pdInstance->vdmExitReceived[triggerInfo->pdMsgSop] = triggerInfo->vdmHeader.structuredVdmHeaderVal;
}
#endif
else
{
}
if (newStateTmp != PSM_UNKNOWN)
{
*returnNewState = newStateTmp;
}
return didNothing;
}
static void PD_PsmEndCommand(pd_instance_t *pdInstance)
{
if (pdInstance->commandProcessing == PD_DPM_INVALID)
{
return;
}
else
{
uint8_t commandFail = 0;
switch (pdInstance->commandProcessing)
{
case PD_DPM_CONTROL_HARD_RESET:
case PD_DPM_CONTROL_SOFT_RESET:
case PD_DPM_CONTROL_CABLE_RESET:
{
/* process in the state machine */
break;
}
#if (defined PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
case PD_DPM_CONTROL_PR_SWAP:
{
switch (pdInstance->psmCurState)
{
case PSM_PE_PRS_SRC_SNK_EVALUATE_PR_SWAP:
case PSM_PE_PRS_SRC_SNK_ACCEPT_PR_SWAP:
case PSM_PE_PRS_SRC_SNK_TRANSITION_TO_OFF:
case PSM_PE_PRS_SRC_SNK_ASSERT_RD:
case PSM_PE_PRS_SRC_SNK_WAIT_SOURCE_ON:
case PSM_PE_PRS_SRC_SNK_SEND_PR_SWAP:
case PSM_PE_PRS_SRC_SNK_REJECT_PR_SWAP:
case PSM_PE_PRS_SNK_SRC_EVALUATE_PR_SWAP:
case PSM_PE_PRS_SNK_SRC_ACCEPT_PR_SWAP:
case PSM_PE_PRS_SNK_SRC_TRANSITION_TO_OFF:
case PSM_PE_PRS_SNK_SRC_ASSERT_RP:
case PSM_PE_PRS_SNK_SRC_SOURCE_ON:
case PSM_PE_PRS_SNK_SRC_SEND_PR_SWAP:
case PSM_PE_PRS_SNK_SRC_REJECT_PR_SWAP:
case PSM_PE_PRS_EVALUATE_PR_SWAP_WAIT_TIMER_TIME_OUT:
/* these states means the pr_swap ams is processing */
break;
default:
/* (void)PD_DpmAppCallback(pdInstance, PD_DPM_PR_SWAP_FAIL, NULL, 1); */
commandFail = 1;
break;
}
break;
}
#endif
case PD_DPM_CONTROL_REQUEST:
switch (pdInstance->psmCurState)
{
case PSM_PE_SRC_NEGOTIATE_CAPABILITY:
case PSM_PE_SRC_TRANSITION_SUPPLY:
case PSM_PE_SNK_EVALUATE_CAPABILITY:
case PSM_PE_SNK_TRANSITION_SINK:
case PSM_PE_SNK_SELECT_CAPABILITY:
case PSM_PE_SNK_SELECT_CAPABILITY_WAIT_TIMER_TIME_OUT:
break;
case PSM_PE_SNK_READY:
if (pdInstance->psmSnkReceiveRdoWaitRetry != 0U)
{
/* even in snk_rdy bu it is wait reply */
}
else
{
/* (void)PD_DpmAppCallback(pdInstance, PD_DPM_SNK_RDO_FAIL, NULL, 1); */
commandFail = 1;
}
break;
default:
commandFail = 1;
break;
}
break;
case PD_DPM_CONTROL_POWER_NEGOTIATION:
switch (pdInstance->psmCurState)
{
case PSM_PE_SRC_DISCOVERY:
case PSM_PE_SRC_NEGOTIATE_CAPABILITY:
case PSM_PE_SRC_TRANSITION_SUPPLY:
case PSM_PE_SNK_TRANSITION_SINK:
case PSM_PE_SNK_SELECT_CAPABILITY:
case PSM_PE_SNK_SELECT_CAPABILITY_WAIT_TIMER_TIME_OUT:
case PSM_PE_SRC_SEND_CAPABILITIES:
case PSM_PE_SNK_WAIT_FOR_CAPABILITIES:
case PSM_PE_SNK_GIVE_SINK_CAP:
case PSM_PE_PRS_SNK_SRC_TRANSITION_TO_OFF:
case PSM_PE_PRS_SNK_SRC_SEND_PR_SWAP:
case PSM_PE_DR_SNK_GET_SINK_CAP:
break;
default:
commandFail = 1;
break;
}
break;
case PD_DPM_CONTROL_GET_PARTNER_SOURCE_CAPABILITIES:
switch (pdInstance->psmCurState)
{
case PSM_PE_DR_SRC_GET_SOURCE_CAP:
case PSM_PE_SNK_GET_SOURCE_CAP:
case PSM_PE_SNK_READY:
break;
default:
commandFail = 1;
break;
}
break;
case PD_DPM_CONTROL_GET_PARTNER_SINK_CAPABILITIES:
switch (pdInstance->psmCurState)
{
case PSM_PE_DR_SNK_GET_SINK_CAP:
case PSM_PE_SRC_GET_SINK_CAP:
break;
default:
commandFail = 1;
break;
}
break;
case PD_DPM_CONTROL_GOTO_MIN:
switch (pdInstance->psmCurState)
{
case PSM_PE_SNK_TRANSITION_SINK:
case PSM_PE_SRC_TRANSITION_SUPPLY:
break;
default:
commandFail = 1;
break;
}
break;
#if (defined PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
case PD_DPM_CONTROL_DR_SWAP:
switch (pdInstance->psmCurState)
{
case PSM_PE_DRS_SEND_DR_SWAP:
case PSM_PE_DRS_EVALUATE_DR_SWAP:
case PSM_PE_DRS_ACCEPT_DR_SWAP:
case PSM_PE_DRS_REJECT_DR_SWAP:
case PSM_PE_DRS_CHANGE_TO_DFP_OR_UFP:
break;
default:
commandFail = 1;
break;
}
break;
#endif
#if (defined PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
case PD_DPM_CONTROL_VCONN_SWAP:
switch (pdInstance->psmCurState)
{
case PSM_PE_VCS_SEND_SWAP:
case PSM_PE_VCS_WAIT_FOR_VCONN:
case PSM_PE_VCS_TURN_OFF_VCONN:
case PSM_PE_VCS_TURN_ON_VCONN:
case PSM_PE_VCS_SEND_PS_RDY:
case PSM_PE_VCS_EVALUATE_SWAP:
case PSM_PE_VCS_ACCEPT_SWAP:
case PSM_PE_VCS_REJECT_SWAP:
break;
default:
commandFail = 1;
break;
}
break;
#endif
case PD_DPM_GET_SRC_EXT_CAP:
switch (pdInstance->psmCurState)
{
case PE_SNK_GET_SOURCE_CAP_EXT:
case PE_DR_SRC_GET_SOURCE_CAP_EXT:
case PE_SRC_GIVE_SOURCE_CAP_EXT:
case PE_DR_SNK_GIVE_SOURCE_CAP_EXT:
break;
default:
commandFail = 1;
break;
}
break;
#if (defined PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
case PD_DPM_GET_STATUS:
switch (pdInstance->psmCurState)
{
case PE_SNK_Get_Source_Status:
case PE_SRC_Give_Source_Status:
case PE_SRC_Get_Sink_Status:
case PE_SNK_Give_Sink_Status:
break;
default:
commandFail = 1;
break;
}
break;
#if (defined PD_CONFIG_PD3_PPS_ENABLE) && (PD_CONFIG_PD3_PPS_ENABLE)
case PD_DPM_GET_PPS_STATUS:
switch (pdInstance->psmCurState)
{
case PE_SNK_Get_PPS_Status:
case PE_SRC_Give_PPS_Status:
break;
default:
commandFail = 1;
break;
}
break;
#endif
case PD_DPM_GET_BATTERY_CAP:
switch (pdInstance->psmCurState)
{
case PE_Give_Battery_Cap:
case PE_Get_Battery_Cap:
break;
default:
commandFail = 1;
break;
}
break;
case PD_DPM_GET_BATTERY_STATUS:
switch (pdInstance->psmCurState)
{
case PE_Get_Battery_Status:
case PE_Give_Battery_Status:
break;
default:
commandFail = 1;
break;
}
break;
case PD_DPM_GET_MANUFACTURER_INFO:
switch (pdInstance->psmCurState)
{
case PE_Get_Manufacturer_Info:
case PE_Give_Manufacturer_Info:
break;
default:
commandFail = 1;
break;
}
break;
#if 0
case PD_DPM_SECURITY_REQUEST:
switch (pdInstance->psmCurState)
{
case PE_Send_Security_Request:
case PE_Send_Security_Response:
case PE_Security_Response_Received:
case PSM_PE_SNK_READY:
case PSM_PE_SRC_READY:
break;
default:
commandFail = 1;
break;
}
break;
#endif
case PD_DPM_ALERT:
switch (pdInstance->psmCurState)
{
case PE_SRC_Send_Source_Alert:
case PE_SNK_Source_Alert_Received:
case PE_SNK_Send_Sink_Alert:
case PE_SRC_Sink_Alert_Received:
break;
default:
commandFail = 1;
break;
}
break;
#endif
#if (defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
case PD_DPM_FAST_ROLE_SWAP:
switch (pdInstance->psmCurState)
{
case PE_FRS_SRC_SNK_CC_Signal:
case PE_FRS_SRC_SNK_Evaluate_Swap:
case PE_FRS_SRC_SNK_Accept_Swap:
case PE_FRS_SRC_SNK_Transition_to_off:
case PE_FRS_SRC_SNK_Assert_Rd:
case PE_FRS_SRC_SNK_Wait_Source_on:
case PE_FRS_SNK_SRC_Send_Swap:
case PE_FRS_SNK_SRC_Transition_to_off:
case PE_FRS_SNK_SRC_Vbus_Applied:
case PE_FRS_SNK_SRC_Assert_Rp:
case PE_FRS_SNK_SRC_Source_on:
break;
default:
commandFail = 1;
break;
}
break;
#endif
default:
/* No action required. */
break;
}
if (commandFail != 0U)
{
PD_PsmCommandFail(pdInstance, pdInstance->commandProcessing);
}
}
}
static uint8_t PD_PsmRdyStateCheckDpmMessage(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo)
{
if (triggerInfo->dpmMsg >= PD_DPM_CONTROL_DISCOVERY_IDENTITY)
{
return 0;
}
triggerInfo->triggerEvent = PSM_TRIGGER_NONE;
if (PD_PsmStartCommand(pdInstance, triggerInfo->dpmMsg, 1) == 0U)
{
PD_PsmCommandFail(pdInstance, triggerInfo->dpmMsg);
return 0;
}
return 1;
}
static void PD_PsmSinkAndSourceRdyProcessDpmMessage(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo)
{
#if (((defined PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)) || \
((defined PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)) || \
((defined PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)) || \
((defined PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)))
switch (triggerInfo->dpmMsg)
{
#if (defined PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
case PD_DPM_CONTROL_PR_SWAP:
{
if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tPrSwapWaitTimer) != 0U)
{
if (pdInstance->curPowerRole == kPD_PowerRoleSink)
{
pdInstance->psmNewState = PSM_PE_PRS_SNK_SRC_SEND_PR_SWAP;
}
else
{
pdInstance->psmNewState = PSM_PE_PRS_SRC_SNK_SEND_PR_SWAP;
}
}
else
{
pdInstance->psmNewState = PSM_PE_PRS_EVALUATE_PR_SWAP_WAIT_TIMER_TIME_OUT;
}
break;
}
#endif
#if (defined PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
case PD_DPM_CONTROL_DR_SWAP:
{
#if (defined PD_CONFIG_ALT_MODE_SUPPORT) && (PD_CONFIG_ALT_MODE_SUPPORT)
/* Check alternate mode */
if (PD_PsmCheckInAltMode(pdInstance, kPD_MsgSOP) != 0U)
{
/* In the alt mode, wait the exit mode */
/* Send Exit mode(DFP) or attention(UFP) to request to exit active mode. */
if (PD_AltModeExitModeForDrSwap(pdInstance->altModeHandle) != 0U)
{
pdInstance->drSwapTriggerExitMode = 1;
/* Reaching here, the commandProcessing has been assigned to PD_DPM_CONTROL_DR_SWAP, and DFP will
send kVDM_ExitMode or UFP will send kVDM_Attention. If the commandProcessing isn't assigned to
PD_DPM_INVALID, the kVDM_ExitMode or kVDM_Attention cannot be sent because calling the PD_Command
funtion to initiate an AMS will return kStatus_PD_Busy. */
pdInstance->commandProcessing = PD_DPM_INVALID;
}
}
else
#endif
{
/* Not in the alt mode */
if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tDrSwapWaitTimer) != 0U)
{
pdInstance->psmNewState = PSM_PE_DRS_SEND_DR_SWAP;
}
else
{
pdInstance->psmNewState = PSM_PE_DRS_EVALUATE_DR_SWAP_WAIT_TIMER_TIME_OUT;
}
}
break;
}
#endif
#if (defined PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
case PD_DPM_CONTROL_VCONN_SWAP:
{
pdInstance->psmNewState = PSM_PE_VCS_SEND_SWAP;
break;
}
#endif
#if (defined PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
case PD_DPM_GET_BATTERY_CAP:
{
pdInstance->psmNewState = PE_Get_Battery_Cap;
break;
}
case PD_DPM_GET_BATTERY_STATUS:
{
pdInstance->psmNewState = PE_Get_Battery_Status;
break;
}
case PD_DPM_GET_MANUFACTURER_INFO:
{
pdInstance->psmNewState = PE_Get_Manufacturer_Info;
break;
}
#if 0
case PD_DPM_SECURITY_REQUEST:
{
pdInstance->psmNewState = PE_Send_Security_Request;
break;
}
#endif
#endif
default:
/* No action required. */
break;
}
#endif
}
#if (defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)
static void PD_PsmSinkRdyProcessDpmMessage(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo)
{
if (PD_PsmRdyStateCheckDpmMessage(pdInstance, triggerInfo) != 0U)
{
switch (triggerInfo->dpmMsg)
{
case PD_DPM_CONTROL_REQUEST:
{
if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tSinkRequestTimer) != 0U)
{
pdInstance->psmNewState = PSM_PE_SNK_SELECT_CAPABILITY;
}
else
{
pdInstance->psmNewState = PSM_PE_SNK_SELECT_CAPABILITY_WAIT_TIMER_TIME_OUT;
}
break;
}
case PD_DPM_CONTROL_GET_PARTNER_SOURCE_CAPABILITIES:
{
pdInstance->psmNewState = PSM_PE_SNK_GET_SOURCE_CAP;
break;
}
case PD_DPM_CONTROL_GET_PARTNER_SINK_CAPABILITIES:
{
pdInstance->psmNewState = PSM_PE_DR_SNK_GET_SINK_CAP;
break;
}
#if (defined PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
case PD_DPM_GET_SRC_EXT_CAP:
{
pdInstance->psmNewState = PE_SNK_GET_SOURCE_CAP_EXT;
break;
}
case PD_DPM_GET_STATUS:
{
pdInstance->psmNewState = PE_SNK_Get_Source_Status;
break;
}
#if (defined PD_CONFIG_PD3_PPS_ENABLE) && (PD_CONFIG_PD3_PPS_ENABLE)
case PD_DPM_GET_PPS_STATUS:
{
pdInstance->psmNewState = PE_SNK_Get_PPS_Status;
break;
}
#endif
case PD_DPM_ALERT:
{
pdInstance->psmNewState = PE_SNK_Send_Sink_Alert;
break;
}
#endif
default:
/* No action required. */
break;
}
PD_PsmSinkAndSourceRdyProcessDpmMessage(pdInstance, triggerInfo);
}
}
#endif
#if (defined PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
static void PD_PsmSourceRdyProcessDpmMessage(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo)
{
if (PD_PsmRdyStateCheckDpmMessage(pdInstance, triggerInfo) != 0U)
{
switch (triggerInfo->dpmMsg)
{
case PD_DPM_CONTROL_POWER_NEGOTIATION:
{
pdInstance->psmNewState = PSM_PE_SRC_SEND_CAPABILITIES;
break;
}
case PD_DPM_CONTROL_GOTO_MIN:
{
pdInstance->psmGotoMinTx = 1;
pdInstance->psmNewState = PSM_PE_SRC_TRANSITION_SUPPLY;
break;
}
case PD_DPM_CONTROL_GET_PARTNER_SOURCE_CAPABILITIES:
{
pdInstance->psmNewState = PSM_PE_DR_SRC_GET_SOURCE_CAP;
break;
}
case PD_DPM_CONTROL_GET_PARTNER_SINK_CAPABILITIES:
{
pdInstance->psmNewState = PSM_PE_SRC_GET_SINK_CAP;
break;
}
#if (defined PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
case PD_DPM_GET_SRC_EXT_CAP:
{
pdInstance->psmNewState = PE_DR_SRC_GET_SOURCE_CAP_EXT;
break;
}
case PD_DPM_GET_STATUS:
{
pdInstance->psmNewState = PE_SRC_Get_Sink_Status;
break;
}
case PD_DPM_ALERT:
{
pdInstance->psmNewState = PE_SRC_Send_Source_Alert;
break;
}
#endif
default:
/* No action required. */
break;
}
PD_PsmSinkAndSourceRdyProcessDpmMessage(pdInstance, triggerInfo);
}
}
#endif
static void PD_PsmRdyProcessPdMessage(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo)
{
pd_psm_state_t replyNotSupport = PSM_UNKNOWN;
pd_psm_state_t sinkOrSoruceNotSupportState;
uint8_t msgProcessed = 1;
if ((triggerInfo->pdMsgSop != kPD_MsgSOP) || (triggerInfo->pdMsgType == kPD_MsgVendorDefined))
{
return;
}
triggerInfo->triggerEvent = PSM_TRIGGER_NONE;
/* note: vdm message will be processed before this */
#if (defined PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
if (pdInstance->curPowerRole == kPD_PowerRoleSource)
{
sinkOrSoruceNotSupportState = PSM_PE_SRC_READY;
switch (triggerInfo->pdMsgType)
{
case kPD_MsgGotoMin:
{
/* not_supported */
replyNotSupport = sinkOrSoruceNotSupportState;
break;
}
case kPD_MsgGetSourceCap:
{
pdInstance->psmNewState = PSM_PE_SRC_SEND_CAPABILITIES;
#if defined(PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE) && (PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE)
pdInstance->powerNegotiationInitiator = 0;
#endif
break;
}
case kPD_MsgGetSinkCap:
{
if (pdInstance->pdPowerPortConfig->typecRole == (uint8_t)kPowerConfig_SourceOnly)
{
replyNotSupport = sinkOrSoruceNotSupportState;
}
else
{
pdInstance->psmNewState = PSM_PE_DR_SRC_GIVE_SINK_CAP;
}
break;
}
case kPD_MsgRequest:
{
pdInstance->partnerRdoRequest.rdoVal =
USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(((uint8_t *)triggerInfo->pdMsgDataBuffer));
#if (defined PD_CONFIG_PD3_PPS_ENABLE) && (PD_CONFIG_PD3_PPS_ENABLE)
/* SourcePPSCommTimer */
if (PD_PsmSourceIsPPSRDO(pdInstance) != 0U)
{
(void)PD_TimerStart(pdInstance, tSourcePPSCommTimer, T_PPS_TIMEOUT);
}
#endif
pdInstance->psmNewState = PSM_PE_SRC_NEGOTIATE_CAPABILITY;
(void)PD_PsmStartCommand(pdInstance, PD_DPM_CONTROL_REQUEST, 0);
break;
}
case kPD_MsgGetStatus:
{
pdInstance->alertWaitReply = 0;
pdInstance->psmNewState = PE_SRC_Give_Source_Status;
break;
}
case kPD_MsgFrSwap:
{
#if (defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
if ((PD_PsmIsDualRole(pdInstance) != 0U) && (pdInstance->frSignaledWaitFrSwap != 0U))
{
/* no need to enter PE_FRS_SRC_SNK_CC_Signal */
PD_ConnectSetPowerProgress(pdInstance, kVbusPower_InFRSwap);
pdInstance->frSignaledWaitFrSwap = 0u;
pdInstance->psmNewState = PE_FRS_SRC_SNK_Evaluate_Swap;
}
else
{
pdInstance->psmNewState = PSM_HARD_RESET;
}
#else
replyNotSupport = sinkOrSoruceNotSupportState;
#endif
break;
}
#if (defined PD_CONFIG_PD3_PPS_ENABLE) && (PD_CONFIG_PD3_PPS_ENABLE)
case kPD_MsgGetPpsStatus:
pdInstance->psmNewState = PE_SRC_Give_PPS_Status;
break;
#endif
default:
msgProcessed = 0;
break;
}
}
else
#endif
#if (defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)
{
sinkOrSoruceNotSupportState = PSM_PE_SNK_READY;
switch (triggerInfo->pdMsgType)
{
case kPD_MsgRequest:
{
replyNotSupport = sinkOrSoruceNotSupportState;
break;
}
case kPD_MsgGotoMin:
{
(void)PD_PsmStartCommand(pdInstance, PD_DPM_CONTROL_GOTO_MIN, 0);
pdInstance->psmGotoMinRx = 1;
pdInstance->psmNewState = PSM_PE_SNK_TRANSITION_SINK;
break;
}
case kPD_MsgGetSinkCap:
{
pdInstance->psmNewState = PSM_PE_SNK_GIVE_SINK_CAP;
break;
}
case kPD_MsgGetSourceCap:
{
if (pdInstance->pdPowerPortConfig->typecRole == (uint8_t)kPowerConfig_SinkOnly)
{
replyNotSupport = sinkOrSoruceNotSupportState;
}
else
{
pdInstance->psmNewState = PSM_PE_DR_SNK_GIVE_SOURCE_CAP;
}
break;
}
case kPD_MsgGetStatus:
{
pdInstance->alertWaitReply = 0;
pdInstance->psmNewState = PE_SNK_Give_Sink_Status;
break;
}
#if (defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
case kPD_MsgFrSwap:
{
/* not_supported, only source can receive this msg */
replyNotSupport = PSM_PE_SNK_READY;
break;
}
#endif
default:
msgProcessed = 0;
break;
}
}
#else
{
}
#endif
if (msgProcessed == 0U)
{
pd_command_result_t commandResultCallback;
#if (defined PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
pd_extended_msg_header_t extHeader;
extHeader.extendedMsgHeaderVal =
USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(((uint8_t *)triggerInfo->pdMsgDataBuffer));
#endif
triggerInfo->triggerEvent = PSM_TRIGGER_NONE;
/* sink and source all process these messages similarly */
/* note: vdm message will be processed before this */
switch (triggerInfo->pdMsgType)
{
case kPD_MsgPrSwap:
{
#if (defined PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
if (PD_PsmIsDualRole(pdInstance) != 0U)
{
(void)PD_PsmStartCommand(pdInstance, PD_DPM_CONTROL_PR_SWAP, 0);
if (pdInstance->curPowerRole == kPD_PowerRoleSource)
{
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
/* auto accept is true and partner source cap is not got */
if ((pdInstance->swapToSnkSrcCapReceived == 0U) && (PD_POLICY_SUPPORT(pdInstance)) &&
(PD_POLICY_GET_AUTO_ACCEPT_PRSWAP_AS_SOURCE_SUPPORT(pdInstance)) &&
(PD_POLICY_GET_AUTO_ACCEPT_PRSWAP_AS_SOURCE(pdInstance) ==
(uint8_t)kAutoRequestProcess_Accept))
{
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY_LOG) && (PD_CONFIG_ENABLE_AUTO_POLICY_LOG)
(void)PRINTF("auto reply wait for pr swap, and start to get the partner's source caps\r\n");
#endif
if (PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(pdInstance, kPD_MsgWait,
PSM_PE_DR_SRC_GET_SOURCE_CAP) != 0U)
{
PD_PsmSetAutoPolicyState(pdInstance, PSM_RDY_EVAL_INIT);
commandResultCallback = kCommandResult_Wait;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_PR_SWAP_FAIL, &commandResultCallback, 1);
if (PD_PsmStartCommand(pdInstance, PD_DPM_CONTROL_GET_PARTNER_SOURCE_CAPABILITIES, 1) !=
0U)
{
pdInstance->dumpResponse = 1;
}
else
{
/* If fail, wait for next kPD_MsgPrSwap from the partner Sink. */
}
}
}
else
#endif
{
pdInstance->psmNewState = PSM_PE_PRS_SRC_SNK_EVALUATE_PR_SWAP;
}
}
else
{
pdInstance->psmNewState = PSM_PE_PRS_SNK_SRC_EVALUATE_PR_SWAP;
}
}
else
#endif
{
replyNotSupport = sinkOrSoruceNotSupportState;
}
break;
}
case kPD_MsgDrSwap:
{
#if (defined PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
if (PD_PsmCheckInAltMode(pdInstance, kPD_MsgSOP) != 0U)
{
pdInstance->psmNewState = PSM_HARD_RESET;
}
else
{
if (pdInstance->pdPowerPortConfig->dataFunction == (uint8_t)kDataConfig_DRD)
{
(void)PD_PsmStartCommand(pdInstance, PD_DPM_CONTROL_DR_SWAP, 0);
pdInstance->psmNewState = PSM_PE_DRS_EVALUATE_DR_SWAP;
}
else
{
replyNotSupport = sinkOrSoruceNotSupportState;
}
}
#else
replyNotSupport = sinkOrSoruceNotSupportState;
#endif
break;
}
case kPD_MsgVconnSwap:
{
#if (defined PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
if (pdInstance->pdPowerPortConfig->vconnSupported != 0U)
{
(void)PD_PsmStartCommand(pdInstance, PD_DPM_CONTROL_VCONN_SWAP, 0);
pdInstance->psmNewState = PSM_PE_VCS_EVALUATE_SWAP;
}
else
#endif
{
replyNotSupport = sinkOrSoruceNotSupportState;
}
break;
}
case kPD_MsgGetSourceCapExtended:
{
if (pdInstance->pdPowerPortConfig->typecRole == (uint8_t)kPowerConfig_SinkOnly)
{
replyNotSupport = sinkOrSoruceNotSupportState;
}
else
{
if (pdInstance->curPowerRole == kPD_PowerRoleSource)
{
pdInstance->psmNewState = PE_SRC_GIVE_SOURCE_CAP_EXT;
}
else
{
pdInstance->psmNewState = PE_DR_SNK_GIVE_SOURCE_CAP_EXT;
}
}
break;
}
case kPD_MsgAlert:
{
pd_command_data_param_t commandExtParam;
if (pdInstance->curPowerRole == kPD_PowerRoleSink)
{
pdInstance->psmNewState = PE_SNK_Source_Alert_Received;
}
else
{
pdInstance->psmNewState = PE_SRC_Sink_Alert_Received;
}
commandExtParam.dataBuffer = (uint8_t *)triggerInfo->pdMsgDataBuffer;
commandExtParam.dataLength = 4;
commandExtParam.sop = (uint8_t)kPD_MsgSOP;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_ALERT_RECEIVED, &commandExtParam, 0);
if (commandExtParam.resultStatus == (uint8_t)kCommandResult_NotSupported)
{
(void)PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(pdInstance, kPD_MsgNotSupported,
PE_PSM_STATE_ROLE_RDY_STATE);
}
break;
}
case kPD_MsgNotSupported:
commandResultCallback = kCommandResult_NotSupported;
#if 0
if (pdInstance->commandProcessing == PD_DPM_SECURITY_REQUEST)
{
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SECURITY_REQUEST_FAIL, &commandResultCallback, 1);
}
else
#endif
if (pdInstance->alertWaitReply != 0U)
{
pdInstance->alertWaitReply = 0;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SEND_ALERT_FAIL, &commandResultCallback, 0);
}
else
{
}
break;
#if (defined PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
case kPD_MsgGetBatteryCap:
case kPD_MsgGetBatteryStatus:
case kPD_MsgGetManufacturerInfo:
pdInstance->commandExtParamCallback.dataBuffer = (uint8_t *)&(pdInstance->receivedData[1]);
pdInstance->commandExtParamCallback.dataBuffer += 2; /* data pos */
pdInstance->commandExtParamCallback.dataLength = extHeader.bitFields.dataSize;
pdInstance->commandExtParamCallback.sop = (uint8_t)triggerInfo->pdMsgSop;
if (triggerInfo->pdMsgType == kPD_MsgGetBatteryCap)
{
pdInstance->psmNewState = PE_Give_Battery_Cap;
}
else if (triggerInfo->pdMsgType == kPD_MsgGetBatteryStatus)
{
pdInstance->psmNewState = PE_Give_Battery_Status;
}
else
{
pdInstance->psmNewState = PE_Give_Manufacturer_Info;
}
break;
case kPD_MsgSecurityRequest:
{
#if 0
/* (initiator) chunked request received */
pdInstance->psmNewState = PE_Send_Security_Response;
#endif
replyNotSupport = sinkOrSoruceNotSupportState;
break;
}
#if 0
case kPD_MsgSecurityResponse:
{
/* receive all the data */
pdInstance->psmNewState = PE_Security_Response_Received;
pdInstance->commandExtParamCallback.dataBuffer = (uint8_t *)&(pdInstance->receivedData[1]);
pdInstance->commandExtParamCallback.dataBuffer += 2; /* data pos */
pdInstance->commandExtParamCallback.dataLength = extHeader.bitFields.dataSize;
pdInstance->commandExtParamCallback.sop = (uint8_t)triggerInfo->pdMsgSop;
break;
}
#endif
#endif
case kPD_MsgPing:
/* nothing need do, in case the default soft_reset */
break;
default:
if (((triggerInfo->pdMsgType > kPD_MsgInvalid) && (triggerInfo->pdMsgType <= kPD_MsgSoftReset)) ||
((triggerInfo->pdMsgType >= kPD_MsgNotSupported) && (triggerInfo->pdMsgType <= kPD_MsgFrSwap)) ||
((triggerInfo->pdMsgType >= kPD_MsgSourceCapabilities) &&
(triggerInfo->pdMsgType <= kPD_MsgVendorDefined)) ||
((triggerInfo->pdMsgType >= kPD_MsgSourceCapExtended) &&
(triggerInfo->pdMsgType <= kPD_MsgFirmwareUpdaetResponse)))
{
/* unexpected message */
pdInstance->psmNewState = PSM_SEND_SOFT_RESET;
}
else
{
/* receive unrecognized message */
replyNotSupport = sinkOrSoruceNotSupportState;
}
break;
}
}
if (replyNotSupport != PSM_UNKNOWN)
{
(void)PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(pdInstance, PD_NOT_SUPPORT_REPLY_MSG, replyNotSupport);
}
}
static uint8_t PD_PsmCanPendingReceive(pd_instance_t *pdInstance)
{
if ((pdInstance->psmCurState == PSM_PE_SNK_STARTUP) || (pdInstance->psmCurState == PSM_PE_SNK_DISCOVERY) ||
(pdInstance->psmCurState == PSM_PE_SNK_TRANSITION_TO_DEFAULT) || (pdInstance->psmCurState == PSM_HARD_RESET))
{
return 0;
}
if ((pdInstance->psmNewState == PSM_PE_SNK_STARTUP) || (pdInstance->psmNewState == PSM_PE_SNK_DISCOVERY) ||
(pdInstance->psmNewState == PSM_PE_SNK_TRANSITION_TO_DEFAULT) || (pdInstance->psmNewState == PSM_HARD_RESET) ||
(pdInstance->psmNewState == PSM_PE_SNK_WAIT_FOR_CAPABILITIES))
{
return 0;
}
return 1;
}
static void PD_PsmProcessImportEventBeforeNextStateMachine(pd_instance_t *pdInstance)
{
#if (defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
uint32_t taskEventSet = 0;
(void)OSA_EventGet(pdInstance->taskEventHandle, PD_TASK_EVENT_FR_SWAP_SINGAL, &taskEventSet);
if (taskEventSet != 0U)
{
(void)OSA_EventClear(pdInstance->taskEventHandle, PD_TASK_EVENT_FR_SWAP_SINGAL);
if (pdInstance->curPowerRole == kPD_PowerRoleSink)
{
pdInstance->psmNewState = PE_FRS_SNK_SRC_Send_Swap;
}
}
#endif
}
static uint8_t PD_PsmNoResponseHardResetCountCheck(pd_instance_t *pdInstance)
{
if ((PD_TimerCheckValidTimeOut(pdInstance, tNoResponseTimer) != 0U) &&
(pdInstance->psmHardResetCount > N_HARD_RESET_COUNT))
{
if (pdInstance->psmPreviouslyPdConnected != 0U)
{
pdInstance->psmNewState = PSM_EXIT_TO_ERROR_RECOVERY;
return 1;
}
#if (defined PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
else
{
if (pdInstance->curPowerRole == kPD_PowerRoleSource)
{
pdInstance->psmNewState = PSM_PE_SRC_DISABLED;
return 1;
}
}
#endif
}
return 0;
}
#if (defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)) || \
(defined(PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)) || \
(defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT))
static void PD_PsmStateWaitReply(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo, uint8_t *didNothingStepB)
{
pd_psm_state_t acceptState;
pd_psm_state_t otherState;
pd_dpm_callback_event_t failCallbackEvent;
pd_command_result_t commandResultCallback = kCommandResult_None;
switch (pdInstance->psmCurState)
{
#if defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
case PSM_PE_PRS_SRC_SNK_SEND_PR_SWAP:
acceptState = PSM_PE_PRS_SRC_SNK_TRANSITION_TO_OFF;
otherState = PSM_PE_SRC_READY;
failCallbackEvent = PD_DPM_PR_SWAP_FAIL;
break;
case PSM_PE_PRS_SNK_SRC_SEND_PR_SWAP:
acceptState = PSM_PE_PRS_SNK_SRC_TRANSITION_TO_OFF;
otherState = PSM_PE_SNK_READY;
failCallbackEvent = PD_DPM_PR_SWAP_FAIL;
break;
#endif
#if defined(PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
case PSM_PE_DRS_SEND_DR_SWAP:
acceptState = PSM_PE_DRS_CHANGE_TO_DFP_OR_UFP;
otherState = (pd_psm_state_t)pdInstance->psmDrSwapPrevState;
failCallbackEvent = PD_DPM_DR_SWAP_FAIL;
break;
#endif
#if defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
case PSM_PE_VCS_SEND_SWAP:
acceptState = (pdInstance->psmPresentlyVconnSource == kPD_IsVconnSource ? PSM_PE_VCS_WAIT_FOR_VCONN :
PSM_PE_VCS_TURN_ON_VCONN);
otherState = (pd_psm_state_t)pdInstance->psmVconnSwapPrevState;
failCallbackEvent = PD_DPM_VCONN_SWAP_FAIL;
break;
#endif
default:
acceptState = PSM_UNKNOWN;
otherState = PSM_UNKNOWN;
failCallbackEvent = PD_DPM_EVENT_INVALID;
break;
}
if ((triggerInfo->triggerEvent == PSM_TRIGGER_PD_MSG) && (failCallbackEvent != PD_DPM_EVENT_INVALID))
{
switch (triggerInfo->pdMsgType)
{
case kPD_MsgAccept:
{
#if defined(PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
if (failCallbackEvent == PD_DPM_DR_SWAP_FAIL)
{
pdInstance->curDataRole =
(pdInstance->curDataRole == kPD_DataRoleUFP) ? kPD_DataRoleDFP : kPD_DataRoleUFP;
(void)PD_PhyControl(pdInstance, PD_PHY_SET_MSG_HEADER_INFO, NULL);
}
#endif
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
commandResultCallback = kCommandResult_Accept;
#endif
pdInstance->psmNewState = acceptState;
break;
}
case kPD_MsgReject:
{
pdInstance->psmNewState = otherState;
commandResultCallback = kCommandResult_Reject;
(void)PD_DpmAppCallback(pdInstance, failCallbackEvent, &commandResultCallback, 1);
break;
}
case kPD_MsgWait:
{
pdInstance->psmNewState = otherState;
#if defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
if (failCallbackEvent == PD_DPM_PR_SWAP_FAIL)
{
(void)PD_TimerStart(pdInstance, tPrSwapWaitTimer, T_PRSWAP_WAIT);
}
#endif
#if defined(PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
if (failCallbackEvent == PD_DPM_DR_SWAP_FAIL)
{
(void)PD_TimerStart(pdInstance, tDrSwapWaitTimer, T_DRSWAP_WAIT);
}
#endif
commandResultCallback = kCommandResult_Wait;
(void)PD_DpmAppCallback(pdInstance, failCallbackEvent, &commandResultCallback, 1);
break;
}
default:
if (triggerInfo->pdMsgType != kPD_MsgInvalid)
{
/* SourceCapabilities and VendorDefined are handled in the global section. */
/* soft reset other packets */
pdInstance->psmNewState = PSM_SEND_SOFT_RESET;
commandResultCallback = kCommandResult_Error;
}
break;
}
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
if (commandResultCallback != kCommandResult_None)
{
PD_PsmReadyAutoPolicyResult(pdInstance, commandResultCallback);
}
#endif
}
else if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tSenderResponseTimer) != 0U)
{
pdInstance->psmNewState = otherState;
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
PD_PsmReadyAutoPolicyResult(pdInstance, kCommandResult_Timeout);
#endif
}
else
{
*didNothingStepB = 1;
}
}
#endif
#if defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
static void PD_PsmPowerSwapSinkSourceTransitionOff(pd_instance_t *pdInstance,
psm_trigger_info_t *triggerInfo,
pd_psm_state_t newState,
uint8_t *didNothingStepB)
{
if (triggerInfo->triggerEvent == PSM_TRIGGER_PD_MSG)
{
if ((triggerInfo->pdMsgSop == kPD_MsgSOP) && (triggerInfo->pdMsgType == kPD_MsgPsRdy))
{
(void)PD_TimerClear(pdInstance, tPSSourceOffTimer);
pdInstance->curPowerRole = kPD_PowerRoleSource;
(void)PD_PhyControl(pdInstance, PD_PHY_SET_MSG_HEADER_INFO, NULL);
pdInstance->psmNewState = newState;
}
else if ((triggerInfo->pdMsgSop == kPD_MsgSOP) && (triggerInfo->pdMsgType == kPD_MsgPing))
{
/* Remain in the same state */
pdInstance->psmNewState = pdInstance->psmCurState;
}
else
{
/* A protocol error during power role swap triggers a Hard Reset */
pdInstance->psmNewState = PSM_HARD_RESET;
}
}
else if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tPSSourceOffTimer) != 0U)
{
pdInstance->psmNewState = PSM_EXIT_TO_ERROR_RECOVERY;
}
else
{
*didNothingStepB = 1;
}
}
static void PD_PsmPowerSwapSinkOpenVbus(pd_instance_t *pdInstance, pd_dpm_callback_event_t callbackEvent)
{
if (PD_PsmSendControlTransitionWithErrorRecovery(pdInstance, kPD_MsgPsRdy, PSM_PE_SRC_STARTUP) != 0U)
{
/* Swap from SINK to SOURCE */
/* pr swap end */
PD_ConnectSetPowerProgress(pdInstance, kVbusPower_Stable);
#if defined(PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
/* Cable plug will need a soft reset */
pdInstance->psmCablePlugResetNeeded = 1;
#endif
pdInstance->enterSrcFromSwap = 1;
(void)PD_DpmAppCallback(pdInstance, callbackEvent, NULL, 1);
}
}
#endif
#if (defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)) || \
(defined(PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)) || \
(defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT))
static void PD_PsmEvaluateSwap(pd_instance_t *pdInstance,
pd_dpm_callback_event_t requestEvent,
pd_psm_state_t acceptState,
pd_psm_state_t rejectState)
{
if (requestEvent != PD_DPM_EVENT_INVALID)
{
(void)PD_DpmAppCallback(pdInstance, requestEvent, &pdInstance->commandEvaluateResult, 0);
}
if (pdInstance->commandEvaluateResult == kCommandResult_Accept)
{
pdInstance->psmNewState = acceptState;
}
else
{
pdInstance->psmNewState = rejectState;
}
}
#endif
#if defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
static void PD_PsmPowerSwapAssertRdRp(pd_instance_t *pdInstance, pd_power_role_t powerRole, pd_psm_state_t nextState)
{
pdInstance->curPowerRole = powerRole;
PD_ConnectSetPRSwapRole(pdInstance, pdInstance->curPowerRole);
pdInstance->psmNewState = nextState;
}
#endif
#if (defined(PD_CONFIG_VBUS_ALARM_SUPPORT) && (PD_CONFIG_VBUS_ALARM_SUPPORT)) || \
(defined(PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE))
static inline void PD_PsmSetVbusAlarmAndSinkDisconnect(pd_instance_t *pdInstance)
{
pd_rdo_t rdo;
pd_source_pdo_t pdo;
uint16_t minVoltage;
#if defined(PD_CONFIG_VBUS_ALARM_SUPPORT) && (PD_CONFIG_VBUS_ALARM_SUPPORT)
uint16_t maxVoltage;
uint32_t paramVal;
#endif
if (pdInstance->curPowerRole == kPD_PowerRoleSource)
{
rdo.rdoVal = pdInstance->partnerRdoRequest.rdoVal;
pdo.PDOValue = pdInstance->pdPowerPortConfig->sourceCaps[rdo.bitFields.objectPosition - 1U];
}
else
{
rdo.rdoVal = pdInstance->rdoRequest.rdoVal;
pdo.PDOValue = pdInstance->partnerSourcePDOs[rdo.bitFields.objectPosition - 1U].PDOValue;
}
switch ((pd_pdo_type_t)pdo.commonPDO.pdoType)
{
case kPDO_Fixed:
minVoltage = (uint16_t)pdo.fixedPDO.voltage * PD_PDO_VOLTAGE_UNIT;
#if defined(PD_CONFIG_VBUS_ALARM_SUPPORT) && (PD_CONFIG_VBUS_ALARM_SUPPORT)
maxVoltage = minVoltage / 100U * 105U + 500U; /* vSrcNew(max) + vSrcValid(max) */
#endif
minVoltage = minVoltage / 100U * 95U - 500U; /* vSrcNew(min) + vSrcValid(min) */
break;
case kPDO_Battery:
minVoltage = (uint16_t)pdo.batteryPDO.minVoltage * PD_PDO_VOLTAGE_UNIT;
#if defined(PD_CONFIG_VBUS_ALARM_SUPPORT) && (PD_CONFIG_VBUS_ALARM_SUPPORT)
maxVoltage = (uint16_t)pdo.batteryPDO.maxVoltage * PD_PDO_VOLTAGE_UNIT;
#endif
break;
case kPDO_Variable:
minVoltage = (uint16_t)pdo.variablePDO.minVoltage * PD_PDO_VOLTAGE_UNIT;
#if defined(PD_CONFIG_VBUS_ALARM_SUPPORT) && (PD_CONFIG_VBUS_ALARM_SUPPORT)
maxVoltage = (uint16_t)pdo.variablePDO.maxVoltage * PD_PDO_VOLTAGE_UNIT;
#endif
break;
case kPDO_APDO:
minVoltage = (uint16_t)rdo.programRDOBitFields.outputVoltage * PD_PRDO_VOLTAGE_UNIT;
#if defined(PD_CONFIG_VBUS_ALARM_SUPPORT) && (PD_CONFIG_VBUS_ALARM_SUPPORT)
maxVoltage = minVoltage / 100U * 105U + 100U; /* vPpsNew(max) + vPpsValid(max) */
#endif
minVoltage = minVoltage / 100U * 95U - 100U; /* vPpsNew(min) + vPpsValid(min) */
break;
default:
/* cannot reach here normally. */
/* minVoltage = 5000U * 95U / 1000U - 500U;
maxVoltage = 5000U * 105U / 100U + 500U; */
break;
}
#if defined(PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)
if (pdInstance->curPowerRole == kPD_PowerRoleSink)
{
minVoltage -= 750U; /* Voltage - Cable IR Drop(750mV) */
/* Set VBUS_SINK_DISCONNECT_THRESHOLD according to power negotiation result. */
(void)PD_PhyControl(pdInstance, PD_PHY_SET_VBUS_SINK_DISCONNECT, &minVoltage);
}
#endif
#if defined(PD_CONFIG_VBUS_ALARM_SUPPORT) && (PD_CONFIG_VBUS_ALARM_SUPPORT)
paramVal = ((uint32_t)maxVoltage << 16U) | (uint32_t)minVoltage;
(void)PD_PhyControl(pdInstance, PD_PHY_INFORM_VBUS_VOLTAGE_RANGE, &paramVal);
#endif
}
#endif
static void PD_PsmResetStateWhenEnterReadyState(pd_instance_t *pdInstance)
{
#if ((defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE))
pdInstance->psmSecondaryState[0] = PSM_IDLE;
pdInstance->psmSecondaryState[1] = PSM_IDLE;
pdInstance->psmSecondaryState[2] = PSM_IDLE;
#endif
pdInstance->psmExplicitContractExisted = 1;
#if defined(PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE) && (PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE)
pdInstance->powerNegotiationInitiator = 1;
#endif
#if (defined PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
if (PD_CheckWhetherInitiateCableDiscoveryIdentityOrNot(pdInstance) != 0U)
{
pdInstance->pendingSOP = (uint8_t)kPD_MsgSOPMask | (uint8_t)kPD_MsgSOPpMask | (uint8_t)kPD_MsgSOPppMask;
(void)PD_TimerStart(pdInstance, tDiscoverIdentityTimer, T_DISCOVER_IDENTITY);
}
else
#endif
{
pdInstance->pendingSOP = (uint8_t)kPD_MsgSOPMask;
}
#if (defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
if (pdInstance->frsEnabled == 0U)
{
PD_FRSControl(pdInstance, 1);
pdInstance->frsEnabled = 1;
}
#endif
/* Stop ignoring droops on VBus */
/* kVbusPower_ChangeInProgress is done */
PD_ConnectSetPowerProgress(pdInstance, kVbusPower_Stable);
#if (defined(PD_CONFIG_VBUS_ALARM_SUPPORT) && (PD_CONFIG_VBUS_ALARM_SUPPORT)) || \
(defined(PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE))
PD_PsmSetVbusAlarmAndSinkDisconnect(pdInstance);
#endif
}
#if defined(PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
static void PD_StateSendReplyExtDataTransition(pd_instance_t *pdInstance, message_type_t msgType)
{
if (pdInstance->commandExtParamCallback.resultStatus != (uint8_t)kCommandResult_NotSupported)
{
if (msgType == kPD_MsgBatteryStatus)
{
(void)PD_MsgSendDataTransition(pdInstance, msgType, pdInstance->commandExtParamCallback.dataLength >> 2,
(void *)pdInstance->commandExtParamCallback.dataBuffer,
PE_PSM_STATE_ROLE_RDY_STATE, PSM_CHECK_ASYNC_RX, PSM_SEND_SOFT_RESET);
}
else
{
(void)PD_MsgSendExtTransition(pdInstance, kPD_MsgSOP, msgType,
pdInstance->commandExtParamCallback.dataLength,
pdInstance->commandExtParamCallback.dataBuffer, PE_PSM_STATE_ROLE_RDY_STATE,
PSM_CHECK_ASYNC_RX, PSM_SEND_SOFT_RESET);
}
}
else
{
(void)PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(pdInstance, kPD_MsgNotSupported,
PE_PSM_STATE_ROLE_RDY_STATE);
}
}
#endif
static void PD_PsmCheckChunkedFeature(pd_instance_t *pdInstance, pd_rdo_t rdo)
{
if ((rdo.bitFields.unchunkedSupported != 0U) &&
(pdInstance->selfOrPartnerFirstSourcePDO.fixedPDO.unchunkedSupported != 0U))
{
pdInstance->unchunkedFeature = 1;
}
else
{
pdInstance->unchunkedFeature = 0;
}
}
#if (defined PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
static void PD_PsmTurnOffVconnAndVbus(pd_instance_t *pdInstance, pd_vbus_power_progress_t powerState)
{
#if (defined PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
if (pdInstance->callbackFns->PD_ControlVconn != NULL)
{
(void)pdInstance->callbackFns->PD_ControlVconn(pdInstance->callbackParam, 0);
}
#endif
if (pdInstance->callbackFns->PD_SrcTurnOffVbus != NULL)
{
(void)pdInstance->callbackFns->PD_SrcTurnOffVbus(pdInstance->callbackParam, powerState);
}
}
#endif
/* state process small functions when enter the state */
static inline void PD_PsmEnterIdleState(pd_instance_t *pdInstance)
{
pdInstance->psmHardResetCount = 0;
#if (defined PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
pdInstance->psmSendCapsCounter = 0;
#endif
#if (defined PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
pdInstance->cableDiscoverIdentityCounter = 0;
#endif
/* kVbusPower_InHardReset is end */
PD_ConnectSetPowerProgress(pdInstance, kVbusPower_Stable);
PD_MsgReset(pdInstance);
PD_PsmReset(pdInstance);
if (pdInstance->pdConfig->deviceType == (uint8_t)kDeviceType_AlternateModeProduct)
{
/* If we are an alternate mode adapter, then set tAMETimeout. */
(void)PD_TimerStart(pdInstance, tAMETimeoutTimer, T_AME_TIMEOUT);
}
if (pdInstance->curPowerRole == kPD_PowerRoleSource)
{
#if (defined PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
pdInstance->enterSrcFromSwap = 0;
pdInstance->psmNewState = PSM_PE_SRC_STARTUP;
#else
pdInstance->psmNewState = PSM_BYPASS;
#endif
}
else if (pdInstance->curPowerRole == kPD_PowerRoleSink)
{
#if (defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)
pdInstance->psmNewState = PSM_PE_SNK_STARTUP;
#else
pdInstance->psmNewState = PSM_BYPASS;
#endif
}
else
{
/* No action required. */
}
}
static inline void PD_PsmEnterHardResetState(pd_instance_t *pdInstance)
{
#if ((defined PD_CONFIG_EXTENDED_CHUNK_LAYER_SUPPORT) && (PD_CONFIG_EXTENDED_CHUNK_LAYER_SUPPORT))
PD_MsgChunkingLayerResetFlags(pdInstance);
#endif
/* Do this as early as possible, to prevent disconnects
* Hard Reset is in progress, ignore VBus going away.
* source need set this too, because judge vbus too (dead battery related) for disconnect.
*/
/* If there is an AMS in progress, end this AMS with failure before starting Hard Reset. */
PD_PsmCommandFail(pdInstance, pdInstance->commandProcessing);
PD_ConnectSetPowerProgress(pdInstance, kVbusPower_InHardReset);
PD_PsmReset(pdInstance);
/* Delay for 1ms to make sure any previous GoodCRC tranmission has ended. */
(void)PD_PsmTimerWait(pdInstance, tDelayTimer, mSec(1), 0U);
/* source send hard_reset, 1. send hard_reset msg. */
PD_MsgSendHardOrCableReset(pdInstance, 0);
if (pdInstance->curPowerRole == kPD_PowerRoleSource)
{
(void)PD_TimerStart(pdInstance, tPSHardResetTimer, T_PS_HARD_RESET);
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SRC_HARD_RESET_REQUEST, NULL, 0);
}
else
{
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SNK_HARD_RESET_REQUEST, NULL, 0);
}
pdInstance->psmHardResetCount++;
}
static inline void PD_PsmEnterSendSoftResetState(pd_instance_t *pdInstance)
{
/* Interate at least 1 time to cover an RX between our initial discard, and tx completion */
uint8_t retryCount = 1; /* as retry time variable */
#if ((defined PD_CONFIG_EXTENDED_CHUNK_LAYER_SUPPORT) && (PD_CONFIG_EXTENDED_CHUNK_LAYER_SUPPORT))
PD_MsgChunkingLayerResetFlags(pdInstance);
#endif
#if (defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE)
#if 0
if (pdInstance->psmSoftResetSop != kPD_MsgSOP)
{
PD_PsmSecondaryStateHandlerTerminate(pdInstance, pdInstance->psmSoftResetSop);
/*PD_PsmSecondaryStateHandler(pdInstance, pdInstance->psmSoftResetSop, pdInstance->psmSoftResetSop,
*/
/*&triggerInfo); */
}
#endif
#endif
do
{
if (PD_MsgSend(pdInstance, kPD_MsgSOP, kPD_MsgSoftReset, 2, NULL) == kStatus_PD_Success)
{
(void)PD_TimerStart(pdInstance, tSenderResponseTimer, T_SENDER_RESPONSE);
}
else if (((PD_MsgRecvPending(pdInstance) != 0U) &&
((uint8_t)((MSG_DATA_HEADER & PD_MSG_HEADER_MESSAGE_TYPE_MASK) >> PD_MSG_HEADER_MESSAGE_TYPE_POS) ==
(uint8_t)kPD_MsgSoftReset)) ||
(pdInstance->hardResetReceived == 1U))
{
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SOFT_RESET_SUCCESS, NULL,
(pdInstance->commandProcessing == PD_DPM_CONTROL_SOFT_RESET) ? 1U : 0U);
}
else if ((PD_MsgRecvPending(pdInstance) != 0U) && (retryCount > 0U))
{
retryCount--;
continue;
}
else
{
if (pdInstance->commandProcessing == PD_DPM_CONTROL_SOFT_RESET)
{
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SOFT_RESET_FAIL, NULL, 1);
}
pdInstance->psmNewState = PSM_HARD_RESET;
}
break;
} while (true);
}
#if (defined PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
static inline void PD_PsmEnterSrcStartUpState(pd_instance_t *pdInstance)
{
pdInstance->psmPresentlyPdConnected = 0;
pdInstance->psmSendCapsCounter = 0;
#if (defined PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
pdInstance->cableDiscoverIdentityCounter = 0;
#endif
#if (defined PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE) && (PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE)
pdInstance->powerNegotiationInitiator = 0;
#endif
/* kVbusPower_InHardReset is end */
PD_ConnectSetPowerProgress(pdInstance, kVbusPower_Stable);
/* Delay for 1ms to make sure any previous GoodCRC tranmission has ended. */
(void)PD_PsmTimerWait(pdInstance, tDelayTimer, mSec(1), 0U);
PD_MsgReset(pdInstance);
(void)PD_PhyControl(pdInstance, PD_PHY_SET_MSG_HEADER_INFO, NULL);
pdInstance->pendingSOP = (uint8_t)kPD_MsgSOPMask;
PD_MsgStartReceive(pdInstance);
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
PD_PsmSetAutoPolicyState(pdInstance, PSM_RDY_EVAL_INIT);
#endif
/* A large value allows the sink to debounce CC and VBUS after the connection. */
if (pdInstance->enterSrcFromSwap != 0U)
{
(void)PD_TimerStart(pdInstance, tSwapSourceStartTimer, T_SEND_SOURCE_CAP);
}
else
{
pdInstance->psmNewState = PSM_PE_SRC_IMPLICIT_CABLE_DISCOVERY;
}
}
static inline void PD_PsmEnterImplicitCableDiscoveryState(pd_instance_t *pdInstance)
{
#if (defined(PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)) && \
(defined(PD_CONFIG_SRC_AUTO_DISCOVER_CABLE_PLUG) && (PD_CONFIG_SRC_AUTO_DISCOVER_CABLE_PLUG))
/* (The initial source && Ra present) || (swap to source from initial sink, cannot detect the Ra) */
if (((pdInstance->raPresent != 0U) || (pdInstance->initialPowerRole == kPD_PowerRoleSink)) &&
(pdInstance->psmPresentlyVconnSource == kPD_IsVconnSource) && (pdInstance->psmCableIdentitiesDataCount == 0U))
{
pdInstance->pendingSOP = (uint8_t)kPD_MsgSOPMask | (uint8_t)kPD_MsgSOPpMask | (uint8_t)kPD_MsgSOPppMask;
if (pdInstance->psmCablePlugResetNeeded != 0U)
{
pdInstance->psmNewSecondaryState[1] = PSM_PE_SRC_IMPLICIT_CABLE_SOFT_RESET;
}
else
{
pdInstance->psmNewSecondaryState[1] = PSM_PE_SRC_VDM_IDENTITY_REQUEST;
}
}
else
#endif
{
#if (defined(PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)) && \
(defined(PD_CONFIG_SRC_AUTO_DISCOVER_CABLE_PLUG) && (PD_CONFIG_SRC_AUTO_DISCOVER_CABLE_PLUG))
pdInstance->pendingSOP = (uint8_t)kPD_MsgSOPMask;
#endif
pdInstance->psmNewState = PSM_PE_SRC_SEND_CAPABILITIES;
}
}
static inline void PD_PsmEnterSrcSendCapsState(pd_instance_t *pdInstance)
{
pdInstance->selfOrPartnerFirstSourcePDO.PDOValue = pdInstance->pdPowerPortConfig->sourceCaps[0];
if (pdInstance->commandProcessing == PD_DPM_INVALID)
{
/* PD_DPM_INVALID means that it is the first time to send source capabilities,
the GetSourceCap message is received or the SoftReset process(receive or send) has been completed. */
(void)PD_PsmStartCommand(pdInstance, PD_DPM_CONTROL_POWER_NEGOTIATION,
#if defined(PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE) && (PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE)
pdInstance->powerNegotiationInitiator
#else
0
#endif
);
}
pdInstance->psmSendCapsCounter++;
if (PD_MsgSendDataTransition(
pdInstance, kPD_MsgSourceCapabilities, pdInstance->pdPowerPortConfig->sourceCapCount,
PD_PsmGetSourcePDOs(pdInstance), PE_PSM_STATE_NO_CHANGE, PSM_CHECK_ASYNC_RX,
(pdInstance->psmPresentlyPdConnected != 0U) ? PSM_SEND_SOFT_RESET : PSM_PE_SRC_DISCOVERY) != 0U)
{
pdInstance->psmPresentlyPdConnected = 1;
pdInstance->psmPreviouslyPdConnected = 1;
(void)PD_TimerClear(pdInstance, tNoResponseTimer);
pdInstance->psmHardResetCount = 0;
pdInstance->psmSendCapsCounter = 0;
(void)PD_TimerStart(pdInstance, tSenderResponseTimer, T_SENDER_RESPONSE);
}
}
static inline void PD_PsmEnterSrcNegotiateCapState(pd_instance_t *pdInstance)
{
pd_negotiate_power_request_t negotiateResult;
PD_PsmCheckChunkedFeature(pdInstance, pdInstance->partnerRdoRequest);
negotiateResult.rdo = pdInstance->partnerRdoRequest;
negotiateResult.negotiateResult = (uint8_t)kCommandResult_Accept;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SRC_RDO_REQUEST, &negotiateResult, 0);
if (negotiateResult.negotiateResult == (uint8_t)kCommandResult_Accept)
{
pdInstance->psmGotoMinTx = 0;
pdInstance->psmNewState = PSM_PE_SRC_TRANSITION_SUPPLY;
}
else
{
pdInstance->commandEvaluateResult = (pd_command_result_t)negotiateResult.negotiateResult;
pdInstance->psmNewState = PSM_PE_SRC_CAPABILITY_RESPONSE;
}
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
PD_PsmSetAutoPolicyState(pdInstance, PSM_RDY_EVAL_INIT);
#endif
}
static inline void PD_PsmEnterSrcTransitionSupplyState(pd_instance_t *pdInstance)
{
uint8_t enable;
if (PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(
pdInstance, ((pdInstance->psmGotoMinTx != 0U) ? kPD_MsgGotoMin : kPD_MsgAccept), PE_PSM_STATE_NO_CHANGE) !=
0U)
{
/* transition power */
(void)PD_PsmTimerWait(pdInstance, tDelayTimer, T_SRC_TRANSITION, PD_TASK_EVENT_RECEIVED_HARD_RESET);
if (pdInstance->psmGotoMinTx != 0U)
{
(void)pdInstance->callbackFns->PD_SrcGotoMinReducePower(pdInstance->callbackParam);
}
else
{
/* Start ignoring droops on VBus */
PD_ConnectSetPowerProgress(pdInstance, kVbusPower_ChangeInProgress);
(void)pdInstance->callbackFns->PD_SrcTurnOnRequestVbus(pdInstance->callbackParam,
pdInstance->partnerRdoRequest);
enable = 1;
(void)PD_PhyControl(pdInstance, PD_PHY_CONTROL_VBUS_AUTO_DISCHARGE, &enable);
}
}
else
{
if (pdInstance->psmGotoMinTx != 0U)
{
pdInstance->psmGotoMinTx = 0;
}
}
}
static inline void PD_PsmEnterSrcCapResponseState(pd_instance_t *pdInstance)
{
message_type_t msgType;
if (pdInstance->commandEvaluateResult == kCommandResult_Reject)
{
msgType = kPD_MsgReject;
}
else
{
msgType = kPD_MsgWait;
pdInstance->commandEvaluateResult = kCommandResult_Error;
}
if (PD_PsmSendControlTransitionWithHardReset(pdInstance, msgType, PE_PSM_STATE_NO_CHANGE) != 0U)
{
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SRC_RDO_FAIL, &pdInstance->commandEvaluateResult, 1);
if (pdInstance->psmExplicitContractExisted == 0U)
{
pdInstance->psmNewState = PSM_PE_SRC_WAIT_NEW_CAPABILITIES;
}
else
{
uint8_t stillValid = 0;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SRC_CONTRACT_STILL_VALID, &stillValid, 0);
if ((stillValid != 0U) || (msgType == kPD_MsgWait))
{
pdInstance->psmNewState = PSM_PE_SRC_READY;
}
else
{
pdInstance->psmNewState = PSM_HARD_RESET;
}
}
}
}
static inline void PD_PsmEnterSrcTransitionToDefaultState(pd_instance_t *pdInstance)
{
uint32_t eventSet = 0;
pdInstance->psmPresentlyPdConnected = 0;
pdInstance->psmExplicitContractExisted = 0;
pdInstance->psmHardResetNeedsVSafe0V = 1;
/* source send hard_reset, 2. change to supply vsafe5v. */
/* source receive hard_reset, 2. change to supply vsafe5v. */
(void)PD_TimerClear(pdInstance, tSrcRecoverTimer);
do
{
PD_PsmTurnOffVconnAndVbus(pdInstance, kVbusPower_InHardReset);
PD_DpmDischargeVbus(pdInstance, 1);
if (PD_PsmCheckVsafe0V(pdInstance) != 0U)
{
break;
}
/* When VBUS decreases to vSafe0V, the EXTENDED_STATUS.vSafe0V register will be set and an interrupt
will be asserted, so software does not need to check vSafe0V constantly. */
(void)OSA_EventWait(pdInstance->taskEventHandle, PD_TASK_EVENT_ALL, 0, 5, &eventSet);
} while (true);
PD_DpmDischargeVbus(pdInstance, 0);
/* source send hard_reset, 3. start tSrcRecover timer. */
/* source receive hard_reset, 3. start tSrcRecover timer. */
/* 1. vbus is vsafe0v -> start the tSrcRecover timer -> After tSrcRecover the Source applies power to
* VBUS */
(void)PD_TimerStart(pdInstance, tSrcRecoverTimer, T_SRC_RECOVER);
/* Message reception should not be re-enabled until PE_SNK_Startup */
PD_MsgReset(pdInstance);
/* Change our data role to DFP, and turn off vconn */
pdInstance->curDataRole = kPD_DataRoleDFP;
pdInstance->psmPresentlyVconnSource = kPD_IsVconnSource;
(void)PD_PhyControl(pdInstance, PD_PHY_SET_MSG_HEADER_INFO, NULL);
#if defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
PD_DpmDischargeVconn(pdInstance, 1);
#endif /* PD_CONFIG_VCONN_SUPPORT */
}
static inline void PD_PsmEnterGiveSrcCapState(pd_instance_t *pdInstance)
{
if (((pdInstance->pdPowerPortConfig->typecRole == (uint8_t)kPowerConfig_SourceOnly) ||
(pdInstance->pdPowerPortConfig->typecRole == (uint8_t)kPowerConfig_SinkDefault) ||
(pdInstance->pdPowerPortConfig->typecRole == (uint8_t)kPowerConfig_SourceDefault) ||
(pdInstance->pdPowerPortConfig->typecRole == (uint8_t)kPowerConfig_DRPToggling)) &&
(pdInstance->pdPowerPortConfig->sourceCaps != NULL))
{
(void)PD_MsgSendDataTransition(pdInstance, kPD_MsgSourceCapabilities,
pdInstance->pdPowerPortConfig->sourceCapCount, PD_PsmGetSourcePDOs(pdInstance),
PE_PSM_STATE_ROLE_RDY_STATE, PSM_CHECK_ASYNC_RX, PSM_SEND_SOFT_RESET);
}
else
{
(void)PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(pdInstance, PD_NOT_SUPPORT_REPLY_MSG,
PE_PSM_STATE_ROLE_RDY_STATE);
}
}
#endif
static inline void PD_PsmEnterGetSinkOrSourceCapState(pd_instance_t *pdInstance, pd_psm_state_t prevState)
{
message_type_t msgType = kPD_MsgGetSinkCap;
pd_psm_state_t successSate = PE_PSM_STATE_NO_CHANGE;
if ((pdInstance->psmCurState == PSM_PE_DR_SRC_GET_SOURCE_CAP) ||
(pdInstance->psmCurState == PSM_PE_SNK_GET_SOURCE_CAP))
{
msgType = kPD_MsgGetSourceCap;
}
if (pdInstance->psmCurState == PSM_PE_SNK_GET_SOURCE_CAP)
{
successSate = PSM_PE_SNK_READY;
}
(void)PD_PsmSendControlTransitionWithSendResponserTimeOut(pdInstance, msgType, successSate, prevState,
PSM_SEND_SOFT_RESET);
}
#if (defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)) || \
((defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE))
static inline void PD_PsmEnterGiveSinkCapState(pd_instance_t *pdInstance)
{
if ((pdInstance->pdPowerPortConfig->typecRole != (uint8_t)kPowerConfig_SourceOnly) &&
(pdInstance->pdPowerPortConfig->sinkCaps != NULL))
{
(void)PD_MsgSendDataTransition(pdInstance, kPD_MsgSinkCapabilities, pdInstance->pdPowerPortConfig->sinkCapCount,
PD_PsmGetSinkPDOs(pdInstance), PE_PSM_STATE_ROLE_RDY_STATE, PSM_CHECK_ASYNC_RX,
PSM_SEND_SOFT_RESET);
}
else
{
(void)PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(pdInstance, PD_NOT_SUPPORT_REPLY_MSG,
PE_PSM_STATE_ROLE_RDY_STATE);
}
}
#endif
#if (defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)
static inline void PD_PsmEnterSnkStartUpState(pd_instance_t *pdInstance)
{
/* Delay for 1ms to make sure any previous GoodCRC tranmission has ended. */
(void)PD_PsmTimerWait(pdInstance, tDelayTimer, mSec(1), 0U);
PD_MsgReset(pdInstance);
pdInstance->pendingSOP = (uint8_t)kPD_MsgSOPMask;
PD_MsgStartReceive(pdInstance);
(void)PD_PhyControl(pdInstance, PD_PHY_SET_MSG_HEADER_INFO, NULL);
#if (defined PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
pdInstance->cableDiscoverIdentityCounter = 0;
#endif
pdInstance->psmPresentlyPdConnected = 0;
/* Do not clear previouslyPdConnected here */
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
PD_PsmSetAutoPolicyState(pdInstance, PSM_RDY_EVAL_INIT);
#endif
pdInstance->psmNewState = PSM_PE_SNK_DISCOVERY;
}
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
void PD_AutoSinkNegotiation(pd_instance_t *pdInstance, pd_rdo_t *rdoRequest)
{
uint8_t snkCapIndex;
uint8_t srcCapIndex;
pd_sink_pdo_t sinkPdo;
pd_source_pdo_t sourcePDO;
uint32_t requestVoltageMin = 0; /* mV */
uint32_t requestVoltageMax = 0; /* mV */
uint32_t requestCurrent = 0; /* mA */
uint32_t currentPower = 0; /* mW */
rdoRequest->bitFields.objectPosition = 1;
rdoRequest->bitFields.giveBack = 0;
rdoRequest->bitFields.noUsbSuspend = 1;
#if ((defined PD_CONFIG_REVISION) && (PD_CONFIG_REVISION >= PD_SPEC_REVISION_30))
rdoRequest->bitFields.unchunkedSupported = 1;
#endif
sourcePDO.PDOValue = pdInstance->partnerSourcePDOs[0].PDOValue;
sinkPdo.PDOValue = pdInstance->pdPowerPortConfig->sinkCaps[0];
rdoRequest->bitFields.usbCommunicationsCapable = sinkPdo.fixedPDO.usbCommunicationsCapable;
if (sourcePDO.fixedPDO.maxCurrent >= sinkPdo.fixedPDO.operateCurrent)
{
rdoRequest->bitFields.operateValue = sinkPdo.fixedPDO.operateCurrent;
rdoRequest->bitFields.capabilityMismatch = 0;
}
else
{
rdoRequest->bitFields.operateValue = sourcePDO.fixedPDO.maxCurrent;
rdoRequest->bitFields.capabilityMismatch = 1;
}
rdoRequest->bitFields.maxOrMinOperateValue = rdoRequest->bitFields.operateValue;
currentPower =
rdoRequest->bitFields.operateValue * PD_PDO_CURRENT_UNIT * sinkPdo.fixedPDO.voltage * PD_PDO_VOLTAGE_UNIT;
for (snkCapIndex = (uint8_t)pdInstance->pdPowerPortConfig->sinkCapCount - 1U; snkCapIndex > 0U; --snkCapIndex)
{
sinkPdo.PDOValue = pdInstance->pdPowerPortConfig->sinkCaps[snkCapIndex];
switch ((pd_pdo_type_t)sinkPdo.commonPDO.pdoType)
{
case kPDO_Fixed:
{
requestVoltageMin = sinkPdo.fixedPDO.voltage * PD_PDO_VOLTAGE_UNIT;
requestVoltageMax = requestVoltageMin;
requestCurrent = sinkPdo.fixedPDO.operateCurrent * PD_PDO_CURRENT_UNIT;
break;
}
case kPDO_Variable:
{
requestVoltageMin = sinkPdo.variablePDO.minVoltage * PD_PDO_VOLTAGE_UNIT;
requestVoltageMax = sinkPdo.variablePDO.maxVoltage * PD_PDO_VOLTAGE_UNIT;
requestCurrent = sinkPdo.variablePDO.operateCurrent * PD_PDO_CURRENT_UNIT;
break;
}
case kPDO_Battery:
{
requestVoltageMin = sinkPdo.batteryPDO.minVoltage * PD_PDO_VOLTAGE_UNIT;
requestVoltageMax = sinkPdo.batteryPDO.maxVoltage * PD_PDO_VOLTAGE_UNIT;
requestCurrent = (sinkPdo.batteryPDO.operatePower * PD_PDO_POWER_UNIT) * 1000U / requestVoltageMin;
break;
}
case kPDO_APDO:
{
requestVoltageMin = sinkPdo.apdoPDO.minVoltage * PD_APDO_VOLTAGE_UNIT;
requestVoltageMax = sinkPdo.apdoPDO.maxVoltage * PD_APDO_VOLTAGE_UNIT;
requestCurrent = sinkPdo.apdoPDO.maxCurrent * PD_APDO_CURRENT_UNIT;
break;
}
default:
/* No action required. */
break;
}
for (srcCapIndex = 0; srcCapIndex < pdInstance->partnerSourcePDOsCount; ++srcCapIndex)
{
uint32_t power;
uint32_t current;
uint8_t misMatch = 0;
uint32_t pdoMaxVoltage = 0;
uint32_t pdoMinVoltage = 0;
sourcePDO.PDOValue = pdInstance->partnerSourcePDOs[srcCapIndex].PDOValue;
switch ((pd_pdo_type_t)sourcePDO.commonPDO.pdoType)
{
case kPDO_Fixed:
{
pdoMinVoltage = sourcePDO.fixedPDO.voltage * PD_PDO_VOLTAGE_UNIT;
pdoMaxVoltage = pdoMinVoltage;
if ((pdoMaxVoltage > requestVoltageMax) || (pdoMinVoltage < requestVoltageMin))
{
continue;
}
current = requestCurrent;
if (current > sourcePDO.fixedPDO.maxCurrent * PD_PDO_CURRENT_UNIT)
{
current = sourcePDO.fixedPDO.maxCurrent * PD_PDO_CURRENT_UNIT;
misMatch = 1U;
}
power = pdoMinVoltage * current / 1000U;
if (power > currentPower)
{
currentPower = power;
rdoRequest->bitFields.operateValue = current / PD_PDO_CURRENT_UNIT;
rdoRequest->bitFields.capabilityMismatch = misMatch;
rdoRequest->bitFields.objectPosition = (uint32_t)srcCapIndex + 1U;
rdoRequest->bitFields.maxOrMinOperateValue = rdoRequest->bitFields.operateValue;
}
break;
}
case kPDO_Variable:
{
pdoMaxVoltage = sourcePDO.variablePDO.maxVoltage * PD_PDO_VOLTAGE_UNIT;
pdoMinVoltage = sourcePDO.variablePDO.minVoltage * PD_PDO_VOLTAGE_UNIT;
if ((pdoMaxVoltage > requestVoltageMax) || (pdoMinVoltage < requestVoltageMin))
{
continue;
}
current = requestCurrent;
if (current > sourcePDO.variablePDO.maxCurrent * PD_PDO_CURRENT_UNIT)
{
current = sourcePDO.variablePDO.maxCurrent * PD_PDO_CURRENT_UNIT;
misMatch = 1;
}
power = pdoMinVoltage * current / 1000U;
if (power > currentPower)
{
currentPower = power;
rdoRequest->bitFields.operateValue = current / PD_PDO_CURRENT_UNIT;
rdoRequest->bitFields.capabilityMismatch = misMatch;
rdoRequest->bitFields.objectPosition = (uint32_t)srcCapIndex + 1U;
rdoRequest->bitFields.maxOrMinOperateValue = rdoRequest->bitFields.operateValue;
}
break;
}
case kPDO_Battery:
{
pdoMaxVoltage = sourcePDO.batteryPDO.maxVoltage * PD_PDO_VOLTAGE_UNIT;
pdoMinVoltage = sourcePDO.batteryPDO.minVoltage * PD_PDO_VOLTAGE_UNIT;
if ((pdoMaxVoltage > requestVoltageMax) || (pdoMinVoltage < requestVoltageMin))
{
continue;
}
power = requestVoltageMax * requestCurrent / 1000U;
if (power > (sourcePDO.batteryPDO.maxAllowPower * PD_PDO_POWER_UNIT))
{
power = sourcePDO.batteryPDO.maxAllowPower * PD_PDO_POWER_UNIT;
misMatch = 1;
}
if (power > currentPower)
{
currentPower = power;
rdoRequest->bitFields.operateValue = power / PD_PDO_POWER_UNIT;
rdoRequest->bitFields.capabilityMismatch = misMatch;
rdoRequest->bitFields.objectPosition = (uint32_t)srcCapIndex + 1U;
rdoRequest->bitFields.maxOrMinOperateValue = rdoRequest->bitFields.operateValue;
}
break;
}
case kPDO_APDO:
{
uint32_t voltage;
pdoMaxVoltage = sourcePDO.apdoPDO.maxVoltage * PD_APDO_VOLTAGE_UNIT;
pdoMinVoltage = sourcePDO.apdoPDO.minVoltage * PD_APDO_VOLTAGE_UNIT;
if (((requestVoltageMin < pdoMinVoltage) && (requestVoltageMax < pdoMinVoltage)) ||
((requestVoltageMin > pdoMaxVoltage) && (requestVoltageMax > pdoMaxVoltage)))
{
continue;
}
voltage = requestVoltageMax;
if (voltage > pdoMaxVoltage)
{
voltage = pdoMaxVoltage;
}
current = requestCurrent;
if (current > sourcePDO.apdoPDO.maxCurrent * PD_APDO_CURRENT_UNIT)
{
current = sourcePDO.apdoPDO.maxCurrent * PD_APDO_CURRENT_UNIT;
misMatch = 1U;
}
power = voltage * current / 1000U;
if (power > currentPower)
{
currentPower = power;
rdoRequest->bitFields.operateValue = current / PD_PRDO_CURRENT_UNIT;
rdoRequest->bitFields.capabilityMismatch = misMatch;
rdoRequest->bitFields.objectPosition = (uint32_t)srcCapIndex + 1U;
rdoRequest->bitFields.maxOrMinOperateValue = rdoRequest->bitFields.operateValue;
}
break;
}
default:
/* No action required. */
break;
}
}
}
}
#endif
static inline void PD_PsmEnterSnkEvaluateCapState(pd_instance_t *pdInstance)
{
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
PD_PsmSetAutoPolicyState(pdInstance, PSM_RDY_EVAL_INIT);
#endif
pdInstance->psmHardResetCount = 0;
(void)PD_TimerClear(pdInstance, tNoResponseTimer);
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
if (PD_POLICY_GET_AUTO_SINK_NEGOTIATION_SUPPORT(pdInstance))
{
PD_AutoSinkNegotiation(pdInstance, &pdInstance->rdoRequest);
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY_LOG) && (PD_CONFIG_ENABLE_AUTO_POLICY_LOG)
(void)PRINTF("sink auto do the request negotiation\r\n");
#endif
}
else
#endif
{
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SNK_GET_RDO, &pdInstance->rdoRequest, 0);
}
if (pdInstance->revision < PD_SPEC_REVISION_30)
{
pdInstance->rdoRequest.bitFields.unchunkedSupported = 0;
}
if (pdInstance->commandProcessing == PD_DPM_INVALID)
{
(void)PD_PsmStartCommand(pdInstance, PD_DPM_CONTROL_REQUEST, 0);
}
PD_PsmCheckChunkedFeature(pdInstance, pdInstance->rdoRequest);
pdInstance->psmNewState = PSM_PE_SNK_SELECT_CAPABILITY;
}
static inline void PD_PsmEnterSnkReadyState(pd_instance_t *pdInstance)
{
PD_PsmResetStateWhenEnterReadyState(pdInstance);
#if (defined PD_CONFIG_PD3_PPS_ENABLE) && (PD_CONFIG_PD3_PPS_ENABLE)
/* SinkPPSPeriodicTimer */
if (PD_PsmSinkIsPPSRDO(pdInstance) != 0U)
{
(void)PD_TimerStart(pdInstance, tSinkPPSPeriodicTimer, T_PPS_REQUEST);
}
#endif
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
PD_PsmSetAutoPolicyState(pdInstance, PSM_RDY_EVAL_INIT);
#endif
}
static inline void PD_PsmEnterSnkTransitionToDefaultState(pd_instance_t *pdInstance)
{
/* Message reception should not be re-enabled until PE_SNK_Startup */
PD_MsgReset(pdInstance);
pdInstance->psmExplicitContractExisted = 0u;
pdInstance->psmPresentlyPdConnected = 0;
pdInstance->curDataRole = kPD_DataRoleUFP;
pdInstance->psmPresentlyVconnSource = kPD_NotVconnSource;
(void)PD_PhyControl(pdInstance, PD_PHY_SET_MSG_HEADER_INFO, NULL);
#if defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
/* Request DPM to turn off vconn */
PD_DpmSetVconn(pdInstance, 0);
#endif
(void)PD_TimerStart(pdInstance, tNoResponseTimer, T_NO_RESPONSE);
if (PD_PsmCheckVsafe5V(pdInstance) != 0U)
{
pdInstance->psmHardResetNeedsVSafe0V = 1;
(void)PD_TimerStart(pdInstance, tPSHardResetTimer, T_PS_HARD_RESET + T_SAFE0V_MAX);
}
pdInstance->psmNewState = PSM_PE_SNK_STARTUP;
}
#endif
static pd_state_machine_state_t PD_PsmEnterState(pd_instance_t *pdInstance)
{
pd_psm_state_t prevState;
uint8_t didNothingC = 1;
pd_state_machine_state_t returnState = kSM_None;
while (pdInstance->psmNewState != pdInstance->psmCurState)
{
if (pdInstance->psmNewState == PE_PSM_STATE_ROLE_RDY_STATE)
{
if (pdInstance->curPowerRole == kPD_PowerRoleSource)
{
pdInstance->psmNewState = PSM_PE_SRC_READY;
}
else
{
pdInstance->psmNewState = PSM_PE_SNK_READY;
}
}
didNothingC = 0;
prevState = pdInstance->psmCurState;
pdInstance->psmCurState = pdInstance->psmNewState;
switch (pdInstance->psmCurState)
{
case PSM_EXIT_TO_ERROR_RECOVERY: /* (C) */
case PSM_EXIT_TO_ERROR_RECOVERY_WITH_DELAY: /* (C) */
if (pdInstance->psmCurState == PSM_EXIT_TO_ERROR_RECOVERY_WITH_DELAY)
{
/* Delay for 1ms to make sure any previous GoodCRC transmission has ended. */
(void)PD_PsmTimerWait(pdInstance, tDelayTimer, mSec(1), 0U);
}
returnState = kSM_ErrorRecovery;
break;
case PSM_UNKNOWN: /* (C) */
case PSM_IDLE: /* (C) */
pdInstance->psmNewState = PSM_IDLE;
pdInstance->psmCurState = PSM_IDLE;
PD_PsmEnterIdleState(pdInstance);
break;
case PSM_INTERRUPTED_REQUEST: /* (C) */
break;
case PSM_HARD_RESET: /* (C) */
PD_PsmEnterHardResetState(pdInstance);
break;
case PSM_SEND_SOFT_RESET: /* (C) */
PD_PsmEnterSendSoftResetState(pdInstance);
break;
case PSM_SOFT_RESET: /* (C) */
#if ((defined PD_CONFIG_EXTENDED_CHUNK_LAYER_SUPPORT) && (PD_CONFIG_EXTENDED_CHUNK_LAYER_SUPPORT))
PD_MsgChunkingLayerResetFlags(pdInstance);
#endif
/* Alert the DPM so it can reset it's state */
if (PD_PsmSendControlTransitionWithHardReset(
pdInstance, kPD_MsgAccept,
(pd_psm_state_t)((pdInstance->curPowerRole == kPD_PowerRoleSource) ?
PSM_PE_SRC_IMPLICIT_CABLE_DISCOVERY :
PSM_PE_SNK_WAIT_FOR_CAPABILITIES)) != 0U)
{
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SOFT_RESET_REQUEST, NULL, 1);
}
break;
#if (defined PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
case PSM_PE_SRC_STARTUP: /* (C) */
PD_PsmEnterSrcStartUpState(pdInstance);
break;
case PSM_PE_SRC_DISCOVERY: /* (C) */
#if (defined(PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)) && \
(defined(PD_CONFIG_SRC_AUTO_DISCOVER_CABLE_PLUG) && (PD_CONFIG_SRC_AUTO_DISCOVER_CABLE_PLUG))
/* cable plug didn't response data object on PE_SRC_STARTUP state */
if ((pdInstance->psmSecondaryState[1] == PSM_IDLE) &&
PD_CheckWhetherInitiateCableDiscoveryIdentityOrNot(pdInstance) != 0U)
{
pdInstance->pendingSOP =
(uint8_t)kPD_MsgSOPMask | (uint8_t)kPD_MsgSOPpMask | (uint8_t)kPD_MsgSOPppMask;
pdInstance->psmNewSecondaryState[1] = PSM_PE_SRC_VDM_IDENTITY_REQUEST;
}
#endif
pdInstance->psmPresentlyPdConnected = 0;
/* Do not clear previouslyPdConnected here */
(void)PD_TimerStart(pdInstance, tSourceCapabilityTimer, T_SEND_SOURCE_CAP);
break;
case PSM_PE_SRC_IMPLICIT_CABLE_DISCOVERY: /* (C) */
PD_PsmEnterImplicitCableDiscoveryState(pdInstance);
break;
case PSM_PE_SRC_SEND_CAPABILITIES: /* (C) */
PD_PsmEnterSrcSendCapsState(pdInstance);
break;
case PSM_PE_SRC_NEGOTIATE_CAPABILITY: /* (C) */
PD_PsmEnterSrcNegotiateCapState(pdInstance);
break;
case PSM_PE_SRC_TRANSITION_SUPPLY: /* (C) */
PD_PsmEnterSrcTransitionSupplyState(pdInstance);
break;
case PSM_PE_SRC_READY: /* (C) */
PD_PsmResetStateWhenEnterReadyState(pdInstance);
#if (defined PD_CONFIG_PD3_PPS_ENABLE) && (PD_CONFIG_PD3_PPS_ENABLE)
/* SourcePPSCommTimer */
if (PD_PsmSourceIsPPSRDO(pdInstance) != 0U)
{
(void)PD_TimerStart(pdInstance, tSourcePPSCommTimer, T_PPS_TIMEOUT);
}
#endif
break;
case PSM_PE_SRC_WAIT_NEW_CAPABILITIES: /* (C) */
break;
case PSM_PE_SRC_DISABLED: /* (C) */
(void)PD_PhyControl(pdInstance, PD_PHY_RESET_MSG_FUNCTION, NULL);
(void)PD_DpmAppCallback(pdInstance, PD_FUNCTION_DISABLED, NULL, 0);
break;
case PSM_PE_SRC_CAPABILITY_RESPONSE: /* (C) */
PD_PsmEnterSrcCapResponseState(pdInstance);
break;
case PSM_PE_SRC_HARD_RESET_RECEIVED: /* (C) */
break;
case PSM_PE_SRC_TRANSITION_TO_DEFAULT: /* (C) */
PD_PsmEnterSrcTransitionToDefaultState(pdInstance);
break;
case PSM_PE_SRC_GIVE_SOURCE_CAP: /* (C) */
#if defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
case PSM_PE_DR_SNK_GIVE_SOURCE_CAP: /* (C) */
#endif
PD_PsmEnterGiveSrcCapState(pdInstance);
break;
#endif
#if (defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)
case PSM_PE_SNK_STARTUP: /* (C) */
PD_PsmEnterSnkStartUpState(pdInstance);
break;
case PSM_PE_SNK_DISCOVERY: /* (C) */
break;
case PSM_PE_SNK_WAIT_FOR_CAPABILITIES: /* (C) */
(void)PD_PhyControl(pdInstance, PD_PHY_SET_MSG_HEADER_INFO, NULL);
pdInstance->pendingSOP = (uint8_t)kPD_MsgSOPMask;
PD_MsgStartReceive(pdInstance);
(void)PD_TimerStart(pdInstance, tSinkWaitCapTimer, T_SINK_WAIT_CAP);
break;
case PSM_PE_SNK_EVALUATE_CAPABILITY: /* (C) */
PD_PsmEnterSnkEvaluateCapState(pdInstance);
break;
case PSM_PE_SNK_SELECT_CAPABILITY: /* (C) */
if (PD_MsgSendDataTransition(
pdInstance, kPD_MsgRequest, 1, (void *)(&pdInstance->rdoRequest), PE_PSM_STATE_NO_CHANGE,
(prevState == PSM_PE_SNK_READY ? prevState : PSM_CHECK_ASYNC_RX), PSM_SEND_SOFT_RESET) != 0U)
{
(void)PD_TimerStart(pdInstance, tSenderResponseTimer, T_SENDER_RESPONSE);
}
break;
case PSM_PE_SNK_SELECT_CAPABILITY_WAIT_TIMER_TIME_OUT: /* (C) */
break;
case PSM_PE_SNK_TRANSITION_SINK: /* (C) */
(void)PD_TimerStart(pdInstance, tPSTransitionTimer, T_PS_TRANSITION);
if (pdInstance->psmGotoMinRx != 0U)
{
(void)pdInstance->callbackFns->PD_SnkGotoMinReducePower(pdInstance->callbackParam);
}
else
{
/* Start ignoring droops on VBus */
/* Source starts to change its power capability tSrcTransition after the GoodCRC Message was
received, so it is safe to change the power progress here. */
PD_ConnectSetPowerProgress(pdInstance, kVbusPower_ChangeInProgress);
/* Reduce power comsumption to pSnkStdby. */
(void)pdInstance->callbackFns->PD_SnkDrawTypeCVbus(pdInstance->callbackParam, 0,
kVbusPower_ChangeInProgress);
}
break;
case PSM_PE_SNK_READY: /* (C) */
PD_PsmEnterSnkReadyState(pdInstance);
break;
case PSM_PE_SNK_TRANSITION_TO_DEFAULT: /* (C) */
PD_PsmEnterSnkTransitionToDefaultState(pdInstance);
break;
#endif
#if (defined PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
case PSM_PE_SRC_GET_SINK_CAP: /* (C) */
#endif
#if defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
case PSM_PE_DR_SNK_GET_SINK_CAP: /* (C) */
case PSM_PE_DR_SRC_GET_SOURCE_CAP: /* (C) */
#endif
#if (defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)
case PSM_PE_SNK_GET_SOURCE_CAP: /* (C) */
#endif
PD_PsmEnterGetSinkOrSourceCapState(pdInstance, prevState);
break;
#if (defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)) || \
((defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE))
case PSM_PE_DR_SRC_GIVE_SINK_CAP: /* (C) */
case PSM_PE_SNK_GIVE_SINK_CAP: /* (C) */
PD_PsmEnterGiveSinkCapState(pdInstance);
break;
#endif
#if defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
case PSM_PE_PRS_SRC_SNK_EVALUATE_PR_SWAP: /* (C) */
{
pd_dpm_callback_event_t requestEvent = PD_DPM_PR_SWAP_REQUEST;
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
PD_PsmSetAutoPolicyState(pdInstance, PSM_RDY_EVAL_INIT);
if (PD_POLICY_SUPPORT(pdInstance) && (PD_POLICY_GET_AUTO_ACCEPT_PRSWAP_AS_SOURCE_SUPPORT(pdInstance)))
{
if (pdInstance->swapToSnkSrcCapReceived != 0U)
{
pd_source_pdo_t pdo;
pdInstance->swapToSnkSrcCapReceived = 0;
pdo.PDOValue = pdInstance->pdPowerPortConfig->sourceCaps[0];
if ((pdo.fixedPDO.externalPowered != 0U) &&
(pdInstance->partnerSourcePDOs[0].fixedPDO.externalPowered == 0U))
{
requestEvent = PD_DPM_EVENT_INVALID;
pdInstance->commandEvaluateResult = kCommandResult_Reject;
}
}
if (requestEvent != PD_DPM_EVENT_INVALID)
{
pdInstance->commandEvaluateResult =
(pd_command_result_t)PD_POLICY_GET_AUTO_ACCEPT_PRSWAP_AS_SOURCE(pdInstance);
requestEvent = PD_DPM_EVENT_INVALID;
}
}
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY_LOG) && (PD_CONFIG_ENABLE_AUTO_POLICY_LOG)
if (requestEvent == PD_DPM_EVENT_INVALID)
{
PD_PsmPrintAutoPolicyReplySwapRequestLog(pdInstance, (uint8_t)kPD_MsgPrSwap);
}
#endif
#endif
PD_PsmEvaluateSwap(pdInstance, requestEvent, PSM_PE_PRS_SRC_SNK_ACCEPT_PR_SWAP,
PSM_PE_PRS_SRC_SNK_REJECT_PR_SWAP);
break;
}
case PSM_PE_PRS_SNK_SRC_EVALUATE_PR_SWAP: /* (C) */
{
pd_dpm_callback_event_t requestEvent = PD_DPM_PR_SWAP_REQUEST;
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
PD_PsmSetAutoPolicyState(pdInstance, PSM_RDY_EVAL_INIT);
if (PD_POLICY_SUPPORT(pdInstance) && (PD_POLICY_GET_AUTO_ACCEPT_PRSWAP_AS_SINK_SUPPORT(pdInstance)))
{
requestEvent = PD_DPM_EVENT_INVALID;
if ((PD_POLICY_GET_AUTO_ACCEPT_PRSWAP_AS_SINK(pdInstance) == (uint8_t)kAutoRequestProcess_Accept) &&
((PD_PsmGetExternalPowerState(pdInstance) != 0U) ||
(pdInstance->selfOrPartnerFirstSourcePDO.fixedPDO.externalPowered == 0U)))
{
pdInstance->commandEvaluateResult = kCommandResult_Accept;
}
else
{
pdInstance->commandEvaluateResult = kCommandResult_Reject;
}
}
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY_LOG) && (PD_CONFIG_ENABLE_AUTO_POLICY_LOG)
if (requestEvent == PD_DPM_EVENT_INVALID)
{
PD_PsmPrintAutoPolicyReplySwapRequestLog(pdInstance, (uint8_t)kPD_MsgPrSwap);
}
#endif
#endif
PD_PsmEvaluateSwap(pdInstance, requestEvent, PSM_PE_PRS_SNK_SRC_ACCEPT_PR_SWAP,
PSM_PE_PRS_SNK_SRC_REJECT_PR_SWAP);
break;
}
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
case PE_FRS_SRC_SNK_Evaluate_Swap: /* C */
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
PD_PsmSetAutoPolicyState(pdInstance, PSM_RDY_EVAL_INIT);
#endif
PD_PsmEvaluateSwap(pdInstance, PD_DPM_FR_SWAP_REQUEST, PE_FRS_SRC_SNK_Accept_Swap, PSM_HARD_RESET);
break;
#endif
case PSM_PE_PRS_SRC_SNK_ACCEPT_PR_SWAP: /* (C) */
(void)PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(pdInstance, kPD_MsgAccept,
PSM_PE_PRS_SRC_SNK_TRANSITION_TO_OFF);
break;
case PSM_PE_PRS_SNK_SRC_ACCEPT_PR_SWAP: /* (C) */
(void)PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(pdInstance, kPD_MsgAccept,
PSM_PE_PRS_SNK_SRC_TRANSITION_TO_OFF);
break;
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
case PE_FRS_SRC_SNK_Accept_Swap: /* C */
(void)PD_PsmSendControlTransitionWithTry(pdInstance, kPD_MsgAccept, PE_FRS_SRC_SNK_Transition_to_off,
PSM_HARD_RESET, PSM_HARD_RESET);
break;
#endif
case PSM_PE_PRS_SRC_SNK_TRANSITION_TO_OFF: /* (C) */
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
if (pdInstance->frsEnabled != 0U)
{
PD_FRSControl(pdInstance, 0);
pdInstance->frsEnabled = 0;
}
#endif
PD_ConnectSetPowerProgress(pdInstance, kVbusPower_InPRSwap);
/* pr swap transition to standby */
/* 1. tSrcTransition */
(void)PD_PsmTimerWait(pdInstance, tDelayTimer, T_SRC_TRANSITION, PD_TASK_EVENT_RECEIVED_HARD_RESET);
/* 2. start enter to standby tSrcSwapStdby */
(void)pdInstance->callbackFns->PD_SrcTurnOffVbus(pdInstance->callbackParam, kVbusPower_InPRSwap);
PD_DpmDischargeVbus(pdInstance, 1);
break;
case PSM_PE_PRS_SNK_SRC_TRANSITION_TO_OFF: /* (C) */
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
if (pdInstance->frsEnabled != 0U)
{
PD_FRSControl(pdInstance, 0);
pdInstance->frsEnabled = 0;
}
#endif
pdInstance->psmExplicitContractExisted = 0;
(void)PD_TimerStart(pdInstance, tPSSourceOffTimer, T_PS_SOURCE_OFF);
PD_ConnectSetPowerProgress(pdInstance, kVbusPower_InPRSwap);
/* sink transition to standby. */
(void)pdInstance->callbackFns->PD_SnkStopDrawVbus(pdInstance->callbackParam, kVbusPower_InPRSwap);
break;
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
case PE_FRS_SNK_SRC_Transition_to_off: /* C */
/* uint8_t enable = 0; */
/* (void)PD_PhyControl(pdInstance, PD_PHY_CONTROL_FR_SWAP, &enable); */
(void)PD_TimerStart(pdInstance, tPSSourceOffTimer, T_PS_SOURCE_OFF);
break;
case PE_FRS_SRC_SNK_Transition_to_off: /* C */
PD_FRSControl(pdInstance, 0);
pdInstance->frsEnabled = 0;
(void)PD_TimerStart(pdInstance, timrFRSwapWaitPowerStable, T_FRSWAP_WAIT_POWER_STABLE);
break;
#endif
case PSM_PE_PRS_SRC_SNK_ASSERT_RD: /* (C) */
PD_PsmPowerSwapAssertRdRp(pdInstance, kPD_PowerRoleSink, PSM_PE_PRS_SRC_SNK_WAIT_SOURCE_ON);
break;
case PSM_PE_PRS_SNK_SRC_ASSERT_RP: /* (C) */
PD_PsmPowerSwapAssertRdRp(pdInstance, kPD_PowerRoleSource, PSM_PE_PRS_SNK_SRC_SOURCE_ON);
break;
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
case PE_FRS_SRC_SNK_Assert_Rd: /* C */
PD_PsmPowerSwapAssertRdRp(pdInstance, kPD_PowerRoleSink, PE_FRS_SRC_SNK_Wait_Source_on);
break;
case PE_FRS_SNK_SRC_Assert_Rp: /* C */
PD_PsmPowerSwapAssertRdRp(pdInstance, kPD_PowerRoleSource, PE_FRS_SNK_SRC_Source_on);
break;
#endif
case PSM_PE_PRS_SRC_SNK_WAIT_SOURCE_ON: /* (C) */
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
case PE_FRS_SRC_SNK_Wait_Source_on: /* C */
#endif
/* 0 Role stays as standby until we receive the PS_RDY message */
(void)PD_PhyControl(pdInstance, PD_PHY_SET_MSG_HEADER_INFO, NULL);
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
if (PE_FRS_SRC_SNK_Wait_Source_on == pdInstance->psmCurState)
{
if (PD_PsmSendControlTransitionWithTry(pdInstance, kPD_MsgPsRdy, PE_FRS_SRC_SNK_Wait_Source_on,
PSM_EXIT_TO_ERROR_RECOVERY_WITH_DELAY,
PSM_EXIT_TO_ERROR_RECOVERY_WITH_DELAY) != 0U)
{
(void)PD_TimerStart(pdInstance, tPSSourceOnTimer, T_PS_SOURCE_ON);
}
}
else
#endif
{
if (PD_PsmSendControlTransitionWithErrorRecovery(pdInstance, kPD_MsgPsRdy,
PE_PSM_STATE_NO_CHANGE) != 0U)
{
(void)PD_TimerStart(pdInstance, tPSSourceOnTimer, T_PS_SOURCE_ON);
}
}
break;
case PSM_PE_PRS_SNK_SRC_SOURCE_ON: /* (C) */
(void)pdInstance->callbackFns->PD_SrcTurnOnTypeCVbus(pdInstance->callbackParam, kVbusPower_InPRSwap);
break;
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
case PE_FRS_SNK_SRC_Source_on: /* C */
PD_PsmPowerSwapSinkOpenVbus(pdInstance, PD_DPM_FR_SWAP_SUCCESS);
break;
#endif
case PSM_PE_PRS_SRC_SNK_SEND_PR_SWAP: /* (C) */
case PSM_PE_PRS_SNK_SRC_SEND_PR_SWAP: /* (C) */
(void)PD_PsmSendControlTransitionWithSendResponserTimeOut(
pdInstance, kPD_MsgPrSwap, PE_PSM_STATE_NO_CHANGE, prevState, PSM_SEND_SOFT_RESET);
break;
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
case PE_FRS_SNK_SRC_Send_Swap: /* C */
pdInstance->fr5VOpened = 0;
PD_FRSControl(pdInstance, 0);
pdInstance->frsEnabled = 0;
PD_PsmCheckFRS5V(pdInstance);
if (PD_PsmSendControlTransitionWithSendResponserTimeOut(
pdInstance, kPD_MsgFrSwap, PE_PSM_STATE_NO_CHANGE, PSM_EXIT_TO_ERROR_RECOVERY_WITH_DELAY,
PSM_EXIT_TO_ERROR_RECOVERY_WITH_DELAY) != 0U)
{
(void)PD_PsmStartCommand(pdInstance, PD_DPM_FAST_ROLE_SWAP, 0);
}
else
{
pdInstance->psmNewState = PSM_EXIT_TO_ERROR_RECOVERY_WITH_DELAY;
}
break;
#endif
case PSM_PE_PRS_SRC_SNK_REJECT_PR_SWAP: /* (C) */
case PSM_PE_PRS_SNK_SRC_REJECT_PR_SWAP: /* (C) */
{
pd_command_result_t callbackResult = kCommandResult_Reject;
(void)PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(
pdInstance,
((pdInstance->commandEvaluateResult == kCommandResult_Reject) ? kPD_MsgReject : kPD_MsgWait),
PE_PSM_STATE_ROLE_RDY_STATE);
(void)PD_DpmAppCallback(pdInstance, PD_DPM_PR_SWAP_FAIL, &callbackResult, 1);
break;
}
#endif
#if defined(PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
case PSM_PE_DRS_EVALUATE_DR_SWAP: /* (C) */
{
pd_dpm_callback_event_t requestEvent = PD_DPM_DR_SWAP_REQUEST;
pdInstance->psmDrSwapPrevState = prevState;
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
PD_PsmSetAutoPolicyState(pdInstance, PSM_RDY_EVAL_INIT);
if (PD_POLICY_SUPPORT(pdInstance) && (((pdInstance->curDataRole == kPD_DataRoleUFP) &&
PD_POLICY_GET_AUTO_ACCEPT_DRSWAP_AS_DFP_SUPPORT(pdInstance)) ||
((pdInstance->curDataRole == kPD_DataRoleDFP) &&
PD_POLICY_GET_AUTO_ACCEPT_DRSWAP_AS_UFP_SUPPORT(pdInstance))))
{
if (pdInstance->curDataRole == kPD_DataRoleUFP)
{
pdInstance->commandEvaluateResult =
(pd_command_result_t)PD_POLICY_GET_AUTO_ACCEPT_DRSWAP_AS_DFP(pdInstance);
}
else
{
pdInstance->commandEvaluateResult =
(pd_command_result_t)PD_POLICY_GET_AUTO_ACCEPT_DRSWAP_AS_UFP(pdInstance);
}
requestEvent = PD_DPM_EVENT_INVALID;
}
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY_LOG) && (PD_CONFIG_ENABLE_AUTO_POLICY_LOG)
if (requestEvent == PD_DPM_EVENT_INVALID)
{
PD_PsmPrintAutoPolicyReplySwapRequestLog(pdInstance, (uint8_t)kPD_MsgDrSwap);
}
#endif
#endif
PD_PsmEvaluateSwap(pdInstance, requestEvent, PSM_PE_DRS_ACCEPT_DR_SWAP, PSM_PE_DRS_REJECT_DR_SWAP);
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
pdInstance->drSwapResult = pdInstance->commandEvaluateResult;
#endif
break;
}
case PSM_PE_DRS_EVALUATE_DR_SWAP_WAIT_TIMER_TIME_OUT: /* (C) */
case PSM_PE_PRS_EVALUATE_PR_SWAP_WAIT_TIMER_TIME_OUT: /* (C) */
break;
case PSM_PE_DRS_REJECT_DR_SWAP: /* (C) */
{
(void)PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(
pdInstance,
((pdInstance->commandEvaluateResult == kCommandResult_Reject) ? kPD_MsgReject : kPD_MsgWait),
(pd_psm_state_t)pdInstance->psmDrSwapPrevState);
if (pdInstance->commandEvaluateResult != kCommandResult_Reject)
{
pdInstance->commandEvaluateResult = kCommandResult_Wait;
}
(void)PD_DpmAppCallback(pdInstance, PD_DPM_DR_SWAP_FAIL, &pdInstance->commandEvaluateResult, 1);
break;
}
case PSM_PE_DRS_SEND_DR_SWAP: /* (C) */
pdInstance->psmDrSwapPrevState = prevState; /* snk_rdy or src_rdy */
(void)PD_PsmSendControlTransitionWithSendResponserTimeOut(
pdInstance, kPD_MsgDrSwap, PE_PSM_STATE_NO_CHANGE, prevState, PSM_SEND_SOFT_RESET);
break;
case PSM_PE_DRS_ACCEPT_DR_SWAP: /* (C) */
{
(void)PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(pdInstance, kPD_MsgAccept,
PSM_PE_DRS_CHANGE_TO_DFP_OR_UFP);
if (pdInstance->psmNewState == PSM_PE_DRS_CHANGE_TO_DFP_OR_UFP)
{
pdInstance->curDataRole =
(pdInstance->curDataRole == kPD_DataRoleUFP) ? kPD_DataRoleDFP : kPD_DataRoleUFP;
(void)PD_PhyControl(pdInstance, PD_PHY_SET_MSG_HEADER_INFO, NULL);
}
break;
}
case PSM_PE_DRS_CHANGE_TO_DFP_OR_UFP: /* (C) */
{
/* Exit any active alternate mode */
pdInstance->pendingSOP = (uint8_t)kPD_MsgSOPMask;
if (pdInstance->curDataRole == kPD_DataRoleDFP)
{
(void)PD_DpmAppCallback(pdInstance, PD_DPM_DR_SWAP_SUCCESS, NULL, 1);
#if 0 /* even do the cable discovery identity, but cannot do SOP'/SOP'' communication after negotiation done */
#if (defined PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
pdInstance->pendingSOP = (uint8_t)kPD_MsgSOPMask | (uint8_t)kPD_MsgSOPpMask | (uint8_t)kPD_MsgSOPppMask;
#endif
#endif
}
else
{
(void)PD_DpmAppCallback(pdInstance, PD_DPM_DR_SWAP_SUCCESS, NULL, 1);
}
/* Raise the interrupt */
if ((pdInstance->curDataRole == kPD_DataRoleDFP) || (pdInstance->curPowerRole == kPD_PowerRoleSource))
{
#if defined(PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
/* Cable plug will need a soft reset */
pdInstance->psmCablePlugResetNeeded = 1;
#endif
}
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
pdInstance->drSwapResult = kCommandResult_Accept;
PD_PsmSetAutoPolicyState(pdInstance, PSM_RDY_EVAL_INIT);
#endif
/* return to previous state */
pdInstance->psmNewState = pdInstance->psmDrSwapPrevState;
break;
}
#endif
#if defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
case PSM_PE_VCS_SEND_SWAP: /* (C) */
pdInstance->psmVconnSwapPrevState = prevState;
(void)PD_PsmSendControlTransitionWithSendResponserTimeOut(
pdInstance, kPD_MsgVconnSwap, PE_PSM_STATE_NO_CHANGE, pdInstance->psmVconnSwapPrevState,
PSM_SEND_SOFT_RESET);
break;
case PSM_PE_VCS_WAIT_FOR_VCONN: /* (C) */
(void)PD_TimerStart(pdInstance, tVconnOnTimer, T_VCONN_SOURCE_ON);
break;
case PSM_PE_VCS_TURN_OFF_VCONN: /* (C) */
pdInstance->psmPresentlyVconnSource = kPD_NotVconnSource;
#if (defined PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
pdInstance->cableDiscoverIdentityCounter = 0;
#endif
/* Inform the DPM */
PD_DpmSetVconn(pdInstance, 0);
(void)PD_DpmAppCallback(pdInstance, PD_DPM_VCONN_SWAP_SUCCESS, NULL, 1);
/* return to previous state */
pdInstance->psmNewState = pdInstance->psmVconnSwapPrevState;
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
pdInstance->vconnSwapResult = kCommandResult_Accept;
PD_PsmSetAutoPolicyState(pdInstance, PSM_RDY_EVAL_INIT);
#endif
break;
case PSM_PE_VCS_TURN_ON_VCONN: /* (C) */
pdInstance->psmPresentlyVconnSource = kPD_IsVconnSource;
/* Inform the DPM */
PD_DpmSetVconn(pdInstance, 1);
(void)PD_TimerStart(pdInstance, tVconnOnTimer, T_VCONN_SOURCE_ON / 2);
break;
case PSM_PE_VCS_SEND_PS_RDY: /* (C) */
if (PD_MsgSendControlTransition(pdInstance, kPD_MsgPsRdy, pdInstance->psmVconnSwapPrevState,
PSM_SEND_SOFT_RESET, PSM_SEND_SOFT_RESET) != 0U)
{
#if (defined PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
pdInstance->cableDiscoverIdentityCounter = 0;
#endif
(void)PD_DpmAppCallback(pdInstance, PD_DPM_VCONN_SWAP_SUCCESS, NULL, 1);
}
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
pdInstance->vconnSwapResult = kCommandResult_Accept;
PD_PsmSetAutoPolicyState(pdInstance, PSM_RDY_EVAL_INIT);
#endif
break;
case PSM_PE_VCS_EVALUATE_SWAP: /* (C) */
{
pd_dpm_callback_event_t requestEvent = PD_DPM_VCONN_SWAP_REQUEST;
pdInstance->psmVconnSwapPrevState = prevState;
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
PD_PsmSetAutoPolicyState(pdInstance, PSM_RDY_EVAL_INIT);
if (PD_POLICY_SUPPORT(pdInstance) &&
(((pdInstance->psmPresentlyVconnSource == kPD_NotVconnSource) &&
PD_POLICY_GET_AUTO_ACCEPT_VCONNSWAP_TURN_ON_SUPPORT(pdInstance)) ||
((pdInstance->psmPresentlyVconnSource == kPD_IsVconnSource) &&
PD_POLICY_GET_AUTO_ACCEPT_VCONNSWAP_TURN_OFF_SUPPORT(pdInstance))))
{
if (pdInstance->psmPresentlyVconnSource == kPD_NotVconnSource)
{
pdInstance->commandEvaluateResult =
(pd_command_result_t)PD_POLICY_GET_AUTO_ACCEPT_VCONNSWAP_TURN_ON(pdInstance);
}
else
{
pdInstance->commandEvaluateResult =
(pd_command_result_t)PD_POLICY_GET_AUTO_ACCEPT_VCONNSWAP_TURN_OFF(pdInstance);
}
requestEvent = PD_DPM_EVENT_INVALID;
}
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY_LOG) && (PD_CONFIG_ENABLE_AUTO_POLICY_LOG)
if (requestEvent == PD_DPM_EVENT_INVALID)
{
PD_PsmPrintAutoPolicyReplySwapRequestLog(pdInstance, (uint8_t)kPD_MsgVconnSwap);
}
#endif
#endif /* PD_CONFIG_ENABLE_AUTO_POLICY */
PD_PsmEvaluateSwap(pdInstance, requestEvent, PSM_PE_VCS_ACCEPT_SWAP, PSM_PE_VCS_REJECT_SWAP);
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
pdInstance->vconnSwapResult = pdInstance->commandEvaluateResult;
#endif
break;
}
case PSM_PE_VCS_ACCEPT_SWAP: /* (C) */
(void)PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(
pdInstance, kPD_MsgAccept,
(pdInstance->psmPresentlyVconnSource == kPD_IsVconnSource) ? PSM_PE_VCS_WAIT_FOR_VCONN :
PSM_PE_VCS_TURN_ON_VCONN);
break;
case PSM_PE_VCS_REJECT_SWAP: /* (C) */
(void)PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(
pdInstance,
(pdInstance->commandEvaluateResult == kCommandResult_Reject) ? kPD_MsgReject : kPD_MsgWait,
(pd_psm_state_t)pdInstance->psmVconnSwapPrevState);
if (pdInstance->commandEvaluateResult != kCommandResult_Reject)
{
pdInstance->commandEvaluateResult = kCommandResult_Wait;
}
(void)PD_DpmAppCallback(pdInstance, PD_DPM_VCONN_SWAP_FAIL, &pdInstance->commandEvaluateResult, 1);
break;
#endif /* PD_CONFIG_VCONN_SUPPORT */
#if defined(PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
case PE_SNK_GET_SOURCE_CAP_EXT: /* C */
case PE_DR_SRC_GET_SOURCE_CAP_EXT: /* C */
(void)PD_PsmSendControlTransitionWithSendResponserTimeOut(
pdInstance, kPD_MsgGetSourceCapExtended, PE_PSM_STATE_NO_CHANGE, prevState, PSM_SEND_SOFT_RESET);
break;
case PE_SRC_Get_Sink_Status: /* C */
case PE_SNK_Get_Source_Status: /* C */
(void)PD_PsmSendControlTransitionWithSendResponserTimeOut(
pdInstance, kPD_MsgGetStatus, PE_PSM_STATE_NO_CHANGE, prevState, PSM_SEND_SOFT_RESET);
break;
#if defined(PD_CONFIG_PD3_PPS_ENABLE) && (PD_CONFIG_PD3_PPS_ENABLE)
case PE_SNK_Get_PPS_Status: /* C */
(void)PD_PsmSendControlTransitionWithSendResponserTimeOut(
pdInstance, kPD_MsgGetPpsStatus, PE_PSM_STATE_NO_CHANGE, prevState, PSM_SEND_SOFT_RESET);
break;
#endif
case PE_Get_Battery_Cap: /* C */
case PE_Get_Battery_Status: /* C */
if (PD_MsgSendExtTransition(pdInstance, kPD_MsgSOP,
(PE_Get_Battery_Cap == pdInstance->psmCurState) ? kPD_MsgGetBatteryCap :
kPD_MsgGetBatteryStatus,
1, &pdInstance->getBatteryCapDataBlock, PE_PSM_STATE_NO_CHANGE, prevState,
PSM_SEND_SOFT_RESET) != 0U)
{
(void)PD_TimerStart(pdInstance, tSenderResponseTimer, T_SENDER_RESPONSE);
}
break;
case PE_Get_Manufacturer_Info: /* C */
if (PD_MsgSendExtTransition(pdInstance, (start_of_packet_t)pdInstance->commandExtParam.sop,
kPD_MsgGetManufacturerInfo, 2, pdInstance->commandExtParam.dataBuffer,
PE_PSM_STATE_NO_CHANGE, prevState, PSM_SEND_SOFT_RESET) != 0U)
{
(void)PD_TimerStart(pdInstance, tSenderResponseTimer, T_SENDER_RESPONSE);
}
break;
case PE_SRC_Send_Source_Alert: /* C */
case PE_SNK_Send_Sink_Alert: /* C */
if (PD_MsgSendDataTransition(pdInstance, kPD_MsgAlert, 1, &pdInstance->alertADO,
PE_PSM_STATE_ROLE_RDY_STATE, prevState, PSM_SEND_SOFT_RESET) != 0U)
{
pdInstance->alertWaitReply = 1u;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SEND_ALERT_SUCCESS, NULL, 1);
}
else
{
pd_command_result_t errorResult = kCommandResult_Error;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SEND_ALERT_FAIL, &errorResult, 1);
}
break;
case PE_SRC_GIVE_SOURCE_CAP_EXT: /* C */
case PE_DR_SNK_GIVE_SOURCE_CAP_EXT: /* C */
pdInstance->commandExtParamCallback.resultStatus = (uint8_t)kCommandResult_NotSupported;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_GIVE_SRC_EXT_CAP, &pdInstance->commandExtParamCallback, 0);
PD_StateSendReplyExtDataTransition(pdInstance, kPD_MsgSourceCapExtended);
break;
case PE_SRC_Give_Source_Status: /* C */
case PE_SNK_Give_Sink_Status: /* C */
pdInstance->commandExtParamCallback.resultStatus = (uint8_t)kCommandResult_NotSupported;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_GIVE_STATUS, &pdInstance->commandExtParamCallback, 0);
PD_StateSendReplyExtDataTransition(pdInstance, kPD_MsgStatus);
break;
#if (defined PD_CONFIG_PD3_PPS_ENABLE) && (PD_CONFIG_PD3_PPS_ENABLE)
case PE_SRC_Give_PPS_Status: /* C */
pdInstance->commandExtParamCallback.resultStatus = (uint8_t)kCommandResult_NotSupported;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_GIVE_PPS_STATUS, &pdInstance->commandExtParamCallback, 0);
PD_StateSendReplyExtDataTransition(pdInstance, kPD_MsgPpsStatus);
break;
#endif
case PE_Give_Battery_Cap: /* C */
pdInstance->commandExtParamCallback.resultStatus = (uint8_t)kCommandResult_NotSupported;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_GIVE_BATTERY_CAP, &pdInstance->commandExtParamCallback, 0);
PD_StateSendReplyExtDataTransition(pdInstance, kPD_MsgBatteryCapabilities);
break;
case PE_Give_Battery_Status: /* C */
pdInstance->commandExtParamCallback.resultStatus = (uint8_t)kCommandResult_NotSupported;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_GIVE_BATTERY_STATUS, &pdInstance->commandExtParamCallback,
0);
PD_StateSendReplyExtDataTransition(pdInstance, kPD_MsgBatteryStatus);
break;
case PE_Give_Manufacturer_Info: /* C */
pdInstance->commandExtParamCallback.resultStatus = (uint8_t)kCommandResult_NotSupported;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_GIVE_MANUFACTURER_INFO, &pdInstance->commandExtParamCallback,
0);
PD_StateSendReplyExtDataTransition(pdInstance, kPD_MsgManufacturerInfo);
break;
case PE_SNK_Source_Alert_Received: /* C */
case PE_SRC_Sink_Alert_Received: /* C */
pdInstance->psmNewState = PE_PSM_STATE_ROLE_RDY_STATE;
break;
#if 0
case PE_Send_Security_Request: /* C */
{
pd_status_t sendStatus = kStatus_PD_Error;
/* even this msg is chunked, it only needs one chunk. */
if (!pdInstance->unchunkedFeature != 0U)
{
sendStatus = PD_PsmChunkingLayerTXStateMachine(pdInstance,
kPD_MsgSOP, kPD_MsgSecurityRequest,
pdInstance->commandExtParam.dataBuffer,
pdInstance->commandExtParam.dataLength, NULL);
if (sendStatus != kStatus_PD_Success)
{
uint8_t inCase32Tmp = kCommandResult_Error;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SECURITY_REQUEST_FAIL, &inCase32Tmp, 1);
PD_PsmTransitionOnMsgSendError(pdInstance, prevState, PSM_SEND_SOFT_RESET);
}
else
{
pdInstance->psmNewState = PE_PSM_STATE_ROLE_RDY_STATE;
}
}
else
{
if (PD_MsgSendExtTransition(pdInstance, (start_of_packet_t)pdInstance->commandExtParam.sop,
kPD_MsgSecurityRequest, pdInstance->commandExtParam.dataLength,
pdInstance->commandExtParam.dataBuffer, PE_PSM_STATE_ROLE_RDY_STATE,
prevState, PSM_SEND_SOFT_RESET) == 0U)
{
uint8_t inCase32Tmp = kCommandResult_Error;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SECURITY_REQUEST_FAIL, &inCase32Tmp, 1);
}
}
break;
}
case PE_Send_Security_Response: /* C */
{
pd_status_t sendStatus = kStatus_PD_Error;
/* first time */
(void)PD_DpmAppCallback(pdInstance, PD_DPM_RESPONSE_SECURITY_REQUEST, &pdInstance->commandExtParamCallback,
0);
if ((pdInstance->commandExtParamCallback.resultStatus != (uint8_t)kCommandResult_NotSupported) &&
(pdInstance->unchunkedFeature == 0U))
{
sendStatus = PD_PsmChunkingLayerTXStateMachine(pdInstance,
kPD_MsgSOP, kPD_MsgSecurityResponse,
pdInstance->commandExtParamCallback.dataBuffer,
pdInstance->commandExtParamCallback.dataLength, NULL);
if (sendStatus != kStatus_PD_Success)
{
PD_PsmTransitionOnMsgSendError(pdInstance, PSM_CHECK_ASYNC_RX, PSM_SEND_SOFT_RESET);
}
else
{
if (PD_PsmChunkingLayerCheckSentDone(pdInstance))
{
pdInstance->psmNewState = PE_PSM_STATE_ROLE_RDY_STATE;
}
else
{
/* wait chunk message sent done */
}
}
}
else
{
if ((pdInstance->commandExtParamCallback.resultStatus != (uint8_t)kCommandResult_NotSupported) &&
(pdInstance->unchunkedFeature != 0U))
{
PD_MsgSendExtTransition(pdInstance, (start_of_packet_t)pdInstance->commandExtParam.sop,
kPD_MsgSecurityResponse, pdInstance->commandExtParamCallback.dataLength,
pdInstance->commandExtParamCallback.dataBuffer, PE_PSM_STATE_ROLE_RDY_STATE,
PSM_CHECK_ASYNC_RX, PSM_SEND_SOFT_RESET);
}
else if (pdInstance->commandExtParamCallback.resultStatus == (uint8_t)kCommandResult_NotSupported)
{
(void)PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(pdInstance, kPD_MsgNotSupported,
PE_PSM_STATE_ROLE_RDY_STATE);
}
else
{
/* No action required. */
}
}
break;
}
case PE_Security_Response_Received: /* C */
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SECURITY_RESPONSE_RECEIVED, &pdInstance->commandExtParamCallback, 0);
pdInstance->psmNewState = PE_PSM_STATE_ROLE_RDY_STATE;
break;
#endif
#endif /* PD_CONFIG_EXTENDED_MSG_SUPPORT */
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
case PE_FRS_SRC_SNK_CC_Signal: /* C */
{
PD_MsgReceive(pdInstance);
(void)PD_TimerStart(pdInstance, tFRSwapSignalTimer, 500);
break;
}
case PE_FRS_SNK_SRC_Vbus_Applied: /* C */
break;
#endif
case PSM_PE_BIST_TEST_DATA_MODE: /* (C) */
break;
case PSM_PE_BIST_CARRIER_MODE_2: /* (C) */
{
#if (defined PD_CONFIG_COMPLIANCE_TEST_ENABLE) && (PD_CONFIG_COMPLIANCE_TEST_ENABLE)
pd_bist_mst_t bistMode = kBIST_CarrierMode2;
(void)PD_TimerStart(pdInstance, tBISTContModeTimer, T_BIST_CONT_MODE);
/* Delay for 1ms to make sure any previous GoodCRC tranmission has ended. */
(void)PD_PsmTimerWait(pdInstance, tDelayTimer, mSec(1), 0U);
(void)PD_PhyControl(pdInstance, PD_PHY_ENTER_BIST, &bistMode);
#endif
break;
}
case PSM_CHECK_ASYNC_RX: /* (C) */
break;
case PSM_BYPASS: /* (C) */
break;
default:
/* No action required. */
break;
}
if (returnState != kSM_None)
{
return returnState;
}
PD_PsmEndCommand(pdInstance);
PD_PsmSetNormalPower(pdInstance);
}
PD_PsmProcessImportEventBeforeNextStateMachine(pdInstance);
if (didNothingC == 1U)
{
return kSM_WaitEvent;
}
else
{
return kSM_Continue;
}
}
static pd_state_machine_state_t PD_PsmGetNewestEvent(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo)
{
uint32_t taskEventSet = 0;
uint8_t processMessage;
(void)OSA_EventGet(pdInstance->taskEventHandle, PD_TASK_EVENT_ALL, &taskEventSet);
if ((taskEventSet & (uint32_t)PD_TASK_EVENT_TIME_OUT) != 0U)
{
(void)OSA_EventClear(pdInstance->taskEventHandle, PD_TASK_EVENT_TIME_OUT);
#if ((defined PD_CONFIG_EXTENDED_CHUNK_LAYER_SUPPORT) && (PD_CONFIG_EXTENDED_CHUNK_LAYER_SUPPORT))
if (PD_PsmChunkingLayerRXTimerWaiting(pdInstance) != 0U)
{
(void)PD_PsmChunkingLayerRXStateMachine(pdInstance, triggerInfo);
}
#endif
#if (defined(PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)) && \
(defined(PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE) && (PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE))
if ((PD_TimerCheckInvalidOrTimeOut(pdInstance, tDpmComandRetryTimer) != 0U) &&
(pdInstance->commandRetryCount > 0U))
{
PD_StackSetEvent(pdInstance, PD_TASK_EVENT_DPM_MSG);
return kSM_Continue;
}
#endif
}
else if ((taskEventSet & (uint32_t)PD_TASK_EVENT_RECEIVED_HARD_RESET) != 0U)
{
(void)OSA_EventClear(pdInstance->taskEventHandle, PD_TASK_EVENT_PD_MSG);
(void)OSA_EventClear(pdInstance->taskEventHandle, PD_TASK_EVENT_RECEIVED_HARD_RESET);
if (pdInstance->psmCurState != PSM_PE_BIST_CARRIER_MODE_2)
{
/* Hard reset is ignored when in BIST carrier mode */
pdInstance->hardResetReceived = 0;
triggerInfo->triggerEvent = PSM_TRIGGER_RECEIVE_HARD_RESET;
}
}
else if ((taskEventSet & (uint32_t)PD_TASK_EVENT_FR_SWAP_SINGAL) != 0U)
{
(void)OSA_EventClear(pdInstance->taskEventHandle, PD_TASK_EVENT_FR_SWAP_SINGAL);
if (pdInstance->curPowerRole == kPD_PowerRoleSink)
{
pdInstance->psmNewState = PE_FRS_SNK_SRC_Send_Swap;
}
}
else if ((taskEventSet & (uint32_t)PD_TASK_EVENT_PD_MSG) != 0U)
{
(void)OSA_EventClear(pdInstance->taskEventHandle, PD_TASK_EVENT_PD_MSG);
if (pdInstance->psmCurState != PSM_PE_BIST_TEST_DATA_MODE)
{
processMessage = 0;
if (PD_MsgGetReceiveResult(pdInstance) != 0U)
{
if (pdInstance->receivedSop == kPD_MsgSOP)
{
processMessage = 1;
}
#if (defined PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
else if ((pdInstance->receivedSop == kPD_MsgSOPp) || (pdInstance->receivedSop == kPD_MsgSOPpp))
{
PD_MsgReceive(pdInstance);
processMessage = 1;
}
#endif
else
{
/* No action required. */
}
}
if (processMessage != 0U)
{
uint8_t msgType;
triggerInfo->msgHeader.msgHeaderVal = (uint16_t)(MSG_DATA_HEADER);
triggerInfo->pdMsgSop = pdInstance->receivedSop;
triggerInfo->pdMsgDataBuffer = MSG_DATA_BUFFER;
triggerInfo->pdMsgDataLength =
(uint8_t)((MSG_DATA_HEADER & PD_MSG_HEADER_NUMBER_OF_DATA_OBJECTS_MASK) >>
PD_MSG_HEADER_NUMBER_OF_DATA_OBJECTS_POS);
msgType = (uint8_t)triggerInfo->msgHeader.bitFields.messageType;
if (triggerInfo->msgHeader.bitFields.extended == 0U)
{
if (triggerInfo->msgHeader.bitFields.NumOfDataObjs == 0U)
{
triggerInfo->pdMsgType = (message_type_t)msgType;
/* There are three places: two message will be sent continuously by one port.
* 1. fast role swap.
* 2. sink beginning power role swap.
* 3. rdo request in source.
* 4. after soft reset, the partner will send source_caps.
*/
if (triggerInfo->pdMsgType == kPD_MsgAccept)
{
if (pdInstance->psmCurState != PSM_SEND_SOFT_RESET)
{
PD_MsgReceive(pdInstance);
}
}
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
if (triggerInfo->pdMsgType == kPD_MsgFrSwap)
{
pdInstance->frSwapReceived = 1;
}
#endif
}
else
{
msgType |= PD_MSG_DATA_TYPE_MASK;
triggerInfo->pdMsgType = (message_type_t)msgType;
if (triggerInfo->pdMsgType == kPD_MsgRequest)
{
PD_PsmCheckRevision(pdInstance, triggerInfo->msgHeader);
}
}
}
else
{
msgType |= PD_MSG_EXT_TYPE_MASK;
triggerInfo->pdMsgType = (message_type_t)msgType;
triggerInfo->pdExtMsgLength =
((uint32_t)((uint8_t *)triggerInfo->pdMsgDataBuffer)[0] +
((uint32_t)((uint8_t *)triggerInfo->pdMsgDataBuffer)[1] & 0x01U) * 256U);
}
triggerInfo->triggerEvent = PSM_TRIGGER_PD_MSG;
if (triggerInfo->pdMsgType == kPD_MsgVendorDefined)
{
triggerInfo->vdmHeader.structuredVdmHeaderVal =
USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(((uint8_t *)triggerInfo->pdMsgDataBuffer));
/* Vendor Defined message can be interrupted. */
PD_MsgReceive(pdInstance);
(void)OSA_EventGet(pdInstance->taskEventHandle, PD_TASK_EVENT_PD_MSG, &taskEventSet);
if (taskEventSet != 0U)
{
PD_PsmProcessImportEventBeforeNextStateMachine(pdInstance);
return kSM_Continue; /* process next message */
}
}
#if ((defined PD_CONFIG_EXTENDED_CHUNK_LAYER_SUPPORT) && (PD_CONFIG_EXTENDED_CHUNK_LAYER_SUPPORT))
if (PD_PsmChunkingLayerRXStateMachine(pdInstance, triggerInfo) == 0U)
{
return kSM_Continue;
}
#endif
}
else
{
}
}
else
{
/* Ignore everything except Hard Reset and disconnect */
}
}
else if ((taskEventSet & (uint32_t)PD_TASK_EVENT_DPM_MSG) != 0U)
{
pd_command_t command = (pd_command_t)PD_DpmGetMsg(pdInstance);
switch (command)
{
case PD_DPM_CONTROL_SOFT_RESET:
case PD_DPM_CONTROL_HARD_RESET:
case PD_DPM_FAST_ROLE_SWAP:
break;
default:
if ((pdInstance->psmCurState != PSM_PE_SNK_READY) && (pdInstance->psmCurState != PSM_PE_SRC_READY))
{
command = PD_DPM_INVALID;
}
break;
}
if (command != PD_DPM_INVALID)
{
#if (defined(PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)) && \
(defined(PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE) && (PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE))
if ((PD_MsgSnkCheckStartCommand(pdInstance, command) == 0U) &&
(pdInstance->curPowerRole == kPD_PowerRoleSink))
{
if (pdInstance->commandRetryCount > 0U)
{
(void)PD_TimerStart(pdInstance, tDpmComandRetryTimer, T_DPM_COMMAND_RETRY);
pdInstance->commandRetryCount--;
}
else
{
PD_PsmCommandFail(pdInstance, command);
PD_DpmClearMsg(pdInstance, command);
}
}
else
{
#endif
triggerInfo->triggerEvent = PSM_TRIGGER_DPM_MSG;
triggerInfo->dpmMsg = command;
PD_DpmClearMsg(pdInstance, command);
#if (defined(PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)) && \
(defined(PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE) && (PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE))
pdInstance->commandRetryCount = 0;
}
#endif
}
else
{
#if (defined(PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)) && \
(defined(PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE) && (PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE))
pdInstance->commandRetryCount = 0;
#endif
PD_PsmCommandFail(pdInstance, command);
PD_DpmClearMsg(pdInstance, command);
}
(void)OSA_EventClear(pdInstance->taskEventHandle, PD_TASK_EVENT_DPM_MSG);
}
else if ((taskEventSet & (uint32_t)PD_TASK_EVENT_SEND_DONE) != 0U)
{
(void)OSA_EventClear(pdInstance->taskEventHandle, PD_TASK_EVENT_SEND_DONE);
}
else
{
PD_PortTaskEventProcess(pdInstance, taskEventSet);
triggerInfo->triggerEvent = PSM_TRIGGER_NONE;
}
return kSM_None;
}
static uint8_t PD_PsmCheckTimeOutHardReset(pd_instance_t *pdInstance)
{
uint8_t needHardReset = 0;
if ((pdInstance->psmHardResetCount <= N_HARD_RESET_COUNT) && (pdInstance->curPowerRole == kPD_PowerRoleSink))
{
if (PD_TimerCheckValidTimeOut(pdInstance, tSinkWaitCapTimer) != 0U)
{
(void)PD_TimerClear(pdInstance, tSinkWaitCapTimer);
needHardReset = 1;
}
if (PD_TimerCheckValidTimeOut(pdInstance, tPSTransitionTimer) != 0U)
{
(void)PD_TimerClear(pdInstance, tPSTransitionTimer);
needHardReset = 1;
}
if (PD_TimerCheckValidTimeOut(pdInstance, tNoResponseTimer) != 0U)
{
(void)PD_TimerClear(pdInstance, tNoResponseTimer);
needHardReset = 1;
}
}
return needHardReset;
}
static uint8_t PD_PsmProcessHardResetState(pd_instance_t *pdInstance)
{
#if (defined PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
if (pdInstance->curPowerRole == kPD_PowerRoleSource)
{
/* source send hard_reset, 2. after tpstimer. */
if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tPSHardResetTimer) != 0U)
{
/* Hard reset is complete */
pdInstance->psmNewState = PSM_PE_SRC_TRANSITION_TO_DEFAULT;
}
else
{
return 1;
}
}
else
#endif
#if (defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)
if (pdInstance->curPowerRole == kPD_PowerRoleSink)
{
/* sink send hard_reset */
pdInstance->psmNewState = PD_PsmSinkHardResetfunction(pdInstance);
}
else
#endif
{
}
return 0;
}
static uint8_t PD_PsmProcessSendSoftResetState(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo)
{
if ((triggerInfo->triggerEvent == PSM_TRIGGER_PD_MSG) && (triggerInfo->pdMsgSop == kPD_MsgSOP) &&
(triggerInfo->pdMsgType == kPD_MsgAccept))
{
(void)PD_TimerClear(pdInstance, tSenderResponseTimer);
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SOFT_RESET_SUCCESS, NULL,
(pdInstance->commandProcessing == PD_DPM_CONTROL_SOFT_RESET) ? 1U : 0U);
if (pdInstance->curPowerRole == kPD_PowerRoleSource)
{
pdInstance->psmNewState = PSM_PE_SRC_IMPLICIT_CABLE_DISCOVERY;
}
else
{
pdInstance->psmNewState = PSM_PE_SNK_WAIT_FOR_CAPABILITIES;
}
}
else if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tSenderResponseTimer) != 0U)
{
if (pdInstance->commandProcessing == PD_DPM_CONTROL_SOFT_RESET)
{
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SOFT_RESET_FAIL, NULL, 1);
}
pdInstance->psmNewState = PSM_HARD_RESET;
}
else
{
return 1;
}
return 0;
}
static void PD_PsmCheckUnexpectedReceivedMsg(pd_instance_t *pdInstance,
trigger_event_t triggerEvent,
uint8_t *didNothingStepB)
{
if (triggerEvent == PSM_TRIGGER_PD_MSG)
{
switch (pdInstance->psmCurState)
{
case PSM_PE_SRC_STARTUP:
case PSM_PE_SRC_DISCOVERY:
pdInstance->psmNewState = PSM_HARD_RESET;
*didNothingStepB = 0;
break;
case PSM_PE_PRS_SRC_SNK_TRANSITION_TO_OFF:
case PSM_PE_PRS_SNK_SRC_SOURCE_ON:
pdInstance->psmNewState = PSM_CHECK_ASYNC_RX;
*didNothingStepB = 0;
break;
case PSM_PE_SNK_WAIT_FOR_CAPABILITIES:
pdInstance->psmNewState = PSM_SEND_SOFT_RESET;
*didNothingStepB = 0;
break;
default:
/* No action required. */
break;
}
}
}
static uint8_t PD_PsmProcessReadyState(pd_instance_t *pdInstance, psm_trigger_info_t *triggerInfo)
{
uint8_t didNothingStepB = 0;
#if ((defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE))
uint8_t didNothing = 1;
didNothing &= PD_PsmSecondaryStateHandler(pdInstance, kPD_MsgSOP, triggerInfo);
#if (defined PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
if ((PD_TimerCheckValidTimeOut(pdInstance, tDiscoverIdentityTimer) != 0U) &&
(pdInstance->psmSecondaryState[1] == PSM_IDLE) &&
(pdInstance->cableDiscoverIdentityCounter < N_DISCOVER_IDENTITY_COUNTER))
{
pdInstance->cableDiscoverIdentityTimeout = 1;
(void)PD_TimerClear(pdInstance, tDiscoverIdentityTimer);
pdInstance->psmNewSecondaryState[1] = PSM_PE_SRC_VDM_IDENTITY_REQUEST;
}
didNothing &= PD_PsmSecondaryStateHandler(pdInstance, kPD_MsgSOPp, triggerInfo);
didNothing &= PD_PsmSecondaryStateHandler(pdInstance, kPD_MsgSOPpp, triggerInfo);
/* second state is IDLE && don't get success && count is not max && DiscoverIdentityTimer is timeout */
if ((pdInstance->psmSecondaryState[1] == PSM_IDLE) &&
(PD_CheckWhetherInitiateCableDiscoveryIdentityOrNot(pdInstance) != 0U) &&
(pdInstance->cableDiscoverIdentityTimeout != 0U))
{
pdInstance->cableDiscoverIdentityTimeout = 0;
(void)PD_TimerStart(pdInstance, tDiscoverIdentityTimer, T_DISCOVER_IDENTITY);
}
/* cable discover success || beyond maximum count */
else if (((pdInstance->psmCableIdentitiesDataCount > 0U) ||
(pdInstance->cableDiscoverIdentityCounter >= N_DISCOVER_IDENTITY_COUNTER)) &&
(pdInstance->pendingSOP != (uint8_t)kPD_MsgSOPMask))
{
pdInstance->pendingSOP = (uint8_t)kPD_MsgSOPMask;
pdInstance->receiveState = 0;
PD_MsgReceive(pdInstance);
}
else
{
/* No action required. */
}
#endif
if ((pdInstance->psmSecondaryState[0] == PSM_IDLE) && (pdInstance->psmSecondaryState[1] == PSM_IDLE) &&
(pdInstance->psmSecondaryState[2] == PSM_IDLE) && (didNothing != 0U))
{
didNothingStepB = 1;
}
#endif
if (triggerInfo->triggerEvent == PSM_TRIGGER_PD_MSG)
{
PD_PsmRdyProcessPdMessage(pdInstance, triggerInfo);
}
else if (triggerInfo->triggerEvent == PSM_TRIGGER_DPM_MSG)
{
#if (defined PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
if (pdInstance->psmCurState == PSM_PE_SRC_READY)
{
PD_PsmSourceRdyProcessDpmMessage(pdInstance, triggerInfo);
}
#endif
#if (defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)
if (pdInstance->psmCurState == PSM_PE_SNK_READY)
{
PD_PsmSinkRdyProcessDpmMessage(pdInstance, triggerInfo);
}
#endif
}
else
{
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
didNothingStepB = PD_PsmReadyAutoPolicyProcess(pdInstance);
#else
didNothingStepB = 1;
#endif
}
return didNothingStepB;
}
#if (defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)) || \
((defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE))
static inline uint8_t PD_PsmGetTypeCCurrent(pd_instance_t *pdInstance)
{
uint8_t typeCurrent = (uint8_t)kCurrent_Invalid;
(void)PD_PhyControl(pdInstance, PD_PHY_GET_TYPEC_CURRENT_CAP, &typeCurrent);
return typeCurrent;
}
#endif
static pd_state_machine_state_t PD_PsmProcessState(pd_instance_t *pdInstance)
{
psm_trigger_info_t triggerInfo;
pd_state_machine_state_t returnState = kSM_None;
uint8_t didNothingStepA = 1;
uint8_t didNothingStepB = 1;
uint8_t msgReceived = 0;
if (pdInstance->psmCurState != PSM_UNKNOWN)
{
triggerInfo.triggerEvent = PSM_TRIGGER_NONE;
triggerInfo.pdMsgType = kPD_MsgInvalid;
triggerInfo.pdMsgSop = kPD_MsgSOPInvalid;
triggerInfo.dpmMsg = PD_DPM_INVALID;
triggerInfo.pdMsgDataBuffer = NULL;
triggerInfo.vdmHeader.structuredVdmHeaderVal = 0U;
/* get the newest events */
if (PD_PsmGetNewestEvent(pdInstance, &triggerInfo) == kSM_Continue)
{
return kSM_Continue;
}
if (triggerInfo.triggerEvent == PSM_TRIGGER_PD_MSG)
{
msgReceived = 1;
}
if (((triggerInfo.triggerEvent == PSM_TRIGGER_PD_MSG) && (triggerInfo.pdMsgSop == kPD_MsgSOP)) ||
(triggerInfo.triggerEvent == PSM_TRIGGER_RECEIVE_HARD_RESET))
{
didNothingStepA &= PD_PsmPrimaryStateProcessPdMsg(pdInstance, &pdInstance->psmNewState, &triggerInfo);
}
else if (triggerInfo.triggerEvent == PSM_TRIGGER_DPM_MSG)
{
didNothingStepA &= PD_PsmPrimaryStateProcessDpmMsg(pdInstance, &pdInstance->psmNewState, &triggerInfo);
}
else
{
/* No action required. */
}
if (didNothingStepA == 0U)
{
if ((msgReceived != 0U) && (PD_PsmCanPendingReceive(pdInstance) != 0U))
{
PD_MsgReceive(pdInstance); /* msg has been processed, receiving next msg */
}
PD_PsmProcessImportEventBeforeNextStateMachine(pdInstance);
return kSM_Continue;
}
/* different timeout need hard_reset */
if (PD_PsmCheckTimeOutHardReset(pdInstance) != 0U)
{
didNothingStepA = 0;
pdInstance->psmNewState = PSM_HARD_RESET;
}
/* alternate mode tAMETimeoutTimer */
else if (PD_TimerCheckValidTimeOut(pdInstance, tAMETimeoutTimer) != 0U)
{
(void)PD_TimerClear(pdInstance, tAMETimeoutTimer);
PD_ConnectAltModeEnterFail(pdInstance, pdInstance->psmPresentlyPdConnected);
#ifdef USBPD_ENABLE_USB_BILLBOARD
UsbbSetAltModeConfigResult(AMR_CONFIG_FAILED);
#endif
}
/* Check if we are waiting for an event for state transition */
else if (pdInstance->psmNewState == pdInstance->psmCurState)
{
didNothingStepB = 0;
switch (pdInstance->psmCurState)
{
case PSM_EXIT_TO_ERROR_RECOVERY: /* (B) */
case PSM_EXIT_TO_ERROR_RECOVERY_WITH_DELAY: /* (B) */
returnState = kSM_ErrorRecovery;
break;
#if (defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE)
case PSM_INTERRUPTED_REQUEST: /* (B) */
/* Transitioned back here after VDM handling, re attempt the request */
pdInstance->psmNewState = pdInstance->psmInterruptedState;
pdInstance->psmInterruptedState = PSM_UNKNOWN;
break;
#endif
/* do hard_reset actively do in (C) */
case PSM_HARD_RESET: /* (B) */
didNothingStepB = PD_PsmProcessHardResetState(pdInstance);
break;
case PSM_SEND_SOFT_RESET: /* (B) */
didNothingStepB = PD_PsmProcessSendSoftResetState(pdInstance, &triggerInfo);
break;
case PSM_SOFT_RESET: /* (B) */
/* If we get here, then recover with a hard reset */
pdInstance->psmNewState = PSM_HARD_RESET;
break;
case PSM_CHECK_ASYNC_RX: /* (B) */
/* The async conditions at the top of the loop have been evaluated */
/* continue to soft reset */
pdInstance->psmNewState = PSM_SEND_SOFT_RESET;
break;
case PSM_BYPASS: /* (B) */
/* We do nothing here. */
didNothingStepB = 1;
break;
#if (defined PD_CONFIG_SOURCE_ROLE_ENABLE) && (PD_CONFIG_SOURCE_ROLE_ENABLE)
case PSM_PE_SRC_STARTUP: /* (B) */
{
if (PD_TimerCheckValidTimeOut(pdInstance, tSwapSourceStartTimer) != 0U)
{
(void)PD_TimerClear(pdInstance, tSwapSourceStartTimer);
pdInstance->psmNewState = PSM_PE_SRC_IMPLICIT_CABLE_DISCOVERY;
}
else
{
didNothingStepB = 1;
}
break;
}
case PSM_PE_SRC_DISCOVERY: /* (B) */
{
if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tSourceCapabilityTimer) != 0U)
{
if ((pdInstance->psmSendCapsCounter > N_CAPS_COUNT))
{
pdInstance->psmNewState = PSM_PE_SRC_DISABLED;
}
else
{
#if (defined(PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)) && \
(defined(PD_CONFIG_SRC_AUTO_DISCOVER_CABLE_PLUG) && (PD_CONFIG_SRC_AUTO_DISCOVER_CABLE_PLUG))
pdInstance->pendingSOP = (uint8_t)kPD_MsgSOPMask;
#endif
pdInstance->psmNewState = PSM_PE_SRC_SEND_CAPABILITIES;
}
}
#if (defined(PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)) && \
(defined(PD_CONFIG_SRC_AUTO_DISCOVER_CABLE_PLUG) && (PD_CONFIG_SRC_AUTO_DISCOVER_CABLE_PLUG))
else if (PD_CheckWhetherInitiateCableDiscoveryIdentityOrNot(pdInstance) != 0U)
{
/* cable plug didn't response data object on PE_SRC_STARTUP state */
(void)PD_PsmSecondaryStateHandler(pdInstance, kPD_MsgSOPp, &triggerInfo);
}
#endif
else if (PD_PsmNoResponseHardResetCountCheck(pdInstance) == 0U)
{
didNothingStepB = 1;
}
else
{
}
break;
}
case PSM_PE_SRC_IMPLICIT_CABLE_DISCOVERY: /* (B) */
{
#if (defined(PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)) && \
(defined(PD_CONFIG_SRC_AUTO_DISCOVER_CABLE_PLUG) && (PD_CONFIG_SRC_AUTO_DISCOVER_CABLE_PLUG))
(void)PD_PsmSecondaryStateHandler(pdInstance, kPD_MsgSOPp, &triggerInfo);
if (pdInstance->psmSecondaryState[1] == PSM_IDLE)
{
pdInstance->pendingSOP = (uint8_t)kPD_MsgSOPMask;
pdInstance->psmNewState = PSM_PE_SRC_SEND_CAPABILITIES;
}
#endif
break;
}
case PSM_PE_SRC_SEND_CAPABILITIES: /* (B) */
{
if (triggerInfo.triggerEvent == PSM_TRIGGER_PD_MSG)
{
(void)PD_TimerClear(pdInstance, tSenderResponseTimer);
if (triggerInfo.pdMsgType == kPD_MsgRequest)
{
pdInstance->partnerRdoRequest.rdoVal =
USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(((uint8_t *)triggerInfo.pdMsgDataBuffer));
pdInstance->psmNewState = PSM_PE_SRC_NEGOTIATE_CAPABILITY;
}
else
{
/* discard vendor defined message at here */
if (triggerInfo.pdMsgType != kPD_MsgVendorDefined)
{
pdInstance->psmNewState = PSM_SEND_SOFT_RESET;
}
}
}
else if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tSenderResponseTimer) != 0U)
{
pdInstance->psmNewState = PSM_HARD_RESET;
}
else if (PD_PsmNoResponseHardResetCountCheck(pdInstance) == 0U)
{
didNothingStepB = 1;
}
else
{
/* No action required. */
}
break;
}
case PSM_PE_SRC_TRANSITION_SUPPLY: /* (B) */
{
(void)PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(pdInstance, kPD_MsgPsRdy,
PSM_PE_SRC_READY);
if (pdInstance->psmGotoMinTx != 0U)
{
pdInstance->psmGotoMinTx = 0;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SRC_GOTOMIN_SUCCESS, NULL, 1);
}
else if (pdInstance->psmNewState == PSM_PE_SRC_READY)
{
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SRC_RDO_SUCCESS, NULL, 1);
}
else
{
/* No action required. */
}
break;
}
case PSM_PE_SRC_READY: /* (B) */
{
if (PD_PsmProcessReadyState(pdInstance, &triggerInfo) != 0U)
{
#if (defined PD_CONFIG_PD3_PPS_ENABLE) && (PD_CONFIG_PD3_PPS_ENABLE)
if ((PD_TimerCheckValidTimeOut(pdInstance, tSourcePPSCommTimer) != 0U) &&
(PD_PsmSourceIsPPSRDO(pdInstance) != 0U))
{
pdInstance->psmNewState = PSM_HARD_RESET;
}
else
#endif
{
#if defined(PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE) && (PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE)
typec_current_val_t typecCurrent = kCurrent_Invalid;
(void)PD_PhyControl(pdInstance, PD_PHY_GET_TYPEC_CURRENT_CAP, &typecCurrent);
if (typecCurrent != kCurrent_3A)
{
typecCurrent = kCurrent_3A;
(void)PD_PhyControl(pdInstance, PD_PHY_SRC_SET_TYPEC_CURRENT_CAP, &typecCurrent);
}
#endif
didNothingStepB = 1;
}
}
break;
}
case PSM_PE_SRC_DISABLED: /* (B) */
{
if (PD_PsmNoResponseHardResetCountCheck(pdInstance) == 0U)
{
didNothingStepB = 1;
}
break;
}
case PSM_PE_SRC_WAIT_NEW_CAPABILITIES: /* (B) */
/* The exit transition is handled by the global state transitions */
didNothingStepB = 1;
break;
case PSM_PE_SRC_HARD_RESET_RECEIVED: /* (B) */
{
if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tPSHardResetTimer) != 0U)
{
pdInstance->psmNewState = PSM_PE_SRC_TRANSITION_TO_DEFAULT;
}
else
{
didNothingStepB = 1;
}
break;
}
case PSM_PE_SRC_TRANSITION_TO_DEFAULT: /* (B) */
{
if (pdInstance->psmHardResetNeedsVSafe0V != 0U)
{
/* source send hard_reset, 4. after tSrcRecover, open vsafe5v. */
/* source receive hard_reset, 4. after tSrcRecover, open vsafe5v. */
/* 2. wait tSrcRecover */
if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tSrcRecoverTimer) != 0U)
{
pdInstance->psmHardResetNeedsVSafe0V = 0;
(void)pdInstance->callbackFns->PD_SrcTurnOnTypeCVbus(pdInstance->callbackParam,
kVbusPower_InHardReset);
#if defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
PD_DpmDischargeVconn(pdInstance, 0);
PD_DpmSetVconn(pdInstance, 1);
#endif /* PD_CONFIG_VCONN_SUPPORT */
}
else
{
didNothingStepB = 1;
}
}
/* source send hard_reset, 5. wait vsafe5v. */
/* source receive hard_reset, 5. wait vsafe5v. */
else if (PD_PsmCheckVsafe5V(pdInstance) != 0U)
{
(void)PD_TimerStart(pdInstance, tNoResponseTimer, T_NO_RESPONSE);
pdInstance->enterSrcFromSwap = 0;
pdInstance->psmNewState = PSM_PE_SRC_STARTUP;
}
else
{
/* Wait until the power supply transitions to default. */
didNothingStepB = 0;
}
break;
}
#endif
#if (defined PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)
case PSM_PE_SNK_DISCOVERY: /* (B) */
{
if (PD_PsmNoResponseHardResetCountCheck(pdInstance) != 0U)
{
}
else if (pdInstance->psmHardResetNeedsVSafe0V != 0U)
{
if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tPSHardResetTimer) != 0U)
{
pdInstance->psmHardResetNeedsVSafe0V = 0U;
}
else if (PD_PsmCheckVsafe5V(pdInstance) == 0U)
{
pdInstance->psmHardResetNeedsVSafe0V = 0U;
}
else
{
/* No change in state, we should stay in low power mode */
didNothingStepB = 1U;
}
}
else if (PD_PsmCheckVsafe5V(pdInstance) != 0U)
{
if (pdInstance->asmHardResetSnkProcessing != 0U)
{
pdInstance->asmHardResetSnkProcessing = 0U;
(void)pdInstance->callbackFns->PD_SnkDrawTypeCVbus(
pdInstance->callbackParam, (uint8_t)PD_PsmGetTypeCCurrent(pdInstance),
kVbusPower_InHardReset);
}
/* Hard Reset is no longer in progress, allow VBus monitoring */
/* kVbusPower_InHardReset is end */
PD_ConnectSetPowerProgress(pdInstance, kVbusPower_Stable);
pdInstance->psmHardResetNeedsVSafe0V = 0U;
pdInstance->psmNewState = PSM_PE_SNK_WAIT_FOR_CAPABILITIES;
}
else
{
/* need check vbus constantly */
didNothingStepB = 0;
}
break;
}
case PSM_PE_SNK_WAIT_FOR_CAPABILITIES: /* (B) */
{
if (PD_PsmNoResponseHardResetCountCheck(pdInstance) == 0U)
{
didNothingStepB = 1;
}
else
{
}
break;
}
case PSM_PE_SNK_SELECT_CAPABILITY: /* (B) */
{
if (triggerInfo.triggerEvent == PSM_TRIGGER_PD_MSG)
{
pd_command_result_t commandResultCallback;
switch (triggerInfo.pdMsgType)
{
case kPD_MsgAccept:
pdInstance->psmNewState = PSM_PE_SNK_TRANSITION_SINK;
break;
case kPD_MsgWait:
commandResultCallback = kCommandResult_Wait;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SNK_RDO_FAIL, &commandResultCallback, 1);
if (pdInstance->psmExplicitContractExisted != 0U)
{
pdInstance->psmNewState = PSM_PE_SNK_READY;
pdInstance->psmSnkReceiveRdoWaitRetry = 1;
(void)PD_TimerStart(pdInstance, tSinkRequestTimer, T_SINK_REQUEST);
}
else
{
pdInstance->psmNewState = PSM_PE_SNK_WAIT_FOR_CAPABILITIES;
}
break;
case kPD_MsgReject:
commandResultCallback = kCommandResult_Reject;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SNK_RDO_FAIL, &commandResultCallback, 1);
if (pdInstance->psmExplicitContractExisted == 0U)
{
pdInstance->psmNewState = PSM_PE_SNK_WAIT_FOR_CAPABILITIES;
}
else
{
pdInstance->psmNewState = PSM_PE_SNK_READY;
}
break;
default:
if (triggerInfo.pdMsgType != kPD_MsgInvalid)
{
/* SourceCapabilities and VendorDefined are handled in the global section. */
/* soft reset other packets */
pdInstance->psmNewState = PSM_CHECK_ASYNC_RX;
}
break;
}
}
else if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tSenderResponseTimer) != 0U)
{
pdInstance->psmNewState = PSM_HARD_RESET;
}
else
{
didNothingStepB = 1;
}
break;
}
case PSM_PE_SNK_SELECT_CAPABILITY_WAIT_TIMER_TIME_OUT: /* (B) */
{
if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tSinkRequestTimer) != 0U)
{
pdInstance->psmNewState = PSM_PE_SNK_SELECT_CAPABILITY;
}
break;
}
case PSM_PE_SNK_TRANSITION_SINK: /* (B) */
{
if (triggerInfo.triggerEvent == PSM_TRIGGER_PD_MSG)
{
/* SourceCapabilities and VendorDefined are handled in the global section. */
if ((triggerInfo.pdMsgSop == kPD_MsgSOP) && (triggerInfo.pdMsgType == kPD_MsgPing))
{
/* Remain in the same state */
/* pdInstance->psmNewState = PSM_PE_SNK_TRANSITION_SINK; */
}
else
{
(void)PD_TimerClear(pdInstance, tPSTransitionTimer);
if ((triggerInfo.pdMsgSop == kPD_MsgSOP) && (triggerInfo.pdMsgType == kPD_MsgPsRdy))
{
PD_MsgReceive(pdInstance);
if (pdInstance->psmGotoMinRx != 0U)
{
pdInstance->psmGotoMinRx = 0;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SNK_GOTOMIN_SUCCESS, NULL, 1);
}
else
{
(void)pdInstance->callbackFns->PD_SnkDrawRequestVbus(pdInstance->callbackParam,
pdInstance->rdoRequest);
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SNK_RDO_SUCCESS, &pdInstance->rdoRequest,
1);
}
pdInstance->psmNewState = PSM_PE_SNK_READY;
}
else
{
pdInstance->psmNewState = PSM_HARD_RESET;
}
}
}
else
{
didNothingStepB = 1;
}
break;
}
case PSM_PE_SNK_READY: /* (B) */
{
if (PD_PsmProcessReadyState(pdInstance, &triggerInfo) != 0U)
{
if (PD_TimerCheckValidTimeOut(pdInstance, tSinkRequestTimer) != 0U)
{
if (pdInstance->psmSnkReceiveRdoWaitRetry != 0U)
{
pdInstance->psmSnkReceiveRdoWaitRetry = 0U;
pdInstance->psmNewState = PSM_PE_SNK_SELECT_CAPABILITY;
}
}
#if (defined PD_CONFIG_PD3_PPS_ENABLE) && (PD_CONFIG_PD3_PPS_ENABLE)
else if ((PD_TimerCheckValidTimeOut(pdInstance, tSinkPPSPeriodicTimer) != 0U) &&
(PD_PsmSinkIsPPSRDO(pdInstance) != 0U))
{
pdInstance->psmNewState = PSM_PE_SNK_EVALUATE_CAPABILITY;
}
#endif
else
{
didNothingStepB = 1;
}
}
break;
}
case PSM_PE_SNK_TRANSITION_TO_DEFAULT: /* (B) */
break;
#endif
#if defined(PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
case PSM_PE_DR_SRC_GET_SOURCE_CAP: /* (B) */
{
if (triggerInfo.triggerEvent == PSM_TRIGGER_PD_MSG)
{
(void)PD_TimerClear(pdInstance, tSenderResponseTimer);
/* SourceCapabilities and VendorDefined are handled in the global section. */
if ((triggerInfo.pdMsgSop == kPD_MsgSOP) && ((triggerInfo.pdMsgType == kPD_MsgReject) ||
(triggerInfo.pdMsgType == kPD_MsgNotSupported)))
{
pdInstance->psmNewState = PSM_PE_SRC_READY;
pd_command_result_t commandResultCallback;
if (triggerInfo.pdMsgType == kPD_MsgReject)
{
commandResultCallback = kCommandResult_Reject;
}
else
{
commandResultCallback = kCommandResult_NotSupported;
}
(void)PD_DpmAppCallback(pdInstance, PD_DPM_GET_PARTNER_SRC_CAP_FAIL, &commandResultCallback,
1);
}
else
{
pdInstance->psmNewState = PSM_SEND_SOFT_RESET;
}
}
else if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tSenderResponseTimer) != 0U)
{
pdInstance->psmNewState = PSM_PE_SRC_READY;
}
else
{
didNothingStepB = 1;
}
break;
}
case PSM_PE_PRS_SRC_SNK_TRANSITION_TO_OFF: /* (B) */
{
/* check source is standby */
if (PD_PsmCheckVsafe0V(pdInstance) != 0U)
{
/* NOTE : DPM will actively discharge VBUS, and use a timer to ensure at least a min discharge
* time
*/
/* have enter standby */
PD_DpmDischargeVbus(pdInstance, 0);
pdInstance->psmNewState = PSM_PE_PRS_SRC_SNK_ASSERT_RD;
}
else
{
didNothingStepB = 0; /* need check vbus constantly */
}
break;
}
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
case PE_FRS_SRC_SNK_Transition_to_off: /* B */
{
/* wait vbus reach vSafe5V */
if (PD_TimerCheckInvalidOrTimeOut(pdInstance, timrFRSwapWaitPowerStable) != 0U)
{
if (PD_PsmCheckVsafe5V(pdInstance) != 0U)
{
pdInstance->psmNewState = PE_FRS_SRC_SNK_Assert_Rd;
}
}
else
{
/* need check vbus constantly */
didNothingStepB = 0;
}
break;
}
#endif
case PSM_PE_PRS_SNK_SRC_TRANSITION_TO_OFF: /* (B) */
PD_PsmPowerSwapSinkSourceTransitionOff(pdInstance, &triggerInfo, PSM_PE_PRS_SNK_SRC_ASSERT_RP,
&didNothingStepB);
break;
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
case PE_FRS_SNK_SRC_Transition_to_off: /* B */
PD_PsmCheckFRS5V(pdInstance);
PD_PsmPowerSwapSinkSourceTransitionOff(pdInstance, &triggerInfo, PE_FRS_SNK_SRC_Vbus_Applied,
&didNothingStepB);
break;
#endif
case PSM_PE_PRS_SRC_SNK_WAIT_SOURCE_ON: /* (B) */
#if (defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
case PE_FRS_SRC_SNK_Wait_Source_on: /* B */
#endif
{
if (triggerInfo.triggerEvent == PSM_TRIGGER_PD_MSG)
{
if ((triggerInfo.pdMsgSop == kPD_MsgSOP) && (triggerInfo.pdMsgType == kPD_MsgPsRdy))
{
pd_vbus_power_progress_t vbusPowerState;
pd_dpm_callback_event_t callbackEvent;
#if 0
/* SIP code doesn't do this */
PD_FRSControl(pdInstance, 1);
#endif
PD_MsgStopReceive(pdInstance);
(void)PD_TimerClear(pdInstance, tPSSourceOnTimer);
/* Swap from SOURCE to SINK */
/* pr swap end */
PD_ConnectSetPowerProgress(pdInstance, kVbusPower_Stable);
#if defined(PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
/* Cable plug will need a soft reset */
pdInstance->psmCablePlugResetNeeded = 1;
#endif
#if (defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
if (pdInstance->psmCurState == PE_FRS_SRC_SNK_Wait_Source_on)
{
vbusPowerState = kVbusPower_InFRSwap;
}
else
#endif
{
vbusPowerState = kVbusPower_InPRSwap;
}
(void)pdInstance->callbackFns->PD_SnkDrawTypeCVbus(
pdInstance->callbackParam, (uint8_t)PD_PsmGetTypeCCurrent(pdInstance), vbusPowerState);
#if (defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
if (pdInstance->psmCurState == PE_FRS_SRC_SNK_Wait_Source_on)
{
callbackEvent = PD_DPM_FR_SWAP_SUCCESS;
}
else
#endif
{
callbackEvent = PD_DPM_PR_SWAP_SUCCESS;
}
(void)PD_DpmAppCallback(pdInstance, callbackEvent, NULL, 1);
pdInstance->psmNewState = PSM_PE_SNK_STARTUP;
}
else
{
/* A protocol error during power role swap triggers a Hard Reset */
pdInstance->psmNewState = PSM_HARD_RESET;
}
}
else if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tPSSourceOnTimer) != 0U)
{
pdInstance->psmNewState = PSM_EXIT_TO_ERROR_RECOVERY;
}
else
{
didNothingStepB = 1;
}
break;
}
case PSM_PE_PRS_SRC_SNK_SEND_PR_SWAP: /* (B) */
case PSM_PE_PRS_SNK_SRC_SEND_PR_SWAP: /* (B) */
PD_PsmStateWaitReply(pdInstance, &triggerInfo, &didNothingStepB);
break;
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
case PE_FRS_SNK_SRC_Send_Swap: /* B */
{
PD_PsmCheckFRS5V(pdInstance);
if (triggerInfo.triggerEvent == PSM_TRIGGER_PD_MSG)
{
if (triggerInfo.pdMsgType == kPD_MsgAccept)
{
pdInstance->psmNewState = PE_FRS_SNK_SRC_Transition_to_off;
}
else
{
pdInstance->psmNewState = PSM_EXIT_TO_ERROR_RECOVERY_WITH_DELAY;
}
}
else if (PD_TimerCheckValidTimeOut(pdInstance, tSenderResponseTimer) != 0U)
{
pdInstance->psmNewState = PSM_EXIT_TO_ERROR_RECOVERY;
}
else
{
didNothingStepB = 1;
}
break;
}
#endif
case PSM_PE_PRS_SNK_SRC_SOURCE_ON: /* (B) */
{
if (PD_PsmCheckVsafe5V(pdInstance) != 0U)
{
PD_PsmPowerSwapSinkOpenVbus(pdInstance, PD_DPM_PR_SWAP_SUCCESS);
}
else
{
didNothingStepB = 1;
}
break;
}
case PSM_PE_PRS_EVALUATE_PR_SWAP_WAIT_TIMER_TIME_OUT: /* (B) */
{
if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tPrSwapWaitTimer) != 0U)
{
if (pdInstance->curPowerRole == kPD_PowerRoleSource)
{
pdInstance->psmNewState = PSM_PE_PRS_SRC_SNK_SEND_PR_SWAP;
}
else
{
pdInstance->psmNewState = PSM_PE_PRS_SNK_SRC_SEND_PR_SWAP;
}
}
break;
}
case PSM_PE_DR_SNK_GET_SINK_CAP: /* (B) */
case PSM_PE_SRC_GET_SINK_CAP: /* (B) */
{
if (triggerInfo.triggerEvent == PSM_TRIGGER_PD_MSG)
{
pdInstance->psmNewState = PE_PSM_STATE_ROLE_RDY_STATE;
/* SourceCapabilities and VendorDefined are handled in the global section. */
(void)PD_TimerClear(pdInstance, tSenderResponseTimer);
if (triggerInfo.pdMsgType == kPD_MsgSinkCapabilities)
{
pd_capabilities_t sinkCapa;
/* Clear any pending message now that we have the latest */
(void)PD_DpmClearMsg(pdInstance, PD_DPM_CONTROL_GET_PARTNER_SINK_CAPABILITIES);
/* Update the PDOs for the EC and send interrupt */
sinkCapa.capabilities = triggerInfo.pdMsgDataBuffer;
sinkCapa.capabilitiesCount = triggerInfo.pdMsgDataLength;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_GET_PARTNER_SNK_CAP_SUCCESS, &sinkCapa, 1);
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
#if (defined PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
pdInstance->portPartnerSinkPDO1.PDOValue = sinkCapa.capabilities[0];
#endif
#endif
}
else if ((triggerInfo.pdMsgType == kPD_MsgReject) ||
(triggerInfo.pdMsgType == kPD_MsgNotSupported))
{
pd_command_result_t commandResultCallback;
if (triggerInfo.pdMsgType == kPD_MsgReject)
{
commandResultCallback = kCommandResult_Reject;
}
else
{
commandResultCallback = kCommandResult_NotSupported;
}
(void)PD_DpmAppCallback(pdInstance, PD_DPM_GET_PARTNER_SNK_CAP_FAIL, &commandResultCallback,
1);
}
else
{
pdInstance->psmNewState = PSM_SEND_SOFT_RESET;
}
}
else if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tSenderResponseTimer) != 0U)
{
pdInstance->psmNewState = PE_PSM_STATE_ROLE_RDY_STATE;
}
else
{
didNothingStepB = 1;
}
break;
}
#endif
#if defined(PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
case PSM_PE_DRS_SEND_DR_SWAP: /* (B) */
PD_PsmStateWaitReply(pdInstance, &triggerInfo, &didNothingStepB);
break;
case PSM_PE_DRS_EVALUATE_DR_SWAP_WAIT_TIMER_TIME_OUT: /* (B) */
if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tDrSwapWaitTimer) != 0U)
{
pdInstance->psmNewState = PSM_PE_DRS_SEND_DR_SWAP;
}
break;
#endif
#if defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
case PSM_PE_VCS_SEND_SWAP: /* (B) */
PD_PsmStateWaitReply(pdInstance, &triggerInfo, &didNothingStepB);
break;
case PSM_PE_VCS_WAIT_FOR_VCONN: /* (B) */
{
if (triggerInfo.triggerEvent == PSM_TRIGGER_PD_MSG)
{
/* SourceCapabilities and VendorDefined are handled in the global section. */
(void)PD_TimerClear(pdInstance, tVconnOnTimer);
if ((triggerInfo.pdMsgSop == kPD_MsgSOP) && (triggerInfo.pdMsgType == kPD_MsgPsRdy))
{
pdInstance->psmNewState = PSM_PE_VCS_TURN_OFF_VCONN;
}
else
{
pdInstance->psmNewState = PSM_SEND_SOFT_RESET;
}
}
else if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tVconnOnTimer) != 0U)
{
pdInstance->psmNewState = PSM_HARD_RESET;
}
else
{
didNothingStepB = 1;
}
break;
}
case PSM_PE_VCS_TURN_ON_VCONN: /* (B) */
{
if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tVconnOnTimer) != 0U)
{
pdInstance->psmNewState = PSM_PE_VCS_SEND_PS_RDY;
}
else
{
didNothingStepB = 1;
}
break;
}
#endif
#if (defined PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
case PE_DR_SRC_GET_SOURCE_CAP_EXT: /* B */
case PE_SNK_GET_SOURCE_CAP_EXT: /* B */
PD_StateWaitReplyExtDataProcess(pdInstance, &triggerInfo, kPD_MsgSourceCapExtended,
PD_DPM_GET_SRC_EXT_CAP_SUCCESS, PD_DPM_GET_SRC_EXT_CAP_FAIL,
&didNothingStepB);
break;
case PE_SRC_Get_Sink_Status: /* B */
case PE_SNK_Get_Source_Status: /* B */
PD_StateWaitReplyExtDataProcess(pdInstance, &triggerInfo, kPD_MsgStatus, PD_DPM_GET_STATUS_SUCCESS,
PD_DPM_GET_STATUS_FAIL, &didNothingStepB);
break;
#if defined(PD_CONFIG_PD3_PPS_ENABLE) && (PD_CONFIG_PD3_PPS_ENABLE)
case PE_SNK_Get_PPS_Status: /* B */
PD_StateWaitReplyExtDataProcess(pdInstance, &triggerInfo, kPD_MsgPpsStatus,
PD_DPM_GET_PPS_STATUS_SUCCESS, PD_DPM_GET_PPS_STATUS_FAIL,
&didNothingStepB);
break;
#endif
case PE_Get_Battery_Cap: /* B */
PD_StateWaitReplyExtDataProcess(pdInstance, &triggerInfo, kPD_MsgBatteryCapabilities,
PD_DPM_GET_BATTERY_CAP_SUCCESS, PD_DPM_GET_BATTERY_CAP_FAIL,
&didNothingStepB);
break;
case PE_Get_Battery_Status: /* B */
PD_StateWaitReplyExtDataProcess(pdInstance, &triggerInfo, kPD_MsgBatteryStatus,
PD_DPM_GET_BATTERY_STATUS_SUCCESS, PD_DPM_GET_BATTERY_STATUS_FAIL,
&didNothingStepB);
break;
case PE_Get_Manufacturer_Info: /* B */
PD_StateWaitReplyExtDataProcess(pdInstance, &triggerInfo, kPD_MsgManufacturerInfo,
PD_DPM_GET_MANUFACTURER_INFO_SUCCESS,
PD_DPM_GET_MANUFACTURER_INFO_FAIL, &didNothingStepB);
break;
#endif
#if (defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
case PE_FRS_SRC_SNK_CC_Signal: /* B */
didNothingStepB = 1;
if (((triggerInfo.triggerEvent == PSM_TRIGGER_PD_MSG) &&
(triggerInfo.msgHeader.bitFields.NumOfDataObjs == 0U) &&
(triggerInfo.msgHeader.bitFields.messageType == (uint8_t)kPD_MsgFrSwap)) ||
(pdInstance->frSwapReceived != 0U))
{
PD_ConnectSetPowerProgress(pdInstance, kVbusPower_InFRSwap);
pdInstance->frSwapReceived = 0;
pdInstance->psmNewState = PE_FRS_SRC_SNK_Evaluate_Swap;
didNothingStepB = 0;
}
else if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tFRSwapSignalTimer) != 0U)
{
/* In normal situation, this system cannot execute to here because the system has no power now
*/
PD_ConnectSetPowerProgress(pdInstance, kVbusPower_Stable);
}
else
{
/* No action required. */
}
break;
case PE_FRS_SNK_SRC_Vbus_Applied: /* B */
{
uint8_t checkVal;
PD_PsmCheckFRS5V(pdInstance);
(void)PD_PhyControl(pdInstance, PD_PHY_FR_SWAP_CHECK_VBUS_APPLIED, &checkVal);
if ((pdInstance->fr5VOpened != 0U) || (checkVal != 0U))
{
pdInstance->fr5VOpened = 1;
pdInstance->psmNewState = PE_FRS_SNK_SRC_Assert_Rp;
}
else
{
/* need check vbus constantly */
didNothingStepB = 0;
}
break;
}
#endif
case PSM_PE_BIST_TEST_DATA_MODE: /* (B) */
didNothingStepB = 1;
break;
case PSM_PE_BIST_CARRIER_MODE_2: /* (B) */
#if (defined PD_CONFIG_COMPLIANCE_TEST_ENABLE) && (PD_CONFIG_COMPLIANCE_TEST_ENABLE)
if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tBISTContModeTimer) != 0U)
{
(void)PD_PhyControl(pdInstance, PD_PHY_RESET_MSG_FUNCTION, NULL);
if (pdInstance->curPowerRole == kPD_PowerRoleSource)
{
pdInstance->psmNewState = PSM_PE_SRC_TRANSITION_TO_DEFAULT;
}
if (pdInstance->curPowerRole == kPD_PowerRoleSink)
{
pdInstance->psmNewState = PSM_PE_SNK_TRANSITION_TO_DEFAULT;
}
/* (void)PD_PhyControl(pdInstance, PD_PHY_EXIT_BIST, NULL); */
}
else
{
/* We do nothing here, it's all done by the hardware until the device is power cycled. */
didNothingStepB = 1;
}
#endif
break;
#if 0
case PE_Send_Security_Response: /* (B) */
{
if (PD_PsmChunkingLayerTXStateMachine(pdInstance,
kPD_MsgSOP, kPD_MsgSecurityResponse,
pdInstance->commandExtParam.dataBuffer,
pdInstance->commandExtParam.dataLength, &triggerInfo)
!= kStatus_PD_Success)
{
PD_PsmTransitionOnMsgSendError(pdInstance, PSM_CHECK_ASYNC_RX, PSM_SEND_SOFT_RESET);
}
else
{
if (PD_PsmChunkingLayerCheckSentDone(pdInstance))
{
pdInstance->psmNewState = PE_PSM_STATE_ROLE_RDY_STATE;
}
else
{
/* wait chunk message sent done */
}
}
break;
}
#endif
default:
didNothingStepB = 1;
break;
}
}
else
{
/* No action required. */
}
if (returnState != kSM_None)
{
return returnState;
}
if (triggerInfo.triggerEvent == PSM_TRIGGER_DPM_MSG)
{
PD_PsmCommandFail(pdInstance, triggerInfo.dpmMsg);
}
/* put this type exception process codes here, then the normal process codes are simple */
PD_PsmCheckUnexpectedReceivedMsg(pdInstance, triggerInfo.triggerEvent, &didNothingStepB);
}
if ((msgReceived != 0U) && (PD_PsmCanPendingReceive(pdInstance) != 0U))
{
PD_MsgReceive(pdInstance); /* msg has been processed, receiving next msg */
}
PD_PsmProcessImportEventBeforeNextStateMachine(pdInstance);
if ((didNothingStepB == 0U) || (didNothingStepA == 0U))
{
return kSM_Continue;
}
return kSM_WaitEvent;
}
/*! ***************************************************************************
VMD process related functions
******************************************************************************/
#if ((defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE)) || \
(defined(PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE))
static void PD_PsmEndVdmCommand(pd_instance_t *pdInstance, pd_psm_state_t secondState)
{
if (secondState != PSM_IDLE)
{
return;
}
if (pdInstance->commandProcessing <= PD_DPM_ALERT)
{
return;
}
else
{
PD_PsmCommandFail(pdInstance, pdInstance->commandProcessing);
}
}
#endif
#if (defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE)
static pd_psm_state_t PD_PsmVdmCheckkVDMBusyTimer(pd_instance_t *pdInstance, pd_psm_state_t newState)
{
if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tVDMBusyTimer) != 0U)
{
return newState;
}
else
{
pdInstance->psmVDMBusyWaitDpmMsg = newState;
return PSM_PE_DFP_UFP_VDM_VDM_BUSY_WAIT;
}
}
static pd_psm_state_t PD_PsmVdmIdleProcessDpmMessage(pd_instance_t *pdInstance,
start_of_packet_t statIndex,
psm_trigger_info_t *triggerInfo)
{
pd_psm_state_t secondNewState = PSM_UNKNOWN;
if (triggerInfo->dpmMsg >= PD_DPM_CONTROL_DISCOVERY_IDENTITY)
{
/* special process */
if (pdInstance->structuredVdmCommandParameter.vdmSop != (uint8_t)statIndex)
{
return PSM_UNKNOWN;
}
switch (triggerInfo->dpmMsg)
{
case PD_DPM_CONTROL_CABLE_RESET:
if (statIndex == kPD_MsgSOP)
{
return PSM_UNKNOWN;
}
break;
default:
/* No action required. */
break;
}
/* common process */
triggerInfo->triggerEvent = PSM_TRIGGER_NONE;
if (PD_PsmStartCommand(pdInstance, triggerInfo->dpmMsg, 1) == 0U)
{
PD_PsmCommandFail(pdInstance, triggerInfo->dpmMsg);
return PSM_IDLE;
}
switch (triggerInfo->dpmMsg)
{
case PD_DPM_CONTROL_CABLE_RESET:
{
secondNewState = PSM_PE_DFP_CBL_SEND_CABLE_RESET;
break;
}
case PD_DPM_CONTROL_DISCOVERY_IDENTITY:
secondNewState = PD_PsmVdmCheckkVDMBusyTimer(pdInstance, PSM_PE_DFP_UFP_VDM_IDENTITY_REQUEST);
break;
case PD_DPM_CONTROL_DISCOVERY_SVIDS:
secondNewState = PD_PsmVdmCheckkVDMBusyTimer(pdInstance, PSM_PE_DFP_VDM_SVIDS_REQUEST);
break;
case PD_DPM_CONTROL_DISCOVERY_MODES:
secondNewState = PD_PsmVdmCheckkVDMBusyTimer(pdInstance, PSM_PE_DFP_VDM_MODES_REQUEST);
break;
case PD_DPM_CONTROL_ENTER_MODE:
{
secondNewState = PSM_PE_DFP_VDM_MODE_ENTRY_REQUEST;
break;
}
case PD_DPM_CONTROL_EXIT_MODE:
{
secondNewState = PSM_PE_DFP_VDM_MODE_EXIT_REQUEST;
break;
}
case PD_DPM_CONTROL_SEND_ATTENTION:
{
secondNewState = PSM_PE_DFP_VDM_ATTENTION_REQUEST;
break;
}
case PD_DPM_SEND_VENDOR_STRUCTURED_VDM:
{
secondNewState = PSM_PE_VENDOR_STRUCTURED_VDM_REQUEST;
break;
}
case PD_DPM_SEND_UNSTRUCTURED_VDM:
{
secondNewState = PSM_PD_SEND_UNSTRUCTURED_VDM;
break;
}
default:
/* No action required. */
break;
}
}
return secondNewState;
}
#if 0
static uint8_t PDPsmVdmEnterExitModePdMsgProcess(pd_instance_t *pdInstance,
uint8_t statIndex,
psm_trigger_info_t *triggerInfo,
pd_svdm_command_request_t *commandVdmRequest)
{
if (pdInstance->curDataRole == kPD_DataRoleDFP)
{
pd_structured_vdm_header_t reponseVdmHeader;
reponseVdmHeader.structuredVdmHeaderVal = triggerInfo->vdmHeader.structuredVdmHeaderVal;
/* not supported */
reponseVdmHeader.bitFields.commandType = kVDM_ResponderNAK;
(void)PD_MsgSendStructuredVDM(pdInstance, (start_of_packet_t)statIndex, reponseVdmHeader, 0, NULL);
}
else
{
commandVdmRequest->vdoSop = (uint8_t)triggerInfo->pdMsgSop;
commandVdmRequest->vdmHeader.structuredVdmHeaderVal = triggerInfo->vdmHeader.structuredVdmHeaderVal;
if (triggerInfo->vdmHeader.bitFields.command == kVDM_EnterMode)
{
if (triggerInfo->msgHeader.bitFields.NumOfDataObjs >= 1)
{
commandVdmRequest->vdoCount = 1;
commandVdmRequest->vdoData = triggerInfo->pdMsgDataBuffer + 1U;
}
}
if (((statIndex == 0) && (pdInstance->curDataRole == kPD_DataRoleUFP)) || (statIndex >= 1))
{
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_REQUEST, commandVdmRequest, 0);
return 1;
}
}
return 0;
}
#endif
static void PD_PsmVdmIdleProcessPdMessage(pd_instance_t *pdInstance,
start_of_packet_t statIndex,
psm_trigger_info_t *triggerInfo)
{
/* note: vdm message will be processed before this */
if (triggerInfo->pdMsgType == kPD_MsgVendorDefined)
{
if (triggerInfo->pdMsgSop != statIndex)
{
return;
}
triggerInfo->triggerEvent = PSM_TRIGGER_NONE;
/* structured vdm */
if (triggerInfo->vdmHeader.bitFields.vdmType != 0U)
{
if (triggerInfo->vdmHeader.bitFields.commandType == (uint8_t)kVDM_Initiator)
{
pd_svdm_command_request_t commandVdmRequest;
uint8_t needReply = 0;
if ((triggerInfo->vdmHeader.bitFields.command >= (uint8_t)kVDM_DiscoverIdentity) &&
(triggerInfo->vdmHeader.bitFields.command <= (uint8_t)kVDM_ExitMode) &&
(pdInstance->curDataRole == kPD_DataRoleDFP))
{
/* PD2.0 spec: When the UUT working as DFP receives Identity, SVID, Mode, Enter Mode and Exit Mode,
the UUT must ignore these message. */
if (pdInstance->revision < PD_SPEC_REVISION_30)
{
if ((triggerInfo->vdmHeader.bitFields.SVID != PD_STANDARD_ID) &&
((triggerInfo->vdmHeader.bitFields.command == (uint8_t)kVDM_DiscoverIdentity) ||
(triggerInfo->vdmHeader.bitFields.command == (uint8_t)kVDM_DiscoverSVIDs)))
{
/* Ellisys compliance test TEST.PD.VDM.SRC.2, need reply NAK */
}
else
{
return; /* ignore these commands */
}
}
else
{
/* PD3.0 spec: When the UUT working as DFP receives Enter Mode and Exit Mode,
the UUT must reply with Not Supported. */
if ((triggerInfo->vdmHeader.bitFields.command == (uint8_t)kVDM_EnterMode) ||
(triggerInfo->vdmHeader.bitFields.command == (uint8_t)kVDM_ExitMode))
{
(void)PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(
pdInstance, PD_NOT_SUPPORT_REPLY_MSG, pdInstance->psmCurState);
return;
}
}
}
commandVdmRequest.requestResultStatus = (uint8_t)kCommandResult_NotSupported;
commandVdmRequest.vdoSop = (uint8_t)triggerInfo->pdMsgSop;
commandVdmRequest.vdmHeader.structuredVdmHeaderVal = triggerInfo->vdmHeader.structuredVdmHeaderVal;
/* process the message and get the reply data */
/* special process */
switch ((pd_vdm_command_t)triggerInfo->vdmHeader.bitFields.command)
{
case kVDM_DiscoverIdentity:
needReply = 1;
if (triggerInfo->vdmHeader.bitFields.SVID == PD_STANDARD_ID)
{
commandVdmRequest.vdoData = NULL;
commandVdmRequest.vdoCount = 0;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_REQUEST, &commandVdmRequest, 0);
if ((commandVdmRequest.vdoData != NULL) && (pdInstance->revision < PD_SPEC_REVISION_30))
{
pd_id_header_vdo_t *idHeader =
(pd_id_header_vdo_t *)(void *)&pdInstance->sendingData[2];
(void)memcpy((void *)idHeader, (void *)commandVdmRequest.vdoData,
(uint32_t)commandVdmRequest.vdoCount << 2U);
/* Ellisys compliance test TEST.PD.VDM.SNK.1, For PD2.0, ID Header Bits 25-16 shall be
all 0 (Reserved) (TEST.PD.VDM.SNK.1#3) */
idHeader->bitFields.connectorType = 0U;
idHeader->bitFields.productTypeDFP = 0U;
commandVdmRequest.vdoData = (uint32_t *)(void *)idHeader;
/* Ellisys compliance test TD.PD.VDMU.E1. For VDM1.0, if the Product Type declared in
the ID Header (VDO #2) is Hub (1) or Peripheral (2) and the Number of Data Objects
must be 4. */
if (commandVdmRequest.vdoCount > 3U)
{
if ((idHeader->bitFields.productTypeUFPOrCablePlug >
(uint8_t)kProductTypeUfp_AMA) ||
(idHeader->bitFields.productTypeUFPOrCablePlug <
(uint8_t)kProductTypeCable_PassiveCable))
{
commandVdmRequest.vdoCount = 3U;
}
}
}
}
else
{
commandVdmRequest.requestResultStatus = (uint8_t)kCommandResult_VDMNAK;
}
break;
case kVDM_DiscoverSVIDs:
needReply = 1;
if (triggerInfo->vdmHeader.bitFields.SVID == PD_STANDARD_ID)
{
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_REQUEST, &commandVdmRequest, 0);
}
else
{
commandVdmRequest.requestResultStatus = (uint8_t)kCommandResult_VDMNAK;
}
break;
case kVDM_DiscoverModes:
needReply = 1;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_REQUEST, &commandVdmRequest, 0);
break;
case kVDM_EnterMode:
if (triggerInfo->msgHeader.bitFields.NumOfDataObjs >= 1U)
{
commandVdmRequest.vdoCount = 1;
commandVdmRequest.vdoData = triggerInfo->pdMsgDataBuffer + 1U;
}
needReply = 1;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_REQUEST, &commandVdmRequest, 0);
break;
case kVDM_ExitMode:
pdInstance->psmVdmActiveModeValidMask &=
~((uint8_t)0x01U << triggerInfo->vdmHeader.bitFields.objPos);
pdInstance->vdmExitReceived[statIndex] = 0;
needReply = 1;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_REQUEST, &commandVdmRequest, 0);
#if (defined PD_CONFIG_ALT_MODE_SUPPORT) && (PD_CONFIG_ALT_MODE_SUPPORT)
/* UFP issues DR Swap to trigger Exit mode(Attention)? */
if ((pdInstance->drSwapTriggerExitMode != 0U) && (pdInstance->psmVdmActiveModeValidMask == 0U))
{
/* After exiting active mode, need to trigger DR Swap again. */
pdInstance->drSwapTriggerExitMode = 0;
(void)PD_Command(pdInstance, (uint32_t)PD_DPM_CONTROL_DR_SWAP, NULL);
}
#endif
break;
case kVDM_Attention:
if (triggerInfo->msgHeader.bitFields.NumOfDataObjs >= 1U)
{
commandVdmRequest.vdoCount = 1;
commandVdmRequest.vdoData = triggerInfo->pdMsgDataBuffer + 1U;
}
needReply = 0;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_REQUEST, &commandVdmRequest, 0);
break;
default:
{
/* vendor structured vdm */
if (triggerInfo->vdmHeader.bitFields.command >= 16U)
{
needReply = 1;
commandVdmRequest.vdoCount = (uint8_t)(triggerInfo->pdMsgDataLength - 1U);
commandVdmRequest.vdmHeader.structuredVdmHeaderVal =
USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(((uint8_t *)triggerInfo->pdMsgDataBuffer));
commandVdmRequest.vdoData = triggerInfo->pdMsgDataBuffer + 1U;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_REQUEST, &commandVdmRequest, 0);
}
break;
}
}
/* reply response mseeage */
if (needReply != 0U)
{
pd_structured_vdm_header_t reponseVdmHeader;
reponseVdmHeader.structuredVdmHeaderVal = triggerInfo->vdmHeader.structuredVdmHeaderVal;
if (reponseVdmHeader.bitFields.vdmVersion > PD_CONFIG_STRUCTURED_VDM_VERSION)
{
if (pdInstance->revision < PD_SPEC_REVISION_30)
{
reponseVdmHeader.bitFields.vdmVersion = PD_SPEC_STRUCTURED_VDM_VERSION_10;
}
else
{
reponseVdmHeader.bitFields.vdmVersion = PD_CONFIG_STRUCTURED_VDM_VERSION;
}
}
if (commandVdmRequest.requestResultStatus == (uint8_t)kCommandResult_NotSupported)
{
/* PD2.0 spec: If Structured VDMs are not supported,
* a Structured VDM Command received by a DFP or UFP
* Shall be ignored */
if (pdInstance->revision < PD_SPEC_REVISION_30)
{
return; /* ignore these commands */
}
else
{
/* PD3.0 spec: If Structured VDMs are not supported,
* the DFP or UFP receiving a VDM Command Shall send
* a Not_Supported Message in response */
(void)PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(
pdInstance, PD_NOT_SUPPORT_REPLY_MSG, pdInstance->psmCurState);
return;
}
}
else if (commandVdmRequest.requestResultStatus == (uint8_t)kCommandResult_VDMACK)
{
reponseVdmHeader.bitFields.commandType = (uint32_t)kVDM_ResponderACK;
if (PD_MsgSendStructuredVDM(pdInstance, (start_of_packet_t)statIndex, reponseVdmHeader,
commandVdmRequest.vdoCount,
(uint32_t *)commandVdmRequest.vdoData) == kStatus_PD_Success)
{
if (triggerInfo->vdmHeader.bitFields.command == (uint8_t)kVDM_EnterMode)
{
pdInstance->psmVdmActiveModeValidMask |=
((uint8_t)0x01U << triggerInfo->vdmHeader.bitFields.objPos);
}
}
}
else
{
switch ((pd_vdm_command_t)triggerInfo->vdmHeader.bitFields.command)
{
case kVDM_EnterMode:
case kVDM_ExitMode:
reponseVdmHeader.bitFields.commandType = (uint8_t)kVDM_ResponderNAK;
break;
case kVDM_DiscoverIdentity:
case kVDM_DiscoverSVIDs:
case kVDM_DiscoverModes:
default:
if (commandVdmRequest.requestResultStatus == (uint8_t)kCommandResult_VDMNAK)
{
reponseVdmHeader.bitFields.commandType = (uint8_t)kVDM_ResponderNAK;
}
else
{
reponseVdmHeader.bitFields.commandType = (uint8_t)kVDM_ResponderBUSY;
}
break;
}
(void)PD_MsgSendStructuredVDM(pdInstance, statIndex, reponseVdmHeader, 0, NULL);
}
}
}
else
{
/* should not reach here */
}
}
else
{
/* unstructured vdm */
pd_unstructured_vdm_command_param_t unstructuredVDMParam;
unstructuredVDMParam.vdmSop = (uint8_t)triggerInfo->pdMsgSop;
unstructuredVDMParam.vdmHeaderAndVDOsData = triggerInfo->pdMsgDataBuffer;
unstructuredVDMParam.vdmHeaderAndVDOsCount = triggerInfo->pdMsgDataLength;
unstructuredVDMParam.resultStatus = (uint8_t)kCommandResult_None;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_UNSTRUCTURED_VDM_RECEIVED, &unstructuredVDMParam, 0);
#if defined(PD_CONFIG_REVISION) && (PD_CONFIG_REVISION >= PD_SPEC_REVISION_30)
if (unstructuredVDMParam.resultStatus == (uint8_t)kCommandResult_NotSupported)
{
if (pdInstance->revision >= PD_SPEC_REVISION_30)
{
(void)PD_PsmSendControlTransitionWithAsyncRxAndSoftReset(pdInstance, kPD_MsgNotSupported,
pdInstance->psmCurState);
}
else
{
/* PD2.0 spec: ignore this message. */
}
}
#endif
}
}
}
#endif
#if (defined(PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE)) || \
(defined(PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE))
/*! ***************************************************************************
\brief Common Handler for structured VDM initiator requests
\param reject_flags will perSopPartner[kPD_MsgSOP].flags on failure
\retval PSM_IDLE on failure
\retval org_state on success
\note Only called from CLP task context
******************************************************************************/
static pd_psm_state_t PD_PsmStructuredVdmInitiatorRequest(pd_instance_t *pdInstance,
start_of_packet_t sopIndex,
uint16_t svid,
uint8_t position,
pd_vdm_command_t command,
uint8_t vdo_count,
uint32_t *vdos)
{
pd_structured_vdm_header_t vdmHeader;
vdmHeader.structuredVdmHeaderVal = 0;
vdmHeader.bitFields.command = (uint8_t)command;
vdmHeader.bitFields.commandType = (uint8_t)kVDM_Initiator;
vdmHeader.bitFields.objPos = position;
vdmHeader.bitFields.SVID = svid;
vdmHeader.bitFields.vdmType = 1;
#if defined(PD_CONFIG_REVISION) && (PD_CONFIG_REVISION >= PD_SPEC_REVISION_30)
vdmHeader.bitFields.vdmVersion = (pdInstance->revision < PD_SPEC_REVISION_30) ? PD_SPEC_STRUCTURED_VDM_VERSION_10 :
PD_CONFIG_STRUCTURED_VDM_VERSION;
#else
vdmHeader.bitFields.vdmVersion = PD_SPEC_STRUCTURED_VDM_VERSION_10;
#endif
/* Send Discover Modes request */
if (PD_MsgSendStructuredVDM(pdInstance, sopIndex, vdmHeader, vdo_count, vdos) == kStatus_PD_Success)
{
if (command == kVDM_EnterMode)
{
(void)PD_TimerStart(pdInstance, tVDMModeEntryTimer, T_VDM_WAIT_MODE_ENTRY);
}
else if (command == kVDM_ExitMode)
{
(void)PD_TimerStart(pdInstance, tVDMModeExitTimer, T_VDM_WAIT_MODE_EXIT);
}
else
{
(void)PD_TimerStart(pdInstance, tVDMResponseTimer, T_VDM_SENDER_RESPONSE);
}
/* Event driven -> wait for response packet or timeout */
return pdInstance->psmSecondaryState[sopIndex];
}
else
{
return PSM_IDLE;
}
}
static pd_psm_state_t PD_PsmVdmResponseHandler(pd_instance_t *pdInstance,
start_of_packet_t sop,
uint8_t vdmMsgType,
psm_trigger_info_t *triggerInfo,
tTimer_t timr,
pd_psm_state_t ackState,
pd_psm_state_t nakState)
{
uint8_t expected = 0;
pd_psm_state_t newStateTmp = PSM_UNKNOWN;
if ((triggerInfo->triggerEvent == PSM_TRIGGER_PD_MSG) && (triggerInfo->pdMsgType == kPD_MsgVendorDefined) &&
(triggerInfo->vdmHeader.bitFields.command == vdmMsgType) &&
(triggerInfo->vdmHeader.bitFields.commandType != (uint8_t)kVDM_Initiator) && (triggerInfo->pdMsgSop == sop))
{
if ((vdmMsgType == (uint8_t)kVDM_DiscoverIdentity) || (vdmMsgType == (uint8_t)kVDM_DiscoverSVIDs))
{
if (triggerInfo->vdmHeader.bitFields.SVID == PD_STANDARD_ID)
{
expected = 1;
}
}
else
{
expected = 1;
}
}
if (expected != 0U)
{
(void)PD_TimerClear(pdInstance, timr);
triggerInfo->triggerEvent = PSM_TRIGGER_NONE;
pdInstance->amsVdmReplyMsg = (pd_vdm_command_type_t)triggerInfo->vdmHeader.bitFields.commandType;
switch (pdInstance->amsVdmReplyMsg)
{
case kVDM_ResponderACK:
newStateTmp = ackState;
break;
case kVDM_ResponderBUSY:
newStateTmp = nakState;
break;
case kVDM_ResponderNAK:
if (vdmMsgType == (uint8_t)kVDM_ExitMode)
{
newStateTmp = ackState;
}
else
{
newStateTmp = nakState;
}
break;
default:
newStateTmp = nakState;
break;
}
}
else if (PD_TimerCheckInvalidOrTimeOut(pdInstance, timr) != 0U)
{
pdInstance->amsVdmReplyMsg = kVDM_ComandTypeInvalid;
newStateTmp = nakState;
}
else
{
/* TODO: AMS interrupt process */
}
return newStateTmp;
}
/*! ***************************************************************************
\brief Meet the requirement to terminate the msgSopP and kPD_MsgSOPp communications on
******************************************************************************/
#if defined(PD_CONFIG_SINK_ROLE_ENABLE) && (PD_CONFIG_SINK_ROLE_ENABLE)
static void PD_PsmSecondaryStateHandlerTerminate(pd_instance_t *pdInstance, start_of_packet_t sop)
{
uint8_t i;
if (sop == kPD_MsgSOPInvalid)
{
for (i = 0; i < 3U; i++)
{
pdInstance->psmNewSecondaryState[i] = PSM_IDLE;
}
}
else
{
if (pdInstance->psmSecondaryState[sop] != PSM_IDLE)
{
pdInstance->psmNewSecondaryState[sop] = PSM_IDLE;
}
}
}
#endif
/*! ***************************************************************************
\brief
\note Only called from CLP task context
******************************************************************************/
static uint8_t PD_PsmSecondaryStateHandler(pd_instance_t *pdInstance,
start_of_packet_t statIndex,
psm_trigger_info_t *triggerInfo)
{
uint8_t didNothingSecond = 0;
pd_psm_state_t secondNewState = PSM_UNKNOWN;
uint8_t index;
while (true)
{
/* global transition */
if (triggerInfo->triggerEvent == PSM_TRIGGER_PD_MSG)
{
/* sop has high priority */
if (statIndex != kPD_MsgSOP)
{
if (
#if defined(PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
(pdInstance->psmNewSecondaryState[statIndex] != PSM_PE_DFP_CBL_SEND_CABLE_RESET) &&
(pdInstance->psmSecondaryState[statIndex] != PSM_PE_DFP_CBL_SEND_CABLE_RESET) &&
(pdInstance->psmSecondaryState[statIndex] != PSM_PE_DFP_CBL_SEND_SOFT_RESET) &&
#endif
((pdInstance->psmNewSecondaryState[statIndex] != PSM_UNKNOWN) ||
(pdInstance->psmSecondaryState[statIndex] != PSM_IDLE)))
{
/* During PD Connection (Explicit Contract): */
/* o The DFP can communicate with a Cable Plug, using SOP' Packets or SOP" Packets, at any time it
*/
/* is not engaged in any other SOP Communications. */
/* o If SOP Packets are received by the DFP, during SOP' or SOP" Communication, the SOP' or SOP" */
/* Communication is immediately terminated (the Cable Plug times out and does not retry) */
/* o If the DFP needs to initiate an SOP Communication during an ongoing SOP' or SOP" Communication
*/
/* (e.g.for a Capabilities change) then the SOP' or SOP" Communications will be interrupted. */
/* Check for pending message on SOP */
/* Primary state machine needs to handle kPD_MsgSOP */
if (triggerInfo->pdMsgSop == kPD_MsgSOP)
{
/* Abort the current action */
pdInstance->psmNewSecondaryState[statIndex] = PSM_IDLE;
didNothingSecond = 1;
}
}
/* Allow soft reset to also interrupt with priority over cable resets */
if (triggerInfo->pdMsgType == kPD_MsgSoftReset)
{
/* Abort the current action */
pdInstance->psmNewSecondaryState[statIndex] = PSM_IDLE;
didNothingSecond = 1;
}
if (didNothingSecond != 0U)
{
return didNothingSecond;
}
}
}
/* global transition for dpm message */
if ((triggerInfo->triggerEvent == PSM_TRIGGER_DPM_MSG) &&
(triggerInfo->dpmMsg >= PD_DPM_CONTROL_DISCOVERY_IDENTITY))
{
if (((pdInstance->psmNewSecondaryState[statIndex] != PSM_UNKNOWN) ||
(pdInstance->psmSecondaryState[statIndex] != PSM_IDLE)) &&
(pdInstance->structuredVdmCommandParameter.vdmSop == (uint8_t)statIndex))
{
triggerInfo->triggerEvent = PSM_TRIGGER_NONE;
PD_PsmCommandFail(pdInstance, triggerInfo->dpmMsg);
}
}
/* State C */
if (pdInstance->psmNewSecondaryState[statIndex] != PSM_UNKNOWN)
{
pd_svdm_command_result_t commandVdmResult;
pdInstance->psmSecondaryState[statIndex] = pdInstance->psmNewSecondaryState[statIndex];
pdInstance->psmNewSecondaryState[statIndex] = PSM_UNKNOWN;
secondNewState = pdInstance->psmSecondaryState[statIndex];
commandVdmResult.vdmHeader.structuredVdmHeaderVal =
pdInstance->structuredVdmCommandParameter.vdmHeader.structuredVdmHeaderVal;
commandVdmResult.vdoSop = (uint8_t)triggerInfo->pdMsgSop;
switch (pdInstance->psmSecondaryState[statIndex])
{
case PSM_IDLE: /* C */
/* dpm message will callback */
break;
case PSM_PE_SRC_IMPLICIT_CABLE_SOFT_RESET: /* C */
if (PD_MsgSend(pdInstance, kPD_MsgSOPp, kPD_MsgSoftReset, 2, NULL) == kStatus_PD_Success)
{
(void)PD_TimerStart(pdInstance, tSenderResponseTimer, T_SENDER_RESPONSE);
}
else
{
secondNewState = PSM_IDLE;
}
break;
case PSM_PE_SRC_VDM_IDENTITY_REQUEST: /* C , only for sopp */
#if defined(PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
pdInstance->cableDiscoverIdentityCounter++;
secondNewState = PD_PsmStructuredVdmInitiatorRequest(pdInstance, statIndex, PD_STANDARD_ID, 0,
kVDM_DiscoverIdentity, 0, NULL);
#endif
break;
case PSM_PE_DFP_VDM_SVIDS_REQUEST: /* C */
secondNewState = PD_PsmStructuredVdmInitiatorRequest(pdInstance, statIndex, PD_STANDARD_ID, 0,
kVDM_DiscoverSVIDs, 0, NULL);
break;
case PSM_PE_DFP_VDM_MODES_REQUEST: /* C */
secondNewState = PD_PsmStructuredVdmInitiatorRequest(
pdInstance, statIndex,
(uint16_t)pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.SVID, 0,
kVDM_DiscoverModes, 0, NULL);
break;
case PSM_PE_DFP_VDM_MODE_ENTRY_REQUEST: /* C */
secondNewState = PD_PsmStructuredVdmInitiatorRequest(
pdInstance, statIndex,
(uint16_t)pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.SVID,
(uint8_t)pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.objPos, kVDM_EnterMode,
(pdInstance->structuredVdmCommandParameter.vdoCount != 0U) ? 1U : 0U,
(pdInstance->structuredVdmCommandParameter.vdoCount != 0U) ?
(pdInstance->structuredVdmCommandParameter.vdoData) :
NULL);
break;
case PSM_PE_DFP_VDM_MODE_EXIT_REQUEST: /* C */
secondNewState = PD_PsmStructuredVdmInitiatorRequest(
pdInstance, statIndex,
(uint16_t)pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.SVID,
(uint8_t)pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.objPos, kVDM_ExitMode, 0,
NULL);
break;
case PSM_PE_DFP_VDM_MODE_EXIT_HARD_RESET: /* C */
commandVdmResult.vdmCommand = (uint8_t)kVDM_ExitMode;
commandVdmResult.vdoData = NULL;
commandVdmResult.vdoCount = 0;
if (pdInstance->amsVdmReplyMsg == kVDM_ResponderBUSY)
{
commandVdmResult.vdmCommandResult = (uint8_t)kCommandResult_VDMBUSY;
}
else
{
/* time out or receive non-right message */
commandVdmResult.vdmCommandResult = (uint8_t)kCommandResult_Error;
}
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_FAIL, &commandVdmResult, 1);
secondNewState = PSM_IDLE;
pdInstance->psmNewState = PSM_HARD_RESET;
/* TODO: it may be CABLE. */
break;
case PSM_PE_DFP_VDM_ATTENTION_REQUEST: /* C */
secondNewState = PD_PsmStructuredVdmInitiatorRequest(
pdInstance, statIndex,
(uint16_t)pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.SVID,
(uint8_t)pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.objPos, kVDM_Attention,
(pdInstance->structuredVdmCommandParameter.vdoCount != 0U) ? 1U : 0U,
(pdInstance->structuredVdmCommandParameter.vdoCount != 0U) ?
(pdInstance->structuredVdmCommandParameter.vdoData) :
NULL);
commandVdmResult.vdmCommand = (uint8_t)kVDM_Attention;
commandVdmResult.vdoData = NULL;
commandVdmResult.vdoCount = 0;
if (secondNewState == PSM_IDLE)
{
commandVdmResult.vdmCommandResult = (uint8_t)kCommandResult_Error;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_FAIL, &commandVdmResult, 1);
}
else
{
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_SUCCESS, &commandVdmResult, 1);
}
break;
case PSM_PE_DFP_CBL_SEND_CABLE_RESET: /* C */
PD_MsgSendHardOrCableReset(pdInstance, 1);
secondNewState = PSM_IDLE;
break;
case PSM_PE_VENDOR_STRUCTURED_VDM_REQUEST: /* C */
secondNewState = PD_PsmStructuredVdmInitiatorRequest(
pdInstance, statIndex,
(uint16_t)pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.SVID,
(uint8_t)pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.objPos,
(pd_vdm_command_t)pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.command,
pdInstance->structuredVdmCommandParameter.vdoCount,
pdInstance->structuredVdmCommandParameter.vdoData);
if (pdInstance->structuredVdmCommandParameter.vendorVDMNeedResponse == 0U)
{
commandVdmResult.vdmCommand =
(uint8_t)pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.command;
commandVdmResult.vdoData = NULL;
commandVdmResult.vdoCount = 0;
if (secondNewState == pdInstance->psmSecondaryState[statIndex])
{
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_SUCCESS, &commandVdmResult, 1);
}
else
{
commandVdmResult.vdmCommandResult = (uint8_t)kCommandResult_Error;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_FAIL, &commandVdmResult, 1);
}
secondNewState = PSM_IDLE;
}
break;
case PSM_PE_SRC_VDM_IDENTITY_ACKED: /* C */
{
#if defined(PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
pd_id_header_vdo_t *headerVDO = (pd_id_header_vdo_t *)((void *)&pdInstance->psmCableIdentities[1]);
pdInstance->psmCableIdentitiesDataCount = triggerInfo->pdMsgDataLength;
for (index = 0; index < triggerInfo->pdMsgDataLength; ++index)
{
pdInstance->psmCableIdentities[index] =
USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(((uint8_t *)(triggerInfo->pdMsgDataBuffer + index)));
}
if ((headerVDO->bitFields.productTypeUFPOrCablePlug == VDM_ID_HEADER_VDO_PASSIVE_CABLE_VAL) ||
(headerVDO->bitFields.productTypeUFPOrCablePlug == VDM_ID_HEADER_VDO_ACTIVE_CABLE_VAL))
{
if (pdInstance->psmCableIdentitiesDataCount > 4U)
{
pd_passive_cable_vdo_vdm20_t *cableVDO =
(pd_passive_cable_vdo_vdm20_t *)((void *)&pdInstance->psmCableIdentities[4]);
switch (cableVDO->bitFields.vbusCurrentHandlingCapability)
{
case 0x01u:
pdInstance->dpmCableMaxCurrent = 3000 / 10; /* 3A */
break;
case 0x02u:
pdInstance->dpmCableMaxCurrent = 5000 / 10; /* 5A */
break;
default:
pdInstance->dpmCableMaxCurrent = 3000 / 10; /* 3A */
break;
}
}
}
secondNewState = PSM_IDLE;
#endif
break;
}
case PSM_PE_SRC_VDM_IDENTITY_NAKED: /* C */
for (index = 0; index < 7U; ++index)
{
pdInstance->psmCableIdentities[index] = 0;
}
secondNewState = PSM_IDLE;
break;
case PSM_PE_DFP_UFP_VDM_IDENTITY_REQUEST: /* C */
secondNewState = PD_PsmStructuredVdmInitiatorRequest(pdInstance, statIndex, PD_STANDARD_ID, 0,
kVDM_DiscoverIdentity, 0, NULL);
break;
case PSM_PE_DFP_UFP_VDM_IDENTITY_ACKED: /* C */
case PSM_PE_DFP_VDM_SVIDS_ACKED: /* C */
case PSM_PE_DFP_VDM_MODES_ACKED: /* C */
case PSM_PE_VENDOR_STRUCTURED_VDM_ACKED: /* C */
if (pdInstance->psmSecondaryState[statIndex] == PSM_PE_DFP_UFP_VDM_IDENTITY_ACKED)
{
commandVdmResult.vdmCommand = (uint8_t)kVDM_DiscoverIdentity;
}
else if (pdInstance->psmSecondaryState[statIndex] == PSM_PE_DFP_VDM_SVIDS_ACKED)
{
commandVdmResult.vdmCommand = (uint8_t)kVDM_DiscoverSVIDs;
}
else if (pdInstance->psmSecondaryState[statIndex] == PSM_PE_DFP_VDM_MODES_ACKED)
{
commandVdmResult.vdmCommand = (uint8_t)kVDM_DiscoverModes;
}
else if (pdInstance->psmSecondaryState[statIndex] == PSM_PE_VENDOR_STRUCTURED_VDM_ACKED)
{
commandVdmResult.vdmCommand = (uint8_t)commandVdmResult.vdmHeader.bitFields.command;
}
else
{
/* No action required. */
}
commandVdmResult.vdmHeader.structuredVdmHeaderVal =
USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(((uint8_t *)triggerInfo->pdMsgDataBuffer));
commandVdmResult.vdoData = triggerInfo->pdMsgDataBuffer + 1U;
commandVdmResult.vdoCount = triggerInfo->pdMsgDataLength - 1U;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_SUCCESS, &commandVdmResult, 1);
secondNewState = PSM_IDLE;
break;
case PSM_PE_DFP_VDM_MODE_ENTRY_ACKED: /* C */
commandVdmResult.vdmHeader.structuredVdmHeaderVal =
USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(((uint8_t *)triggerInfo->pdMsgDataBuffer));
commandVdmResult.vdmCommand = (uint8_t)kVDM_EnterMode;
commandVdmResult.vdoData = NULL;
commandVdmResult.vdoCount = 0;
pdInstance->psmVdmActiveModeValidMask |= (uint8_t)0x01U
<< (((uint8_t *)triggerInfo->pdMsgDataBuffer)[1] & 0x07U);
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_SUCCESS, &commandVdmResult, 1);
secondNewState = PSM_IDLE;
break;
case PSM_PE_DFP_VDM_MODE_EXIT_ACKED: /* C */
commandVdmResult.vdmCommand = (uint8_t)kVDM_ExitMode;
commandVdmResult.vdoData = NULL;
commandVdmResult.vdoCount = 0;
pdInstance->psmVdmActiveModeValidMask &=
~((uint8_t)0x01U << pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.objPos);
if (pdInstance->amsVdmReplyMsg == kVDM_ResponderACK)
{
commandVdmResult.vdmHeader.structuredVdmHeaderVal =
USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(((uint8_t *)triggerInfo->pdMsgDataBuffer));
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_SUCCESS, &commandVdmResult, 1);
}
else
{
commandVdmResult.vdmCommandResult = (uint8_t)kCommandResult_VDMNAK;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_FAIL, &commandVdmResult, 1);
}
#if (defined PD_CONFIG_ALT_MODE_SUPPORT) && (PD_CONFIG_ALT_MODE_SUPPORT)
/* DFP issues DR Swap to trigger Exit mode? */
if ((pdInstance->drSwapTriggerExitMode != 0U) && (pdInstance->psmVdmActiveModeValidMask == 0U))
{
/* After exiting active mode, need to trigger DR Swap again. */
pdInstance->drSwapTriggerExitMode = 0;
(void)PD_Command(pdInstance, (uint32_t)PD_DPM_CONTROL_DR_SWAP, NULL);
}
#endif
secondNewState = PSM_IDLE;
break;
case PSM_PE_DFP_UFP_VDM_IDENTITY_NAKED: /* C */
case PSM_PE_DFP_VDM_SVIDS_NAKED: /* C */
case PSM_PE_DFP_VDM_MODES_NAKED: /* C */
case PSM_PE_DFP_VDM_MODE_ENTRY_NAKED: /* C */
case PSM_PE_VENDOR_STRUCTURED_VDM_NAKED: /* C */
switch (pdInstance->psmSecondaryState[statIndex])
{
case PSM_PE_DFP_UFP_VDM_IDENTITY_NAKED:
commandVdmResult.vdmCommand = (uint8_t)kVDM_DiscoverIdentity;
break;
case PSM_PE_DFP_VDM_SVIDS_NAKED:
commandVdmResult.vdmCommand = (uint8_t)kVDM_DiscoverSVIDs;
break;
case PSM_PE_DFP_VDM_MODES_NAKED:
commandVdmResult.vdmCommand = (uint8_t)kVDM_DiscoverModes;
break;
case PSM_PE_DFP_VDM_MODE_ENTRY_NAKED:
commandVdmResult.vdmCommand = (uint8_t)kVDM_EnterMode;
break;
case PSM_PE_VENDOR_STRUCTURED_VDM_NAKED:
commandVdmResult.vdmCommand =
(uint8_t)pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.command;
break;
default:
/* No action required. */
break;
}
commandVdmResult.vdoData = NULL;
commandVdmResult.vdoCount = 0;
if (pdInstance->amsVdmReplyMsg == kVDM_ResponderNAK)
{
commandVdmResult.vdmCommandResult = (uint8_t)kCommandResult_VDMNAK;
}
else if (pdInstance->amsVdmReplyMsg == kVDM_ResponderBUSY)
{
(void)PD_TimerStart(pdInstance, tVDMBusyTimer, T_VDM_BUSY);
commandVdmResult.vdmCommandResult = (uint8_t)kCommandResult_VDMBUSY;
}
else
{
/* time out or receive non-right message */
commandVdmResult.vdmCommandResult = (uint8_t)kCommandResult_Error;
}
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_FAIL, &commandVdmResult, 1);
secondNewState = PSM_IDLE;
break;
#if ((defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE))
case PSM_PD_SEND_UNSTRUCTURED_VDM: /* C */
{
pd_status_t status = PD_MsgSend(
pdInstance, (start_of_packet_t)pdInstance->unstructuredVdmCommandParameter.vdmSop,
kPD_MsgVendorDefined,
(uint32_t)pdInstance->unstructuredVdmCommandParameter.vdmHeaderAndVDOsCount * 4U + 2U,
(uint8_t *)pdInstance->unstructuredVdmCommandParameter.vdmHeaderAndVDOsData);
if (status == kStatus_PD_Success)
{
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SEND_UNSTRUCTURED_VDM_SUCCESS, NULL, 1);
}
else
{
pd_command_result_t commandResultCallback = kCommandResult_Error;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_SEND_UNSTRUCTURED_VDM_FAIL, &commandResultCallback,
1);
}
secondNewState = PSM_IDLE;
break;
}
#endif
default:
/* No action required. */
break;
}
PD_PsmEndVdmCommand(pdInstance, pdInstance->psmSecondaryState[statIndex]);
if (secondNewState != pdInstance->psmSecondaryState[statIndex])
{
pdInstance->psmNewSecondaryState[statIndex] = secondNewState;
continue;
}
}
/* state B */
secondNewState = pdInstance->psmSecondaryState[statIndex];
switch (pdInstance->psmSecondaryState[statIndex])
{
case PSM_IDLE: /* B */
if (triggerInfo->triggerEvent == PSM_TRIGGER_PD_MSG)
{
PD_PsmVdmIdleProcessPdMessage(pdInstance, statIndex, triggerInfo);
}
else if (triggerInfo->triggerEvent == PSM_TRIGGER_DPM_MSG)
{
secondNewState = PD_PsmVdmIdleProcessDpmMessage(pdInstance, statIndex, triggerInfo);
}
else
{
/* No action required. */
}
/* Used to response to a ACK/NAK VDM message.
Prevent that psmSecondaryState is not equal to PSM_IDLE when receiving a Exit Mode command. */
if (pdInstance->vdmExitReceived[statIndex] != 0U)
{
pd_svdm_command_request_t commandVdmRequest;
pd_structured_vdm_header_t reponseVdmHeader;
commandVdmRequest.vdmHeader.structuredVdmHeaderVal = pdInstance->vdmExitReceived[statIndex];
pdInstance->vdmExitReceived[statIndex] = 0;
commandVdmRequest.vdoSop = (uint8_t)triggerInfo->pdMsgSop;
(void)PD_DpmAppCallback(pdInstance, PD_DPM_STRUCTURED_VDM_REQUEST, &commandVdmRequest, 0);
reponseVdmHeader.structuredVdmHeaderVal = commandVdmRequest.vdmHeader.structuredVdmHeaderVal;
if (commandVdmRequest.requestResultStatus == (uint8_t)kCommandResult_VDMACK)
{
reponseVdmHeader.bitFields.commandType = (uint32_t)kVDM_ResponderACK;
(void)PD_MsgSendStructuredVDM(pdInstance, statIndex, reponseVdmHeader,
commandVdmRequest.vdoCount,
(uint32_t *)commandVdmRequest.vdoData);
}
else
{
reponseVdmHeader.bitFields.commandType = (uint32_t)kVDM_ResponderNAK;
(void)PD_MsgSendStructuredVDM(pdInstance, statIndex, reponseVdmHeader, 0, NULL);
}
}
break;
case PSM_PE_DFP_UFP_VDM_VDM_BUSY_WAIT: /* B */
if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tVDMBusyTimer) != 0U)
{
secondNewState = pdInstance->psmVDMBusyWaitDpmMsg;
}
break;
case PSM_PE_SRC_IMPLICIT_CABLE_SOFT_RESET: /* B */
if ((triggerInfo->triggerEvent == PSM_TRIGGER_PD_MSG) && (triggerInfo->pdMsgSop == statIndex) &&
(triggerInfo->pdMsgType == kPD_MsgAccept))
{
(void)PD_TimerClear(pdInstance, tSenderResponseTimer);
secondNewState = PSM_PE_SRC_VDM_IDENTITY_REQUEST;
}
else if (PD_TimerCheckInvalidOrTimeOut(pdInstance, tSenderResponseTimer) != 0U)
{
secondNewState = PSM_IDLE;
}
else
{
didNothingSecond = 1;
}
break;
case PSM_PE_SRC_VDM_IDENTITY_REQUEST: /* B */
#if defined(PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
secondNewState = PD_PsmVdmResponseHandler(pdInstance, statIndex, (uint8_t)kVDM_DiscoverIdentity,
triggerInfo, tVDMResponseTimer, PSM_PE_SRC_VDM_IDENTITY_ACKED,
PSM_PE_SRC_VDM_IDENTITY_NAKED);
#endif
break;
case PSM_PE_DFP_UFP_VDM_IDENTITY_REQUEST: /* B */
secondNewState = PD_PsmVdmResponseHandler(
pdInstance, statIndex, (uint8_t)kVDM_DiscoverIdentity, triggerInfo, tVDMResponseTimer,
PSM_PE_DFP_UFP_VDM_IDENTITY_ACKED, PSM_PE_DFP_UFP_VDM_IDENTITY_NAKED);
break;
case PSM_PE_DFP_VDM_SVIDS_REQUEST: /* B */
secondNewState =
PD_PsmVdmResponseHandler(pdInstance, statIndex, (uint8_t)kVDM_DiscoverSVIDs, triggerInfo,
tVDMResponseTimer, PSM_PE_DFP_VDM_SVIDS_ACKED, PSM_PE_DFP_VDM_SVIDS_NAKED);
break;
case PSM_PE_DFP_VDM_MODES_REQUEST: /* B */
secondNewState =
PD_PsmVdmResponseHandler(pdInstance, statIndex, (uint8_t)kVDM_DiscoverModes, triggerInfo,
tVDMResponseTimer, PSM_PE_DFP_VDM_MODES_ACKED, PSM_PE_DFP_VDM_MODES_NAKED);
break;
case PSM_PE_DFP_VDM_MODE_ENTRY_REQUEST: /* B */
secondNewState = PD_PsmVdmResponseHandler(pdInstance, statIndex, (uint8_t)kVDM_EnterMode, triggerInfo,
tVDMModeEntryTimer, PSM_PE_DFP_VDM_MODE_ENTRY_ACKED,
PSM_PE_DFP_VDM_MODE_ENTRY_NAKED);
break;
/* The Responder shall not return a BUSY acknowledgement and shall
only return a NAK acknowledgement to a request not containing an Active Mode (i.e. Invalid object
position). An
Initiator which fails to receive an ACK within tVDMWaitModeExit or receives a NAK or BUSY response shall
exit its
Active Mode. */
case PSM_PE_DFP_VDM_MODE_EXIT_REQUEST: /* B */
secondNewState = PD_PsmVdmResponseHandler(pdInstance, statIndex, (uint8_t)kVDM_ExitMode, triggerInfo,
tVDMModeExitTimer, PSM_PE_DFP_VDM_MODE_EXIT_ACKED,
PSM_PE_DFP_VDM_MODE_EXIT_HARD_RESET);
break;
case PSM_PE_DFP_VDM_ATTENTION_REQUEST: /* B */
secondNewState = PSM_IDLE;
break;
case PSM_PE_VENDOR_STRUCTURED_VDM_REQUEST: /* B */
secondNewState = PD_PsmVdmResponseHandler(
pdInstance, statIndex,
(uint8_t)pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.command, triggerInfo,
tVDMResponseTimer, PSM_PE_VENDOR_STRUCTURED_VDM_ACKED, PSM_PE_VENDOR_STRUCTURED_VDM_NAKED);
break;
default:
/* No action required. */
break;
}
if ((secondNewState != PSM_UNKNOWN) && (secondNewState != pdInstance->psmSecondaryState[statIndex]))
{
pdInstance->psmNewSecondaryState[statIndex] = secondNewState;
continue;
}
return didNothingSecond;
}
}
#endif
#if (defined PD_CONFIG_CABLE_COMMUNICATION_ENABLE) && (PD_CONFIG_CABLE_COMMUNICATION_ENABLE)
static uint8_t PD_CheckWhetherInitiateCableDiscoveryIdentityOrNot(pd_instance_t *pdInstance)
{
if (((pdInstance->raPresent != 0U) || (pdInstance->initialPowerRole == kPD_PowerRoleSink)) &&
(pdInstance->psmPresentlyVconnSource == kPD_IsVconnSource) && (pdInstance->psmCableIdentitiesDataCount == 0U) &&
(pdInstance->cableDiscoverIdentityCounter < N_DISCOVER_IDENTITY_COUNTER))
{
return 1;
}
return 0;
}
#endif
static pd_state_machine_state_t PD_PsmStateMachine(pd_instance_t *pdInstance)
{
pd_state_machine_state_t returnVal = kSM_Continue;
/* Did we do anything in Step A or B or C */
/* Step A: common process */
/* Step B: state is not changed */
/* Step C: change to new state */
do
{
returnVal = PD_PsmEnterState(pdInstance);
returnVal = PD_PsmDisconnectCheck(pdInstance, returnVal);
if ((returnVal != kSM_ErrorRecovery) && (returnVal != kSM_Detach))
{
returnVal = PD_PsmProcessState(pdInstance);
returnVal = PD_PsmDisconnectCheck(pdInstance, returnVal);
}
} while (((pdInstance->psmCurState != pdInstance->psmNewState) || (returnVal == kSM_Continue)) &&
(returnVal != kSM_ErrorRecovery) && (returnVal != kSM_Detach));
if ((returnVal == kSM_ErrorRecovery) || (returnVal == kSM_Detach))
{
PD_TimerCancelAllTimers(pdInstance, _tStartTimer, _tMaxDpmTimer);
}
return returnVal;
}
static pd_status_t PD_DpmAppCallback(pd_instance_t *pdInstance,
pd_dpm_callback_event_t event,
void *param,
uint8_t done)
{
pd_status_t status1 = kStatus_PD_Error;
#if (defined PD_CONFIG_ALT_MODE_SUPPORT) && (PD_CONFIG_ALT_MODE_SUPPORT)
pd_status_t status2 = kStatus_PD_Error;
#endif
if (done != 0U)
{
#if defined(PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE) && (PD_CONFIG_PD3_AMS_COLLISION_AVOID_ENABLE)
PD_MsgSrcEndCommand(pdInstance);
#endif
/* in case the power is not reset to normal operation */
#if (defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
if (pdInstance->inProgress != kVbusPower_InFRSwap)
#endif
{
PD_ConnectSetPowerProgress(pdInstance, kVbusPower_Stable);
}
pdInstance->commandProcessing = PD_DPM_INVALID;
}
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
if (pdInstance->dumpResponse != 0U)
{
pdInstance->dumpResponse = 0;
}
else
#endif
{
#if (defined PD_CONFIG_ALT_MODE_SUPPORT) && (PD_CONFIG_ALT_MODE_SUPPORT)
status2 = PD_AltModeCallback(pdInstance, (uint32_t)event, param);
#endif
status1 = pdInstance->pdCallback(pdInstance->callbackParam, (uint32_t)event, param);
#if (defined PD_CONFIG_ALT_MODE_SUPPORT) && (PD_CONFIG_ALT_MODE_SUPPORT)
if ((status1 == kStatus_PD_Success) || (status2 == kStatus_PD_Success))
{
return kStatus_PD_Success;
}
#endif
}
return status1;
}
#if defined(PD_CONFIG_PHY_LOW_POWER_LEVEL) && (PD_CONFIG_PHY_LOW_POWER_LEVEL)
static void PD_LowPowerTransition(pd_instance_t *pdInstance)
{
pd_stack_state_t getInfo = kState_Busy;
(void)PD_Control(pdInstance, (uint32_t)PD_CONTROL_GET_PD_STATE, &getInfo);
if ((getInfo == kState_Idle) && (pdInstance->lowPowerState == 0u))
{
/* PD stack idle && not in low power state */
(void)pdInstance->phyInterface->pdPhyControl(pdInstance, PD_PHY_ENTER_LOW_POWER_STATE, NULL);
}
else if ((getInfo == kState_Busy) && (pdInstance->lowPowerState != 0u))
{
/* PD stack busy && in low power state */
(void)pdInstance->phyInterface->pdPhyControl(pdInstance, PD_PHY_EXIT_LOW_POWER_STATE, NULL);
}
else
{
/* No action required. */
}
}
#endif
static pd_status_t PD_InitiateAmsCheck(pd_instance_t *pdInstance, pd_command_t command)
{
pd_status_t status = kStatus_PD_Busy;
if ((pdInstance->psmCurState != PSM_PE_SRC_READY) && (pdInstance->psmCurState != PSM_PE_SNK_READY))
{
}
else if (pdInstance->commandProcessing != PD_DPM_INVALID)
{
}
else if (pdInstance->inProgress != kVbusPower_Stable)
{
}
else
{
status = kStatus_PD_Success;
}
return status;
}
uint8_t PD_PsmCheckVsafe0V(pd_instance_t *pdInstance)
{
uint8_t powerState = PD_VBUS_POWER_STATE_VSAFE0V_MASK;
(void)PD_PhyControl(pdInstance, PD_PHY_GET_VBUS_POWER_STATE, &powerState);
if ((powerState & PD_VBUS_POWER_STATE_VSAFE0V_MASK) != 0U)
{
return 1;
}
return 0;
}
uint8_t PD_PsmCheckVsafe5V(pd_instance_t *pdInstance)
{
uint8_t powerState = (PD_VBUS_POWER_STATE_VSAFE5V_MASK | PD_VBUS_POWER_STATE_VBUS_MASK);
(void)PD_PhyControl(pdInstance, PD_PHY_GET_VBUS_POWER_STATE, &powerState);
if ((powerState & (PD_VBUS_POWER_STATE_VSAFE5V_MASK | PD_VBUS_POWER_STATE_VBUS_MASK)) != 0U)
{
return 1;
}
return 0;
}
/* 0 - timeout, other values - the remaining time. */
uint16_t PD_PsmTimerWait(pd_instance_t *pdInstance, tTimer_t timrName, uint16_t timrTime, uint32_t checkEvent)
{
uint32_t eventSet = 0;
(void)PD_TimerStart(pdInstance, timrName, timrTime);
do
{
(void)OSA_EventWait(pdInstance->taskEventHandle, PD_TASK_EVENT_ALL, 0, (uint32_t)timrTime, &eventSet);
PD_PortTaskEventProcess(pdInstance, eventSet);
if ((PD_TimerCheckInvalidOrTimeOut(pdInstance, timrName) != 0U) && ((eventSet & PD_TASK_EVENT_TIME_OUT) != 0U))
{
break;
}
else if ((eventSet & checkEvent) != 0U)
{
break;
}
/* Disconnected */
else if (PD_ConnectCheck(pdInstance) == kConnectState_Disconnected)
{
break;
}
else
{
/* No action required. */
}
} while (true);
(void)PD_TimerClear(pdInstance, timrName);
return pdInstance->timrsTimeValue[(uint8_t)timrName];
}
/*! ***************************************************************************
task process related functions
******************************************************************************/
void PD_PortTaskEventProcess(pd_instance_t *pdInstance, uint32_t eventSet)
{
if ((eventSet & (uint32_t)PD_TASK_EVENT_PHY_STATE_CHAGNE) != 0U)
{
(void)PD_PhyControl(pdInstance, PD_PHY_UPDATE_STATE, NULL);
}
if (pdInstance->dpmStateMachine == 0U)
{
/* clear events, and only respond to PHY event and FR swap event in the detached state. */
eventSet &= ~(uint32_t)((uint32_t)PD_TASK_EVENT_PHY_STATE_CHAGNE | (uint32_t)PD_TASK_EVENT_FR_SWAP_SINGAL);
if (eventSet != 0U)
{
(void)OSA_EventClear(pdInstance->taskEventHandle, eventSet);
}
}
else
{
/* If PD state machine is running, only clear other event, and other events will be handled later. */
if ((eventSet & (uint32_t)PD_TASK_EVENT_OTHER) != 0U)
{
(void)OSA_EventClear(pdInstance->taskEventHandle, PD_TASK_EVENT_OTHER);
}
}
}
void PD_StackStateMachine(pd_instance_t *pdInstance)
{
uint32_t taskEventSet = 0;
TypeCState_t typecState;
pd_connect_state_t connectState;
pd_state_machine_state_t smState = kSM_None;
uint8_t connected;
if (pdInstance->initializeLabel == 0U)
{
pdInstance->initializeLabel = 1;
pdInstance->isConnected = 0;
/* We want to override any existing MTP-based connection */
PD_ConnectInitRole(pdInstance, 0);
pdInstance->connectedResult = PD_ConnectGetStateMachine(pdInstance);
#if defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
PD_DpmSetVconn(pdInstance, 0);
#endif /* PD_CONFIG_VCONN_SUPPORT */
}
#if defined(PD_CONFIG_PHY_LOW_POWER_LEVEL) && (PD_CONFIG_PHY_LOW_POWER_LEVEL)
PD_LowPowerTransition(pdInstance);
#endif
#if (defined PD_CONFIG_COMMON_TASK) && (PD_CONFIG_COMMON_TASK)
(void)OSA_EventWait(pdInstance->taskEventHandle, PD_TASK_EVENT_ALL, 0, 0, &taskEventSet);
#else
(void)OSA_EventWait(pdInstance->taskEventHandle, PD_TASK_EVENT_ALL, 0, pdInstance->taskWaitTime, &taskEventSet);
#endif
/* if waiting for ever and no event */
#ifndef SDK_OS_FREE_RTOS
if ((pdInstance->taskWaitTime == osaWaitForever_c) && (taskEventSet == 0u))
{
return;
}
#endif
#if defined(PD_CONFIG_PHY_LOW_POWER_LEVEL) && (PD_CONFIG_PHY_LOW_POWER_LEVEL)
PD_LowPowerTransition(pdInstance);
#endif
PD_PortTaskEventProcess(pdInstance, taskEventSet);
/* Process Type-C state change by PD stack */
typecState = PD_ConnectGetStateMachine(pdInstance);
if (typecState != pdInstance->connectedResult)
{
pdInstance->connectedResult = typecState;
}
/* Process Type-C state change by Type-C state machine */
connectState = PD_ConnectCheck(pdInstance);
typecState = PD_ConnectGetStateMachine(pdInstance);
if (connectState != kConnectState_NotStable)
{
if (connectState == kConnectState_Connected)
{
connected = 1;
}
else
{
connected = 0;
}
/* connect state change */
if ((connected != pdInstance->isConnected) ||
((pdInstance->isConnected != 0U) && (typecState != pdInstance->connectedResult)))
{
if (connected != 0U)
{
switch (typecState)
{
case TYPEC_ATTACHED_SRC:
case TYPEC_ATTACHED_SNK:
pdInstance->pendingSOP = (uint8_t)kPD_MsgSOPMask;
if (typecState == TYPEC_ATTACHED_SRC)
{
pdInstance->curPowerRole = kPD_PowerRoleSource;
pdInstance->initialPowerRole = kPD_PowerRoleSource;
pdInstance->curDataRole = kPD_DataRoleDFP;
pdInstance->psmPresentlyVconnSource = kPD_IsVconnSource;
}
else
{
pdInstance->curPowerRole = kPD_PowerRoleSink;
pdInstance->initialPowerRole = kPD_PowerRoleSink;
pdInstance->curDataRole = kPD_DataRoleUFP;
pdInstance->psmPresentlyVconnSource = kPD_NotVconnSource;
}
break;
case TYPEC_AUDIO_ACCESSORY:
case TYPEC_UNORIENTED_DEBUG_ACCESSORY_SRC:
case TYPEC_DEBUG_ACCESSORY_SNK:
case TYPEC_ORIENTED_DEBUG_ACCESSORY_SNK:
case TYPEC_POWERED_ACCESSORY:
/* do nothing */
/* pdInstance->curPowerRole = kPD_PowerRoleSource; */
/* pdInstance->curDataRole = kPD_DataRoleDFP; */
break;
#if (defined PD_CONFIG_DEBUG_ACCESSORY_SUPPORT) && (PD_CONFIG_DEBUG_ACCESSORY_SUPPORT)
case TYPEC_ORIENTED_DEBUG_ACCESSORY_SRC:
if (PD_CONFIG_DEBUG_ACCESSORY_ROLE == CONFIG_DEBUG_ACCESSORY_NONE)
{
/* Wait for disconnection */
}
else
{
pdInstance->curPowerRole = kPD_PowerRoleSource;
pdInstance->initialPowerRole = kPD_PowerRoleSource;
pdInstance->curDataRole = kPD_DataRoleDFP;
pdInstance->psmPresentlyVconnSource = kPD_IsVconnSource;
}
break;
#endif
default:
/* No action required. */
break;
}
/* change from disconnect to connect */
if (pdInstance->isConnected == 0U)
{
(void)PD_DpmAppCallback(pdInstance, PD_CONNECTED, NULL, 0);
PD_PsmConnect(pdInstance);
}
/* still connect, but role change. For example: Try.SRC */
else if (typecState != pdInstance->connectedResult)
{
pdInstance->psmNewState = PSM_IDLE;
(void)PD_DpmAppCallback(pdInstance, PD_CONNECT_ROLE_CHANGE, NULL, 0);
}
else
{
/* No action required. */
}
}
/* change from connect to disconnect */
else if (pdInstance->isConnected != 0U)
{
PD_PsmDisconnect(pdInstance);
(void)PD_DpmAppCallback(pdInstance, PD_DISCONNECTED, NULL, 0);
pdInstance->initializeLabel = 0;
PD_StackSetEvent(pdInstance, PD_TASK_EVENT_RESET_CONFIGURE);
}
else
{
/* No action required. */
}
pdInstance->isConnected = connected;
}
else if (pdInstance->isConnected != 0U) /* connect result stable and connected */
{
pdInstance->noConnectButVBusExist = 0;
if (pdInstance->dpmStateMachine != 0U)
{
smState = PD_PsmStateMachine(pdInstance);
}
else
{
/* wait vbus charge */
/* Neither Source nor Sink should enter PSM before VSafe5V is available */
if (PD_PsmCheckVsafe5V(pdInstance) != 0U)
{
pdInstance->dpmStateMachine = 1;
pdInstance->psmNewState = PSM_IDLE;
smState = PD_PsmStateMachine(pdInstance);
}
}
/* Force a partner disconnect if the PSM has requested a error recovery */
if ((smState == kSM_ErrorRecovery) || (smState == kSM_Detach))
{
pdInstance->isConnected = 0;
PD_PsmDisconnect(pdInstance);
if (smState == kSM_ErrorRecovery)
{
PD_ConnectInitRole(pdInstance, 1);
pdInstance->initializeLabel = 1;
}
else
{
pdInstance->initializeLabel = 0;
}
(void)PD_DpmAppCallback(pdInstance, PD_DISCONNECTED, NULL, 0);
PD_StackSetEvent(pdInstance, PD_TASK_EVENT_RESET_CONFIGURE);
}
else if (smState == kSM_Continue)
{
pdInstance->taskWaitTime = PD_WAIT_EVENT_TIME;
}
else
{
pdInstance->taskWaitTime = osaWaitForever_c; /* wait forever */
}
}
else
{
/* No action required. */
}
#if (defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
/* check FR_Swap signal */
(void)OSA_EventGet(pdInstance->taskEventHandle, PD_TASK_EVENT_FR_SWAP_SINGAL, &taskEventSet);
if (taskEventSet != 0U)
{
if (pdInstance->isConnected == 0U)
{
(void)OSA_EventClear(pdInstance->taskEventHandle, PD_TASK_EVENT_FR_SWAP_SINGAL);
/* when receiving FR_Swap signal, PTN5110 will open source vbus defaultly. */
if (pdInstance->pdConfig->phyType == (uint8_t)kPD_PhyPTN5110)
{
(void)pdInstance->callbackFns->PD_SrcTurnOffVbus(pdInstance->callbackParam, kVbusPower_Stable);
}
}
}
/* check unreasonable situation */
if (pdInstance->isConnected == 0U)
{
if (PD_PsmCheckVsafe5V(pdInstance) != 0U)
{
pdInstance->noConnectButVBusExist++;
PD_PsmTurnOffVconnAndVbus(pdInstance, kVbusPower_Stable);
if (pdInstance->noConnectButVBusExist >= 100U)
{
connected = 1; /* connected means enablement here. */
pdInstance->noConnectButVBusExist = 0;
(void)pdInstance->phyInterface->pdPhyDeinit(pdInstance);
(void)pdInstance->phyInterface->pdPhyInit(pdInstance);
(void)pdInstance->phyInterface->pdPhyControl(pdInstance, PD_PHY_CONTROL_ALERT_INTERRUPT,
&connected);
}
}
}
else
{
pdInstance->noConnectButVBusExist = 0;
}
#endif
}
pdInstance->connectedResult = typecState;
#if 0
/* unclear error recovery */
connectStatus = PD_ConnectGetStateMachine(pdInstance);
if (connectStatus == PD_ConnectGetInitRoleState(pdInstance))
{
pdInstance->typeCStateNeedRecovery++;
}
else
{
pdInstance->typeCStateNeedRecovery = 0;
}
if ((!(pdInstance->isConnected)) && (pdInstance->typeCStateNeedRecovery >= 100))
{
pdInstance->typeCStateNeedRecovery = 0;
PD_ConnectInitRole(pdInstance, 1);
}
#endif
}
void PD_DpmDischargeVbus(pd_instance_t *pdInstance, uint8_t enable)
{
(void)PD_PhyControl(pdInstance, PD_PHY_DISCHARGE_VBUS, &enable);
}
#if defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
void PD_DpmDischargeVconn(pd_instance_t *pdInstance, uint8_t enable)
{
(void)PD_PhyControl(pdInstance, PD_PHY_DISCHARGE_VCONN, &enable);
}
void PD_DpmSetVconn(pd_instance_t *pdInstance, uint8_t enable)
{
if ((pdInstance->pdPowerPortConfig->vconnSupported != 0U) && (pdInstance->callbackFns->PD_ControlVconn != NULL))
{
(void)pdInstance->callbackFns->PD_ControlVconn(pdInstance->callbackParam, enable);
}
}
#endif /* PD_CONFIG_VCONN_SUPPORT */
/* change to command and is async */
pd_status_t PD_Command(pd_handle pdHandle, uint32_t command, void *param)
{
pd_status_t status;
pd_instance_t *pdInstance = (pd_instance_t *)pdHandle;
/* Check if an AMS can be initiated */
status = PD_InitiateAmsCheck(pdInstance, (pd_command_t)command);
#if (defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE)
/* common process */
switch ((pd_command_t)command)
{
case PD_DPM_CONTROL_DISCOVERY_IDENTITY:
case PD_DPM_CONTROL_DISCOVERY_SVIDS:
case PD_DPM_CONTROL_DISCOVERY_MODES:
{
pdInstance->structuredVdmCommandParameter = *((pd_svdm_command_param_t *)param);
pdInstance->structuredVdmCommandParameter.vdoCount = 0;
pdInstance->structuredVdmCommandParameter.vdoData = NULL;
pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.commandType = (uint8_t)kVDM_Initiator;
pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.objPos = 0;
#if defined(PD_CONFIG_REVISION) && (PD_CONFIG_REVISION >= PD_SPEC_REVISION_30)
pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.vdmVersion =
(pdInstance->revision < PD_SPEC_REVISION_30) ? PD_SPEC_STRUCTURED_VDM_VERSION_10 :
PD_CONFIG_STRUCTURED_VDM_VERSION;
#else
pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.vdmVersion =
PD_SPEC_STRUCTURED_VDM_VERSION_10;
#endif
pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.vdmType = 1;
if ((command == (uint32_t)PD_DPM_CONTROL_DISCOVERY_IDENTITY) ||
(command == (uint32_t)PD_DPM_CONTROL_DISCOVERY_SVIDS))
{
pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.SVID = PD_STANDARD_ID;
}
break;
}
case PD_DPM_SEND_VENDOR_STRUCTURED_VDM:
case PD_DPM_CONTROL_ENTER_MODE:
case PD_DPM_CONTROL_EXIT_MODE:
case PD_DPM_CONTROL_SEND_ATTENTION:
{
pdInstance->structuredVdmCommandParameter = *((pd_svdm_command_param_t *)param);
pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.commandType = (uint8_t)kVDM_Initiator;
#if defined(PD_CONFIG_REVISION) && (PD_CONFIG_REVISION >= PD_SPEC_REVISION_30)
pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.vdmVersion =
(pdInstance->revision < PD_SPEC_REVISION_30) ? PD_SPEC_STRUCTURED_VDM_VERSION_10 :
PD_CONFIG_STRUCTURED_VDM_VERSION;
#else
pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.vdmVersion =
PD_SPEC_STRUCTURED_VDM_VERSION_10;
#endif
pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.vdmType = 1;
if (command == (uint32_t)PD_DPM_CONTROL_EXIT_MODE)
{
pdInstance->structuredVdmCommandParameter.vdoCount = 0;
pdInstance->structuredVdmCommandParameter.vdoData = NULL;
}
break;
}
default:
/* No action required. */
break;
}
#endif
/* special process */
switch ((pd_command_t)command)
{
case PD_DPM_CONTROL_POWER_NEGOTIATION:
{
if (pdInstance->curPowerRole != kPD_PowerRoleSource)
{
status = kStatus_PD_Error;
}
break;
}
case PD_DPM_CONTROL_REQUEST:
{
if (pdInstance->curPowerRole == kPD_PowerRoleSink)
{
pdInstance->rdoRequest.rdoVal = *((uint32_t *)param);
}
else
{
status = kStatus_PD_Error;
}
break;
}
case PD_DPM_CONTROL_GOTO_MIN:
{
if (pdInstance->psmCurState != PSM_PE_SRC_READY)
{
status = kStatus_PD_Error;
}
break;
}
#if (defined PD_CONFIG_DUAL_POWER_ROLE_ENABLE) && (PD_CONFIG_DUAL_POWER_ROLE_ENABLE)
case PD_DPM_CONTROL_PR_SWAP:
{
if (PD_PsmIsDualRole(pdInstance) == 0U)
{
status = kStatus_PD_Error;
}
break;
}
#endif
#if (defined PD_CONFIG_DUAL_DATA_ROLE_ENABLE) && (PD_CONFIG_DUAL_DATA_ROLE_ENABLE)
case PD_DPM_CONTROL_DR_SWAP:
{
if (pdInstance->pdPowerPortConfig->dataFunction != (uint8_t)kDataConfig_DRD)
{
status = kStatus_PD_Error;
}
break;
}
#endif
#if (defined PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
case PD_DPM_CONTROL_VCONN_SWAP:
{
if (pdInstance->pdPowerPortConfig->vconnSupported == 0U)
{
status = kStatus_PD_Error;
}
break;
}
#endif
#if (defined PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
case PD_DPM_GET_SRC_EXT_CAP:
#endif
case PD_DPM_CONTROL_GET_PARTNER_SOURCE_CAPABILITIES:
{
if (pdInstance->pdPowerPortConfig->typecRole == (uint8_t)kPowerConfig_SourceOnly)
{
status = kStatus_PD_Error;
}
break;
}
case PD_DPM_CONTROL_GET_PARTNER_SINK_CAPABILITIES:
{
if (pdInstance->pdPowerPortConfig->typecRole == (uint8_t)kPowerConfig_SinkOnly)
{
status = kStatus_PD_Error;
}
break;
}
case PD_DPM_CONTROL_SOFT_RESET:
pdInstance->psmSoftResetSop = *((start_of_packet_t *)param);
break;
case PD_DPM_CONTROL_HARD_RESET:
/* Hard Reset is always success, whether PD stack is idle or not. */
status = kStatus_PD_Success;
break;
#if (defined PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE) && (PD_CONFIG_VENDOR_DEFINED_MESSAGE_ENABLE)
case PD_DPM_CONTROL_DISCOVERY_IDENTITY:
{
pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.command = (uint8_t)kVDM_DiscoverIdentity;
break;
}
case PD_DPM_CONTROL_DISCOVERY_SVIDS:
{
pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.command = (uint8_t)kVDM_DiscoverSVIDs;
break;
}
case PD_DPM_CONTROL_DISCOVERY_MODES:
{
pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.command = (uint8_t)kVDM_DiscoverModes;
break;
}
case PD_DPM_CONTROL_SEND_ATTENTION:
{
pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.command = (uint8_t)kVDM_Attention;
break;
}
case PD_DPM_SEND_VENDOR_STRUCTURED_VDM:
{
break;
}
case PD_DPM_CONTROL_ENTER_MODE:
{
pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.command = (uint8_t)kVDM_EnterMode;
if (pdInstance->curDataRole != kPD_DataRoleDFP)
{
status = kStatus_PD_Error;
}
break;
}
case PD_DPM_CONTROL_EXIT_MODE:
{
pdInstance->structuredVdmCommandParameter.vdmHeader.bitFields.command = (uint8_t)kVDM_ExitMode;
if (pdInstance->curDataRole != kPD_DataRoleDFP)
{
status = kStatus_PD_Error;
}
break;
}
case PD_DPM_SEND_UNSTRUCTURED_VDM:
{
pd_unstructured_vdm_header_t *unstructuredVDMHeader;
pdInstance->unstructuredVdmCommandParameter = *((pd_unstructured_vdm_command_param_t *)param);
unstructuredVDMHeader =
(pd_unstructured_vdm_header_t *)((void *)&pdInstance->unstructuredVdmCommandParameter
.vdmHeaderAndVDOsData[0]);
unstructuredVDMHeader->bitFields.vdmType = 0;
break;
}
#endif
case PD_DPM_CONTROL_CABLE_RESET:
break;
#if (defined PD_CONFIG_EXTENDED_MSG_SUPPORT) && (PD_CONFIG_EXTENDED_MSG_SUPPORT)
case PD_DPM_GET_STATUS:
break;
#if (defined PD_CONFIG_PD3_PPS_ENABLE) && (PD_CONFIG_PD3_PPS_ENABLE)
case PD_DPM_GET_PPS_STATUS:
if (pdInstance->curPowerRole != kPD_PowerRoleSink)
{
status = kStatus_PD_Error;
}
break;
#endif
case PD_DPM_GET_BATTERY_CAP:
case PD_DPM_GET_BATTERY_STATUS:
pdInstance->getBatteryCapDataBlock = *((uint8_t *)param);
break;
case PD_DPM_GET_MANUFACTURER_INFO:
#if 0
case PD_DPM_SECURITY_REQUEST:
case PD_DPM_FIRMWARE_UPDATE_REQUEST:
#endif
pdInstance->commandExtParam = *((pd_command_data_param_t *)param);
break;
case PD_DPM_ALERT:
pdInstance->alertADO = *((uint32_t *)param);
break;
#endif
#if (defined PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
case PD_DPM_FAST_ROLE_SWAP:
if ((pdInstance->psmCurState != PSM_PE_SRC_READY) || (pdInstance->curPowerRole != kPD_PowerRoleSource) ||
(PD_PsmIsDualRole(pdInstance) == 0U))
{
status = kStatus_PD_Error;
}
else
{
/* Fast Role Swap is always success, whether PD stack is idle or not. */
status = kStatus_PD_Success;
}
break;
#endif
default:
status = kStatus_PD_Error;
break;
}
if (status == kStatus_PD_Success)
{
/* (1). PTN5110 need signal fr_swap before turn off vbus, otherwise signal will fail
* (2). "enter the PE_FRS_SRC_SNK_CC_Signal state" after "signal fr_swap" need be atomic.
* the psmNewState need change in the same task context, it is the PD task. here
* will not change it. So the (2) is not satisfied.
*/
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
OSA_SR_ALLOC();
if (command == (uint32_t)PD_DPM_FAST_ROLE_SWAP)
{
/* fr swap msg is received but the state may not be in PE_FRS_SRC_SNK_CC_Signal,
* frSwapReceived avoid lost the fr swap msg if not in the PE_FRS_SRC_SNK_CC_Signal state */
pdInstance->frSwapReceived = 0;
/* frs signal is sent and wait the frs msg.
* "(1) The PD_DPM_FAST_ROLE_SWAP is processed by PD task" and "(2) received the fr swap msg"
* (1) may be ahead (2); (2) may be ahead (1).
* frSignaledWaitFrSwap is used to enter PE_FRS_SRC_SNK_CC_Signal only in one place.
*/
pdInstance->frSignaledWaitFrSwap = 1;
PD_ConnectSetPowerProgress(pdInstance, kVbusPower_InFRSwap);
OSA_ENTER_CRITICAL();
(void)PD_PhyControl(pdInstance, PD_PHY_SIGNAL_FR_SWAP, NULL);
}
#endif
PD_DpmSendMsg(pdHandle, (uint8_t)command);
#if defined(PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE) && (PD_CONFIG_PD3_FAST_ROLE_SWAP_ENABLE)
if (command == (uint32_t)PD_DPM_FAST_ROLE_SWAP)
{
OSA_EXIT_CRITICAL();
}
#endif
}
return status;
}
pd_status_t PD_Control(pd_handle pdHandle, uint32_t controlCode, void *param)
{
pd_instance_t *pdInstance = (pd_instance_t *)pdHandle;
pd_status_t status = kStatus_PD_Success;
switch ((pd_control_t)controlCode)
{
case PD_CONTROL_GET_PD_STATE:
/* The following caditions indicate PD or Type-C state machine is busy: */
/* 1. There are the running timers. */
/* 2. There are the pending events. */
/* 3. There is the AMS being executed. */
/* 4. VBUS power is not stable. */
/* 5. Type-C state machine is not in the stable state. */
/* 6. Type-C is in the attached state, but PD state machine is not in the PE_SNK_READY, PE_SRC_READY,
PE_SRC_DISABLED and PE_SNK_WAIT_FOR_CAPABILITIES state.
a. PE_SNK_READY and PE_SRC_READY state indicate that an explict contact has been established.
b. PE_SRC_DISABLED state indicates the partner sink doesn't reply GoodCRC in response to SrcCapability
message. There isn't PD contact establishment or the partner sink doesn't support PD communication.
c. PE_SNK_WAIT_FOR_CAPABILITIES state indicates the self-sink doesn't receive SrcCapability message.
There isn't PD contact establishment or the partner source doesn't support PD communication. */
if ((PD_TimerBusy(pdHandle) != 0U) || (PD_StackHasPendingEvent(pdInstance) != 0U) ||
(pdInstance->commandProcessing != PD_DPM_INVALID) || (pdInstance->inProgress != kVbusPower_Stable) ||
(PD_ConnectState(pdInstance) == kConnectState_NotStable) ||
((pdInstance->isConnected != 0U) && (pdInstance->psmCurState != PSM_PE_SNK_READY) &&
(pdInstance->psmCurState != PSM_PE_SRC_READY) && (pdInstance->psmCurState != PSM_PE_SRC_DISABLED) &&
(pdInstance->psmCurState != PSM_PE_SNK_WAIT_FOR_CAPABILITIES)))
{
*((uint8_t *)param) = (uint8_t)kState_Busy;
}
else
{
*((uint8_t *)param) = (uint8_t)kState_Idle;
}
break;
case PD_CONTROL_GET_TYPEC_ORIENTATION:
if (pdInstance->ccUsed == kPD_CC1)
{
*((uint8_t *)param) = 0;
}
else
{
*((uint8_t *)param) = 1;
}
break;
case PD_CONTROL_GET_POWER_ROLE:
*((uint8_t *)param) = (uint8_t)pdInstance->curPowerRole;
break;
case PD_CONTROL_GET_DATA_ROLE:
*((uint8_t *)param) = (uint8_t)pdInstance->curDataRole;
break;
case PD_CONTROL_GET_TYPEC_CONNECT_STATE:
*((uint8_t *)param) = (uint8_t)pdInstance->connectState;
break;
case PD_CONTROL_GET_VCONN_ROLE:
*((uint8_t *)param) = (uint8_t)pdInstance->psmPresentlyVconnSource;
break;
case PD_CONTROL_GET_TYPEC_CURRENT_VALUE:
case PD_CONTROL_GET_SNK_TYPEC_CURRENT_CAP:
status = PD_PhyControl(pdInstance, PD_PHY_GET_TYPEC_CURRENT_CAP, param);
break;
case PD_CONTROL_PHY_POWER_PIN:
(void)PD_PhyControl(pdInstance, PD_PHY_CONTROL_POWER_PIN, param);
break;
#if defined(PD_CONFIG_VCONN_SUPPORT) && (PD_CONFIG_VCONN_SUPPORT)
case PD_CONTROL_VCONN:
(void)PD_PhyControl(pdInstance, PD_PHY_CONTROL_VCONN, param);
break;
#endif
case PD_CONTROL_DISCHARGE_VBUS:
{
uint32_t eventSet = 0U;
PD_DpmDischargeVbus(pdInstance, 1);
#if (defined PD_CONFIG_MIN_DISCHARGE_TIME_ENABLE) && (PD_CONFIG_MIN_DISCHARGE_TIME_ENABLE)
(void)PD_TimerStart(pdInstance, tTypeCVbusMinDischargeTimer, T_MIN_VBUS_DISCHARGE);
while (PD_TimerCheckValidTimeOut(pdInstance, tTypeCVbusMinDischargeTimer) == 0U)
#else
(void)PD_TimerStart(pdInstance, tTypeCVbusMaxDischargeTimer, T_MAX_VBUS_DISCHARGE);
while (PD_TimerCheckValidTimeOut(pdInstance, tTypeCVbusMaxDischargeTimer) == 0U)
#endif
{
if (PD_PsmCheckVsafe0V(pdInstance) != 0U)
{
break;
}
/* When VBUS decreases to vSafe0V, the EXTENDED_STATUS.vSafe0V register will be set and an interrupt
will be asserted, so software does not need to check vSafe0V constantly. */
(void)OSA_EventWait(pdInstance->taskEventHandle, PD_TASK_EVENT_ALL, 0, 5, &eventSet);
}
PD_DpmDischargeVbus(pdInstance, 0);
break;
}
case PD_CONTROL_INFORM_VBUS_VOLTAGE_RANGE:
#if !(defined(PD_CONFIG_VBUS_ALARM_SUPPORT) && (PD_CONFIG_VBUS_ALARM_SUPPORT))
(void)PD_PhyControl(pdInstance, PD_PHY_INFORM_VBUS_VOLTAGE_RANGE, param);
#endif
break;
case PD_CONTROL_GET_CABLE_INFO:
{
pd_cable_plug_info_t *plugInfo;
if (param == NULL)
{
break;
}
plugInfo = (pd_cable_plug_info_t *)param;
if (pdInstance->psmCableIdentitiesDataCount > 0U)
{
pd_id_header_vdo_t *headerVDO = (pd_id_header_vdo_t *)((void *)&pdInstance->psmCableIdentities[1]);
pd_structured_vdm_header_t *vdmHeader =
(pd_structured_vdm_header_t *)((void *)&pdInstance->psmCableIdentities[0]);
plugInfo->vdmVersion = (uint8_t)vdmHeader->bitFields.vdmVersion;
if (headerVDO->bitFields.productTypeUFPOrCablePlug == VDM_ID_HEADER_VDO_PASSIVE_CABLE_VAL)
{
plugInfo->cableType = (uint8_t)kCableType_PassiveCable;
}
else if (headerVDO->bitFields.productTypeUFPOrCablePlug == VDM_ID_HEADER_VDO_ACTIVE_CABLE_VAL)
{
plugInfo->cableType = (uint8_t)kCableType_ActiveCable;
}
else
{
plugInfo->cableType = (uint8_t)kCableType_Invalid;
}
plugInfo->vdoValue = pdInstance->psmCableIdentities[4];
}
else
{
plugInfo->cableType = (uint8_t)kCableType_Invalid;
}
break;
}
#if (defined PD_CONFIG_ENABLE_AUTO_POLICY) && (PD_CONFIG_ENABLE_AUTO_POLICY)
case PD_CONTROL_INFORM_EXTERNAL_POWER_STATE:
if (pdInstance->rdySeenExtPower != *((uint8_t *)param))
{
PD_PsmExternalPowerChange(pdInstance);
}
break;
#endif
#if (defined PD_CONFIG_ALT_MODE_DP_SUPPORT) && (PD_CONFIG_ALT_MODE_DP_SUPPORT)
case PD_CONTROL_ALT_MODE:
PD_AltModeControl(pdInstance->altModeHandle, param);
break;
#endif
#if (defined PD_CONFIG_PHY_LOW_POWER_LEVEL) && (PD_CONFIG_PHY_LOW_POWER_LEVEL)
case PD_CONTROL_ENTER_LOW_POWER:
(void)PD_PhyControl(pdInstance, PD_PHY_ENTER_LOW_POWER_STATE, NULL);
break;
case PD_CONTROL_EXIT_LOW_POWER:
(void)PD_PhyControl(pdInstance, PD_PHY_EXIT_LOW_POWER_STATE, NULL);
break;
case PD_CONTROL_GET_PD_LOW_POWER_STATE:
*((uint8_t *)param) = (pdInstance->lowPowerState != 0U) ? 1U : 0U;
break;
#endif
default:
/* No action required. */
break;
}
return status;
}
void PD_DpmAltModeCallback(pd_handle pdHandle, pd_dpm_callback_event_t event, void *param)
{
(void)((pd_instance_t *)(pdHandle))->pdCallback(((pd_instance_t *)(pdHandle))->callbackParam, event, param);
}