From 8bc228ebb58ea709e981287a57a0864f914fb4e0 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 12:41:20 +0200 Subject: [PATCH 01/42] Add decoder for cJTAG from sigrok --- .../decoders/cjtag/__init__.py | 36 ++ libsigrokdecode4DSL/decoders/cjtag/pd.py | 323 ++++++++++++++++++ 2 files changed, 359 insertions(+) create mode 100644 libsigrokdecode4DSL/decoders/cjtag/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/cjtag/pd.py diff --git a/libsigrokdecode4DSL/decoders/cjtag/__init__.py b/libsigrokdecode4DSL/decoders/cjtag/__init__.py new file mode 100644 index 00000000..168d4d60 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/cjtag/__init__.py @@ -0,0 +1,36 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012 Uwe Hermann +## +## 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 +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see . +## + +''' +JTAG (Joint Test Action Group), a.k.a. "IEEE 1149.1: Standard Test Access Port +and Boundary-Scan Architecture", is a protocol used for testing, debugging, +and flashing various digital ICs. + +Details: +https://en.wikipedia.org/wiki/Joint_Test_Action_Group +http://focus.ti.com/lit/an/ssya002c/ssya002c.pdf + +This decoder handles a tiny part of IEEE 1149.7, the CJTAG OSCAN1 format. +ZBS is currently not supported. + +Details: +http://developers-club.com/posts/237885/ +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/cjtag/pd.py b/libsigrokdecode4DSL/decoders/cjtag/pd.py new file mode 100644 index 00000000..cd4dc4e5 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/cjtag/pd.py @@ -0,0 +1,323 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2012-2020 Uwe Hermann +## Copyright (C) 2019 Zhiyuan Wan +## Copyright (C) 2019 Kongou Hikari +## +## 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 +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see . +## + +import sigrokdecode as srd +from common.srdhelper import SrdStrEnum + +''' +OUTPUT_PYTHON format: + +Packet: +[, ] + +: + - 'NEW STATE': is the new state of the JTAG state machine. + Valid values: 'TEST-LOGIC-RESET', 'RUN-TEST/IDLE', 'SELECT-DR-SCAN', + 'CAPTURE-DR', 'SHIFT-DR', 'EXIT1-DR', 'PAUSE-DR', 'EXIT2-DR', 'UPDATE-DR', + 'SELECT-IR-SCAN', 'CAPTURE-IR', 'SHIFT-IR', 'EXIT1-IR', 'PAUSE-IR', + 'EXIT2-IR', 'UPDATE-IR'. + - 'IR TDI': Bitstring that was clocked into the IR register. + - 'IR TDO': Bitstring that was clocked out of the IR register. + - 'DR TDI': Bitstring that was clocked into the DR register. + - 'DR TDO': Bitstring that was clocked out of the DR register. + +All bitstrings are a list consisting of two items. The first is a sequence +of '1' and '0' characters (the right-most character is the LSB. Example: +'01110001', where 1 is the LSB). The second item is a list of ss/es values +for each bit that is in the bitstring. +''' + +s = 'TEST-LOGIC-RESET RUN-TEST/IDLE \ + SELECT-DR-SCAN CAPTURE-DR UPDATE-DR PAUSE-DR SHIFT-DR EXIT1-DR EXIT2-DR \ + SELECT-IR-SCAN CAPTURE-IR UPDATE-IR PAUSE-IR SHIFT-IR EXIT1-IR EXIT2-IR' +St = SrdStrEnum.from_str('St', s) + +jtag_states = [s.value for s in St] + +s = 'EC SPARE TPDEL TPREV TPST RDYC DLYC SCNFMT CP OAC'.split() +s = ['CJTAG_' + x for x in s] + ['OSCAN1', 'FOUR_WIRE'] +CSt = SrdStrEnum.from_list('CSt', s) + +cjtag_states = [s.value for s in CSt] + +class Decoder(srd.Decoder): + api_version = 3 + id = 'cjtag' + name = 'cJTAG' + longname = 'Compact Joint Test Action Group (IEEE 1149.7)' + desc = 'Protocol for testing, debugging, and flashing ICs.' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['jtag'] + tags = ['Debug/trace'] + channels = ( + {'id': 'tckc', 'name': 'TCKC', 'desc': 'Test clock'}, + {'id': 'tmsc', 'name': 'TMSC', 'desc': 'Test mode select'}, + ) + annotations = \ + tuple([tuple([s.lower(), s]) for s in jtag_states]) + \ + tuple([tuple([s.lower(), s]) for s in cjtag_states]) + ( \ + ('bit-tdi', 'Bit (TDI)'), + ('bit-tdo', 'Bit (TDO)'), + ('bitstring-tdi', 'Bitstring (TDI)'), + ('bitstring-tdo', 'Bitstring (TDO)'), + ('bit-tms', 'Bit (TMS)'), + ) + annotation_rows = ( + ('bits-tdi', 'Bits (TDI)', (28,)), + ('bits-tdo', 'Bits (TDO)', (29,)), + ('bitstrings-tdi', 'Bitstrings (TDI)', (30,)), + ('bitstrings-tdo', 'Bitstrings (TDO)', (31,)), + ('bits-tms', 'Bits (TMS)', (32,)), + ('cjtag-states', 'CJTAG states', + tuple(range(len(jtag_states), len(jtag_states + cjtag_states)))), + ('jtag-states', 'JTAG states', tuple(range(len(jtag_states)))), + ) + + def __init__(self): + self.reset() + + def reset(self): + # self.state = St.TEST_LOGIC_RESET + self.state = St.RUN_TEST_IDLE + self.cjtagstate = CSt.FOUR_WIRE + self.oldcjtagstate = None + self.escape_edges = 0 + self.oaclen = 0 + self.oldtms = 0 + self.oacp = 0 + self.oscan1cycle = 0 + self.oldstate = None + self.bits_tdi = [] + self.bits_tdo = [] + self.bits_samplenums_tdi = [] + self.bits_samplenums_tdo = [] + self.ss_item = self.es_item = None + self.ss_bitstring = self.es_bitstring = None + self.saved_item = None + self.first = True + self.first_bit = True + + def start(self): + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss_item, self.es_item, self.out_ann, data) + + def putp(self, data): + self.put(self.ss_item, self.es_item, self.out_python, data) + + def putx_bs(self, data): + self.put(self.ss_bitstring, self.es_bitstring, self.out_ann, data) + + def putp_bs(self, data): + self.put(self.ss_bitstring, self.es_bitstring, self.out_python, data) + + def advance_state_machine(self, tms): + self.oldstate = self.state + + if self.cjtagstate.value.startswith('CJTAG_'): + self.oacp += 1 + if self.oacp > 4 and self.oaclen == 12: + self.cjtagstate = CSt.CJTAG_EC + + if self.oacp == 8 and tms == 0: + self.oaclen = 36 + if self.oacp > 8 and self.oaclen == 36: + self.cjtagstate = CSt.CJTAG_SPARE + if self.oacp > 13 and self.oaclen == 36: + self.cjtagstate = CSt.CJTAG_TPDEL + if self.oacp > 16 and self.oaclen == 36: + self.cjtagstate = CSt.CJTAG_TPREV + if self.oacp > 18 and self.oaclen == 36: + self.cjtagstate = CSt.CJTAG_TPST + if self.oacp > 23 and self.oaclen == 36: + self.cjtagstate = CSt.CJTAG_RDYC + if self.oacp > 25 and self.oaclen == 36: + self.cjtagstate = CSt.CJTAG_DLYC + if self.oacp > 27 and self.oaclen == 36: + self.cjtagstate = CSt.CJTAG_SCNFMT + + if self.oacp > 8 and self.oaclen == 12: + self.cjtagstate = CSt.CJTAG_CP + if self.oacp > 32 and self.oaclen == 36: + self.cjtagstate = CSt.CJTAG_CP + + if self.oacp > self.oaclen: + self.cjtagstate = CSt.OSCAN1 + self.oscan1cycle = 1 + # Because Nuclei cJTAG device asserts a reset during cJTAG + # online activating. + self.state = St.TEST_LOGIC_RESET + return + + # Intro "tree" + if self.state == St.TEST_LOGIC_RESET: + self.state = St.TEST_LOGIC_RESET if (tms) else St.RUN_TEST_IDLE + elif self.state == St.RUN_TEST_IDLE: + self.state = St.SELECT_DR_SCAN if (tms) else St.RUN_TEST_IDLE + + # DR "tree" + elif self.state == St.SELECT_DR_SCAN: + self.state = St.SELECT_IR_SCAN if (tms) else St.CAPTURE_DR + elif self.state == St.CAPTURE_DR: + self.state = St.EXIT1_DR if (tms) else St.SHIFT_DR + elif self.state == St.SHIFT_DR: + self.state = St.EXIT1_DR if (tms) else St.SHIFT_DR + elif self.state == St.EXIT1_DR: + self.state = St.UPDATE_DR if (tms) else St.PAUSE_DR + elif self.state == St.PAUSE_DR: + self.state = St.EXIT2_DR if (tms) else St.PAUSE_DR + elif self.state == St.EXIT2_DR: + self.state = St.UPDATE_DR if (tms) else St.SHIFT_DR + elif self.state == St.UPDATE_DR: + self.state = St.SELECT_DR_SCAN if (tms) else St.RUN_TEST_IDLE + + # IR "tree" + elif self.state == St.SELECT_IR_SCAN: + self.state = St.TEST_LOGIC_RESET if (tms) else St.CAPTURE_IR + elif self.state == St.CAPTURE_IR: + self.state = St.EXIT1_IR if (tms) else St.SHIFT_IR + elif self.state == St.SHIFT_IR: + self.state = St.EXIT1_IR if (tms) else St.SHIFT_IR + elif self.state == St.EXIT1_IR: + self.state = St.UPDATE_IR if (tms) else St.PAUSE_IR + elif self.state == St.PAUSE_IR: + self.state = St.EXIT2_IR if (tms) else St.PAUSE_IR + elif self.state == St.EXIT2_IR: + self.state = St.UPDATE_IR if (tms) else St.SHIFT_IR + elif self.state == St.UPDATE_IR: + self.state = St.SELECT_DR_SCAN if (tms) else St.RUN_TEST_IDLE + + def handle_rising_tckc_edge(self, tdi, tdo, tck, tms): + + # Rising TCK edges always advance the state machine. + self.advance_state_machine(tms) + + if self.first: + # Save the start sample and item for later (no output yet). + self.ss_item = self.samplenum + self.first = False + else: + # Output the saved item (from the last CLK edge to the current). + self.es_item = self.samplenum + # Output the old state (from last rising TCK edge to current one). + self.putx([jtag_states.index(self.oldstate.value), [self.oldstate.value]]) + self.putp(['NEW STATE', self.state.value]) + + self.putx([len(jtag_states) + cjtag_states.index(self.oldcjtagstate.value), + [self.oldcjtagstate.value]]) + if (self.oldcjtagstate.value.startswith('CJTAG_')): + self.putx([32, [str(self.oldtms)]]) + self.oldtms = tms + + # Upon SHIFT-*/EXIT1-* collect the current TDI/TDO values. + if self.oldstate.value.startswith('SHIFT-') or \ + self.oldstate.value.startswith('EXIT1-'): + if self.first_bit: + self.ss_bitstring = self.samplenum + self.first_bit = False + else: + self.putx([28, [str(self.bits_tdi[0])]]) + self.putx([29, [str(self.bits_tdo[0])]]) + # Use self.samplenum as ES of the previous bit. + self.bits_samplenums_tdi[0][1] = self.samplenum + self.bits_samplenums_tdo[0][1] = self.samplenum + + self.bits_tdi.insert(0, tdi) + self.bits_tdo.insert(0, tdo) + + # Use self.samplenum as SS of the current bit. + self.bits_samplenums_tdi.insert(0, [self.samplenum, -1]) + self.bits_samplenums_tdo.insert(0, [self.samplenum, -1]) + + # Output all TDI/TDO bits if we just switched to UPDATE-*. + if self.state.value.startswith('UPDATE-'): + + self.es_bitstring = self.samplenum + + t = self.state.value[-2:] + ' TDI' + b = ''.join(map(str, self.bits_tdi[1:])) + h = ' (0x%x' % int('0b0' + b, 2) + ')' + s = t + ': ' + b + h + ', ' + str(len(self.bits_tdi[1:])) + ' bits' + self.putx_bs([30, [s]]) + self.putp_bs([t, [b, self.bits_samplenums_tdi[1:]]]) + self.bits_tdi = [] + self.bits_samplenums_tdi = [] + + t = self.state.value[-2:] + ' TDO' + b = ''.join(map(str, self.bits_tdo[1:])) + h = ' (0x%x' % int('0b0' + b, 2) + ')' + s = t + ': ' + b + h + ', ' + str(len(self.bits_tdo[1:])) + ' bits' + self.putx_bs([31, [s]]) + self.putp_bs([t, [b, self.bits_samplenums_tdo[1:]]]) + self.bits_tdo = [] + self.bits_samplenums_tdo = [] + + self.first_bit = True + + self.ss_bitstring = self.samplenum + + self.ss_item = self.samplenum + + def handle_tmsc_edge(self): + self.escape_edges += 1 + + def handle_tapc_state(self): + self.oldcjtagstate = self.cjtagstate + + if self.escape_edges >= 8: + self.cjtagstate = CSt.FOUR_WIRE + if self.escape_edges == 6: + self.cjtagstate = CSt.CJTAG_OAC + self.oacp = 0 + self.oaclen = 12 + + self.escape_edges = 0 + + def decode(self): + tdi = tms = tdo = 0 + + while True: + # Wait for a rising edge on TCKC. + tckc, tmsc = self.wait({0: 'r'}) + self.handle_tapc_state() + + if self.cjtagstate == CSt.OSCAN1: + if self.oscan1cycle == 0: # nTDI + tdi = 1 if (tmsc == 0) else 0 + self.oscan1cycle = 1 + elif self.oscan1cycle == 1: # TMS + tms = tmsc + self.oscan1cycle = 2 + elif self.oscan1cycle == 2: # TDO + tdo = tmsc + self.handle_rising_tckc_edge(tdi, tdo, tckc, tms) + self.oscan1cycle = 0 + else: + self.handle_rising_tckc_edge(None, None, tckc, tmsc) + + while (tckc == 1): + tckc, tmsc_n = self.wait([{0: 'f'}, {1: 'e'}]) + if tmsc_n != tmsc: + tmsc = tmsc_n + self.handle_tmsc_edge() From 93d7e092473deeaee12c1b840faea21a2248ab9c Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 12:45:21 +0200 Subject: [PATCH 02/42] Add SBUS (Futaba) decoder from sigrok --- .../decoders/sbus_futaba/__init__.py | 35 +++ .../decoders/sbus_futaba/pd.py | 273 ++++++++++++++++++ 2 files changed, 308 insertions(+) create mode 100644 libsigrokdecode4DSL/decoders/sbus_futaba/__init__.py create mode 100644 libsigrokdecode4DSL/decoders/sbus_futaba/pd.py diff --git a/libsigrokdecode4DSL/decoders/sbus_futaba/__init__.py b/libsigrokdecode4DSL/decoders/sbus_futaba/__init__.py new file mode 100644 index 00000000..9404f4f2 --- /dev/null +++ b/libsigrokdecode4DSL/decoders/sbus_futaba/__init__.py @@ -0,0 +1,35 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2022 Gerhard Sittig +## +## 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 +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see . +## + +''' +SBUS by Futaba, a hobby remote control protocol on top of UART. +Sometimes referred to as "Serial BUS" or S-BUS. + +UART communication typically runs at 100kbps with 8e2 frame format and +inverted signals (high voltage level is logic low). + +SBUS messages take 3ms to transfer, and typically repeat in intervals +of 7ms or 14ms. An SBUS message consists of 25 UART bytes, and carries +16 proportional channels with 11 bits each, and 2 digital channels +(boolean, 1 bit), and flags which represent current communication state. +Proportional channel values typically are in the 192..1792 range, but +individual implementations may differ. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/sbus_futaba/pd.py b/libsigrokdecode4DSL/decoders/sbus_futaba/pd.py new file mode 100644 index 00000000..75c2cfba --- /dev/null +++ b/libsigrokdecode4DSL/decoders/sbus_futaba/pd.py @@ -0,0 +1,273 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2022 Gerhard Sittig +## +## 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 +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see . +## + +""" +OUTPUT_PYTHON format: + +Packet: +(, ) + +This is the list of codes and their respective values: + - 'HEADER': The data is the header byte's value. + - 'PROPORTIONAL': The data is a tuple of the channel number (1-based) + and the channel's value. + - 'DIGITAL': The data is a tuple of the channel number (1-based) + and the channel's value. + - 'FLAG': The data is a tuple of the flag's name, and the flag's value. + - 'FOOTER': The data is the footer byte's value. +""" + +import sigrokdecode as srd +from common.srdhelper import bitpack_lsb + +class Ann: + HEADER, PROPORTIONAL, DIGITAL, FRAME_LOST, FAILSAFE, FOOTER, \ + WARN = range(7) + FLAG_LSB = FRAME_LOST + +class Decoder(srd.Decoder): + api_version = 3 + id = 'sbus_futaba' + name = 'SBUS (Futaba)' + longname = 'Futaba SBUS (Serial bus)' + desc = 'Serial bus for hobby remote control by Futaba' + license = 'gplv2+' + inputs = ['uart'] + outputs = ['sbus_futaba'] + tags = ['Remote Control'] + options = ( + {'id': 'prop_val_min', 'desc': 'Proportional value lower boundary', 'default': 0}, + {'id': 'prop_val_max', 'desc': 'Proportional value upper boundary', 'default': 2047}, + ) + annotations = ( + ('header', 'Header'), + ('proportional', 'Proportional'), + ('digital', 'Digital'), + ('framelost', 'Frame Lost'), + ('failsafe', 'Failsafe'), + ('footer', 'Footer'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('framing', 'Framing', (Ann.HEADER, Ann.FOOTER, + Ann.FRAME_LOST, Ann.FAILSAFE)), + ('channels', 'Channels', (Ann.PROPORTIONAL, Ann.DIGITAL)), + ('warnings', 'Warnings', (Ann.WARN,)), + ) + + def __init__(self): + self.bits_accum = [] + self.sent_fields = None + self.msg_complete = None + self.failed = None + self.reset() + + def reset(self): + self.bits_accum.clear() + self.sent_fields = 0 + self.msg_complete = False + self.failed = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_py = self.register(srd.OUTPUT_PYTHON) + + def putg(self, ss, es, data): + # Put a graphical annotation. + self.put(ss, es, self.out_ann, data) + + def putpy(self, ss, es, data): + # Pass Python to upper layers. + self.put(ss, es, self.out_py, data) + + def get_ss_es_bits(self, bitcount): + # Get start/end times, and bit values of given length. + # Gets all remaining data when 'bitcount' is None. + if bitcount is None: + bitcount = len(self.bits_accum) + if len(self.bits_accum) < bitcount: + return None, None, None + bits = self.bits_accum[:bitcount] + self.bits_accum = self.bits_accum[bitcount:] + ss, es = bits[0][1], bits[-1][2] + bits = [b[0] for b in bits] + return ss, es, bits + + def flush_accum_bits(self): + # Valid data was queued. See if we got full SBUS fields so far. + # Annotate them early, cease inspection of failed messages. The + # implementation is phrased to reduce the potential for clipboard + # errors: 'upto' is the next supported field count, 'want' is one + # field's bit count. Grab as many as we find in an invocation. + upto = 0 + if self.failed: + return + # Annotate the header byte. Not seeing the expected bit pattern + # emits a warning annotation, but by design won't fail the SBUS + # message. It's considered more useful to present the channels' + # values instead. The warning still raises awareness. + upto += 1 + want = 8 + while self.sent_fields < upto: + if len(self.bits_accum) < want: + return + ss, es, bits = self.get_ss_es_bits(want) + value = bitpack_lsb(bits) + text = ['0x{:02x}'.format(value)] + self.putg(ss, es, [Ann.HEADER, text]) + if value != 0x0f: + text = ['Unexpected header', 'Header'] + self.putg(ss, es, [Ann.WARN, text]) + self.putpy(ss, es, ['HEADER', value]) + self.sent_fields += 1 + # Annotate the proportional channels' data. Check for user + # provided value range violations. Channel numbers are in + # the 1..18 range (1-based). + upto += 16 + want = 11 + while self.sent_fields < upto: + if len(self.bits_accum) < want: + return + ss, es, bits = self.get_ss_es_bits(want) + value = bitpack_lsb(bits) + text = ['{:d}'.format(value)] + self.putg(ss, es, [Ann.PROPORTIONAL, text]) + if value < self.options['prop_val_min']: + text = ['Low proportional value', 'Low value', 'Low'] + self.putg(ss, es, [Ann.WARN, text]) + if value > self.options['prop_val_max']: + text = ['High proportional value', 'High value', 'High'] + self.putg(ss, es, [Ann.WARN, text]) + idx = self.sent_fields - (upto - 16) + ch_nr = 1 + idx + self.putpy(ss, es, ['PROPORTIONAL', (ch_nr, value)]) + self.sent_fields += 1 + # Annotate the digital channels' data. + upto += 2 + want = 1 + while self.sent_fields < upto: + if len(self.bits_accum) < want: + return + ss, es, bits = self.get_ss_es_bits(want) + value = bitpack_lsb(bits) + text = ['{:d}'.format(value)] + self.putg(ss, es, [Ann.DIGITAL, text]) + idx = self.sent_fields - (upto - 2) + ch_nr = 17 + idx + self.putpy(ss, es, ['DIGITAL', (ch_nr, value)]) + self.sent_fields += 1 + # Annotate the flags' state. Index starts from LSB. + flag_names = ['framelost', 'failsafe', 'msb'] + upto += 2 + want = 1 + while self.sent_fields < upto: + if len(self.bits_accum) < want: + return + ss, es, bits = self.get_ss_es_bits(want) + value = bitpack_lsb(bits) + text = ['{:d}'.format(value)] + idx = self.sent_fields - (upto - 2) + cls = Ann.FLAG_LSB + idx + self.putg(ss, es, [cls, text]) + flg_name = flag_names[idx] + self.putpy(ss, es, ['FLAG', (flg_name, value)]) + self.sent_fields += 1 + # Warn when flags' padding (bits [7:4]) is unexpexted. + upto += 1 + want = 4 + while self.sent_fields < upto: + if len(self.bits_accum) < want: + return + ss, es, bits = self.get_ss_es_bits(want) + value = bitpack_lsb(bits) + if value != 0x0: + text = ['Unexpected MSB flags', 'Flags'] + self.putg(ss, es, [Ann.WARN, text]) + flg_name = flag_names[-1] + self.putpy(ss, es, ['FLAG', (flg_name, value)]) + self.sent_fields += 1 + # Annotate the footer byte. Warn when unexpected. + upto += 1 + want = 8 + while self.sent_fields < upto: + if len(self.bits_accum) < want: + return + ss, es, bits = self.get_ss_es_bits(want) + value = bitpack_lsb(bits) + text = ['0x{:02x}'.format(value)] + self.putg(ss, es, [Ann.FOOTER, text]) + if value != 0x00: + text = ['Unexpected footer', 'Footer'] + self.putg(ss, es, [Ann.WARN, text]) + self.putpy(ss, es, ['FOOTER', value]) + self.sent_fields += 1 + # Check for the completion of an SBUS message. Warn when more + # UART data is seen after the message. Defer the warning until + # more bits were collected, flush at next IDLE or BREAK, which + # spans all unprocessed data, and improves perception. + if self.sent_fields >= upto: + self.msg_complete = True + if self.msg_complete and self.bits_accum: + self.failed = ['Excess data bits', 'Excess'] + + def handle_bits(self, ss, es, bits): + # UART data bits were seen. Store them, validity is yet unknown. + self.bits_accum.extend(bits) + + def handle_frame(self, ss, es, value, valid): + # A UART frame became complete. Get its validity. Process its bits. + if not valid: + self.failed = ['Invalid data', 'Invalid'] + self.flush_accum_bits() + + def handle_idle(self, ss, es): + # An IDLE period was seen in the UART level. Flush, reset state. + if self.bits_accum and not self.failed: + self.failed = ['Unprocessed data bits', 'Unprocessed'] + if self.bits_accum and self.failed: + ss, es, _ = self.get_ss_es_bits(None) + self.putg(ss, es, [Ann.WARN, self.failed]) + self.reset() + + def handle_break(self, ss, es): + # A BREAK period was seen in the UART level. Warn, reset state. + break_ss, break_es = ss, es + if not self.failed: + self.failed = ['BREAK condition', 'Break'] + # Re-use logic for "annotated bits warning". + self.handle_idle(None, None) + # Unconditionally annotate BREAK as warning. + text = ['BREAK condition', 'Break'] + self.putg(ss, es, [Ann.WARN, text]) + self.reset() + + def decode(self, ss, es, data): + # Implementor's note: Expects DATA bits to arrive before FRAME + # validity. Either of IDLE or BREAK terminates an SBUS message. + ptype, rxtx, pdata = data + if ptype == 'DATA': + _, bits = pdata + self.handle_bits(ss, es, bits) + elif ptype == 'FRAME': + value, valid = pdata + self.handle_frame(ss, es, value, valid) + elif ptype == 'IDLE': + self.handle_idle(ss, es) + elif ptype == 'BREAK': + self.handle_break(ss, es) From 625e61480f400a92a0fa912e96de979f4bbd6f15 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 12:49:34 +0200 Subject: [PATCH 03/42] Update ADE77xx decoder --- libsigrokdecode4DSL/decoders/ade77xx/__init__.py | 3 +-- libsigrokdecode4DSL/decoders/ade77xx/pd.py | 14 +++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/ade77xx/__init__.py b/libsigrokdecode4DSL/decoders/ade77xx/__init__.py index cbe8689d..7da0419a 100644 --- a/libsigrokdecode4DSL/decoders/ade77xx/__init__.py +++ b/libsigrokdecode4DSL/decoders/ade77xx/__init__.py @@ -14,8 +14,7 @@ ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +## along with this program; if not, see . ## ''' diff --git a/libsigrokdecode4DSL/decoders/ade77xx/pd.py b/libsigrokdecode4DSL/decoders/ade77xx/pd.py index 74219eee..5421cf47 100644 --- a/libsigrokdecode4DSL/decoders/ade77xx/pd.py +++ b/libsigrokdecode4DSL/decoders/ade77xx/pd.py @@ -36,13 +36,13 @@ class Decoder(srd.Decoder): outputs = [] tags = ['Analog/digital', 'IC', 'Sensor'] annotations = ( - ('read', 'Register read commands'), - ('write', 'Register write commands'), - ('warning', 'Warnings'), + ('read', 'Register read'), + ('write', 'Register write'), + ('warning', 'Warning'), ) annotation_rows = ( - ('read', 'Read', (0,)), - ('write', 'Write', (1,)), + ('reads', 'Reads', (0,)), + ('writes', 'Writes', (1,)), ('warnings', 'Warnings', (2,)), ) @@ -124,8 +124,8 @@ def decode(self, ss, es, data): vali = self.miso_bytes[1] if write: - self.putx([1, ['%s: {$}' % rblob[0], '@%02X' % valo]]) + self.putx([1, ['%s: %#x' % (rblob[0], valo)]]) else: - self.putx([0, ['%s: {$}' % rblob[0], '@%02X' % valo]]) + self.putx([0, ['%s: %#x' % (rblob[0], vali)]]) self.reset_data() From 882369cf47f9c0d18ee32590047c4f1f38e3920c Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 12:50:40 +0200 Subject: [PATCH 04/42] Update ADF435x decoder --- libsigrokdecode4DSL/decoders/adf435x/pd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/adf435x/pd.py b/libsigrokdecode4DSL/decoders/adf435x/pd.py index f6c6e6e0..c60ed4e4 100644 --- a/libsigrokdecode4DSL/decoders/adf435x/pd.py +++ b/libsigrokdecode4DSL/decoders/adf435x/pd.py @@ -99,10 +99,10 @@ class Decoder(srd.Decoder): tags = ['Clock/timing', 'IC', 'Wireless/RF'] annotations = ( # Sent from the host to the chip. - ('register', 'Register written to the device'), + ('write', 'Register write'), ) annotation_rows = ( - ('registers', 'Register writes', (ANN_REG,)), + ('writes', 'Register writes', (ANN_REG,)), ) def __init__(self): From f5489661320e19cc1640a3dfb293f55b7a9d594e Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 12:51:10 +0200 Subject: [PATCH 05/42] Update ANDS5020 decoder --- libsigrokdecode4DSL/decoders/adns5020/pd.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/adns5020/pd.py b/libsigrokdecode4DSL/decoders/adns5020/pd.py index e25aa5a6..b03fcaa6 100644 --- a/libsigrokdecode4DSL/decoders/adns5020/pd.py +++ b/libsigrokdecode4DSL/decoders/adns5020/pd.py @@ -49,13 +49,13 @@ class Decoder(srd.Decoder): outputs = [] tags = ['IC', 'PC', 'Sensor'] annotations = ( - ('read', 'Register read commands'), - ('write', 'Register write commands'), - ('warning', 'Warnings'), + ('read', 'Register read'), + ('write', 'Register write'), + ('warning', 'Warning'), ) annotation_rows = ( - ('read', 'Read', (0,)), - ('write', 'Write', (1,)), + ('reads', 'Reads', (0,)), + ('writes', 'Writes', (1,)), ('warnings', 'Warnings', (2,)), ) @@ -108,10 +108,9 @@ def decode(self, ss, es, data): reg_desc = regs.get(reg, 'Reserved %#x' % reg) if reg > 0x63: reg_desc = 'Unknown' - if write: - self.putx([1, ['%s: {$}' % reg_desc, '@%02X' % arg]]) + self.putx([1, ['%s: %#x' % (reg_desc, arg)]]) else: - self.putx([0, ['%s: {$}' % reg_desc, '@%02X' % arg]]) + self.putx([0, ['%s: %d' % (reg_desc, arg)]]) self.mosi_bytes = [] From c654ed0f32c1fdaea84781bc2c3a70039596c789 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 12:51:30 +0200 Subject: [PATCH 06/42] Update AM230x decoder --- libsigrokdecode4DSL/decoders/am230x/pd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/am230x/pd.py b/libsigrokdecode4DSL/decoders/am230x/pd.py index fbc68d39..eedf9428 100644 --- a/libsigrokdecode4DSL/decoders/am230x/pd.py +++ b/libsigrokdecode4DSL/decoders/am230x/pd.py @@ -56,8 +56,8 @@ class Decoder(srd.Decoder): ('bit', 'Bit'), ('end', 'End'), ('byte', 'Byte'), - ('humidity', 'Relative humidity in percent'), - ('temperature', 'Temperature in degrees Celsius'), + ('humidity', 'Relative humidity'), + ('temperature', 'Temperature'), ('checksum', 'Checksum'), ) annotation_rows = ( From 5a5476ec01648d4949c961f64d510496e76fbeac Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 12:51:57 +0200 Subject: [PATCH 07/42] Update ARM ITM decoder --- libsigrokdecode4DSL/decoders/arm_itm/pd.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/arm_itm/pd.py b/libsigrokdecode4DSL/decoders/arm_itm/pd.py index 64149787..8ceeac46 100644 --- a/libsigrokdecode4DSL/decoders/arm_itm/pd.py +++ b/libsigrokdecode4DSL/decoders/arm_itm/pd.py @@ -55,7 +55,7 @@ class Decoder(srd.Decoder): 'default': ''}, ) annotations = ( - ('trace', 'Trace information'), + ('trace', 'Trace info'), ('timestamp', 'Timestamp'), ('software', 'Software message'), ('dwt_event', 'DWT event'), @@ -69,15 +69,15 @@ class Decoder(srd.Decoder): ('function', 'Current function'), ) annotation_rows = ( - ('trace', 'Trace information', (0, 1)), - ('software', 'Software trace', (2,)), - ('dwt_event', 'DWT event', (3,)), - ('dwt_watchpoint', 'DWT watchpoint', (4,)), - ('dwt_exc', 'Exception trace', (5,)), - ('dwt_pc', 'Program counter', (6,)), - ('mode', 'Current mode', (7, 8, 9)), - ('location', 'Current location', (10,)), - ('function', 'Current function', (11,)), + ('traces', 'Trace info', (0, 1)), + ('softwares', 'Software traces', (2,)), + ('dwt_events', 'DWT events', (3,)), + ('dwt_watchpoints', 'DWT watchpoints', (4,)), + ('dwt_excs', 'Exception traces', (5,)), + ('dwt_pcs', 'Program counters', (6,)), + ('modes', 'Current modes', (7, 8, 9)), + ('locations', 'Current locations', (10,)), + ('functions', 'Current functions', (11,)), ) def __init__(self): From 1e944be1ea04edacf743226f9a50c6c1a243d60c Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 12:52:20 +0200 Subject: [PATCH 08/42] Update ADx1345 decoder --- libsigrokdecode4DSL/decoders/adxl345/pd.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libsigrokdecode4DSL/decoders/adxl345/pd.py b/libsigrokdecode4DSL/decoders/adxl345/pd.py index 8ccb6cad..2d53e4c0 100644 --- a/libsigrokdecode4DSL/decoders/adxl345/pd.py +++ b/libsigrokdecode4DSL/decoders/adxl345/pd.py @@ -410,7 +410,8 @@ def decode(self, ss, es, data): self.address <<= 1 self.address >>= 1 self.put(start_sample, addr_bit[2], self.out_ann, - [Ann.REG_ADDRESS, ['ADDRESS: {$}', 'ADDR: {$}', '{$}', '@%02X' % self.address]]) + [Ann.REG_ADDRESS, ['ADDRESS: 0x%02X' % self.address, 'ADDR: 0x%02X' + % self.address, '0x%02X' % self.address]]) self.ss = -1 self.state = St.DATA From c7652158083a4991d3ed085e76bbdfced3fc2515 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 12:52:44 +0200 Subject: [PATCH 09/42] Update ARM ETMv3 decoder --- libsigrokdecode4DSL/decoders/arm_etmv3/pd.py | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/arm_etmv3/pd.py b/libsigrokdecode4DSL/decoders/arm_etmv3/pd.py index 6649b46e..a0bbd94c 100644 --- a/libsigrokdecode4DSL/decoders/arm_etmv3/pd.py +++ b/libsigrokdecode4DSL/decoders/arm_etmv3/pd.py @@ -138,26 +138,26 @@ class Decoder(srd.Decoder): tags = ['Debug/trace'] annotations = ( ('trace', 'Trace info'), - ('branch', 'Branches'), - ('exception', 'Exceptions'), + ('branch', 'Branch'), + ('exception', 'Exception'), ('execution', 'Instruction execution'), ('data', 'Data access'), ('pc', 'Program counter'), - ('instr_e', 'Executed instructions'), - ('instr_n', 'Not executed instructions'), + ('instr_e', 'Executed instruction'), + ('instr_n', 'Not executed instruction'), ('source', 'Source code'), ('location', 'Current location'), ('function', 'Current function'), ) annotation_rows = ( - ('trace', 'Trace info', (0,)), + ('traces', 'Trace info', (0,)), ('flow', 'Code flow', (1, 2, 3,)), - ('data', 'Data access', (4,)), - ('pc', 'Program counter', (5,)), - ('instruction', 'Instructions', (6, 7,)), - ('source', 'Source code', (8,)), - ('location', 'Current location', (9,)), - ('function', 'Current function', (10,)), + ('data-vals', 'Data access', (4,)), + ('pc-vals', 'Program counters', (5,)), + ('instructions', 'Instructions', (6, 7,)), + ('sources', 'Source code', (8,)), + ('locations', 'Current locations', (9,)), + ('functions', 'Current functions', (10,)), ) options = ( {'id': 'objdump', 'desc': 'objdump path', From e244c18df7de6a5479ab48facb53551874edc64f Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 12:53:59 +0200 Subject: [PATCH 10/42] Update ARM TPIU decoder --- libsigrokdecode4DSL/decoders/arm_tpiu/pd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/arm_tpiu/pd.py b/libsigrokdecode4DSL/decoders/arm_tpiu/pd.py index 29b4605f..eac932fe 100644 --- a/libsigrokdecode4DSL/decoders/arm_tpiu/pd.py +++ b/libsigrokdecode4DSL/decoders/arm_tpiu/pd.py @@ -38,8 +38,8 @@ class Decoder(srd.Decoder): ('data', 'Stream data'), ) annotation_rows = ( - ('stream', 'Current stream', (0,)), - ('data', 'Stream data', (1,)), + ('streams', 'Current streams', (0,)), + ('data-vals', 'Stream data', (1,)), ) def __init__(self): From c2ed14e7dbe2107bae0fe7962660c6c0efb619ca Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 12:56:55 +0200 Subject: [PATCH 11/42] Update AVR ISP decoder --- libsigrokdecode4DSL/decoders/avr_isp/pd.py | 104 ++++++++++++++++----- 1 file changed, 83 insertions(+), 21 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/avr_isp/pd.py b/libsigrokdecode4DSL/decoders/avr_isp/pd.py index a0719b73..e3af4d6f 100644 --- a/libsigrokdecode4DSL/decoders/avr_isp/pd.py +++ b/libsigrokdecode4DSL/decoders/avr_isp/pd.py @@ -20,6 +20,10 @@ import sigrokdecode as srd from .parts import * +class Ann: + PE, RSB0, RSB1, RSB2, CE, RFB, RHFB, REFB, \ + RLB, REEM, RP, LPMP, WP, WARN, DEV, = range(15) + VENDOR_CODE_ATMEL = 0x1e class Decoder(srd.Decoder): @@ -41,14 +45,20 @@ class Decoder(srd.Decoder): ('rfb', 'Read fuse bits'), ('rhfb', 'Read high fuse bits'), ('refb', 'Read extended fuse bits'), - ('warnings', 'Warnings'), + ('rlb', 'Read lock bits'), + ('reem', 'Read EEPROM memory'), + ('rp', 'Read program memory'), + ('lpmp' , 'Load program memory page'), + ('wp', 'Write program memory'), + ('warning', 'Warning'), ('dev', 'Device'), ) annotation_rows = ( - ('bits', 'Bits', ()), - ('commands', 'Commands', tuple(range(7 + 1))), - ('warnings', 'Warnings', (8,)), - ('dev', 'Device', (9,)), + ('commands', 'Commands', (Ann.PE, Ann.RSB0, Ann.RSB1, Ann.RSB2, + Ann.CE, Ann.RFB, Ann.RHFB, Ann.REFB, + Ann.RLB, Ann.REEM, Ann.RP, Ann.LPMP, Ann.WP,)), + ('warnings', 'Warnings', (Ann.WARN,)), + ('devs', 'Devices', (Ann.DEV,)), ) def __init__(self): @@ -70,17 +80,17 @@ def putx(self, data): def handle_cmd_programming_enable(self, cmd, ret): # Programming enable. # Note: The chip doesn't send any ACK for 'Programming enable'. - self.putx([0, ['Programming enable']]) + self.putx([Ann.PE, ['Programming enable']]) # Sanity check on reply. if ret[1:4] != [0xac, 0x53, cmd[2]]: - self.putx([8, ['Warning: Unexpected bytes in reply!']]) + self.putx([Ann.WARN, ['Warning: Unexpected bytes in reply!']]) def handle_cmd_read_signature_byte_0x00(self, cmd, ret): # Signature byte 0x00: vendor code. self.vendor_code = ret[3] v = vendor_code[self.vendor_code] - self.putx([1, ['Vendor code: 0x%02x (%s)' % (ret[3], v)]]) + self.putx([Ann.RSB0, ['Vendor code: 0x%02x (%s)' % (ret[3], v)]]) # Store for later. self.xx = cmd[1] # Same as ret[2]. @@ -89,16 +99,16 @@ def handle_cmd_read_signature_byte_0x00(self, cmd, ret): # Sanity check on reply. if ret[1] != 0x30 or ret[2] != cmd[1]: - self.putx([8, ['Warning: Unexpected bytes in reply!']]) + self.putx([Ann.WARN, ['Warning: Unexpected bytes in reply!']]) # Sanity check for the vendor code. if self.vendor_code != VENDOR_CODE_ATMEL: - self.putx([8, ['Warning: Vendor code was not 0x1e (Atmel)!']]) + self.putx([Ann.WARN, ['Warning: Vendor code was not 0x1e (Atmel)!']]) def handle_cmd_read_signature_byte_0x01(self, cmd, ret): # Signature byte 0x01: part family and memory size. self.part_fam_flash_size = ret[3] - self.putx([2, ['Part family / memory size: 0x%02x' % ret[3]]]) + self.putx([Ann.RSB1, ['Part family / memory size: 0x%02x' % ret[3]]]) # Store for later. self.mm = cmd[3] @@ -106,20 +116,20 @@ def handle_cmd_read_signature_byte_0x01(self, cmd, ret): # Sanity check on reply. if ret[1] != 0x30 or ret[2] != cmd[1] or ret[0] != self.yy: - self.putx([8, ['Warning: Unexpected bytes in reply!']]) + self.putx([Ann.WARN, ['Warning: Unexpected bytes in reply!']]) def handle_cmd_read_signature_byte_0x02(self, cmd, ret): # Signature byte 0x02: part number. self.part_number = ret[3] - self.putx([3, ['Part number: 0x%02x' % ret[3]]]) + self.putx([Ann.RSB2, ['Part number: 0x%02x' % ret[3]]]) p = part[(self.part_fam_flash_size, self.part_number)] - data = [9, ['Device: Atmel %s' % p]] + data = [Ann.DEV, ['Device: Atmel %s' % p]] self.put(self.ss_device, self.es_cmd, self.out_ann, data) # Sanity check on reply. if ret[1] != 0x30 or ret[2] != self.xx or ret[0] != self.mm: - self.putx([8, ['Warning: Unexpected bytes in reply!']]) + self.putx([Ann.WARN, ['Warning: Unexpected bytes in reply!']]) self.xx, self.yy, self.zz, self.mm = 0, 0, 0, 0 @@ -127,36 +137,78 @@ def handle_cmd_chip_erase(self, cmd, ret): # Chip erase (erases both flash an EEPROM). # Upon successful chip erase, the lock bits will also be erased. # The only way to end a Chip Erase cycle is to release RESET#. - self.putx([4, ['Chip erase']]) + self.putx([Ann.CE, ['Chip erase']]) # TODO: Check/handle RESET#. # Sanity check on reply. bit = (ret[2] & (1 << 7)) >> 7 if ret[1] != 0xac or bit != 1 or ret[3] != cmd[2]: - self.putx([8, ['Warning: Unexpected bytes in reply!']]) + self.putx([Ann.WARN, ['Warning: Unexpected bytes in reply!']]) def handle_cmd_read_fuse_bits(self, cmd, ret): # Read fuse bits. - self.putx([5, ['Read fuse bits: 0x%02x' % ret[3]]]) + self.putx([Ann.RFB, ['Read fuse bits: 0x%02x' % ret[3]]]) # TODO: Decode fuse bits. # TODO: Sanity check on reply. def handle_cmd_read_fuse_high_bits(self, cmd, ret): # Read fuse high bits. - self.putx([6, ['Read fuse high bits: 0x%02x' % ret[3]]]) + self.putx([Ann.RHFB, ['Read fuse high bits: 0x%02x' % ret[3]]]) # TODO: Decode fuse bits. # TODO: Sanity check on reply. def handle_cmd_read_extended_fuse_bits(self, cmd, ret): # Read extended fuse bits. - self.putx([7, ['Read extended fuse bits: 0x%02x' % ret[3]]]) + self.putx([Ann.REFB, ['Read extended fuse bits: 0x%02x' % ret[3]]]) # TODO: Decode fuse bits. # TODO: Sanity check on reply. + def handle_cmd_read_lock_bits(self, cmd, ret): + # Read lock bits + self.putx([Ann.RLB, ['Read lock bits: 0x%02x' % ret[3]]]) + + def handle_cmd_read_eeprom_memory(self, cmd, ret): + # Read EEPROM Memory + _addr = ((cmd[1] & 1) << 8) + cmd[2] + self.putx([Ann.REEM, ['Read EEPROM Memory: [0x%03x]: 0x%02x' % (_addr, ret[3])]]) + + def handle_cmd_read_program_memory(self, cmd, ret): + # Read Program Memory + _HL = 'Low' + _H = 'L' + if cmd[0] & 0x08: + _HL = 'High' + _H = 'H' + _addr = ((cmd[1] & 0x0f) << 8) + cmd[2] + self.putx([Ann.RP, [ + 'Read program memory %s: [0x%03x]: 0x%02x' % (_HL, _addr, ret[3]), + '[%03x%s]:%02x' % (_addr, _H, ret[3]), + '%02x' % ret[3] + ]]) + + def handle_cmd_load_program_memory_page(self, cmd, ret): + # Load Program Memory Page + _HL = 'Low' + _H = 'L' + if cmd[0] & 0x08: + _HL = 'High' + _H = 'H' + _addr = cmd[2] & 0x1F + self.putx([Ann.LPMP, [ + 'Load program memory page %s: [0x%03x]: 0x%02x' % (_HL, _addr, cmd[3]), + '[%03x%s]=%02x' % (_addr, _H, cmd[3]), + '%02x' % cmd[3] + ]]) + + def handle_cmd_write_program_memory_page(self, cmd, ret): + # Write Program Memory Page + _addr = ((cmd[1] & 0x0F) << 3) + (cmd[2] << 5) + self.putx([Ann.WP, ['Write program memory page: 0x%02x' % _addr]]) + def handle_command(self, cmd, ret): if cmd[:2] == [0xac, 0x53]: self.handle_cmd_programming_enable(cmd, ret) @@ -174,10 +226,20 @@ def handle_command(self, cmd, ret): self.handle_cmd_read_signature_byte_0x01(cmd, ret) elif cmd[0] == 0x30 and cmd[2] == 0x02: self.handle_cmd_read_signature_byte_0x02(cmd, ret) + elif cmd[:2] == [0x58, 0x00]: + self.handle_cmd_read_lock_bits(cmd,ret) + elif cmd[0] == 0xa0 and (cmd[1] & (3 << 6)) == (0 << 6): + self.handle_cmd_read_eeprom_memory(cmd, ret) + elif (cmd[0] == 0x20 or cmd[0] == 0x28) and ((cmd[1] & 0xf0) == 0x00): + self.handle_cmd_read_program_memory(cmd, ret) + elif (cmd[0] == 0x40 or cmd[0] == 0x48) and ((cmd[1] & 0xf0) == 0x00): + self.handle_cmd_load_program_memory_page(cmd, ret) + elif (cmd[0] == 0x4C and ((cmd[1] & 0xf0) == 0x00)): + self.handle_cmd_write_program_memory_page(cmd, ret) else: c = '%02x %02x %02x %02x' % tuple(cmd) r = '%02x %02x %02x %02x' % tuple(ret) - self.putx([0, ['Unknown command: %s (reply: %s)!' % (c, r)]]) + self.putx([Ann.WARN, ['Unknown command: %s (reply: %s)!' % (c, r)]]) def decode(self, ss, es, data): ptype, mosi, miso = data From 9fd93d57d3371bce4a946bced25db8dc3bda5f37 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 12:57:55 +0200 Subject: [PATCH 12/42] Update Caliper decoder --- libsigrokdecode4DSL/decoders/caliper/pd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsigrokdecode4DSL/decoders/caliper/pd.py b/libsigrokdecode4DSL/decoders/caliper/pd.py index b9e5851f..20a2a555 100644 --- a/libsigrokdecode4DSL/decoders/caliper/pd.py +++ b/libsigrokdecode4DSL/decoders/caliper/pd.py @@ -91,7 +91,7 @@ def decode(self): # after inactivity for a user specified period. Present the # number of unprocessed bits to the user for diagnostics. clk, data = self.wait(wait_cond) - if timeout_ms and not self.matched & 0b1 == 0b1: + if timeout_ms and not self.matched[0]: if self.number_bits or self.flags_bits: count = len(self.number_bits) + len(self.flags_bits) self.putg(self.ss, self.samplenum, 1, [ From 451790eb34c707ce3b2b24e8fb0b8431910013cb Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:02:44 +0200 Subject: [PATCH 13/42] Update CAN decoder (now supports CAN-FD) --- libsigrokdecode4DSL/decoders/can/__init__.py | 2 + libsigrokdecode4DSL/decoders/can/pd.py | 233 ++++++++++++++----- 2 files changed, 171 insertions(+), 64 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/can/__init__.py b/libsigrokdecode4DSL/decoders/can/__init__.py index 47f571d6..888bb819 100644 --- a/libsigrokdecode4DSL/decoders/can/__init__.py +++ b/libsigrokdecode4DSL/decoders/can/__init__.py @@ -24,6 +24,8 @@ This decoder assumes that a single CAN_RX line is sampled (e.g. on the digital output side of a CAN transceiver IC such as the Microchip MCP-2515DM-BM). + +It also has support for CAN-FD. ''' from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/can/pd.py b/libsigrokdecode4DSL/decoders/can/pd.py index ceb79b74..46d91b16 100644 --- a/libsigrokdecode4DSL/decoders/can/pd.py +++ b/libsigrokdecode4DSL/decoders/can/pd.py @@ -3,6 +3,7 @@ ## ## Copyright (C) 2012-2013 Uwe Hermann ## Copyright (C) 2019 DreamSourceLab +## Copyright (C) 2019 Stephan Thiele ## ## 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 @@ -18,11 +19,15 @@ ## along with this program; if not, see . ## +from common.srdhelper import bitpack_msb import sigrokdecode as srd class SamplerateError(Exception): pass +def dlc2len(dlc): + return [0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64][dlc] + class Decoder(srd.Decoder): api_version = 3 id = 'can' @@ -31,17 +36,18 @@ class Decoder(srd.Decoder): desc = 'Field bus protocol for distributed realtime control.' license = 'gplv2+' inputs = ['logic'] - outputs = [] + outputs = ['can'] tags = ['Automotive'] channels = ( - {'id': 'can_rx', 'name': 'CAN', 'desc': 'CAN bus line'}, + {'id': 'can_rx', 'name': 'CAN RX', 'desc': 'CAN bus line'}, ) options = ( - {'id': 'bitrate', 'desc': 'Bitrate (bits/s)', 'default': 1000000}, + {'id': 'nominal_bitrate', 'desc': 'Nominal bitrate (bits/s)', 'default': 1000000}, + {'id': 'fast_bitrate', 'desc': 'Fast bitrate (bits/s)', 'default': 2000000}, {'id': 'sample_point', 'desc': 'Sample point (%)', 'default': 70.0}, ) annotations = ( - ('data', 'CAN payload data'), + ('data', 'Payload data'), ('sof', 'Start of frame'), ('eof', 'End of frame'), ('id', 'Identifier'), @@ -57,7 +63,7 @@ class Decoder(srd.Decoder): ('ack-slot', 'ACK slot'), ('ack-delimiter', 'ACK delimiter'), ('stuff-bit', 'Stuff bit'), - ('warnings', 'Human-readable warnings'), + ('warning', 'Warning'), ('bit', 'Bit'), ) annotation_rows = ( @@ -75,11 +81,22 @@ def reset(self): def start(self): self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_python = self.register(srd.OUTPUT_PYTHON) + + def set_bit_rate(self, bitrate): + self.bit_width = float(self.samplerate) / float(bitrate) + self.sample_point = (self.bit_width / 100.0) * self.options['sample_point'] + + def set_nominal_bitrate(self): + self.set_bit_rate(self.options['nominal_bitrate']) + + def set_fast_bitrate(self): + self.set_bit_rate(self.options['fast_bitrate']) def metadata(self, key, value): if key == srd.SRD_CONF_SAMPLERATE: self.samplerate = value - self.bit_width = float(self.samplerate) / float(self.options['bitrate']) + self.bit_width = float(self.samplerate) / float(self.options['nominal_bitrate']) self.sample_point = (self.bit_width / 100.0) * self.options['sample_point'] # Generic helper for CAN bit annotations. @@ -95,10 +112,17 @@ def putx(self, data): def put12(self, data): self.putg(self.ss_bit12, self.ss_bit12, data) + # Single-CAN-bit annotation using the samplenum of CAN bit 32. + def put32(self, data): + self.putg(self.ss_bit32, self.ss_bit32, data) + # Multi-CAN-bit annotation from self.ss_block to current samplenum. def putb(self, data): self.putg(self.ss_block, self.samplenum, data) + def putpy(self, data): + self.put(self.ss_packet, self.es_packet, self.out_python, data) + def reset_variables(self): self.state = 'IDLE' self.sof = self.frame_type = self.dlc = None @@ -108,7 +132,12 @@ def reset_variables(self): self.last_databit = 999 # Positive value that bitnum+x will never match self.ss_block = None self.ss_bit12 = None + self.ss_bit32 = None self.ss_databytebits = [] + self.frame_bytes = [] + self.rtr_type = None + self.fd = False + self.rtr = None # Poor man's clock synchronization. Use signal edges which change to # dominant state in rather simple ways. This naive approach is neither @@ -119,16 +148,12 @@ def dom_edge_seen(self, force = False): self.dom_edge_snum = self.samplenum self.dom_edge_bcount = self.curbit - def bit_sampled(self): - # EMPTY - pass - # Determine the position of the next desired bit's sample point. def get_sample_point(self, bitnum): samplenum = self.dom_edge_snum - samplenum += int(self.bit_width * (bitnum - self.dom_edge_bcount)) - samplenum += int(self.sample_point) - return samplenum + samplenum += self.bit_width * (bitnum - self.dom_edge_bcount) + samplenum += self.sample_point + return int(samplenum) def is_stuff_bit(self): # CAN uses NRZ encoding and bit stuffing. @@ -161,45 +186,67 @@ def decode_frame_end(self, can_rx, bitnum): # Remember start of CRC sequence (see below). if bitnum == (self.last_databit + 1): self.ss_block = self.samplenum + if self.fd: + if dlc2len(self.dlc) < 16: + self.crc_len = 27 # 17 + SBC + stuff bits + else: + self.crc_len = 32 # 21 + SBC + stuff bits + else: + self.crc_len = 15 + + # CRC sequence (15 bits, 17 bits or 21 bits) + elif bitnum == (self.last_databit + self.crc_len): + if self.fd: + if dlc2len(self.dlc) < 16: + crc_type = "CRC-17" + else: + crc_type = "CRC-21" + else: + crc_type = "CRC-15" - # CRC sequence (15 bits) - elif bitnum == (self.last_databit + 15): x = self.last_databit + 1 - crc_bits = self.bits[x:x + 15 + 1] - self.crc = int(''.join(str(d) for d in crc_bits), 2) - self.putb([11, ['CRC sequence: 0x%04x' % self.crc, - 'CRC: 0x%04x' % self.crc, 'CRC']]) + crc_bits = self.bits[x:x + self.crc_len + 1] + self.crc = bitpack_msb(crc_bits) + self.putb([11, ['%s sequence: 0x%04x' % (crc_type, self.crc), + '%s: 0x%04x' % (crc_type, self.crc), '%s' % crc_type]]) if not self.is_valid_crc(crc_bits): self.putb([16, ['CRC is invalid']]) # CRC delimiter bit (recessive) - elif bitnum == (self.last_databit + 16): + elif bitnum == (self.last_databit + self.crc_len + 1): self.putx([12, ['CRC delimiter: %d' % can_rx, 'CRC d: %d' % can_rx, 'CRC d']]) if can_rx != 1: self.putx([16, ['CRC delimiter must be a recessive bit']]) + if self.fd: + self.set_nominal_bitrate() + # ACK slot bit (dominant: ACK, recessive: NACK) - elif bitnum == (self.last_databit + 17): + elif bitnum == (self.last_databit + self.crc_len + 2): ack = 'ACK' if can_rx == 0 else 'NACK' self.putx([13, ['ACK slot: %s' % ack, 'ACK s: %s' % ack, 'ACK s']]) # ACK delimiter bit (recessive) - elif bitnum == (self.last_databit + 18): + elif bitnum == (self.last_databit + self.crc_len + 3): self.putx([14, ['ACK delimiter: %d' % can_rx, 'ACK d: %d' % can_rx, 'ACK d']]) if can_rx != 1: self.putx([16, ['ACK delimiter must be a recessive bit']]) # Remember start of EOF (see below). - elif bitnum == (self.last_databit + 19): + elif bitnum == (self.last_databit + self.crc_len + 4): self.ss_block = self.samplenum # End of frame (EOF), 7 recessive bits - elif bitnum == (self.last_databit + 25): + elif bitnum == (self.last_databit + self.crc_len + 10): self.putb([2, ['End of frame', 'EOF', 'E']]) if self.rawbits[-7:] != [1, 1, 1, 1, 1, 1, 1]: self.putb([16, ['End of frame (EOF) must be 7 recessive bits']]) + self.es_packet = self.samplenum + py_data = tuple([self.frame_type, self.fullid, self.rtr_type, + self.dlc, self.frame_bytes]) + self.putpy(py_data) self.reset_variables() return True @@ -208,43 +255,66 @@ def decode_frame_end(self, can_rx, bitnum): # Returns True if the frame ended (EOF), False otherwise. def decode_standard_frame(self, can_rx, bitnum): - # Bit 14: RB0 (reserved bit) - # Has to be sent dominant, but receivers should accept recessive too. + # Bit 14: FDF (Flexible data format) + # Has to be sent dominant when FD frame, has to be sent recessive + # when classic CAN frame. if bitnum == 14: - self.putx([7, ['Reserved bit 0: %d' % can_rx, - 'RB0: %d' % can_rx, 'RB0']]) + self.fd = True if can_rx else False + if self.fd: + self.putx([7, ['Flexible data format: %d' % can_rx, + 'FDF: %d' % can_rx, 'FDF']]) + else: + self.putx([7, ['Reserved bit 0: %d' % can_rx, + 'RB0: %d' % can_rx, 'RB0']]) + + if self.fd: + # Bit 12: Substitute remote request (SRR) bit + self.put12([8, ['Substitute remote request', 'SRR']]) + self.dlc_start = 18 + else: + # Bit 12: Remote transmission request (RTR) bit + # Data frame: dominant, remote frame: recessive + # Remote frames do not contain a data field. + rtr = 'remote' if self.bits[12] == 1 else 'data' + self.put12([8, ['Remote transmission request: %s frame' % rtr, + 'RTR: %s frame' % rtr, 'RTR']]) + self.rtr_type = rtr + self.dlc_start = 15 - # Bit 12: Remote transmission request (RTR) bit - # Data frame: dominant, remote frame: recessive - # Remote frames do not contain a data field. - rtr = 'remote' if self.bits[12] == 1 else 'data' - self.put12([8, ['Remote transmission request: %s frame' % rtr, - 'RTR: %s frame' % rtr, 'RTR']]) + if bitnum == 15 and self.fd: + self.putx([7, ['Reserved: %d' % can_rx, 'R0: %d' % can_rx, 'R0']]) + + if bitnum == 16 and self.fd: + self.putx([7, ['Bit rate switch: %d' % can_rx, 'BRS: %d' % can_rx, 'BRS']]) + + if bitnum == 17 and self.fd: + self.putx([7, ['Error state indicator: %d' % can_rx, 'ESI: %d' % can_rx, 'ESI']]) # Remember start of DLC (see below). - elif bitnum == 15: + elif bitnum == self.dlc_start: self.ss_block = self.samplenum # Bits 15-18: Data length code (DLC), in number of bytes (0-8). - elif bitnum == 18: - self.dlc = int(''.join(str(d) for d in self.bits[15:18 + 1]), 2) + elif bitnum == self.dlc_start + 3: + self.dlc = bitpack_msb(self.bits[self.dlc_start:self.dlc_start + 4]) self.putb([10, ['Data length code: %d' % self.dlc, 'DLC: %d' % self.dlc, 'DLC']]) - self.last_databit = 18 + (self.dlc * 8) - if self.dlc > 8: + self.last_databit = self.dlc_start + 3 + (dlc2len(self.dlc) * 8) + if self.dlc > 8 and not self.fd: self.putb([16, ['Data length code (DLC) > 8 is not allowed']]) # Remember all databyte bits, except the very last one. - elif bitnum in range(19, self.last_databit): + elif bitnum in range(self.dlc_start + 4, self.last_databit): self.ss_databytebits.append(self.samplenum) # Bits 19-X: Data field (0-8 bytes, depending on DLC) # The bits within a data byte are transferred MSB-first. elif bitnum == self.last_databit: self.ss_databytebits.append(self.samplenum) # Last databyte bit. - for i in range(self.dlc): - x = 18 + (8 * i) + 1 - b = int(''.join(str(d) for d in self.bits[x:x + 8]), 2) + for i in range(dlc2len(self.dlc)): + x = self.dlc_start + 4 + (8 * i) + b = bitpack_msb(self.bits[x:x + 8]) + self.frame_bytes.append(b) ss = self.ss_databytebits[i * 8] es = self.ss_databytebits[((i + 1) * 8) - 1] self.putg(ss, es, [0, ['Data byte %d: 0x%02x' % (i, b), @@ -262,15 +332,17 @@ def decode_extended_frame(self, can_rx, bitnum): # Remember start of EID (see below). if bitnum == 14: self.ss_block = self.samplenum + self.fd = False + self.dlc_start = 35 # Bits 14-31: Extended identifier (EID[17..0]) elif bitnum == 31: - self.eid = int(''.join(str(d) for d in self.bits[14:]), 2) + self.eid = bitpack_msb(self.bits[14:]) s = '%d (0x%x)' % (self.eid, self.eid) self.putb([4, ['Extended Identifier: %s' % s, 'Extended ID: %s' % s, 'Extended ID', 'EID']]) - self.fullid = self.id << 18 | self.eid + self.fullid = self.ident << 18 | self.eid s = '%d (0x%x)' % (self.fullid, self.fullid) self.putb([5, ['Full Identifier: %s' % s, 'Full ID: %s' % s, 'Full ID', 'FID']]) @@ -282,43 +354,67 @@ def decode_extended_frame(self, can_rx, bitnum): # Bit 32: Remote transmission request (RTR) bit # Data frame: dominant, remote frame: recessive # Remote frames do not contain a data field. + + # Remember start of RTR (see below). if bitnum == 32: - rtr = 'remote' if can_rx == 1 else 'data' - self.putx([8, ['Remote transmission request: %s frame' % rtr, - 'RTR: %s frame' % rtr, 'RTR']]) + self.ss_bit32 = self.samplenum + self.rtr = can_rx + + if not self.fd: + rtr = 'remote' if can_rx == 1 else 'data' + self.putx([8, ['Remote transmission request: %s frame' % rtr, + 'RTR: %s frame' % rtr, 'RTR']]) + self.rtr_type = rtr # Bit 33: RB1 (reserved bit) elif bitnum == 33: - self.putx([7, ['Reserved bit 1: %d' % can_rx, - 'RB1: %d' % can_rx, 'RB1']]) + self.fd = True if can_rx else False + if self.fd: + self.dlc_start = 37 + self.putx([7, ['Flexible data format: %d' % can_rx, + 'FDF: %d' % can_rx, 'FDF']]) + self.put32([7, ['Reserved bit 1: %d' % self.rtr, + 'RB1: %d' % self.rtr, 'RB1']]) + else: + self.putx([7, ['Reserved bit 1: %d' % can_rx, + 'RB1: %d' % can_rx, 'RB1']]) # Bit 34: RB0 (reserved bit) elif bitnum == 34: self.putx([7, ['Reserved bit 0: %d' % can_rx, 'RB0: %d' % can_rx, 'RB0']]) + elif bitnum == 35 and self.fd: + self.putx([7, ['Bit rate switch: %d' % can_rx, + 'BRS: %d' % can_rx, 'BRS']]) + + elif bitnum == 36 and self.fd: + self.putx([7, ['Error state indicator: %d' % can_rx, + 'ESI: %d' % can_rx, 'ESI']]) + # Remember start of DLC (see below). - elif bitnum == 35: + elif bitnum == self.dlc_start: self.ss_block = self.samplenum # Bits 35-38: Data length code (DLC), in number of bytes (0-8). - elif bitnum == 38: - self.dlc = int(''.join(str(d) for d in self.bits[35:38 + 1]), 2) + elif bitnum == self.dlc_start + 3: + self.dlc = bitpack_msb(self.bits[self.dlc_start:self.dlc_start + 4]) self.putb([10, ['Data length code: %d' % self.dlc, 'DLC: %d' % self.dlc, 'DLC']]) - self.last_databit = 38 + (self.dlc * 8) + self.last_databit = self.dlc_start + 3 + (dlc2len(self.dlc) * 8) # Remember all databyte bits, except the very last one. - elif bitnum in range(39, self.last_databit): + elif bitnum in range(self.dlc_start + 4, self.last_databit): self.ss_databytebits.append(self.samplenum) # Bits 39-X: Data field (0-8 bytes, depending on DLC) # The bits within a data byte are transferred MSB-first. elif bitnum == self.last_databit: self.ss_databytebits.append(self.samplenum) # Last databyte bit. - for i in range(self.dlc): - x = 38 + (8 * i) + 1 - b = int(''.join(str(d) for d in self.bits[x:x + 8]), 2) + for i in range(dlc2len(self.dlc)): + x = self.dlc_start + 4 + (8 * i) + b = bitpack_msb(self.bits[x:x + 8]) + self.frame_bytes.append(b) ss = self.ss_databytebits[i * 8] es = self.ss_databytebits[((i + 1) * 8) - 1] self.putg(ss, es, [0, ['Data byte %d: 0x%02x' % (i, b), @@ -337,6 +433,12 @@ def handle_bit(self, can_rx): # Get the index of the current CAN frame bit (without stuff bits). bitnum = len(self.bits) - 1 + if self.fd and can_rx: + if bitnum == 16 and self.frame_type == 'standard' \ + or bitnum == 35 and self.frame_type == 'extended': + self.dom_edge_seen(force=True) + self.set_fast_bitrate() + # If this is a stuff bit, remove it from self.bits and ignore it. if self.is_stuff_bit(): self.putx([15, [str(can_rx)]]) @@ -347,6 +449,7 @@ def handle_bit(self, can_rx): # Bit 0: Start of frame (SOF) bit if bitnum == 0: + self.ss_packet = self.samplenum self.putx([1, ['Start of frame', 'SOF', 'S']]) if can_rx != 0: self.putx([16, ['Start of frame (SOF) must be a dominant bit']]) @@ -358,10 +461,13 @@ def handle_bit(self, can_rx): # Bits 1-11: Identifier (ID[10..0]) # The bits ID[10..4] must NOT be all recessive. elif bitnum == 11: - self.id = int(''.join(str(d) for d in self.bits[1:]), 2) - s = '%d (0x%x)' % (self.id, self.id), + # BEWARE! Don't clobber the decoder's .id field which is + # part of its boiler plate! + self.ident = bitpack_msb(self.bits[1:]) + self.fullid = self.ident + s = '%d (0x%x)' % (self.ident, self.ident), self.putb([3, ['Identifier: %s' % s, 'ID: %s' % s, 'ID']]) - if (self.id & 0x7f0) == 0x7f0: + if (self.ident & 0x7f0) == 0x7f0: self.putb([16, ['Identifier bits 10..4 must not be all recessive']]) # RTR or SRR bit, depending on frame type (gets handled later). @@ -408,8 +514,7 @@ def decode(self): # Wait until we're in the correct bit/sampling position. pos = self.get_sample_point(self.curbit) (can_rx,) = self.wait([{'skip': pos - self.samplenum}, {0: 'f'}]) - if (self.matched & (0b1 << 1)): + if self.matched[1]: self.dom_edge_seen() - if (self.matched & (0b1 << 0)): + if self.matched[0]: self.handle_bit(can_rx) - self.bit_sampled() From 691401cdcb4bb3ee7089f18459a723e40a177a2e Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:05:42 +0200 Subject: [PATCH 14/42] Update CC1101 decoder --- libsigrokdecode4DSL/decoders/cc1101/pd.py | 57 ++++++++++++----------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/cc1101/pd.py b/libsigrokdecode4DSL/decoders/cc1101/pd.py index a2038907..f62f18ec 100644 --- a/libsigrokdecode4DSL/decoders/cc1101/pd.py +++ b/libsigrokdecode4DSL/decoders/cc1101/pd.py @@ -19,17 +19,15 @@ import sigrokdecode as srd from collections import namedtuple +from common.srdhelper import SrdIntEnum from .lists import * -ANN_STROBE, ANN_SINGLE_READ, ANN_SINGLE_WRITE, ANN_BURST_READ, \ - ANN_BURST_WRITE, ANN_STATUS_READ, ANN_STATUS, ANN_WARN = range(8) +Ann = SrdIntEnum.from_str('Ann', 'STROBE SINGLE_READ SINGLE_WRITE BURST_READ \ + BURST_WRITE STATUS_READ STATUS WARN') Pos = namedtuple('Pos', ['ss', 'es']) Data = namedtuple('Data', ['mosi', 'miso']) -class ChannelError(Exception): - pass - class Decoder(srd.Decoder): api_version = 3 id = 'cc1101' @@ -47,15 +45,14 @@ class Decoder(srd.Decoder): ('burst_read', 'Burst register read'), ('burst_write', 'Burst register write'), ('status_read', 'Status read'), - ('status', 'Status register'), + ('status_reg', 'Status register'), ('warning', 'Warning'), ) annotation_rows = ( - ('cmd', 'Commands', (ANN_STROBE,)), - ('data', 'Data', (ANN_SINGLE_READ, ANN_SINGLE_WRITE, ANN_BURST_READ, - ANN_BURST_WRITE, ANN_STATUS_READ)), - ('status', 'Status register', (ANN_STATUS,)), - ('warnings', 'Warnings', (ANN_WARN,)), + ('cmds', 'Commands', (Ann.STROBE,)), + ('data', 'Data', (Ann.prefixes('SINGLE_ BURST_ STATUS_'))), + ('status', 'Status register', (Ann.STATUS,)), + ('warnings', 'Warnings', (Ann.WARN,)), ) def __init__(self): @@ -71,10 +68,15 @@ def start(self): def warn(self, pos, msg): '''Put a warning message 'msg' at 'pos'.''' - self.put(pos.ss, pos.es, self.out_ann, [ANN_WARN, [msg]]) + self.put(pos.ss, pos.es, self.out_ann, [Ann.WARN, [msg]]) + + def putp(self, pos, ann, msg): + '''Put an annotation message 'msg' at 'pos'.''' + self.put(pos.ss, pos.es, self.out_ann, [ann, [msg]]) - def put_ann(self, pos, ann, data): - self.put(pos.ss, pos.es, self.out_ann, [ann, data]) + def putp2(self, pos, ann, msg1, msg2): + '''Put an annotation message 'msg' at 'pos'.''' + self.put(pos.ss, pos.es, self.out_ann, [ann, [msg1, msg2]]) def next(self): '''Resets the decoder after a complete command was decoded.''' @@ -112,7 +114,7 @@ def decode_command(self, pos, b): self.cmd, self.dat, self.min, self.max = c if self.cmd == 'Strobe': - self.put_ann(pos, ANN_STROBE, [self.format_command()]) + self.putp(pos, Ann.STROBE, self.format_command()) else: # Don't output anything now, the command is merged with # the data bytes following it. @@ -177,7 +179,7 @@ def decode_reg(self, pos, ann, regid, data): else: name = regid - if regid == 'STATUS' and ann == ANN_STATUS: + if regid == 'STATUS' and ann == Ann.STATUS: label = 'Status' self.decode_status_reg(pos, ann, data, label) else: @@ -206,10 +208,9 @@ def decode_status_reg(self, pos, ann, data, label): else: longtext_fifo = '{} bytes free in TX FIFO'.format(fifo_bytes) - text = '{} = '.format(label) + '{$}' + text = '{} = {:02X}'.format(label, status) longtext = ''.join([text, '; ', longtext_chiprdy, longtext_state, longtext_fifo]) - #self.printlog(longtext + ' ,' + text + '\n') - self.put_ann(pos, ann, [longtext, text, '@%02X' % status]) + self.putp2(pos, ann, longtext, text) def decode_mb_data(self, pos, ann, data, label): '''Decodes the data bytes 'data' of a multibyte command at position @@ -219,24 +220,24 @@ def escape(b): return '{:02X}'.format(b) data = ' '.join([escape(b) for b in data]) - text = '{} = '.format(label) + '{$}' - self.put_ann(pos, ann, [text, '@' + data]) + text = '{} = {}'.format(label, data) + self.putp(pos, ann, text) def finish_command(self, pos): '''Decodes the remaining data bytes at position 'pos'.''' if self.cmd == 'Write': - self.decode_reg(pos, ANN_SINGLE_WRITE, self.dat, self.mosi_bytes()) + self.decode_reg(pos, Ann.SINGLE_WRITE, self.dat, self.mosi_bytes()) elif self.cmd == 'Burst write': - self.decode_reg(pos, ANN_BURST_WRITE, self.dat, self.mosi_bytes()) + self.decode_reg(pos, Ann.BURST_WRITE, self.dat, self.mosi_bytes()) elif self.cmd == 'Read': - self.decode_reg(pos, ANN_SINGLE_READ, self.dat, self.miso_bytes()) + self.decode_reg(pos, Ann.SINGLE_READ, self.dat, self.miso_bytes()) elif self.cmd == 'Burst read': - self.decode_reg(pos, ANN_BURST_READ, self.dat, self.miso_bytes()) + self.decode_reg(pos, Ann.BURST_READ, self.dat, self.miso_bytes()) elif self.cmd == 'Strobe': - self.decode_reg(pos, ANN_STROBE, self.dat, self.mosi_bytes()) + self.decode_reg(pos, Ann.STROBE, self.dat, self.mosi_bytes()) elif self.cmd == 'Status read': - self.decode_reg(pos, ANN_STATUS_READ, self.dat, self.miso_bytes()) + self.decode_reg(pos, Ann.STATUS_READ, self.dat, self.miso_bytes()) else: self.warn(pos, 'unhandled command') @@ -281,7 +282,7 @@ def decode(self, ss, es, data): # First MOSI byte is always the command. self.decode_command(pos, mosi) # First MISO byte is always the status register. - self.decode_reg(pos, ANN_STATUS, 'STATUS', [miso]) + self.decode_reg(pos, Ann.STATUS, 'STATUS', [miso]) else: if not self.cmd or len(self.mb) >= self.max: self.warn(pos, 'excess byte') From 369f8c288c6bfee7182e4affe3faebb2e51c4cef Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:07:50 +0200 Subject: [PATCH 15/42] Update Dali decoder --- libsigrokdecode4DSL/decoders/dali/pd.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/dali/pd.py b/libsigrokdecode4DSL/decoders/dali/pd.py index 53147463..419e364b 100644 --- a/libsigrokdecode4DSL/decoders/dali/pd.py +++ b/libsigrokdecode4DSL/decoders/dali/pd.py @@ -42,7 +42,7 @@ class Decoder(srd.Decoder): ) annotations = ( ('bit', 'Bit'), - ('startbit', 'Startbit'), + ('startbit', 'Start bit'), ('sbit', 'Select bit'), ('ybit', 'Individual or group'), ('address', 'Address'), @@ -52,7 +52,7 @@ class Decoder(srd.Decoder): ) annotation_rows = ( ('bits', 'Bits', (0,)), - ('raw', 'Raw data', (7,)), + ('raw-data', 'Raw data', (7,)), ('fields', 'Fields', (1, 2, 3, 4, 5, 6)), ) @@ -61,7 +61,6 @@ def __init__(self): def reset(self): self.samplerate = None - self.samplenum = None self.edges, self.bits, self.ss_es_bits = [], [], [] self.state = 'IDLE' self.dev_type = None From 79a1bb503503fdc596746fcc03159baed28e8675 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:08:08 +0200 Subject: [PATCH 16/42] Update DCF77 decoder --- libsigrokdecode4DSL/decoders/dcf77/pd.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/dcf77/pd.py b/libsigrokdecode4DSL/decoders/dcf77/pd.py index 7365134e..acb6bdaf 100644 --- a/libsigrokdecode4DSL/decoders/dcf77/pd.py +++ b/libsigrokdecode4DSL/decoders/dcf77/pd.py @@ -39,7 +39,7 @@ class Decoder(srd.Decoder): ) annotations = ( ('start-of-minute', 'Start of minute'), - ('special-bits', 'Special bits (civil warnings, weather forecast)'), + ('special-bit', 'Special bit (civil warnings, weather forecast)'), ('call-bit', 'Call bit'), ('summer-time', 'Summer time announcement'), ('cest', 'CEST bit'), @@ -55,9 +55,9 @@ class Decoder(srd.Decoder): ('month', 'Month'), ('year', 'Year'), ('date-parity', 'Date parity bit'), - ('raw-bits', 'Raw bits'), - ('unknown-bits', 'Unknown bits'), - ('warnings', 'Human-readable warnings'), + ('raw-bit', 'Raw bit'), + ('unknown-bit', 'Unknown bit'), + ('warning', 'Warning'), ) annotation_rows = ( ('bits', 'Bits', (17, 18)), From 50ac697b89e3742be503190c290dedbc24cfdb76 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:08:51 +0200 Subject: [PATCH 17/42] Update DMx512 decoder --- .../decoders/dmx512/__init__.py | 2 +- libsigrokdecode4DSL/decoders/dmx512/pd.py | 434 +++++++++++++----- 2 files changed, 309 insertions(+), 127 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/dmx512/__init__.py b/libsigrokdecode4DSL/decoders/dmx512/__init__.py index b5e57836..588f6977 100644 --- a/libsigrokdecode4DSL/decoders/dmx512/__init__.py +++ b/libsigrokdecode4DSL/decoders/dmx512/__init__.py @@ -1,7 +1,7 @@ ## ## This file is part of the libsigrokdecode project. ## -## Copyright (C) 2016 Fabian J. Stumpf +## Copyright (C) 2019 Gerhard Sittig ## ## 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 diff --git a/libsigrokdecode4DSL/decoders/dmx512/pd.py b/libsigrokdecode4DSL/decoders/dmx512/pd.py index 355095ee..a0cd83f3 100644 --- a/libsigrokdecode4DSL/decoders/dmx512/pd.py +++ b/libsigrokdecode4DSL/decoders/dmx512/pd.py @@ -2,6 +2,7 @@ ## This file is part of the libsigrokdecode project. ## ## Copyright (C) 2016 Fabian J. Stumpf +## Copyright (C) 2019-2020 Gerhard Sittig ## ## 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 @@ -17,8 +18,54 @@ ## along with this program; if not, see . ## +''' +OUTPUT_PYTHON format: + +Packet: +[, ] + +This is the list of codes and their respective values: + - 'PACKET': The data is a list of tuples with the bytes' start and end + positions as well as a byte value and a validity flag. This output + represents a DMX packet. The sample numbers span the range beginning + at the start of the start code and ending at the end of the last data + byte in the packet. The start code value resides at index 0. + +Developer notes on the DMX512 protocol: + +See Wikipedia for an overview: + https://en.wikipedia.org/wiki/DMX512#Electrical (physics, transport) + https://en.wikipedia.org/wiki/DMX512#Protocol (UART frames, DMX frames) + RS-485 transport, differential thus either polarity (needs user spec) + 8n2 UART frames at 250kbps, BREAK to start a new DMX frame + slot 0 carries start code, slot 1 up to 512 max carry data for peripherals + start code 0 for "boring lights", non-zero start code for extensions. + +TODO +- Cover more DMX packet types beyond start code 0x00 (standard). See + https://en.wikipedia.org/wiki/DMX512#Protocol for a list (0x17 text, + 0xcc RDM, 0xcf sysinfo) and a reference to the ESTA database. These + can either get added here or can get implemented in a stacked decoder. +- Run on more captures as these become available. Verify the min/max + BREAK, MARK, and RESET to RESET period checks. Add more conditions that + are worth checking to determine the health of the bus, see the (German) + http://www.soundlight.de/techtips/dmx512/dmx2000a.htm article for ideas. +- Is there a more user friendly way of having the DMX512 decoder configure + the UART decoder's parameters? Currently users need to setup the polarity + (which is acceptable, and an essential feature), but also the bitrate and + frame format (which may or may not be considered acceptable). +- (Not a DMX512 decoder TODO item) Current UART decoder implementation does + not handle two STOP bits, but DMX512 will transparently benefit when UART + gets adjusted. Until then the second STOP bit will be mistaken for a MARK + but that's just cosmetics, available data gets interpreted correctly. +''' + import sigrokdecode as srd +class Ann: + BREAK, MAB, INTERFRAME, INTERPACKET, STARTCODE, DATABYTE, CHANNEL_DATA, \ + SLOT_DATA, RESET, WARN, ERROR = range(11) + class Decoder(srd.Decoder): api_version = 3 id = 'dmx512' @@ -26,34 +73,49 @@ class Decoder(srd.Decoder): longname = 'Digital MultipleX 512' desc = 'Digital MultipleX 512 (DMX512) lighting protocol.' license = 'gplv2+' - inputs = ['logic'] - outputs = [] + inputs = ['uart'] + outputs = ['dmx512'] tags = ['Embedded/industrial', 'Lighting'] - channels = ( - {'id': 'dmx', 'name': 'DMX data', 'desc': 'Any DMX data line'}, - ) options = ( - {'id': 'invert', 'desc': 'Invert Signal?', 'default': 'no', - 'values': ('yes', 'no')}, + {'id': 'min_break', 'desc': 'Minimum BREAK length (us)', 'default': 88}, + {'id': 'max_mark', 'desc': 'Maximum MARK length (us)', 'default': 1000000}, + {'id': 'min_break_break', 'desc': 'Minimum BREAK to BREAK interval (us)', + 'default': 1196}, + {'id': 'max_reset_reset', 'desc': 'Maximum RESET to RESET interval (us)', + 'default': 1250000}, + {'id': 'show_zero', 'desc': 'Display all-zero set-point values', + 'default': 'no', 'values': ('yes', 'no')}, + {'id': 'format', 'desc': 'Data format', 'default': 'dec', + 'values': ('dec', 'hex', 'bin')}, ) annotations = ( - ('bit', 'Bit'), + # Lowest layer (above UART): BREAK MARK ( FRAME [MARK] )* + # with MARK being after-break or inter-frame or inter-packet. ('break', 'Break'), ('mab', 'Mark after break'), - ('startbit', 'Start bit'), - ('stopbits', 'Stop bit'), - ('startcode', 'Start code'), - ('channel', 'Channel'), ('interframe', 'Interframe'), ('interpacket', 'Interpacket'), - ('data', 'Data'), + # Next layer: STARTCODE ( DATABYTE )* + ('startcode', 'Start code'), + ('databyte', 'Data byte'), + # Next layer: CHANNEL or SLOT values + ('chan_data', 'Channel data'), + ('slot_data', 'Slot data'), + # Next layer: RESET + ('reset', 'Reset sequence'), + # Warnings and errors. + ('warning', 'Warning'), ('error', 'Error'), ) annotation_rows = ( - ('name', 'Logical', (1, 2, 5, 6, 7, 8)), - ('data', 'Data', (9,)), - ('bits', 'Bits', (0, 3, 4)), - ('errors', 'Errors', (10,)), + ('dmx_fields', 'Fields', (Ann.BREAK, Ann.MAB, + Ann.STARTCODE, Ann.INTERFRAME, + Ann.DATABYTE, Ann.INTERPACKET)), + ('chans_data', 'Channels data', (Ann.CHANNEL_DATA,)), + ('slots_data', 'Slots data', (Ann.SLOT_DATA,)), + ('resets', 'Reset sequences', (Ann.RESET,)), + ('warnings', 'Warnings', (Ann.WARN,)), + ('errors', 'Errors', (Ann.ERROR,)), ) def __init__(self): @@ -61,119 +123,239 @@ def __init__(self): def reset(self): self.samplerate = None - self.sample_usec = None - self.run_start = -1 - self.state = 'FIND BREAK' + self.samples_per_usec = None + self.last_reset = None + self.last_break = None + self.packet = None + self.last_es = None + self.last_frame = None + self.start_code = None def start(self): self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_python = self.register(srd.OUTPUT_PYTHON) def metadata(self, key, value): if key == srd.SRD_CONF_SAMPLERATE: self.samplerate = value - self.sample_usec = 1 / value * 1000000 - self.skip_per_bit = int(4 / self.sample_usec) - - def putr(self, data): - self.put(self.run_start, self.samplenum, self.out_ann, data) - - def decode(self): - if not self.samplerate: - raise SamplerateError('Cannot decode without samplerate.') - - inv = self.options['invert'] == 'yes' - - (dmx,) = self.wait({0: 'h' if inv else 'l'}) - self.run_start = self.samplenum - - while True: - # Seek for an interval with no state change with a length between - # 88 and 1000000 us (BREAK). - if self.state == 'FIND BREAK': - (dmx,) = self.wait({0: 'f' if inv else 'r'}) - runlen = (self.samplenum - self.run_start) * self.sample_usec - if runlen > 88 and runlen < 1000000: - self.putr([1, ['Break']]) - self.state = 'MARK MAB' - self.channel = 0 - elif runlen >= 1000000: - # Error condition. - self.putr([10, ['Invalid break length']]) - else: - (dmx,) = self.wait({0: 'h' if inv else 'l'}) - self.run_start = self.samplenum - # Directly following the BREAK is the MARK AFTER BREAK. - elif self.state == 'MARK MAB': - self.run_start = self.samplenum - (dmx,) = self.wait({0: 'r' if inv else 'f'}) - self.putr([2, ['MAB']]) - self.state = 'READ BYTE' - self.channel = 0 - self.bit = 0 - self.aggreg = dmx - self.run_start = self.samplenum - # Mark and read a single transmitted byte - # (start bit, 8 data bits, 2 stop bits). - elif self.state == 'READ BYTE': - bit_start = self.samplenum - bit_end = self.run_start + (self.bit + 1) * self.skip_per_bit - (dmx,) = self.wait({'skip': round(self.skip_per_bit/2)}) - bit_value = not dmx if inv else dmx - - if self.bit == 0: - self.byte = 0 - self.put(bit_start, bit_end, - self.out_ann, [3, ['Start bit']]) - if bit_value != 0: - # (Possibly) invalid start bit, mark but don't fail. - self.put(bit_start, bit_end, - self.out_ann, [10, ['Invalid start bit']]) - elif self.bit >= 9: - self.put(bit_start, bit_end, - self.out_ann, [4, ['Stop bit']]) - if bit_value != 1: - # Invalid stop bit, mark. - self.put(bit_start, bit_end, - self.out_ann, [10, ['Invalid stop bit']]) - if self.bit == 10: - # On invalid 2nd stop bit, search for new break. - self.state = 'FIND BREAK' - else: - # Label and process one bit. - self.put(bit_start, bit_end, - self.out_ann, [0, [str(bit_value)]]) - self.byte |= bit_value << (self.bit - 1) - - # Label a complete byte. - if self.state == 'READ BYTE' and self.bit == 10: - if self.channel == 0: - d = [5, ['Start code']] - else: - d = [6, ['Channel ' + str(self.channel)]] - self.put(self.run_start, bit_end, self.out_ann, d) - self.put(self.run_start + self.skip_per_bit, - bit_end - 2 * self.skip_per_bit, - self.out_ann, [9, [str(self.byte) + ' / ' + \ - str(hex(self.byte))]]) - # Continue by scanning the IFT. - self.channel += 1 - self.run_start = self.samplenum - self.state = 'MARK IFT' - - self.bit += 1 - (dmx,) = self.wait({'skip': round(bit_end - self.samplenum)}) - # Mark the INTERFRAME-TIME between bytes / INTERPACKET-TIME between packets. - elif self.state == 'MARK IFT': - self.run_start = self.samplenum - if self.channel > 512: - (dmx,) = self.wait({0: 'h' if inv else 'l'}) - self.putr([8, ['Interpacket']]) - self.state = 'FIND BREAK' - self.run_start = self.samplenum - else: - if (not dmx if inv else dmx): - (dmx,) = self.wait({0: 'h' if inv else 'l'}) - self.putr([7, ['Interframe']]) - self.state = 'READ BYTE' - self.bit = 0 - self.run_start = self.samplenum + self.samples_per_usec = value / 1000000 + + def have_samplerate(self): + return bool(self.samplerate) + + def samples_to_usecs(self, count): + return count / self.samples_per_usec + + def putg(self, ss, es, data): + self.put(ss, es, self.out_ann, data) + + def putpy(self, ss, es, data): + self.put(ss, es, self.out_python, data) + + def format_value(self, v): + fmt = self.options['format'] + if fmt == 'dec': + return '{:d}'.format(v) + if fmt == 'hex': + return '{:02X}'.format(v) + if fmt == 'bin': + return '{:08b}'.format(v) + return '{}'.format(v) + + def flush_packet(self): + if self.packet: + ss, es = self.packet[0][0], self.packet[-1][1] + self.putpy(ss, es, ['PACKET', self.packet]) + self.packet = None + + def flush_reset(self, ss, es): + if ss is not None and es is not None: + self.putg(ss, es, [Ann.RESET, ['RESET SEQUENCE', 'RESET', 'R']]) + if self.last_reset and self.have_samplerate(): + duration = self.samples_to_usecs(es - self.last_reset) + if duration > self.options['max_reset_reset']: + txts = ['Excessive RESET to RESET interval', 'RESET to RESET', 'RESET'] + self.putg(self.last_reset, es, [Ann.WARN, txts]) + self.last_reset = es + + def flush_break(self, ss, es): + self.putg(ss, es, [Ann.BREAK, ['BREAK', 'B']]) + if self.have_samplerate(): + duration = self.samples_to_usecs(es - ss) + if duration < self.options['min_break']: + txts = ['Short BREAK period', 'Short BREAK', 'BREAK'] + self.putg(ss, es, [Ann.WARN, txts]) + if self.last_break: + duration = self.samples_to_usecs(ss - self.last_break) + if duration < self.options['min_break_break']: + txts = ['Short BREAK to BREAK interval', 'Short BREAK to BREAK', 'BREAK'] + self.putg(ss, es, [Ann.WARN, txts]) + self.last_break = ss + self.last_es = es + + def flush_mark(self, ss, es, is_mab = False, is_if = False, is_ip = False): + '''Handle several kinds of MARK conditions.''' + + if ss is None or es is None or ss >= es: + return + + if is_mab: + ann = Ann.MAB + txts = ['MARK AFTER BREAK', 'MAB'] + elif is_if: + ann = Ann.INTERFRAME + txts = ['INTER FRAME', 'IF'] + elif is_ip: + ann = Ann.INTERPACKET + txts = ['INTER PACKET', 'IP'] + else: + return + self.putg(ss, es, [ann, txts]) + + if self.have_samplerate(): + duration = self.samples_to_usecs(es - ss) + if duration > self.options['max_mark']: + txts = ['Excessive MARK length', 'MARK length', 'MARK'] + self.putg(ss, es, [Ann.ERROR, txts]) + + def flush_frame(self, ss, es, value, valid): + '''Handle UART frame content. Accumulate DMX packet.''' + + if not valid: + txts = ['Invalid frame', 'Frame'] + self.putg(ss, es, [Ann.ERROR, txts]) + + self.last_es = es + + # Cease packet inspection before first BREAK. + if not self.last_break: + return + + # Accumulate the sequence of bytes for the current DMX frame. + # Emit the annotation at the "DMX fields" level. + is_start = self.packet is None + if is_start: + self.packet = [] + slot_nr = len(self.packet) + item = (ss, es, value, valid) + self.packet.append(item) + if is_start: + # Slot 0, the start code. Determines the DMX frame type. + self.start_code = value + ann = Ann.STARTCODE + val_text = self.format_value(value) + txts = [ + 'STARTCODE {}'.format(val_text), + 'START {}'.format(val_text), + '{}'.format(val_text), + ] + else: + # Slot 1+, the payload bytes. + ann = Ann.DATABYTE + val_text = self.format_value(value) + txts = [ + 'DATABYTE {:d}: {}'.format(slot_nr, val_text), + 'DATA {:d}: {}'.format(slot_nr, val_text), + 'DATA {}'.format(val_text), + '{}'.format(val_text), + ] + self.putg(ss, es, [ann, txts]) + + # Tell channel data for peripherals from arbitrary slot values. + # Can get extended for other start code types in case protocol + # extensions are handled here and not in stacked decoders. + if is_start: + ann = None + elif self.start_code == 0: + # Start code was 0. Slots carry values for channels. + # Optionally suppress zero-values to make used channels + # stand out, to help users focus their attention. + ann = Ann.CHANNEL_DATA + if value == 0 and self.options['show_zero'] == 'no': + ann = None + else: + val_text = self.format_value(value) + txts = [ + 'CHANNEL {:d}: {}'.format(slot_nr, val_text), + 'CH {:d}: {}'.format(slot_nr, val_text), + 'CH {}'.format(val_text), + '{}'.format(val_text), + ] + else: + # Unhandled start code. Provide "anonymous" values. + ann = Ann.SLOT_DATA + val_text = self.format_value(value) + txts = [ + 'SLOT {:d}: {}'.format(slot_nr, val_text), + 'SL {:d}: {}'.format(slot_nr, val_text), + 'SL {}'.format(val_text), + '{}'.format(val_text), + ] + if ann is not None: + self.putg(ss, es, [ann, txts]) + + if is_start and value == 0: + self.flush_reset(self.last_break, es) + + def handle_break(self, ss, es): + '''Handle UART BREAK conditions.''' + + # Check the last frame before BREAK if one was queued. It could + # have been "invalid" since the STOP bit check failed. If there + # is an invalid frame which happens to start at the start of the + # BREAK condition, then discard it. Otherwise flush its output. + last_frame = self.last_frame + self.last_frame = None + frame_invalid = last_frame and not last_frame[3] + frame_zero_data = last_frame and last_frame[2] == 0 + frame_is_break = last_frame and last_frame[0] == ss + if frame_invalid and frame_zero_data and frame_is_break: + last_frame = None + if last_frame is not None: + self.flush_frame(*last_frame) + + # Handle inter-packet MARK (works for zero length, too). + self.flush_mark(self.last_es, ss, is_ip = True) + + # Handle accumulated packets. + self.flush_packet() + self.packet = None + + # Annotate the BREAK condition. Start accumulation of a packet. + self.flush_break(ss, es) + + def handle_frame(self, ss, es, value, valid): + '''Handle UART data frames.''' + + # Flush previously deferred frame (if available). Can't have been + # BREAK if another data frame follows. + last_frame = self.last_frame + self.last_frame = None + if last_frame: + self.flush_frame(*last_frame) + + # Handle inter-frame MARK (works for zero length, too). + is_mab = self.last_break and self.packet is None + is_if = self.packet + self.flush_mark(self.last_es, ss, is_mab = is_mab, is_if = is_if) + + # Defer handling of invalid frames, because they may start a new + # BREAK which we will only learn about much later. Immediately + # annotate valid frames. + if valid: + self.flush_frame(ss, es, value, valid) + else: + self.last_frame = (ss, es, value, valid) + + def decode(self, ss, es, data): + # Lack of a sample rate in the input capture only disables the + # optional warnings about exceeded timespans here at the DMX512 + # decoder level. That the lower layer UART decoder depends on a + # sample rate is handled there, and is not relevant here. + + ptype, rxtx, pdata = data + if ptype == 'BREAK': + self.handle_break(ss, es) + elif ptype == 'FRAME': + value, valid = pdata + self.handle_frame(ss, es, value, valid) From 2871e021ecff4b5e5e6e01ad6b3c887c50bf35b1 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:09:17 +0200 Subject: [PATCH 18/42] Update DS1307 decoder --- libsigrokdecode4DSL/decoders/ds1307/pd.py | 92 ++++++++++++----------- 1 file changed, 49 insertions(+), 43 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/ds1307/pd.py b/libsigrokdecode4DSL/decoders/ds1307/pd.py index f8ebe195..51d673d3 100644 --- a/libsigrokdecode4DSL/decoders/ds1307/pd.py +++ b/libsigrokdecode4DSL/decoders/ds1307/pd.py @@ -1,7 +1,7 @@ ## ## This file is part of the libsigrokdecode project. ## -## Copyright (C) 2012-2014 Uwe Hermann +## Copyright (C) 2012-2020 Uwe Hermann ## Copyright (C) 2013 Matt Ranostay ## ## This program is free software; you can redistribute it and/or modify @@ -20,7 +20,7 @@ import re import sigrokdecode as srd -from common.srdhelper import bcd2int +from common.srdhelper import bcd2int, SrdIntEnum days_of_week = ( 'Sunday', 'Monday', 'Tuesday', 'Wednesday', @@ -47,10 +47,15 @@ DS1307_I2C_ADDRESS = 0x68 def regs_and_bits(): - l = [('reg-' + r.lower(), r + ' register') for r in regs] - l += [('bit-' + re.sub('\/| ', '-', b).lower(), b + ' bit') for b in bits] + l = [('reg_' + r.lower(), r + ' register') for r in regs] + l += [('bit_' + re.sub('\/| ', '_', b).lower(), b + ' bit') for b in bits] return tuple(l) +a = ['REG_' + r.upper() for r in regs] + \ + ['BIT_' + re.sub('\/| ', '_', b).upper() for b in bits] + \ + ['READ_DATE_TIME', 'WRITE_DATE_TIME', 'READ_REG', 'WRITE_REG', 'WARNING'] +Ann = SrdIntEnum.from_list('Ann', a) + class Decoder(srd.Decoder): api_version = 3 id = 'ds1307' @@ -62,17 +67,17 @@ class Decoder(srd.Decoder): outputs = [] tags = ['Clock/timing', 'IC'] annotations = regs_and_bits() + ( - ('read-datetime', 'Read date/time'), - ('write-datetime', 'Write date/time'), - ('reg-read', 'Register read'), - ('reg-write', 'Register write'), - ('warnings', 'Warnings'), + ('read_date_time', 'Read date/time'), + ('write_date_time', 'Write date/time'), + ('read_reg', 'Register read'), + ('write_reg', 'Register write'), + ('warning', 'Warning'), ) annotation_rows = ( - ('bits', 'Bits', tuple(range(9, 24))), - ('regs', 'Registers', tuple(range(9))), - ('date-time', 'Date/time', (24, 25, 26, 27)), - ('warnings', 'Warnings', (28,)), + ('bits', 'Bits', Ann.prefixes('BIT_')), + ('regs', 'Registers', Ann.prefixes('REG_')), + ('date_time', 'Date/time', Ann.prefixes('READ_ WRITE_')), + ('warnings', 'Warnings', (Ann.WARNING,)), ) def __init__(self): @@ -100,84 +105,85 @@ def putd(self, bit1, bit2, data): def putr(self, bit): self.put(self.bits[bit][1], self.bits[bit][2], self.out_ann, - [11, ['Reserved bit', 'Reserved', 'Rsvd', 'R']]) + [Ann.BIT_RESERVED, ['Reserved bit', 'Reserved', 'Rsvd', 'R']]) def handle_reg_0x00(self, b): # Seconds (0-59) / Clock halt bit - self.putd(7, 0, [0, ['Seconds', 'Sec', 'S']]) + self.putd(7, 0, [Ann.REG_SECONDS, ['Seconds', 'Sec', 'S']]) ch = 1 if (b & (1 << 7)) else 0 - self.putd(7, 7, [9, ['Clock halt: %d' % ch, 'Clk hlt: %d' % ch, - 'CH: %d' % ch, 'CH']]) + self.putd(7, 7, [Ann.BIT_CLOCK_HALT, ['Clock halt: %d' % ch, + 'Clk hlt: %d' % ch, 'CH: %d' % ch, 'CH']]) s = self.seconds = bcd2int(b & 0x7f) - self.putd(6, 0, [10, ['Second: %d' % s, 'Sec: %d' % s, 'S: %d' % s, 'S']]) + self.putd(6, 0, [Ann.BIT_SECONDS, ['Second: %d' % s, 'Sec: %d' % s, + 'S: %d' % s, 'S']]) def handle_reg_0x01(self, b): # Minutes (0-59) - self.putd(7, 0, [1, ['Minutes', 'Min', 'M']]) + self.putd(7, 0, [Ann.REG_MINUTES, ['Minutes', 'Min', 'M']]) self.putr(7) m = self.minutes = bcd2int(b & 0x7f) - self.putd(6, 0, [12, ['Minute: %d' % m, 'Min: %d' % m, 'M: %d' % m, 'M']]) + self.putd(6, 0, [Ann.BIT_MINUTES, ['Minute: %d' % m, 'Min: %d' % m, 'M: %d' % m, 'M']]) def handle_reg_0x02(self, b): # Hours (1-12+AM/PM or 0-23) - self.putd(7, 0, [2, ['Hours', 'H']]) + self.putd(7, 0, [Ann.REG_HOURS, ['Hours', 'H']]) self.putr(7) ampm_mode = True if (b & (1 << 6)) else False if ampm_mode: - self.putd(6, 6, [13, ['12-hour mode', '12h mode', '12h']]) + self.putd(6, 6, [Ann.BIT_12_24_HOURS, ['12-hour mode', '12h mode', '12h']]) a = 'PM' if (b & (1 << 5)) else 'AM' - self.putd(5, 5, [14, [a, a[0]]]) + self.putd(5, 5, [Ann.BIT_AM_PM, [a, a[0]]]) h = self.hours = bcd2int(b & 0x1f) - self.putd(4, 0, [15, ['Hour: %d' % h, 'H: %d' % h, 'H']]) + self.putd(4, 0, [Ann.BIT_HOURS, ['Hour: %d' % h, 'H: %d' % h, 'H']]) else: - self.putd(6, 6, [13, ['24-hour mode', '24h mode', '24h']]) + self.putd(6, 6, [Ann.BIT_12_24_HOURS, ['24-hour mode', '24h mode', '24h']]) h = self.hours = bcd2int(b & 0x3f) - self.putd(5, 0, [15, ['Hour: %d' % h, 'H: %d' % h, 'H']]) + self.putd(5, 0, [Ann.BIT_HOURS, ['Hour: %d' % h, 'H: %d' % h, 'H']]) def handle_reg_0x03(self, b): # Day / day of week (1-7) - self.putd(7, 0, [3, ['Day of week', 'Day', 'D']]) + self.putd(7, 0, [Ann.REG_DAY, ['Day of week', 'Day', 'D']]) for i in (7, 6, 5, 4, 3): self.putr(i) w = self.days = bcd2int(b & 0x07) ws = days_of_week[self.days - 1] - self.putd(2, 0, [16, ['Weekday: %s' % ws, 'WD: %s' % ws, 'WD', 'W']]) + self.putd(2, 0, [Ann.BIT_DAY, ['Weekday: %s' % ws, 'WD: %s' % ws, 'WD', 'W']]) def handle_reg_0x04(self, b): # Date (1-31) - self.putd(7, 0, [4, ['Date', 'D']]) + self.putd(7, 0, [Ann.REG_DATE, ['Date', 'D']]) for i in (7, 6): self.putr(i) d = self.date = bcd2int(b & 0x3f) - self.putd(5, 0, [17, ['Date: %d' % d, 'D: %d' % d, 'D']]) + self.putd(5, 0, [Ann.BIT_DATE, ['Date: %d' % d, 'D: %d' % d, 'D']]) def handle_reg_0x05(self, b): # Month (1-12) - self.putd(7, 0, [5, ['Month', 'Mon', 'M']]) + self.putd(7, 0, [Ann.REG_MONTH, ['Month', 'Mon', 'M']]) for i in (7, 6, 5): self.putr(i) m = self.months = bcd2int(b & 0x1f) - self.putd(4, 0, [18, ['Month: %d' % m, 'Mon: %d' % m, 'M: %d' % m, 'M']]) + self.putd(4, 0, [Ann.BIT_MONTH, ['Month: %d' % m, 'Mon: %d' % m, 'M: %d' % m, 'M']]) def handle_reg_0x06(self, b): # Year (0-99) - self.putd(7, 0, [6, ['Year', 'Y']]) + self.putd(7, 0, [Ann.REG_YEAR, ['Year', 'Y']]) y = self.years = bcd2int(b & 0xff) self.years += 2000 - self.putd(7, 0, [19, ['Year: %d' % y, 'Y: %d' % y, 'Y']]) + self.putd(7, 0, [Ann.BIT_YEAR, ['Year: %d' % y, 'Y: %d' % y, 'Y']]) def handle_reg_0x07(self, b): # Control Register - self.putd(7, 0, [7, ['Control', 'Ctrl', 'C']]) + self.putd(7, 0, [Ann.REG_CONTROL, ['Control', 'Ctrl', 'C']]) for i in (6, 5, 3, 2): self.putr(i) o = 1 if (b & (1 << 7)) else 0 s = 1 if (b & (1 << 4)) else 0 s2 = 'en' if (b & (1 << 4)) else 'dis' r = rates[b & 0x03] - self.putd(7, 7, [20, ['Output control: %d' % o, + self.putd(7, 7, [Ann.BIT_OUT, ['Output control: %d' % o, 'OUT: %d' % o, 'O: %d' % o, 'O']]) - self.putd(4, 4, [21, ['Square wave output: %sabled' % s2, + self.putd(4, 4, [Ann.BIT_SQWE, ['Square wave output: %sabled' % s2, 'SQWE: %sabled' % s2, 'SQWE: %d' % s, 'S: %d' % s, 'S']]) - self.putd(1, 0, [22, ['Square wave output rate: %s' % r, + self.putd(1, 0, [Ann.BIT_RS, ['Square wave output rate: %s' % r, 'Square wave rate: %s' % r, 'SQW rate: %s' % r, 'Rate: %s' % r, 'RS: %s' % s, 'RS', 'R']]) def handle_reg_0x3f(self, b): # RAM (bytes 0x08-0x3f) - self.putd(7, 0, [8, ['RAM', 'R']]) - self.putd(7, 0, [23, ['SRAM: 0x%02X' % b, '0x%02X' % b]]) + self.putd(7, 0, [Ann.REG_RAM, ['RAM', 'R']]) + self.putd(7, 0, [Ann.BIT_RAM, ['SRAM: 0x%02X' % b, '0x%02X' % b]]) def output_datetime(self, cls, rw): # TODO: Handle read/write of only parts of these items. @@ -201,7 +207,7 @@ def is_correct_chip(self, addr): if addr == DS1307_I2C_ADDRESS: return True self.put(self.ss_block, self.es, self.out_ann, - [28, ['Ignoring non-DS1307 data (slave 0x%02X)' % addr]]) + [Ann.WARNING, ['Ignoring non-DS1307 data (slave 0x%02X)' % addr]]) return False def decode(self, ss, es, data): @@ -246,7 +252,7 @@ def decode(self, ss, es, data): if cmd == 'DATA WRITE': self.handle_reg(databyte) elif cmd == 'STOP': - self.output_datetime(25, 'Written') + self.output_datetime(Ann.WRITE_DATE_TIME, 'Written') self.state = 'IDLE' elif self.state == 'READ RTC REGS': # Wait for an address read operation. @@ -260,5 +266,5 @@ def decode(self, ss, es, data): if cmd == 'DATA READ': self.handle_reg(databyte) elif cmd == 'STOP': - self.output_datetime(24, 'Read') + self.output_datetime(Ann.READ_DATE_TIME, 'Read') self.state = 'IDLE' From e16012a4118152fe28279433a63e3a0c31224937 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:09:34 +0200 Subject: [PATCH 19/42] Update DS2408 decoder --- libsigrokdecode4DSL/decoders/ds2408/pd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsigrokdecode4DSL/decoders/ds2408/pd.py b/libsigrokdecode4DSL/decoders/ds2408/pd.py index 33f2873f..97fb650f 100644 --- a/libsigrokdecode4DSL/decoders/ds2408/pd.py +++ b/libsigrokdecode4DSL/decoders/ds2408/pd.py @@ -40,7 +40,7 @@ class Decoder(srd.Decoder): outputs = [] tags = ['Embedded/industrial', 'IC'] annotations = ( - ('text', 'Human-readable text'), + ('text', 'Text'), ) def __init__(self): From 391dcb75fbd23a3c7e3bd278202e9880ddfcdc37 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:09:52 +0200 Subject: [PATCH 20/42] Update DS243x decoder --- libsigrokdecode4DSL/decoders/ds243x/pd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsigrokdecode4DSL/decoders/ds243x/pd.py b/libsigrokdecode4DSL/decoders/ds243x/pd.py index 7f9f6660..0fbdcdf5 100644 --- a/libsigrokdecode4DSL/decoders/ds243x/pd.py +++ b/libsigrokdecode4DSL/decoders/ds243x/pd.py @@ -71,7 +71,7 @@ class Decoder(srd.Decoder): outputs = [] tags = ['IC', 'Memory'] annotations = ( - ('text', 'Human-readable text'), + ('text', 'Text'), ) binary = ( ('mem_read', 'Data read from memory'), From 17abc963bfa339488fed634541e11831474f276a Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:10:21 +0200 Subject: [PATCH 21/42] Update DS28EA00 decoder --- libsigrokdecode4DSL/decoders/ds28ea00/pd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsigrokdecode4DSL/decoders/ds28ea00/pd.py b/libsigrokdecode4DSL/decoders/ds28ea00/pd.py index 9a578449..39290b45 100644 --- a/libsigrokdecode4DSL/decoders/ds28ea00/pd.py +++ b/libsigrokdecode4DSL/decoders/ds28ea00/pd.py @@ -45,7 +45,7 @@ class Decoder(srd.Decoder): outputs = [] tags = ['IC', 'Sensor'] annotations = ( - ('text', 'Human-readable text'), + ('text', 'Text'), ) def __init__(self): From e27ab19bf5555dc7828ed072e54ae8d18bc4635f Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:11:07 +0200 Subject: [PATCH 22/42] Update DSI decoder --- libsigrokdecode4DSL/decoders/dsi/pd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/dsi/pd.py b/libsigrokdecode4DSL/decoders/dsi/pd.py index 7ce95179..b5faf6f6 100644 --- a/libsigrokdecode4DSL/decoders/dsi/pd.py +++ b/libsigrokdecode4DSL/decoders/dsi/pd.py @@ -47,7 +47,7 @@ class Decoder(srd.Decoder): ) annotation_rows = ( ('bits', 'Bits', (0,)), - ('raw', 'Raw data', (3,)), + ('raw-vals', 'Raw data', (3,)), ('fields', 'Fields', (1, 2)), ) @@ -56,7 +56,6 @@ def __init__(self): def reset(self): self.samplerate = None - self.samplenum = None self.edges, self.bits, self.ss_es_bits = [], [], [] self.state = 'IDLE' @@ -112,6 +111,7 @@ def decode(self): raise SamplerateError('Cannot decode without samplerate.') bit = 0 while True: + # TODO: Come up with more appropriate self.wait() conditions. (self.dsi,) = self.wait() if self.options['polarity'] == 'active-high': self.dsi ^= 1 # Invert. From d27025e5a5e706acac6bfa76963c86206bdb4fdf Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:11:55 +0200 Subject: [PATCH 23/42] Update EDID decoder --- libsigrokdecode4DSL/decoders/edid/pd.py | 27 ++++++++++++++----------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/edid/pd.py b/libsigrokdecode4DSL/decoders/edid/pd.py index 2d7460ce..73405352 100644 --- a/libsigrokdecode4DSL/decoders/edid/pd.py +++ b/libsigrokdecode4DSL/decoders/edid/pd.py @@ -26,8 +26,11 @@ # - Extensions import sigrokdecode as srd +from common.srdhelper import SrdIntEnum import os +St = SrdIntEnum.from_str('St', 'OFFSET EXTENSIONS HEADER EDID') + EDID_HEADER = [0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00] OFF_VENDOR = 8 OFF_VERSION = 18 @@ -83,12 +86,12 @@ class Decoder(srd.Decoder): outputs = [] tags = ['Display', 'Memory', 'PC'] annotations = ( - ('fields', 'EDID structure fields'), - ('sections', 'EDID structure sections'), + ('field', 'Field'), + ('section', 'Section'), ) annotation_rows = ( - ('sections', 'Sections', (1,)), ('fields', 'Fields', (0,)), + ('sections', 'Sections', (1,)), ) def __init__(self): @@ -116,22 +119,22 @@ def decode(self, ss, es, data): cmd, data = data if cmd == 'ADDRESS WRITE' and data == 0x50: - self.state = 'offset' + self.state = St.OFFSET self.ss = ss return if cmd == 'ADDRESS READ' and data == 0x50: if self.extension > 0: - self.state = 'extensions' + self.state = St.EXTENSIONS s = str(self.extension) t = ["Extension: " + s, "X: " + s, s] else: - self.state = 'header' + self.state = St.HEADER t = ["EDID"] self.put(ss, es, self.out_ann, [ANN_SECTIONS, t]) return - if cmd == 'DATA WRITE' and self.state == 'offset': + if cmd == 'DATA WRITE' and self.state == St.OFFSET: self.offset = data self.extension = self.offset // 128 self.cnt = self.offset % 128 @@ -163,7 +166,7 @@ def decode(self, ss, es, data): self.sn.append([ss, es]) self.cache.append(data) - if self.state is None or self.state == 'header': + if self.state is None or self.state == St.HEADER: # Wait for the EDID header if self.cnt >= OFF_VENDOR: if self.cache[-8:] == EDID_HEADER: @@ -171,12 +174,12 @@ def decode(self, ss, es, data): self.sn = self.sn[-8:] self.cache = self.cache[-8:] self.cnt = 8 - self.state = 'edid' + self.state = St.EDID self.put(self.sn[0][0], es, self.out_ann, [ANN_SECTIONS, ['Header']]) self.put(self.sn[0][0], es, self.out_ann, [ANN_FIELDS, ['Header pattern']]) - elif self.state == 'edid': + elif self.state == St.EDID: if self.cnt == OFF_VERSION: self.decode_vid(-10) self.decode_pid(-8) @@ -224,9 +227,9 @@ def decode(self, ss, es, data): csstr = 'WRONG!' self.put(ss, es, self.out_ann, [0, ['Checksum: %d (%s)' % ( self.cache[self.cnt-1], csstr)]]) - self.state = 'extensions' + self.state = St.EXTENSIONS - elif self.state == 'extensions': + elif self.state == St.EXTENSIONS: cache = self.ext_cache[self.extension - 1] sn = self.ext_sn[self.extension - 1] v = cache[self.cnt - 1] From 79dd96659a4c3bcd11e23661c2bb0fcc501cf397 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:12:33 +0200 Subject: [PATCH 24/42] Update EEPROM24xx decoder --- libsigrokdecode4DSL/decoders/eeprom24xx/lists.py | 10 ++++++++++ libsigrokdecode4DSL/decoders/eeprom24xx/pd.py | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/libsigrokdecode4DSL/decoders/eeprom24xx/lists.py b/libsigrokdecode4DSL/decoders/eeprom24xx/lists.py index c6ee63d5..a66cb19a 100644 --- a/libsigrokdecode4DSL/decoders/eeprom24xx/lists.py +++ b/libsigrokdecode4DSL/decoders/eeprom24xx/lists.py @@ -189,6 +189,16 @@ 'addr_pins': 3, # Called E0, E1, E2 on this chip. 'max_speed': 400, }, + 'st_m24c32': { + 'vendor': 'ST', + 'model': 'M24C32', + 'size': 4 * 1024, + 'page_size': 32, + 'page_wraparound': True, + 'addr_bytes': 2, + 'addr_pins': 3, # Called E0, E1, E2 on this chip. + 'max_speed': 1000, + }, # Xicor 'xicor_x24c02': { diff --git a/libsigrokdecode4DSL/decoders/eeprom24xx/pd.py b/libsigrokdecode4DSL/decoders/eeprom24xx/pd.py index 033a44b2..549ee2df 100644 --- a/libsigrokdecode4DSL/decoders/eeprom24xx/pd.py +++ b/libsigrokdecode4DSL/decoders/eeprom24xx/pd.py @@ -38,7 +38,7 @@ class Decoder(srd.Decoder): ) annotations = ( # Warnings - ('warnings', 'Warnings'), + ('warning', 'Warning'), # Bits/bytes ('control-code', 'Control code'), ('address-pin', 'Address pin (A0/A1/A2)'), From e5d9b5aa1c1b66c27d2c09f3eed9d7e32cfc4673 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:13:01 +0200 Subject: [PATCH 25/42] Update EEPROM93xx decoder --- libsigrokdecode4DSL/decoders/eeprom93xx/pd.py | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/eeprom93xx/pd.py b/libsigrokdecode4DSL/decoders/eeprom93xx/pd.py index 7b64e59a..8c08fc80 100644 --- a/libsigrokdecode4DSL/decoders/eeprom93xx/pd.py +++ b/libsigrokdecode4DSL/decoders/eeprom93xx/pd.py @@ -32,6 +32,8 @@ class Decoder(srd.Decoder): options = ( {'id': 'addresssize', 'desc': 'Address size', 'default': 8}, {'id': 'wordsize', 'desc': 'Word size', 'default': 16}, + {'id': 'format', 'desc': 'Data format', 'default': 'hex', + 'values': ('ascii', 'hex')}, ) annotations = ( ('si-data', 'SI data'), @@ -42,6 +44,10 @@ class Decoder(srd.Decoder): ('data', 'Data', (0, 1)), ('warnings', 'Warnings', (2,)), ) + binary = ( + ('address', 'Address'), + ('data', 'Data'), + ) def __init__(self): self.reset() @@ -51,6 +57,7 @@ def reset(self): def start(self): self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.register(srd.OUTPUT_BINARY) self.addresssize = self.options['addresssize'] self.wordsize = self.options['wordsize'] @@ -60,7 +67,8 @@ def put_address(self, data): for b in range(len(data)): a += (data[b].si << (len(data) - b - 1)) self.put(data[0].ss, data[-1].es, self.out_ann, - [0, ['Address: 0x%x' % a, 'Addr: 0x%x' % a, '0x%x' % a]]) + [0, ['Address: 0x%04x' % a, 'Addr: 0x%04x' % a, '0x%04x' % a]]) + self.put(data[0].ss, data[-1].es, self.out_binary, [0, bytes([a])]) def put_word(self, si, data): # Decode word (MSb first). @@ -69,8 +77,22 @@ def put_word(self, si, data): d = data[b].si if si else data[b].so word += (d << (len(data) - b - 1)) idx = 0 if si else 1 - self.put(data[0].ss, data[-1].es, - self.out_ann, [idx, ['Data: 0x%x' % word, '0x%x' % word]]) + + if self.options['format'] == 'ascii': + word_str = '' + for s in range(0, len(data), 8): + c = 0xff & (word >> s) + if c in range(32, 126 + 1): + word_str = chr(c) + word_str + else: + word_str = '[{:02X}]'.format(c) + word_str + self.put(data[0].ss, data[-1].es, + self.out_ann, [idx, ['Data: %s' % word_str, '%s' % word_str]]) + else: + self.put(data[0].ss, data[-1].es, + self.out_ann, [idx, ['Data: 0x%04x' % word, '0x%04x' % word]]) + self.put(data[0].ss, data[-1].es, self.out_binary, + [1, bytes([(word & 0xff00) >> 8, word & 0xff])]) def decode(self, ss, es, data): if len(data) < (2 + self.addresssize): From 12205aecd7851d71d72ef84ee999e19fa7025e61 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:13:21 +0200 Subject: [PATCH 26/42] Update ENC28J60 decoder --- libsigrokdecode4DSL/decoders/enc28j60/pd.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/enc28j60/pd.py b/libsigrokdecode4DSL/decoders/enc28j60/pd.py index 1bd69a50..e8ce6e7b 100644 --- a/libsigrokdecode4DSL/decoders/enc28j60/pd.py +++ b/libsigrokdecode4DSL/decoders/enc28j60/pd.py @@ -67,9 +67,9 @@ class Decoder(srd.Decoder): ('warning', 'Warning'), ) annotation_rows = ( + ('fields', 'Fields', (ANN_DATA, ANN_REG_ADDR)), ('commands', 'Commands', (ANN_RCR, ANN_RBM, ANN_WCR, ANN_WBM, ANN_BFS, ANN_BFC, ANN_SRC)), - ('fields', 'Fields', (ANN_DATA, ANN_REG_ADDR)), ('warnings', 'Warnings', (ANN_WARNING,)), ) @@ -130,10 +130,14 @@ def _put_register_header(self): if reg_name is None: # We don't know the bank we're in yet. - self.putr([ANN_REG_ADDR, ['Reg Bank ? Addr {$}', '?:{$}', '@%02X' % reg_addr]]) - self.putr([ANN_WARNING, ['Warning: Register bank not known yet.', 'Warning']]) + self.putr([ANN_REG_ADDR, [ + 'Reg Bank ? Addr 0x{0:02X}'.format(reg_addr), + '?:{0:02X}'.format(reg_addr)]]) + self.putr([ANN_WARNING, ['Warning: Register bank not known yet.', + 'Warning']]) else: - self.putr([ANN_REG_ADDR, ['Reg {0}'.format(reg_name), '{0}'.format(reg_name)]]) + self.putr([ANN_REG_ADDR, ['Reg {0}'.format(reg_name), + '{0}'.format(reg_name)]]) if (reg_name == '-') or (reg_name == 'Reserved'): self.putr([ANN_WARNING, ['Warning: Invalid register accessed.', @@ -147,9 +151,11 @@ def _put_data_byte(self, data, byte_index, binary=False): self.range_es = self.ranges[byte_index + 1][0] if binary: - self.putr([ANN_DATA, ['Data 0b{0:08b}'.format(data), '{0:08b}'.format(data)]]) + self.putr([ANN_DATA, ['Data 0b{0:08b}'.format(data), + '{0:08b}'.format(data)]]) else: - self.putr([ANN_DATA, ['Data {$}','{S}', '@%02X' % data]]) + self.putr([ANN_DATA, ['Data 0x{0:02X}'.format(data), + '{0:02X}'.format(data)]]) def _put_command_warning(self, reason): self.putc([ANN_WARNING, ['Warning: {0}'.format(reason), 'Warning']]) From 09cf6d7eb18594c817560ca13f1f0c360b1b26d3 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:13:45 +0200 Subject: [PATCH 27/42] Update FlexRay decoder --- libsigrokdecode4DSL/decoders/flexray/pd.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/flexray/pd.py b/libsigrokdecode4DSL/decoders/flexray/pd.py index fc52b95f..8ec30439 100644 --- a/libsigrokdecode4DSL/decoders/flexray/pd.py +++ b/libsigrokdecode4DSL/decoders/flexray/pd.py @@ -407,7 +407,7 @@ def decode(self): # Wait until we're in the correct bit/sampling position. pos = self.get_sample_point(self.curbit) (fr_rx,) = self.wait([{'skip': pos - self.samplenum}, {0: 'f'}]) - if self.matched & 0b10: + if self.matched[1]: self.dom_edge_seen() - if self.matched & 0b01: - self.handle_bit(fr_rx) \ No newline at end of file + if self.matched[0]: + self.handle_bit(fr_rx) From b47fa89e1803c2ae4362858b352bacfde269408e Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:14:32 +0200 Subject: [PATCH 28/42] Update I2C filter decoder --- libsigrokdecode4DSL/decoders/i2cfilter/pd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsigrokdecode4DSL/decoders/i2cfilter/pd.py b/libsigrokdecode4DSL/decoders/i2cfilter/pd.py index 7798e17a..a54baab2 100644 --- a/libsigrokdecode4DSL/decoders/i2cfilter/pd.py +++ b/libsigrokdecode4DSL/decoders/i2cfilter/pd.py @@ -33,7 +33,7 @@ class Decoder(srd.Decoder): outputs = ['i2c'] tags = ['Util'] options = ( - {'id': 'address', 'desc': 'Address to filter out of the I²C stream', + {'id': 'address', 'desc': 'Slave address to filter (decimal)', 'default': 0}, {'id': 'direction', 'desc': 'Direction to filter', 'default': 'both', 'values': ('read', 'write', 'both')} From 0c38af0de75faf08ddb39207d37d0758f8b87fac Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:15:06 +0200 Subject: [PATCH 29/42] Update IEEE488 decoder --- libsigrokdecode4DSL/decoders/ieee488/pd.py | 129 ++++++++++++++++++--- 1 file changed, 113 insertions(+), 16 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/ieee488/pd.py b/libsigrokdecode4DSL/decoders/ieee488/pd.py index 5fb6fa88..b0948a68 100644 --- a/libsigrokdecode4DSL/decoders/ieee488/pd.py +++ b/libsigrokdecode4DSL/decoders/ieee488/pd.py @@ -69,6 +69,8 @@ when addressing channels within the device. - 'DATA_BYTE': is the talker address (when available), is the raw data byte (transport layer, ATN inactive). + - 'PPOLL': is not applicable, is a list of bit indices + (DIO1 to DIO8 order) which responded to the PP request. Extracted payload information (peers and their communicated data): - 'TALK_LISTEN': is the current talker, is the list of @@ -239,11 +241,12 @@ def _get_data_text(b): ANN_RAW_BIT, ANN_RAW_BYTE, ANN_CMD, ANN_LADDR, ANN_TADDR, ANN_SADDR, ANN_DATA, ANN_EOI, + ANN_PP, ANN_TEXT, # TODO Want to provide one annotation class per talker address (0-30)? ANN_IEC_PERIPH, ANN_WARN, -) = range(11) +) = range(12) ( BIN_RAW, @@ -284,10 +287,12 @@ class Decoder(srd.Decoder): {'id': 'clk', 'name': 'CLK', 'desc': 'Serial clock'}, ) options = ( - {'id': 'iec_periph', 'desc': 'Decode Commodore IEC bus peripherals details', + {'id': 'iec_periph', 'desc': 'Decode Commodore IEC peripherals', 'default': 'no', 'values': ('no', 'yes')}, {'id': 'delim', 'desc': 'Payload data delimiter', 'default': 'eol', 'values': ('none', 'eol')}, + {'id': 'atn_parity', 'desc': 'ATN commands use parity', + 'default': 'no', 'values': ('no', 'yes')}, ) annotations = ( ('bit', 'IEC bit'), @@ -298,6 +303,7 @@ class Decoder(srd.Decoder): ('saddr', 'Secondary address'), ('data', 'Data byte'), ('eoi', 'EOI'), + ('pp', 'Parallel poll'), ('text', 'Talker text'), ('periph', 'IEC bus peripherals'), ('warning', 'Warning'), @@ -307,6 +313,7 @@ class Decoder(srd.Decoder): ('raws', 'Raw bytes', (ANN_RAW_BYTE,)), ('gpib', 'Commands/data', (ANN_CMD, ANN_LADDR, ANN_TADDR, ANN_SADDR, ANN_DATA,)), ('eois', 'EOI', (ANN_EOI,)), + ('polls', 'Polls', (ANN_PP,)), ('texts', 'Talker texts', (ANN_TEXT,)), ('periphs', 'IEC peripherals', (ANN_IEC_PERIPH,)), ('warnings', 'Warnings', (ANN_WARN,)), @@ -333,6 +340,7 @@ def reset(self): self.es_eoi = None self.ss_text = None self.es_text = None + self.ss_pp = None self.last_talker = None self.last_listener = [] self.last_iec_addr = None @@ -401,6 +409,63 @@ def check_extra_flush(self, b): if had_eol and not is_eol: self.flush_bytes_text_accu() + def check_pp(self, dio = None): + # The combination of ATN and EOI means PP (parallel poll). Track + # this condition's start and end, and keep grabing the DIO lines' + # state as long as the condition is seen, since DAV is not used + # in the PP communication. + capture_in_pp = self.curr_atn and self.curr_eoi + decoder_in_pp = self.ss_pp is not None + if capture_in_pp and not decoder_in_pp: + # Phase starts. Track its ss. Start collecting DIO state. + self.ss_pp = self.samplenum + self.dio_pp = [] + return 'enter' + if not capture_in_pp and decoder_in_pp: + # Phase ends. Void its ss. Process collected DIO state. + ss, es = self.ss_pp, self.samplenum + dio = self.dio_pp or [] + self.ss_pp, self.dio_pp = None, None + if ss == es: + # False positive, caused by low oversampling. + return 'leave' + # Emit its annotation. Translate bit indices 0..7 for the + # DIO1..DIO8 signals to display text. Pass bit indices in + # the Python output for upper layers. + # + # TODO The presentation of this information may need more + # adjustment. The bit positions need not translate to known + # device addresses. Bits need not even belong to a single + # device. Participants and their location in the DIO pattern + # is configurable. Leave the interpretation to upper layers. + bits = [i for i, b in enumerate(dio) if b] + bits_text = ' '.join(['{}'.format(i + 1) for i in bits]) + dios = ['DIO{}'.format(i + 1) for i in bits] + dios_text = ' '.join(dios or ['-']) + text = [ + 'PPOLL {}'.format(dios_text), + 'PP {}'.format(bits_text), + 'PP', + ] + self.emit_data_ann(ss, es, ANN_PP, text) + self.putpy(ss, es, 'PPOLL', None, bits) + # Cease collecting DIO state. + return 'leave' + if decoder_in_pp: + # Keep collecting DIO state for each individual sample in + # the PP phase. Logically OR all DIO values that were seen. + # This increases robustness for low oversampling captures, + # where DIO may no longer be asserted when ATN/EOI deassert, + # and DIO was not asserted yet when ATN/EOI start asserting. + if dio is None: + dio = [] + if len(dio) > len(self.dio_pp): + self.dio_pp.extend([ 0, ] * (len(dio) - len(self.dio_pp))) + for i, b in enumerate(dio): + self.dio_pp[i] |= b + return 'keep' + return 'idle' + def handle_ifc_change(self, ifc): # Track IFC line for parallel input. # Assertion of IFC de-selects all talkers and listeners. @@ -486,6 +551,13 @@ def handle_data_byte(self): upd_iec = False, py_type = None py_peers = False + if self.options['atn_parity'] == 'yes': + par = 1 if b & 0x80 else 0 + b &= ~0x80 + ones = bin(b).count('1') + par + if ones % 2: + warn_texts = ['Command parity error', 'parity', 'PAR'] + self.emit_warn_ann(self.ss_raw, self.es_raw, warn_texts) is_cmd, is_unl, is_unt = _is_command(b) laddr = _is_listen_addr(b) taddr = _is_talk_addr(b) @@ -624,12 +696,12 @@ def decode_serial(self, has_clk, has_data_1, has_atn, has_srq): data, clk = pins[PIN_DATA], pins[PIN_CLK] atn, = self.invert_pins([pins[PIN_ATN]]) - if self.matched & 0b1: + if self.matched[0]: # Falling edge on ATN, reset step. step = STEP_WAIT_READY_TO_SEND if step == STEP_WAIT_READY_TO_SEND: - # Don't use self.matched_[1] here since we might come from + # Don't use self.matched[1] here since we might come from # a step with different conds due to the code above. if data == 0 and clk == 1: # Rising edge on CLK while DATA is low: Ready to send. @@ -654,7 +726,7 @@ def decode_serial(self, has_clk, has_data_1, has_atn, has_srq): step = STEP_CLOCK_DATA_BITS ss_bit = self.samplenum elif step == STEP_CLOCK_DATA_BITS: - if self.matched & 0b10: + if self.matched[1]: if clk == 1: # Rising edge on CLK; latch DATA. bits.append(data) @@ -671,10 +743,6 @@ def decode_serial(self, has_clk, has_data_1, has_atn, has_srq): self.handle_eoi_change(False) step = STEP_WAIT_READY_TO_SEND - def check_bit(self, d): - v = self.matched & (1 << d) - return (v >> d) == 1 - def decode_parallel(self, has_data_n, has_dav, has_atn, has_eoi, has_srq): if False in has_data_n or not has_dav or not has_atn: @@ -687,6 +755,11 @@ def decode_parallel(self, has_data_n, has_dav, has_atn, has_eoi, has_srq): # low signal levels, i.e. won't include the initial falling edge. # Scan for ATN/EOI edges as well (including the trick which works # around initial pin state). + # + # Use efficient edge based wait conditions for most activities, + # though some phases may require individual inspection of each + # sample (think parallel poll in combination with slow sampling). + # # Map low-active physical transport lines to positive logic here, # to simplify logical inspection/decoding of communicated data, # and to avoid redundancy and inconsistency in later code paths. @@ -703,6 +776,14 @@ def decode_parallel(self, has_data_n, has_dav, has_atn, has_eoi, has_srq): if has_ifc: idx_ifc = len(waitcond) waitcond.append({PIN_IFC: 'l'}) + idx_pp_check = None + def add_data_cond(conds): + idx = len(conds) + conds.append({'skip': 1}) + return idx + def del_data_cond(conds, idx): + conds.pop(idx) + return None while True: pins = self.wait(waitcond) pins = self.invert_pins(pins) @@ -711,19 +792,35 @@ def decode_parallel(self, has_data_n, has_dav, has_atn, has_eoi, has_srq): # captures, many edges fall onto the same sample number. So # we process active edges of flags early (before processing # data bits), and inactive edges late (after data got processed). - if idx_ifc is not None and self.check_bit(idx_ifc) and pins[PIN_IFC] == 1: + want_pp_check = False + if idx_ifc is not None and self.matched[idx_ifc] and pins[PIN_IFC] == 1: self.handle_ifc_change(pins[PIN_IFC]) - if idx_eoi is not None and self.check_bit(idx_eoi) and pins[PIN_EOI] == 1: + if idx_eoi is not None and self.matched[idx_eoi] and pins[PIN_EOI] == 1: self.handle_eoi_change(pins[PIN_EOI]) - if self.check_bit(idx_atn) and pins[PIN_ATN] == 1: + want_pp_check = True + if self.matched[idx_atn] and pins[PIN_ATN] == 1: self.handle_atn_change(pins[PIN_ATN]) - if self.check_bit(idx_dav): + want_pp_check = True + if want_pp_check and not idx_pp_check: + pp = self.check_pp() + if pp in ('enter',): + idx_pp_check = add_data_cond(waitcond) + if self.matched[idx_dav]: self.handle_dav_change(pins[PIN_DAV], pins[PIN_DIO1:PIN_DIO8 + 1]) - if self.check_bit(idx_atn) and pins[PIN_ATN] == 0: + if idx_pp_check: + pp = self.check_pp(pins[PIN_DIO1:PIN_DIO8 + 1]) + want_pp_check = False + if self.matched[idx_atn] and pins[PIN_ATN] == 0: self.handle_atn_change(pins[PIN_ATN]) - if idx_eoi is not None and self.check_bit(idx_eoi) and pins[PIN_EOI] == 0: + want_pp_check = True + if idx_eoi is not None and self.matched[idx_eoi] and pins[PIN_EOI] == 0: self.handle_eoi_change(pins[PIN_EOI]) - if idx_ifc is not None and self.check_bit(idx_ifc) and pins[PIN_IFC] == 0: + want_pp_check = True + if idx_pp_check is not None and want_pp_check: + pp = self.check_pp(pins[PIN_DIO1:PIN_DIO8 + 1]) + if pp in ('leave',) and idx_pp_check is not None: + idx_pp_check = del_data_cond(waitcond, idx_pp_check) + if idx_ifc is not None and self.matched[idx_ifc] and pins[PIN_IFC] == 0: self.handle_ifc_change(pins[PIN_IFC]) waitcond[idx_dav][PIN_DAV] = 'e' From 7c9a11f316b33adcb879e59a8f22078192a95553 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:17:01 +0200 Subject: [PATCH 30/42] Update Gray Code decoder --- libsigrokdecode4DSL/decoders/graycode/pd.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/graycode/pd.py b/libsigrokdecode4DSL/decoders/graycode/pd.py index 9303c33a..58301cee 100644 --- a/libsigrokdecode4DSL/decoders/graycode/pd.py +++ b/libsigrokdecode4DSL/decoders/graycode/pd.py @@ -95,12 +95,12 @@ class Decoder(srd.Decoder): ('phase', 'Phase'), ('increment', 'Increment'), ('count', 'Count'), - ('turns', 'Turns'), + ('turn', 'Turn'), ('interval', 'Interval'), ('average', 'Average'), ('rpm', 'Rate'), ) - annotation_rows = tuple((u, v, (i,)) for i, (u, v) in enumerate(annotations)) + annotation_rows = tuple((u + 's', v + 's', (i,)) for i, (u, v) in enumerate(annotations)) def __init__(self): self.reset() @@ -148,8 +148,7 @@ def decode(self): self.ENCODER_STEPS = 1 << self.num_channels - (d0, d1, d2, d3, d4, d5, d6, d7) = self.wait() - startbits = (d0, d1, d2, d3, d4, d5, d6, d7) + startbits = self.wait() curtime = self.samplenum self.turns.set(self.samplenum, 0) @@ -158,8 +157,7 @@ def decode(self): while True: prevtime = curtime - (d0, d1, d2, d3, d4, d5, d6, d7) = self.wait([{i: 'e'} for i in range(self.num_channels)]) - bits = (d0, d1, d2, d3, d4, d5, d6, d7) + bits = self.wait([{i: 'e'} for i in range(self.num_channels)]) curtime = self.samplenum oldcount = self.count.get() From 6d9661f1eff62b54347e41ea22209aa8470dea1c Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:18:03 +0200 Subject: [PATCH 31/42] Update IR IRMP decoder --- .../decoders/ir_irmp/irmp_library.py | 69 ++++++++++++++----- libsigrokdecode4DSL/decoders/ir_irmp/pd.py | 40 ++++++----- 2 files changed, 71 insertions(+), 38 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/ir_irmp/irmp_library.py b/libsigrokdecode4DSL/decoders/ir_irmp/irmp_library.py index 5ec65222..a1bc2583 100644 --- a/libsigrokdecode4DSL/decoders/ir_irmp/irmp_library.py +++ b/libsigrokdecode4DSL/decoders/ir_irmp/irmp_library.py @@ -2,6 +2,7 @@ ## This file is part of the libsigrokdecode project. ## ## Copyright (C) 2019 Rene Staffen +## Copyright (C) 2020-2021 Gerhard Sittig ## ## 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 @@ -61,12 +62,24 @@ def _library_setup_api(self): Lookup the C library's API routines. Declare their prototypes. ''' - if not self._lib: - return False - self._lib.irmp_get_sample_rate.restype = ctypes.c_uint32 self._lib.irmp_get_sample_rate.argtypes = [] + self._lib.irmp_instance_alloc.restype = ctypes.c_void_p + self._lib.irmp_instance_alloc.argtypes = [] + + self._lib.irmp_instance_free.restype = None + self._lib.irmp_instance_free.argtypes = [ ctypes.c_void_p, ] + + self._lib.irmp_instance_id.restype = ctypes.c_size_t + self._lib.irmp_instance_id.argtypes = [ ctypes.c_void_p, ] + + self._lib.irmp_instance_lock.restype = ctypes.c_int + self._lib.irmp_instance_lock.argtypes = [ ctypes.c_void_p, ctypes.c_int, ] + + self._lib.irmp_instance_unlock.restype = None + self._lib.irmp_instance_unlock.argtypes = [ ctypes.c_void_p, ] + self._lib.irmp_reset_state.restype = None self._lib.irmp_reset_state.argtypes = [] @@ -85,6 +98,7 @@ def _library_setup_api(self): # Create a result buffer that's local to the library instance. self._data = self.ResultData() + self._inst = None return True @@ -93,30 +107,47 @@ def __init__(self): Create a library instance. ''' - # Only create a working instance for the first invocation. - # Degrade all other instances, make them fail "late" during - # execution, so that users will see the errors. - self._lib = None - self._data = None - if IrmpLibrary.__usable_instance is None: - filename = self._library_filename() - self._lib = ctypes.cdll.LoadLibrary(filename) - self._library_setup_api() - IrmpLibrary.__usable_instance = self + filename = self._library_filename() + self._lib = ctypes.cdll.LoadLibrary(filename) + self._library_setup_api() + + def __del__(self): + ''' + Release a disposed library instance. + ''' + + if self._inst: + self._lib.irmp_instance_free(self._inst) + self._inst = None + + def __enter__(self): + ''' + Enter a context (lock management). + ''' + + if self._inst is None: + self._inst = self._lib.irmp_instance_alloc() + self._lib.irmp_instance_lock(self._inst, 1) + return self + + def __exit__(self, extype, exvalue, trace): + ''' + Leave a context (lock management). + ''' + + self._lib.irmp_instance_unlock(self._inst) + return False + + def client_id(self): + return self._lib.irmp_instance_id(self._inst) def get_sample_rate(self): - if not self._lib: - return None return self._lib.irmp_get_sample_rate() def reset_state(self): - if not self._lib: - return None self._lib.irmp_reset_state() def add_one_sample(self, level): - if not self._lib: - raise Exception("IRMP library limited to a single instance.") if not self._lib.irmp_add_one_sample(int(level)): return False self._lib.irmp_get_result_data(ctypes.byref(self._data)) diff --git a/libsigrokdecode4DSL/decoders/ir_irmp/pd.py b/libsigrokdecode4DSL/decoders/ir_irmp/pd.py index 979c1e01..b8df8190 100644 --- a/libsigrokdecode4DSL/decoders/ir_irmp/pd.py +++ b/libsigrokdecode4DSL/decoders/ir_irmp/pd.py @@ -3,6 +3,7 @@ ## ## Copyright (C) 2014 Gump Yang ## Copyright (C) 2019 Rene Staffen +## Copyright (C) 2020-2021 Gerhard Sittig ## ## 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 @@ -97,7 +98,7 @@ def __init__(self): self.reset() def reset(self): - self.want_reset = True + pass def start(self): self.out_ann = self.register(srd.OUTPUT_ANN) @@ -113,25 +114,26 @@ def decode(self): except Exception as e: txt = e.args[0] raise LibraryError(txt) - if self.irmp: - self.lib_rate = self.irmp.get_sample_rate() - if not self.irmp or not self.lib_rate: - raise LibraryError('Cannot access IRMP library. One instance limit exceeded?') + if not self.irmp: + raise LibraryError('Cannot access IRMP library.') if not self.samplerate: raise SamplerateError('Cannot decode without samplerate.') - if self.samplerate % self.lib_rate: - raise SamplerateError('Capture samplerate must be multiple of library samplerate ({})'.format(self.lib_rate)) - self.rate_factor = int(self.samplerate / self.lib_rate) - if self.want_reset: - self.irmp.reset_state() - self.want_reset = False + lib_rate = self.irmp.get_sample_rate() + if not lib_rate: + raise LibraryError('Cannot determine IRMP library\'s samplerate.') + if self.samplerate % lib_rate: + raise SamplerateError('Capture samplerate must be multiple of library samplerate ({})'.format(lib_rate)) + + self.rate_factor = int(self.samplerate / lib_rate) + active = 0 if self.options['polarity'] == 'active-low' else 1 - self.active = 0 if self.options['polarity'] == 'active-low' else 1 ir, = self.wait() - while True: - if self.active == 1: - ir = 1 - ir - if self.irmp.add_one_sample(ir): - data = self.irmp.get_result_data() - self.putframe(data) - ir, = self.wait([{'skip': self.rate_factor}]) + with self.irmp: + self.irmp.reset_state() + while True: + if active == 1: + ir = 1 - ir + if self.irmp.add_one_sample(ir): + data = self.irmp.get_result_data() + self.putframe(data) + ir, = self.wait([{'skip': self.rate_factor}]) From acd5f6c7ab5bc9a131f131f2b0ff7b52afe0b253 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:23:06 +0200 Subject: [PATCH 32/42] Update IR NEC decoder --- .../decoders/ir_nec/__init__.py | 1 + libsigrokdecode4DSL/decoders/ir_nec/lists.py | 43 ++++ libsigrokdecode4DSL/decoders/ir_nec/pd.py | 214 ++++++++++++------ 3 files changed, 183 insertions(+), 75 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/ir_nec/__init__.py b/libsigrokdecode4DSL/decoders/ir_nec/__init__.py index c361c3dc..c3ab2936 100644 --- a/libsigrokdecode4DSL/decoders/ir_nec/__init__.py +++ b/libsigrokdecode4DSL/decoders/ir_nec/__init__.py @@ -19,6 +19,7 @@ ''' NEC is a pulse-distance based infrared remote control protocol. +See https://www.sbprojects.net/knowledge/ir/nec.php for a description. ''' from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/ir_nec/lists.py b/libsigrokdecode4DSL/decoders/ir_nec/lists.py index 7d47a46d..dbb9288d 100644 --- a/libsigrokdecode4DSL/decoders/ir_nec/lists.py +++ b/libsigrokdecode4DSL/decoders/ir_nec/lists.py @@ -19,7 +19,9 @@ # Addresses/devices. Items that are not listed are reserved/unknown. address = { + 0x00: 'Joy-it SBC-IRC01', 0x40: 'Matsui TV', + 0xEA41: 'Unknown LED Panel', } digits = { @@ -47,4 +49,45 @@ 31: ['Program down', 'P-'], 68: ['AV', 'AV'], }.items())), + + # This is most likely a generic remote control. The PCB + # has space for 16 buttons total, of which not all are + # connected. The PCB is marked "JSY", "XSK-5462", and + # "2014-6-12 JW". It consists of only a single IC, marked + # "BJEC107BNE" or similar. The following buttons are + # marked for the remote control of a LED panel this was + # found in. + 0xEA41: { + 0x10: ['Warmer', 'T+'], + 0x11: ['Colder', 'T-'], + 0x12: ['Brighter', '+'], + 0x13: ['Darker', '-'], + 0x14: ['Off', 'O'], + 0x15: ['On', 'I'], + 0x41: ['Min Brightness', 'Min'], + 0x48: ['Max Brightness', 'Max'], + }, + 0x00: { + 0x45: ['Volume down', 'Vol-'], + 0x46: ['Play/Pause', 'P/P'], + 0x47: ['Volume up', 'Vol+'], + 0x44: ['Setup', 'Set'], + 0x40: ['Up', 'U'], + 0x43: ['Stop / Mode', 'S/M'], + 0x07: ['Left', 'L'], + 0x15: ['Enter', 'E'], + 0x09: ['Right', 'R'], + 0x16: ['0 / 10+', '0'], + 0x19: ['Down', 'D'], + 0x0D: ['Back', 'B'], + 0x0C: ['1', '1'], + 0x18: ['2', '2'], + 0x5E: ['3', '3'], + 0x08: ['4', '4'], + 0x1C: ['5', '5'], + 0x5A: ['6', '6'], + 0x42: ['7', '7'], + 0x52: ['8', '8'], + 0x4A: ['9', '9'], + } } diff --git a/libsigrokdecode4DSL/decoders/ir_nec/pd.py b/libsigrokdecode4DSL/decoders/ir_nec/pd.py index 830892e8..d46d18c3 100644 --- a/libsigrokdecode4DSL/decoders/ir_nec/pd.py +++ b/libsigrokdecode4DSL/decoders/ir_nec/pd.py @@ -18,12 +18,34 @@ ## along with this program; if not, see . ## -import sigrokdecode as srd +from common.srdhelper import bitpack from .lists import * +import sigrokdecode as srd + +# Concentrate all timing constraints of the IR protocol here in a single +# location at the top of the source, to raise awareness and to simplify +# review and adjustment. The tolerance is an arbitrary choice, available +# literature does not mention any. The inter-frame timeout is not a part +# of the protocol, but an implementation detail of this sigrok decoder. +_TIME_TOL = 8 # tolerance, in percent +_TIME_IDLE = 20.0 # inter-frame timeout, in ms +_TIME_LC = 13.5 # leader code, in ms +_TIME_RC = 11.25 # repeat code, in ms +_TIME_ONE = 2.25 # one data bit, in ms +_TIME_ZERO = 1.125 # zero data bit, in ms +_TIME_STOP = 0.562 # stop bit, in ms class SamplerateError(Exception): pass +class Pin: + IR, = range(1) + +class Ann: + BIT, AGC, LONG_PAUSE, SHORT_PAUSE, STOP_BIT, \ + LEADER_CODE, ADDR, ADDR_INV, CMD, CMD_INV, REPEAT_CODE, \ + REMOTE, WARN = range(13) + class Decoder(srd.Decoder): api_version = 3 id = 'ir_nec' @@ -39,8 +61,10 @@ class Decoder(srd.Decoder): ) options = ( {'id': 'polarity', 'desc': 'Polarity', 'default': 'active-low', - 'values': ('active-low', 'active-high')}, + 'values': ('auto', 'active-low', 'active-high')}, {'id': 'cd_freq', 'desc': 'Carrier Frequency', 'default': 0}, + {'id': 'extended', 'desc': 'Extended NEC Protocol', + 'default': 'no', 'values': ('yes', 'no')}, ) annotations = ( ('bit', 'Bit'), @@ -55,13 +79,13 @@ class Decoder(srd.Decoder): ('cmd-inv', 'Command#'), ('repeat-code', 'Repeat code'), ('remote', 'Remote'), - ('warnings', 'Warnings'), + ('warning', 'Warning'), ) annotation_rows = ( - ('bits', 'Bits', (0, 1, 2, 3, 4)), - ('fields', 'Fields', (5, 6, 7, 8, 9, 10)), - ('remote', 'Remote', (11,)), - ('warnings', 'Warnings', (12,)), + ('bits', 'Bits', (Ann.BIT, Ann.AGC, Ann.LONG_PAUSE, Ann.SHORT_PAUSE, Ann.STOP_BIT)), + ('fields', 'Fields', (Ann.LEADER_CODE, Ann.ADDR, Ann.ADDR_INV, Ann.CMD, Ann.CMD_INV, Ann.REPEAT_CODE)), + ('remote-vals', 'Remote', (Ann.REMOTE,)), + ('warnings', 'Warnings', (Ann.WARN,)), ) def putx(self, data): @@ -70,36 +94,44 @@ def putx(self, data): def putb(self, data): self.put(self.ss_bit, self.samplenum, self.out_ann, data) - def putd(self, data): + def putd(self, data, bit_count): name = self.state.title() - d = {'ADDRESS': 6, 'ADDRESS#': 7, 'COMMAND': 8, 'COMMAND#': 9} + d = {'ADDRESS': Ann.ADDR, 'ADDRESS#': Ann.ADDR_INV, + 'COMMAND': Ann.CMD, 'COMMAND#': Ann.CMD_INV} s = {'ADDRESS': ['ADDR', 'A'], 'ADDRESS#': ['ADDR#', 'A#'], 'COMMAND': ['CMD', 'C'], 'COMMAND#': ['CMD#', 'C#']} - self.putx([d[self.state], ['%s: 0x%02X' % (name, data), - '%s: 0x%02X' % (s[self.state][0], data), - '%s: 0x%02X' % (s[self.state][1], data), s[self.state][1]]]) + fmt = '{{}}: 0x{{:0{}X}}'.format(bit_count // 4) + self.putx([d[self.state], [ + fmt.format(name, data), + fmt.format(s[self.state][0], data), + fmt.format(s[self.state][1], data), + s[self.state][1], + ]]) def putstop(self, ss): self.put(ss, ss + self.stop, self.out_ann, - [4, ['Stop bit', 'Stop', 'St', 'S']]) + [Ann.STOP_BIT, ['Stop bit', 'Stop', 'St', 'S']]) def putpause(self, p): self.put(self.ss_start, self.ss_other_edge, self.out_ann, - [1, ['AGC pulse', 'AGC', 'A']]) - idx = 2 if p == 'Long' else 3 - self.put(self.ss_other_edge, self.samplenum, self.out_ann, - [idx, [p + ' pause', '%s-pause' % p[0], '%sP' % p[0], 'P']]) + [Ann.AGC, ['AGC pulse', 'AGC', 'A']]) + idx = Ann.LONG_PAUSE if p == 'Long' else Ann.SHORT_PAUSE + self.put(self.ss_other_edge, self.samplenum, self.out_ann, [idx, [ + '{} pause'.format(p), + '{}-pause'.format(p[0]), + '{}P'.format(p[0]), + 'P', + ]]) def putremote(self): dev = address.get(self.addr, 'Unknown device') - buttons = command.get(self.addr, None) - if buttons is None: - btn = ['Unknown', 'Unk'] - else: - btn = buttons.get(self.cmd, ['Unknown', 'Unk']) - self.put(self.ss_remote, self.ss_bit + self.stop, self.out_ann, - [11, ['%s: %s' % (dev, btn[0]), '%s: %s' % (dev, btn[1]), - '%s' % btn[1]]]) + buttons = command.get(self.addr, {}) + btn = buttons.get(self.cmd, ['Unknown', 'Unk']) + self.put(self.ss_remote, self.ss_bit + self.stop, self.out_ann, [Ann.REMOTE, [ + '{}: {}'.format(dev, btn[0]), + '{}: {}'.format(dev, btn[1]), + '{}'.format(btn[1]), + ]]) def __init__(self): self.reset() @@ -107,22 +139,24 @@ def __init__(self): def reset(self): self.state = 'IDLE' self.ss_bit = self.ss_start = self.ss_other_edge = self.ss_remote = 0 - self.data = self.count = self.active = None + self.data = [] self.addr = self.cmd = None def start(self): self.out_ann = self.register(srd.OUTPUT_ANN) - self.active = 0 if self.options['polarity'] == 'active-low' else 1 def metadata(self, key, value): if key == srd.SRD_CONF_SAMPLERATE: self.samplerate = value - self.tolerance = 0.05 # +/-5% - self.lc = int(self.samplerate * 0.0135) - 1 # 13.5ms - self.rc = int(self.samplerate * 0.01125) - 1 # 11.25ms - self.dazero = int(self.samplerate * 0.001125) - 1 # 1.125ms - self.daone = int(self.samplerate * 0.00225) - 1 # 2.25ms - self.stop = int(self.samplerate * 0.000652) - 1 # 0.652ms + + def calc_rate(self): + self.tolerance = _TIME_TOL / 100 + self.lc = int(self.samplerate * _TIME_LC / 1000) - 1 + self.rc = int(self.samplerate * _TIME_RC / 1000) - 1 + self.dazero = int(self.samplerate * _TIME_ZERO / 1000) - 1 + self.daone = int(self.samplerate * _TIME_ONE / 1000) - 1 + self.stop = int(self.samplerate * _TIME_STOP / 1000) - 1 + self.idle_to = int(self.samplerate * _TIME_IDLE / 1000) - 1 def compare_with_tolerance(self, measured, base): return (measured >= base * (1 - self.tolerance) @@ -135,37 +169,57 @@ def handle_bit(self, tick): elif self.compare_with_tolerance(tick, self.daone): ret = 1 if ret in (0, 1): - self.putb([0, ['%d' % ret]]) - self.data |= (ret << self.count) # LSB-first - self.count = self.count + 1 + self.putb([Ann.BIT, ['{:d}'.format(ret)]]) + self.data.append(ret) self.ss_bit = self.samplenum - def data_ok(self): - ret, name = (self.data >> 8) & (self.data & 0xff), self.state.title() - if self.count == 8: + def data_ok(self, check, want_len): + name = self.state.title() + normal, inverted = bitpack(self.data[:8]), bitpack(self.data[8:]) + valid = (normal ^ inverted) == 0xff + show = inverted if self.state.endswith('#') else normal + is_ext_addr = self.is_extended and self.state == 'ADDRESS' + if is_ext_addr: + normal = bitpack(self.data) + show = normal + valid = True + if len(self.data) == want_len: if self.state == 'ADDRESS': - self.addr = self.data + self.addr = normal if self.state == 'COMMAND': - self.cmd = self.data - self.putd(self.data) + self.cmd = normal + self.putd(show, want_len) self.ss_start = self.samplenum + if is_ext_addr: + self.data = [] + self.ss_bit = self.ss_start = self.samplenum return True - if ret == 0: - self.putd(self.data >> 8) - else: - self.putx([12, ['%s error: 0x%04X' % (name, self.data)]]) - self.data = self.count = 0 + self.putd(show, want_len) + if check and not valid: + warn_show = bitpack(self.data) + self.putx([Ann.WARN, ['{} error: 0x{:04X}'.format(name, warn_show)]]) + self.data = [] self.ss_bit = self.ss_start = self.samplenum - return ret == 0 + return valid def decode(self): if not self.samplerate: raise SamplerateError('Cannot decode without samplerate.') + self.calc_rate() cd_count = None if self.options['cd_freq']: cd_count = int(self.samplerate / self.options['cd_freq']) + 1 - prev_ir = None + prev_ir = None + + if self.options['polarity'] == 'auto': + # Take sample 0 as reference. + curr_level, = self.wait({'skip': 0}) + active = 1 - curr_level + else: + active = 0 if self.options['polarity'] == 'active-low' else 1 + self.is_extended = self.options['extended'] == 'yes' + want_addr_len = 16 if self.is_extended else 8 while True: # Detect changes in the presence of an active input signal. @@ -182,54 +236,64 @@ def decode(self): # active period, but will shift their signal changes by one # carrier period before they get passed to decoding logic. if cd_count: - (cur_ir,) = self.wait([{0: 'e'}, {'skip': cd_count}]) - if (self.matched & (0b1 << 0)): - cur_ir = self.active + (cur_ir,) = self.wait([{Pin.IR: 'e'}, {'skip': cd_count}]) + if self.matched[0]: + cur_ir = active if cur_ir == prev_ir: continue prev_ir = cur_ir self.ir = cur_ir else: - (self.ir,) = self.wait({0: 'e'}) + (self.ir,) = self.wait({Pin.IR: 'e'}) - if self.ir != self.active: - # Save the non-active edge, then wait for the next edge. + if self.ir != active: + # Save the location of the non-active edge (recessive), + # then wait for the next edge. Immediately process the + # end of the STOP bit which completes an IR frame. self.ss_other_edge = self.samplenum - continue + if self.state != 'STOP': + continue - b = self.samplenum - self.ss_bit + # Reset internal state for long periods of idle level. + width = self.samplenum - self.ss_bit + if width >= self.idle_to and self.state != 'STOP': + self.reset() # State machine. if self.state == 'IDLE': - if self.compare_with_tolerance(b, self.lc): + if self.compare_with_tolerance(width, self.lc): self.putpause('Long') - self.putx([5, ['Leader code', 'Leader', 'LC', 'L']]) + self.putx([Ann.LEADER_CODE, ['Leader code', 'Leader', 'LC', 'L']]) self.ss_remote = self.ss_start - self.data = self.count = 0 + self.data = [] self.state = 'ADDRESS' - elif self.compare_with_tolerance(b, self.rc): + elif self.compare_with_tolerance(width, self.rc): self.putpause('Short') self.putstop(self.samplenum) self.samplenum += self.stop - self.putx([10, ['Repeat code', 'Repeat', 'RC', 'R']]) - self.data = self.count = 0 + self.putx([Ann.REPEAT_CODE, ['Repeat code', 'Repeat', 'RC', 'R']]) + self.data = [] self.ss_bit = self.ss_start = self.samplenum elif self.state == 'ADDRESS': - self.handle_bit(b) - if self.count == 8: - self.state = 'ADDRESS#' if self.data_ok() else 'IDLE' + self.handle_bit(width) + if len(self.data) == want_addr_len: + self.data_ok(False, want_addr_len) + self.state = 'COMMAND' if self.is_extended else 'ADDRESS#' elif self.state == 'ADDRESS#': - self.handle_bit(b) - if self.count == 16: - self.state = 'COMMAND' if self.data_ok() else 'IDLE' + self.handle_bit(width) + if len(self.data) == 16: + self.data_ok(True, 8) + self.state = 'COMMAND' elif self.state == 'COMMAND': - self.handle_bit(b) - if self.count == 8: - self.state = 'COMMAND#' if self.data_ok() else 'IDLE' + self.handle_bit(width) + if len(self.data) == 8: + self.data_ok(False, 8) + self.state = 'COMMAND#' elif self.state == 'COMMAND#': - self.handle_bit(b) - if self.count == 16: - self.state = 'STOP' if self.data_ok() else 'IDLE' + self.handle_bit(width) + if len(self.data) == 16: + self.data_ok(True, 8) + self.state = 'STOP' elif self.state == 'STOP': self.putstop(self.ss_bit) self.putremote() From 2dd49d275b1d1a71d201ffa3f9159ad7222016cf Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:23:29 +0200 Subject: [PATCH 33/42] Update IR RC5 decoder --- libsigrokdecode4DSL/decoders/ir_rc5/pd.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/ir_rc5/pd.py b/libsigrokdecode4DSL/decoders/ir_rc5/pd.py index e18a90bf..bbe0ca76 100644 --- a/libsigrokdecode4DSL/decoders/ir_rc5/pd.py +++ b/libsigrokdecode4DSL/decoders/ir_rc5/pd.py @@ -61,13 +61,12 @@ def __init__(self): def reset(self): self.samplerate = None - self.samplenum = None self.edges, self.bits, self.ss_es_bits = [], [], [] self.state = 'IDLE' def start(self): self.out_ann = self.register(srd.OUTPUT_ANN) - self.old_ir = 1 if self.options['polarity'] == 'active-low' else 0 + self.next_edge = 'l' if self.options['polarity'] == 'active-low' else 'h' def metadata(self, key, value): if key == srd.SRD_CONF_SAMPLERATE: @@ -143,11 +142,7 @@ def decode(self): raise SamplerateError('Cannot decode without samplerate.') while True: - (self.ir,) = self.wait() - - # Wait for any edge (rising or falling). - if self.old_ir == self.ir: - continue + (self.ir,) = self.wait({0: self.next_edge}) # State machine. if self.state == 'IDLE': @@ -155,7 +150,7 @@ def decode(self): self.edges.append(self.samplenum) self.bits.append([self.samplenum, bit]) self.state = 'MID1' - self.old_ir = self.ir + self.next_edge = 'l' if self.ir else 'h' continue edge = self.edge_type() if edge == 'e': @@ -184,4 +179,4 @@ def decode(self): self.handle_bits() self.reset_decoder_state() - self.old_ir = self.ir + self.next_edge = 'l' if self.ir else 'h' From 23c424cc7018203f79894f11024ec8ab5cd9b12e Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:23:46 +0200 Subject: [PATCH 34/42] Update IR RC6 decoder --- libsigrokdecode4DSL/decoders/ir_rc6/pd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsigrokdecode4DSL/decoders/ir_rc6/pd.py b/libsigrokdecode4DSL/decoders/ir_rc6/pd.py index bd570173..e195dbd1 100644 --- a/libsigrokdecode4DSL/decoders/ir_rc6/pd.py +++ b/libsigrokdecode4DSL/decoders/ir_rc6/pd.py @@ -146,7 +146,7 @@ def decode(self): (self.ir,) = self.wait(conditions) if len(conditions) == 2: - if self.matched & 0b10: + if self.matched[1]: self.state = 'IDLE' self.edges.append(self.samplenum) From 73d5188a54ae3f09b7522bba02252be4bdbda0a8 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:24:22 +0200 Subject: [PATCH 35/42] Update Jitter decoder --- libsigrokdecode4DSL/decoders/jitter/pd.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/jitter/pd.py b/libsigrokdecode4DSL/decoders/jitter/pd.py index 8ea1aa67..220790ef 100644 --- a/libsigrokdecode4DSL/decoders/jitter/pd.py +++ b/libsigrokdecode4DSL/decoders/jitter/pd.py @@ -51,13 +51,13 @@ class Decoder(srd.Decoder): ) annotations = ( ('jitter', 'Jitter value'), - ('clk_missed', 'Clock missed'), - ('sig_missed', 'Signal missed'), + ('clk_miss', 'Clock miss'), + ('sig_miss', 'Signal miss'), ) annotation_rows = ( - ('jitter', 'Jitter values', (0,)), - ('clk_missed', 'Clock missed', (1,)), - ('sig_missed', 'Signal missed', (2,)), + ('jitter_vals', 'Jitter values', (0,)), + ('clk_misses', 'Clock misses', (1,)), + ('sig_misses', 'Signal misses', (2,)), ) binary = ( ('ascii-float', 'Jitter values as newline-separated ASCII floats'), @@ -181,7 +181,7 @@ def decode(self): raise SamplerateError('Cannot decode without samplerate.') while True: # Wait for a transition on CLK and/or SIG. - (clk, sig) = self.wait([{0: 'e'}, {1: 'e'}]) + clk, sig = self.wait([{0: 'e'}, {1: 'e'}]) # State machine: # For each sample we can move 2 steps forward in the state machine. From a01127c0269e80ed59dfcf8985907d6c5fa2f1f6 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:25:11 +0200 Subject: [PATCH 36/42] Update JTAG EJTAG decoder --- libsigrokdecode4DSL/decoders/jtag_ejtag/pd.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/jtag_ejtag/pd.py b/libsigrokdecode4DSL/decoders/jtag_ejtag/pd.py index f16f0b4e..191526b2 100644 --- a/libsigrokdecode4DSL/decoders/jtag_ejtag/pd.py +++ b/libsigrokdecode4DSL/decoders/jtag_ejtag/pd.py @@ -18,7 +18,7 @@ ## import sigrokdecode as srd -from common.srdhelper import bin2int +from common.srdhelper import bin2int, SrdIntEnum class Instruction(object): IDCODE = 0x01 @@ -53,7 +53,7 @@ class ControlReg(object): PRACC = (1 << 18) PRNW = (1 << 19) -class Ann(object): +class Ann(SrdIntEnum): INSTRUCTION = 0 REGISTER = 1 CONTROL_FIELD_IN = 10 @@ -207,10 +207,10 @@ class Decoder(srd.Decoder): ) annotation_rows = ( ('instructions', 'Instructions', (0,)), - ('regs', 'Registers', regs_items['rows_range']), ('control_fields_in', 'Control fields in', (10,)), ('control_fields_out', 'Control fields out', (11,)), - ('pracc', 'PrAcc', (12,)), + ('regs', 'Registers', regs_items['rows_range']), + ('pracc-vals', 'PrAcc', (12,)), ) def __init__(self): From f5fa68ca96bac9256e3de156dcb2929b7b6a7a13 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:26:16 +0200 Subject: [PATCH 37/42] Update LFast decoder --- libsigrokdecode4DSL/decoders/lfast/pd.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/lfast/pd.py b/libsigrokdecode4DSL/decoders/lfast/pd.py index bd4c8ec4..7476e59a 100644 --- a/libsigrokdecode4DSL/decoders/lfast/pd.py +++ b/libsigrokdecode4DSL/decoders/lfast/pd.py @@ -256,15 +256,11 @@ def handle_sleepbit(self): self.put_payload() def decode(self): - bMoreMatch = False - while True: if self.timeout == 0: rising_edge, = self.wait({0: 'e'}) - bMoreMatch = False else: rising_edge, = self.wait([{0: 'e'}, {'skip': self.timeout}]) - bMoreMatch = True # If this is the first edge, we only update ss if self.ss == 0: @@ -276,7 +272,7 @@ def decode(self): self.es = self.samplenum # Check for the sleep bit if this is a timeout condition - if bMoreMatch and self.matched & 0b10 == 0b10: + if (len(self.matched) == 2) and self.matched[1]: rising_edge = ~rising_edge if self.state == state_sync: self.reset() @@ -335,5 +331,5 @@ def decode(self): # If we got here when a timeout occurred, we have processed all null # bits that we could and should reset now to find the next packet - if bMoreMatch and self.matched & 0b10 == 0b10: + if (len(self.matched) == 2) and self.matched[1]: self.reset() From 4c1d709b42ce43b722baf272df139e6a53bda7d5 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:26:53 +0200 Subject: [PATCH 38/42] Update LIN decoder --- libsigrokdecode4DSL/decoders/lin/__init__.py | 56 +-- libsigrokdecode4DSL/decoders/lin/pd.py | 487 ++++++++++--------- 2 files changed, 275 insertions(+), 268 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/lin/__init__.py b/libsigrokdecode4DSL/decoders/lin/__init__.py index f5b2835f..4e8c5790 100644 --- a/libsigrokdecode4DSL/decoders/lin/__init__.py +++ b/libsigrokdecode4DSL/decoders/lin/__init__.py @@ -1,28 +1,28 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Stephan Thiele -## -## 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 -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, see . -## - -''' -This decoder stacks on top of the 'uart' PD and decodes the LIN -(Local Interconnect Network) protocol. - -LIN is layered on top of the UART (async serial) protocol, with 8n1 settings. -Bytes are sent LSB-first. -''' - -from .pd import Decoder +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Stephan Thiele +## +## 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 +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see . +## + +''' +This decoder stacks on top of the 'uart' PD and decodes the LIN +(Local Interconnect Network) protocol. + +LIN is layered on top of the UART (async serial) protocol, with 8n1 settings. +Bytes are sent LSB-first. +''' + +from .pd import Decoder diff --git a/libsigrokdecode4DSL/decoders/lin/pd.py b/libsigrokdecode4DSL/decoders/lin/pd.py index a22be37d..11495d11 100644 --- a/libsigrokdecode4DSL/decoders/lin/pd.py +++ b/libsigrokdecode4DSL/decoders/lin/pd.py @@ -1,240 +1,247 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2018 Stephan Thiele -## -## 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 -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, see . -## - -import sigrokdecode as srd - -class LinFsm: - class State: - WaitForBreak = 'WAIT_FOR_BREAK' - Sync = 'SYNC' - Pid = 'PID' - Data = 'DATA' - Checksum = 'CHECKSUM' - Error = 'ERROR' - - def transit(self, target_state): - if not self._transition_allowed(target_state): - return False - self.state = target_state - return True - - def _transition_allowed(self, target_state): - if target_state == LinFsm.State.Error: - return True - return target_state in self.allowed_state[self.state] - - def reset(self): - self.state = LinFsm.State.WaitForBreak - - def __init__(self): - a = dict() - a[LinFsm.State.WaitForBreak] = (LinFsm.State.Sync,) - a[LinFsm.State.Sync] = (LinFsm.State.Pid,) - a[LinFsm.State.Pid] = (LinFsm.State.Data,) - a[LinFsm.State.Data] = (LinFsm.State.Data, LinFsm.State.Checksum) - a[LinFsm.State.Checksum] = (LinFsm.State.WaitForBreak,) - a[LinFsm.State.Error] = (LinFsm.State.Sync,) - self.allowed_state = a - - self.state = None - self.reset() - -class Decoder(srd.Decoder): - api_version = 3 - id = 'lin' - name = 'LIN' - longname = 'Local Interconnect Network' - desc = 'Local Interconnect Network (LIN) protocol.' - license = 'gplv2+' - inputs = ['uart'] - outputs = [] - tags = ['Automotive'] - options = ( - {'id': 'version', 'desc': 'Protocol version', 'default': 2, 'values': (1, 2)}, - ) - annotations = ( - ('data', 'LIN data'), - ('control', 'Protocol info'), - ('error', 'Error descriptions'), - ('inline_error', 'Protocol violations and errors'), - ) - annotation_rows = ( - ('data', 'Data', (0, 1, 3)), - ('error', 'Error', (2,)), - ) - - def __init__(self): - self.reset() - - def reset(self): - self.fsm = LinFsm() - self.lin_header = [] - self.lin_rsp = [] - self.lin_version = None - self.out_ann = None - self.ss_block = None - self.es_block = None - self.done_break = False - - def start(self): - self.out_ann = self.register(srd.OUTPUT_ANN) - self.lin_version = self.options['version'] - - def putx(self, data): - self.put(self.ss_block, self.es_block, self.out_ann, data) - - def wipe_break_null_byte(self, value): - # Upon a break condition a null byte is received which must be ignored. - if self.fsm.state not in (LinFsm.State.WaitForBreak, LinFsm.State.Error): - if len(self.lin_rsp): - value = self.lin_rsp.pop()[2] - else: - self.lin_header.pop() - - if value != 0: - self.fsm.transit(LinFsm.State.Error) - self.handle_error(None) - return False - - return True - - def handle_wait_for_break(self, value): - self.wipe_break_null_byte(value) - - def handle_break(self, value): - if self.fsm.state not in (LinFsm.State.WaitForBreak, LinFsm.State.Error): - if self.wipe_break_null_byte(value): - self.fsm.transit(LinFsm.State.Checksum) - self.handle_checksum() - - self.fsm.reset() - self.fsm.transit(LinFsm.State.Sync) - self.done_break = True - self.putx([1, ['Break condition', 'Break', 'Brk', 'B']]) - - def handle_sync(self, value): - self.fsm.transit(LinFsm.State.Pid) - self.lin_header.append((self.ss_block, self.es_block, value)) - - def handle_pid(self, value): - self.fsm.transit(LinFsm.State.Data) - self.lin_header.append((self.ss_block, self.es_block, value)) - - def handle_data(self, value): - self.lin_rsp.append((self.ss_block, self.es_block, value)) - - def handle_checksum(self): - sync = self.lin_header.pop(0) if len(self.lin_header) else None - - self.put(sync[0], sync[1], self.out_ann, [0, ['Sync', 'S']]) - - if sync[2] != 0x55: - self.put(sync[0], sync[1], self.out_ann, - [2, ['Sync is not 0x55', 'Not 0x55', '!= 0x55']]) - - pid = self.lin_header.pop(0) if len(self.lin_header) else None - checksum = self.lin_rsp.pop() if len(self.lin_rsp) else None - - if pid: - id_ = pid[2] & 0x3F - parity = pid[2] >> 6 - - expected_parity = self.calc_parity(pid[2]) - parity_valid = parity == expected_parity - - if not parity_valid: - self.put(pid[0], pid[1], self.out_ann, [2, ['P != %d' % expected_parity]]) - - ann_class = 0 if parity_valid else 3 - self.put(pid[0], pid[1], self.out_ann, [ann_class, [ - 'ID: %02X Parity: %d (%s)' % (id_, parity, 'ok' if parity_valid else 'bad'), - 'ID: 0x%02X' % id_, 'I: %d' % id_ - ]]) - - if len(self.lin_rsp): - checksum_valid = self.checksum_is_valid(pid[2], self.lin_rsp, checksum[2]) - - for b in self.lin_rsp: - self.put(b[0], b[1], self.out_ann, [0, ['Data: 0x%02X' % b[2], 'D: 0x%02X' % b[2]]]) - - ann_class = 0 if checksum_valid else 3 - self.put(checksum[0], checksum[1], self.out_ann, - [ann_class, ['Checksum: 0x%02X' % checksum[2], 'Checksum', 'Chk', 'C']]) - - if not checksum_valid: - self.put(checksum[0], checksum[1], self.out_ann, [2, ['Checksum invalid']]) - else: - pass # No response. - - self.lin_header.clear() - self.lin_rsp.clear() - - def handle_error(self, dummy): - self.putx([3, ['Error', 'Err', 'E']]) - - def checksum_is_valid(self, pid, data, checksum): - if self.lin_version == 2: - id_ = pid & 0x3F - - if id_ != 60 and id_ != 61: - checksum += pid - - for d in data: - checksum += d[2] - - carry_bits = int(checksum / 256) - checksum += carry_bits - - return checksum & 0xFF == 0xFF - - @staticmethod - def calc_parity(pid): - id_ = [((pid & 0x3F) >> i) & 1 for i in range(8)] - - p0 = id_[0] ^ id_[1] ^ id_[2] ^ id_[4] - p1 = not (id_[1] ^ id_[3] ^ id_[4] ^ id_[5]) - - return (p0 << 0) | (p1 << 1) - - def end(self): - if self.done_break and len(self.lin_rsp): - self.handle_checksum(); - - def decode(self, ss, es, data): - ptype, rxtx, pdata = data - - self.ss_block, self.es_block = ss, es - - # Ignore all UART packets except the actual data packets or BREAK. - if ptype == 'BREAK': - self.handle_break(pdata) - if ptype != 'DATA': - return - - # We're only interested in the byte value (not individual bits). - pdata = pdata[0] - - # Short LIN overview: - # - Message begins with a BREAK (0x00) for at least 13 bittimes. - # - Break is always followed by a SYNC byte (0x55). - # - Sync byte is followed by a PID byte (Protected Identifier). - # - PID byte is followed by 1 - 8 data bytes and a final checksum byte. - - handler = getattr(self, 'handle_%s' % self.fsm.state.lower()) - handler(pdata) +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2018 Stephan Thiele +## +## 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 +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see . +## + +import sigrokdecode as srd + +class LinFsm: + class State: + WaitForBreak = 'WAIT_FOR_BREAK' + Sync = 'SYNC' + Pid = 'PID' + Data = 'DATA' + Checksum = 'CHECKSUM' + Error = 'ERROR' + + def transit(self, target_state): + if not self._transition_allowed(target_state): + return False + self.state = target_state + return True + + def _transition_allowed(self, target_state): + if target_state == LinFsm.State.Error: + return True + return target_state in self.allowed_state[self.state] + + def reset(self): + self.state = LinFsm.State.WaitForBreak + self.uart_idle_count = 0 + + def __init__(self): + a = dict() + a[LinFsm.State.WaitForBreak] = (LinFsm.State.Sync,) + a[LinFsm.State.Sync] = (LinFsm.State.Pid,) + a[LinFsm.State.Pid] = (LinFsm.State.Data,) + a[LinFsm.State.Data] = (LinFsm.State.Data, LinFsm.State.Checksum) + a[LinFsm.State.Checksum] = (LinFsm.State.WaitForBreak,) + a[LinFsm.State.Error] = (LinFsm.State.Sync,) + self.allowed_state = a + + self.state = None + self.uart_idle_count = 0 + self.reset() + +class Decoder(srd.Decoder): + api_version = 3 + id = 'lin' + name = 'LIN' + longname = 'Local Interconnect Network' + desc = 'Local Interconnect Network (LIN) protocol.' + license = 'gplv2+' + inputs = ['uart'] + outputs = [] + tags = ['Automotive'] + options = ( + {'id': 'version', 'desc': 'Protocol version', 'default': 2, 'values': (1, 2)}, + ) + annotations = ( + ('data', 'LIN data'), + ('control', 'Protocol info'), + ('error', 'Error description'), + ('inline_error', 'Protocol violation or error'), + ) + annotation_rows = ( + ('data_vals', 'Data', (0, 1, 3)), + ('errors', 'Errors', (2,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.fsm = LinFsm() + self.lin_header = [] + self.lin_rsp = [] + self.lin_version = None + self.ss_block = None + self.es_block = None + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + self.lin_version = self.options['version'] + + def putx(self, data): + self.put(self.ss_block, self.es_block, self.out_ann, data) + + def wipe_break_null_byte(self, value): + # Upon a break condition a null byte is received which must be ignored. + if self.fsm.state not in (LinFsm.State.WaitForBreak, LinFsm.State.Error): + if len(self.lin_rsp): + value = self.lin_rsp.pop()[2] + else: + self.lin_header.pop() + + if value != 0: + self.fsm.transit(LinFsm.State.Error) + self.handle_error(None) + return False + + return True + + def handle_uart_idle(self): + if self.fsm.state not in (LinFsm.State.WaitForBreak, LinFsm.State.Error): + self.fsm.uart_idle_count += 1 + + if self.fsm.uart_idle_count == 2: + self.fsm.transit(LinFsm.State.Checksum) + self.handle_checksum() + self.fsm.reset() + + def handle_wait_for_break(self, value): + self.wipe_break_null_byte(value) + + def handle_break(self, value): + if self.fsm.state not in (LinFsm.State.WaitForBreak, LinFsm.State.Error): + if self.wipe_break_null_byte(value): + self.fsm.transit(LinFsm.State.Checksum) + self.handle_checksum() + + self.fsm.reset() + self.fsm.transit(LinFsm.State.Sync) + + self.putx([1, ['Break condition', 'Break', 'Brk', 'B']]) + + def handle_sync(self, value): + self.fsm.transit(LinFsm.State.Pid) + self.lin_header.append((self.ss_block, self.es_block, value)) + + def handle_pid(self, value): + self.fsm.transit(LinFsm.State.Data) + self.lin_header.append((self.ss_block, self.es_block, value)) + + def handle_data(self, value): + self.lin_rsp.append((self.ss_block, self.es_block, value)) + + def handle_checksum(self): + sync = self.lin_header.pop(0) if len(self.lin_header) else None + + self.put(sync[0], sync[1], self.out_ann, [0, ['Sync', 'S']]) + + if sync[2] != 0x55: + self.put(sync[0], sync[1], self.out_ann, + [2, ['Sync is not 0x55', 'Not 0x55', '!= 0x55']]) + + pid = self.lin_header.pop(0) if len(self.lin_header) else None + checksum = self.lin_rsp.pop() if len(self.lin_rsp) else None + + if pid: + id_ = pid[2] & 0x3F + parity = pid[2] >> 6 + + expected_parity = self.calc_parity(pid[2]) + parity_valid = parity == expected_parity + + if not parity_valid: + self.put(pid[0], pid[1], self.out_ann, [2, ['P != %d' % expected_parity]]) + + ann_class = 0 if parity_valid else 3 + self.put(pid[0], pid[1], self.out_ann, [ann_class, [ + 'ID: %02X Parity: %d (%s)' % (id_, parity, 'ok' if parity_valid else 'bad'), + 'ID: 0x%02X' % id_, 'I: %d' % id_ + ]]) + + if len(self.lin_rsp): + checksum_valid = self.checksum_is_valid(pid[2], self.lin_rsp, checksum[2]) + + for b in self.lin_rsp: + self.put(b[0], b[1], self.out_ann, [0, ['Data: 0x%02X' % b[2], 'D: 0x%02X' % b[2]]]) + + ann_class = 0 if checksum_valid else 3 + self.put(checksum[0], checksum[1], self.out_ann, + [ann_class, ['Checksum: 0x%02X' % checksum[2], 'Checksum', 'Chk', 'C']]) + + if not checksum_valid: + self.put(checksum[0], checksum[1], self.out_ann, [2, ['Checksum invalid']]) + else: + pass # No response. + + self.lin_header.clear() + self.lin_rsp.clear() + + def handle_error(self, dummy): + self.putx([3, ['Error', 'Err', 'E']]) + + def checksum_is_valid(self, pid, data, checksum): + if self.lin_version == 2: + id_ = pid & 0x3F + + if id_ != 60 and id_ != 61: + checksum += pid + + for d in data: + checksum += d[2] + + carry_bits = int(checksum / 256) + checksum += carry_bits + + return checksum & 0xFF == 0xFF + + @staticmethod + def calc_parity(pid): + id_ = [((pid & 0x3F) >> i) & 1 for i in range(8)] + + p0 = id_[0] ^ id_[1] ^ id_[2] ^ id_[4] + p1 = not (id_[1] ^ id_[3] ^ id_[4] ^ id_[5]) + + return (p0 << 0) | (p1 << 1) + + def decode(self, ss, es, data): + ptype, rxtx, pdata = data + + self.ss_block, self.es_block = ss, es + + # Ignore all UART packets except the actual data packets or BREAK. + if ptype == 'IDLE': + self.handle_uart_idle() + if ptype == 'BREAK': + self.handle_break(pdata) + if ptype != 'DATA': + return + + # We're only interested in the byte value (not individual bits). + pdata = pdata[0] + + # Short LIN overview: + # - Message begins with a BREAK (0x00) for at least 13 bittimes. + # - Break is always followed by a SYNC byte (0x55). + # - Sync byte is followed by a PID byte (Protected Identifier). + # - PID byte is followed by 1 - 8 data bytes and a final checksum byte. + + handler = getattr(self, 'handle_%s' % self.fsm.state.lower()) + handler(pdata) From f826edbc01ec9fdc258bb9f77c30404f7f112ef5 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:27:34 +0200 Subject: [PATCH 39/42] Update LM75 decoder --- libsigrokdecode4DSL/decoders/lm75/pd.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/lm75/pd.py b/libsigrokdecode4DSL/decoders/lm75/pd.py index 14df1b52..d59fa5f4 100644 --- a/libsigrokdecode4DSL/decoders/lm75/pd.py +++ b/libsigrokdecode4DSL/decoders/lm75/pd.py @@ -55,11 +55,11 @@ class Decoder(srd.Decoder): 'values': (9, 10, 11, 12)}, ) annotations = ( - ('celsius', 'Temperature in degrees Celsius'), - ('kelvin', 'Temperature in Kelvin'), - ('text-verbose', 'Human-readable text (verbose)'), - ('text', 'Human-readable text'), - ('warnings', 'Human-readable warnings'), + ('celsius', 'Temperature / °C'), + ('kelvin', 'Temperature / Kelvin'), + ('text-verbose', 'Text (verbose)'), + ('text', 'Text'), + ('warning', 'Warning'), ) def __init__(self): From 3921a7bd02ffd7b373b5bd9a83ff16d48352d151 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:29:04 +0200 Subject: [PATCH 40/42] Update MAPLE Bus decoder --- libsigrokdecode4DSL/decoders/maple_bus/pd.py | 24 ++++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/maple_bus/pd.py b/libsigrokdecode4DSL/decoders/maple_bus/pd.py index 0e4e6043..9c4ad046 100644 --- a/libsigrokdecode4DSL/decoders/maple_bus/pd.py +++ b/libsigrokdecode4DSL/decoders/maple_bus/pd.py @@ -19,6 +19,9 @@ ## import sigrokdecode as srd +from common.srdhelper import SrdIntEnum + +Pin = SrdIntEnum.from_str('Pin', 'SDCKA SDCKB') ann = [ ['Size', 'L'], @@ -143,14 +146,14 @@ def frame_error(self): self.putx([7, ['Frame error', 'F error', 'FE']]) def handle_start(self): - self.wait({0: 'l', 1: 'h'}) + self.wait({Pin.SDCKA: 'l', Pin.SDCKB: 'h'}) self.ss = self.samplenum count = 0 while True: - (sdcka, sdckb) = self.wait([{1: 'f'}, {0: 'r'}]) - if (self.matched & (0b1 << 0)): + sdcka, sdckb = self.wait([{Pin.SDCKB: 'f'}, {Pin.SDCKA: 'r'}]) + if self.matched[0]: count = count + 1 - if (self.matched & (0b1 << 1)): + if self.matched[1]: self.es = self.samplenum if sdckb == 1: if count == 4: @@ -176,16 +179,17 @@ def handle_byte_or_stop(self): countb = 0 self.data = 0 while countb < 4: - (sdcka, sdckb) = self.wait([{0: 'f'}, {1: 'f'}]) + sdcka, sdckb = self.wait([{Pin.SDCKA: 'f'}, {Pin.SDCKB: 'f'}]) self.es = self.samplenum - if (self.matched & (0b1 << 0)): + if self.matched[0]: if counta == countb: self.got_bit(sdckb) counta = counta + 1 elif counta == 1 and countb == 0 and self.data == 0 and sdckb == 0: - self.wait([{0: 'h', 1: 'h'}, {0: 'f'}, {1: 'f'}]) + self.wait([{Pin.SDCKA: 'h', Pin.SDCKB: 'h'}, + {Pin.SDCKA: 'f'}, {Pin.SDCKB: 'f'}]) self.es = self.samplenum - if (self.matched & (0b1 << 0)): + if self.matched[0]: self.got_end() else: self.frame_error() @@ -193,7 +197,7 @@ def handle_byte_or_stop(self): else: self.frame_error() return False - elif (self.matched & (0b1 << 1)): + elif self.matched[1]: if counta == countb + 1: self.got_bit(sdcka) countb = countb + 1 @@ -203,7 +207,7 @@ def handle_byte_or_stop(self): else: self.frame_error() return False - self.wait({0: 'h'}) + self.wait({Pin.SDCKA: 'h'}) self.es = self.samplenum self.got_byte() return True From 8aaaa42fbf879d8f2e85a6d23a67d87af7492fd8 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:29:37 +0200 Subject: [PATCH 41/42] Update MAX7219 decoder --- libsigrokdecode4DSL/decoders/max7219/pd.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/max7219/pd.py b/libsigrokdecode4DSL/decoders/max7219/pd.py index 4f3e4a68..eb26e105 100644 --- a/libsigrokdecode4DSL/decoders/max7219/pd.py +++ b/libsigrokdecode4DSL/decoders/max7219/pd.py @@ -51,9 +51,9 @@ class Decoder(srd.Decoder): outputs = [] tags = ['Display'] annotations = ( - ('register', 'Registers written to the device'), - ('digit', 'Digits displayed on the device'), - ('warnings', 'Human-readable warnings'), + ('register', 'Register write'), + ('digit', 'Digit displayed'), + ('warning', 'Warning'), ) annotation_rows = ( ('commands', 'Commands', (ann_reg, ann_digit)), @@ -75,14 +75,11 @@ def putreg(self, ss, es, reg, value): self.put(ss, es, self.out_ann, [ann_reg, ['%s: %s' % (reg, value)]]) def putdigit(self, ss, es, digit, value): - self.put(ss, es, self.out_ann, [ann_digit, ['Digit %d: {$}' % digit, '@%02X' % value]]) + self.put(ss, es, self.out_ann, [ann_digit, ['Digit %d: %02X' % (digit, value)]]) def putwarn(self, ss, es, message): self.put(ss, es, self.out_ann, [ann_warning, [message]]) - def putwarn_ann(self, ss, es, message): - self.put(ss, es, self.out_ann, [ann_warning, message]) - def decode(self, ss, es, data): ptype, mosi, _ = data @@ -100,7 +97,8 @@ def decode(self, ss, es, data): name, decoder = registers[self.addr] self.putreg(self.addr_start, es, name, decoder(mosi)) else: - self.putwarn_ann(self.addr_start, es,['Unknown register {$}', '@%02X' % self.addr]) + self.putwarn(self.addr_start, es, + 'Unknown register %02X' % (self.addr)) self.pos += 1 elif ptype == 'CS-CHANGE': From 9adb12689986fba98493719be1f3d86d01f820e7 Mon Sep 17 00:00:00 2001 From: Abdelhak Bougouffa Date: Mon, 8 Aug 2022 13:30:21 +0200 Subject: [PATCH 42/42] Update MCS48 decoder --- libsigrokdecode4DSL/decoders/mcs48/pd.py | 26 ++++++++++++++++-------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/libsigrokdecode4DSL/decoders/mcs48/pd.py b/libsigrokdecode4DSL/decoders/mcs48/pd.py index 50216a41..098c6433 100644 --- a/libsigrokdecode4DSL/decoders/mcs48/pd.py +++ b/libsigrokdecode4DSL/decoders/mcs48/pd.py @@ -19,6 +19,10 @@ ## import sigrokdecode as srd +from common.srdhelper import SrdIntEnum + +Ann = SrdIntEnum.from_str('Ann', 'ROMDATA') +Bin = SrdIntEnum.from_str('Bin', 'ROMDATA') class ChannelError(Exception): pass @@ -59,6 +63,10 @@ class Decoder(srd.Decoder): binary = ( ('romdata', 'AAAA:DD'), ) + OFF_ALE, OFF_PSEN = 0, 1 + OFF_DATA_BOT, OFF_DATA_TOP = 2, 10 + OFF_ADDR_BOT, OFF_ADDR_TOP = 10, 14 + OFF_BANK_BOT, OFF_BANK_TOP = 14, 15 def __init__(self): self.reset() @@ -92,28 +100,28 @@ def newdata(self, data): self.data_s = self.samplenum if self.started: anntext = '{:04X}:{:02X}'.format(self.addr, self.data) - self.put(self.addr_s, self.data_s, self.out_ann, [0, [anntext]]) + self.put(self.addr_s, self.data_s, self.out_ann, [Ann.ROMDATA, [anntext]]) bindata = self.addr.to_bytes(2, byteorder='big') bindata += self.data.to_bytes(1, byteorder='big') - self.put(self.addr_s, self.data_s, self.out_bin, [0, bindata]) + self.put(self.addr_s, self.data_s, self.out_bin, [Bin.ROMDATA, bindata]) def decode(self): # Address bits above A11 are optional, and are considered to be A12+. # This logic needs more adjustment when more bank address pins are # to get supported. For now, having just A12 is considered sufficient. - has_bank = self.has_channel(14) + has_bank = self.has_channel(self.OFF_BANK_BOT) bank_pin_count = 1 if has_bank else 0 # Sample address on the falling ALE edge. # Save data on falling edge of PSEN. while True: - (ale, psen, d0, d1, d2, d3, d4, d5, d6, d7, a8, a9, a10, a11, a12) = self.wait([{0: 'f'}, {1: 'r'}]) - data = (d0, d1, d2, d3, d4, d5, d6, d7) - addr = (a8, a9, a10, a11) - bank = (a12, ) + pins = self.wait([{self.OFF_ALE: 'f'}, {self.OFF_PSEN: 'r'}]) + data = pins[self.OFF_DATA_BOT:self.OFF_DATA_TOP] + addr = pins[self.OFF_ADDR_BOT:self.OFF_ADDR_TOP] + bank = pins[self.OFF_BANK_BOT:self.OFF_BANK_TOP] if has_bank: addr += bank[:bank_pin_count] # Handle those conditions (one or more) that matched this time. - if (self.matched & (0b1 << 0)): + if self.matched[0]: self.newaddr(addr, data) - if (self.matched & (0b1 << 1)): + if self.matched[1]: self.newdata(data)