# -*- coding: utf-8 -*-
'''
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
'''

import sys
import os
import platform
import shutil
import struct

import pandas as pd
from PySide6 import QtCore, QtWidgets
from PySide6.QtGui import QIcon, QFont, QPixmap
from PySide6.QtWidgets import QTableWidgetItem, QComboBox, QMessageBox, QItemDelegate

from ui import Ui_MainWindow
from ui import Ui_ddrparam

window_title_g = "Rockchip DDR bin tool V1.01"
logo_file_g = "resource/image/logo.icon"
logo_file_ubuntu_g = "resource/image/logo.icon"
logo_file_windows_g = "resource/image/logo.icon"
rockchip_logo_file_g = "resource/image/rockchip_logo.png"

ddrbin_param_dict_g = {
    "RK3588" : "resource/config/ddrbin_param_rk3588.csv",
    "RK3568/RK3566" : "resource/config/ddrbin_param_rk3568.csv",
    "RK3528" : "resource/config/ddrbin_param_rk3528.csv",
    "RK3399" : "resource/config/ddrbin_param_rk3399.csv",
    "RK3328/RK322xh" : "resource/config/ddrbin_param_rk3328.csv",
    "RK3368" : "resource/config/ddrbin_param_rk3368.csv",
    "RK3326/PX30" : "resource/config/ddrbin_param_rk3326.csv",
    "RK3308" : "resource/config/ddrbin_param_rk3308.csv",
    "RK3288" : "resource/config/ddrbin_param_rk3288.csv",
    "RK322x" : "resource/config/ddrbin_param_rk322x.csv",
    "RK1808" : "resource/config/ddrbin_param_rk1808.csv",
    "RV1126/RV1109" : "resource/config/ddrbin_param_rv1126.csv",
    "RV1108" : "resource/config/ddrbin_param_rv1108.csv",
    "Other" : "resource/config/ddrbin_param.csv"
    }

loader_pack_dict_g = {
    "RK3588" : "",
    "RK3568/RK3566" : "",
    "RK3528" : "",
    "RK3399" : "",
    "RK3328/RK322xh" : "",
    "RK3368" : "",
    "RK3326/PX30" : "",
    "RK3308" : "",
    "RK3288" : "",
    "RK322x" : "",
    "RK1808" : "",
    "RV1126/RV1109" : "",
    "RV1108" : "",
    "Other" : ""
    }

boot_merge_tool_win_path = "resource\\tools\\boot_merger.exe"
ddr_bin_tool_win_path = "resource\\tools\\ddrbin_tool.exe"

boot_merge_tool_linux_path = "resource/tools/boot_merger"
ddr_bin_tool_linux_path = "resource/tools/ddrbin_tool"

