Skip to content

Instantly share code, notes, and snippets.

@nicolas17
Last active November 8, 2025 06:54
Show Gist options
  • Save nicolas17/16e7b51ae861cce6000aa5904826168d to your computer and use it in GitHub Desktop.
Save nicolas17/16e7b51ae861cce6000aa5904826168d to your computer and use it in GitHub Desktop.

Revisions

  1. nicolas17 revised this gist May 27, 2024. 1 changed file with 17 additions and 2 deletions.
    19 changes: 17 additions & 2 deletions pd.py
    Original file line number Diff line number Diff line change
    @@ -24,10 +24,13 @@ class Decoder(srd.Decoder):
    ('addr', 'Address'),
    ('data', 'Data'),
    ('rw', 'R/W Bit'),
    ('write', 'Write'),
    ('read', 'Read'),
    )
    annotation_rows = (
    ('bits', 'Bits', (0,)),
    ('values', 'Values', (1,2,3)),
    ('txs', 'TXs', (4,5)),
    )

    def __init__(self):
    @@ -108,7 +111,7 @@ def decode_tx(self, bits):
    f'0x{data:x}',
    ]])

    return (dir, addr, data, tx_start, end)
    return (dir, addr, data, tx_start, tx_end)

    def decode_edges(self):
    while True:
    @@ -151,4 +154,16 @@ def decode(self):
    assert self.sample_rate is not None

    for tx in self.decode_txs(self.decode_bits(self.decode_edges())):
    pass
    dir, addr, data, tx_start, tx_end = tx
    if dir:
    self.put(tx_start, tx_end, self.out_ann, [4, [
    f"Write addr 0x{addr:02x} data 0x{data:02x}",
    f"Write 0x{addr:02x} data 0x{data:02x}",
    f"W 0x{addr:02x} data 0x{data:02x}",
    ]])
    else:
    self.put(tx_start, tx_end, self.out_ann, [5, [
    f"Read addr 0x{addr:02x} data 0x{data:02x}",
    f"Read 0x{addr:02x} data 0x{data:02x}",
    f"R 0x{addr:02x} data 0x{data:02x}",
    ]])
  2. nicolas17 revised this gist May 27, 2024. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions pd.py
    Original file line number Diff line number Diff line change
    @@ -70,9 +70,9 @@ def decode_tx(self, bits):

    tx_start = field_start
    self.put(field_start, end, self.out_ann, [1, [
    f'Address: #0x{addr:04x}',
    f'Addr: #0x{addr:04x}',
    f'#0x{addr:04x}',
    f'Address: #0x{addr:02x}',
    f'Addr: #0x{addr:02x}',
    f'#0x{addr:02x}',
    f'0x{addr:x}'
    ]])

  3. nicolas17 revised this gist May 27, 2024. 1 changed file with 25 additions and 19 deletions.
    44 changes: 25 additions & 19 deletions pd.py
    Original file line number Diff line number Diff line change
    @@ -52,25 +52,28 @@ def start(self):
    def decode_txs(self, bits):
    while True:
    tx = self.decode_tx(bits)
    if tx:
    yield tx

    def decode_tx(self, bits):
    # Parse address
    num = 0
    startsample = 0
    addr = 0
    field_start = 0
    for bitcount in range(7):
    bit, start, end = next(bits)
    if bit == "reset": return

    if bitcount == 0:
    startsample = start
    field_start = start

    num |= (bit << bitcount)
    addr |= (bit << bitcount)

    self.put(startsample, end, self.out_ann, [1, [
    f'Address: #0x{num:04x}',
    f'Addr: #0x{num:04x}',
    f'#0x{num:04x}',
    f'0x{num:x}'
    tx_start = field_start
    self.put(field_start, end, self.out_ann, [1, [
    f'Address: #0x{addr:04x}',
    f'Addr: #0x{addr:04x}',
    f'#0x{addr:04x}',
    f'0x{addr:x}'
    ]])

    # Parse R/W bit
    @@ -85,25 +88,28 @@ def decode_tx(self, bits):
    self.put(start, end, self.out_ann, [3, label])

    # Parse data
    num = 0
    startsample = 0
    data = 0
    field_start = 0
    for bitcount in range(8):
    bit, start, end = next(bits)
    if bit == "reset": return

    if bitcount == 0:
    startsample = start
    field_start = start

    num |= (bit << bitcount)
    data |= (bit << bitcount)

    self.put(startsample, end, self.out_ann, [2, [
    f'Data {"to write" if dir else "read"}: 0x{num:x}',
    f'Data {"W" if dir else "R"}: 0x{num:x}',
    f'Data: 0x{num:x}',
    f'D: 0x{num:x}',
    f'0x{num:x}',
    tx_end = end
    self.put(field_start, end, self.out_ann, [2, [
    f'Data {"to write" if dir else "read"}: 0x{data:x}',
    f'Data {"W" if dir else "R"}: 0x{data:x}',
    f'Data: 0x{data:x}',
    f'D: 0x{data:x}',
    f'0x{data:x}',
    ]])

    return (dir, addr, data, tx_start, end)

    def decode_edges(self):
    while True:
    self.wait({0: 'f'})
  4. nicolas17 revised this gist May 27, 2024. 1 changed file with 51 additions and 52 deletions.
    103 changes: 51 additions & 52 deletions pd.py
    Original file line number Diff line number Diff line change
    @@ -54,56 +54,55 @@ def decode_txs(self, bits):
    tx = self.decode_tx(bits)

    def decode_tx(self, bits):
    state = "INITIAL"
    num = bitcount = startsample = 0

    for bit, start, end in bits:
    if bit == "reset":
    return

    bit = int(bit)

    if state == 'INITIAL':
    if startsample == 0:
    startsample = start

    num |= (bit << bitcount)
    bitcount += 1
    if bitcount == 7:
    self.put(startsample, end, self.out_ann, [1, [
    f'Address: #0x{num:04x}',
    f'Addr: #0x{num:04x}',
    f'#0x{num:04x}',
    f'0x{num:x}'
    ]])
    state = 'RW'
    num = bitcount = startsample = 0

    elif state == 'RW':
    if bit:
    label = ['Write', 'W']
    else:
    label = ['Read', 'R']
    dir = bit
    self.put(start, end, self.out_ann, [3, label])
    state = 'DATA'
    num = bitcount = startsample = 0

    elif state == 'DATA':
    if startsample == 0:
    startsample = start

    num |= (bit << bitcount)
    bitcount += 1
    if bitcount == 8:
    self.put(startsample, end, self.out_ann, [2, [
    f'Data {"to write" if dir else "read"}: 0x{num:x}',
    f'Data {"W" if dir else "R"}: 0x{num:x}',
    f'Data: 0x{num:x}',
    f'D: 0x{num:x}',
    f'0x{num:x}',
    ]])
    return
    # Parse address
    num = 0
    startsample = 0
    for bitcount in range(7):
    bit, start, end = next(bits)
    if bit == "reset": return

    if bitcount == 0:
    startsample = start

    num |= (bit << bitcount)

    self.put(startsample, end, self.out_ann, [1, [
    f'Address: #0x{num:04x}',
    f'Addr: #0x{num:04x}',
    f'#0x{num:04x}',
    f'0x{num:x}'
    ]])

    # Parse R/W bit
    bit, start, end = next(bits)
    if bit == "reset": return

    if bit:
    label = ['Write', 'W']
    else:
    label = ['Read', 'R']
    dir = bit
    self.put(start, end, self.out_ann, [3, label])

    # Parse data
    num = 0
    startsample = 0
    for bitcount in range(8):
    bit, start, end = next(bits)
    if bit == "reset": return

    if bitcount == 0:
    startsample = start

    num |= (bit << bitcount)

    self.put(startsample, end, self.out_ann, [2, [
    f'Data {"to write" if dir else "read"}: 0x{num:x}',
    f'Data {"W" if dir else "R"}: 0x{num:x}',
    f'Data: 0x{num:x}',
    f'D: 0x{num:x}',
    f'0x{num:x}',
    ]])

    def decode_edges(self):
    while True:
    @@ -136,10 +135,10 @@ def decode_bits(self, edges):
    yield ("reset", ann_start, ann_end)
    elif MIN_ZERO <= t <= MAX_ZERO:
    self.put(ann_start, ann_end, self.out_ann, [0, ['0']])
    yield ("0", ann_start, ann_end)
    yield (0, ann_start, ann_end)
    elif MIN_ONE <= t <= MAX_ONE:
    self.put(ann_start, ann_end, self.out_ann, [0, ['1']])
    yield ("1", ann_start, ann_end)
    yield (1, ann_start, ann_end)

    def decode(self):
    print("DECODE")
  5. nicolas17 revised this gist May 27, 2024. 1 changed file with 41 additions and 40 deletions.
    81 changes: 41 additions & 40 deletions pd.py
    Original file line number Diff line number Diff line change
    @@ -48,61 +48,62 @@ def metadata(self, key, value):
    def start(self):
    print("START")
    self.out_ann = self.register(srd.OUTPUT_ANN)
    self.set_state('INITIAL')

    def set_state(self, state):
    self.state = state
    self.num = 0
    self.bitcount = 0
    self.startsample = 0

    def decode_txs(self, bits):
    while True:
    tx = self.decode_tx(bits)

    def decode_tx(self, bits):
    state = "INITIAL"
    num = bitcount = startsample = 0

    for bit, start, end in bits:
    if bit == "reset":
    self.set_state("INITIAL")
    continue
    return

    bit = int(bit)

    if self.state == 'INITIAL':
    if self.startsample == 0:
    self.startsample = start

    self.num |= (bit << self.bitcount)
    self.bitcount += 1
    if self.bitcount == 7:
    self.put(self.startsample, end, self.out_ann, [1, [
    f'Address: #0x{self.num:04x}',
    f'Addr: #0x{self.num:04x}',
    f'#0x{self.num:04x}',
    f'0x{self.num:x}'
    if state == 'INITIAL':
    if startsample == 0:
    startsample = start

    num |= (bit << bitcount)
    bitcount += 1
    if bitcount == 7:
    self.put(startsample, end, self.out_ann, [1, [
    f'Address: #0x{num:04x}',
    f'Addr: #0x{num:04x}',
    f'#0x{num:04x}',
    f'0x{num:x}'
    ]])
    self.set_state('RW')
    state = 'RW'
    num = bitcount = startsample = 0

    elif self.state == 'RW':
    elif state == 'RW':
    if bit:
    label = ['Write', 'W']
    else:
    label = ['Read', 'R']
    self.dir=bit
    dir = bit
    self.put(start, end, self.out_ann, [3, label])
    self.set_state('DATA')

    elif self.state == 'DATA':
    if self.startsample == 0:
    self.startsample = start

    self.num |= (bit << self.bitcount)
    self.bitcount += 1
    if self.bitcount == 8:
    self.put(self.startsample, end, self.out_ann, [2, [
    f'Data {"to write" if self.dir else "read"}: 0x{self.num:x}',
    f'Data {"W" if self.dir else "R"}: 0x{self.num:x}',
    f'Data: 0x{self.num:x}',
    f'D: 0x{self.num:x}',
    f'0x{self.num:x}',
    state = 'DATA'
    num = bitcount = startsample = 0

    elif state == 'DATA':
    if startsample == 0:
    startsample = start

    num |= (bit << bitcount)
    bitcount += 1
    if bitcount == 8:
    self.put(startsample, end, self.out_ann, [2, [
    f'Data {"to write" if dir else "read"}: 0x{num:x}',
    f'Data {"W" if dir else "R"}: 0x{num:x}',
    f'Data: 0x{num:x}',
    f'D: 0x{num:x}',
    f'0x{num:x}',
    ]])
    self.set_state('INITIAL')
    return

    def decode_edges(self):
    while True:
  6. nicolas17 revised this gist May 27, 2024. 1 changed file with 49 additions and 47 deletions.
    96 changes: 49 additions & 47 deletions pd.py
    Original file line number Diff line number Diff line change
    @@ -56,46 +56,53 @@ def set_state(self, state):
    self.bitcount = 0
    self.startsample = 0

    def decode_bit(self, bit, start, end):
    if self.state == 'INITIAL':
    if self.startsample == 0:
    self.startsample = start

    self.num |= (bit << self.bitcount)
    self.bitcount += 1
    if self.bitcount == 7:
    self.put(self.startsample, end, self.out_ann, [1, [
    f'Address: #0x{self.num:04x}',
    f'Addr: #0x{self.num:04x}',
    f'#0x{self.num:04x}',
    f'0x{self.num:x}'
    ]])
    self.set_state('RW')

    elif self.state == 'RW':
    if bit:
    label = ['Write', 'W']
    else:
    label = ['Read', 'R']
    self.dir=bit
    self.put(start, end, self.out_ann, [3, label])
    self.set_state('DATA')

    elif self.state == 'DATA':
    if self.startsample == 0:
    self.startsample = start

    self.num |= (bit << self.bitcount)
    self.bitcount += 1
    if self.bitcount == 8:
    self.put(self.startsample, end, self.out_ann, [2, [
    f'Data {"to write" if self.dir else "read"}: 0x{self.num:x}',
    f'Data {"W" if self.dir else "R"}: 0x{self.num:x}',
    f'Data: 0x{self.num:x}',
    f'D: 0x{self.num:x}',
    f'0x{self.num:x}',
    ]])
    self.set_state('INITIAL')
    def decode_txs(self, bits):
    for bit, start, end in bits:
    if bit == "reset":
    self.set_state("INITIAL")
    continue

    bit = int(bit)

    if self.state == 'INITIAL':
    if self.startsample == 0:
    self.startsample = start

    self.num |= (bit << self.bitcount)
    self.bitcount += 1
    if self.bitcount == 7:
    self.put(self.startsample, end, self.out_ann, [1, [
    f'Address: #0x{self.num:04x}',
    f'Addr: #0x{self.num:04x}',
    f'#0x{self.num:04x}',
    f'0x{self.num:x}'
    ]])
    self.set_state('RW')

    elif self.state == 'RW':
    if bit:
    label = ['Write', 'W']
    else:
    label = ['Read', 'R']
    self.dir=bit
    self.put(start, end, self.out_ann, [3, label])
    self.set_state('DATA')

    elif self.state == 'DATA':
    if self.startsample == 0:
    self.startsample = start

    self.num |= (bit << self.bitcount)
    self.bitcount += 1
    if self.bitcount == 8:
    self.put(self.startsample, end, self.out_ann, [2, [
    f'Data {"to write" if self.dir else "read"}: 0x{self.num:x}',
    f'Data {"W" if self.dir else "R"}: 0x{self.num:x}',
    f'Data: 0x{self.num:x}',
    f'D: 0x{self.num:x}',
    f'0x{self.num:x}',
    ]])
    self.set_state('INITIAL')

    def decode_edges(self):
    while True:
    @@ -137,10 +144,5 @@ def decode(self):
    print("DECODE")
    assert self.sample_rate is not None

    for bit, start, end in self.decode_bits(self.decode_edges()):
    if bit == "reset":
    self.set_state('INITIAL')
    elif bit == "0":
    self.decode_bit(0, start, end)
    elif bit == "1":
    self.decode_bit(1, start, end)
    for tx in self.decode_txs(self.decode_bits(self.decode_edges())):
    pass
  7. nicolas17 revised this gist May 27, 2024. 1 changed file with 29 additions and 11 deletions.
    40 changes: 29 additions & 11 deletions pd.py
    Original file line number Diff line number Diff line change
    @@ -97,32 +97,50 @@ def decode_bit(self, bit, start, end):
    ]])
    self.set_state('INITIAL')

    def decode(self):
    print("DECODE")
    assert self.sample_rate is not None
    def decode_edges(self):
    while True:
    self.wait({0: 'f'})
    fall_sample = self.samplenum
    self.wait({0: 'r'})
    raise_sample = self.samplenum
    yield (fall_sample, raise_sample)

    def decode_bits(self, edges):
    """
    Measures the timings between edges and decodes them into bits.
    Yields tuples with ("reset"|"0"|"1", start, end).
    """
    MICRO = 1_000_000
    MIN_BREAK = self.sample_rate * 190 // MICRO
    MIN_ZERO = self.sample_rate * 86 // MICRO
    MAX_ZERO = self.sample_rate * 145 // MICRO
    MIN_ONE = self.sample_rate * 17 // MICRO
    MAX_ONE = self.sample_rate * 50 // MICRO

    while True:
    self.wait({0: 'f'})
    fall_sample = self.samplenum
    self.wait({0: 'r'})
    raise_sample = self.samplenum
    for fall_sample, raise_sample in edges:
    t = raise_sample - fall_sample

    ann_start = fall_sample
    ann_end = raise_sample

    if t > MIN_BREAK:
    self.put(ann_start, ann_end, self.out_ann, [0, ['Reset']])
    self.set_state('INITIAL')
    yield ("reset", ann_start, ann_end)
    elif MIN_ZERO <= t <= MAX_ZERO:
    self.put(ann_start, ann_end, self.out_ann, [0, ['0']])
    self.decode_bit(0, ann_start, ann_end)
    yield ("0", ann_start, ann_end)
    elif MIN_ONE <= t <= MAX_ONE:
    self.put(ann_start, ann_end, self.out_ann, [0, ['1']])
    self.decode_bit(1, ann_start, ann_end)
    yield ("1", ann_start, ann_end)

    def decode(self):
    print("DECODE")
    assert self.sample_rate is not None

    for bit, start, end in self.decode_bits(self.decode_edges()):
    if bit == "reset":
    self.set_state('INITIAL')
    elif bit == "0":
    self.decode_bit(0, start, end)
    elif bit == "1":
    self.decode_bit(1, start, end)
  8. nicolas17 revised this gist May 26, 2024. 1 changed file with 57 additions and 2 deletions.
    59 changes: 57 additions & 2 deletions pd.py
    Original file line number Diff line number Diff line change
    @@ -20,10 +20,14 @@ class Decoder(srd.Decoder):
    )
    options = ()
    annotations = (
    ('bit', 'Value'),
    ('bit', 'Bit'),
    ('addr', 'Address'),
    ('data', 'Data'),
    ('rw', 'R/W Bit'),
    )
    annotation_rows = (
    ('bits', 'Values', (0,)),
    ('bits', 'Bits', (0,)),
    ('values', 'Values', (1,2,3)),
    )

    def __init__(self):
    @@ -44,6 +48,54 @@ def metadata(self, key, value):
    def start(self):
    print("START")
    self.out_ann = self.register(srd.OUTPUT_ANN)
    self.set_state('INITIAL')

    def set_state(self, state):
    self.state = state
    self.num = 0
    self.bitcount = 0
    self.startsample = 0

    def decode_bit(self, bit, start, end):
    if self.state == 'INITIAL':
    if self.startsample == 0:
    self.startsample = start

    self.num |= (bit << self.bitcount)
    self.bitcount += 1
    if self.bitcount == 7:
    self.put(self.startsample, end, self.out_ann, [1, [
    f'Address: #0x{self.num:04x}',
    f'Addr: #0x{self.num:04x}',
    f'#0x{self.num:04x}',
    f'0x{self.num:x}'
    ]])
    self.set_state('RW')

    elif self.state == 'RW':
    if bit:
    label = ['Write', 'W']
    else:
    label = ['Read', 'R']
    self.dir=bit
    self.put(start, end, self.out_ann, [3, label])
    self.set_state('DATA')

    elif self.state == 'DATA':
    if self.startsample == 0:
    self.startsample = start

    self.num |= (bit << self.bitcount)
    self.bitcount += 1
    if self.bitcount == 8:
    self.put(self.startsample, end, self.out_ann, [2, [
    f'Data {"to write" if self.dir else "read"}: 0x{self.num:x}',
    f'Data {"W" if self.dir else "R"}: 0x{self.num:x}',
    f'Data: 0x{self.num:x}',
    f'D: 0x{self.num:x}',
    f'0x{self.num:x}',
    ]])
    self.set_state('INITIAL')

    def decode(self):
    print("DECODE")
    @@ -67,7 +119,10 @@ def decode(self):

    if t > MIN_BREAK:
    self.put(ann_start, ann_end, self.out_ann, [0, ['Reset']])
    self.set_state('INITIAL')
    elif MIN_ZERO <= t <= MAX_ZERO:
    self.put(ann_start, ann_end, self.out_ann, [0, ['0']])
    self.decode_bit(0, ann_start, ann_end)
    elif MIN_ONE <= t <= MAX_ONE:
    self.put(ann_start, ann_end, self.out_ann, [0, ['1']])
    self.decode_bit(1, ann_start, ann_end)
  9. nicolas17 revised this gist May 26, 2024. 1 changed file with 24 additions and 2 deletions.
    26 changes: 24 additions & 2 deletions pd.py
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,5 @@
    # Copyright (c) 2024 JJTech <[email protected]>
    # Copyright (c) 2024 Nicolás Alvarez <[email protected]>
    #
    # SPDX-License-Identifier: GPL-2.0-or-later

    @@ -47,5 +48,26 @@ def start(self):
    def decode(self):
    print("DECODE")
    assert self.sample_rate is not None
    self.wait({0: 'f'})
    self.put(self.samplenum, self.samplenum, self.out_ann, [0, ['test', 'test', 'test']])
    MICRO = 1_000_000
    MIN_BREAK = self.sample_rate * 190 // MICRO
    MIN_ZERO = self.sample_rate * 86 // MICRO
    MAX_ZERO = self.sample_rate * 145 // MICRO
    MIN_ONE = self.sample_rate * 17 // MICRO
    MAX_ONE = self.sample_rate * 50 // MICRO

    while True:
    self.wait({0: 'f'})
    fall_sample = self.samplenum
    self.wait({0: 'r'})
    raise_sample = self.samplenum
    t = raise_sample - fall_sample

    ann_start = fall_sample
    ann_end = raise_sample

    if t > MIN_BREAK:
    self.put(ann_start, ann_end, self.out_ann, [0, ['Reset']])
    elif MIN_ZERO <= t <= MAX_ZERO:
    self.put(ann_start, ann_end, self.out_ann, [0, ['0']])
    elif MIN_ONE <= t <= MAX_ONE:
    self.put(ann_start, ann_end, self.out_ann, [0, ['1']])
  10. @JJTech0130 JJTech0130 created this gist May 26, 2024.
    16 changes: 16 additions & 0 deletions __init__.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    # Copyright (c) 2024 JJTech <[email protected]>
    #
    # SPDX-License-Identifier: GPL-2.0-or-later

    """
    HDQ (High-speed Data Queue) is a simple protocol used for Texas Instruments
    'Gas Gauge' battery fuel gauges. It is used to read and write data to the fuel
    gauge's memory.
    Similarly to the '1-wire' protocol, it is a single-wire protocol that uses a
    single data line to communicate with the fuel gauge.
    Protocol documentation: https://www.ti.com/lit/pdf/slua408
    """
    import sigrokdecode as srd # type: ignore

    from .pd import Decoder
    51 changes: 51 additions & 0 deletions pd.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,51 @@
    # Copyright (c) 2024 JJTech <[email protected]>
    #
    # SPDX-License-Identifier: GPL-2.0-or-later

    import sigrokdecode as srd # type: ignore

    class Decoder(srd.Decoder):
    api_version = 3
    id = 'hdq'
    name = 'HDQ'
    longname = 'HDQ (High-speed Data Queue)'
    desc = 'Texas Instruments Gas Gauge battery fuel gauge protocol'
    license = 'mit'
    inputs = ['logic']
    outputs = ['hdq']
    tags = ['Embedded/industrial']
    channels = (
    {'id': 'data', 'name': 'Data', 'desc': 'Data line'},
    )
    options = ()
    annotations = (
    ('bit', 'Value'),
    )
    annotation_rows = (
    ('bits', 'Values', (0,)),
    )

    def __init__(self):
    print("INIT")
    self.reset()

    def reset(self):
    print("RESET")
    self.sample_rate = None

    self.previous_sample_num = 0

    def metadata(self, key, value):
    print("METADATA")
    if key == srd.SRD_CONF_SAMPLERATE:
    self.sample_rate = value

    def start(self):
    print("START")
    self.out_ann = self.register(srd.OUTPUT_ANN)

    def decode(self):
    print("DECODE")
    assert self.sample_rate is not None
    self.wait({0: 'f'})
    self.put(self.samplenum, self.samplenum, self.out_ann, [0, ['test', 'test', 'test']])