pdSink模块

状态 最后更新 API版本
Active 2019-11-20 V1.00.00

描述

此模块提供对PD作为Sink的访问

pdSink和fastChgTrig

您可能会认为,pdSink应当被fastChgTrig包含,毕竟PD也是一种快速充电协议。但是有几个让人不这么做的理由:

  • PD协议功能比其他快速充电协议更强大,使得其很难被抽象进其他协议的模型。

  • 与fastChgTrig内的协议不同,PD不使用D+ D-作为通讯载体。事实上,PD与 fastChgTrig内的协议使用的硬件是完全独立的。

注意事项

  • 使用这个模块需要一些PD协议的基础知识,其标准文档可在USB-IF的网站内找到。

  • 尽管PD和其他协议的硬件是独立的(即理论上,它可以与其他协议同时运行),但充电器不接受同时运行两个协议这种做法,这会引起相互冲突的请求,产生不完全定义的行为。在使用pdSink之前,应当调用fastChgTrig.open(),正如使用fastChgTrig模块一样,这可以避免上述情况。

  • 这个模块企图寻找使用复杂程度和灵活性间的平衡。即使您完全理解各API,如果您缺少对PD或该协议在此平台底层软件的实现的了解,您也可能会陷入代码无法工作的窘境。推荐您在编写代码前,先查看本页末尾的示例代码,对操作流程有大概的了解。

典型操作流程(面向过程)

下面列出与PD充电器间建立通讯并完成请求的典型流程: 1.调用 pdSink.init() 来初始化硬件和底层软件, 检查返回值, 如果返回值为 pdSink.OK, 则继续操作。如果返回值不为pdSink.OK,说明没有PD充电器连接。

2.反复查询 pdSink.isSrcCapReceived() 直到其返回值为true (通常您需要设计2秒的超时), 如果超时, 则操作失败, 或者您需要调用 pdSink.sendHardReset() 然后重新开始步骤1. 需要注意的是,在PD充电器接入后,充电器只会在几秒钟内持续发送src_cap消息,这意味着除非您的代码在表头上电后立刻启动,您大概率会无法收到src_cap消息。此时,您需要调用pdSink.sendHardReset()来复位充电头,此后,您应该能收到src_cap消息。

3.调用 pdSink.getSrcCapNum()pdSink.getSrcCap() 将PDO传输到lua中, 如果您已经预先知道您的电源的Source_Capability,您可以略过这一步。

4.调用 pdSink.request() 来获得请求您想要的电压和电流。

pdSink.init()

描述

这将初始化pdSink模块,详细地,它将做以下工作:

  • 检测Source的连接状态,如果没有Source连接,返回pdSink.FAIL

  • 如果有连接被检测到,在对应的CC引脚上初始化PD通讯,复位底层软件状态,并返回pdSink.OK

您需要检查本函数的返回值,以决定是否需要下一步操作。

参数

nil

返回值

number pdSink.FAIL 如果没有CC连接或其他失败情况发生. pdSink.OK 如果初始化完成.

调用例

rtval = pdSink.init()

pdSink.getCCStatus()

描述

这个函数没有进行任何硬件操作,他只返回在pdSink.init()调用后CC引脚的连接状态。

Parameters

nil

Return value

number pdSink.CC1_SRC_ATTACHED 如果Source连接在CC1。 pdSink.CC2_SRC_ATTACHED 如果Source连接在CC2。 pdSink.NO_SRC_ATTACHED 如果没有Source被检测到。

调用例

status = pdSink.getCCStatus()

pdSink.isSrcCapReceived()

描述

检查Source_Capability消息是否已经收到,这个状态在pdSink.init()pdSink.deinit()将被清除,在Source_Capability收到时将会被置为true。

参数

nil

返回值

boolean true 如果已收到Source_Capability消息。 false 如果暂未收到Source_Capability消息。

调用例

received = pdSink.isSrcCapReceived()

pdSink.getNumofSrcCap()

描述

获取Source_Capability消息中PDO的个数。

参数

nil

返回值

number Source_Capability消息中PDO的个数。

调用例

pdo_num = pdSink.getNumofSrcCap()

pdSink.getSrcCap()

Source_Capability消息中指定PDO的信息

参数

Name Type Range Usage
<index> number 0~6 指定要获取的PDO的索引

返回值

table 返回一个table,具有以下的结构:

类型 范围 用途
type number pdSink.FIXED pdSink.BATTERY pdSink.VARIABLE pdSink.AUGMENTED PDO的类型
voltage number 如果该PDO是FIXED的,那么该域的值为该PDO的固定电压值。如果该PDO是AUGMENTED的,那么该域的值为该PDO中报告的最小电压值。
voltageMax number 如果PDO是FIXED的,该域没有意义。如果该PDO是AUGMENTED的,那么该域的值为该PDO中报告的最大电压值
currentMax number 该PDO报告的最大电流值

调用例

pdo0 = pdSink.getSrcCap(0)

pdSink.sendHardReset()

描述

发送一个硬复位消息。

参数

nil

返回值

nil

调用例

pdSink.sendHardReset()

pdSink.request()

描述

