#
# Copyright 2018 Ettus Research, a National Instruments Company
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
"""
DS125DF410 driver class

For use with TI's retimer chip
"""

import math
from builtins import object

from usrp_mpm.mpmlog import get_logger

LINE_RATE_PRESETS = {"Ethernet": 0xF6, "CPRI1": 0x36, "CPRI2": 0x46}
ALL_CHANS = range(4)


class DS125DF410(object):
    """
    Driver class for DS125DF410 access.

    Inputs:
    regs_iface : regs_iface bus driver to access device
    parent_log : logger of parent
    """

    # (deemphasis, swing)
    DRIVER_PRESETS = {}

    def __init__(self, regs_iface, parent_log=None):
        self.log = (
            parent_log.getChild("DS125DF410")
            if parent_log is not None
            else get_logger("DS125DF410")
        )
        self.regs_iface = regs_iface
        # Set channel select register to control set
        self.regs_iface.poke8(0xFF, 0)
        # Probe chip ID
        chip_id = self.regs_iface.peek8(0x01)
        assert chip_id == 0xD1
        self.log.debug("Probed DS125DF410 retimer")
        for chan in ALL_CHANS:
            self._set_chan_select(chan)
            # Reset channel registers
            self.regs_iface.poke8(0x00, 0x04)
            # Enable DFE mode
            self.regs_iface.poke8(0x1E, 0xE1)
            self.regs_iface.poke8(0x31, 0x40)

    def _rmw(self, addr, data, mask):
        """Read, modify, write"""
        base = self.regs_iface.peek8(addr) & ~mask
        data = (data & mask) | base
        self.regs_iface.poke8(addr, data)

    def _set_chan_select(self, chan):
        """
        Channel select
        """
        assert chan in ALL_CHANS
        self.regs_iface.poke8(0xFF, chan + 4)

    def set_rate_preset(self, preset, channels=None):
        """
        Set rate preset
        """
        channels = channels or ALL_CHANS
        assert preset in LINE_RATE_PRESETS.keys()
        for chan in channels:
            self._set_chan_select(chan)
            self.regs_iface.poke8(0x2F, LINE_RATE_PRESETS[preset])

    def set_rate(self, rate, channels=None):
        """
        Set rate
        """
        channels = channels or ALL_CHANS
        self.log.trace("Writing custom line rate {}".format(rate))
        ppm_val = int(math.ceil(rate * 1280.0))
        assert ppm_val <= 0x7FFF
        for chan in channels:
            assert chan in ALL_CHANS
            self._set_chan_select(chan)
            # Set VCO divider to 1
            self.regs_iface.poke8(0x2F, 0xC6)
            # Set frequency range detection
            self.regs_iface.poke8(0x60, (ppm_val & 0x00FF))
            self.regs_iface.poke8(0x62, (ppm_val & 0x00FF))
            self.regs_iface.poke8(0x61, 0x80 | ((ppm_val >> 8) & 0x00FF))
            self.regs_iface.poke8(0x63, 0x80 | ((ppm_val >> 8) & 0x00FF))
            # Set VCO tolerance range to max
            self.regs_iface.poke8(0x64, 0xFF)

    def set_driver_preset(self, preset, channels=None):
        """
        Set driver preset
        """
        channels = channels or ALL_CHANS
        assert preset in self.DRIVER_PRESETS.keys()
        self.log.trace("Setting retimer's driver for " + preset + " preset")
        deemphasis, swing = self.DRIVER_PRESETS[preset]
        for chan in channels:
            self._set_chan_select(chan)
            self._rmw(0x15, deemphasis, 0x47)
            self._rmw(0x2D, swing, 0x07)