class modify_ddr_bin():
    def check_if_loadr_file(loader_file_path):
        f = open(loader_file_path, 'rb')
        context = f.read(5)
        f.close()

        real_context = struct.unpack('5s', context)
        real_context = str(str(real_context[0]))[2:-1]

        if real_context == 'LDR f' or real_context == 'BOOTf':
            return True
        else:
            return False

    def get_loader_param(loader_file_path):
        loader_param = {}

        f = open(loader_file_path, 'rb')
        context = f.read(46)
        real_context = struct.unpack('<4sH4BI7s4sBIBBIBBIB1B2B', context)
        #print("real_context: ", real_context)
        loader_param["uiTag"] = str(str(real_context[0]))[2:-1]
        loader_param["ussize"] = str(real_context[1])
        dwVersion_0 =  str(real_context[2])
        dwVersion_1 =  str(real_context[3])
        loader_param["dwVersion"] = str(dwVersion_1 + '.' + dwVersion_0)
        loader_param["dwMergeVersion"] = hex(real_context[6])
        loader_param["stReleaseTime"] = str(real_context[7])
        emSupportChip= str(str(real_context[8]))[2:-1]
        loader_param["emSupportChip"] = emSupportChip[3]+emSupportChip[2]+emSupportChip[1]+emSupportChip[0]
        loader_param["uc471EntryCount"] = real_context[9]
        loader_param["dw471EntryOffset"] = real_context[10]
        loader_param["uc471EntrySize"] = real_context[11]
        loader_param["uc472EntryCount"] = real_context[12]
        loader_param["dw472EntryOffset"] = real_context[13]
        loader_param["uc472EntrySize"] = real_context[14]
        loader_param["ucLoaderEntryCount"] = real_context[15]
        loader_param["dwLoaderEntryOffset"] = real_context[16]
        loader_param["ucLoaderEntrySize"] = real_context[17]
        loader_param["ucSignFlag"] = str(real_context[18])

        ucRc4Flag_0 = str(real_context[-2])
        ucRc4Flag_1 = str(real_context[-1])
        if ucRc4Flag_1 == '1' and ucRc4Flag_0 == '1':
            loader_param["ucRc4Flag"] = '3'
        elif ucRc4Flag_1 == '1' and ucRc4Flag_0 == '0':
            loader_param["ucRc4Flag"] = '2'
        elif ucRc4Flag_1 == '0' and ucRc4Flag_0 == '1':
            loader_param["ucRc4Flag"] = '1'
        else:
            loader_param["ucRc4Flag"] = '0'

        f.seek(loader_param["dw471EntryOffset"])
        context = f.read(54)
        real_context = struct.unpack('<53sB', context)
        loader_param["471_dwDataDelay"] = str(real_context[-1])

        f.seek(loader_param["dw472EntryOffset"])
        context = f.read(54)
        real_context = struct.unpack('<53sB', context)
        loader_param["472_dwDataDelay"] = str(real_context[-1])

        f.close()

        '''
        print("uiTag: ", loader_param["uiTag"])
        print("ussize: ", loader_param["ussize"])
        print("dwVersion: ", loader_param["dwVersion"])
        print("dwMergeVersion: ", loader_param["dwMergeVersion"])
        print("stReleaseTime:", loader_param["stReleaseTime"])
        print("emSupportChip: ", loader_param["emSupportChip"])
        print("uc471EntryCount: ", loader_param["uc471EntryCount"])
        print("dw471EntryOffset: ", loader_param["dw471EntryOffset"])
        print("uc471EntrySize: ", loader_param["uc471EntrySize"])
        print("uc472EntryCount: ", loader_param["uc472EntryCount"])
        print("dw472EntryOffset: ", loader_param["dw472EntryOffset"])
        print("uc472EntrySize: ", loader_param["uc472EntrySize"])
        print("ucLoaderEntryCount: ", loader_param["ucLoaderEntryCount"])
        print("dwLoaderEntryOffset: ", loader_param["dwLoaderEntryOffset"])
        print("ucLoaderEntrySize: ", loader_param["ucLoaderEntrySize"])
        print("ucSignFlag: ", loader_param["ucSignFlag"])
        print("ucRc4Flag: ", loader_param["ucRc4Flag"])
        print("471_dwDataDelay: ", loader_param["471_dwDataDelay"])
        print("472_dwDataDelay: ", loader_param["472_dwDataDelay"])
        '''

        return loader_param


    def get_cfg_file(csv_file_path):
        """
        读取config文件(.csv)
        :Param Str file_path: config文件(.csv)路径
        :Return Dataframe data_df: 文件数据
        """
        if os.path.exists(csv_file_path) == False:
            print("get_cfg_file error, file_path not exist\n")
            return

        data_df = pd.read_csv(csv_file_path, encoding="gbk")
        #print(len(data_df))

        return data_df


    def loader_unpack(loader_file_path, chip_name='NULL'):
        """
        使用boot_merger工具对loader文件进行解包
        :Param Str file_path: loader.bin文件路径
        :Return Dict loader_params_dict: 解包后获取的loader参数
        """

        output_dir_name = 'output'
        loader_params_dict = {"pack_params" : "null", "loader_471" : "null", "loader_472" : "null",
            "loader_473_1" : "null","loader_473_2" : "null", "loader_473_3" : "null",
            "loader_FlashData_path" : "null", "loader_FlashBoot_path" : "null", "loader_file_path" : "null"}

        if not os.path.exists(output_dir_name):
            os.mkdir(output_dir_name)

        # loader unpack command: boot_merger.exe unpack -i resource/loader.bin -o output
        if platform.system().lower() == 'linux':
                boot_merge_tool_path = boot_merge_tool_linux_path
                os.chmod(boot_merge_tool_path, 0x775)
        else:
                boot_merge_tool_path = boot_merge_tool_win_path
        cmd_str = boot_merge_tool_path + " unpack -i " + "\"" + loader_file_path + "\"" + " -o " + output_dir_name
        with os.popen(cmd_str, "r")as f:
            text_str = f.read()
        print(text_str)
        if "Error" in text_str:
            print("boot_merge unpack error")
            return
        text_list = text_str.split('\n')[:-1]

        if len(text_list) == 8:
            # 记录loader_471文件路径
            offset = text_list[3].find('file=')
            loader_params_dict['loader_471'] = output_dir_name + "/" + text_list[3][offset + 5 : len(text_list[3])]
            # 记录loader_472文件路径
            offset = text_list[4].find('file=')
            loader_params_dict['loader_472'] = output_dir_name + "/" + text_list[4][offset + 5 : len(text_list[4])]
            # 记录loader_473_1文件路径
            offset = text_list[5].find('file=')
            loader_params_dict['loader_473_1'] = output_dir_name + "/" + text_list[5][offset + 5 : len(text_list[5])]
            # 记录loader_473_2文件路径
            offset = text_list[6].find('file=')
            loader_params_dict['loader_473_2'] = output_dir_name + "/" + text_list[6][offset + 5 : len(text_list[6])]
        else:
            # 记录loader_471文件路径
            offset = text_list[4].find('file=')
            loader_params_dict['loader_471'] = output_dir_name + "/" + text_list[4][offset + 5 : len(text_list[4])]
            # 记录loader_472文件路径
            offset = text_list[5].find('file=')
            loader_params_dict['loader_472'] = output_dir_name + "/" + text_list[5][offset + 5 : len(text_list[5])]
            # 记录loader_473_1文件路径
            offset = text_list[6].find('file=')
            loader_params_dict['loader_473_1'] = output_dir_name + "/" + text_list[6][offset + 5 : len(text_list[6])]
            # 记录loader_473_2文件路径
            offset = text_list[7].find('file=')
            loader_params_dict['loader_473_2'] = output_dir_name + "/" + text_list[7][offset + 5 : len(text_list[7])]
            # 记录loader_473_3文件路径
            offset = text_list[8].find('file=')
            loader_params_dict['loader_473_3'] = output_dir_name + "/" + text_list[8][offset + 5 : len(text_list[8])]

        for value in loader_params_dict.values():
            if "FlashData" in value:
                loader_params_dict['loader_FlashData_path'] = value
            if "FlashBoot" in value:
                loader_params_dict['loader_FlashBoot_path'] = value

        # 记录loader文件路径
        loader_params_dict['loader_file_path'] = loader_file_path

        loader_param = modify_ddr_bin.get_loader_param(loader_file_path)
        print("uiTag: ", loader_param["uiTag"])
        print("ussize: ", loader_param["ussize"])
        print("dwVersion: ", loader_param["dwVersion"])
        print("emSupportChip: ", loader_param["emSupportChip"])
        print("ucRc4Flag: ", loader_param["ucRc4Flag"])

        cmd_str = "-c -"
        if chip_name[0:2] == "RK" or chip_name[0:2] == "RV":
            cmd_str = cmd_str + chip_name[0:2]
        else:
            cmd_str = cmd_str + 'RK'
        cmd_str += loader_param["emSupportChip"]
        cmd_str += ' -v ' + loader_param["dwVersion"]
        if loader_param["uiTag"] == "LDR ":
            cmd_str += ' -n'
        if loader_param["471_dwDataDelay"] != '0':
            cmd_str += ' -d ' + loader_param["471_dwDataDelay"]
        if loader_param["472_dwDataDelay"] != '0':
            cmd_str += ' -s ' + loader_param["472_dwDataDelay"]
        cmd_str += ' -r ' + loader_param["ucRc4Flag"]

        loader_params_dict['pack_params'] = cmd_str
        '''
        print("loader_471=" + loader_params_dict['loader_471'])
        print("loader_472=" + loader_params_dict['loader_472'])
        print("loader_473_1=" + loader_params_dict['loader_473_1'])
        print("loader_473_2=" + loader_params_dict['loader_473_2'])
        print("loader_file_path=" + loader_params_dict['loader_file_path'])
        '''

        return loader_params_dict


    def loader_pack(loader_params_dict, loader_file_rename = True):
        file_path = loader_params_dict['loader_file_path']

        # 打包后的新loader文件名加_new标识。
        if loader_file_rename == True:
            if file_path[-4:] == ".bin":
                file_path = file_path[ :-4] + "_new.bin"
            else:
                file_path = file_path + "_new.bin"

        # copy ddr.bin to FlashData.bin
        shutil.copy(loader_params_dict['loader_471'], loader_params_dict['loader_FlashData_path'])

        # loader pack command:
        #   boot_merger.exe pack -c -RK3588 -v 1.11 -n -d 1 -r 3
        #   -1 ddr.bin -2 usbplug.bin -3 FlashData.bin -3 FlashBoot.bin -o loader.bin"
        if platform.system().lower() == 'linux':
                boot_merge_tool_path = boot_merge_tool_linux_path
        else:
                boot_merge_tool_path = boot_merge_tool_win_path
        cmd_str = boot_merge_tool_path + " pack " + loader_params_dict['pack_params'] + \
            " -1 " + loader_params_dict['loader_471'] + " -2 " + loader_params_dict['loader_472'] + \
            " -3 " + loader_params_dict['loader_FlashData_path'] + " -3 " + loader_params_dict['loader_FlashBoot_path'] + \
            " -o " + "\"" + file_path + "\""
        #print("cmd_str: ", cmd_str)
        with os.popen(cmd_str, "r")as f:
            text_str = f.read()
        print(text_str)

        return file_path


    def get_ddr_params(ddr_bin_file_path, chip_name="NULL"):
        """
        从ddr bin中获取DDR配置参数ddr params
        :Param Str file_path: ddr bin的文件路径
        :Return Dict: ddr配置参数
        """
        output_dir_name = 'output'
        gen_param_file_path = output_dir_name + "/" + "gen_param.txt"

        if '/' in chip_name.lower():
            ret_int = -1
            chip_name_str = chip_name.lower() + '/'
            chip_name_list = chip_name_str.split('/')[:-1]
            for chip_name_str in chip_name_list:
                if chip_name_str in ddr_bin_file_path:
                    ret_int = 0
        elif chip_name != "NULL" and chip_name != "Other":
            if chip_name.lower() in ddr_bin_file_path:
                ret_int = 0
            else:
                ret_int = -1
        else:
            ret_int = 0

        print(chip_name, ddr_bin_file_path)

        if not os.path.exists(output_dir_name):
            os.mkdir(output_dir_name)

        if os.path.exists(gen_param_file_path):
            os.remove(gen_param_file_path)

        # ddr bin gen param command:
        #   ddrbin_tool.exe -g gen_param.txt ddr_bin.bin"
        if platform.system().lower() == 'linux':
                ddr_bin_tool_path = ddr_bin_tool_linux_path
                os.chmod(ddr_bin_tool_path, 0x775)
        else:
                ddr_bin_tool_path = ddr_bin_tool_win_path
        cmd_str = ddr_bin_tool_path + " -g " + gen_param_file_path + ' ' + "\"" + ddr_bin_file_path + "\""
        print(cmd_str)
        with os.popen(cmd_str, "r")as f:
            text_str = f.read()
        print(text_str)

        with open(gen_param_file_path, "r")as f:
            res_str = f.read()

        res_list = res_str.split('\n')[:-1]

        res_dict = {}
        for res in res_list:
            offset = res.find('=')
            if offset != -1:
                res_dict.update({res[0: offset]: res[offset + 1 : len(res)]})

        return res_dict, ret_int


    def update_ddr_bin(res_dict, ddr_bin_path, ddr_bin_path_rename = True):
        """
        DDR配置参数ddr params重新生成ddr bin
        :Param Dict res_dict: ddr配置参数
        """
        res_list = []
        for key in res_dict:
            value = res_dict[key]
            res_list.append(key + '=' + value)
        res_list.append('end')

        res_str = '\n'.join(res_list)

        output_dir_name = 'output'
        gen_param_new_file_path = output_dir_name + "/" + "gen_param_new.txt"

        with open(gen_param_new_file_path,"w")as f:
                f.write(res_str)

        #new_ddr_bin_path = ddr_bin_path
        if ddr_bin_path_rename == True:
            # 打包后的新ddr bin文件名加_new标识。
            if ddr_bin_path[-4:] == ".bin":
                new_ddr_bin_path = ddr_bin_path[ :-4] + "_new.bin"
            else:
                new_ddr_bin_path = ddr_bin_path + "_new.bin"
            shutil.copy(ddr_bin_path, new_ddr_bin_path)
        else:
            new_ddr_bin_path = ddr_bin_path

        # ddr bin gen ddr bin command:
        #   ddrbin_tool.exe gen_param.txt ddr_bin.bin"
        if platform.system().lower() == 'linux':
                ddr_bin_tool_path = ddr_bin_tool_linux_path
        else:
                ddr_bin_tool_path = ddr_bin_tool_win_path
        cmd_str = ddr_bin_tool_path + " " + gen_param_new_file_path + " " + "\"" + new_ddr_bin_path + "\""
        with os.popen(cmd_str, "r")as f:
            text_str = f.read()
        print(text_str)

        return new_ddr_bin_path

    def cpmpare_ddr_param():
        output_dir_name = 'output'
        gen_param_file_path = output_dir_name + "/" + "gen_param.txt"
        gen_param_file_new_path = output_dir_name + "/" + "gen_param_new.txt"

        with open(gen_param_file_path, "r")as f:
            res_str = f.read()

        res_list = res_str.split('\n')[:-1]

        res_dict = {}
        for res in res_list:
            offset = res.find('=')
            if offset != -1:
                res_dict.update({res[0: offset]: res[offset + 1 : len(res)]})

        with open(gen_param_file_new_path, "r")as f:
            res_str = f.read()

        res_list = res_str.split('\n')[:-1]

        res_dict_new = {}
        for res in res_list:
            offset = res.find('=')
            if offset != -1:
                res_dict_new.update({res[0: offset]: res[offset + 1 : len(res)]})

        ret_str = 'ddr parameter modified：\n'
        for key in res_dict:
            if res_dict[key] != res_dict_new[key]:
                ret_str += key + ": " + res_dict[key] + " => " + res_dict_new[key] + "\n"
        if ret_str == 'ddr parameter modified：\n':
            ret_str += "NULL"

        return ret_str

