Skip to content

Latest commit

 

History

History
855 lines (661 loc) · 18.7 KB

File metadata and controls

855 lines (661 loc) · 18.7 KB

PipPD API

This document describes the current public API of PipPD.

The goal is accuracy over marketing. PipPD is not a full USB-PD stack. It is a compact FUSB302-oriented library with a clean split between PHY access, packet encoding, and sink policy.

Build

PipPD uses C++17.

For PlatformIO:

build_unflags = -std=gnu++11
build_flags = -std=gnu++17

Architecture

The library is split into three layers:

  • PipPD: FUSB302 PHY / register / FIFO / CC / VBUS handling
  • Protocol: USB-PD packet encoding, parsing, revision-aware TX/RX, a small unchunked PD 3.x extended-message subset, and minimal structured VDM helpers
  • SinkPolicy: sink-side negotiation, retries, timeouts, PPS selection, fallback, recovery, and compact PD 3.x service-message handling
  • CableDiscovery: compact helper for SOP' Discover Identity / e-marker identity probing

Important boundaries:

  • PipPD does not implement high-level negotiation policy
  • Protocol does not know about contract selection or recovery policy
  • SinkPolicy works through PipPD + Protocol and does not reach into FUSB302 registers directly

Public Types

Main classes:

  • PipPD
  • Protocol
  • SinkPolicy
  • CableDiscovery

Core config and state:

  • Config
  • Status
  • Interrupts
  • DebugRegisters
  • ThresholdScan
  • DeviceId

PHY enums:

  • Mode
  • CCLine
  • Current
  • TransmitStart
  • SpecRevision

Protocol types:

  • MessageHeader
  • PdPacket
  • RxMessage
  • TxResult
  • PacketTarget
  • SourceCapabilities
  • FixedSupplyPdo
  • ProgrammableSupplyPdo
  • FixedRequestDataObject
  • PpsRequestDataObject
  • ExtendedHeader
  • ExtendedMessageType
  • AlertDataObject
  • StatusDataBlock
  • PpsStatusDataBlock
  • StructuredVdmHeader
  • IdHeaderVdo
  • CertStatVdo
  • ProductVdo
  • CableVdo

Sink policy types:

  • SinkPreferences
  • SinkContract
  • SinkContractType
  • SinkState
  • SinkError
  • SupplyPreference
  • PowerPreference
  • Pd3ServiceRequestType
  • Pd3ServiceResult

Cable discovery types:

  • CableDiscoveryState
  • CableIdentityQuality
  • CableDiscoveryTraceEventType
  • CableIdentity
  • CableDiscoveryTraceEvent

PipPD

Basic setup

#include <PipPD.h>

PipPD pd;

Config config;
config.wire = &Wire;
config.i2cAddress = 0x22;
config.interruptPin = 4;
config.mode = Sink;
config.specRevision = Rev30;
config.sourceCurrent = UsbDefault;
config.enableInternalPullDowns = true;
config.transmitStart = StartWithControl0;

pd.begin(config);

Config

Fields:

  • wire
  • i2cAddress
  • interruptPin
  • mode
  • specRevision
  • sourceCurrent
  • enableInternalPullDowns
  • enableVbusMonitoring
  • enableSopPrime
  • enableSopDoublePrime
  • enableAutoCrc
  • transmitStart

Notes:

  • enableInternalPullDowns = true uses FUSB302 internal sink pull-downs on CC1/CC2
  • Set enableInternalPullDowns = false only if the board already provides the sink pull-down network externally
  • StartWithControl0 starts TX with CONTROL0.TX_START
  • StartWithFifoToken starts TX with the TXON FIFO token

Lifecycle

pd.begin(config);
pd.reset();
pd.update();

Type-C runtime helpers

pd.restartDetection();
pd.stopDetection();
pd.setMode(Sink);
pd.setSourceCurrent(Current1A5);

Status access

pd.online();
pd.attached();
pd.hasInterrupt();
pd.vbusPresent();

pd.mode();
pd.role();
pd.orientation();
pd.sinkCurrent();

pd.deviceId();
pd.status();
pd.lastInterrupts();

FIFO / PHY helpers