请求使用一个指定PDO, 并指定电压和电流。

参数

返回值

名称 类型 范围 用途
<pdo> number 0~6 指定要请求的PDO的索引
[voltage] number 如果该PDO是FIXED的, 那么该参数必须为该PDO唯一的电压。如果该PDO是AUGMENTED的,指定要请求的电压值,必须保证电压值在该PDO所报告的范围内。 如果该参数缺省,且该PDO是FIXED的,那么请求的电压值为该PDO唯一的电压。
[current] number 指定要请求的作业电流,该参数必须在该PDO所报告的电流范围内。如果该参数缺省,作业电流为该PDO中报告的最大电流。

返回值

number pdSink.OK 请求成功并且PS_Ready已收到。 pdSink.FAIL 请求超时或者PS_Ready未收到。

Example call

--Request PDO with index 1, voltage 9V, current 3A
result = pdSink.request(1,9.00,3.00)

pdSink.deinit()

描述

禁能PD通讯,并复位底层软件到默认状态。 请注意该函数不会复位充电器,如果您需要这么做,您需要额外调用pdSink.sendHardReset()

参数

nil

返回值

nil

调用例

pdSink.deinit()

pdSink.onSrcCapReceived()

描述

注册或取消注册在Source Capability收到时的回调函数。

参数

名称 类型 范围 用途
<callback> nil 或 function 指定回调函数,当该事件发生时,回调函数被调用,且调用后不会被自动取消注册。要取消注册回调函数,用nil作为参数调用本函数。

返回值

nil

调用例

function onSrcCapReceived() 
  print("Source Capability received.")
end

pdSink.onSrcCapReceived(onSrcCapReceived)

模块示例代码(过程)

--[[This is a demo for PD APIs.
    You connect the meter to a PD charger with a C-C cable, and DO NOT plug-in any other device.
    The output of the demo is on the debug terminal.
   
    The demo detect if any source is attached first, if no source is detected, it exits.
    Then it waits for src_cap, if not received, it sends a HARD_RST message to reset the charger, if still no src_cap is received, it exits.
    After the src_cap received, it prints out the src_cap on the terminal.
    Then it started to request FIXED pdos of the charger one by one.
    If there is any AUGMENTED(PPS) pdo, it requests them one by one.
    The voltage reading and request status is on the terminal.

    Detailed Documentation:
    Version: 191120
    Author:  yanke928
]]

function WaitForSourceCap()
  i = 2000
  while(i > 0) do 
    i = i - 1;
    if(pdSink.isSrcCapReceived()) then 
      return true
    end
    delay.ms(1)
  end
  return false
end

function DemoEnd()
  print("---End of PD demo---")
  os.exit(0)
end

print("---Start of PD demo---")

--Open fastChgTrig
if(fastChgTrig.open() ~= fastChgTrig.OK) then
  print("Failed to open fastChgTrig") 
  DemoEnd()
end

--Init PD
pdSink.init()

print("PD inited") 

--Check if any source is attached
if(pdSink.getCCStatus() == pdSink.NO_SRC_ATTACHED) then
  print("No CC attached") 
  DemoEnd()
end

print("Waiting for src_cap") 

--Wait for src_cap.
received = WaitForSourceCap()

--In case of time out, try a hard reset
if(received  == false) then
  print("src_cap timeout, sending hard reset") 
  pdSink.sendHardReset()
  pdSink.init()

  print("Waiting for src_cap again.") 
  received = WaitForSourceCap()

  --If we still cannot receive src_cap
  if(received == false) then
    print("No src_cap received, exiting...")
    DemoEnd()
  end
end

print("src_cap received")

delay.ms(1000)

--Get src_cap into table
src_cap_num = pdSink.getNumofSrcCap()
print(string.format("We have %d src_caps:",src_cap_num))
src_caps = {}
for i = 0,src_cap_num -1 do
  src_caps[i] = pdSink.getSrcCap(i)
  --Fixed type, print voltage and max current
  if(src_caps[i].type == pdSink.FIXED) then
     print(string.format("No.[%d] Type[FIXED] Voltage[%.2fV] Current[%.2fA]",i,src_caps[i].voltage,src_caps[i].currentMax))
  elseif (src_caps[i].type == pdSink.AUGMENTED) then
     print(string.format("No.[%d] Type[AUGMENTED] Voltage[%.2f~%.2fV] Current[%.2fA] ",i,src_caps[i].voltage,src_caps[i].voltageMax,src_caps[i].currentMax))
  else
     print(string.format("No.[%d] Unknown Type",i))
  end
end

meter.setDataSource(meter.INSTANT)

print("Started to request FIXED PDOs")
for i = 0,src_cap_num -1 do
  if(src_caps[i].type == pdSink.FIXED) then
     print(string.format("Requesting FIXED No.%d",i))
     if(pdSink.request(i,src_caps[i].voltage,src_caps[i].currentMax) ~= pdSink.OK) then 
        print("Request failed")
        DemoEnd()
     end
     print(string.format("Request Success, voltage now: %.3fV",meter.readVoltage()))
     delay.ms(1000)
   end
end