class EmptyDelegate(QItemDelegate):
  def __init__(self,parent):
    super(EmptyDelegate, self).__init__(parent)
  def createEditor(self, QWidget, QStyleOptionViewItem, QModelIndex):
    return None

#ddrparam界面
class Ui_login_ddrparam(QtWidgets.QMainWindow, Ui_ddrparam):
    def __init__(self):
        super(Ui_login_ddrparam,self).__init__()
        self.setupUi(self)
        # 显示窗口标题
        self.setWindowTitle(window_title_g)
        # 显示窗口图标
        if platform.system().lower() == 'linux':
            self.setWindowIcon(QIcon(logo_file_ubuntu_g))
        else:
            self.setWindowIcon(QIcon(logo_file_windows_g))
        # 注册状态栏
        self.statusBar()
        self.statusBar().showMessage('Ready: 请点击【...】选择要修改的文件或者输入文件路径后点击【确认】')

        # 变量声明
        self.chip_name = 'null'
        self.ddr_bin_file_path = 'null'
        self.loader_file_path = 'null'
        self.loader_pack_params = 'null'
        self.language = 'null'
        self.res_dict = {}
        self.loader_params_dict = {}

        # 按钮注册和属性配置
        # 注册ddr bin相关功能按钮
        self.pushButton_db_sel.clicked.connect(self.clicked_button_db_sel)
        self.pushButton_db_con.clicked.connect(self.clicked_button_db_con)
        self.pushButton_db_gen.clicked.connect(self.clicked_button_db_gen)
        # 注册loader相关功能按钮
        self.pushButton_ld_sel.clicked.connect(self.clicked_button_ld_sel)
        self.pushButton_ld_con.clicked.connect(self.clicked_button_ld_con)
        self.pushButton_ld_gen.clicked.connect(self.clicked_button_ld_gen)
        # 注册DDR类型选择按钮
        self.pushButton_common.clicked.connect(self.clicked_button_common)
        self.pushButton_lpddr5.clicked.connect(self.clicked_button_lpddr5)
        self.pushButton_lpddr4.clicked.connect(self.clicked_button_lpddr4)
        self.pushButton_lpddr4x.clicked.connect(self.clicked_button_lpddr4x)
        self.pushButton_lpddr3.clicked.connect(self.clicked_button_lpddr3)
        self.pushButton_lpddr2.clicked.connect(self.clicked_button_lpddr2)
        self.pushButton_ddr4.clicked.connect(self.clicked_button_ddr4)
        self.pushButton_ddr3.clicked.connect(self.clicked_button_ddr3)
        self.pushButton_ddr2.clicked.connect(self.clicked_button_ddr2)
        self.pushButton_all.clicked.connect(self.clicked_button_all)
        # 隐藏loader相关按钮
        self.pushButton_ld_sel.setVisible(False)
        self.pushButton_ld_con.setVisible(False)
        self.pushButton_ld_gen.setVisible(False)
        self.lineEdit_loader.setVisible(False)
        self.lineEdit_pack_param.setVisible(False)

        # 隐藏 all param按钮
        self.pushButton_all.setVisible(False)

        # disable ddr bin generate按钮
        self.pushButton_db_gen.setEnabled(False)
        # disable DDR类型选择按钮
        self.pushButton_all.setEnabled(False)
        self.pushButton_common.setEnabled(False)
        self.pushButton_lpddr5.setEnabled(False)
        self.pushButton_lpddr4.setEnabled(False)
        self.pushButton_lpddr4x.setEnabled(False)
        self.pushButton_lpddr3.setEnabled(False)
        self.pushButton_lpddr2.setEnabled(False)
        self.pushButton_ddr4.setEnabled(False)
        self.pushButton_ddr3.setEnabled(False)
        self.pushButton_ddr2.setEnabled(False)

        # 调用Drops方法
        self.setAcceptDrops(True)
    # 鼠标拖入事件
    def dragEnterEvent(self, evn):
        #print('鼠标拖入窗口了')
        # 鼠标放开函数事件
        evn.accept()
    # 鼠标放开执行
    def dropEvent(self, evn):
        #print('鼠标放开了')
        print('拖入文件路径：\n' + evn.mimeData().text())
        if self.pushButton_db_con.isEnabled():
            if platform.system().lower() == 'linux':
                self.lineEdit_ddrbin.setText(str(evn.mimeData().text()[7:-2].replace('%20', ' ')))
            else:
                self.lineEdit_ddrbin.setText(str(evn.mimeData().text()[8:]))
            self.clicked_button_db_con()
        else:
            if platform.system().lower() == 'linux':
                self.lineEdit_ddrbin.setText(str(evn.mimeData().text()[7:-2]).replace('%20', ' '))
            else:
                self.lineEdit_ddrbin.setText(str(evn.mimeData().text()[8:]))
            self.clicked_button_ld_con()
    #def dragMoveEvent(self, evn):
    #    print('鼠标移入')
    # 弹出提示框
    def show_warning_message(self, message):
        QMessageBox.warning(self, "Warning", message, QMessageBox.Ok)
    def show_information_message(self, message):
        QMessageBox.information(self, "Information", message, QMessageBox.Ok)
    def show_error_message(self, message):
        QMessageBox.critical(self, "Error", message)
    # 刷新DDR参数tableWidget
    def show_ddr_params_tableWidget(self, csv_file_path, dram_type = "NULL"):
        # 判断存放DDR params的字典是否存在
        if not bool(self.res_dict):
            return

        # 读取完整的ddr params数据
        data_df_full = modify_ddr_bin.get_cfg_file(ddrbin_param_dict_g["Other"]).fillna(' ')

        # 截取指定DDR类型的数据，如果是"DRAM_TYPE_ALL"，则显示完整的ddr params数据
        if dram_type == "DRAM_TYPE_ALL":
            data_df = data_df_full
            columns_list = data_df.columns.tolist()
            data_df = data_df.loc[(data_df[columns_list[0]]!=' ')]
        else:
            # 读取当前芯片平台的ddr params数据
            data_df = modify_ddr_bin.get_cfg_file(csv_file_path).fillna(' ')
            columns_list = data_df.columns.tolist()
            # 为空的项，从data_df_full读取填充
            for row in range(data_df.shape[0]):
                if data_df.iloc[row, 2] == ' ' and data_df_full.loc[data_df_full[columns_list[0]] == str(data_df.iloc[row, 0])].iloc[0, 2] != ' ':
                    data_df.iloc[row, 2] = data_df_full.loc[data_df_full[columns_list[0]] == str(data_df.iloc[row, 0])].iloc[0, 2]
                if data_df.iloc[row, 3] == ' ' and data_df_full.loc[data_df_full[columns_list[0]] == str(data_df.iloc[row, 0])].iloc[0, 3] != ' ':
                    data_df.iloc[row, 3] = data_df_full.loc[data_df_full[columns_list[0]] == str(data_df.iloc[row, 0])].iloc[0, 3]
                if data_df.iloc[row, 4] == ' ' and data_df_full.loc[data_df_full[columns_list[0]] == str(data_df.iloc[row, 0])].iloc[0, 4] != ' ':
                    data_df.iloc[row, 4] = data_df_full.loc[data_df_full[columns_list[0]] == str(data_df.iloc[row, 0])].iloc[0, 4]
                if data_df.iloc[row, 5] == ' ' and data_df_full.loc[data_df_full[columns_list[0]] == str(data_df.iloc[row, 0])].iloc[0, 5] != ' ':
                    data_df.iloc[row, 5] = data_df_full.loc[data_df_full[columns_list[0]] == str(data_df.iloc[row, 0])].iloc[0, 5]
                if data_df.iloc[row, 6] == ' ' and data_df_full.loc[data_df_full[columns_list[0]] == str(data_df.iloc[row, 0])].iloc[0, 6] != ' ':
                    data_df.iloc[row, 6] = data_df_full.loc[data_df_full[columns_list[0]] == str(data_df.iloc[row, 0])].iloc[0, 6]
            # 截取自定DDR类型的数据
            data_df = data_df.loc[(data_df[columns_list[-1]] == dram_type)]

        # 删除最后一列(属性)
        data_df = data_df.drop([columns_list[-1]], axis =1)
        if self.language == "English":
            data_df = data_df.drop([columns_list[-3]], axis =1)
        else:
            data_df = data_df.drop([columns_list[-2]], axis =1)
        # 获取新的datafram列名称
        if self.language == "English":
            columns_list = ["name", "value", "effective value", "Unit", "params"]
        else:
            columns_list = data_df.columns.tolist()
        # 设置列表模型
        self.tableWidget.setColumnCount(len(columns_list))
        self.tableWidget.setRowCount(data_df.shape[0])
        # 设置水平方向两个头标签文本内容
        self.tableWidget.setHorizontalHeaderLabels(columns_list)

        # 从data_df读取数据填充tableWidget item
        for row in range(data_df.shape[0]):
            for column in range(data_df.shape[1]):
                #print(row, column)
                # 如果“有效值”带“|”，则“配置值”显示为QComboBox复选框形式
                if column == 1:
                    try:
                        item_data = self.res_dict[str(data_df.iloc[row, 0])]
                    except KeyError:
                        continue
                    newItem = QTableWidgetItem(item_data)
                    # 设置字体，字号，颜色
                    newItem.setFont(QFont('Times', 12, QFont.Black))
                    self.tableWidget.setItem(row, column, newItem)
                    # 判断有效值带“|”，则创建QComboBox()
                    data_str = str(data_df.iloc[row, column + 1])
                    if "|" in data_str:
                        data_list = data_str.split('|')
                        if self.tableWidget.item(row, column).text() not in data_list:
                            data_list.append(self.tableWidget.item(row, column).text())
                        comBox_direction = QComboBox()
                        comBox_direction.addItems(data_list)
                        comBox_direction.setCurrentText(self.tableWidget.item(row, column).text())
                        #comBox_direction.setStyleSheet("QComboBox{margin:3px};")
                        # 设置字体，字号，颜色
                        comBox_direction.setFont(QFont('Times', 12, QFont.Black))
                        self.tableWidget.setCellWidget(row, column, comBox_direction)
                    # 判断有效值带"——"，则设置单元格不可编辑
                    elif "——" in data_str:
                        newItem.setFlags(QtCore.Qt.ItemIsEnabled)
                # 如果“有效值”带“|”，因为“配置值”项已改为复选框形式，“有效值”项目值显示单字符“|”
                elif column == 2:
                    item_data = str(data_df.iloc[row, column])
                    if "|" in item_data:
                        newItem = QTableWidgetItem('|')
                    else:
                        newItem = QTableWidgetItem(item_data)
                    self.tableWidget.setItem(row, column, newItem)
                else:
                    item_data = str(data_df.iloc[row, column])
                    newItem = QTableWidgetItem(item_data)
                    self.tableWidget.setItem(row, column, newItem)

        # 水平方向标签拓展剩下的窗口部分，填满表格
        self.tableWidget.horizontalHeader().setStretchLastSection(True)
        # 水平方向，根据内容自动调节大小
        self.tableWidget.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
        # 垂直方向，根据内容自动调节大小
        self.tableWidget.verticalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
        # 隔行改变颜色
        self.tableWidget.setAlternatingRowColors(True)
        # 除第一列外，其他列设置为不可编辑
        for column in range(self.tableWidget.columnCount()):
            if column != 1:
                self.tableWidget.setItemDelegateForColumn(column, EmptyDelegate(self))


    # 根据ddr params，enable相关按钮
    def enable_pushbutton_dram_type(self, data_dict):
        if not bool(data_dict):
            return

        self.pushButton_db_gen.setEnabled(True)
        self.pushButton_ld_gen.setEnabled(True)

        self.pushButton_common.setEnabled(True)
        self.pushButton_all.setEnabled(True)
        self.pushButton_lpddr5.setEnabled(False)
        self.pushButton_lpddr4.setEnabled(False)
        self.pushButton_lpddr4x.setEnabled(False)
        self.pushButton_lpddr3.setEnabled(False)
        self.pushButton_lpddr2.setEnabled(False)
        self.pushButton_ddr4.setEnabled(False)
        self.pushButton_ddr3.setEnabled(False)
        self.pushButton_ddr2.setEnabled(False)
        if data_dict["lp5_freq"] != '0':
            self.pushButton_lpddr5.setEnabled(True)
        if data_dict["lp4_freq"] != '0':
            self.pushButton_lpddr4.setEnabled(True)
        if data_dict["lp4x_freq"] != '0':
            self.pushButton_lpddr4x.setEnabled(True)
        if data_dict["lp3_freq"] != '0':
            self.pushButton_lpddr3.setEnabled(True)
        if data_dict["lp2_freq"] != '0':
            self.pushButton_lpddr2.setEnabled(True)
        if data_dict["ddr4_freq"] != '0':
            self.pushButton_ddr4.setEnabled(True)
        if data_dict["ddr3_freq"] != '0':
            self.pushButton_ddr3.setEnabled(True)
        if data_dict["ddr2_freq"] != '0':
            self.pushButton_ddr2.setEnabled(True)
    # 从tableWidget读取配置值更新ddr params
    def update_ddr_params_by_tableWidget(self, remove_CellWidget = True):
            try:
                self.tableWidget
            except AttributeError:
                return

            # 将复选框选中的值，填入tableWidget item
            for row in range(self.tableWidget.rowCount()):
                #for column in range(self.tableWidget.columnCount()):
                    #print(self.tableWidget.item(row, 0).text())
                    try:
                        item_str = self.tableWidget.item(row, 2).text()
                    except AttributeError:
                        continue
                    # 读取复选框中的值
                    if "|" in item_str:
                        newItem = QTableWidgetItem(self.tableWidget.cellWidget(row, 1).currentText())
                        self.tableWidget.setItem(row, 1, newItem)
                        if remove_CellWidget == True:
                            self.tableWidget.removeCellWidget(row, 1)
                    # 检查配置值是否在有效范围内
                    elif "-" in item_str:
                        offset = item_str.find('-')
                        try:
                            value = self.tableWidget.item(row, 1).text()
                        except AttributeError:
                            continue
                        # 字符串转为整型苏剧
                        if "0x" in item_str[: offset]:
                            min_int = int(item_str[: offset], 16)
                        else:
                            min_int = int(item_str[: offset])
                        if "0x" in item_str[offset + 1:]:
                            max_int = int(item_str[offset + 1:], 16)
                        else:
                            max_int = int(item_str[offset + 1:])
                        if "0x" in value:
                            value = int(value, 16)
                        else:
                            value = int(value)
                        if value < min_int or value > max_int:
                            print(self.tableWidget.item(row, 0).text(), value, item_str)
                            continue

            # 从tableWidget item读取数据，更新ddr params
            for row in range(self.tableWidget.rowCount()):
                param_name = self.tableWidget.item(row, 0).text()
                try:
                    param_value = self.tableWidget.item(row, 1).text()
                except AttributeError:
                    continue
                self.res_dict[param_name] = param_value
    # 定义dram type相关按钮
    def clicked_button_dram_type(self, dram_type):
        if self.res_dict:
            self.update_ddr_params_by_tableWidget()
            self.show_ddr_params_tableWidget(ddrbin_param_dict_g[self.chip_name], dram_type)
            if self.language == "English":
                self.statusBar().showMessage(str('OK: get ' + dram_type + ' parameter succeed，Creat ddr bin if completed modification.'))
            else:
                self.statusBar().showMessage(str('OK: 获取' + dram_type + '参数成功，请完成配置完成后点击对应的【生成】按钮。'))
        else:
            if self.language == "English":
                self.statusBar().showMessage('Error: DDR parameter is NULL，please reselect ddr bin which you need modify.')
            else:
                self.statusBar().showMessage('Error: DDR配置参数为空，请先选择要修改原始的文件。')
    def clicked_button_common(self):
        self.clicked_button_dram_type("COMMON")
    def clicked_button_lpddr5(self):
        self.clicked_button_dram_type("LPDDR5")
    def clicked_button_lpddr4(self):
        self.clicked_button_dram_type("LPDDR4")
    def clicked_button_lpddr4x(self):
        self.clicked_button_dram_type("LPDDR4X")
    def clicked_button_lpddr3(self):
        self.clicked_button_dram_type("LPDDR3")
    def clicked_button_lpddr2(self):
        self.clicked_button_dram_type("LPDDR2")
    def clicked_button_ddr4(self):
        self.clicked_button_dram_type("DDR4")
    def clicked_button_ddr3(self):
        self.clicked_button_dram_type("DDR3")
    def clicked_button_ddr2(self):
        self.clicked_button_dram_type("DDR2")
    def clicked_button_all(self):
        self.clicked_button_dram_type("DRAM_TYPE_ALL")
    # 定义按钮功能，选取ddr bin文件
    def clicked_button_db_sel(self):
        openfile_name = QtWidgets.QFileDialog.getOpenFileName(self, '选择文件', '', 'binary file(*.bin);;All Files(*)')
        self.lineEdit_ddrbin.setText(str(openfile_name[0]))
        self.clicked_button_db_con()
    # 定义按钮功能，读取ddr bin中的ddr params
    def clicked_button_db_con(self):
        self.res_dict = {}
        # 读取输入框内的ddr bin文件路径
        self.ddr_bin_file_path = self.lineEdit_ddrbin.text()

        # 如果输入的是“loader”，则根据平台支持情况，显示loader相关按钮或者提示不支持。
        if self.ddr_bin_file_path == 'loader':
            if self.chip_name in loader_pack_dict_g:
                self.loader_pack_params = loader_pack_dict_g[self.chip_name]
                # 显示loader相关功能按钮
                self.pushButton_ld_gen.setVisible(True)
                self.pushButton_ld_con.setVisible(True)
                self.pushButton_ld_sel.setVisible(True)
                self.lineEdit_loader.setVisible(True)
                self.lineEdit_pack_param.setVisible(True)
                # button disable，ddr bin相关按钮
                self.pushButton_db_sel.setEnabled(False)
                self.pushButton_db_con.setEnabled(False)
                # button disable，loader生成按钮，在加载loader文件后enable
                self.pushButton_ld_gen.setEnabled(False)
            else:
                if self.language == "English":
                    self.show_warning_message("[" + self.chip_name + "]，unsupported.")
                else:
                    self.show_warning_message("【" + self.chip_name + "】，暂不支持该功能。")
            return
        elif self.ddr_bin_file_path == 'all_param':
            self.pushButton_all.setVisible(True)
            return

        # 检查ddr bin文件是否存在
        if os.path.exists(self.ddr_bin_file_path) == False:
            if self.language == "English":
                self.statusBar().showMessage('Error: file does not exist，please check file path.')
            else:
                self.statusBar().showMessage('Error：文件不存在，请检查文件路径是否正确。')
            return
        # 如果是loader文件显示loader相关按钮，否则隐藏loader相关按钮
        if modify_ddr_bin.check_if_loadr_file(self.ddr_bin_file_path) == True:
            self.loader_pack_params = loader_pack_dict_g[self.chip_name]
            #self.show_warning_message("所选文件可能是loader文件，请确认，并正确选择ddr bin文件。")
            # 显示loader相关功能按钮
            self.pushButton_ld_gen.setVisible(True)
            self.lineEdit_pack_param.setVisible(True)

            self.lineEdit_loader.setText(self.ddr_bin_file_path)
            self.clicked_button_ld_con()
            return
        else:
            # 显示loader相关功能按钮
            self.pushButton_ld_gen.setVisible(False)
            self.lineEdit_pack_param.setVisible(False)

        # 读取ddr bin文件中的ddr prams
        self.res_dict, ret = modify_ddr_bin.get_ddr_params(self.ddr_bin_file_path, self.chip_name)
        if ret != 0:
            if self.language == "English":
                self.show_warning_message("please check file is [" + self.chip_name + "] ddr bin, reselect if not.")
            else:
                self.show_warning_message("请确认所选文件是否为【" + self.chip_name + "】ddr bin文件。如果不是，请重选。")
        if not bool(self.res_dict):
            if self.language == "English":
                self.statusBar().showMessage('ERROR: get DDR parameter fail, please check file is ddr bin.')
                self.show_error_message("get DDR parameter fail, please check file is ddr bin.")
            else:
                self.statusBar().showMessage('ERROR： 获取DDR参数，失败。请检查所选文件是否为ddr bin文件。')
                self.show_error_message("获取DDR参数，失败。请检查所选文件是否为ddr bin文件。")
        else:
            if self.language == "English":
                self.statusBar().showMessage('OK：get DDR prameter succeed, please select dram type which need modify.')
            else:
                self.statusBar().showMessage('OK：获取DDR参数，成功。请选择要修改参数的DDR类型。')
        # tableWidget默认显示“COMMON”属性参数
        self.show_ddr_params_tableWidget(ddrbin_param_dict_g[self.chip_name], "COMMON")
        # 根据ddr params中的dram type支持情况，使能相关按钮
        self.enable_pushbutton_dram_type(self.res_dict)
    # 定义按钮功能，生成ddr bin
    def clicked_button_db_gen(self):
        if self.res_dict:
            self.update_ddr_params_by_tableWidget(remove_CellWidget = False)
            file_path = modify_ddr_bin.update_ddr_bin(self.res_dict, self.ddr_bin_file_path, not self.radioButton.isChecked())
            if self.language == "English":
                self.statusBar().showMessage(str('OK：Create ddr bin succeed. file path: ' + file_path))
            else:
                self.statusBar().showMessage(str('OK：生成ddr bin，成功。文件路径为：' + file_path))
            data_str =  modify_ddr_bin.cpmpare_ddr_param()
            if self.language == "English":
                self.show_information_message('Crete ddr bin succeed, file path: ' + file_path + '\n\n' + data_str)
            else:
                self.show_information_message('生成ddr bin，成功。文件路径为：' + file_path + '\n\n' + data_str)
        else:
            if self.language == "English":
                self.statusBar().showMessage('Error: DDR parameter is NULL.')
            else:
                self.statusBar().showMessage('Error: DDR配置参数为空，请先读取')
    # 定义按钮功能，选取loader文件
    def clicked_button_ld_sel(self):
        openfile_name = QtWidgets.QFileDialog.getOpenFileName(self, '选择文件', '', 'binary file(*.bin);;All Files(*)')
        self.lineEdit_loader.setText(str(openfile_name[0]))
        self.clicked_button_ld_con()
    # 定义按钮功能，读取loader的ddr params
    def clicked_button_ld_con(self):
        self.res_dict = {}
        # 读取输入框内的loader文件路径
        self.loader_file_path = self.lineEdit_loader.text()

        if self.loader_file_path == 'pack_param':
            self.lineEdit_pack_param.setVisible(True)
            return

        # 检查loader文件是否存在
        if os.path.exists(self.loader_file_path) == False:
            if self.language == "English":
                self.statusBar().showMessage('Error: loader file does not exist')
            else:
                self.statusBar().showMessage('Error：loader文件不存在')
            return

        # loader文件解包
        self.loader_params_dict = modify_ddr_bin.loader_unpack(self.loader_file_path, self.chip_name)
        if not bool(self.loader_params_dict):
            if self.language == "English":
                self.statusBar().showMessage('Error: loader unpack fail, please check file is loader.')
                self.show_error_message("loader unpack fail, please check file is loader.")
            else:
                self.statusBar().showMessage('Error：解包失败，请检查该文件是否为loader文件。')
                self.show_error_message("解包失败，请检查该文件是否为loader文件。")
            return

        # 记录loader文件路径
        self.loader_file_path = self.loader_params_dict["loader_file_path"]
        # 记录ddr bin文件路径
        self.ddr_bin_file_path = self.loader_params_dict["loader_471"]
        # 读取ddr bin文件中的ddr params
        self.res_dict, ret_int = modify_ddr_bin.get_ddr_params(self.ddr_bin_file_path, self.chip_name)
        if ret_int != 0:
            if self.language == "English":
                self.show_warning_message("please check file is [" + self.chip_name + "】loader, reselect if not.")
            else:
                self.show_warning_message("请确认所选文件是否为【" + self.chip_name + "】loader文件。如果不是，请重选。")
        # tableWidget默认显示“COMMON”属性参数
        self.show_ddr_params_tableWidget(ddrbin_param_dict_g[self.chip_name], "COMMON")
        # 根据ddr params中的dram type支持情况，使能相关按钮
        self.enable_pushbutton_dram_type(self.res_dict)
        if self.language == "English":
            self.statusBar().showMessage('OK: get DDR parameter succeed, please select dram type which need modify')
        else:
            self.statusBar().showMessage('OK： 获取DDR参数，成功。请选择要配置的DDR类型。')

        self.loader_params_dict["pack_params"] += ' ' + self.loader_pack_params
        self.lineEdit_pack_param.setText(self.loader_params_dict["pack_params"])
        # loader警告框
        if self.language == "English":
            self.show_warning_message("The loader file generated by the tool may have different packing parameters from the original loader file. " + \
                "Therefore, the Loader generated by the tool is only use for debugging DDR parameter. " +\
                "After DDR parameter debugging, select create the DDR bin file and pack the generated DDR bin file in the code project.")
        else:
            self.show_warning_message("该工具重新生成的loader文件与原始loader文件可能存在打包参数的差异，因此通过该工具生成的loader仅供调测DDR参数使用。" +\
                "正式使用的loader，请选择生成ddr bin文件，并将生成的ddr bin文件放入代码工程中进行打包。")
    #定义按钮功能，重新生成loader
    def clicked_button_ld_gen(self):
        if self.res_dict:
            self.update_ddr_params_by_tableWidget(remove_CellWidget = False)
            self.loader_params_dict["loader_471"] = \
                modify_ddr_bin.update_ddr_bin(self.res_dict, self.ddr_bin_file_path, False)
            self.loader_params_dict["pack_params"] = self.lineEdit_pack_param.text()

            if "loader_file_path" not in self.loader_params_dict:
                if self.language == "English":
                    self.statusBar().showMessage('Error: Create loader fail')
                else:
                    self.statusBar().showMessage('Error： 生成loader，失败。请先加载loader文件。')
                return
            # 打包loader文件
            file_path = modify_ddr_bin.loader_pack(self.loader_params_dict, not self.radioButton.isChecked())
            if self.language == "English":
                self.statusBar().showMessage('OK: Create loader succeed, file path：' + file_path)
            else:
                self.statusBar().showMessage('OK: 生成loader，成功。文件路径为：' + file_path)
            data_str =  modify_ddr_bin.cpmpare_ddr_param()
            if self.language == "English":
                self.show_information_message('Create loader succeed, file path：' + file_path + '\n\n' + data_str)
            else:
                self.show_information_message('生成loader，成功。文件路径为：' + file_path + '\n\n' + data_str)
        else:
            if self.language == "English":
                self.statusBar().showMessage('Error: DDR parameter is NULL')
            else:
                self.statusBar().showMessage('Error: DDR配置参数为空，请先读取')