pd.flushRxFifo();
pd.flushTxFifo();
pd.enableAutoCrc(true);
pd.enableSopPrime(true);
pd.enableSopDoublePrime(false);
pd.prepareTransmit();
pd.sendHardReset();
pd.writeTxFifo(data, size);
pd.readRxFifo(data, size);
pd.startTransmit();

Debug and measurement helpers

DebugRegisters debug;
pd.readDebugRegisters(debug);

bool high = false;
pd.measureCC(CC1, 20, high);
pd.measureVBUS(30, high);

ThresholdScan scan;
pd.scanCC(CC1, scan);
pd.scanVBUS(scan);

Protocol

Basic setup

#include <Protocol.h>

Protocol protocol(pd);

Responsibilities

  • encode/decode MessageHeader
  • build/parse PdPacket
  • classify control and data messages
  • encode/decode fixed PDOs
  • encode/decode PPS APDOs
  • encode/decode fixed RDOs
  • encode/decode PPS RDOs
  • encode/decode unchunked extended headers
  • build/parse typed Status and PPS Status
  • build/parse typed Alert
  • build TX frames for SOP and SOP'
  • receive and decode PD messages from FUSB302 RX FIFO
  • extract SourceCapabilities
  • build/parse minimal structured VDM identity headers and cable identity VDOs

Example usage

uint32_t rawPdo = Protocol::makeFixedSourcePdo(fixedPdo);
auto parsedFixed = Protocol::parseFixedSourcePdo(rawPdo);

uint32_t rawApdo = Protocol::makeProgrammableSupplyPdo(ppsApdo);
auto parsedPps = Protocol::parseProgrammableSupplyPdo(rawApdo);

uint32_t rawRdo = Protocol::makePpsRequest(ppsRequest);
auto parsedRdo = Protocol::parsePpsRequest(rawRdo);

AlertDataObject alert = Protocol::parseAlertDataObject(rawAlert);

RX

RxMessage message;
if (protocol.receiveMessage(message)) {
  if (Protocol::isSourceCapabilities(message.packet)) {
    SourceCapabilities caps;
    Protocol::extractSourceCapabilities(message.packet, caps);
  }
}

TX

PdPacket packet{};
packet.header.isDataMessage = false;
packet.header.messageType = CtrlGetSourceCap;

protocol.transmitSop(packet);

Protocol can also transmit to SOP' through PacketTarget:

protocol.transmit(packet, TargetSopPrime);

TxResult

TxResult exposes step-by-step TX diagnostics:

  • payloadBuilt
  • frameBuilt
  • flushed
  • prepared
  • written
  • started
  • debugRead
  • ok
  • usedTxOnToken
  • frameSize
  • after

PD 3.x typed helpers

Useful helpers:

  • encodeExtendedHeader(...)
  • decodeExtendedHeader(...)
  • extendedType(...)
  • isExtendedMessage(...)
  • isAlertMessage(...)
  • isStatusMessage(...)
  • isPpsStatusMessage(...)
  • makeAlertDataObject(...)
  • parseAlertDataObject(...)
  • buildStatusData(...)
  • extractStatusData(...)
  • buildPpsStatusData(...)
  • extractPpsStatusData(...)

CableDiscovery

Scope

CableDiscovery is a narrow helper for one MVP flow only:

  1. send structured Discover Identity on SOP'
  2. wait for one response / timeout / NAK / BUSY
  3. decode a compact cable identity result

It does not try to be a general VDM framework or a cable policy engine.

Basic setup

#include <CableDiscovery.h>

PipPD pd;
Protocol protocol(pd);
CableDiscovery cableDiscovery(pd, protocol);

cableDiscovery.setLogStream(&Serial);

Main API

  • start()
  • update()
  • state()
  • busy()
  • finished()
  • success()
  • result()
  • decodeIdentityResponse(...)
  • clearTrace()
  • traceCount()
  • traceEvent(...)
  • printTrace(...)
  • printSummary(...)

Result model

CableIdentity intentionally stays compact.

Useful fields:

  • responseReceived
  • markerPresent
  • quality
  • productType
  • activeCable
  • passiveCable
  • currentCapability
  • usbSpeed
  • vendorId
  • productId
  • bcdDevice
  • xid
  • hasProductVdo
  • rawVdmHeader
  • rawIdHeader
  • rawCertStat
  • rawProductVdo
  • rawCableVdo

