Hi!

This is the patch for the TCS3472x decoder (I2C protocol). Include captures.

I2C pins are:

 * SDA -> D2
 * SCL -> D3

Sorry for the previous error. I got thing messed up moving files between directories.

Let me know any problem.


Candid Moe

>From 3f8020927b2a1e4e5349626ccf1070d304cb947c Mon Sep 17 00:00:00 2001
From: Candid Moe <candid...@gmail.com>
Date: Wed, 18 Dec 2019 09:11:05 -0300
Subject: [PATCH] Add tcs3472x decoder (second try)

---
 decoders/tcs3472x/__init__.py |  26 ++
 decoders/tcs3472x/pd.py       | 470 ++++++++++++++++++++++++++++++++++
 2 files changed, 496 insertions(+)
 create mode 100644 decoders/tcs3472x/__init__.py
 create mode 100644 decoders/tcs3472x/pd.py

diff --git a/decoders/tcs3472x/__init__.py b/decoders/tcs3472x/__init__.py
new file mode 100644
index 0000000..66ef29f
--- /dev/null
+++ b/decoders/tcs3472x/__init__.py
@@ -0,0 +1,26 @@
+##
+## This file is part of the libsigrokdecode project.
+##
+## Copyright (C) 2019 Candid Moe <candid...@gmail.com>
+##
+## 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 <http://www.gnu.org/licenses/>.
+##
+
+'''
+TCS3472x is a color light-to-digital converter with IR filter.
+
+This decoder is compatible with the whole TCS3472x family.
+'''
+
+from .pd import Decoder
diff --git a/decoders/tcs3472x/pd.py b/decoders/tcs3472x/pd.py
new file mode 100644
index 0000000..6511880
--- /dev/null
+++ b/decoders/tcs3472x/pd.py
@@ -0,0 +1,470 @@
+##
+## This file is part of the libsigrokdecode project.
+##
+## Copyright (C) 2010-2016 Uwe Hermann <u...@hermann-uwe.de>
+##
+## 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 <http://www.gnu.org/licenses/>.
+##
+
+import sigrokdecode as srd
+
+masks = {
+    "PON": 0x01,
+    "AEN": 0x02,
+    "WEN": 0x08,
+    "AIEN": 0x10,
+    "APERS": 0x0F,
+    "AGAIN": 0x03,
+    "AINT": 0x10,
+    "AVALID": 0x01,
+    "WLONG": 0x02,
+}
+
+#   Current tcs3472x register, used for next read/writes
+register_id = 0
+#   Where the command start in decoder
+sequence_start = 0
+#   Where the command end in decoder
+sequence_end = 0
+#   Values read/written under current command
+byte_values = []
+#
+protocol_analyzer = None
+
+
+'''
+    A collection of functions for putting data in the UI.
+    In general, one function for each TCS3472x command.
+'''
+def put_command_0x00():
+    options = "("
+    for value in byte_values:
+        options = "("
+        for mask in ["AIEN", "WEN", "AEN", "PON"]:
+            if not value & masks[mask]:
+                options += "~"
+            options += mask + ","
+    options += ")"
+
+    long_desc = "Register {0:#04x} {1:s}={2:s}".format(register_id, register_set[register_id][0], options)
+    medium_desc = "Register {1:s}={2:s}".format(register_id, register_set[register_id][0], options)
+    short_desc = "{0:s}={1:s}".format(register_set[register_id][0], options)
+    return [0, [long_desc, medium_desc, short_desc]]
+
+
+def put_command_register(reg_id, value):
+    long_desc = "Register {0:#04x} {1:s}={2:d}".format(reg_id, register_set[reg_id][0], value)
+    medium_desc = "Register {1:s}={2:d}".format(reg_id, register_set[reg_id][0], value)
+    short_desc = "{0:s}={1:d}".format(register_set[reg_id][0], value)
+    return [0, [long_desc, medium_desc, short_desc]]
+
+
+def put_command_color(color, value):
+
+    long_desc = "{0:s} Channel={1:d}".format(color, value)
+    medium_desc = "{0:s}={1:d}".format(color, value)
+    short_desc = "{0:s}={1:d}".format(color[0], value)
+
+    return [0, [long_desc, medium_desc, short_desc]]
+
+
+def evaluate_bytes_values():
+    '''
+    Evaluate a 8/16 bit values read from the chip.
+    '''
+    if len(byte_values) == 1:
+        value = byte_values[0]
+    else:
+        value = (byte_values[1] << 8) + byte_values[0]
+    return value
+
+
+def put_command_0x01():
+    return put_command_register(0x01, byte_values[0])
+
+
+def put_command_0x03():
+    return put_command_register(0x03, byte_values[0])
+
+
+def put_command_0x04():
+    return put_command_register(0x04, evaluate_bytes_values())
+
+
+def put_command_0x05():
+    return put_command_register(0x05, evaluate_bytes_values())
+
+
+def put_command_0x06():
+    return put_command_register(0x06, evaluate_bytes_values())
+
+
+def put_command_0x07():
+    return put_command_register(0x06, evaluate_bytes_values())
+
+
+def put_command_0x0C():
+    persistence = byte_values[0] & masks["APERS"]
+    if persistence > 3:
+        persistence = (persistence - 3) * 5
+
+    if persistence == 0:
+        option = "Int after each RGBC cycle"
+    else:
+        option = "Int after {0} out of range".format(persistence)
+
+    long_desc = "Register {0:#04x} {1:s}={2:s}".format(register_id, register_set[register_id][0], option)
+    medium_desc = "Register {1:s}={2:s}".format(register_id, register_set[register_id][0], option)
+    short_desc = "{0:s}={1:s}".format(register_set[register_id][0], option)
+    return [0, [long_desc, medium_desc, short_desc]]
+
+
+def put_command_0x0D():
+    wlong = byte_values[0] & masks["WLONG"]
+    if wlong == 1:
+        option = "Wait 12x"
+    else:
+        option = "Wait 1x"
+
+    long_desc = "Register {0:#04x} {1:s}={2:s}".format(register_id, register_set[register_id][0], option)
+    medium_desc = "Register {1:s}={2:s}".format(register_id, register_set[register_id][0], option)
+    short_desc = "{0:s}={1:s}".format(register_set[register_id][0], option)
+    return [0, [long_desc, medium_desc, short_desc]]
+
+
+def put_command_0x0F():
+    val = byte_values[0] & masks["AGAIN"]
+    again = ["1x", "4x", "16x", "60x"][val]
+
+    long_desc = "Register {0:#04x} {1:s} AGAIN={2:s}".format(register_id, register_set[register_id][0], again)
+    medium_desc = "{1:s} AGAIN ={2:s}".format(register_id, register_set[register_id][0], again)
+    short_desc = "AGAIN={1:s}".format(register_set[register_id][0], again)
+    return [0, [long_desc, medium_desc, short_desc]]
+
+
+def put_command_0x12():
+    if byte_values[0] == 0x44:
+        option = "(TCS34721/TCS34725)"
+    else:
+        if byte_values[0] == 0x4D:
+            option = "(TCS34723/TCS34727)"
+        else:
+            option = "unknown"
+
+    long_desc = "Chip id={0:#04x} {1:s}".format(byte_values[0], option)
+    medium_desc = "Chip id {0:#04x}".format(byte_values[0])
+    short_desc = "{0:#04x}".format(byte_values[0])
+    return [0, [long_desc, medium_desc, short_desc]]
+
+
+def put_command_0x13():
+    option = ""
+
+    if byte_values[0] & masks["AINT"]:
+        option = "CLEAR valid, "
+
+    if byte_values[0] & masks["AVALID"]:
+        option += "Integration complete"
+
+    long_desc = "Register {0:#04x} {1:s}={2:s}".format(register_id, register_set[register_id][0], option)
+    medium_desc = "Register {1:s}={2:s}".format(register_id, register_set[register_id][0], option)
+    short_desc = "{0:s}={1:s}".format(register_set[register_id][0], option)
+
+    return [0, [long_desc, medium_desc, short_desc]]
+
+
+def put_command_0x14():
+    return put_command_color("Clear", evaluate_bytes_values())
+
+
+def put_command_0x15():
+    return put_command_color("Clear", evaluate_bytes_values())
+
+
+def put_command_0x16():
+    return put_command_color("Red", evaluate_bytes_values())
+
+
+def put_command_0x17():
+    return put_command_color("Red", evaluate_bytes_values())
+
+
+def put_command_0x18():
+    return put_command_color("Green", evaluate_bytes_values())
+
+
+def put_command_0x19():
+    return put_command_color("Green", evaluate_bytes_values())
+
+
+def put_command_0x1A():
+    return put_command_color("Blue", evaluate_bytes_values())
+
+
+def put_command_0x1B():
+    return put_command_color("Blue", evaluate_bytes_values())
+
+
+def put_command():
+    if register_id == 0x66:
+        long_desc = "CLEAR channel interrupt clear"
+        medium_desc = "CLEAR interrupt clear"
+        short_desc = "C interrupt clear"
+    else:
+        long_desc = "Select register {0:#04x} {1:s}".format(register_id, register_set[register_id][0])
+        medium_desc = "Register {0:#04x} {1:s}".format(register_id, register_set[register_id][0])
+        short_desc = "{0:#04x}".format(register_id)
+
+    return [0, [long_desc, medium_desc, short_desc]]
+
+
+def command(ss, es, value):
+    '''
+    Start collecting data for a new command
+    '''
+    global sequence_end
+    global register_id
+    global byte_values
+    byte_values = []
+    sequence_end = es
+    register_id = value & 0x7F
+
+    # print("Register {0:#04x} {1:s}".format(register_id, register_set[register_id][0]))
+
+
+def set_sequence_start(ss, es, value):
+    '''
+    Remember where the command start in the sequence
+    '''
+    global sequence_start
+    sequence_start = ss
+
+
+def set_sequence_end(ss, es, value):
+    '''
+    Remember where the command end in the sequence
+    '''
+    global sequence_end
+    sequence_end = es
+
+
+def append_byte_value(ss, es, value):
+    '''
+    Append a data value in the command
+    '''
+    global byte_values
+    byte_values.append(value)
+
+
+def interpret_byte_values(ss, es, value):
+    global register_id
+    global byte_values
+    global protocol_analyzer
+
+    if byte_values:
+        fcn = register_set[register_id][1]
+        protocol_analyzer.put(sequence_start, sequence_end, protocol_analyzer.out_ann, fcn())
+    else:
+        protocol_analyzer.put(sequence_start, sequence_end, protocol_analyzer.out_ann, put_command())
+
+
+register_set = {
+    0x00: ["ENABLE", put_command_0x00],
+    0x01: ["ATIME", put_command_0x01],
+    0x03: ["WTIME", put_command_0x03],
+    0x04: ["AILTL", put_command_0x04],
+    0x05: ["AILTH", put_command_0x05],
+    0x06: ["AIHTL", put_command_0x06],
+    0x07: ["AIHTH", put_command_0x07],
+    0x0C: ["PERS", put_command_0x0C],
+    0x0D: ["CONFIG", put_command_0x0D],
+    0x0F: ["CONTROL", put_command_0x0F],
+    0x12: ["ID", put_command_0x12],
+    0x13: ["STATUS", put_command_0x13],
+    0x14: ["CDATAL", put_command_0x14],
+    0x15: ["CDATAH", put_command_0x15],
+    0x16: ["RDATAL", put_command_0x16],
+    0x17: ["RDATAH", put_command_0x17],
+    0x18: ["GDATAL", put_command_0x18],
+    0x19: ["GDATAH", put_command_0x19],
+    0x1A: ["BDATAL", put_command_0x1A],
+    0x1B: ["BDATAH", put_command_0x1B],
+}
+
+
+class State:
+    '''
+    A state for the state machine
+    '''
+
+    def __init__(self, name):
+        self.name = name
+        self.inputs = []
+        self.action = []
+
+    def set_action(self, action):
+        '''
+        Receive a function that will called when reaching this state.
+        '''
+        self.action.append(action)
+
+    def do_action(self, ss, es, value):
+        '''
+        Execute the registered action for this state.
+        '''
+        for action in self.action:
+            action(ss, es, value)
+
+    def add_input(self, ptype, pnext):
+        '''
+        Define next state upon receiving giving input (ptype)
+        '''
+        self.inputs.append([ptype, pnext])
+
+    def next(self, ptype):
+        '''
+        Return the next state giving the input
+        '''
+        for inp in self.inputs:
+            if inp[0] == ptype:
+                return inp[1]
+
+        return None
+
+    def __str__(self):
+        return self.name
+
+    def __format__(self, format_spec):
+        return self.name
+
+'''
+ State Machine definition.
+'''
+state_initial = State("Initial")
+start = State("Start")
+
+address_write = State("Address Write")
+address_write.set_action(set_sequence_start)
+ack_address_write = State("Ack Address Write")
+ack_data_write = State("Ack Data Write")
+
+address_read = State("Address Read")
+address_read.set_action(set_sequence_start)
+ack_address_read = State("Ack Address Read")
+ack_data_read = State("Ack Data Read")
+nack_data_read = State("Nack Data Read")
+
+wait_ack = State("Wait_Ack")
+data_write_command = State("Command")
+data_write_command.set_action(command)
+data_write = State("Data Write")
+data_write.set_action(set_sequence_end)
+data_write.set_action(append_byte_value)
+
+data_read = State("Data Read")
+data_read.set_action(set_sequence_end)
+data_read.set_action(append_byte_value)
+state_initial.add_input("START", start)
+state_initial.set_action(interpret_byte_values)
+
+start.add_input("ADDRESS WRITE", address_write)
+
+address_write.add_input("ACK", ack_address_write)
+ack_address_write.add_input("DATA WRITE", data_write_command)
+data_write_command.add_input("ACK", ack_data_write)
+data_write.add_input("ACK", ack_data_write)
+ack_data_write.add_input("STOP", state_initial)
+ack_data_write.add_input("DATA WRITE", data_write)
+
+start.add_input("ADDRESS READ",  address_read)
+address_read.add_input("ACK", ack_address_read)
+ack_address_read.add_input("DATA READ", data_read)
+data_read.add_input("ACK", ack_data_read)
+data_read.add_input("NACK", nack_data_read)
+ack_data_read.add_input("STOP", state_initial)
+ack_data_read.add_input("DATA READ", data_read)
+nack_data_read.add_input("STOP", state_initial)
+
+
+class Decoder(srd.Decoder):
+    api_version = 2
+    id = 'tcs3472x'
+    name = 'TCS3472X'
+    longname = 'TCS3472X'
+    desc = 'Color light-to-digital converter with IR filter'
+    license = 'gplv2+'
+    inputs = ['i2c']
+    outputs = []
+
+    options = (
+        {'id': 'device_address',
+         'desc': 'I2C device address',
+          'default': '0x29', 'values': ('0x29', '0x39')},
+    )
+
+    annotations = (
+        ('register', 'Register'),
+    )
+    annotation_rows = (
+        ('register', 'Data', (0,)),
+    )
+
+    def __init__(self):
+        global protocol_analyzer
+        protocol_analyzer = self
+        self.commands = list()
+        self.state = state_initial
+        self.out_ann = None
+        self.out_python = None
+        self.reset()
+
+    def start(self):
+        self.out_ann = self.register(srd.OUTPUT_ANN)
+
+        self.reset()
+
+    def reset(self):
+        self.state = state_initial
+
+    def decode(self, ss, es, data):
+
+        global sequence_start
+        global sequence_end
+        global register_id
+        global register_set
+
+        ptype = data[0]
+        value = data[1]
+
+        if ptype == "BITS":
+            return
+
+#        print(ss, es, ptype, value)
+
+        next_state = self.state.next(ptype)
+
+        # Filter out things not addressed to our chip
+        if next_state == address_write or next_state == address_read:
+            if value != int(self.options["device_address"], 0):
+                next_state = None
+
+        if next_state is None:
+            self.reset()
+        else:
+            old_state = self.state
+            self.state = next_state
+            self.state.do_action(ss, es, value)
+         #   print("State {0:s} -> {1:s} {2:d}, {3:d}".format(old_state, self.state, sequence_start, sequence_end))
+
+
-- 
2.17.1

Attachment: capture.sr
Description: Binary data

Attachment: capture2.sr
Description: Binary data

Attachment: capture3.sr
Description: Binary data

_______________________________________________
sigrok-devel mailing list
sigrok-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sigrok-devel

Reply via email to