print("Started to request AUGMENTED PDOs")
for i = 0,src_cap_num -1 do
  if(src_caps[i].type == pdSink.AUGMENTED) then
     --Here, we use the middle point of the PPS voltage to give an example.
     req_volt = (src_caps[i].voltage + src_caps[i].voltageMax) / 2
     print(string.format("Requesting AUGMENTED No.%d Voltage %.3fV",i,req_volt))
     if(pdSink.request(i,req_volt,src_caps[i].currentMax) ~= pdSink.OK) then 
        print("Request failed")
        DemoEnd()
     end
     print(string.format("Request Success, voltage now: %.3fV",meter.readVoltage()))
     delay.ms(1000)
   end
end

DemoEnd()

模块示例代码(事件驱动)

--[[This is a event-driven demo for PD APIs.
    You connect the meter to a PD charger with a C-C cable, and DO NOT plug-in any other device.
    The output of the demo is on the debug terminal.
   
    The demo detect if any source is attached first, if no source is detected, it exits.
    Then it waits for src_cap, if not received, it sends a HARD_RST message to reset the charger, if still no src_cap is received, it exits.
    After the src_cap received, it prints out the src_cap on the terminal.
    Then it started to request FIXED pdos of the charger one by one.
    If there is any AUGMENTED(PPS) pdo, it requests them one by one.
    The voltage reading and request status is on the terminal.

    Detailed Documentation:
    Version: 191120
    Author:  yanke928
]]


timeoutTimerCount = 0
srcCapOK = false
src_caps = {}
src_cap_num = 0
request_index = 0

function demoEnd()
  print("----End of demo----")
  os.exit()
end

function requestTimer_callback(tim)
   if(src_caps[request_index].type == pdSink.FIXED) then
     print(string.format("Requesting FIXED No.%d",request_index))
     if(pdSink.request(request_index,src_caps[request_index].voltage,src_caps[request_index].currentMax) ~= pdSink.OK) then 
        print("Request failed")
        DemoEnd()
     end
     print(string.format("Request Success, voltage now: %.3fV",meter.readVoltage()))
   else if(src_caps[request_index].type == pdSink.AUGMENTED) then
       --Here, we use the middle point of the PPS voltage to give an example.
       req_volt = (src_caps[request_index].voltage + src_caps[request_index].voltageMax) / 2
       print(string.format("Requesting AUGMENTED No.%d Voltage %.3fV",request_index,req_volt))
       if(pdSink.request(request_index,req_volt,src_caps[request_index].currentMax) ~= pdSink.OK) then 
          print("Request failed")
          DemoEnd()
       end
       print(string.format("Request Success, voltage now: %.3fV",meter.readVoltage()))
     end
   end

   request_index = request_index + 1
   if(request_index == src_cap_num) then 
     print("All PDO requested, exiting...")
     demoEnd()
   end
end

function timeoutTimer_callback(tim)
  timeoutTimerCount = timeoutTimerCount + 1

  if(srcCapOK ~= true) then
    if(timeoutTimerCount == 2) then
      print("No src_cap received, exiting...")
      demoEnd()
    end
    print("src_cap timeout, sending hard reset...") 
    pdSink.sendHardReset()
    pdSink.init()
  else 
    requestTimer= tmr.new()
    requestTimer:setup(0,1000,tmr.AUTO_RELOAD,requestTimer_callback)
    requestTimer:start()
    pdSink.onSrcCapReceived(nil)
    tim:remove()
  end
end

function onSrcCapReceived() 
  print("Source Capability Received")
  srcCapOK = true
  --Get src_cap into table
  src_cap_num = pdSink.getNumofSrcCap()
  print(string.format("We have %d src_caps:",src_cap_num))
  for i = 0,src_cap_num -1 do
    src_caps[i] = pdSink.getSrcCap(i)
    --Fixed type, print voltage and max current
    if(src_caps[i].type == pdSink.FIXED) then
       print(string.format("No.[%d] Type[FIXED] Voltage[%.2fV] Current[%.2fA]",i,src_caps[i].voltage,src_caps[i].currentMax))
    elseif (src_caps[i].type == pdSink.AUGMENTED) then
       print(string.format("No.[%d] Type[AUGMENTED] Voltage[%.2f~%.2fV] Current[%.2fA] ",i,src_caps[i].voltage,src_caps[i].voltageMax,src_caps[i].currentMax))
    else
      print(string.format("No.[%d] Unknown Type",i))
    end
  end
end 

print("----Start of demo----")

if(fastChgTrig.open() ~= fastChgTrig.OK) then 
  print("Failed to open fastChgTrig")
  demoEnd()
end

--Init PD
pdSink.init()
print("PD inited") 

--Check if any source is attached
if(pdSink.getCCStatus() == pdSink.NO_SRC_ATTACHED) then
  print("No CC attached") 
  DemoEnd()
end

timeoutTimer = tmr.new()
timeoutTimer :setup(2000,2000,tmr.AUTO_RELOAD,timeoutTimer_callback)
timeoutTimer :start()
pdSink.onSrcCapReceived(onSrcCapReceived)
print("Waiting for src_cap...")