/** ****************************************************************************** * @file usbpd_dpm_user.c * @author MCD Application Team * @brief USBPD DPM user code ****************************************************************************** * @attention * *

© Copyright (c) 2018 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */ #define USBPD_DPM_USER_C /* Includes ------------------------------------------------------------------*/ #include "usbpd_core.h" #include "usbpd_pdo_defs.h" #include "usbpd_dpm_core.h" #include "usbpd_dpm_conf.h" #include "usbpd_dpm_user.h" #include "usbpd_vdm_user.h" #ifdef _TRACE #include "usbpd_trace.h" #endif /* _TRACE */ #if defined(_GUI_INTERFACE) #include "gui_api.h" #endif #include "usbpd_hw_if.h" #include "usbpd_pwr_if.h" #include "string.h" #include "cmsis_os.h" #include "printf.h" /** @addtogroup STM32_USBPD_LIBRARY * @{ */ /** @addtogroup USBPD_USER * @{ */ /* Private typedef -----------------------------------------------------------*/ /** @brief Sink Request characteritics Structure definition * */ typedef struct { uint32_t RequestedVoltageInmVunits; /*!< Sink request operating voltage in mV units */ uint32_t MaxOperatingCurrentInmAunits; /*!< Sink request Max operating current in mA units */ uint32_t OperatingCurrentInmAunits; /*!< Sink request operating current in mA units */ uint32_t MaxOperatingPowerInmWunits; /*!< Sink request Max operating power in mW units */ uint32_t OperatingPowerInmWunits; /*!< Sink request operating power in mW units */ } USBPD_DPM_SNKPowerRequestDetails_TypeDef; /* Private define ------------------------------------------------------------*/ /** @defgroup USBPD_USER_PRIVATE_DEFINES USBPD USER Private Defines * @{ */ #define DPM_TIMER_ENABLE_MSK ((uint16_t)0x8000U) /*!< Enable Timer Mask */ #define DPM_TIMER_READ_MSK ((uint16_t)0x7FFFU) /*!< Read Timer Mask */ #define DPM_BOX_MESSAGES_MAX 30u /* Timer used to send a GET_SRC_CAPA_EXT*/ #define DPM_TIMER_GET_SRC_CAPA_EXT 300u /*!< 300ms */ /* Timer used to check if need to send an alert */ #define DPM_TIMER_ALERT 100u /*!< 100ms */ #define DPM_NO_SRC_PDO_FOUND 0xFFU /*!< No match found between Received SRC PDO and SNK capabilities */ /** * @} */ /* Private macro -------------------------------------------------------------*/ /** @defgroup USBPD_USER_PRIVATE_MACROS USBPD USER Private Macros * @{ */ #define DPM_START_TIMER(_PORT_,_TIMER_,_TIMEOUT_) do{ \ DPM_Ports[_PORT_]._TIMER_ = (_TIMEOUT_) | DPM_TIMER_ENABLE_MSK;\ osMessagePut(DPMMsgBox,DPM_USER_EVENT_TIMER, 0); \ }while(0); #define IS_DPM_TIMER_RUNNING(_PORT_, _TIMER_) ((DPM_Ports[_PORT_]._TIMER_ & DPM_TIMER_READ_MSK) > 0) #define IS_DPM_TIMER_EXPIRED(_PORT_, _TIMER_) (DPM_TIMER_ENABLE_MSK == DPM_Ports[_PORT_]._TIMER_) /** * @} */ /* Private variables ---------------------------------------------------------*/ /** @defgroup USBPD_USER_PRIVATE_VARIABLES USBPD USER Private Variables * @{ */ extern uint8_t VDM_Mode_On[USBPD_PORT_COUNT]; extern USBPD_ParamsTypeDef DPM_Params[USBPD_PORT_COUNT]; extern USBPD_PWR_Port_PDO_Storage_TypeDef PWR_Port_PDO_Storage[USBPD_PORT_COUNT]; /** * @} */ /* Private function prototypes -----------------------------------------------*/ /** @defgroup USBPD_USER_PRIVATE_FUNCTIONS USBPD USER Private Functions * @{ */ static void DPM_SNK_BuildRDOfromSelectedPDO(uint8_t PortNum, uint8_t IndexSrcPDO, USBPD_DPM_SNKPowerRequestDetails_TypeDef* PtrRequestPowerDetails, USBPD_SNKRDO_TypeDef* Rdo, USBPD_CORE_PDO_Type_TypeDef *PtrPowerObject); static uint32_t DPM_FindVoltageIndex(uint32_t PortNum, USBPD_DPM_SNKPowerRequestDetails_TypeDef* PtrRequestPowerDetails); static USBPD_StatusTypeDef DPM_TurnOnPower(uint8_t PortNum, USBPD_PortPowerRole_TypeDef Role); static USBPD_StatusTypeDef DPM_TurnOffPower(uint8_t PortNum, USBPD_PortPowerRole_TypeDef Role); static void DPM_AssertRd(uint8_t PortNum); static void DPM_AssertRp(uint8_t PortNum); static uint32_t CheckDPMTimers(void); static void DPM_ManageExtendedCapa(void); static void DPM_ManageAlert(void); /** * @} */ /* Exported functions ------- ------------------------------------------------*/ /** @defgroup USBPD_USER_EXPORTED_FUNCTIONS USBPD USER Exported Functions * @{ */ /** @defgroup USBPD_USER_EXPORTED_FUNCTIONS_GROUP1 USBPD USER Exported Functions called by DPM CORE * @{ */ /** * @brief Initialize DPM (port power role, PWR_IF, CAD and PE Init procedures) * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_UserInit(void) { /* PWR SET UP */ if(USBPD_OK != USBPD_PWR_IF_Init()) { #ifdef _TRACE USBPD_TRACE_Add(USBPD_TRACE_DEBUG, 0, 0, (uint8_t *) "Error Initializing USB PD PWR IF", sizeof("Error Initializing USB PD PWR IF")); #endif /* _TRACE */ return USBPD_ERROR; } if(USBPD_OK != USBPD_PWR_IF_PowerResetGlobal()) return USBPD_ERROR; if (USBPD_OK != USBPD_VDM_UserInit(USBPD_PORT_0)) { #ifdef _TRACE USBPD_TRACE_Add(USBPD_TRACE_DEBUG, 0, 0, (uint8_t *) "Error Initializing USB PD VDM User port 0", sizeof("Error Initializing USB PD VDM User port 0")); #endif /* _TRACE */ return USBPD_ERROR; } #if USBPD_PORT_COUNT == 2 if (USBPD_OK != USBPD_VDM_UserInit(USBPD_PORT_1)) { #ifdef _TRACE USBPD_TRACE_Add(USBPD_TRACE_DEBUG, 0, 0, (uint8_t *) "Error Initializing USB PD VDM User port 1", sizeof("Error Initializing USB PD VDM User port 1")); #endif /* _TRACE */ return USBPD_ERROR; } #endif /* USBPD_PORT_COUNT == 2 */ osMessageQDef(MsgBox, DPM_BOX_MESSAGES_MAX, uint32_t); DPMMsgBox = osMessageCreate(osMessageQ(MsgBox), NULL); osThreadDef(DPM, USBPD_DPM_UserExecute, osPriorityLow, 0, 300); if(NULL == osThreadCreate(osThread(DPM), &DPMMsgBox)) { #ifdef _TRACE USBPD_TRACE_Add(USBPD_TRACE_DEBUG, 0, 0, (uint8_t *) "Error Creating USB PD DPM Thread", sizeof("Error Creating USB PD DPM Thread")); #endif /* _TRACE */ return USBPD_ERROR; } if(USBPD_OK != USBPD_PWR_IF_StartMonitoring()) { #ifdef _TRACE USBPD_TRACE_Add(USBPD_TRACE_DEBUG, 0, 0, (uint8_t *) "Error Starting USB PD Monitoring", sizeof("Error Starting USB PD Monitoring")); #endif /* _TRACE */ return USBPD_ERROR; } return USBPD_OK; } /** * @brief User delay implementation which is OS dependant * @param Time time in ms * @retval None */ void USBPD_DPM_WaitForTime(uint32_t Time) { osDelay(Time); } /** * @brief User processing time, it is recommended to avoid blocking task for long time * @param None * @retval None */ void USBPD_DPM_UserExecute(void const *argument) { /* User code implementation */ uint32_t _timing = osWaitForever; osMessageQId queue = *(osMessageQId *)argument; #if defined(_GUI_INTERFACE) /* Start GUI interface */ GUI_Start(); #endif /* _GUI_INTERFACE */ do { osEvent event = osMessageGet(queue, _timing); switch (((DPM_USER_EVENT)event.value.v & 0xF)) { #if defined(_GUI_INTERFACE) case DPM_USER_EVENT_GUI: { GUI_RXProcess((uint32_t)event.value.v); /* Sent an event to check if measurement report has been requested */ osMessagePut(DPMMsgBox, DPM_USER_EVENT_TIMER, 0); break; } #endif /* _GUI_INTERFACE */ case DPM_USER_EVENT_TIMER: { #if defined(_GUI_INTERFACE) for(uint8_t _instance = 0; _instance < USBPD_PORT_COUNT; _instance++) { /* ------------------------------------------------- */ /* Check if timeout related to Measurement reporting */ /* ------------------------------------------------- */ /* - Send a GUI Event only if PE is connected and Measurement report has been enabled */ if ((USBPD_TRUE == DPM_Params[_instance].PE_IsConnected) && (1 == GUI_USER_Params[_instance].u.d.MeasReportActivation) && (0 != GUI_USER_Params[_instance].u.d.MeasReportValue)) { /* Check if timer has expired */ if (IS_DPM_TIMER_EXPIRED(_instance, DPM_TimerMeasReport)) { uint32_t event_mr = DPM_USER_EVENT_GUI | (_instance << GUI_PE_PORT_NUM_Pos) | (GUI_NOTIF_MEASUREMENT << GUI_PE_NOTIF_Pos); GUI_RXProcess(event_mr); } /* Start or Restart Measurement report timer */ if (!(IS_DPM_TIMER_RUNNING(_instance, DPM_TimerMeasReport))) { DPM_START_TIMER(_instance, DPM_TimerMeasReport, (GUI_USER_Params[_instance].u.d.MeasReportValue * GUI_NOTIF_MEASUREMENT_STEP)); } } else { /* Stop measurement report timer */ DPM_Ports[_instance].DPM_TimerMeasReport = 0; } } #endif /* _GUI_INTERFACE */ /* Manage the extended capa */ DPM_ManageExtendedCapa(); DPM_ManageAlert(); break; } default: break; } _timing = CheckDPMTimers(); } while(1); } /** * @brief function used to manage user timer. * @param PortNum Port number * @retval None */ void USBPD_DPM_UserTimerCounter(uint8_t PortNum) { if((DPM_Ports[PortNum].DPM_TimerSRCExtendedCapa & DPM_TIMER_READ_MSK) > 0) { DPM_Ports[PortNum].DPM_TimerSRCExtendedCapa--; } if((DPM_Ports[PortNum].DPM_TimerAlert & DPM_TIMER_READ_MSK) > 0) { DPM_Ports[PortNum].DPM_TimerAlert--; } #if defined(_GUI_INTERFACE) if((DPM_Ports[PortNum].DPM_TimerMeasReport & DPM_TIMER_READ_MSK) > 0) { DPM_Ports[PortNum].DPM_TimerMeasReport--; } #endif /* _GUI_INTERFACE */ } /** * @brief UserCableDetection reporting events on a specified port from CAD layer. * @param PortNum The handle of the port * @param State CAD state * @retval None */ void USBPD_DPM_UserCableDetection(uint8_t PortNum, USBPD_CAD_EVENT State) { switch(State) { case USBPD_CAD_EVENT_ATTACHED: case USBPD_CAD_EVENT_ATTEMC: #if defined(_GUI_INTERFACE) GUI_FormatAndSendNotification(PortNum, GUI_NOTIF_ISCONNECTED, 0); #endif /* _GUI_INTERFACE */ USBPD_VDM_UserReset(PortNum); if(USBPD_PORTPOWERROLE_SRC == DPM_Params[PortNum].PE_PowerRole) { USBPD_DPM_WaitForTime(110); if (USBPD_OK != USBPD_PWR_IF_VBUSEnable(PortNum)) { /* Should not occurr */ while(1){ osDelay(1); }; } } DPM_Ports[PortNum].DPM_IsConnected = 1; break; case USBPD_CAD_EVENT_DETACHED : case USBPD_CAD_EVENT_EMC : default : /* reset all values received from port partner */ memset(&DPM_Ports[PortNum], 0, sizeof(DPM_Ports[PortNum])); #if defined(_GUI_INTERFACE) GUI_FormatAndSendNotification(PortNum, GUI_NOTIF_ISCONNECTED | GUI_NOTIF_POWER_EVENT, 0); #endif /* _GUI_INTERFACE */ USBPD_VDM_UserReset(PortNum); DPM_Ports[PortNum].FlagSendGetSrcCapaExtended = 0; if(USBPD_PORTPOWERROLE_SRC == DPM_Params[PortNum].PE_PowerRole) { if (USBPD_OK != USBPD_PWR_IF_VBUSDisable(PortNum)) { /* Should not occurr */ while(1); } } #if defined(_VCONN_SUPPORT) if(USBPD_TRUE == DPM_Params[PortNum].VconnStatus) { /* Switch Off Vconn */ USBPD_DPM_PE_VconnPwr(PortNum, USBPD_DISABLE); } #endif /* _VCONN_SUPPORT */ DPM_Ports[PortNum].DPM_IsConnected = 0; break; } } /** * @} */ /** @defgroup USBPD_USER_EXPORTED_FUNCTIONS_GROUP2 USBPD USER Exported Callbacks functions called by PE * @{ */ /** * @brief Callback function called by PE layer when HardReset message received from PRL * @param PortNum The current port number * @param CurrentRole the current role * @param Status status on hard reset event * @retval None */ void USBPD_DPM_HardReset(uint8_t PortNum, USBPD_PortPowerRole_TypeDef CurrentRole, USBPD_HR_Status_TypeDef Status) { USBPD_VDM_UserReset(PortNum); /* Stop Alert timer */ DPM_Ports[PortNum].DPM_TimerAlert = 0; DPM_Ports[PortNum].DPM_SendAlert.d32 = 0; switch (Status) { case USBPD_HR_STATUS_START_ACK: case USBPD_HR_STATUS_START_REQ: if (USBPD_PORTPOWERROLE_SRC == CurrentRole) { /* Reset the power supply */ DPM_TurnOffPower(PortNum, USBPD_PORTPOWERROLE_SRC); } else { USBPD_PWR_IF_VBUSIsEnabled(PortNum); } break; case USBPD_HR_STATUS_COMPLETED: /* Reset the power supply */ DPM_TurnOnPower(PortNum,CurrentRole); break; default: break; } } /** * @brief Request the DPM to setup the new power level. * @param PortNum The current port number * @retval USBPD status */ USBPD_StatusTypeDef USBPD_DPM_SetupNewPower(uint8_t PortNum) { return USBPD_PWR_IF_SetProfile(PortNum); } /** * @brief Evaluate the swap request from PE. * @param PortNum The current port number * @retval USBPD_ACCEPT, USBPD_WAIT, USBPD_REJECT */ USBPD_StatusTypeDef USBPD_DPM_EvaluatePowerRoleSwap(uint8_t PortNum) { return USBPD_ACCEPT; } /** * @brief Callback function called by PE to inform DPM about PE event. * @param PortNum The current port number * @param EventType @ref USBPD_NotifyEvent_TypeDef * @param EventVal @ref USBPD_NotifyEventValue_TypeDef * @retval None */ void USBPD_DPM_Notification(uint8_t PortNum, USBPD_NotifyEventValue_TypeDef EventVal) { switch(EventVal) { /*************************************************************************** Power Notification */ case USBPD_NOTIFY_POWER_EXPLICIT_CONTRACT : /* Power ready means an explicit contract has been establish and Power is available */ /* Request VDM identify only if not already entered in VDM mode */ if ((0 == VDM_Mode_On[PortNum]) && (USBPD_PORTDATAROLE_DFP == DPM_Params[PortNum].PE_DataRole)) { USBPD_PE_SVDM_RequestIdentity(PortNum, USBPD_SOPTYPE_SOP); } break; /* End Power Notification ***************************************************************************/ /*************************************************************************** REQUEST ANSWER NOTIFICATION */ case USBPD_NOTIFY_REQUEST_ACCEPTED: /* Update DPM_RDOPosition only if current role is SNK */ if (USBPD_PORTPOWERROLE_SNK == DPM_Params[PortNum].PE_PowerRole) { USBPD_SNKRDO_TypeDef rdo; rdo.d32 = DPM_Ports[PortNum].DPM_RequestDOMsg; DPM_Ports[PortNum].DPM_RDOPosition = rdo.GenericRDO.ObjectPosition; #if defined(_GUI_INTERFACE) DPM_USER_Settings[PortNum].DPM_SNKRequestedPower.OperatingVoltageInmVunits = DPM_Ports[PortNum].DPM_RequestedVoltage; DPM_USER_Settings[PortNum].DPM_SNKRequestedPower.OperatingPowerInmWunits = (DPM_Ports[PortNum].DPM_RequestedVoltage * DPM_USER_Settings[PortNum].DPM_SNKRequestedPower.MaxOperatingCurrentInmAunits) / 1000; #endif /* _GUI_INTERFACE */ } break; /* End REQUEST ANSWER NOTIFICATION ***************************************************************************/ case USBPD_NOTIFY_HARDRESET_RX: case USBPD_NOTIFY_HARDRESET_TX: if (USBPD_PORTPOWERROLE_SNK == DPM_Params[PortNum].PE_PowerRole) { USBPD_VDM_UserReset(PortNum); } break; case USBPD_NOTIFY_STATE_SNK_READY: { /* Send GET_SRC_CAPA_EXT only if current revision is PD3.0 */ if ((USBPD_SPECIFICATION_REV3 == DPM_Params[PortNum].PE_SpecRevision) && (1 == DPM_Ports[PortNum].FlagSendGetSrcCapaExtended)) { DPM_START_TIMER(PortNum, DPM_TimerSRCExtendedCapa, DPM_TIMER_GET_SRC_CAPA_EXT); DPM_Ports[PortNum].FlagSendGetSrcCapaExtended = 0; } } break; case USBPD_NOTIFY_STATE_SRC_DISABLED: { /* SINK Port Partner is not PD capable. Legacy cable may have been connected In this state, VBUS is set to 5V */ } break; default: break; } #if defined(_GUI_INTERFACE) GUI_PostNotificationMessage(PortNum, EventVal); #endif /* _GUI_INTERFACE */ } /** * @brief DPM callback to allow PE to retrieve information from DPM/PWR_IF. * @param PortNum Port number * @param DataId Type of data to be updated in DPM based on @ref USBPD_CORE_DataInfoType_TypeDef * @param Ptr Pointer on address where DPM data should be written (u8 pointer) * @param Size Pointer on nb of u8 written by DPM * @retval None */ void USBPD_DPM_GetDataInfo(uint8_t PortNum, USBPD_CORE_DataInfoType_TypeDef DataId, uint8_t *Ptr, uint32_t *Size) { /* Check type of information targeted by request */ switch (DataId) { /* Case Port Source PDO Data information : Case Port SINK PDO Data information : Call PWR_IF PDO reading request. */ case USBPD_CORE_DATATYPE_SRC_PDO : case USBPD_CORE_DATATYPE_SNK_PDO : USBPD_PWR_IF_GetPortPDOs(PortNum, DataId, Ptr, Size); *Size *= 4; break; /* Case Requested voltage value Data information */ case USBPD_CORE_DATATYPE_REQ_VOLTAGE : *Size = 4; (void)memcpy((uint8_t*)Ptr, (uint8_t *)&DPM_Ports[PortNum].DPM_RequestedVoltage, *Size); break; case USBPD_CORE_PPS_STATUS : { /* Get current drawn by sink */ USBPD_PPSSDB_TypeDef pps_status = {0}; /* Disable VBUS & IBUS Measurements */ pps_status.fields.OutputVoltageIn20mVunits = 0xFFFF; pps_status.fields.OutputCurrentIn50mAunits = 0xFF; pps_status.fields.RealTimeFlags = USBPD_PPS_REALTIMEFLAGS_PTF_NOT_SUPPORTED | USBPD_PPS_REALTIMEFLAGS_OMF_DISABLED; *Size = 4; (void)memcpy((uint8_t*)Ptr, (uint8_t *)&pps_status.d32, *Size); } break; case USBPD_CORE_EXTENDED_CAPA : { *Size = sizeof(USBPD_SCEDB_TypeDef); memcpy((uint8_t*)Ptr, (uint8_t *)&DPM_USER_Settings[PortNum].DPM_SRCExtendedCapa, *Size); } break; case USBPD_CORE_INFO_STATUS : { USBPD_SDB_TypeDef infostatus = { .InternalTemp = 0, /*!< Source or Sink internal temperature in degrees centigrade */ .PresentInput = 0, /*!< Present Input */ .PresentBatteryInput = 0, /*!< Present Battery Input */ .EventFlags = 0, /*!< Event Flags */ .TemperatureStatus = 0, /*!< Temperature */ .PowerStatus = 0, /*!< Power Status based on combination of @ref USBPD_SDB_POWER_STATUS*/ }; *Size = sizeof(USBPD_SDB_TypeDef); memcpy((uint8_t *)Ptr, &infostatus, *Size); } break; case USBPD_CORE_MANUFACTURER_INFO : { USBPD_MIDB_TypeDef* manu_info; /* Manufacturer Info Target must be a range 0..1 */ /* Manufacturer Info Ref must be a range 0..7 */ if((DPM_Ports[PortNum].DPM_GetManufacturerInfo.ManufacturerInfoTarget > USBPD_MANUFINFO_TARGET_BATTERY) || (DPM_Ports[PortNum].DPM_GetManufacturerInfo.ManufacturerInfoRef > USBPD_MANUFINFO_REF_MAX_VALUES)) { /* If the Manufacturer Info Target field or Manufacturer Info Ref field in the Get_Manufacturer_Info Message is unrecognized the field Shall return a null terminated ascii text string “Not Supported”.*/ char *_notsupported = "Not Supported\0"; *Size = 4 + 14; /* VID (2) + .PID(2) + sizeof("Not Supported\0")*/ /* Copy Manufacturer Info into data area for transmission */ manu_info = (USBPD_MIDB_TypeDef*)&DPM_USER_Settings[PortNum].DPM_ManuInfoPort; memcpy((uint8_t*)Ptr, (uint8_t *)manu_info, 4); memcpy((uint8_t*)(Ptr + 4), (uint8_t *)_notsupported, 14); } else { if (USBPD_MANUFINFO_TARGET_PORT_CABLE_PLUG == DPM_Ports[PortNum].DPM_GetManufacturerInfo.ManufacturerInfoTarget) { /* Manufacturer info requested for the port */ /* VID(2) + .PID(2) + .ManuString("STMicroelectronics") */ *Size = 4 + strlen((char*)(DPM_USER_Settings[PortNum].DPM_ManuInfoPort.ManuString)); /* Copy Manufacturer Info into data area for transmission */ manu_info = (USBPD_MIDB_TypeDef*)&DPM_USER_Settings[PortNum].DPM_ManuInfoPort; memcpy((uint8_t*)Ptr, (uint8_t *)manu_info, *Size); } else { /* Manufacturer info requested for the battery (not available yet) */ /* If the Manufacturer Info Target field or Manufacturer Info Ref field in the Get_Manufacturer_Info Message is unrecognized the field Shall return a null terminated ascii text string “Not Supported”.*/ char *_notsupported = "Not Supported\0"; *Size = 4 + 14; /* VID (2) + .PID(2) + sizeof("Not Supported\0")*/ /* Copy Manufacturer Info into data area for transmission */ manu_info = (USBPD_MIDB_TypeDef*)&DPM_USER_Settings[PortNum].DPM_ManuInfoPort; memcpy((uint8_t*)Ptr, (uint8_t *)manu_info, 4); memcpy((uint8_t*)(Ptr + 4), (uint8_t *)_notsupported, 14); } } } break; case USBPD_CORE_BATTERY_STATUS: { USBPD_BSDO_TypeDef battery_status; battery_status.d32 = 0; if ((DPM_Ports[PortNum].DPM_GetBatteryStatus.BatteryStatusRef < 8) && (DPM_Ports[PortNum].DPM_GetBatteryStatus.BatteryStatusRef < DPM_USER_Settings[PortNum].DPM_SRCExtendedCapa.NbBatteries)) { battery_status.b.BatteryPC = 0xABCDu; battery_status.b.BatteryInfo = USBPD_BSDO_BATT_INFO_BATT_PRESENT | USBPD_BSDO_BATT_INFO_BATT_ISIDLE; } else { battery_status.b.BatteryPC = 0xFFFFu; battery_status.b.BatteryInfo = USBPD_BSDO_BATT_INFO_INVALID_REF; } *Size = 4; memcpy((uint8_t *)Ptr, (uint8_t *)&battery_status.d32, *Size); } break; case USBPD_CORE_BATTERY_CAPABILITY: { if (0 != DPM_USER_Settings[PortNum].DPM_SRCExtendedCapa.NbBatteries) { *Size = sizeof(USBPD_BCDB_TypeDef); USBPD_BCDB_TypeDef battery_capability = { .VID = USBPD_VID, /*!< Vendor ID (assigned by the USB-IF) */ .PID = USBPD_PID, /*!< Product ID (assigned by the manufacturer) */ .BatteryDesignCapa = 0xAABB, /*!< Battery Design Capacity */ .BatteryLastFullChargeCapa = 0xCCDD, /*!< Battery last full charge capacity */ .BatteryType= 0, /*!< Battery Type */ }; if (DPM_Ports[PortNum].DPM_GetBatteryCapability.BatteryCapRef >= 8) { battery_capability.BatteryType = 1; } memcpy((uint8_t *)Ptr, &battery_capability, *Size); } else { /* Set Size to 0 to send a not supported message */ *Size = 0; } } break; default : *Size = 0; break; } } /** * @brief DPM callback to allow PE to update information in DPM/PWR_IF. * @param PortNum Port number * @param DataId Type of data to be updated in DPM based on @ref USBPD_CORE_DataInfoType_TypeDef * @param Size Nb of bytes to be updated in DPM * @retval None */ void USBPD_DPM_SetDataInfo(uint8_t PortNum, USBPD_CORE_DataInfoType_TypeDef DataId, uint8_t *Ptr, uint32_t Size) { uint32_t index; /* Check type of information targeted by request */ switch (DataId) { /* Case requested DO position Data information : */ case USBPD_CORE_DATATYPE_RDO_POSITION : if (Size == 4) { uint8_t* temp; temp = (uint8_t*)&DPM_Ports[PortNum].DPM_RDOPosition; (void)memcpy(temp, Ptr, Size); DPM_Ports[PortNum].DPM_RDOPositionPrevious = *Ptr; temp = (uint8_t*)&DPM_Ports[PortNum].DPM_RDOPositionPrevious; (void)memcpy(temp, Ptr, Size); } break; /* Case Received Source PDO values Data information : */ case USBPD_CORE_DATATYPE_RCV_SRC_PDO : if (Size <= (USBPD_MAX_NB_PDO * 4)) { uint8_t* rdo; DPM_Ports[PortNum].DPM_NumberOfRcvSRCPDO = (Size / 4); /* Copy PDO data in DPM Handle field */ for (index = 0; index < (Size / 4); index++) { rdo = (uint8_t*)&DPM_Ports[PortNum].DPM_ListOfRcvSRCPDO[index]; (void)memcpy(rdo, (Ptr + (index * 4u)), (4u * sizeof(uint8_t))); } } break; /* Case Received Sink PDO values Data information : */ case USBPD_CORE_DATATYPE_RCV_SNK_PDO : if (Size <= (USBPD_MAX_NB_PDO * 4)) { uint8_t* rdo; DPM_Ports[PortNum].DPM_NumberOfRcvSNKPDO = (Size / 4); /* Copy PDO data in DPM Handle field */ for (index = 0; index < (Size / 4); index++) { rdo = (uint8_t*)&DPM_Ports[PortNum].DPM_ListOfRcvSNKPDO[index]; (void)memcpy(rdo, (Ptr + (index * 4u)), (4u * sizeof(uint8_t))); } } break; /* Case Received Request PDO Data information : */ case USBPD_CORE_DATATYPE_RCV_REQ_PDO : if (Size == 4) { uint8_t* rdo; rdo = (uint8_t*)&DPM_Ports[PortNum].DPM_RcvRequestDOMsg; (void)memcpy(rdo, Ptr, Size); } break; /* Case Request message DO (from Sink to Source) Data information : */ case USBPD_CORE_DATATYPE_REQUEST_DO : if (Size == 4) { uint8_t* rdo; rdo = (uint8_t*)&DPM_Ports[PortNum].DPM_RcvRequestDOMsg; (void)memcpy(rdo, Ptr, Size); } break; case USBPD_CORE_INFO_STATUS : { uint8_t* info_status; info_status = (uint8_t*)&DPM_Ports[PortNum].DPM_RcvStatus; memcpy(info_status, Ptr, Size); } break; case USBPD_CORE_PPS_STATUS : { uint8_t* ext_capa; ext_capa = (uint8_t*)&DPM_Ports[PortNum].DPM_RcvPPSStatus; memcpy(ext_capa, Ptr, Size); } break; case USBPD_CORE_EXTENDED_CAPA : { uint8_t* ext_capa; ext_capa = (uint8_t*)&DPM_Ports[PortNum].DPM_RcvSRCExtendedCapa; memcpy(ext_capa, Ptr, Size); } break; case USBPD_CORE_GET_MANUFACTURER_INFO: { uint8_t* temp = (uint8_t*)Ptr; DPM_Ports[PortNum].DPM_GetManufacturerInfo.ManufacturerInfoTarget = *temp; DPM_Ports[PortNum].DPM_GetManufacturerInfo.ManufacturerInfoRef = *(temp + 1); } break; case USBPD_CORE_GET_BATTERY_STATUS: { DPM_Ports[PortNum].DPM_GetBatteryStatus.BatteryStatusRef = *(uint8_t*)Ptr; } break; case USBPD_CORE_GET_BATTERY_CAPABILITY: { uint8_t* temp = (uint8_t*)Ptr; DPM_Ports[PortNum].DPM_GetBatteryCapability.BatteryCapRef= *temp; } break; case USBPD_CORE_ALERT: { uint8_t* alert; alert = (uint8_t*)&DPM_Ports[PortNum].DPM_RcvAlert.d32; memcpy(alert, Ptr, Size); } break; /* In case of unexpected data type (Set request could not be fulfilled) : */ default : break; } } /** * @brief Evaluate received Request Message from Sink port * @param pdhandle Pointer to USB PD handle * @param PtrPowerObject Pointer on the power data object * @retval USBPD status : USBPD_ACCEPT, USBPD_REJECT, USBPD_WAIT, USBPD_GOTOMIN */ USBPD_StatusTypeDef USBPD_DPM_EvaluateRequest(uint8_t PortNum, USBPD_CORE_PDO_Type_TypeDef *PtrPowerObject) { USBPD_SNKRDO_TypeDef rdo; USBPD_PDO_TypeDef pdo; uint32_t pdomaxcurrent = 0; uint32_t rdomaxcurrent = 0, rdoopcurrent = 0, rdoobjposition = 0; USBPD_HandleTypeDef *pdhandle = &DPM_Ports[PortNum]; rdo.d32 = pdhandle->DPM_RcvRequestDOMsg; rdoobjposition = rdo.GenericRDO.ObjectPosition; /* Set unchuncked bit if supported by ports */ DPM_Params[PortNum].PE_UnchunkSupport = USBPD_FALSE; if ((USBPD_TRUE == rdo.GenericRDO.UnchunkedExtendedMessage) && (USBPD_TRUE == DPM_Settings[PortNum].PE_PD3_Support.d.PE_UnchunkSupport)) { DPM_Params[PortNum].PE_UnchunkSupport = USBPD_TRUE; } pdhandle->DPM_RDOPosition = 0; /* Check if RDP can be met within the supported PDOs by the Source port */ /* USBPD_DPM_EvaluateRequest: Evaluate Sink Request\r */ /* USBPD_DPM_EvaluateRequest: Check if RDP can be met within the supported PDOs by the Source port\r */ /* Search PDO in Port Source PDO list, that corresponds to Position provided in Request RDO */ if (USBPD_PWR_IF_SearchRequestedPDO(PortNum, rdoobjposition, &pdo.d32) != USBPD_OK) { /* Invalid PDO index */ /* USBPD_DPM_EvaluateRequest: Invalid PDOs index */ return USBPD_REJECT; } switch(pdo.GenericPDO.PowerObject) { case USBPD_CORE_PDO_TYPE_FIXED: { pdomaxcurrent = pdo.SRCFixedPDO.MaxCurrentIn10mAunits; rdomaxcurrent = rdo.FixedVariableRDO.MaxOperatingCurrent10mAunits; rdoopcurrent = rdo.FixedVariableRDO.OperatingCurrentIn10mAunits; DPM_Ports[PortNum].DPM_RequestedCurrent = rdoopcurrent * 10; if(rdoopcurrent > pdomaxcurrent) { /* Sink requests too much operating current */ /* USBPD_DPM_EvaluateRequest: Sink requests too much operating current*/ return USBPD_REJECT; } if(rdomaxcurrent > pdomaxcurrent) { /* Sink requests too much maximum operating current */ /* USBPD_DPM_EvaluateRequest: Sink requests too much maximum operating current */ return USBPD_REJECT; } } break; case USBPD_CORE_PDO_TYPE_APDO: { uint32_t pdominvoltage, pdomaxvoltage, rdovoltage; pdomaxcurrent = pdo.SRCSNKAPDO.MaxCurrentIn50mAunits; rdoopcurrent = rdo.ProgRDO.OperatingCurrentIn50mAunits; DPM_Ports[PortNum].DPM_RequestedCurrent = rdoopcurrent * 50; if(rdoopcurrent > pdomaxcurrent) { /* Sink requests too much operating current */ return USBPD_REJECT; } pdominvoltage = pdo.SRCSNKAPDO.MinVoltageIn100mV * 100; pdomaxvoltage = pdo.SRCSNKAPDO.MaxVoltageIn100mV * 100; rdovoltage = rdo.ProgRDO.OutputVoltageIn20mV * 20; if ((rdovoltage < pdominvoltage) || (rdovoltage > pdomaxvoltage)) { /* Sink requests too much maximum operating current */ return USBPD_REJECT; } } break; case USBPD_CORE_PDO_TYPE_BATTERY: case USBPD_CORE_PDO_TYPE_VARIABLE: default: { return USBPD_REJECT; } } /* Set RDO position and requested voltage in DPM port structure */ pdhandle->DPM_RequestedVoltage = pdo.SRCFixedPDO.VoltageIn50mVunits * 50; pdhandle->DPM_RDOPositionPrevious = pdhandle->DPM_RDOPosition; pdhandle->DPM_RDOPosition = rdoobjposition; /* Save the power object */ *PtrPowerObject = pdo.GenericPDO.PowerObject; /* Accept the requested power */ /* USBPD_DPM_EvaluateRequest: Sink requested %d mV %d mA for operating current from %d to %d mA\r", pdo.SRCFixedPDO.VoltageIn50mVunits * 50, pdo.SRCFixedPDO.MaxCurrentIn10mAunits * 10, rdo.FixedVariableRDO.MaxOperatingCurrent10mAunits * 10, rdo.FixedVariableRDO.OperatingCurrentIn10mAunits * 10 */ /* USBPD_DPM_EvaluateRequest: Source accepts the requested power */ return USBPD_ACCEPT; } /** * @brief Evaluate received Capabilities Message from Source port and prepare the request message * @param PortNum Port number * @param PtrRequestData Pointer on selected request data object * @param PtrPowerObjectType Pointer on the power data object * @retval None */ void USBPD_DPM_SNK_EvaluateCapabilities(uint8_t PortNum, uint32_t *PtrRequestData, USBPD_CORE_PDO_Type_TypeDef *PtrPowerObjectType) { USBPD_PDO_TypeDef fixed_pdo; USBPD_SNKRDO_TypeDef rdo; USBPD_HandleTypeDef *pdhandle = &DPM_Ports[PortNum]; USBPD_USER_SettingsTypeDef *puser = (USBPD_USER_SettingsTypeDef *)&DPM_USER_Settings[PortNum]; USBPD_DPM_SNKPowerRequestDetails_TypeDef snkpowerrequestdetails; uint32_t pdoindex, size; uint32_t snkpdolist[USBPD_MAX_NB_PDO]; USBPD_PDO_TypeDef snk_fixed_pdo; /* USBPD_DPM_EvaluateCapabilities: Port Partner Requests Max Voltage */ /* Find the Pdo index for the requested voltage */ pdoindex = DPM_FindVoltageIndex(PortNum, &snkpowerrequestdetails); /* Initialize RDO */ rdo.d32 = 0; /* If no valid SNK PDO or if no SRC PDO match found (index>=nb of valid received SRC PDOs or function returned DPM_NO_SRC_PDO_FOUND*/ if (pdoindex >= pdhandle->DPM_NumberOfRcvSRCPDO) { #ifdef _TRACE USBPD_TRACE_Add(USBPD_TRACE_DEBUG, PortNum, 0, (uint8_t *) "PE_EvaluateCapability: could not find desired voltage", sizeof("PE_EvaluateCapability: could not find desired voltage")); #endif /* _TRACE */ fixed_pdo.d32 = pdhandle->DPM_ListOfRcvSRCPDO[0]; /* Read SNK PDO list for retrieving useful data to fill in RDO */ USBPD_PWR_IF_GetPortPDOs(PortNum, USBPD_CORE_DATATYPE_SNK_PDO, (uint8_t*)&snkpdolist[0], &size); /* Store value of 1st SNK PDO (Fixed) in local variable */ snk_fixed_pdo.d32 = snkpdolist[0]; rdo.FixedVariableRDO.ObjectPosition = 1; rdo.FixedVariableRDO.OperatingCurrentIn10mAunits = fixed_pdo.SRCFixedPDO.MaxCurrentIn10mAunits; rdo.FixedVariableRDO.MaxOperatingCurrent10mAunits = puser->DPM_SNKRequestedPower.MaxOperatingCurrentInmAunits / 10; rdo.FixedVariableRDO.CapabilityMismatch = 1; rdo.FixedVariableRDO.USBCommunicationsCapable = snk_fixed_pdo.SNKFixedPDO.USBCommunicationsCapable; if (USBPD_SPECIFICATION_REV2 < DPM_Params[PortNum].PE_SpecRevision) { rdo.FixedVariableRDO.UnchunkedExtendedMessage = DPM_Settings[PortNum].PE_PD3_Support.d.PE_UnchunkSupport; DPM_Params[PortNum].PE_UnchunkSupport = USBPD_FALSE; /* Set unchuncked bit if supported by port partner;*/ if (USBPD_TRUE == fixed_pdo.SRCFixedPDO.UnchunkedExtendedMessage) { DPM_Params[PortNum].PE_UnchunkSupport = USBPD_TRUE; } } DPM_Ports[PortNum].DPM_RequestedCurrent = puser->DPM_SNKRequestedPower.MaxOperatingCurrentInmAunits; pdhandle->DPM_RequestDOMsg = rdo.d32; *PtrPowerObjectType = USBPD_CORE_PDO_TYPE_FIXED; *PtrRequestData = rdo.d32; pdhandle->DPM_RequestedVoltage = 5000; return; } DPM_SNK_BuildRDOfromSelectedPDO(PortNum, pdoindex, &snkpowerrequestdetails,&rdo, PtrPowerObjectType); /* Check to send a Get Get_Source_Cap_Extended. Can be requested if Peak Current of fixed supply PDOs to 0. */ fixed_pdo.d32 = pdhandle->DPM_ListOfRcvSRCPDO[pdoindex]; if (USBPD_CORE_PDO_TYPE_FIXED == fixed_pdo.GenericPDO.PowerObject) { if (USBPD_CORE_PDO_PEAKEQUAL == fixed_pdo.SRCFixedPDO.PeakCurrent) { DPM_Ports[PortNum].FlagSendGetSrcCapaExtended = 1; } } *PtrRequestData = pdhandle->DPM_RequestDOMsg; } /** * @brief Power role swap status update * @param PortNum Port number * @param CurrentRole the current role * @param Status status on power role swap event */ void USBPD_DPM_PowerRoleSwap(uint8_t PortNum, USBPD_PortPowerRole_TypeDef CurrentRole, USBPD_PRS_Status_TypeDef Status) { switch (Status) { case USBPD_PRS_STATUS_VBUS_OFF: if (CurrentRole == USBPD_PORTPOWERROLE_SRC) { /* This variable is used to avoid VCONN disable during HR procedure */ uint32_t _vconnstate = DPM_Params[PortNum].VconnStatus; DPM_Params[PortNum].VconnStatus = USBPD_FALSE; /* In case of power role swap keep VCONN On */ DPM_TurnOffPower(PortNum, CurrentRole); /* restore vconn status */ DPM_Params[PortNum].VconnStatus = _vconnstate; } break; case USBPD_PRS_STATUS_SRC_RP2RD: DPM_AssertRd(PortNum); break; case USBPD_PRS_STATUS_SNK_RD2RP: DPM_AssertRp(PortNum); break; case USBPD_PRS_STATUS_VBUS_ON: DPM_TurnOnPower(PortNum, CurrentRole); break; default: break; } } #if defined(_VCONN_SUPPORT) /** * @brief Callback to be used by PE to evaluate a Vconn swap * @param PortNum Port number * @retval USBPD_ACCEPT, USBPD_REJECT, USBPD_WAIT */ USBPD_StatusTypeDef USBPD_DPM_EvaluateVconnSwap(uint8_t PortNum) { USBPD_StatusTypeDef status = USBPD_REJECT; if (USBPD_TRUE == DPM_USER_Settings[PortNum].PE_VconnSwap) { status = USBPD_ACCEPT; } return status; } /** * @brief Callback to be used by PE to manage VConn * @param PortNum Port number * @param State Enable or Disable VConn on CC lines * @retval USBPD_ACCEPT, USBPD_REJECT */ USBPD_StatusTypeDef USBPD_DPM_PE_VconnPwr(uint8_t PortNum, USBPD_FunctionalState State) { USBPD_StatusTypeDef status = USBPD_ERROR; if((USBPD_ENABLE == State) && (CCNONE != DPM_Params[PortNum].VconnCCIs)) { status = USBPD_PWR_IF_Enable_VConn(PortNum,DPM_Params[PortNum].VconnCCIs); } if((USBPD_DISABLE == State) && (CCNONE != DPM_Params[PortNum].VconnCCIs)) { status = USBPD_PWR_IF_Disable_VConn(PortNum,DPM_Params[PortNum].VconnCCIs); } return status; } #endif /* _VCONN_SUPPORT */ /** * @brief DPM callback to allow PE to forward extended message information. * @param PortNum Port number * @param MsgType Type of message to be handled in DPM * This parameter can be one of the following values: * @arg @ref USBPD_EXT_SECURITY_REQUEST Security Request extended message * @arg @ref USBPD_EXT_SECURITY_RESPONSE Security Response extended message * @param Ptr Pointer on address Extended Message data could be read (u8 pointer) * @param Size Nb of u8 that compose Extended message * @retval None */ void USBPD_DPM_ExtendedMessageReceived(uint8_t PortNum, USBPD_ExtendedMsg_TypeDef MsgType, uint8_t *ptrData, uint16_t DataSize) { if (DataSize == 0) { /* No data received. */ return; } switch(USBPD_EXTENDED_MESSAGE | MsgType) { default: break; } } /** * @brief DPM callback used to know user choice about Data Role Swap. * @param PortNum Port number * @retval USBPD_REJECT, UBPD_ACCEPT */ USBPD_StatusTypeDef USBPD_DPM_EvaluateDataRoleSwap(uint8_t PortNum) { USBPD_StatusTypeDef status = USBPD_REJECT; if (USBPD_TRUE == DPM_USER_Settings[PortNum].PE_DataSwap) { status = USBPD_ACCEPT; } return status; } /** * @brief Callback to be used by PE to check is VBUS is ready or present * @param PortNum Port number * @param Vsafe Vsafe status based on @ref USBPD_VSAFE_StatusTypeDef * @retval USBPD_DISABLE or USBPD_ENABLE */ USBPD_FunctionalState USBPD_DPM_IsPowerReady(uint8_t PortNum, USBPD_VSAFE_StatusTypeDef Vsafe) { return ((USBPD_OK == USBPD_PWR_IF_SupplyReady(PortNum, Vsafe)) ? USBPD_ENABLE : USBPD_DISABLE); } /** * @} */ /** @defgroup USBPD_USER_EXPORTED_FUNCTIONS_GROUP3 USBPD USER Functions PD messages requests * @{ */ /** * @brief Request the PE to send a hard reset * @param PortNum The current port number * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestHardReset(uint8_t PortNum) { return USBPD_PE_Request_HardReset(PortNum); } /** * @brief Request the PE to send a cable reset. * @param PortNum The current port number * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestCableReset(uint8_t PortNum) { /* Not yet implemeneted. */ return USBPD_ERROR; } /** * @brief Request the PE to send a GOTOMIN message * @param PortNum The current port number * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestGotoMin(uint8_t PortNum) { return USBPD_PE_Request_CtrlMessage(PortNum, USBPD_CONTROLMSG_GOTOMIN, USBPD_SOPTYPE_SOP); } /** * @brief Request the PE to send a PING message * @note In USB-PD stack, only ping management for P3.0 is implemented. * If PD2.0 is used, PING timer needs to be implemented on user side. * @param PortNum The current port number * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestPing(uint8_t PortNum) { return USBPD_PE_Request_CtrlMessage(PortNum, USBPD_CONTROLMSG_PING, USBPD_SOPTYPE_SOP); } /** * @brief Request the PE to send a request message. * @param PortNum The current port number * @param IndexSrcPDO Index on the selected SRC PDO (value between 1 to 7) * @param RequestedVoltage Requested voltage (in MV and use mainly for APDO) * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestMessageRequest(uint8_t PortNum, uint8_t IndexSrcPDO, uint16_t RequestedVoltage) { USBPD_StatusTypeDef status = USBPD_ERROR; uint32_t voltage, allowablepower; USBPD_SNKRDO_TypeDef rdo; USBPD_PDO_TypeDef pdo; USBPD_CORE_PDO_Type_TypeDef pdo_object; USBPD_USER_SettingsTypeDef *puser = (USBPD_USER_SettingsTypeDef *)&DPM_USER_Settings[PortNum]; USBPD_DPM_SNKPowerRequestDetails_TypeDef request_details; rdo.d32 = 0; /* selected SRC PDO */ pdo.d32 = DPM_Ports[PortNum].DPM_ListOfRcvSRCPDO[(IndexSrcPDO - 1)]; voltage = RequestedVoltage; allowablepower = (puser->DPM_SNKRequestedPower.MaxOperatingCurrentInmAunits * RequestedVoltage) / 1000; if (USBPD_TRUE == USBPD_DPM_SNK_EvaluateMatchWithSRCPDO(PortNum, pdo.d32, &voltage, &allowablepower)) { /* Check that voltage has been correctly selected */ if (RequestedVoltage == voltage) { request_details.RequestedVoltageInmVunits = RequestedVoltage; request_details.OperatingCurrentInmAunits = ((1000 * allowablepower)/RequestedVoltage); request_details.MaxOperatingCurrentInmAunits = puser->DPM_SNKRequestedPower.MaxOperatingCurrentInmAunits; request_details.MaxOperatingPowerInmWunits = puser->DPM_SNKRequestedPower.MaxOperatingPowerInmWunits; request_details.OperatingPowerInmWunits = puser->DPM_SNKRequestedPower.OperatingPowerInmWunits; DPM_SNK_BuildRDOfromSelectedPDO(PortNum, (IndexSrcPDO - 1), &request_details, &rdo, &pdo_object); status = USBPD_PE_Send_Request(PortNum, rdo.d32, pdo_object); } } return status; } /** * @brief Request the PE to send a GET_SRC_CAPA message * @param PortNum The current port number * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestGetSourceCapability(uint8_t PortNum) { return USBPD_PE_Request_CtrlMessage(PortNum, USBPD_CONTROLMSG_GET_SRC_CAP, USBPD_SOPTYPE_SOP); } /** * @brief Request the PE to send a GET_SNK_CAPA message * @param PortNum The current port number * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestGetSinkCapability(uint8_t PortNum) { return USBPD_PE_Request_CtrlMessage(PortNum, USBPD_CONTROLMSG_GET_SNK_CAP, USBPD_SOPTYPE_SOP); } /** * @brief Request the PE to perform a Data Role Swap. * @param PortNum The current port number * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestDataRoleSwap(uint8_t PortNum) { return USBPD_PE_Request_CtrlMessage(PortNum, USBPD_CONTROLMSG_DR_SWAP, USBPD_SOPTYPE_SOP); } /** * @brief Request the PE to perform a Power Role Swap. * @param PortNum The current port number * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestPowerRoleSwap(uint8_t PortNum) { return USBPD_PE_Request_CtrlMessage(PortNum, USBPD_CONTROLMSG_PR_SWAP, USBPD_SOPTYPE_SOP); } /** * @brief Request the PE to perform a VCONN Swap. * @param PortNum The current port number * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestVconnSwap(uint8_t PortNum) { return USBPD_PE_Request_CtrlMessage(PortNum, USBPD_CONTROLMSG_VCONN_SWAP, USBPD_SOPTYPE_SOP); } /** * @brief Request the PE to send a soft reset * @param PortNum The current port number * @param SOPType SOP Type based on @ref USBPD_SOPType_TypeDef * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestSoftReset(uint8_t PortNum, USBPD_SOPType_TypeDef SOPType) { return USBPD_PE_Request_CtrlMessage(PortNum, USBPD_CONTROLMSG_SOFT_RESET, SOPType); } /** * @brief Request the PE to send a Source Capability message. * @param PortNum The current port number * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestSourceCapability(uint8_t PortNum) { /* PE will directly get the PDO saved in structure @ref PWR_Port_PDO_Storage */ return USBPD_PE_Request_DataMessage(PortNum, USBPD_DATAMSG_SRC_CAPABILITIES, NULL); } /** * @brief Request the PE to send a VDM discovery identity * @param PortNum The current port number * @param SOPType SOP Type * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestVDM_DiscoveryIdentify(uint8_t PortNum, USBPD_SOPType_TypeDef SOPType) { return USBPD_PE_SVDM_RequestIdentity(PortNum, SOPType); } /** * @brief Request the PE to send a VDM discovery SVID * @param PortNum The current port number * @param SOPType SOP Type * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestVDM_DiscoverySVID(uint8_t PortNum, USBPD_SOPType_TypeDef SOPType) { return USBPD_PE_SVDM_RequestSVID(PortNum, SOPType); } /** * @brief Request the PE to perform a VDM Discovery mode message on one SVID. * @param PortNum The current port number * @param SOPType SOP Type * @param SVID SVID used for discovery mode message * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestVDM_DiscoveryMode(uint8_t PortNum, USBPD_SOPType_TypeDef SOPType, uint16_t SVID) { return USBPD_PE_SVDM_RequestMode(PortNum, SOPType, SVID); } /** * @brief Request the PE to perform a VDM mode enter. * @param PortNum The current port number * @param SOPType SOP Type * @param SVID SVID used for discovery mode message * @param ModeIndex Index of the mode to be entered * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestVDM_EnterMode(uint8_t PortNum, USBPD_SOPType_TypeDef SOPType, uint16_t SVID, uint8_t ModeIndex) { return USBPD_PE_SVDM_RequestModeEnter(PortNum, SOPType, SVID, ModeIndex); } /** * @brief Request the PE to perform a VDM mode exit. * @param PortNum The current port number * @param SOPType SOP Type * @param SVID SVID used for discovery mode message * @param ModeIndex Index of the mode to be exit * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestVDM_ExitMode(uint8_t PortNum, USBPD_SOPType_TypeDef SOPType, uint16_t SVID, uint8_t ModeIndex) { return USBPD_PE_SVDM_RequestModeExit(PortNum, SOPType, SVID, ModeIndex); } /** * @brief Request the PE to perform a VDM Attention. * @param PortNum The current port number * @param SOPType SOP Type * @param SVID Used SVID * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestAttention(uint8_t PortNum, USBPD_SOPType_TypeDef SOPType, uint16_t SVID) { return USBPD_PE_SVDM_RequestAttention(PortNum, SOPType, SVID); } /** * @brief Request the PE to send a Display Port status * @param PortNum The current port number * @param SOPType SOP Type * @param SVID Used SVID * @param pDPStatus Pointer on DP Status data (32 bit) * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestDisplayPortStatus(uint8_t PortNum, USBPD_SOPType_TypeDef SOPType, uint16_t SVID, uint32_t *pDPStatus) { USBPD_VDM_FillDPStatus(PortNum, (USBPD_DPStatus_TypeDef*)pDPStatus); return USBPD_PE_SVDM_RequestSpecific(PortNum, SOPType, SVDM_SPECIFIC_1, SVID); } /** * @brief Request the PE to send a Display Port Config * @param PortNum The current port number * @param SOPType SOP Type * @param SVID Used SVID * @param pDPConfig Pointer on DP Config data (32 bit) * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestDisplayPortConfig(uint8_t PortNum, USBPD_SOPType_TypeDef SOPType, uint16_t SVID, uint32_t *pDPConfig) { USBPD_VDM_FillDPConfig(PortNum, (USBPD_DPConfig_TypeDef*)pDPConfig); return USBPD_PE_SVDM_RequestSpecific(PortNum, SOPType, SVDM_SPECIFIC_2, SVID); } /** * @brief Request the PE to send an ALERT to port partner * @param PortNum The current port number * @param Alert Alert based on @ref USBPD_ADO_TypeDef * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestAlert(uint8_t PortNum, USBPD_ADO_TypeDef Alert) { return USBPD_PE_Request_DataMessage(PortNum, USBPD_DATAMSG_ALERT, (uint32_t*)&Alert.d32); } /** * @brief Request the PE to get a source capability extended * @param PortNum The current port number * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestGetSourceCapabilityExt(uint8_t PortNum) { return USBPD_PE_Request_CtrlMessage(PortNum, USBPD_CONTROLMSG_GET_SRC_CAPEXT, USBPD_SOPTYPE_SOP); } /** * @brief Request the PE to get a sink capability extended * @param PortNum The current port number * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestGetSinkCapabilityExt(uint8_t PortNum) { return USBPD_PE_Request_CtrlMessage(PortNum, USBPD_CONTROLMSG_GET_SNK_CAPEXT, USBPD_SOPTYPE_SOP); } /** * @brief Request the PE to get a manufacturer infor * @param PortNum The current port number * @param SOPType SOP Type * @param pManuInfoData Pointer on manufacturer info based on @ref USBPD_GMIDB_TypeDef * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestGetManufacturerInfo(uint8_t PortNum, USBPD_SOPType_TypeDef SOPType, uint8_t* pManuInfoData) { return USBPD_PE_SendExtendedMessage(PortNum, SOPType, USBPD_EXT_GET_MANUFACTURER_INFO, (uint8_t*)pManuInfoData, sizeof(USBPD_GMIDB_TypeDef)); } /** * @brief Request the PE to request a GET_PPS_STATUS * @param PortNum The current port number * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestGetPPS_Status(uint8_t PortNum) { return USBPD_PE_Request_CtrlMessage(PortNum, USBPD_CONTROLMSG_GET_PPS_STATUS, USBPD_SOPTYPE_SOP); } /** * @brief Request the PE to request a GET_STATUS * @param PortNum The current port number * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestGetStatus(uint8_t PortNum) { return USBPD_PE_Request_CtrlMessage(PortNum, USBPD_CONTROLMSG_GET_STATUS, USBPD_SOPTYPE_SOP); } /** * @brief Request the PE to perform a Fast Role Swap. * @param PortNum The current port number * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestFastRoleSwap(uint8_t PortNum) { return USBPD_PE_Request_CtrlMessage(PortNum, USBPD_CONTROLMSG_FR_SWAP, USBPD_SOPTYPE_SOP); } /** * @brief Request the PE to send a GET_COUNTRY_CODES message * @param PortNum The current port number * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestGetCountryCodes(uint8_t PortNum) { return USBPD_PE_Request_CtrlMessage(PortNum, USBPD_CONTROLMSG_GET_COUNTRY_CODES, USBPD_SOPTYPE_SOP); } /** * @brief Request the PE to send a GET_COUNTRY_INFO message * @param PortNum The current port number * @param CountryCode Country code (1st character and 2nd of the Alpha-2 Country) * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestGetCountryInfo(uint8_t PortNum, uint16_t CountryCode) { return USBPD_PE_Request_DataMessage(PortNum, USBPD_DATAMSG_GET_COUNTRY_INFO, (uint32_t*)&CountryCode); } /** * @brief Request the PE to send a GET_BATTERY_CAPA * @param PortNum The current port number * @param pBatteryCapRef Pointer on the Battery Capability reference * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestGetBatteryCapability(uint8_t PortNum, uint8_t *pBatteryCapRef) { return USBPD_PE_SendExtendedMessage(PortNum, USBPD_SOPTYPE_SOP, USBPD_EXT_GET_BATTERY_CAP, (uint8_t*)pBatteryCapRef, 1); } /** * @brief Request the PE to send a GET_BATTERY_STATUS * @param PortNum The current port number * @param pBatteryStatusRef Pointer on the Battery Status reference * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestGetBatteryStatus(uint8_t PortNum, uint8_t *pBatteryStatusRef) { return USBPD_PE_SendExtendedMessage(PortNum, USBPD_SOPTYPE_SOP, USBPD_EXT_GET_BATTERY_STATUS, (uint8_t*)pBatteryStatusRef, 1); } /** * @brief Request the PE to send a SECURITY_REQUEST * @param PortNum The current port number * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_DPM_RequestSecurityRequest(uint8_t PortNum) { return USBPD_ERROR; } /** * @} */ /** @addtogroup USBPD_USER_PRIVATE_FUNCTIONS * @{ */ /** * @brief Examinate a given SRC PDO to check if matching with SNK capabilities. * @param PortNum Port number * @param SrcPDO Selected SRC PDO (32 bits) * @param PtrRequestedVoltage Pointer on Voltage value that could be reached if SRC PDO is requested (only valid if USBPD_TRUE is returned) in mV * @param PtrRequestedPower Pointer on Power value that could be reached if SRC PDO is requested (only valid if USBPD_TRUE is returned) in mW * @retval USBPD_FALSE of USBPD_TRUE (USBPD_TRUE returned in SRC PDO is considered matching with SNK profile) */ uint32_t USBPD_DPM_SNK_EvaluateMatchWithSRCPDO(uint8_t PortNum, uint32_t SrcPDO, uint32_t* PtrRequestedVoltage, uint32_t* PtrRequestedPower) { USBPD_PDO_TypeDef srcpdo, snkpdo; uint32_t match = USBPD_FALSE; uint32_t nbsnkpdo; uint32_t snkpdo_array[USBPD_MAX_NB_PDO]; uint16_t i, srcvoltage50mv, srcmaxvoltage50mv, srcminvoltage50mv, srcmaxcurrent10ma; uint16_t snkvoltage50mv, snkmaxvoltage50mv, snkminvoltage50mv, snkopcurrent10ma; uint32_t maxrequestedpower, currentrequestedpower; uint32_t maxrequestedvoltage, currentrequestedvoltage; uint32_t snkoppower250mw, srcmaxpower250mw; /* Retrieve SNK PDO list from PWR_IF storage : PDO values + nb of u32 written by PWR_IF (nb of PDOs) */ USBPD_PWR_IF_GetPortPDOs(PortNum, USBPD_CORE_DATATYPE_SNK_PDO, (uint8_t*)snkpdo_array, &nbsnkpdo); if (0 == nbsnkpdo) { return(USBPD_FALSE); } /* Set default output values */ maxrequestedpower = 0; maxrequestedvoltage = 0; /* Check SRC PDO value according to its type */ srcpdo.d32 = SrcPDO; switch(srcpdo.GenericPDO.PowerObject) { /* SRC Fixed Supply PDO */ case USBPD_CORE_PDO_TYPE_FIXED: srcvoltage50mv = srcpdo.SRCFixedPDO.VoltageIn50mVunits; srcmaxcurrent10ma = srcpdo.SRCFixedPDO.MaxCurrentIn10mAunits; /* Loop through SNK PDO list */ for (i=0; i= SRC Voltage && SNK Min voltage <= SRC Voltage && SNK Op current <= SRC Max current Requested Voltage : SRC Voltage Requested Op Current : SNK Op Current Requested Max Current : SNK Op Current */ if ( (snkmaxvoltage50mv >= srcvoltage50mv) &&(snkminvoltage50mv <= srcvoltage50mv) &&(snkopcurrent10ma <= srcmaxcurrent10ma)) { currentrequestedpower = (srcvoltage50mv * snkopcurrent10ma) / 2; /* to get value in mw */ currentrequestedvoltage = srcvoltage50mv; } break; /* SNK Battery Supply PDO */ case USBPD_CORE_PDO_TYPE_BATTERY: snkmaxvoltage50mv = snkpdo.SNKBatteryPDO.MaxVoltageIn50mVunits; snkminvoltage50mv = snkpdo.SNKBatteryPDO.MinVoltageIn50mVunits; snkoppower250mw = snkpdo.SNKBatteryPDO.OperationalPowerIn250mWunits; /* Match if : SNK Max voltage >= SRC Voltage && SNK Min voltage <= SRC Voltage && SNK Op power <= SRC Max current * SRC Voltage Requested Voltage : SRC Voltage Requested Op Current : SNK Op Power/ SRC Voltage Requested Max Current : SNK Op Power/ SRC Voltage */ if ( (snkmaxvoltage50mv >= srcvoltage50mv) &&(snkminvoltage50mv <= srcvoltage50mv) &&(snkoppower250mw <= ((srcvoltage50mv * srcmaxcurrent10ma)/500))) /* to get value in 250 mw units */ { currentrequestedvoltage = srcvoltage50mv; currentrequestedpower = snkoppower250mw; } break; /* SNK Augmented Power Data Object (APDO) */ case USBPD_CORE_PDO_TYPE_APDO: break; default: break; } if (currentrequestedpower > maxrequestedpower) { match = USBPD_TRUE; maxrequestedpower = currentrequestedpower; maxrequestedvoltage = currentrequestedvoltage; } } break; /* SRC Variable Supply (non-battery) PDO */ case USBPD_CORE_PDO_TYPE_VARIABLE: srcmaxvoltage50mv = srcpdo.SRCVariablePDO.MaxVoltageIn50mVunits; srcminvoltage50mv = srcpdo.SRCVariablePDO.MinVoltageIn50mVunits; srcmaxcurrent10ma = srcpdo.SRCVariablePDO.MaxCurrentIn10mAunits; /* Loop through SNK PDO list */ for (i=0; i= SRC Max Voltage && SNK Min voltage <= SRC Min Voltage && SNK Op current <= SRC Max current Requested Voltage : Any value between SRC Min Voltage and SRC Max Voltage Requested Op Current : SNK Op Current Requested Max Current : SNK Op Current */ if ( (snkmaxvoltage50mv >= srcmaxvoltage50mv) &&(snkminvoltage50mv <= srcminvoltage50mv) &&(snkopcurrent10ma <= srcmaxcurrent10ma)) { currentrequestedpower = (srcmaxvoltage50mv * snkopcurrent10ma) / 2; /* to get value in mw */ currentrequestedvoltage = srcmaxvoltage50mv; } break; /* SNK Battery Supply PDO */ case USBPD_CORE_PDO_TYPE_BATTERY: snkmaxvoltage50mv = snkpdo.SNKBatteryPDO.MaxVoltageIn50mVunits; snkminvoltage50mv = snkpdo.SNKBatteryPDO.MinVoltageIn50mVunits; snkoppower250mw = snkpdo.SNKBatteryPDO.OperationalPowerIn250mWunits; /* Match if : SNK Max voltage >= SRC Max Voltage && SNK Min voltage <= SRC Min Voltage && SNK Op power <= SRC Max current * SRC Max Voltage Requested Voltage : Any value between SRC Min Voltage and SRC Max Voltage, that fulfill SNK Op power <= Voltage * SRC Max Current Requested Op Current : SNK Op Power/ SRC Voltage Requested Max Current : SNK Op Power/ SRC Voltage */ if ( (snkmaxvoltage50mv >= srcmaxvoltage50mv) &&(snkminvoltage50mv <= srcminvoltage50mv) &&(snkoppower250mw <= ((srcmaxvoltage50mv * srcmaxcurrent10ma)/500))) /* to get value in 250 mw units */ { currentrequestedpower = snkoppower250mw * 250; /* to get value in mw */ currentrequestedvoltage = srcmaxvoltage50mv; } break; /* SNK Augmented Power Data Object (APDO) */ case USBPD_CORE_PDO_TYPE_APDO: break; default: break; } if (currentrequestedpower > maxrequestedpower) { match = USBPD_TRUE; maxrequestedpower = currentrequestedpower; maxrequestedvoltage = currentrequestedvoltage; } } break; /* SRC Battery Supply PDO */ case USBPD_CORE_PDO_TYPE_BATTERY: srcmaxvoltage50mv = srcpdo.SRCBatteryPDO.MaxVoltageIn50mVunits; srcminvoltage50mv = srcpdo.SRCBatteryPDO.MinVoltageIn50mVunits; srcmaxpower250mw = srcpdo.SRCBatteryPDO.MaxAllowablePowerIn250mWunits; /* Loop through SNK PDO list */ for (i=0; i= SRC Max Voltage && SNK Min voltage <= SRC Min Voltage && SNK Op current * SRC Max Voltage <= SRC Max Power Requested Voltage : Any value between SRC Min Voltage and SRC Max Voltage : SRC Max Voltage Requested Op Current : SNK Op Current Requested Max Current : SNK Op Current */ if ( (snkmaxvoltage50mv >= srcmaxvoltage50mv) &&(snkminvoltage50mv <= srcminvoltage50mv) &&(srcmaxvoltage50mv * snkopcurrent10ma <= srcmaxpower250mw)) { currentrequestedpower = (srcmaxvoltage50mv * snkopcurrent10ma) / 2; /* to get value in mw */ currentrequestedvoltage = srcmaxvoltage50mv; } break; /* SNK Battery Supply PDO */ case USBPD_CORE_PDO_TYPE_BATTERY: snkmaxvoltage50mv = snkpdo.SNKBatteryPDO.MaxVoltageIn50mVunits; snkminvoltage50mv = snkpdo.SNKBatteryPDO.MinVoltageIn50mVunits; snkoppower250mw = snkpdo.SNKBatteryPDO.OperationalPowerIn250mWunits; /* Match if : SNK Max voltage >= SRC Max Voltage && SNK Min voltage <= SRC Min Voltage && SNK Op power <= SRC Max power Requested Voltage : Any value between SRC Min Voltage and SRC Max Voltage, that fulfill SNK Op power <= Voltage * SRC Max Current Requested Op Current : SNK Op Power/ SRC Voltage Requested Max Current : SNK Op Power/ SRC Voltage */ if ( (snkmaxvoltage50mv >= srcmaxvoltage50mv) &&(snkminvoltage50mv <= srcminvoltage50mv) &&(snkoppower250mw <= srcmaxpower250mw)) { currentrequestedpower = snkoppower250mw * 250; /* to get value in mw */ currentrequestedvoltage = srcmaxvoltage50mv; } break; /* SNK Augmented Power Data Object (APDO) */ case USBPD_CORE_PDO_TYPE_APDO: break; default: break; } if (currentrequestedpower > maxrequestedpower) { match = USBPD_TRUE; maxrequestedpower = currentrequestedpower; maxrequestedvoltage = currentrequestedvoltage; } } break; /* Augmented Power Data Object (APDO) */ case USBPD_CORE_PDO_TYPE_APDO: { uint16_t srcmaxvoltage100mv, srcmaxcurrent50ma; srcmaxvoltage100mv = srcpdo.SRCSNKAPDO.MaxVoltageIn100mV; srcmaxcurrent50ma = srcpdo.SRCSNKAPDO.MaxCurrentIn50mAunits; /* Loop through SNK PDO list */ for (i=0; i maxrequestedpower) { match = USBPD_TRUE; maxrequestedpower = currentrequestedpower; maxrequestedvoltage = currentrequestedvoltage; } } } break; default: return(USBPD_FALSE); } if (maxrequestedpower > 0) { *PtrRequestedPower = maxrequestedpower; *PtrRequestedVoltage = maxrequestedvoltage * 50; /* value in mV */ } return(match); } /** * @brief Find PDO index that offers the most amount of power and in accordance with SNK capabilities. * @param PortNum Port number * @param PtrRequestPowerDetails Sink requested power details structure pointer * @retval Index of PDO within source capabilities message (DPM_NO_SRC_PDO_FOUND indicating not found) */ static uint32_t DPM_FindVoltageIndex(uint32_t PortNum, USBPD_DPM_SNKPowerRequestDetails_TypeDef* PtrRequestPowerDetails) { uint32_t *ptpdoarray; USBPD_PDO_TypeDef pdo; uint32_t voltage, reqvoltage, nbpdo, allowablepower, maxpower; uint32_t curr_index = DPM_NO_SRC_PDO_FOUND, temp_index; USBPD_USER_SettingsTypeDef *puser = (USBPD_USER_SettingsTypeDef *)&DPM_USER_Settings[PortNum]; allowablepower = 0; maxpower = 0; reqvoltage = 0; voltage = 0; /* Search PDO index among Source PDO of Port */ nbpdo = DPM_Ports[PortNum].DPM_NumberOfRcvSRCPDO; ptpdoarray = DPM_Ports[PortNum].DPM_ListOfRcvSRCPDO; /* search the better PDO in the list of source PDOs */ for(temp_index = 0; temp_index < nbpdo; temp_index++) { pdo.d32 = ptpdoarray[temp_index]; /* check if the received source PDO is matching any of the SNK PDO */ allowablepower = 0; if (USBPD_TRUE == USBPD_DPM_SNK_EvaluateMatchWithSRCPDO(PortNum, pdo.d32, &voltage, &allowablepower)) { /* choose the "better" PDO, in this case only the distance in absolute value from the target voltage */ if (allowablepower >= maxpower) { /* Add additional check for compatibility of this SRC PDO with port characteristics (defined in DPM_USER_Settings) */ if ( (voltage >= puser->DPM_SNKRequestedPower.MinOperatingVoltageInmVunits) &&(voltage <= puser->DPM_SNKRequestedPower.MaxOperatingVoltageInmVunits) &&(allowablepower <= puser->DPM_SNKRequestedPower.MaxOperatingPowerInmWunits)) { /* consider the current PDO the better one until now */ curr_index = temp_index; maxpower = allowablepower; reqvoltage = voltage; } } } } if (curr_index != DPM_NO_SRC_PDO_FOUND) { PtrRequestPowerDetails->MaxOperatingCurrentInmAunits = puser->DPM_SNKRequestedPower.MaxOperatingCurrentInmAunits; PtrRequestPowerDetails->OperatingCurrentInmAunits = (1000 * maxpower)/voltage; PtrRequestPowerDetails->MaxOperatingPowerInmWunits = puser->DPM_SNKRequestedPower.MaxOperatingPowerInmWunits; PtrRequestPowerDetails->OperatingPowerInmWunits = maxpower; PtrRequestPowerDetails->RequestedVoltageInmVunits = reqvoltage; } return curr_index; } /** * @brief Build RDO to be used in Request message according to selected PDO from received SRC Capabilities * @param PortNum Port number * @param IndexSrcPDO Index on the selected SRC PDO (value between 0 to 6) * @param PtrRequestPowerDetails Sink requested power details structure pointer * @param Rdo Pointer on the RDO * @param PtrPowerObject Pointer on the selected power object * @retval None */ void DPM_SNK_BuildRDOfromSelectedPDO(uint8_t PortNum, uint8_t IndexSrcPDO, USBPD_DPM_SNKPowerRequestDetails_TypeDef* PtrRequestPowerDetails, USBPD_SNKRDO_TypeDef* Rdo, USBPD_CORE_PDO_Type_TypeDef *PtrPowerObject) { uint32_t mv = 0, mw = 0, ma = 0, size; USBPD_PDO_TypeDef pdo; USBPD_SNKRDO_TypeDef rdo; USBPD_HandleTypeDef *pdhandle = &DPM_Ports[PortNum]; USBPD_USER_SettingsTypeDef *puser = (USBPD_USER_SettingsTypeDef *)&DPM_USER_Settings[PortNum]; uint32_t snkpdolist[USBPD_MAX_NB_PDO]; USBPD_PDO_TypeDef snk_fixed_pdo; /* Initialize RDO */ rdo.d32 = 0; /* Read SNK PDO list for retrieving useful data to fill in RDO */ USBPD_PWR_IF_GetPortPDOs(PortNum, USBPD_CORE_DATATYPE_SNK_PDO, (uint8_t*)&snkpdolist[0], &size); /* Store value of 1st SNK PDO (Fixed) in local variable */ snk_fixed_pdo.d32 = snkpdolist[0]; /* Set common fields in RDO */ pdo.d32 = pdhandle->DPM_ListOfRcvSRCPDO[0]; rdo.GenericRDO.USBCommunicationsCapable = snk_fixed_pdo.SNKFixedPDO.USBCommunicationsCapable; #if defined(USBPD_REV30_SUPPORT) && defined(_UNCHUNKED_SUPPORT) if (USBPD_SPECIFICATION_REV2 < DPM_Params[PortNum].PE_SpecRevision) { rdo.FixedVariableRDO.UnchunkedExtendedMessage = DPM_Settings[PortNum].PE_PD3_Support.d.PE_UnchunkSupport; DPM_Params[PortNum].PE_UnchunkSupport = USBPD_FALSE; /* Set unchuncked bit if supported by port partner;*/ if (USBPD_TRUE == pdo.SRCFixedPDO.UnchunkedExtendedMessage) { DPM_Params[PortNum].PE_UnchunkSupport = USBPD_TRUE; } } #endif /* USBPD_REV30_SUPPORT && _UNCHUNKED_SUPPORT */ /* If no valid SNK PDO or if no SRC PDO match found (index>=nb of valid received SRC PDOs */ if ((size < 1) || (IndexSrcPDO >= pdhandle->DPM_NumberOfRcvSRCPDO)) { /* USBPD_DPM_EvaluateCapabilities: Mismatch, could not find desired pdo index */ #ifdef _TRACE USBPD_TRACE_Add(USBPD_TRACE_DEBUG, PortNum, 0, (uint8_t*)"DPM_SNK_BuildRDOfromSelectedPDO: Pb in SRC PDO selection", sizeof("DPM_SNK_BuildRDOfromSelectedPDO: Pb in SRC PDO selection")); #endif /* _TRACE */ rdo.FixedVariableRDO.ObjectPosition = 1; rdo.FixedVariableRDO.OperatingCurrentIn10mAunits = pdo.SRCFixedPDO.MaxCurrentIn10mAunits; rdo.FixedVariableRDO.MaxOperatingCurrent10mAunits = puser->DPM_SNKRequestedPower.MaxOperatingCurrentInmAunits / 10; rdo.FixedVariableRDO.CapabilityMismatch = 1; rdo.FixedVariableRDO.USBCommunicationsCapable = snk_fixed_pdo.SNKFixedPDO.USBCommunicationsCapable; DPM_Ports[PortNum].DPM_RequestedCurrent = puser->DPM_SNKRequestedPower.MaxOperatingCurrentInmAunits; /* USBPD_DPM_EvaluateCapabilities: Mismatch, could not find desired pdo index */ pdhandle->DPM_RequestDOMsg = rdo.d32; return; } /* Set the Object position */ rdo.GenericRDO.ObjectPosition = IndexSrcPDO + 1; rdo.GenericRDO.NoUSBSuspend = 1; /* Extract power information from Power Data Object */ pdo.d32 = pdhandle->DPM_ListOfRcvSRCPDO[IndexSrcPDO]; *PtrPowerObject = pdo.GenericPDO.PowerObject; /* Retrieve request details from SRC PDO selection */ mv = PtrRequestPowerDetails->RequestedVoltageInmVunits; ma = PtrRequestPowerDetails->OperatingCurrentInmAunits; switch(pdo.GenericPDO.PowerObject) { case USBPD_CORE_PDO_TYPE_FIXED: /* USBPD_DPM_EvaluateCapabilities: Mismatch, less power offered than the operating power */ ma = USBPD_MIN(ma, (pdo.SRCFixedPDO.MaxCurrentIn10mAunits * 10)); mw = (ma * mv)/1000; /* mW */ DPM_Ports[PortNum].DPM_RequestedCurrent = ma; rdo.FixedVariableRDO.OperatingCurrentIn10mAunits = ma / 10; rdo.FixedVariableRDO.MaxOperatingCurrent10mAunits = ma / 10; rdo.FixedVariableRDO.CapabilityMismatch = 0; rdo.FixedVariableRDO.GiveBackFlag = 0; if(mw < puser->DPM_SNKRequestedPower.OperatingPowerInmWunits) { /* USBPD_DPM_EvaluateCapabilities: Mismatch, less power offered than the operating power */ rdo.FixedVariableRDO.MaxOperatingCurrent10mAunits = puser->DPM_SNKRequestedPower.MaxOperatingCurrentInmAunits / 10; rdo.FixedVariableRDO.CapabilityMismatch = 1; } break; case USBPD_CORE_PDO_TYPE_VARIABLE: { /* USBPD_DPM_EvaluateCapabilities: Mismatch, less power offered than the operating power */ ma = USBPD_MIN(ma, puser->DPM_SNKRequestedPower.MaxOperatingCurrentInmAunits); mw = (ma * mv)/1000; /* mW */ DPM_Ports[PortNum].DPM_RequestedCurrent = ma; rdo.FixedVariableRDO.OperatingCurrentIn10mAunits = ma / 10; rdo.FixedVariableRDO.MaxOperatingCurrent10mAunits = ma / 10; if(mw < puser->DPM_SNKRequestedPower.OperatingPowerInmWunits) { /* USBPD_DPM_EvaluateCapabilities: Mismatch, less power offered than the operating power */ rdo.FixedVariableRDO.MaxOperatingCurrent10mAunits = puser->DPM_SNKRequestedPower.MaxOperatingCurrentInmAunits / 10; rdo.FixedVariableRDO.CapabilityMismatch = 1; } } break; case USBPD_CORE_PDO_TYPE_BATTERY: { /* USBPD_DPM_EvaluateCapabilities: Battery Request Data Object */ mw = USBPD_MIN(PtrRequestPowerDetails->OperatingPowerInmWunits, puser->DPM_SNKRequestedPower.MaxOperatingPowerInmWunits); /* mW */ ma = (1000 * mw) / mv; /* mA */ ma = USBPD_MIN(ma, puser->DPM_SNKRequestedPower.MaxOperatingCurrentInmAunits); DPM_Ports[PortNum].DPM_RequestedCurrent = ma; mw = (ma * mv)/1000; /* mW */ rdo.BatteryRDO.OperatingPowerIn250mWunits = mw / 250; rdo.BatteryRDO.MaxOperatingPowerIn250mWunits = mw / 250; if(mw < puser->DPM_SNKRequestedPower.OperatingPowerInmWunits) { /* Mismatch, less power offered than the operating power */ rdo.BatteryRDO.CapabilityMismatch = 1; } } break; case USBPD_CORE_PDO_TYPE_APDO: { DPM_Ports[PortNum].DPM_RequestedCurrent = ma; rdo.ProgRDO.ObjectPosition = IndexSrcPDO + 1; rdo.ProgRDO.OperatingCurrentIn50mAunits = ma / 50; rdo.ProgRDO.OutputVoltageIn20mV = mv / 20; } break; default: break; } pdhandle->DPM_RequestDOMsg = rdo.d32; pdhandle->DPM_RDOPosition = rdo.GenericRDO.ObjectPosition; Rdo->d32 = pdhandle->DPM_RequestDOMsg; /* Get the requested voltage */ pdhandle->DPM_RequestedVoltage = mv; } /** * @brief Turn Off power supply. * @param PortNum The current port number * @retval USBPD_OK, USBPD_ERROR */ static USBPD_StatusTypeDef DPM_TurnOffPower(uint8_t PortNum, USBPD_PortPowerRole_TypeDef Role) { USBPD_StatusTypeDef status = USBPD_OK; status = USBPD_PWR_IF_VBUSDisable(PortNum); return status; } /** * @brief Turn On power supply. * @param PortNum The current port number * @retval USBPD_ACCEPT, USBPD_WAIT, USBPD_REJECT */ static USBPD_StatusTypeDef DPM_TurnOnPower(uint8_t PortNum, USBPD_PortPowerRole_TypeDef Role) { USBPD_StatusTypeDef status = USBPD_OK; /* Enable the output */ status = USBPD_PWR_IF_VBUSEnable(PortNum); if(USBPD_PORTPOWERROLE_SRC == Role) { /* Enable the output */ USBPD_DPM_WaitForTime(30); } else { /* stop current sink */ } return status; } /** * @brief Assert Rp resistor. * @param PortNum The current port number * @retval None */ static void DPM_AssertRp(uint8_t PortNum) { USBPD_CAD_AssertRp(PortNum); } /** * @brief Assert Rd resistor. * @param PortNum The current port number * @retval None */ static void DPM_AssertRd(uint8_t PortNum) { USBPD_CAD_AssertRd(PortNum); } static uint32_t CheckDPMTimers(void) { uint32_t _timing = osWaitForever; uint32_t _current_timing; /* Calculate the minimum timers to wake-up DPM tasks */ for(uint8_t instance = 0; instance < USBPD_PORT_COUNT; instance++) { #if defined(_GUI_INTERFACE) /* Check if Measurement reporting has been enabled by the GUI */ _current_timing = DPM_Ports[instance].DPM_TimerMeasReport & DPM_TIMER_READ_MSK; if(_current_timing > 0) { if (_current_timing < _timing) { _timing = _current_timing; } } #endif /* _GUI_INTERFACE */ _current_timing = DPM_Ports[instance].DPM_TimerSRCExtendedCapa & DPM_TIMER_READ_MSK; if(_current_timing > 0) { if (_current_timing < _timing) { _timing = _current_timing; } } _current_timing = DPM_Ports[instance].DPM_TimerAlert & DPM_TIMER_READ_MSK; if(_current_timing > 0) { if (_current_timing < _timing) { _timing = _current_timing; } } } return _timing; } /** * @brief Manage the send of the message GET EXTENDED CAPA. * @retval none */ void DPM_ManageExtendedCapa(void) { for(uint8_t _instance = 0; _instance < USBPD_PORT_COUNT; _instance++) { /* ------------------------------------------------- */ /* Check if send SRC extended capa timer is expired */ /* ------------------------------------------------- */ if (DPM_TIMER_ENABLE_MSK == DPM_Ports[_instance].DPM_TimerSRCExtendedCapa) { DPM_Ports[_instance].DPM_TimerSRCExtendedCapa = 0; USBPD_DPM_RequestGetSourceCapabilityExt(_instance); } } } /** * @brief Manage the ALERT. * @retval none */ void DPM_ManageAlert(void) { for(uint8_t _instance = 0; _instance < USBPD_PORT_COUNT; _instance++) { /* check if Alert timer is expired */ if (DPM_TIMER_ENABLE_MSK == DPM_Ports[_instance].DPM_TimerAlert) { /* Restart alert timer */ DPM_START_TIMER(_instance, DPM_TimerAlert, DPM_TIMER_ALERT); DPM_Ports[_instance].DPM_MeasuredCurrent = HW_IF_PWR_GetCurrent(_instance); if (DPM_Ports[_instance].DPM_MeasuredCurrent > 3600) { USBPD_DPM_RequestHardReset(_instance); } else { if (DPM_Ports[_instance].DPM_MeasuredCurrent > 3400) { if (0 == (DPM_Ports[_instance].DPM_SendAlert.b.TypeAlert & USBPD_ADO_TYPE_ALERT_OCP)) { USBPD_ADO_TypeDef alert = {0}; alert.b.TypeAlert = USBPD_ADO_TYPE_ALERT_OCP; USBPD_DPM_RequestAlert(_instance, alert); DPM_Ports[_instance].DPM_SendAlert.b.TypeAlert |= alert.b.TypeAlert; } } else { /* Reset of the OCP bit */ DPM_Ports[_instance].DPM_SendAlert.b.TypeAlert &= ~USBPD_ADO_TYPE_ALERT_OCP; /* The Operating Condition Change bit Shall be set when a Source or Sink detects its Operating Condition enters or exits either the or temperature states. The Operating Condition Change bit Shall be set when the Source operating in the Programmable Power Supply mode detects it has changed its operating condition between Constant Voltage (CV) and Current Limit (CL). */ USBPD_PDO_TypeDef pdo; pdo.d32 = PWR_Port_PDO_Storage[_instance].SourcePDO.ListOfPDO[DPM_Ports[_instance].DPM_RDOPosition]; if (USBPD_CORE_PDO_TYPE_APDO == pdo.GenericPDO.PowerObject) { if (DPM_Ports[_instance].DPM_MeasuredCurrent > PWR_DECODE_50MA(pdo.SRCSNKAPDO.MaxCurrentIn50mAunits)) { if (0 == (DPM_Ports[_instance].DPM_SendAlert.b.TypeAlert & USBPD_ADO_TYPE_ALERT_OPERATING_COND)) { USBPD_ADO_TypeDef alert = {0}; alert.b.TypeAlert = USBPD_ADO_TYPE_ALERT_OPERATING_COND; USBPD_DPM_RequestAlert(_instance, alert); DPM_Ports[_instance].DPM_SendAlert.b.TypeAlert |= alert.b.TypeAlert; } } else { /* Reset alert bits */ DPM_Ports[_instance].DPM_SendAlert.b.TypeAlert = 0; } } else { /* Reset alert bits */ DPM_Ports[_instance].DPM_SendAlert.b.TypeAlert = 0; } } } } } } /** * @} */ /** * @} */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/