コード例 #1
0
ファイル: pd.py プロジェクト: mrkalePythonApp/tm1638
class Decoder(srd.Decoder):
    """Protocol decoder for 7-segments digital tubes control ``TM1638``."""

    api_version = 3
    id = "tm1638"
    name = "TM1638"
    longname = "Special circuit for LED driver control"
    desc = "Titan Micro Electronics LED drive control special circuit for \
        driving displays with 7-segments digital tubes, two-color LEDs, \
        and keyboard scanning."

    license = "gplv2+"
    inputs = ["tmc"]
    outputs = ["tm1638"]

    annotations = hlp.create_annots({
        "bit": bits,
        "info": info,
    })
    annotation_rows = (
        ("bits", "Bits", tuple(range(AnnBits.RESERVED, AnnBits.ON + 1))),
        ("display", "Display", (AnnInfo.DISPLAY, )),
        ("leds", "LEDchain", (AnnInfo.LEDS, )),
        ("keys", "Keyboard", (AnnInfo.KEYS, )),
        ("warnings", "Warnings", (AnnInfo.WARN, )),
    )

    def __init__(self):
        """Initialize decoder."""
        self.reset()

    def reset(self):
        """Reset decoder and initialize instance variables."""
        # Common parameters
        self.ss = 0  # Start sample
        self.es = 0  # End sample
        self.ssb = 0  # Start sample of an annotation transmission
        self.bits = []  # List of recent processed byte bits
        self.write = None  # Flag about recent R/W command
        self.state = "IDLE"
        # Specific parameters for a device
        self.auto = None  # Flag about current addressing
        self.position = 0  # Processed address position
        self.clear_data()

    def clear_data(self):
        """Clear data cache."""
        self.display = []  # Buffer for displayed chars
        self.leds = []  # Buffer for displayed LEDs
        self.keys = []  # Buffer for pressed keys

    def start(self):
        """Actions before the beginning of the decoding."""
        self.out_ann = self.register(srd.OUTPUT_ANN)

    def putd(self, ss, es, data):
        """Span data output across bit range.

        - Output is an annotation block from the start sample of the first
          bit to the end sample of the last bit.
        """
        self.put(self.bits[ss][1], self.bits[es][2], self.out_ann, data)

    def putr(self, start, end=None):
        """Span reserved bit annotation across bit range bit by bit.

        - Parameters should be considered as a range, so that the end bit
          number is not annotated.
        """
        annots = hlp.compose_annot(bits[AnnBits.RESERVED])
        for bit in range(start, end or (start + 1)):
            self.put(self.bits[bit][1], self.bits[bit][2], self.out_ann,
                     [AnnBits.RESERVED, annots])

    def handle_command(self, data):
        """Detect command and call its handler."""
        mask = 0
        for i in range(CommandBits.MIN, CommandBits.MAX + 1):
            mask |= 1 << i
        cmd = data & mask
        for attr, value in vars(Command).items():
            if not attr.startswith("__") and value == cmd:
                # Bits row - Command bits
                ann = cmd_annot[cmd]
                annots = hlp.compose_annot(bits[ann])
                self.putd(CommandBits.MIN, CommandBits.MAX, [ann, annots])
                # Handler
                fn = getattr(self, "handle_command_{}".format(attr.lower()))
                fn(data & ~mask)

    def handle_command_data(self, data):
        """Process data command."""
        # Bits row - Reserved
        self.putr(DataBits.MODE + 1, CommandBits.MIN)
        # Bits row - Mode bit
        ann = (AnnBits.NORMAL, AnnBits.TEST)[data >> DataBits.MODE & 1]
        annots = hlp.compose_annot(bits[ann])
        self.putd(DataBits.MODE, DataBits.MODE, [ann, annots])
        # Bits row - Addressing bit
        ann = (AnnBits.AUTO, AnnBits.FIXED)[data >> DataBits.ADDR & 1]
        self.auto = (ann == AnnBits.AUTO)
        annots = hlp.compose_annot(bits[ann])
        self.putd(DataBits.ADDR, DataBits.ADDR, [ann, annots])
        # Bits row - Read/Write bit
        self.write = (data >> DataBits.RW & 1 == 0)
        ann = (AnnBits.READ, AnnBits.WRITE)[self.write]
        annots = hlp.compose_annot(bits[ann])
        self.putd(DataBits.RW, DataBits.RW, [ann, annots])
        # Bits row - Prohibited bit
        self.putr(0, DataBits.RW)

    def handle_command_display(self, data):
        """Process display command."""
        # Bits row - Reserved
        self.putr(DisplayBits.SWITCH + 1, CommandBits.MIN)
        # Bits row - Switch bit
        ann = (AnnBits.OFF, AnnBits.ON)[data >> DisplayBits.SWITCH & 1]
        annots = hlp.compose_annot(bits[ann])
        self.putd(DisplayBits.SWITCH, DisplayBits.SWITCH, [ann, annots])
        # Bits row - PWM bits
        mask = 0
        for i in range(DisplayBits.MIN, DisplayBits.MAX + 1):
            mask |= 1 << i
        pwm = contrasts[data & mask]
        ann = AnnBits.CONTRAST
        annots = hlp.compose_annot(bits[ann], ann_value=pwm)
        self.putd(DisplayBits.MIN, DisplayBits.MAX, [ann, annots])

    def handle_command_address(self, data):
        """Process address command."""
        # Bits row - Reserved
        self.putr(AddressBits.MAX + 1, CommandBits.MIN)
        # Bits row - Digit bits
        mask = 0
        for i in range(AddressBits.MIN, AddressBits.MAX + 1):
            mask |= 1 << i
        adr = (data & mask) + 1
        self.position = adr  # Start address
        ann = AnnBits.POSITION
        annots = hlp.compose_annot(bits[ann], ann_value=adr)
        self.putd(AddressBits.MIN, AddressBits.MAX, [ann, annots])

    def handle_data(self, data):
        """Detect display unit and call its handler."""
        if self.write:
            sfx = ("led", "digit")[self.position % 2]
            fn = getattr(self, "handle_data_{}".format(sfx.lower()))
        else:
            sfx = "keyboard"
            fn = getattr(self, "handle_data_{}".format(sfx.lower()))
        fn(data)
        if self.auto:
            self.position += 1  # Automatic address adding

    def handle_data_digit(self, data):
        """Process digital tube data."""
        # Bits row - Active segments bits
        for i in range(8):
            if data >> i & 1:
                annots = [segments[i]]
                self.putd(i, i, [AnnBits.DIGIT, annots])
        # Register digit
        mask = data & ~(1 << 7)
        char = Params.UNKNOWN_CHAR
        dp = ""
        if mask in fonts:
            char = fonts[mask]
            if (data >> 7) & 1:
                dp = Params.DP
        self.display.append(char + dp)

    def handle_data_led(self, data):
        """Process LED data."""
        # Bits row - Active LED
        led = Params.LEDOFF
        for i in range(8):
            if data >> i & 1:
                annots = hlp.compose_annot(bits[led_annot[i]])
                self.putd(i, i, [AnnBits.LED, annots])
                led = leds[i]
        # Register LED
        self.leds.append(led)

    def handle_data_keyboard(self, data):
        """Process key scanning data."""
        # Bits row - Pressed keys
        for bit in range(8):
            if data >> bit & 1:
                key = keybits[bit % 4]
                seg = "KS{}".format(2 * self.position + (bit // 4) + 1)
                keytag = "{}-{}".format(key, seg)
                annots = [keytag]
                self.putd(bit, bit, [AnnBits.KEY, annots])
                self.keys.append(keytag)

    def handle_info(self):
        """Process info rows."""
        # Display row
        if self.display:
            ann = AnnInfo.DISPLAY
            val = "{}".format("".join(self.display))
            annots = hlp.compose_annot(info[ann], ann_value=val)
            self.put(self.ssb, self.es, self.out_ann, [ann, annots])
        # LEDchain row
        if self.leds:
            ann = AnnInfo.LEDS
            val = "{}".format("".join(self.leds))
            annots = hlp.compose_annot(info[ann], ann_value=val)
            self.put(self.ssb, self.es, self.out_ann, [ann, annots])
        # Keyboard row
        if self.keys:
            ann = AnnInfo.KEYS
            val = "{}".format(",".join(
                map(lambda key: switches[key], self.keys)))
            annots = hlp.compose_annot(info[ann], ann_value=val)
            self.put(self.ssb, self.es, self.out_ann, [ann, annots])
        self.clear_data()

    def decode(self, ss, es, data):
        """Decode samples provided by parent decoder."""
        cmd, databyte = data
        self.ss, self.es = ss, es

        if cmd == "BITS":
            """Collect packet of bits that belongs to the following command.
            - Packet is in the form of list of bit lists:
                ["BITS", bitlist]
            - Bit list is a list of 3 items list
                [[bitvalue, startsample, endsample], ...]
            - Samples are counted for aquisition sampling frequency.
            - Parent decoder ``tmc``stores individual bits in the list from
              the least significant bit (LSB) to the most significant bit
              (MSB) as it is at representing numbers in computers.
            """
            self.bits = databyte
            return

        # State machine
        if self.state == "IDLE":
            """Wait for new transmission."""
            if cmd != "START":
                return
            self.ssb = self.ss
            self.state = "REGISTER COMMAND"

        elif self.state == "REGISTER COMMAND":
            """Process command register."""
            if cmd == "COMMAND":
                self.handle_command(databyte)
                self.state = "REGISTER DATA"
            elif cmd == "STOP":
                self.state = "IDLE"

        elif self.state == "REGISTER DATA":
            """Process data register."""
            if cmd == "DATA":
                self.handle_data(databyte)
            elif cmd == "STOP":
                self.handle_info()
                self.state = "IDLE"
コード例 #2
0
ファイル: pd.py プロジェクト: mrkalePythonApp/bh1750
class Decoder(srd.Decoder):
    """Protocol decoder for digital ambient light sensor ``BH1750``."""

    api_version = 3
    id = "bh1750"
    name = "BH1750"
    longname = "Digital ambient light sensor BH1750"
    desc = "Digital 16bit Serial Output Type Ambient Light Sensor IC."
    license = "gplv2+"
    inputs = ["i2c"]
    outputs = ["bh1750"]

    options = (
        {
            "id": "radix",
            "desc": "Number format",
            "default": "Hex",
            "values": ("Hex", "Dec", "Oct", "Bin")
        },
        {
            "id": "params",
            "desc": "Datasheet parameter used",
            "default": "Typical",
            "values": ("Typical", "Maximal", "Minimal")
        },
    )

    annotations = hlp.create_annots({
        "addr": addresses,
        "reg": registers,
        "bit": bits,
        "info": info,
    })
    annotation_rows = (
        ("bits", "Bits", (AnnBits.RESERVED, AnnBits.DATA)),
        ("regs", "Registers", tuple(range(AnnAddrs.GND, AnnRegs.DATA + 1))),
        ("info", "Info", tuple(range(AnnInfo.CHECK, AnnInfo.MTIME + 1))),
        ("warnings", "Warnings", (AnnInfo.WARN, AnnInfo.BADADD)),
    )

    def __init__(self):
        """Initialize decoder."""
        self.reset()

    def reset(self):
        """Reset decoder and initialize instance variables."""
        # Common parameters for I2C sampling
        self.ss = 0  # Start sample
        self.es = 0  # End sample
        self.ssb = 0  # Start sample of an annotation transmission block
        self.write = None  # Flag about recent write action
        self.state = "IDLE"
        # Specific parameters for a device
        self.addr = Address.GND  # Slave address
        self.reg = Register.PWRDOWN  # Processed register
        self.mode = Register.MCHIGH  # Measurement mode
        self.mtreg = Params.MTREG_TYP  # MTreg default value
        self.clear_data()

    def clear_data(self):
        """Clear data cache."""
        self.ssd = 0  # Start sample of an annotation data block
        self.bytes = []  # List of recent processed bytes
        self.bits = []  # List of recent processed byte bits

    def start(self):
        """Actions before the beginning of the decoding."""
        self.out_ann = self.register(srd.OUTPUT_ANN)

    def putd(self, sb, eb, data):
        """Span data output across bit range.

        - Because bits are order with MSB first, the output is an annotation
          block from the last sample of the start bit (sb) to the first sample
          of the end bit (eb).
        - The higher bit the lower sample number.
        """
        self.put(self.bits[eb][1], self.bits[sb][2], self.out_ann, data)

    def putb(self, sb, eb=None, ann=AnnBits.RESERVED):
        """Span special bit annotation across bit range bit by bit.

        Arguments
        ---------
        sb : integer
            Number of the annotated start bit counting from 0.
        eb : integer
            Number of the end bit right after the last annotated bit
            counting from 0. If none value is provided, the method uses
            start value increased by 1, so that just the first bit will be
            annotated.
        ann : integer
            Index of the special bit's annotation in the annotations list
            `bits`. Default value is for reserved bit.

        """
        annots = hlp.compose_annot(bits[ann])
        for bit in range(sb, eb or (sb + 1)):
            self.put(self.bits[bit][1], self.bits[bit][2], self.out_ann,
                     [ann, annots])

    def check_addr(self, addr_slave):
        """Check correct slave address."""
        if addr_slave in (Address.GND, Address.VCC):
            return True
        ann = AnnInfo.BADADD
        val = hlp.format_data(self.addr, self.options["radix"])
        annots = hlp.compose_annot(info[ann], ann_value=val)
        self.put(self.ss, self.es, self.out_ann, [ann, annots])
        return False

    def calculate_sensitivity(self):
        """Calculate measurement light sensitivity in lux per count."""
        accuracy = prm_map_accuracy[self.options["params"]]
        sensitivity = 1 / accuracy * Params.MTREG_TYP / self.mtreg  # lux/count
        if self.mode in [Register.MCHIGH2, Register.MOHIGH2]:
            sensitivity /= 2
        return sensitivity

    def calculate_light(self, rawdata):
        """Calculate ambient light.

        Arguments
        ---------
        rawdata : int
            Content of the illuminance data register.

        Returns
        -------
        float
            Ambient light in lux.

        """
        light = rawdata * self.calculate_sensitivity()
        return light

    def collect_data(self, databyte):
        """Collect data byte to a data cache."""
        if self.bytes:
            self.bytes.insert(0, databyte)
        else:
            self.ssd = self.ss
            self.bytes.append(databyte)

    def handle_addr(self):
        """Process slave address."""
        if not self.bytes:
            return
        # Registers row
        self.addr = self.bytes[0]
        ann = addr_annots[self.addr]
        annots = hlp.compose_annot(addresses[ann])
        self.put(self.ss, self.es, self.out_ann, [ann, annots])
        self.clear_data()

    def handle_reg(self):
        """Process slave register and call its handler."""
        if not (self.bytes and self.write):
            return
        self.reg = self.bytes[0]
        # Handle measurement time registers
        mask_mthigh = ~((1 << (MTregHighBits.MAX + 1)) - 1)
        if (self.reg & mask_mthigh) == Register.MTHIGH:
            self.handle_mtreg_high()
            return
        mask_mtlow = ~((1 << (MTregLowBits.MAX + 1)) - 1)
        if (self.reg & mask_mtlow) == Register.MTLOW:
            self.handle_mtreg_low()
            return
        # Detect measurement mode registers
        if self.reg in range(Register.MCHIGH, Register.MOLOW + 1):
            self.mode = self.reg
        # Registers row
        ann = reg_annots[self.reg]
        annots = hlp.compose_annot(registers[ann])
        self.put(self.ssd, self.es, self.out_ann, [ann, annots])
        self.clear_data()

    def handle_mtreg_high(self):
        """Process measurement time register with high bits."""
        mask = (1 << (MTregLowBits.MAX + 1)) - 1
        self.mtreg &= mask  # Clear high bits
        mtreg = (self.reg << (MTregLowBits.MAX + 1)) & 0xff
        self.mtreg |= mtreg
        self.reg = Register.MTHIGH
        # Bits row - high bits
        bit_min = MTregHighBits.MIN
        bit_max = MTregHighBits.MAX + 1
        self.putb(bit_min, bit_max, AnnBits.DATA)
        # Registers row
        ann = AnnRegs.MTHIGH
        annots = hlp.compose_annot(registers[ann])
        self.put(self.ssd, self.es, self.out_ann, [ann, annots])
        self.clear_data()

    def handle_mtreg_low(self):
        """Process measurement time register with low bits."""
        mask = (1 << (MTregLowBits.MAX + 1)) - 1
        self.mtreg &= ~mask  # Clear low bits
        mtreg = self.reg & mask
        self.mtreg |= mtreg
        self.reg = Register.MTLOW
        # Bits row - low bits
        bit_min = MTregLowBits.MIN
        bit_max = MTregLowBits.MAX + 1
        self.putb(bit_min, bit_max, AnnBits.DATA)
        # Registers row
        ann = AnnRegs.MTLOW
        annots = hlp.compose_annot(registers[ann])
        self.put(self.ssd, self.es, self.out_ann, [ann, annots])
        self.clear_data()

    def handle_nodata(self):
        """Process transmission without any data."""
        # Info row
        ann = AnnInfo.CHECK
        annots = hlp.compose_annot(info[ann])
        self.put(self.ssb, self.es, self.out_ann, [ann, annots])

    def handle_data(self):
        """Process read data."""
        if self.write:
            # Info row
            if self.reg in [Register.MTHIGH, Register.MTLOW]:
                ann = AnnInfo.MTREG
                val = hlp.format_data(self.mtreg, self.options["radix"])
                annots = hlp.compose_annot(info[ann], ann_value=val)
                self.put(self.ssb, self.es, self.out_ann, [ann, annots])
            if self.reg in range(Register.MCHIGH, Register.MOLOW + 1):
                ann = AnnInfo.SENSE
                val = "{:.2f}".format(self.calculate_sensitivity())
                unit = " {}/cnt".format(Params.UNIT_LIGHT)
                annots = hlp.compose_annot(info[ann],
                                           ann_value=val,
                                           ann_unit=unit)
                self.put(self.ssb, self.es, self.out_ann, [ann, annots])
        else:
            regword = (self.bytes[1] << 8) + self.bytes[0]
            # Registers row
            ann = AnnRegs.DATA
            annots = hlp.compose_annot(registers[ann])
            self.put(self.ssd, self.es, self.out_ann, [ann, annots])
            # # Info row
            ann = AnnInfo.LIGHT
            val = "{:.2f}".format(self.calculate_light(regword))
            unit = " {}".format(Params.UNIT_LIGHT)
            annots = hlp.compose_annot(info[ann], ann_value=val, ann_unit=unit)
            self.put(self.ssb, self.es, self.out_ann, [ann, annots])
        self.clear_data()

    def decode(self, ss, es, data):
        """Decode samples provided by parent decoder."""
        cmd, databyte = data
        self.ss, self.es = ss, es

        if cmd == "BITS":
            """Collect packet of bits that belongs to the following command.
            - Packet is in the form of list of bit lists:
                ["BITS", bitlist]
            - Bit list is a list of 3 items list
                [[bitvalue, startsample, endsample], ...]
            - Samples are counted for aquisition sampling frequency.
            - Parent decoder ``i2c``stores individual bits in the list from
              the least significant bit (LSB) to the most significant bit
              (MSB) as it is at representing numbers in computers, although I2C
              bus transmits data in oposite order with MSB first.
            """
            self.bits = databyte + self.bits
            return

        # State machine
        if self.state == "IDLE":
            """Wait for an I2C transmission."""
            if cmd != "START":
                return
            self.ssb = self.ss
            self.state = "ADDRESS SLAVE"

        elif self.state == "ADDRESS SLAVE":
            """Wait for a slave address."""
            if cmd in ["ADDRESS WRITE", "ADDRESS READ"]:
                if self.check_addr(databyte):
                    self.collect_data(databyte)
                    self.handle_addr()
                    if cmd == "ADDRESS READ":
                        self.write = False
                    elif cmd == "ADDRESS WRITE":
                        self.write = True
                    self.state = "REGISTER ADDRESS"
                else:
                    self.state = "IDLE"

        elif self.state == "REGISTER ADDRESS":
            """Process slave register."""
            if cmd in ["DATA WRITE", "DATA READ"]:
                self.collect_data(databyte)
                self.handle_reg()
                self.state = "REGISTER DATA"
            elif cmd in ["STOP", "START REPEAT"]:
                """End of transmission without any register and data."""
                self.handle_nodata()
                self.state = "IDLE"

        elif self.state == "REGISTER DATA":
            """Process data of a slave register.
            - Individual command or data can end either with repeated start
              condition or with stop condition.
            """
            if cmd in ["DATA WRITE", "DATA READ"]:
                self.collect_data(databyte)
            elif cmd == "START REPEAT":
                """Output read data and continue in transmission."""
                self.handle_data()
                self.ssb = self.ss
                self.state = "ADDRESS SLAVE"
            elif cmd == "STOP":
                """Output formatted string with register data.
                - This is end of an I2C transmission. Start waiting for another
                  one.
                """
                self.handle_data()
                self.state = "IDLE"
コード例 #3
0
class Decoder(srd.Decoder):
    """Protocol decoder for real time clock chip ``DS1307``."""

    api_version = 3
    id = "ds1307"
    name = "DS1307"
    longname = "Dallas DS1307 RTC chip"
    desc = "Real time clock chip protocol decoder, v 1.0.0."
    license = "gplv2+"
    inputs = ["i2c"]
    outputs = ["ds1307"]

    options = ({
        "id": "radix",
        "desc": "Number format",
        "default": "Hex",
        "values": ("Hex", "Dec", "Oct", "Bin")
    }, {
        "id": "start_weekday",
        "desc": "The first day of the week",
        "default": "Monday",
        "values": weekdays
    }, {
        "id": "date_format",
        "desc": "Date format",
        "default": "European",
        "values": ("European", "American", "ANSI")
    })

    annotations = hlp.create_annots({
        "addr": addresses,
        "reg": registers,
        "bit": bits,
        "info": info,
    })
    annotation_rows = (
        ("bits", "Bits", tuple(range(AnnBits.RESERVED, AnnBits.NVRAM + 1))),
        ("regs", "Registers", tuple(range(AnnAddrs.SLAVE, AnnRegs.NVRAM + 1))),
        ("datetime", "Datetime", (AnnInfo.DATETIME, AnnInfo.NVRAM)),
        ("warnings", "Warnings", (AnnInfo.WARN, AnnInfo.BADADD)),
    )

    def __init__(self):
        """Initialize decoder."""
        self.reset()

    def reset(self):
        """Reset decoder and initialize instance variables."""
        # Common parameters for I2C sampling
        self.ss = 0  # Start sample
        self.es = 0  # End sample
        self.ssb = 0  # Start sample of an annotation transmission block
        self.write = True  # Flag about recent write action (default write)
        self.state = "IDLE"
        # Specific parameters for a device
        self.addr = Address.SLAVE
        self.reg = -1
        self.second = -1
        self.minute = -1
        self.hour = -1
        self.weekday = -1
        self.day = -1
        self.month = -1
        self.year = -1
        self.clear_data()

    def clear_data(self):
        """Clear data cache."""
        self.ssd = 0
        self.bits = []
        self.bytes = []

    def start(self):
        """Actions before the beginning of the decoding."""
        self.out_ann = self.register(srd.OUTPUT_ANN)

    def putd(self, sb, eb, data):
        """Span data output across bit range.

        - Because bits are order with MSB first, the output is an annotation
          block from the last sample of the start bit (sb) to the first sample
          of the end bit (eb).
        - The higher bit the lower sample number.
        """
        self.put(self.bits[eb][1], self.bits[sb][2], self.out_ann, data)
        # self.put(self.bits[ss][1], self.bits[es][2], self.out_ann, data)

    def putb(self, sb, eb=None, ann=AnnBits.RESERVED):
        """Span special bit annotation across bit range bit by bit.

        Arguments
        ---------
        sb : integer
            Number of the annotated start bit counting from 0.
        eb : integer
            Number of the end bit right after the last annotated bit
            counting from 0. If none value is provided, the method uses
            start value increased by 1, so that just the first bit will be
            annotated.
        ann : integer
            Index of the special bit's annotation in the annotations list
            `bits`. Default value is for reserved bit.

        """
        annots = hlp.compose_annot(bits[ann])
        for bit in range(sb, eb or (sb + 1)):
            self.put(self.bits[bit][1], self.bits[bit][2], self.out_ann,
                     [ann, annots])

    def check_addr(self, addr_slave):
        """Check correct slave address."""
        if addr_slave == Address.SLAVE:
            return True
        ann = AnnInfo.BADADD
        val = hlp.format_data(self.addr, self.options["radix"])
        annots = hlp.compose_annot(info[ann], ann_value=val)
        self.put(self.ss, self.es, self.out_ann, [ann, annots])
        return False

    def collect_data(self, databyte):
        """Collect data byte to a data cache."""
        if self.bytes:
            self.bytes.insert(0, databyte)
        else:
            self.ssd = self.ss
            self.bytes.append(databyte)

    def format_rw(self):
        """Format read/write action."""
        act = (AnnInfo.READ, AnnInfo.WRITE)[self.write]
        return info[act]

    def output_datetime(self):
        """Format datetime string and prefix it by recent r/w operation.

        - Applied decoder options for the starting weekday and date format.
        - Datetime parts are numbered in the format string equally to numbering
          of time keeping registers.
        """
        if self.options["date_format"] == "European":
            format_datetime =\
                "{3:s} {4:02d}.{5:02d}.{6:04d} {2:02d}:{1:02d}:{0:02d}"
        elif self.options["date_format"] == "American":
            format_datetime =\
                "{3:s}, {5:02d}/{4:02d}/{6:04d} {2:02d}:{1:02d}:{0:02d}"
        elif self.options["date_format"] == "ANSI":
            format_datetime =\
                "{6:04d}-{4:02d}-{5:02d}T{2:02d}:{1:02d}:{0:02d}"
        else:
            format_datetime = "Unknown format"
        dt_str = format_datetime.format(
            self.second,
            self.minute,
            self.hour,
            weekdays[self.weekday],
            self.day,
            self.month,
            self.year,
        )
        # Info row
        ann = AnnInfo.DATETIME
        val = dt_str
        act = self.format_rw()
        annots = hlp.compose_annot(info[ann], ann_value=val, ann_action=act)
        self.put(self.ssb, self.es, self.out_ann, [ann, annots])

    def handle_address(self):
        """Process slave address."""
        if not self.bytes:
            return
        # Registers row
        ann = AnnAddrs.SLAVE
        annots = hlp.compose_annot(addresses[ann])
        self.put(self.ssd, self.es, self.out_ann, [ann, annots])
        self.clear_data()

    def handle_pointer(self):
        """Process register pointer."""
        # Registers row
        ann = AnnRegs.POINTER
        val = hlp.format_data(self.reg, self.options["radix"])
        act = self.format_rw()
        annots = hlp.compose_annot(registers[ann],
                                   ann_value=val,
                                   ann_action=act)
        self.put(self.ssd, self.es, self.out_ann, [ann, annots])
        self.clear_data()

    def handle_nodata(self):
        """Process transmission without any data."""
        # Info row
        ann = AnnInfo.CHECK
        annots = hlp.compose_annot(info[ann])
        self.put(self.ssb, self.es, self.out_ann, [ann, annots])

    def handle_reg(self):
        """Create name and call corresponding slave registers handler.

        - Honor auto increment of the register at reading.
        - When the address reaches maximal nvram position, it will wrap around
          to address 0.
        """
        reg = self.reg if self.reg < NvRAM.MIN else NvRAM.MAX
        fn = getattr(self, "handle_reg_{:#04x}".format(reg))
        fn(self.bytes[0])
        self.reg += 1  # Address auto increment
        if self.reg > NvRAM.MAX:  # Address rollover
            self.reg = 0
        self.clear_data()

    def handle_reg_0x00(self, databyte):
        """Process seconds (0-59) and Clock halt bit."""
        # Bits row - Clock Halt bit
        ch = databyte >> TimeBits.CH & 1
        ch_l = ("Run", "Halt")[ch]
        ch_s = ch_l[0].upper()
        ann = AnnBits.CH
        val = [ch, ch_l, ch_s]
        annots = hlp.compose_annot(bits[ann], ann_value=val)
        self.putd(TimeBits.CH, TimeBits.CH, [ann, annots])
        # Bits row - Second bits
        self.second = hlp.bcd2int(databyte & ~(1 << TimeBits.CH))
        ann = AnnBits.SECOND
        val = self.second
        annots = hlp.compose_annot(bits[ann], ann_value=val)
        self.putd(0, TimeBits.CH - 1, [ann, annots])
        # Registers row
        ann = AnnRegs.SECOND
        act = self.format_rw()
        annots = hlp.compose_annot(registers[ann], ann_action=act)
        self.put(self.ssd, self.es, self.out_ann, [ann, annots])

    def handle_reg_0x01(self, databyte):
        """Process minutes (0-59)."""
        # Bits row
        self.putb(7)
        self.minute = hlp.bcd2int(databyte & 0x7f)
        ann = AnnBits.MINUTE
        val = self.minute
        annots = hlp.compose_annot(bits[ann], ann_value=val)
        self.putd(0, 6, [ann, annots])
        # Registers row
        ann = AnnRegs.MINUTE
        act = self.format_rw()
        annots = hlp.compose_annot(registers[ann], ann_action=act)
        self.put(self.ssd, self.es, self.out_ann, [ann, annots])

    def handle_reg_0x02(self, databyte):
        """Process hours (1-12+AM/PM or 0-23) and 12/24 hours mode.

        - In case of 12 hours mode convert hours to 24 hours mode to instance
          variable for formatting.
        """
        # Bits row
        self.putb(7)
        mode12h = databyte >> TimeBits.MODE & 1
        if mode12h:
            # Bits row - 12h mode
            ann = AnnBits.MODE
            val = "12h"
            annots = hlp.compose_annot(bits[ann], ann_value=val)
            self.putd(TimeBits.MODE, TimeBits.MODE, [ann, annots])
            # Bits row - AM/PM mode
            pm = databyte >> TimeBits.AMPM & 1
            pm_l = ("AM", "PM")[pm]
            pm_s = pm_l[0].upper()
            ann = AnnBits.AMPM
            val = [pm, pm_l, pm_s]
            annots = hlp.compose_annot(bits[ann], ann_value=val)
            self.putd(TimeBits.AMPM, TimeBits.AMPM, [ann, annots])
            # Bits row - hours
            self.hour = hlp.bcd2int(databyte & 0x1f)
            # Convert to 24h expression
            self.hour %= 12
            if pm:
                self.hour += 12
            ann = AnnBits.HOUR
            val = self.hour
            annots = hlp.compose_annot(bits[ann], ann_value=val)
            self.putd(0, TimeBits.AMPM - 1, [ann, annots])
        else:
            # Bits row - 24h mode
            ann = AnnBits.MODE
            val = "24h"
            annots = hlp.compose_annot(bits[ann], ann_value=val)
            self.putd(TimeBits.MODE, TimeBits.MODE, [ann, annots])
            # Bits row - hours
            self.hour = hlp.bcd2int(databyte & 0x3f)
            ann = AnnBits.HOUR
            val = self.hour
            annots = hlp.compose_annot(bits[ann], ann_value=val)
            self.putd(0, TimeBits.MODE - 1, [ann, annots])
        # Registers row
        ann = AnnRegs.HOUR
        act = self.format_rw()
        annots = hlp.compose_annot(registers[ann], ann_action=act)
        self.put(self.ssd, self.es, self.out_ann, [ann, annots])

    def handle_reg_0x03(self, databyte):
        """Process weekday (1-7).

        - Recalculate weekday in respect to starting weekday option to instance
          variable for formatting.
        """
        # Bits row - reserved
        self.putb(3, 8)
        # Bits row - calculate weekday
        self.weekday = hlp.bcd2int(databyte & 0x07)
        start_weekday_index = 0
        for i, weekday in enumerate(weekdays):
            if weekday == self.options["start_weekday"]:
                start_weekday_index = i
                break
        start_weekday_index += self.weekday - 1
        start_weekday_index %= 7
        self.weekday = start_weekday_index
        weekday = weekdays[self.weekday]
        # Bits row - weekday
        ann = AnnBits.WEEKDAY
        val = weekday
        annots = hlp.compose_annot(bits[ann], ann_value=val)
        self.putd(0, 2, [ann, annots])
        # Registers row
        ann = AnnRegs.WEEKDAY
        act = self.format_rw()
        annots = hlp.compose_annot(registers[ann], ann_action=act)
        self.put(self.ssd, self.es, self.out_ann, [ann, annots])

    def handle_reg_0x04(self, databyte):
        """Process day (1-31)."""
        # Bits row
        self.putb(6, 8)
        self.day = hlp.bcd2int(databyte & 0x3f)
        ann = AnnBits.DAY
        val = self.day
        annots = hlp.compose_annot(bits[ann], ann_value=val)
        self.putd(0, 5, [ann, annots])
        # Registers row
        ann = AnnRegs.DAY
        act = self.format_rw()
        annots = hlp.compose_annot(registers[ann], ann_action=act)
        self.put(self.ssd, self.es, self.out_ann, [ann, annots])

    def handle_reg_0x05(self, databyte):
        """Process month (1-12)."""
        # Bits row
        self.putb(5, 8)
        self.month = hlp.bcd2int(databyte & 0x1f)
        ann = AnnBits.MONTH
        val = months[self.month]
        annots = hlp.compose_annot(bits[ann], ann_value=val)
        self.putd(0, 4, [ann, annots])
        # Registers row
        ann = AnnRegs.MONTH
        act = self.format_rw()
        annots = hlp.compose_annot(registers[ann], ann_action=act)
        self.put(self.ssd, self.es, self.out_ann, [ann, annots])

    def handle_reg_0x06(self, databyte):
        """Process year (0-99).

        - Add 2000 to double digit year number (expect 21st century)
          to instance variable for formatting.
        """
        # Bits row
        self.year = hlp.bcd2int(databyte & 0xff) + 2000
        ann = AnnBits.YEAR
        val = self.year
        annots = hlp.compose_annot(bits[ann], ann_value=val)
        self.putd(0, 7, [ann, annots])
        # Registers row
        ann = AnnRegs.YEAR
        act = self.format_rw()
        annots = hlp.compose_annot(registers[ann], ann_action=act)
        self.put(self.ssd, self.es, self.out_ann, [ann, annots])

    def handle_reg_0x07(self, databyte):
        """Process control register."""
        # Bits row - Reserved bits
        self.putb(2, 4)
        self.putb(5, 7)
        # Bits row - OUT bit
        out = databyte >> ControlBits.OUT & 1
        ann = AnnBits.OUT
        annots = hlp.compose_annot(bits[ann], ann_value=out)
        self.putd(ControlBits.OUT, ControlBits.OUT, [ann, annots])
        # Bits row - SQWE bit
        sqwe = databyte >> ControlBits.SQWE & 1
        sqwe_l = ("dis", "en")[sqwe] + "abled"
        sqwe_s = sqwe_l[0].upper()
        ann = AnnBits.SQWE
        val = [sqwe, sqwe_l, sqwe_s]
        annots = hlp.compose_annot(bits[ann], ann_value=val)
        self.putd(ControlBits.SQWE, ControlBits.SQWE, [ann, annots])
        # Bits row - RS bits
        rate = rates[databyte & 0x03]
        ann = AnnBits.RS0
        val = rate
        unit = Params.UNIT_HZ
        annots = hlp.compose_annot(bits[ann], ann_value=val, ann_unit=unit)
        val //= 1000
        unit = Params.UNIT_KHZ
        annots_add = hlp.compose_annot(bits[ann], ann_value=val, ann_unit=unit)
        annots.extend(annots_add)
        self.putd(ControlBits.RS0, ControlBits.RS1, [ann, annots])
        # Registers row
        ann = AnnRegs.CONTROL
        act = self.format_rw()
        annots = hlp.compose_annot(registers[ann], ann_action=act)
        self.put(self.ssd, self.es, self.out_ann, [ann, annots])

    def handle_reg_0x3f(self, databyte):
        """Process NVRAM."""
        # Bits row
        ann = AnnBits.NVRAM
        val = hlp.format_data(databyte, self.options["radix"])
        annots = hlp.compose_annot(bits[ann], ann_value=val)
        self.putd(0, 7, [ann, annots])
        # Registers row
        ann = AnnRegs.NVRAM
        act = self.format_rw()
        annots = hlp.compose_annot(registers[ann], ann_action=act)
        self.put(self.ssd, self.es, self.out_ann, [ann, annots])

    def decode(self, ss, es, data):
        """Decode samples provided by parent decoder."""
        cmd, databyte = data
        self.ss, self.es = ss, es

        if cmd == "BITS":
            """Collect packet of bits that belongs to the following command.
            - Packet is in the form of list of bit lists:
                ["BITS", [[bit, startsample, endsample], ...]
            - Samples are counted for aquisition sampling frequency.
            - Parent decoder ``i2c``stores individual bits in the list from
              the least significant bit (LSB) to the most significant bit
              (MSB) as it is at representing numbers in computers, although I2C
              bus transmits data in oposite order with MSB first.
            """
            self.bits = databyte + self.bits
            return

        # State machine
        if self.state == "IDLE":
            """Wait for an I2C transmission."""
            if cmd != "START":
                return
            self.ssb = self.ss
            self.state = "ADDRESS SLAVE"

        elif self.state == "ADDRESS SLAVE":
            """Wait for a slave address."""
            if cmd in ["ADDRESS WRITE", "ADDRESS READ"]:
                if self.check_addr(databyte):
                    self.collect_data(databyte)
                    self.handle_address()
                    if cmd == "ADDRESS READ":
                        self.write = False
                        self.state = "REGISTER DATA"
                    elif cmd == "ADDRESS WRITE":
                        self.write = True
                        self.state = "REGISTER ADDRESS"
                else:
                    self.state = "IDLE"

        elif self.state == "REGISTER ADDRESS":
            """Initial slave register"""
            if cmd == "DATA WRITE":
                self.reg = databyte
                self.collect_data(databyte)
                self.handle_pointer()
                self.state = "REGISTER DATA"
            elif cmd == "STOP":
                """Output end of transmission without any register and data."""
                self.handle_nodata()
                self.state = "IDLE"

        elif self.state == "REGISTER DATA":
            """Process slave register"""
            if cmd in ["DATA WRITE", "DATA READ"]:
                self.collect_data(databyte)
                self.handle_reg()
                self.state = "REGISTER DATA"
            elif cmd == "START REPEAT":
                self.state = "ADDRESS SLAVE"
            elif cmd == "STOP":
                """Wait for next transmission."""
                self.output_datetime()
                self.state = "IDLE"
コード例 #4
0
ファイル: pd.py プロジェクト: mrkalePythonApp/tmp102
class Decoder(srd.Decoder):
    """Protocol decoder for digital temperature sensor ``TMP102``."""

    api_version = 3
    id = "tmp102"
    name = "TMP102"
    longname = "Digital temperature sensor TMP102"
    desc = "Low power digital temperature sensor."
    license = "gplv2+"
    inputs = ["i2c"]
    outputs = ["tmp102"]

    options = (
        {
            "id": "radix",
            "desc": "Number format",
            "default": "Hex",
            "values": ("Hex", "Dec", "Oct", "Bin")
        },
        {
            "id": "units",
            "desc": "Temperature unit",
            "default": "Celsius",
            "values": ("Celsius", "Fahrenheit", "Kelvin")
        },
    )

    annotations = hlp.create_annots({
        "addr": addresses,
        "reg": registers,
        "bit": bits,
        "info": info,
    })
    annotation_rows = (
        ("bits", "Bits", tuple(range(AnnBits.RESERVED, AnnBits.OS + 1))),
        ("regs", "Registers", tuple(range(AnnAddrs.GC, AnnRegs.THIGH + 1))),
        ("info", "Info", tuple(range(AnnInfo.GRST, AnnInfo.THIGH + 1))),
        ("warnings", "Warnings", (AnnInfo.WARN, AnnInfo.BADADD)),
    )

    def __init__(self):
        """Initialize decoder."""
        self.reset()

    def reset(self):
        """Reset decoder and initialize instance variables."""
        # Common parameters for I2C sampling
        self.ss = 0  # Start sample
        self.es = 0  # End sample
        self.ssb = 0  # Start sample of an annotation transmission block
        self.write = True  # Flag about recent write action (default write)
        self.state = "IDLE"
        # Specific parameters for a device
        self.addr = Address.GND  # Slave address (default ADD0 grounded)
        self.reg = Register.TEMP  # Processed slave register (default temp)
        self.em = False  # Flag about extended mode (default Normal)
        self.clear_data()

    def clear_data(self):
        """Clear data cache."""
        self.ssd = 0  # Start sample of an annotation data block
        self.bytes = []  # List of recent processed bytes
        self.bits = []  # List of recent processed byte bits

    def start(self):
        """Actions before the beginning of the decoding."""
        self.out_ann = self.register(srd.OUTPUT_ANN)

    def putd(self, sb, eb, data):
        """Span data output across bit range.

        - Because bits are order with MSB first, the output is an annotation
          block from the last sample of the start bit (sb) to the first sample
          of the end bit (eb).
        - The higher bit the lower sample number.
        """
        self.put(self.bits[eb][1], self.bits[sb][2], self.out_ann, data)

    def putb(self, sb, eb=None, ann=AnnBits.RESERVED):
        """Span special bit annotation across bit range bit by bit.

        Arguments
        ---------
        sb : integer
            Number of the annotated start bit counting from 0.
        eb : integer
            Number of the end bit right after the last annotated bit
            counting from 0. If none value is provided, the method uses
            start value increased by 1, so that just the first bit will be
            annotated.
        ann : integer
            Index of the special bit's annotation in the annotations list
            `bits`. Default value is for reserved bit.

        """
        annots = hlp.compose_annot(bits[ann])
        for bit in range(sb, eb or (sb + 1)):
            self.put(self.bits[bit][1], self.bits[bit][2], self.out_ann,
                     [ann, annots])

    def check_addr(self, addr_slave, check_gencall=False):
        """Check correct slave address or general call."""
        if addr_slave in (
                Address.GND,
                Address.VCC,
                Address.SDA,
                Address.SCL,
        ) or not check_gencall or addr_slave == GeneralCall.ADDRESS:
            return True
        ann = AnnInfo.BADADD
        val = hlp.format_data(self.addr, self.options["radix"])
        annots = hlp.compose_annot(info[ann], ann_value=val)
        self.put(self.ss, self.es, self.out_ann, [ann, annots])
        return False

    def calculate_temperature(self, rawdata):
        """Calculate and convert temperature.

        Arguments
        ---------
        rawdata : int
            Content of the temperature, TLOW, or THIGH register.

        Returns
        -------
        tuple: float, string
            Temperature and unit in a scale determined by corresponding decoder
            option.

        """
        if rawdata & (1 << TempBits.EM):
            self.em = True
        # Extended mode (13-bit resolution)
        if self.em:
            rawdata >>= 3
            if rawdata > 0x0fff:
                rawdata |= 0xe000  # 2s complement
        # Normal mode (12-bit resolution)
        else:
            rawdata >>= 4
            if rawdata > 0x07ff:
                rawdata |= 0xf000  # 2s complement
        temperature = rawdata / 16  # Celsius
        if self.options["units"] == "Fahrenheit":
            temperature *= 9 / 5
            temperature += 32
        elif self.options["units"] == "Kelvin":
            temperature += 273.15
        # Measurement unit
        unit = " {}".format(temp_units[self.options["units"]])
        return temperature, unit

    def collect_data(self, databyte):
        """Collect data byte to a data cache."""
        if self.bytes:
            self.bytes.insert(0, databyte)
        else:
            self.ssd = self.ss
            self.bytes.append(databyte)

    def format_rw(self):
        """Format read/write action."""
        act = (AnnInfo.READ, AnnInfo.WRITE)[self.write]
        return info[act]

    def handle_addr(self):
        """Process slave address."""
        if not self.bytes:
            return
        # Registers row
        self.addr = self.bytes[0]
        ann = addr_annots[self.addr]
        annots = hlp.compose_annot(addresses[ann])
        self.put(self.ss, self.es, self.out_ann, [ann, annots])
        self.clear_data()

    def handle_reg(self):
        """Process slave register."""
        if not self.bytes:
            return
        self.reg = self.bytes[0]
        if self.addr == GeneralCall.ADDRESS:
            ann = reg_annots_gc[self.reg]
            act = None
        else:
            ann = reg_annots[self.reg]
            act = info[AnnInfo.SELECT]
        annots = hlp.compose_annot(registers[ann], ann_action=act)
        self.put(self.ss, self.es, self.out_ann, [ann, annots])
        self.clear_data()

    def handle_nodata(self):
        """Process transmission without any data."""
        # Info row
        ann = AnnInfo.CHECK
        annots = hlp.compose_annot(info[ann])
        self.put(self.ssb, self.es, self.out_ann, [ann, annots])

    def handle_data(self):
        """Create name and call corresponding data register handler."""
        fn = getattr(self, "handle_datareg_{:#04x}".format(self.reg))
        dataword = ((self.bytes[1] << 8) + self.bytes[0]) if (self.bytes) \
            else None
        fn(dataword)
        self.clear_data()

    def handle_datareg_0x06(self, dataword):
        """Process general reset register."""
        # Info row
        ann = AnnInfo.GRST
        annots = hlp.compose_annot(info[ann])
        self.put(self.ssb, self.es, self.out_ann, [ann, annots])

    def handle_datareg_0x01(self, dataword):
        """Process configuration register."""
        # Bits row - OS bit - one-shot measurement
        os = dataword >> ConfigBits.OS & 1
        os_l = ("dis", "en")[os] + "abled"
        os_s = os_l[0].upper()
        ann = AnnBits.OS
        annots = hlp.compose_annot(bits[ann], [os, os_l, os_s])
        self.putd(ConfigBits.OS, ConfigBits.OS, [ann, annots])
        # Bits row - R0/R1 bits - converter resolution
        res = resolutions[dataword >> ConfigBits.R0 & 0b11]
        ann = AnnBits.R0
        val = "{}".format(res)
        annots = hlp.compose_annot(bits[ann], ann_value=val, ann_unit="bit")
        self.putd(ConfigBits.R0, ConfigBits.R1, [ann, annots])
        # Bits row - F0/F1 bits - fault queue
        flt = faults[dataword >> ConfigBits.F0 & 0b11]
        ann = AnnBits.F0
        val = "{}".format(flt)
        annots = hlp.compose_annot(bits[ann], ann_value=val)
        self.putd(ConfigBits.F0, ConfigBits.F1, [ann, annots])
        # Bits row - POL bit - polarity, alert active
        pol = dataword >> ConfigBits.POL & 1
        pol_l = ("low", "high")[pol]
        pol_s = pol_l[0].upper()
        ann = AnnBits.POL
        annots = hlp.compose_annot(bits[ann], ann_value=[pol, pol_l, pol_s])
        self.putd(ConfigBits.POL, ConfigBits.POL, [ann, annots])
        # Bits row - TM bit - thermostat mode
        tm = dataword >> ConfigBits.TM & 1
        tm_l = ("comparator", "interrupt")[tm]
        tm_s = tm_l[0].upper()
        ann = AnnBits.TM
        annots = hlp.compose_annot(bits[ann], ann_value=[tm, tm_l, tm_s])
        self.putd(ConfigBits.TM, ConfigBits.TM, [ann, annots])
        # Bits row - SD bit - shutdown mode
        sd = dataword >> ConfigBits.SD & 1
        sd_l = ("dis", "en")[sd] + "abled"
        sd_s = sd_l[0].upper()
        ann = AnnBits.SD
        annots = hlp.compose_annot(bits[ann], ann_value=[sd, sd_l, sd_s])
        self.putd(ConfigBits.SD, ConfigBits.SD, [ann, annots])
        # Bits row - CR0/CR1 bits - conversion rate
        rate = rates[dataword >> ConfigBits.CR0 & 0b11]
        ann = AnnBits.CR0
        annots = hlp.compose_annot(bits[ann], ann_value=rate, ann_unit="Hz")
        self.putd(ConfigBits.CR0, ConfigBits.CR1, [ann, annots])
        # Bits row - AL bit - alert
        al = dataword >> ConfigBits.AL & 1
        al_l = ("", "in")[al ^ pol] + "active"
        al_s = al_l[0].upper()
        ann = AnnBits.AL
        annots = hlp.compose_annot(bits[ann], ann_value=[al, al_l, al_s])
        self.putd(ConfigBits.AL, ConfigBits.AL, [ann, annots])
        # Bits row - EM bit - extended mode
        em = dataword >> ConfigBits.EM & 1
        self.em = bool(em)
        em_l = ("dis", "en")[em] + "abled"
        em_s = em_l[0].upper()
        ann = AnnBits.EM
        annots = hlp.compose_annot(bits[ann], ann_value=[em, em_l, em_s])
        self.putd(ConfigBits.EM, ConfigBits.EM, [ann, annots])
        # Bits row - reserved bits
        for i in range(ConfigBits.EM - 1, -1, -1):
            self.putb(i)
        # Registers row
        ann = AnnRegs.CONF
        val = hlp.format_data(dataword, self.options["radix"])
        annots = hlp.compose_annot(registers[ann], ann_value=val)
        self.put(self.ssd, self.es, self.out_ann, [ann, annots])
        # Info row
        ann = AnnInfo.CONF
        val = info[prm_annots[(Params.CUSTOM,
                               dataword)[dataword == Params.POWERUP]]]
        act = self.format_rw()
        annots = hlp.compose_annot(info[ann], ann_value=val, ann_action=act)
        self.put(self.ssb, self.es, self.out_ann, [ann, annots])

    def handle_datareg_0x00(self, dataword):
        """Process temperature register."""
        temp, unit = self.calculate_temperature(dataword)
        # Bits row - EM bit - extended mode
        em = int(self.em)
        em_l = ("dis", "en")[self.em] + "abled"
        em_s = em_l[0].upper()
        ann = AnnBits.EM
        annots = hlp.compose_annot(bits[ann], [em, em_l, em_s])
        self.putd(TempBits.EM, TempBits.EM, [ann, annots])
        # Bits row - reserved bits
        res_bits = (3, 2)[self.em]
        bit_min = TempBits.RESERVED
        bit_max = bit_min + res_bits
        self.putb(bit_min, bit_max)
        # Bits row - data bits
        data_bits = 8 * len(self.bytes) - 1 - res_bits
        bit_min = bit_max
        bit_max = bit_min + data_bits
        self.putb(bit_min, bit_max, AnnBits.DATA)
        # Registers row
        ann = AnnRegs.TEMP
        val = hlp.format_data(dataword, self.options["radix"])
        annots = hlp.compose_annot(registers[ann], ann_value=val)
        self.put(self.ssd, self.es, self.out_ann, [ann, annots])
        # Info row
        ann = AnnInfo.TEMP
        annots = hlp.compose_annot(info[ann], ann_value=temp, ann_unit=unit)
        self.put(self.ssb, self.es, self.out_ann, [ann, annots])

    def handle_datareg_0x02(self, dataword):
        """Process TLOW register."""
        temp, unit = self.calculate_temperature(dataword)
        # Registers row
        ann = AnnRegs.TLOW
        val = hlp.format_data(dataword, self.options["radix"])
        annots = hlp.compose_annot(registers[ann], ann_value=val)
        self.put(self.ssd, self.es, self.out_ann, [ann, annots])
        # Info row
        ann = AnnInfo.TLOW
        act = self.format_rw()
        annots = hlp.compose_annot(info[ann],
                                   ann_value=temp,
                                   ann_unit=unit,
                                   ann_action=act)
        self.put(self.ssb, self.es, self.out_ann, [ann, annots])

    def handle_datareg_0x03(self, dataword):
        """Process THIGH register."""
        temp, unit = self.calculate_temperature(dataword)
        # Registers row
        ann = AnnRegs.THIGH
        val = hlp.format_data(dataword, self.options["radix"])
        annots = hlp.compose_annot(registers[ann], ann_value=val)
        self.put(self.ssd, self.es, self.out_ann, [ann, annots])
        # Info row
        ann = AnnInfo.THIGH
        act = self.format_rw()
        annots = hlp.compose_annot(info[ann],
                                   ann_value=temp,
                                   ann_unit=unit,
                                   ann_action=act)
        self.put(self.ssb, self.es, self.out_ann, [ann, annots])

    def decode(self, ss, es, data):
        """Decode samples provided by parent decoder."""
        cmd, databyte = data
        self.ss, self.es = ss, es

        if cmd == "BITS":
            """Collect packet of bits that belongs to the following command.
            - Packet is in the form of list of bit lists:
                ["BITS", bitlist]
            - Bit list is a list of 3 items list
                [[bitvalue, startsample, endsample], ...]
            - Samples are counted for aquisition sampling frequency.
            - Parent decoder ``i2c``stores individual bits in the list from
              the least significant bit (LSB) to the most significant bit
              (MSB) as it is at representing numbers in computers, although I2C
              bus transmits data in oposite order with MSB first.
            """
            self.bits = databyte + self.bits
            return

        # State machine
        if self.state == "IDLE":
            """Wait for an I2C transmission."""
            if cmd != "START":
                return
            self.ssb = self.ss
            self.state = "ADDRESS SLAVE"

        elif self.state == "ADDRESS SLAVE":
            """Wait for a slave address."""
            if cmd in ["ADDRESS WRITE", "ADDRESS READ"]:
                if self.check_addr(databyte, check_gencall=True):
                    self.collect_data(databyte)
                    self.handle_addr()
                    if cmd == "ADDRESS READ":
                        self.write = False
                        self.state = "REGISTER DATA"
                    elif cmd == "ADDRESS WRITE":
                        self.write = True
                        self.state = "REGISTER ADDRESS"
                else:
                    self.state = "IDLE"

        elif self.state == "REGISTER ADDRESS":
            """Process slave register"""
            if cmd in ["DATA WRITE", "DATA READ"]:
                self.collect_data(databyte)
                self.handle_reg()
                self.state = "REGISTER DATA"
            elif cmd in ["STOP", "START REPEAT"]:
                """Output end of transmission without any register and data."""
                self.handle_nodata()
                self.state = "IDLE"

        elif self.state == "REGISTER DATA":
            """Process data of a slave register.
            - Individual command or data can end either with repeated start
              condition or with stop condition.
            """
            if cmd in ["DATA WRITE", "DATA READ"]:
                self.collect_data(databyte)
            elif cmd == "START REPEAT":
                self.state = "ADDRESS SLAVE"
            elif cmd == "STOP":
                """Output formatted string with register data.
                - This is end of an I2C transmission. Start waiting for another
                  one.
                """
                self.handle_data()
                self.state = "IDLE"