# 登录界面
class login(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(login,self).__init__()
        self.setupUi(self)
        # 设置窗口标题和图标
        self.setWindowTitle(window_title_g)
        self.setWindowIcon(QIcon(logo_file_g))
    def language_change(self):
        if self.comboBox_2.currentText() == "English":
            self.label.setText("Select the chip platform: ")
            self.pushButton.setText("submit")
        else:
            self.label.setText("请选择芯片平台：")
            self.pushButton.setText("确认")
    # 定义按钮功能，进入主界面
    def login_enter(self):
        # 隐藏登录界面
        self.hide()
        # 显示主界面
        self.ddrparam = Ui_login_ddrparam()
        self.ddrparam.show()
        # 主界面，rockchip logo
        pixmap = QPixmap(rockchip_logo_file_g)
        self.ddrparam.label_rk_logo.setPixmap (pixmap)
        self.ddrparam.label_rk_logo.setScaledContents (True)

        # 注册主界面“返回”按钮功能，关闭主界面，返回登录界面
        self.ddrparam.pushButton_return.clicked.connect(self.ddrparam.close)
        self.ddrparam.pushButton_return.clicked.connect(self.show)

        # 主界面，获取chip name并显示
        self.ddrparam.chip_name = self.comboBox.currentText()
        self.ddrparam.label_chip_name.setText(str("CHIP:" + self.ddrparam.chip_name))

        # 主界面语言设置
        self.ddrparam.language = self.comboBox_2.currentText()
        if self.ddrparam.language == "English":
            self.ddrparam.lineEdit_ddrbin.setPlaceholderText("Select ddr bin file")
            self.ddrparam.lineEdit_ddrbin.setPlaceholderText("Select ddr bin file")
            self.ddrparam.pushButton_db_con.setText("submit")
            self.ddrparam.pushButton_db_gen.setText("Create ddr bin")
            self.ddrparam.pushButton_ld_gen.setText("Create loader")
            self.ddrparam.pushButton_return.setText("Return")
            self.ddrparam.radioButton.setText("Overwrite File")
            self.ddrparam.statusBar().showMessage('Ready: clicked [...] to select ddr bin file')

if __name__=="__main__":
    #QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
    app = QtWidgets.QApplication(sys.argv)
    # 显示登录界面
    first = login()
    first.show()
    # 登录界面，rockchip logo
    pixmap = QPixmap(rockchip_logo_file_g)
    first.label_rk_logo.setPixmap (pixmap)
    first.label_rk_logo.setScaledContents (True)

    # 登录界面，芯片平台选择
    chip_list = ddrbin_param_dict_g.keys()
    first.comboBox.addItems(chip_list)
    first.comboBox.setFont(QFont('Times', 12, QFont.Black))
    first.comboBox.setStyleSheet("QComboBox{margin:3px};")

    # 登录界面，语言选择
    language_list=["中文", "English"]
    first.comboBox_2.addItems(language_list)
    first.comboBox_2.setStyleSheet("QComboBox{margin:3px};")
    first.comboBox_2.currentIndexChanged.connect(first.language_change)

    # 登录界面，确认按钮
    first.pushButton.clicked.connect(first.login_enter)
    sys.exit(app.exec())