quality tells how usable the decoded result is:

  • CableIdentityUnavailable
  • CableIdentityMarkerAbsent
  • CableIdentityPartial
  • CableIdentityComplete

Discovery flow

if (cableDiscovery.start()) {
  while (!cableDiscovery.finished()) {
    cableDiscovery.update();
  }
}

Important limitations

  • CableDiscovery uses the same PD PHY/channel as SinkPolicy
  • do not run active SinkPolicy.update() and active CableDiscovery.update() in parallel
  • this MVP does not perform VCONN_SWAP
  • discovery success depends on real cable / source / topology behavior; some sink-side topologies will never expose an e-marker from this side

Failure behavior

The helper distinguishes these outcomes:

  • CableDiscoveryNoResponse: no SOP' response before timeout
  • CableDiscoveryNotSupported: Discover Identity returned NAK
  • CableDiscoveryBusy: Discover Identity returned BUSY
  • CableDiscoveryParseError: a response arrived, but it was malformed or not usable for this MVP
  • CableDiscoverySuccess + CableIdentityMarkerAbsent: a structured identity response arrived, but it does not describe a cable marker
  • CableDiscoverySuccess + CableIdentityPartial: the response was usable, but some expected cable VDO data was missing

Cable discovery trace

CableDiscovery keeps a small fixed-size trace buffer with events such as:

  • discovery started
  • request sent
  • identity response received
  • identity decoded
  • marker absent
  • parse partial
  • no response
  • not supported / busy
  • parse failure
  • PHY failure

SinkPolicy

Basic setup

#include <SinkPolicy.h>

PipPD pd;
Protocol protocol(pd);
SinkPolicy sinkPolicy(pd, protocol);

SinkPreferences preferences;
preferences.minVoltageMv = 5000;
preferences.maxVoltageMv = 20000;
preferences.preferredVoltageMv = 9000;
preferences.minCurrentMa = 500;
preferences.preferredCurrentMa = 2000;
preferences.supply = PreferPps;
preferences.preference = PreferMaxPower;

sinkPolicy.setLogStream(&Serial);
sinkPolicy.begin(preferences);

In loop():

sinkPolicy.update();

if (sinkPolicy.hasContract()) {
  const auto& contract = sinkPolicy.contract();
}

Main API

  • begin(...)
  • configure(...)
  • setLogStream(...)
  • update()
  • evaluateSourceCapabilities(...)
  • requestPps(...)
  • requestStatus()
  • requestPpsStatus()
  • isPpsRequestValid(...)
  • state()
  • contract()
  • hasContract()
  • isPpsContract()
  • lastError()
  • preferences()
  • sourceCapabilities()
  • activeServiceRequest()
  • lastServiceType()
  • lastServiceResult()
  • hasStatusData()
  • statusData()
  • hasPpsStatusData()
  • ppsStatusData()
  • hasAlert()
  • alert()
  • clearAlert()
  • retryCount()
  • clearTrace()
  • traceCount()
  • traceCapacity()
  • traceEvent(...)
  • printTrace(...)
  • printPd3Summary(...)

State machine

States:

  • Idle
  • Unattached
  • WaitAttach
  • WaitSourceCaps
  • EvaluateCapabilities
  • SendRequest
  • WaitAccept
  • WaitPsRdy
  • Ready
  • ErrorRecovery

Current behavior

SinkPolicy currently supports:

  • attach wait
  • Source_Capabilities receive and decode
  • fixed PDO selection
  • PPS APDO selection
  • explicit PreferPps -> fixed fallback
  • Request -> Accept -> PS_RDY -> Ready
  • retries and timeouts
  • detach recovery
  • hard-reset recovery
  • dynamic PPS updates on top of an active PPS contract
  • on-demand Get_Status
  • on-demand Get_PPS_Status
  • typed Alert receive while staying in Ready

PD 3.x service messages

Scope

Current PD 3.x support is intentionally narrow:

  • revision-aware protocol headers and TX/RX path
  • unchunked extended messages only
  • typed Status
  • typed PPS Status
  • typed Alert
  • sink-side access through SinkPolicy

