## This file is part of the libsigrokdecode project.
##
## Copyright (C) 2015 Google, Inc
+## Copyright (C) 2018 Peter Hazenberg <sigrok@haas-en-berg.nl>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
SYNC_CODES = [SYNC1, SYNC2, SYNC3]
HRST_CODES = [RST1, RST1, RST1, RST2]
+SOP_SEQUENCES = [
+ (SYNC1, SYNC1, SYNC1, SYNC2),
+ (SYNC1, SYNC1, SYNC3, SYNC3),
+ (SYNC1, SYNC3, SYNC1, SYNC3),
+ (SYNC1, RST2, RST2, SYNC3),
+ (SYNC1, RST2, SYNC3, SYNC2),
+ (RST1, SYNC1, RST1, SYNC3),
+ (RST1, RST1, RST1, RST2),
+]
START_OF_PACKETS = {
- (SYNC1, SYNC1, SYNC1, SYNC2): 'SOP',
- (SYNC1, SYNC1, SYNC3, SYNC3): "SOP'",
- (SYNC1, SYNC3, SYNC1, SYNC3): 'SOP"',
- (SYNC1, RST2, RST2, SYNC3): "SOP' Debug",
- (SYNC1, RST2, SYNC3, SYNC2): 'SOP" Debug',
- (RST1, SYNC1, RST1, SYNC3): 'Cable Reset',
- (RST1, RST1, RST1, RST2): 'Hard Reset',
+ SOP_SEQUENCES[0]: 'SOP',
+ SOP_SEQUENCES[1]: "SOP'",
+ SOP_SEQUENCES[2]: 'SOP"',
+ SOP_SEQUENCES[3]: "SOP' Debug",
+ SOP_SEQUENCES[4]: 'SOP" Debug',
+ SOP_SEQUENCES[5]: 'Cable Reset',
+ SOP_SEQUENCES[6]: 'Hard Reset',
}
SYM_NAME = [
(1 << 26): 'cap_mismatch',
(1 << 27): 'give_back'
}
-PDO_TYPE = ['', 'BATT:', 'VAR:', '<bad>']
+
PDO_FLAGS = {
(1 << 29): 'dual_role_power',
(1 << 28): 'suspend',
}
VDM_ACK = ['REQ', 'ACK', 'NAK', 'BSY']
+
class SamplerateError(Exception):
pass
inputs = ['logic']
outputs = ['usb_pd']
channels = (
- {'id': 'cc', 'name': 'CC', 'desc': 'Control channel'},
+ {'id': 'cc1', 'name': 'CC1', 'desc': 'Control channel 1'},
+ )
+ optional_channels = (
+ {'id': 'cc2', 'name': 'CC2', 'desc': 'Control channel 2'},
)
options = (
{'id': 'fulltext', 'desc': 'full text decoding of the packet',
('raw-data', 'RAW binary data'),
)
+ stored_pdos = {}
+
+
def get_request(self, rdo):
pos = (rdo >> 28) & 7
- op_ma = ((rdo >> 10) & 0x3ff) * 10
- max_ma = (rdo & 0x3ff) * 10
+ op_ma = ((rdo >> 10) & 0x3ff) * 0.01
+ max_ma = (rdo & 0x3ff) * 0.01
flags = ''
for f in sorted(RDO_FLAGS.keys(), reverse = True):
if rdo & f:
- flags += ' ' + RDO_FLAGS[f]
- return '[%d]%d/%d mA%s' % (pos, op_ma, max_ma, flags)
-
- def get_source_cap(self, pdo):
- t = (pdo >> 30) & 3
- if t == 0:
- mv = ((pdo >> 10) & 0x3ff) * 50
- ma = ((pdo >> 0) & 0x3ff) * 10
- p = '%.1fV %.1fA' % (mv/1000.0, ma/1000.0)
- elif t == 1:
- minv = ((pdo >> 10) & 0x3ff) * 50
- maxv = ((pdo >> 20) & 0x3ff) * 50
- mw = ((pdo >> 0) & 0x3ff) * 250
- p = '%.1f/%.1fV %.1fW' % (minv/1000.0, maxv/1000.0, mw/1000.0)
- elif t == 2:
- minv = ((pdo >> 10) & 0x3ff) * 50
- maxv = ((pdo >> 20) & 0x3ff) * 50
- ma = ((pdo >> 0) & 0x3ff) * 10
- p = '%.1f/%.1fV %.1fA' % (minv/1000.0, maxv/1000.0, ma/1000.0)
+ flags += ' [' + RDO_FLAGS[f] + ']'
+ if pos in self.stored_pdos.keys():
+ return '(PDO #%d: %s) %gA (operating) / %gA (max)%s' % (pos, self.stored_pdos[pos], op_ma, max_ma, flags)
else:
- p = ''
+ return '(PDO #%d) %gA (operating) / %gA (max)%s' % (pos, op_ma, max_ma, flags)
+
+ def get_source_sink_cap(self, pdo, idx):
+ t1 = (pdo >> 30) & 3
+ if t1 == 0:
+ t_name = 'Fixed'
+ mv = ((pdo >> 10) & 0x3ff) * 0.05
+ ma = ((pdo >> 0) & 0x3ff) * 0.01
+ p = '%gV %gA (%gW)' % (mv, ma, mv*ma)
+ self.stored_pdos[idx] = '%s %gV' % (t_name, mv)
+ elif t1 == 1:
+ t_name = 'Battery'
+ minv = ((pdo >> 10) & 0x3ff) * 0.05
+ maxv = ((pdo >> 20) & 0x3ff) * 0.05
+ mw = ((pdo >> 0) & 0x3ff) * 0.25
+ p = '%g/%gV %gW' % (minv, maxv, mw)
+ self.stored_pdos[idx] = '%s %g/%gV' % (t_name, minv, maxv)
+ elif t1 == 2:
+ t_name = 'Variable'
+ minv = ((pdo >> 10) & 0x3ff) * 0.05
+ maxv = ((pdo >> 20) & 0x3ff) * 0.05
+ ma = ((pdo >> 0) & 0x3ff) * 0.01
+ p = '%g/%gV %gA' % (minv, maxv, ma)
+ self.stored_pdos[idx] = '%s %g/%gV' % (t_name, minv, maxv)
+ elif t1 == 3:
+ t2 = (pdo >> 28) & 3
+ if t2 == 0:
+ t_name = 'Programmable|PPS'
+ minv = ((pdo >> 8) & 0xff) * 0.1
+ maxv = ((pdo >> 17) & 0xff) * 0.1
+ ma = ((pdo >> 0) & 0xff) * 0.05
+ p = '%g/%gV %gA' % (minv, maxv, ma)
+ if (pdo >> 27) & 0x1:
+ p += ' [limited]'
+ self.stored_pdos[idx] = '%s %g/%gV' % (t_name, minv, maxv)
+ else:
+ t_name = 'Reserved APDO: '+bin(t2)
+ p = '[raw: %s]' % (bin(pdo))
+ self.stored_pdos[idx] = '%s %s' % (t_name, p)
flags = ''
for f in sorted(PDO_FLAGS.keys(), reverse = True):
if pdo & f:
- flags += ' ' + PDO_FLAGS[f]
- return '%s%s%s' % (PDO_TYPE[t], p, flags)
-
- def get_sink_cap(self, pdo):
- t = (pdo >> 30) & 3
- if t == 0:
- mv = ((pdo >> 10) & 0x3ff) * 50
- ma = ((pdo >> 0) & 0x3ff) * 10
- p = '%.1fV %.1fA' % (mv/1000.0, ma/1000.0)
- elif t == 1:
- minv = ((pdo >> 10) & 0x3ff) * 50
- maxv = ((pdo >> 20) & 0x3ff) * 50
- mw = ((pdo >> 0) & 0x3ff) * 250
- p = '%.1f/%.1fV %.1fW' % (minv/1000.0, maxv/1000.0, mw/1000.0)
- elif t == 2:
- minv = ((pdo >> 10) & 0x3ff) * 50
- maxv = ((pdo >> 20) & 0x3ff) * 50
- ma = ((pdo >> 0) & 0x3ff) * 10
- p = '%.1f/%.1fV %.1fA' % (minv/1000.0, maxv/1000.0, ma/1000.0)
- else:
- p = ''
- flags = ''
- for f in sorted(PDO_FLAGS.keys(), reverse = True):
- if pdo & f:
- flags += ' ' + PDO_FLAGS[f]
- return '%s%s%s' % (PDO_TYPE[t], p, flags)
+ flags += ' [' + PDO_FLAGS[f] + ']'
+ return '[%s] %s%s' % (t_name, p, flags)
def get_vdm(self, idx, data):
if idx == 0: # VDM header
def putpayload(self, s0, s1, idx):
t = self.head_type()
- txt = '???'
+ txt = '['+str(idx+1)+'] '
if t == 2:
- txt = self.get_request(self.data[idx])
- elif t == 1:
- txt = self.get_source_cap(self.data[idx])
- elif t == 4:
- txt = self.get_sink_cap(self.data[idx])
+ txt += self.get_request(self.data[idx])
+ elif t == 1 or t == 4:
+ txt += self.get_source_sink_cap(self.data[idx], idx+1)
elif t == 15:
- txt = self.get_vdm(idx, self.data[idx])
+ txt += self.get_vdm(idx, self.data[idx])
elif t == 3:
- txt = self.get_bist(idx, self.data[idx])
+ txt += self.get_bist(idx, self.data[idx])
self.putx(s0, s1, [11, [txt, txt]])
self.text += ' - ' + txt
def find_corrupted_sop(self, k):
# Start of packet are valid even if they have only 3 correct symbols
# out of 4.
- for seq in START_OF_PACKETS.keys():
+ for seq in SOP_SEQUENCES:
if [k[i] == seq[i] for i in range(len(k))].count(True) >= 3:
return START_OF_PACKETS[seq]
return None
for i in range(len(self.bits) - 19):
k = (self.get_sym(i, rec=False), self.get_sym(i+5, rec=False),
self.get_sym(i+10, rec=False), self.get_sym(i+15, rec=False))
- sym = START_OF_PACKETS[k] if k in START_OF_PACKETS else None
+ sym = START_OF_PACKETS.get(k, None)
if not sym:
sym = self.find_corrupted_sop(k)
# We have an interesting symbol sequence
self.bad = []
self.half_one = False
self.start_one = 0
+ self.stored_pdos = {}
def metadata(self, key, value):
if key == srd.SRD_CONF_SAMPLERATE:
if not self.samplerate:
raise SamplerateError('Cannot decode without samplerate.')
while True:
- self.wait({0: 'e'})
+ pins = self.wait([{0: 'e'}, {1: 'e'}, {'skip': 100*1000}])
+
# First sample of the packet, just record the start date
if not self.startsample: