import json
import math
import os
import threading
import time
from threading import Lock

from smbus2 import SMBus, i2c_msg

import ipc_common
import ipc_constants
from ipc_util import transform_register_address

GAIN_READBACK_LENGTH_PER_CHANNEL = 4  # 32 bits; each value is channel level presented as 8.24 fixed point
LIMITER_READBACK_LENGTH_PER_CHANNEL = 20  # 5 values of 32 bits; each value is limiter level presented as 8.24 fixed point
NUM_OF_LIMITERS = 20  # each channels has 5 limiters
AMPLIFIER_STATUS = 24 # 6 values AMPON, SMPSRAW, TEMPRAW, SW_REVISION, AVERAGE_POWER, OVERTEMP

READBACK_START_ADDR = 24592  # fixed start address
STATUS_START_READ = 24586 # fixed start address

# Readback values per channel (1->16)
CHANNEL = "a"
USER_RMS_LIM = "b"
USER_PEAK_LIM = "c"
SPEAKER_RMS_LIM = "d"
SPEAKER_PEAK_LIM = "e"
AMP_LIM = "f"

# Readback status per module (1->4)
AMP_ON = "g"
TEMP = 'h'
AVERAGE_POWER = "i"
OVERTEMP = "j"
VOLTAGE = "k"

OUT_OF_RANGE_VOLTAGE_VALUE = 10


class IPCPeakReadbackService:
    def __init__(self, variant):
        self.variant = variant
        self.stop_event = threading.Event()
        self.readback_thread = None
        self.readback_requests = 0

        self.readback_dict = dict()

        for i in range (0, ipc_constants.NUM_OF_CHANNELS):
            self.readback_dict[CHANNEL + str(i + 1)] = 0.0
            self.readback_dict[USER_RMS_LIM + str(i + 1)] = 0.0
            self.readback_dict[USER_PEAK_LIM + str(i + 1)] = 0.0
            self.readback_dict[SPEAKER_RMS_LIM + str(i + 1)] = 0.0
            self.readback_dict[SPEAKER_PEAK_LIM + str(i + 1)] = 0.0
            self.readback_dict[AMP_LIM + str(i + 1)] = 0.0

        for i in range (0, ipc_constants.NUM_OF_MODULES):
            self.readback_dict[AMP_ON + str(i + 1)] = 0
            self.readback_dict[TEMP + str(i + 1)] = 0.0
            self.readback_dict[AVERAGE_POWER + str(i + 1)] = 0.0
            self.readback_dict[OVERTEMP + str(i + 1)] = 0
            self.readback_dict[VOLTAGE + str(i + 1)] = 0

        self.lock = Lock()

        # If the readback file initially doesn't exist, create it and fill with default values
        if not os.path.isfile(ipc_common.PEAK_READBACK_FILE):
            try:
                levels_file = open(ipc_common.PEAK_READBACK_FILE, "w", os.O_NONBLOCK)
                levels_file.write(json.dumps(self.readback_dict))
                levels_file.flush()
                levels_file.close()
            except IOError as e:
                print(e)

    def start_readback(self):
        with self.lock:
            if self.readback_requests == 0:
                self.readback_thread = threading.Thread(
                    target=peak_readback,
                    name="RB-M",
                    kwargs={
                        "variant": self.variant,
                        "stop_event": self.stop_event,
                        "readback_dict": self.readback_dict
                    }
                )
                self.stop_event.clear()
                self.readback_thread.start()
            self.readback_requests += 1

    def stop_readback(self):
        with self.lock:
            if self.readback_requests == 0:
                return
            else:
                self.readback_requests -= 1
                if self.readback_requests == 0:
                    self.stop_event.set()

    def end_service(self):
        self.stop_event.set()
        try:
            self.readback_thread.join()
        except (RuntimeError, AttributeError) as e:
            pass