Not included in this stage:

  • chunked extended-message orchestration
  • EPR / AVS
  • source/DRP policy
  • role-swap engine
  • full PD 3.x event framework

Requesting Status

if (sinkPolicy.hasContract()) {
  const bool queued = sinkPolicy.requestStatus();
}

Result handling:

if (sinkPolicy.lastServiceType() == Pd3ServiceStatus &&
    sinkPolicy.lastServiceResult() == Pd3ServiceResultSuccess &&
    sinkPolicy.hasStatusData()) {
  const auto& status = sinkPolicy.statusData();
}

Requesting PPS Status

if (sinkPolicy.isPpsContract()) {
  const bool queued = sinkPolicy.requestPpsStatus();
}

Rules:

  • works only when the active contract is PPS
  • does not replace requestPps(...)
  • timeout / not-supported does not tear down the contract

Typed Alert

SinkPolicy stores the last typed Alert received while running the normal sink flow:

if (sinkPolicy.hasAlert()) {
  const auto& alert = sinkPolicy.alert();
  sinkPolicy.clearAlert();
}

Service outcomes

lastServiceResult() reports:

  • Pd3ServiceResultPending
  • Pd3ServiceResultSuccess
  • Pd3ServiceResultNotSupported
  • Pd3ServiceResultBusy
  • Pd3ServiceResultTimeout
  • Pd3ServiceResultParseError

These outcomes are intentionally separate from the main negotiation state machine. A failed Get_Status or Get_PPS_Status does not by itself force recovery or clear the current contract.

Failure semantics

  • Reject / Not_Supported map to Pd3ServiceResultNotSupported
  • Wait maps to Pd3ServiceResultBusy
  • timeout maps to Pd3ServiceResultTimeout
  • malformed or unsupported extended payload maps to Pd3ServiceResultParseError

Summary helper

sinkPolicy.printPd3Summary(Serial);

PPS behavior

Enabling PreferPps

SinkPreferences preferences;
preferences.supply = PreferPps;
preferences.preferredVoltageMv = 9000;
preferences.preferredCurrentMa = 2000;

When preferences.supply == PreferPps, SinkPolicy:

  1. Tries to find a matching PPS APDO
  2. Validates and normalizes the requested PPS voltage/current
  3. Builds a PPS request if valid
  4. Falls back to a fixed PDO if no suitable PPS APDO is available

How to tell whether the contract is PPS

if (sinkPolicy.isPpsContract()) {
  const auto& contract = sinkPolicy.contract();
}

Or check:

if (sinkPolicy.contract().type == PpsContract) {
}

Dynamic PPS update

if (sinkPolicy.isPpsContract()) {
  const bool queued = sinkPolicy.requestPps(8000, 1500);
}

Rules:

  • works only from Ready
  • works only when the active contract is actually PPS
  • the request must stay within the active APDO limits
  • the request must use valid PPS steps:
    • voltage step = 20 mV
    • current step = 50 mA

PPS fallback / reject / timeout behavior

Initial PPS negotiation:

  • if no suitable PPS APDO exists, SinkPolicy falls back to fixed PDO selection
  • if the initial PPS request is rejected or answered with Wait, SinkPolicy falls back to the fixed path

Active PPS update:

  • if requestPps(...) is invalid, it returns false and lastError() becomes PpsRequestInvalid
  • if a PPS update is rejected, the old contract stays active and lastError() becomes PpsUpdateRejected
  • if a PPS update gets Wait, the old contract stays active and lastError() becomes RequestWait
  • if a PPS update times out on Accept or PS_RDY, the old contract stays active and lastError() becomes PpsUpdateTimeout

Trace / history usage

SinkPolicy keeps a compact fixed-size ring buffer of policy events.

Stored events include:

  • attach / detach
  • Source_Capabilities received
  • fixed PDO or PPS APDO selection
  • request sent
  • Accept / Reject / Wait / PS_RDY
  • contract ready
  • PPS update request / apply / reject / timeout
  • hard reset
  • timeout
  • retry
  • PreferPps -> fixed fallback
  • error recovery enter / exit

API:

sinkPolicy.clearTrace();

SinkTraceEvent event;
if (sinkPolicy.traceEvent(0, event)) {
}

sinkPolicy.printTrace(Serial);

