# 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` 如果初始化完成. ### 调用例 ```lua 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`被检测到。 ### 调用例 ```lua status = pdSink.getCCStatus() ``` ## pdSink.isSrcCapReceived() ### 描述 检查`Source_Capability`消息是否已经收到,这个状态在`pdSink.init()`或`pdSink.deinit()`将被清除,在`Source_Capability`收到时将会被置为true。 ### 参数 nil ### 返回值 boolean `true` 如果已收到`Source_Capability`消息。 `false` 如果暂未收到`Source_Capability`消息。 ### 调用例 ```lua received = pdSink.isSrcCapReceived() ``` ## pdSink.getNumofSrcCap() ### 描述 获取`Source_Capability`消息中PDO的个数。 ### 参数 nil ### 返回值 number `Source_Capability`消息中PDO的个数。 ### 调用例 ```lua 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报告的最大电流值| ### 调用例 ```lua pdo0 = pdSink.getSrcCap(0) ``` ## pdSink.sendHardReset() ### 描述 发送一个硬复位消息。 ### 参数 nil ### 返回值 nil ### 调用例 ```lua 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 ```lua --Request PDO with index 1, voltage 9V, current 3A result = pdSink.request(1,9.00,3.00) ``` ## pdSink.deinit() ### 描述 禁能PD通讯,并复位底层软件到默认状态。 请注意该函数不会复位充电器,如果您需要这么做,您需要额外调用`pdSink.sendHardReset()` 。 ### 参数 nil ### 返回值 nil ### 调用例 ```lua pdSink.deinit() ``` ## pdSink.onSrcCapReceived() ### 描述 注册或取消注册在Source Capability收到时的回调函数。 ### 参数 | 名称 | 类型 | 范围 | 用途 | | ------ | ------ | ------ | ------ | | <callback> | nil 或 function| |指定回调函数,当该事件发生时,回调函数被调用,且调用后不会被自动取消注册。要取消注册回调函数,用`nil`作为参数调用本函数。| ### 返回值 nil ### 调用例 ```lua function onSrcCapReceived() print("Source Capability received.") end pdSink.onSrcCapReceived(onSrcCapReceived) ``` ## 模块示例代码(过程) ```lua --[[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() ``` ## 模块示例代码(事件驱动) ```lua --[[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...") ```