def peak_readback(variant, stop_event: threading.Event, readback_dict: dict):
    print("Peak readback started.")
    readback_raw = [0] * (4*GAIN_READBACK_LENGTH_PER_CHANNEL + 4*LIMITER_READBACK_LENGTH_PER_CHANNEL)
    readback_raw_1 = [0] * (4*GAIN_READBACK_LENGTH_PER_CHANNEL + 4*LIMITER_READBACK_LENGTH_PER_CHANNEL)
    readback_raw_2 = [0] * (4*GAIN_READBACK_LENGTH_PER_CHANNEL + 4*LIMITER_READBACK_LENGTH_PER_CHANNEL)
    readback_raw_3 = [0] * (4*GAIN_READBACK_LENGTH_PER_CHANNEL + 4*LIMITER_READBACK_LENGTH_PER_CHANNEL)
    readback_raw_4 = [0] * (4*GAIN_READBACK_LENGTH_PER_CHANNEL + 4*LIMITER_READBACK_LENGTH_PER_CHANNEL)

    readback_status_raw_1 = [0] * (AMPLIFIER_STATUS)
    readback_status_raw_2 = [0] * (AMPLIFIER_STATUS)
    readback_status_raw_3 = [0] * (AMPLIFIER_STATUS)
    readback_status_raw_4 = [0] * (AMPLIFIER_STATUS)

    while not stop_event.is_set():
        # time.sleep(.05)
        time.sleep(.10)

        try:
            with SMBus(0) as bus:
                if (variant == "variant7" or variant == "variant8"):
                    mempage_message_1 = i2c_msg.write(ipc_constants.DSP_1_I2C_ADDRESS, [0xF8, 0x99, 0x00, 0x00])  # Reset register page to 0, DSP1
                    mempage_message_2 = i2c_msg.write(ipc_constants.DSP_2_I2C_ADDRESS, [0xF8, 0x99, 0x00, 0x00])  # Reset register page to 0, DSP2
                    mempage_message_3 = i2c_msg.write(ipc_constants.DSP_3_I2C_ADDRESS, [0xF8, 0x99, 0x00, 0x00])  # Reset register page to 0, DSP3
                    mempage_message_4 = i2c_msg.write(ipc_constants.DSP_4_I2C_ADDRESS, [0xF8, 0x99, 0x00, 0x00])  # Reset register page to 0, DSP4
                    
                    # Read status + readback values
                    write_message_1 = i2c_msg.write(ipc_constants.DSP_1_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_STATUS_START_READ))
                    write_message_2 = i2c_msg.write(ipc_constants.DSP_2_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_STATUS_START_READ))
                    write_message_3 = i2c_msg.write(ipc_constants.DSP_3_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_STATUS_START_READ))
                    write_message_4 = i2c_msg.write(ipc_constants.DSP_4_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_STATUS_START_READ))

                    # Read module status + 4 readback per module + 4 channels limiters per module
                    read_message_1 = i2c_msg.read(ipc_constants.DSP_1_I2C_ADDRESS, AMPLIFIER_STATUS + 4*GAIN_READBACK_LENGTH_PER_CHANNEL + 4*LIMITER_READBACK_LENGTH_PER_CHANNEL)
                    read_message_2 = i2c_msg.read(ipc_constants.DSP_2_I2C_ADDRESS, AMPLIFIER_STATUS + 4*GAIN_READBACK_LENGTH_PER_CHANNEL + 4*LIMITER_READBACK_LENGTH_PER_CHANNEL)
                    read_message_3 = i2c_msg.read(ipc_constants.DSP_3_I2C_ADDRESS, AMPLIFIER_STATUS + 4*GAIN_READBACK_LENGTH_PER_CHANNEL + 4*LIMITER_READBACK_LENGTH_PER_CHANNEL)
                    read_message_4 = i2c_msg.read(ipc_constants.DSP_4_I2C_ADDRESS, AMPLIFIER_STATUS + 4*GAIN_READBACK_LENGTH_PER_CHANNEL + 4*LIMITER_READBACK_LENGTH_PER_CHANNEL)

                    bus.i2c_rdwr(mempage_message_1, write_message_1, read_message_1)
                    bus.i2c_rdwr(mempage_message_2, write_message_2, read_message_2)
                    bus.i2c_rdwr(mempage_message_3, write_message_3, read_message_3)
                    bus.i2c_rdwr(mempage_message_4, write_message_4, read_message_4)

                    list_read_1 = list(read_message_1)
                    list_read_2 = list(read_message_2)
                    list_read_3 = list(read_message_3)
                    list_read_4 = list(read_message_4)  

                    readback_raw_1 = list_read_1[AMPLIFIER_STATUS:]
                    readback_raw_2 = list_read_2[AMPLIFIER_STATUS:]
                    readback_raw_3 = list_read_3[AMPLIFIER_STATUS:]
                    readback_raw_4 = list_read_4[AMPLIFIER_STATUS:]

                    readback_status_raw_1 = list_read_1[:AMPLIFIER_STATUS]
                    readback_status_raw_2 = list_read_2[:AMPLIFIER_STATUS]
                    readback_status_raw_3 = list_read_3[:AMPLIFIER_STATUS]
                    readback_status_raw_4 = list_read_4[:AMPLIFIER_STATUS]

                elif variant == "variant4":
                    mempage_message_1 = i2c_msg.write(ipc_constants.DSP_1_I2C_ADDRESS, [0xF8, 0x99, 0x00, 0x00])  # Reset register page to 0, DSP 1
                    mempage_message_2 = i2c_msg.write(ipc_constants.DSP_2_I2C_ADDRESS, [0xF8, 0x99, 0x00, 0x00])  # Reset register page to 0, DSP 2
                    mempage_message_3 = i2c_msg.write(ipc_constants.DSP_3_I2C_ADDRESS, [0xF8, 0x99, 0x00, 0x00])  # Reset register page to 0, DSP 3
                    mempage_message_4 = i2c_msg.write(ipc_constants.DSP_4_I2C_ADDRESS, [0xF8, 0x99, 0x00, 0x00])  # Reset register page to 0, DSP 4

                    write_message_1 = i2c_msg.write(ipc_constants.DSP_1_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_STATUS_START_READ))  # Get module 1 status + gain for channel 1 from DSP 1
                    read_message_1 = i2c_msg.read(ipc_constants.DSP_1_I2C_ADDRESS, AMPLIFIER_STATUS + GAIN_READBACK_LENGTH_PER_CHANNEL)
                    write_message_2 = i2c_msg.write(ipc_constants.DSP_2_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_STATUS_START_READ))  # Get module 2 status + gain for channel 2 from DSP 2
                    read_message_2 = i2c_msg.read(ipc_constants.DSP_2_I2C_ADDRESS, AMPLIFIER_STATUS + GAIN_READBACK_LENGTH_PER_CHANNEL)
                    write_message_3 = i2c_msg.write(ipc_constants.DSP_3_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_STATUS_START_READ))  # Get module 3 status + gain for channel 3 from DSP 3
                    read_message_3 = i2c_msg.read(ipc_constants.DSP_3_I2C_ADDRESS, AMPLIFIER_STATUS + GAIN_READBACK_LENGTH_PER_CHANNEL)
                    write_message_4 = i2c_msg.write(ipc_constants.DSP_4_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_STATUS_START_READ))  # Get module 4 status + gain for channel 4 from DSP 4
                    read_message_4 = i2c_msg.read(ipc_constants.DSP_4_I2C_ADDRESS, AMPLIFIER_STATUS + GAIN_READBACK_LENGTH_PER_CHANNEL)

                    write_message_5 = i2c_msg.write(ipc_constants.DSP_1_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_USER_1_LIM_RMS_ADDRESS))  # Get limiter values for channel 1 from DSP 1
                    read_message_5 = i2c_msg.read(ipc_constants.DSP_1_I2C_ADDRESS, LIMITER_READBACK_LENGTH_PER_CHANNEL)
                    write_message_6 = i2c_msg.write(ipc_constants.DSP_2_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_USER_1_LIM_RMS_ADDRESS))  # Get limiter values for channel 2 from DSP 2
                    read_message_6 = i2c_msg.read(ipc_constants.DSP_2_I2C_ADDRESS, LIMITER_READBACK_LENGTH_PER_CHANNEL)
                    write_message_7 = i2c_msg.write(ipc_constants.DSP_3_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_USER_1_LIM_RMS_ADDRESS))  # Get limiter values for channel 3 from DSP 3
                    read_message_7 = i2c_msg.read(ipc_constants.DSP_3_I2C_ADDRESS, LIMITER_READBACK_LENGTH_PER_CHANNEL)
                    write_message_8 = i2c_msg.write(ipc_constants.DSP_4_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_USER_1_LIM_RMS_ADDRESS))  # Get limiter values for channel 4 from DSP 4
                    read_message_8 = i2c_msg.read(ipc_constants.DSP_4_I2C_ADDRESS, LIMITER_READBACK_LENGTH_PER_CHANNEL)
                    
                    bus.i2c_rdwr(mempage_message_1, write_message_1, read_message_1)
                    bus.i2c_rdwr(mempage_message_1, write_message_5, read_message_5)
                    bus.i2c_rdwr(mempage_message_2, write_message_2, read_message_2)
                    bus.i2c_rdwr(mempage_message_2, write_message_6, read_message_6)
                    bus.i2c_rdwr(mempage_message_3, write_message_3, read_message_3)
                    bus.i2c_rdwr(mempage_message_3, write_message_7, read_message_7)
                    bus.i2c_rdwr(mempage_message_4, write_message_4, read_message_4)
                    bus.i2c_rdwr(mempage_message_4, write_message_8, read_message_8)

                    list_read_1 = list(read_message_1)
                    list_read_2 = list(read_message_2)
                    list_read_3 = list(read_message_3)
                    list_read_4 = list(read_message_4)

                    read_message_1 = list_read_1[AMPLIFIER_STATUS:]
                    read_message_2 = list_read_2[AMPLIFIER_STATUS:]
                    read_message_3 = list_read_3[AMPLIFIER_STATUS:]
                    read_message_4 = list_read_4[AMPLIFIER_STATUS:]

                    readback_status_raw_1 = list_read_1[:AMPLIFIER_STATUS]
                    readback_status_raw_2 = list_read_2[:AMPLIFIER_STATUS]
                    readback_status_raw_3 = list_read_3[:AMPLIFIER_STATUS]
                    readback_status_raw_4 = list_read_4[:AMPLIFIER_STATUS]

                    readback_raw = list(read_message_1) + list(read_message_2) + list(read_message_3) + list(read_message_4) + list(read_message_5) + list(read_message_6) + list(read_message_7) + list(read_message_8)
                    
                elif variant == "variant3":
                    mempage_message_1 = i2c_msg.write(ipc_constants.DSP_1_I2C_ADDRESS, [0xF8, 0x99, 0x00, 0x00])  # Reset register page to 0, DSP 1
                    mempage_message_2 = i2c_msg.write(ipc_constants.DSP_2_I2C_ADDRESS, [0xF8, 0x99, 0x00, 0x00])  # Reset register page to 0, DSP 2

                    write_message_1 = i2c_msg.write(ipc_constants.DSP_1_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_STATUS_START_READ))  # Get module 1 status + gain for channel 1 from DSP 1
                    read_message_1 = i2c_msg.read(ipc_constants.DSP_1_I2C_ADDRESS, AMPLIFIER_STATUS + GAIN_READBACK_LENGTH_PER_CHANNEL)
                    write_message_2 = i2c_msg.write(ipc_constants.DSP_1_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_OUTPUT_LEVEL_3_ADDRESS))  # Get gain for channel 2 from DSP 1
                    read_message_2 = i2c_msg.read(ipc_constants.DSP_1_I2C_ADDRESS, GAIN_READBACK_LENGTH_PER_CHANNEL)
                    write_message_3 = i2c_msg.write(ipc_constants.DSP_2_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_STATUS_START_READ))  # Get module 2 status + gain for channel 3 from DSP 2
                    read_message_3 = i2c_msg.read(ipc_constants.DSP_2_I2C_ADDRESS, AMPLIFIER_STATUS + GAIN_READBACK_LENGTH_PER_CHANNEL)
                    write_message_4 = i2c_msg.write(ipc_constants.DSP_2_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_OUTPUT_LEVEL_3_ADDRESS))  # Get gain for channel 4 from DSP 2
                    read_message_4 = i2c_msg.read(ipc_constants.DSP_2_I2C_ADDRESS, GAIN_READBACK_LENGTH_PER_CHANNEL)

                    write_message_5 = i2c_msg.write(ipc_constants.DSP_1_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_USER_1_LIM_RMS_ADDRESS))  # Get limiter values for channel 1 from DSP 1
                    read_message_5 = i2c_msg.read(ipc_constants.DSP_1_I2C_ADDRESS, LIMITER_READBACK_LENGTH_PER_CHANNEL)
                    write_message_6 = i2c_msg.write(ipc_constants.DSP_1_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_USER_3_LIM_RMS_ADDRESS))  # Get limiter values for channel 2 from DSP 1
                    read_message_6 = i2c_msg.read(ipc_constants.DSP_1_I2C_ADDRESS, LIMITER_READBACK_LENGTH_PER_CHANNEL)
                    write_message_7 = i2c_msg.write(ipc_constants.DSP_2_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_USER_1_LIM_RMS_ADDRESS))  # Get limiter values for channel 3 from DSP 2
                    read_message_7 = i2c_msg.read(ipc_constants.DSP_2_I2C_ADDRESS, LIMITER_READBACK_LENGTH_PER_CHANNEL)
                    write_message_8 = i2c_msg.write(ipc_constants.DSP_2_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_USER_3_LIM_RMS_ADDRESS))  # Get limiter values for channel 4 from DSP 2
                    read_message_8 = i2c_msg.read(ipc_constants.DSP_2_I2C_ADDRESS, LIMITER_READBACK_LENGTH_PER_CHANNEL)

                    bus.i2c_rdwr(mempage_message_1, write_message_1, read_message_1)
                    bus.i2c_rdwr(mempage_message_1, write_message_5, read_message_5)
                    bus.i2c_rdwr(mempage_message_1, write_message_2, read_message_2)
                    bus.i2c_rdwr(mempage_message_1, write_message_6, read_message_6)
                    bus.i2c_rdwr(mempage_message_2, write_message_3, read_message_3)
                    bus.i2c_rdwr(mempage_message_2, write_message_7, read_message_7)
                    bus.i2c_rdwr(mempage_message_2, write_message_4, read_message_4)
                    bus.i2c_rdwr(mempage_message_2, write_message_8, read_message_8)

                    list_read_1 = list(read_message_1)
                    list_read_3 = list(read_message_3)

                    read_message_1 = list_read_1[AMPLIFIER_STATUS:]
                    read_message_3 = list_read_3[AMPLIFIER_STATUS:]

                    readback_status_raw_1 = list_read_1[:AMPLIFIER_STATUS]
                    readback_status_raw_2 = list_read_3[:AMPLIFIER_STATUS]

                    readback_raw = list(read_message_1) + list(read_message_2) + list(read_message_3) + list(read_message_4) + list(read_message_5) + list(read_message_6) + list(read_message_7) + list(read_message_8)
                    
                else:  # variant 1 and 2 and 5 and 6
                    mempage_message = i2c_msg.write(ipc_constants.DSP_1_I2C_ADDRESS, [0xF8, 0x99, 0x00, 0x00])  # Reset register page to 0

                    # Read status + readback values
                    write_message = i2c_msg.write(ipc_constants.DSP_1_I2C_ADDRESS, transform_register_address(ipc_constants.READBACK_STATUS_START_READ))

                    # Read module status + 4 readback per module + 4 channels limiters per module
                    read_message = i2c_msg.read(ipc_constants.DSP_1_I2C_ADDRESS, AMPLIFIER_STATUS + 4*GAIN_READBACK_LENGTH_PER_CHANNEL + 4*LIMITER_READBACK_LENGTH_PER_CHANNEL)

                    bus.i2c_rdwr(mempage_message, write_message, read_message)

                    list_read = list(read_message)

                    readback_raw = list_read[AMPLIFIER_STATUS:]
                    readback_status_raw_1 = list_read[:AMPLIFIER_STATUS]

        except OSError as e:
            print(e)
            continue


        if (variant == "variant7" or variant == "variant8"):
            for i in range(0, 4 + NUM_OF_LIMITERS):
                if readback_raw_1[i * 4] == 1:
                    # If first byte is 1, there is no active limiter
                    db_1 = 0.0
                else:
                    # Ignore the last byte, it doesn't affect precision much
                    temp_1 = (readback_raw_1[1 + i * 4] * 256 + readback_raw_1[2 + i * 4]) / 65536
                    # convert to db: 20 * log(value)
                    if temp_1 > 0:
                        db_1 = round(20 * math.log10(temp_1),1)
                        if db_1 < -60.0:
                            db_1 = -60
                    else:
                        db_1 = -60.0

                if readback_raw_2[i * 4] == 1:
                    # If first byte is 1, there is no active limiter
                    db_2 = 0.0
                else:
                    # Ignore the last byte, it doesn't affect precision much
                    temp_2 = (readback_raw_2[1 + i * 4] * 256 + readback_raw_2[2 + i * 4]) / 65536
                    # convert to db: 20 * log(value)
                    if temp_2 > 0:
                        db_2 = round(20 * math.log10(temp_2),1)
                        if db_2 < -60.0:
                            db_2 = -60
                    else:
                        db_2 = -60.0

                if readback_raw_3[i * 4] == 1:
                    # If first byte is 1, there is no active limiter
                    db_3 = 0.0
                else:
                    # Ignore the last byte, it doesn't affect precision much
                    temp_3 = (readback_raw_3[1 + i * 4] * 256 + readback_raw_3[2 + i * 4]) / 65536
                    # convert to db: 20 * log(value)
                    if temp_3 > 0:
                        db_3 = round(20 * math.log10(temp_3),1)
                        if db_3 < -60.0:
                            db_3 = -60
                    else:
                        db_3 = -60.0

                if readback_raw_4[i * 4] == 1:
                    # If first byte is 1, there is no active limiter
                    db_4 = 0.0
                else:
                    # Ignore the last byte, it doesn't affect precision much
                    temp_4 = (readback_raw_4[1 + i * 4] * 256 + readback_raw_4[2 + i * 4]) / 65536
                    # convert to db: 20 * log(value)
                    if temp_4 > 0:
                        db_4 = round(20 * math.log10(temp_4),1)
                        if db_4 < -60.0:
                            db_4 = -60
                    else:
                        db_4 = -60.0


                if 0 <= i < 4:  # channels readback values
                    readback_dict[CHANNEL + str(i+1)] = db_1
                    readback_dict[CHANNEL + str(i+5)] = db_2
                    readback_dict[CHANNEL + str(i+9)] = db_3
                    readback_dict[CHANNEL + str(i+13)] = db_4
                elif 4 == i:
                    readback_dict[USER_RMS_LIM + "1"] = db_1
                    readback_dict[USER_RMS_LIM + "5"] = db_2
                    readback_dict[USER_RMS_LIM + "9"] = db_3
                    readback_dict[USER_RMS_LIM + "13"] = db_4
                elif 5 == i:
                    readback_dict[USER_PEAK_LIM + "1"] = db_1
                    readback_dict[USER_PEAK_LIM + "5"] = db_2
                    readback_dict[USER_PEAK_LIM + "9"] = db_3
                    readback_dict[USER_PEAK_LIM + "13"] = db_4
                elif 6 == i:
                    readback_dict[SPEAKER_RMS_LIM + "1"] = db_1
                    readback_dict[SPEAKER_RMS_LIM + "5"] = db_2
                    readback_dict[SPEAKER_RMS_LIM + "9"] = db_3
                    readback_dict[SPEAKER_RMS_LIM + "13"] = db_4
                elif 7 == i:
                    readback_dict[SPEAKER_PEAK_LIM + "1"] = db_1
                    readback_dict[SPEAKER_PEAK_LIM + "5"] = db_2
                    readback_dict[SPEAKER_PEAK_LIM + "9"] = db_3
                    readback_dict[SPEAKER_PEAK_LIM + "13"] = db_4
                elif 8 == i:
                    readback_dict[AMP_LIM + "1"] = db_1
                    readback_dict[AMP_LIM + "5"] = db_2
                    readback_dict[AMP_LIM + "9"] = db_3
                    readback_dict[AMP_LIM + "13"] = db_4
                elif 9 == i:
                    readback_dict[USER_RMS_LIM + "2"] = db_1
                    readback_dict[USER_RMS_LIM + "6"] = db_2
                    readback_dict[USER_RMS_LIM + "10"] = db_3
                    readback_dict[USER_RMS_LIM + "14"] = db_4
                elif 10 == i:
                    readback_dict[USER_PEAK_LIM + "2"] = db_1
                    readback_dict[USER_PEAK_LIM + "6"] = db_2
                    readback_dict[USER_PEAK_LIM + "10"] = db_3
                    readback_dict[USER_PEAK_LIM + "14"] = db_4
                elif 11 == i:
                    readback_dict[SPEAKER_RMS_LIM + "2"] = db_1
                    readback_dict[SPEAKER_RMS_LIM + "6"] = db_2
                    readback_dict[SPEAKER_RMS_LIM + "10"] = db_3
                    readback_dict[SPEAKER_RMS_LIM + "14"] = db_4
                elif 12 == i:
                    readback_dict[SPEAKER_PEAK_LIM + "2"] = db_1
                    readback_dict[SPEAKER_PEAK_LIM + "6"] = db_2
                    readback_dict[SPEAKER_PEAK_LIM + "10"] = db_3
                    readback_dict[SPEAKER_PEAK_LIM + "14"] = db_4
                elif 13 == i:
                    readback_dict[AMP_LIM + "2"] = db_1
                    readback_dict[AMP_LIM + "6"] = db_2
                    readback_dict[AMP_LIM + "10"] = db_3
                    readback_dict[AMP_LIM + "14"] = db_4
                elif 14 == i:
                    readback_dict[USER_RMS_LIM + "3"] = db_1
                    readback_dict[USER_RMS_LIM + "7"] = db_2
                    readback_dict[USER_RMS_LIM + "11"] = db_3
                    readback_dict[USER_RMS_LIM + "15"] = db_4
                elif 15 == i:
                    readback_dict[USER_PEAK_LIM + "3"] = db_1
                    readback_dict[USER_PEAK_LIM + "7"] = db_2
                    readback_dict[USER_PEAK_LIM + "11"] = db_3
                    readback_dict[USER_PEAK_LIM + "15"] = db_4
                elif 16 == i:
                    readback_dict[SPEAKER_RMS_LIM + "3"] = db_1
                    readback_dict[SPEAKER_RMS_LIM + "7"] = db_2
                    readback_dict[SPEAKER_RMS_LIM + "11"] = db_3
                    readback_dict[SPEAKER_RMS_LIM + "15"] = db_4
                elif 17 == i:
                    readback_dict[SPEAKER_PEAK_LIM + "3"] = db_1
                    readback_dict[SPEAKER_PEAK_LIM + "7"] = db_2
                    readback_dict[SPEAKER_PEAK_LIM + "11"] = db_3
                    readback_dict[SPEAKER_PEAK_LIM + "15"] = db_4
                elif 18 == i:
                    readback_dict[AMP_LIM + "3"] = db_1
                    readback_dict[AMP_LIM + "7"] = db_2
                    readback_dict[AMP_LIM + "11"] = db_3
                    readback_dict[AMP_LIM + "15"] = db_4
                elif 19 == i:
                    readback_dict[USER_RMS_LIM + "4"] = db_1
                    readback_dict[USER_RMS_LIM + "8"] = db_2
                    readback_dict[USER_RMS_LIM + "12"] = db_3
                    readback_dict[USER_RMS_LIM + "16"] = db_4
                elif 20 == i:
                    readback_dict[USER_PEAK_LIM + "4"] = db_1
                    readback_dict[USER_PEAK_LIM + "8"] = db_2
                    readback_dict[USER_PEAK_LIM + "12"] = db_3
                    readback_dict[USER_PEAK_LIM + "16"] = db_4
                elif 21 == i:
                    readback_dict[SPEAKER_RMS_LIM + "4"] = db_1
                    readback_dict[SPEAKER_RMS_LIM + "8"] = db_2
                    readback_dict[SPEAKER_RMS_LIM + "12"] = db_3
                    readback_dict[SPEAKER_RMS_LIM + "16"] = db_4
                elif 22 == i:
                    readback_dict[SPEAKER_PEAK_LIM + "4"] = db_1
                    readback_dict[SPEAKER_PEAK_LIM + "8"] = db_2
                    readback_dict[SPEAKER_PEAK_LIM + "12"] = db_3
                    readback_dict[SPEAKER_PEAK_LIM + "16"] = db_4
                elif 23 == i:
                    readback_dict[AMP_LIM + "4"] = db_1
                    readback_dict[AMP_LIM + "8"] = db_2
                    readback_dict[AMP_LIM + "12"] = db_3
                    readback_dict[AMP_LIM + "16"] = db_4

            readback_dict[AMP_ON + "1"] = readback_status_raw_1[3]
            readback_dict[AMP_ON + "2"] = readback_status_raw_2[3]
            readback_dict[AMP_ON + "3"] = readback_status_raw_3[3]
            readback_dict[AMP_ON + "4"] = readback_status_raw_4[3]

            readback_dict[TEMP + "1"] = get_temperature(readback_status_raw_1[8])
            readback_dict[TEMP + "2"] = get_temperature(readback_status_raw_2[8])
            readback_dict[TEMP + "3"] = get_temperature(readback_status_raw_3[8])
            readback_dict[TEMP + "4"] = get_temperature(readback_status_raw_4[8])

            readback_dict[OVERTEMP + "1"] = readback_status_raw_1[23]
            readback_dict[OVERTEMP + "2"] = readback_status_raw_2[23]
            readback_dict[OVERTEMP + "3"] = readback_status_raw_3[23]
            readback_dict[OVERTEMP + "4"] = readback_status_raw_4[23]

            readback_dict[VOLTAGE + "1"] = get_voltage(readback_status_raw_1[7])
            readback_dict[VOLTAGE + "2"] = get_voltage(readback_status_raw_2[7])
            readback_dict[VOLTAGE + "3"] = get_voltage(readback_status_raw_3[7])
            readback_dict[VOLTAGE + "4"] = get_voltage(readback_status_raw_4[7])
    
        else :
            # for i in range(0, ipc_constants.NUM_OF_CHANNELS + NUM_OF_LIMITERS):
            for i in range(0, 4 + NUM_OF_LIMITERS):
                if readback_raw[i * 4] == 1:
                    # If first byte is 1, there is no active limiter
                    db = 0.0
                else:
                    # Ignore the last byte, it doesn't affect precision much
                    temp = (readback_raw[1 + i * 4] * 256 + readback_raw[2 + i * 4]) / 65536
                    # convert to db: 20 * log(value)
                    if temp > 0:
                        db = round(20 * math.log10(temp),1)
                        if db < -60.0:
                            db = -60
                    else:
                        db = -60.0

                if 0 <= i < 4:  # channels readback values
                    readback_dict[CHANNEL + str(i+1)] = db
                elif 4 == i:
                    readback_dict[USER_RMS_LIM + "1"] = db
                elif 5 == i:
                    readback_dict[USER_PEAK_LIM + "1"] = db
                elif 6 == i:
                    readback_dict[SPEAKER_RMS_LIM + "1"] = db
                elif 7 == i:
                    readback_dict[SPEAKER_PEAK_LIM + "1"] = db
                elif 8 == i:
                    readback_dict[AMP_LIM + "1"] = db
                elif 9 == i:
                    readback_dict[USER_RMS_LIM + "2"] = db
                elif 10 == i:
                    readback_dict[USER_PEAK_LIM + "2"] = db
                elif 11 == i:
                    readback_dict[SPEAKER_RMS_LIM + "2"] = db
                elif 12 == i:
                    readback_dict[SPEAKER_PEAK_LIM + "2"] = db
                elif 13 == i:
                    readback_dict[AMP_LIM + "2"] = db
                elif 14 == i:
                    readback_dict[USER_RMS_LIM + "3"] = db
                elif 15 == i:
                    readback_dict[USER_PEAK_LIM + "3"] = db
                elif 16 == i:
                    readback_dict[SPEAKER_RMS_LIM + "3"] = db
                elif 17 == i:
                    readback_dict[SPEAKER_PEAK_LIM + "3"] = db
                elif 18 == i:
                    readback_dict[AMP_LIM + "3"] = db
                elif 19 == i:
                    readback_dict[USER_RMS_LIM + "4"] = db
                elif 20 == i:
                    readback_dict[USER_PEAK_LIM + "4"] = db
                elif 21 == i:
                    readback_dict[SPEAKER_RMS_LIM + "4"] = db
                elif 22 == i:
                    readback_dict[SPEAKER_PEAK_LIM + "4"] = db
                elif 23 == i:
                    readback_dict[AMP_LIM + "4"] = db

            readback_dict[AMP_ON + "1"] = readback_status_raw_1[3]
            readback_dict[AMP_ON + "2"] = readback_status_raw_2[3]
            readback_dict[AMP_ON + "3"] = readback_status_raw_3[3]
            readback_dict[AMP_ON + "4"] = readback_status_raw_4[3]

            readback_dict[TEMP + "1"] = get_temperature(readback_status_raw_1[8])
            readback_dict[TEMP + "2"] = get_temperature(readback_status_raw_2[8])
            readback_dict[TEMP + "3"] = get_temperature(readback_status_raw_3[8])
            readback_dict[TEMP + "4"] = get_temperature(readback_status_raw_3[8])
            
            readback_dict[OVERTEMP + "1"] = readback_status_raw_1[23]
            readback_dict[OVERTEMP + "2"] = readback_status_raw_2[23]
            readback_dict[OVERTEMP + "3"] = readback_status_raw_3[23]
            readback_dict[OVERTEMP + "4"] = readback_status_raw_4[23]

            readback_dict[VOLTAGE + "1"] = get_voltage(readback_status_raw_1[7])
            readback_dict[VOLTAGE + "2"] = get_voltage(readback_status_raw_2[7])
            readback_dict[VOLTAGE + "3"] = get_voltage(readback_status_raw_3[7])
            readback_dict[VOLTAGE + "4"] = get_voltage(readback_status_raw_3[7])

        try:
            levels_file = open(ipc_common.PEAK_READBACK_FILE, "w", os.O_NONBLOCK)
            levels_file.write(json.dumps(readback_dict))
            levels_file.flush()
            levels_file.close()
        except IOError as e:
            print(e)

    print("Peak readback stopped.")


# Convert DSP read value to celsius temperature
def get_temperature(dsp_val):
    temp = 0
    if (dsp_val > 80):
        temp = (-23/42)*dsp_val + 88.81
    else:
        if (dsp_val != 0):
            temp = (-25/40)*dsp_val + 95
    return round(temp,1)

# Check DSP read value range to voltage, with 10V as out of range value
def get_voltage(dsp_val):
    temp = OUT_OF_RANGE_VOLTAGE_VALUE
    if (dsp_val >= 80 and dsp_val <= 255):
        temp = dsp_val
    return round(temp, 0)