Notes:

  • trace is policy-level history, not a full packet capture
  • the buffer is fixed-size and uses no dynamic allocation
  • use it to inspect the last negotiation/recovery decisions during bring-up

Data Structures

SinkPreferences

Fields:

  • specRevision
  • minVoltageMv
  • maxVoltageMv
  • preferredVoltageMv
  • minCurrentMa
  • preferredCurrentMa
  • minPowerMw
  • supply
  • preference

Meaning:

  • specRevision is the preferred TX revision before the partner revision is known
  • preferredVoltageMv is the target voltage for fixed and PPS selection
  • preferredCurrentMa is the preferred operating current
  • supply = FixedOnly disables PPS selection
  • supply = PreferPps tries PPS first and may fall back to fixed

SinkContract

Fields:

  • valid
  • type
  • objectPosition
  • rawPdo
  • rawRdo
  • voltageMv
  • operatingCurrentMa
  • maximumCurrentMa
  • powerMw
  • ppsMinVoltageMv
  • ppsMaxVoltageMv
  • ppsMaxCurrentMa

Meaning:

  • type is FixedContract or PpsContract
  • for fixed contracts, PPS fields remain zero
  • for PPS contracts, the active APDO limits are exposed explicitly

SinkError

Important values:

  • NoError
  • PhyFailure
  • ProtocolFailure
  • SourceCapsTimeout
  • InvalidSourceCaps
  • NoMatchingPdo
  • RequestTransmitFailed
  • Busy
  • NoPdResponse
  • AcceptTimeout
  • RequestRejected
  • RequestWait
  • PsRdyTimeout
  • PpsNotActive
  • PpsRequestInvalid
  • PpsUpdateRejected
  • PpsUpdateTimeout
  • HardResetRecovery
  • Detached
  • RetryLimitReached

Practical meaning:

  • NoPdResponse: the source advertised Type-C current but did not answer PD messages
  • PpsNotActive: requestPps(...) was called when the active contract is not PPS
  • PpsRequestInvalid: requested PPS voltage/current is outside the active APDO or uses invalid PPS step sizes
  • PpsUpdateRejected: the source rejected a PPS update while keeping the previous contract active

Typical Failure Scenarios

  • empty or malformed Source_Capabilities: evaluateSourceCapabilities(...) fails, or runtime negotiation enters recovery with InvalidSourceCaps
  • unsupported PDO set only: selection fails with NoMatchingPdo
  • request sent but Accept never arrives: AcceptTimeout
  • Accept arrives but PS_RDY never arrives: PsRdyTimeout
  • initial PPS request rejected or answered with Wait: policy falls back to fixed PDO selection
  • active PPS update rejected, answered with Wait, or timed out: previous contract remains active
  • Get_Status / Get_PPS_Status timeout: service result becomes Pd3ServiceResultTimeout and the current contract stays active
  • malformed Status / PPS Status payload: service result becomes Pd3ServiceResultParseError

Fallback Semantics

  • PreferPps tries PPS selection first
  • if no suitable PPS APDO exists, policy falls back to fixed PDO selection
  • if the initial PPS request is rejected or answered with Wait, policy falls back to fixed PDO selection
  • active PPS update failures do not clear the current contract; they keep the previous contract and surface the reason through lastError()

Supported Today

  • FUSB302 PHY/core support
  • PD protocol TX/RX
  • revision-aware protocol TX/RX up to PD 3.0
  • unchunked extended-message support for Status and PPS Status
  • typed Alert decode
  • on-demand Get_Status
  • on-demand Get_PPS_Status
  • SOP' TX support for cable discovery
  • minimal structured VDM Discover Identity request/response support
  • Source_Capabilities decode
  • fixed PDO negotiation
  • PPS APDO negotiation
  • PreferPps -> fixed PDO fallback
  • active PPS voltage/current update
  • minimal e-marker / cable identity discovery helper
  • retries, timeouts, and recovery
  • debug register dump

Not Supported Yet

  • chunked extended messages
  • general VDM framework
  • EPR / AVS / 240 W directions
  • VCONN_SWAP orchestration
  • full cable policy engine
  • source mode policy
  • DRP policy
  • event system
  • packet trace/history buffer
  • richer high-level profile layer
  • a full USB-PD stack beyond the current sink negotiation path