pdSink module¶
Status | Last Update | API Version |
---|---|---|
Active | 2019-11-20 | V1.00.00 |
Description¶
This module provides access to Power Delivery protocol as a role of sink.
pdSink and fastChgTrig¶
As you might think, the pdSink
module should be fit into fastChgTrig
module, PD is also a fast-charge protocol after all. But there’re a few reasons that one prefers not to do so:
PD protocol is much more powerful than the others, its operation principle is so different, making it hard to fit into
fastChgTrig
software model.Unlike protocols in
fastChgTrig
, PD doesn’t use D+ D- as communication lines. In fact, the hardware for PD and that for other protocols are totally independent.
Precautions¶
Using this module requires some basic knowledge of PD protocol, whose specification could be found on USB-IF website.
Though the hardware for PD and other protocols are independent (In theory, they could work simultaneously), the charger would not be happy about two protocols running at the same time, this could make conflicting requests and generate undefined behaviors. Before using pdSink, one should call
fastChgTrig.open()
just like usingfastChgTrig
module, this prevents the situation stated above.The module is designed to make a balance between complexity and flexibility. One who fully understands the APIs, but with lack of the knowledge of PD and the very hardware, bottom layer software implementation on this meter, could easily find his script not working, and difficult to find out the reason. It’s highly recommended to have a look at the example code at the bottom of this page.
Typical call sequence¶
The following lists the sequence of calls to establish PD with the charger and get voltage & current you want from the charger:
1.Call pdSink.init()
to initialize hardware and bottom software layer, check its result, if pdSink.OK
, continue operation.
2.Check pdSink.isSrcCapReceived()
with a timeout of 2 seconds, if timeouts, operation fail, or you call pdSink.sendHardReset()
and restart from step 1.
Notice that after CC is attached, the charger typically sends src_cap
message for only a few seconds (Detailed information could be found on the specification), this means except your code runs on start-up, your attempt to receive src_cap
is doomed to end up with a timeout. To handle this case, you issues a hard reset with pdSink.sendHardReset()
to reset the charger and you can receive src_cap
again.
3.Call pdSink.getSrcCapNum()
and pdSink.getSrcCap()
to pass source capabilities to lua region, this step could be omitted if you already knows your charger’s capabilities or you don’t need such information.
4.Call pdSink.request()
to get voltage and current limit you wanted.
pdSink.init()¶
Description¶
This initializes the pdSink module, it does the following things:
Get source attachment status, if no source attached, it returns
pdSink.FAIL
.If attachment detected, initialize PD communications on the corresponding CC pin and return
pdSink.OK
. Reset bottom layer software status.
One should check the result to determine if further operation could be performed.
Parameters¶
nil
Return value¶
number
pdSink.FAIL
if failed.
pdSink.OK
if done.
Example call¶
rtval = pdSink.init()
pdSink.getCCStatus()¶
Description¶
This function doen’t do any hardware work, it just returns the CC attachment status after pdSink.init()
call.
Parameters¶
nil
Return value¶
number
pdSink.CC1_SRC_ATTACHED
if source is attached on CC1.
pdSink.CC2_SRC_ATTACHED
if source is attached on CC2.
pdSink.NO_SRC_ATTACHED
if source is not attached.
Example call¶
status = pdSink.getCCStatus()
pdSink.isSrcCapReceived()¶
Description¶
Check if src_cap message is received. This status is cleared when pdSink.init()
is called, and raised when a src_cap message is received.
Parameters¶
nil
Return value¶
boolean
true
if received.
false
if haven’t received yet..
Example call¶
received = pdSink.isSrcCapReceived()
pdSink.getNumofSrcCap()¶
Description¶
Get number of objects in Source_Capability
message.
Parameters¶
nil
Return value¶
number
Number of objects in Source_Capability
message.
Example call¶
pdo_num = pdSink.getNumofSrcCap()
pdSink.getSrcCap()¶
Get specified PDO with an index.
Parameters¶
Name | Type | Range | Usage |
---|---|---|---|
<index> | number | 0~6 | Specify the index of the object to get |
Return value¶
table Returns a table with the following key-value pairs:
Key | Type | Range | Usage |
---|---|---|---|
type | number | pdSink.FIXED pdSink.BATTERY pdSink.VARIABLE pdSink.AUGMENTED | Type of the PDO |
voltage | number | If the PDO is type FIXED, this is the voltage of the PDO. If the PDO is type AUGMENTED, this is the minimum voltage of the PDO. | |
voltageMax | number | If the PDO is type FIXED, this field has no meaning. If the PDO is type AUGMENTED, this is the maximum voltage of the PDO. | |
currentMax | number | Maximum current of the PDO. |
Example call¶
pdo0 = pdSink.getSrcCap(0)
pdSink.sendHardReset()¶
Description¶
Send a hard reset message.
Parameters¶
nil
Return value¶
nil
Example call¶
pdSink.sendHardReset()
pdSink.request()¶
Description¶
Send a request message to request specified voltage and current limit.
Parameters¶
Name | Type | Range | Usage |
---|---|---|---|
<pdo> | number | 0~6 | Specify the index of the PDO to request |
[voltage] | number | If the PDO is FIXED, the FIXED voltage should be this parameter. If the PDO is AUGMENTED, this specifies the voltage to request, should be in the range of the corresponding PDO.If not specified, and the PDO is FIXED, the voltage will be the FIXED voltage. | |
[current] | number | Specify the operation current to request, this should be in the range of the corresponding PDO. If not specified, the current is the maxium current of the PDO. |
Return value¶
number
pdSink.OK
if the request success with PS_Ready
received.
pdSink.FAIL
if the request timed out or without PS_Ready
received.
Example call¶
--Request PDO with index 1, voltage 9V, current 3A
result = pdSink.request(1,9.00,3.00)
pdSink.deinit()¶
Description¶
Disable PD communication, and reset bottom layer software to default status.
Notice that this won’t reset the charger, you need to call pdSink.sendHardReset()
additionally if you want to do so.
Parameters¶
nil
Return value¶
nil
Example call¶
pdSink.deinit()
pdSink.onSrcCapReceived()¶
Description¶
Register or unregister a callback when a source capability message is received.
Parameters¶
Name | Type | Range | Usage |
---|---|---|---|
<callback> | nil or function | Specify the callback function, when such event happened, the callback is called, the callback won't be unregistered automatically. To unregister the callback, pass nil to this function. |
Return value¶
nil
Example call¶
function onSrcCapReceived()
print("Source Capability received.")
end
pdSink.onSrcCapReceived(onSrcCapReceived)
Example code (Procedural)¶
--[[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()
Example code (Event-Driven)¶
--[[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...")