import sys  
import struct  
import os
#import crcmod
#import menu_pump as menu
#import MenuDesc as menu
import menu_pump_ver_wolong as menu
#import menu_pump_hor_panda as menu
#import menu_mine as menu
import re
import time
import sys
import zlib
import menu_utils as utils
from device_conf import class_comm_device_config
from enum import Enum
from print_color import *
from NameConvert import get_variable_name
import pypinyin
from pypinyin import pinyin
from pypinyin import lazy_pinyin, Style
from datetime import datetime
 
current_time = datetime.now()
print(current_time)


DEFAULT_EMPTY_STR = " "
DEFAULT_FORMAT_STR = "%5d"

MENU_ITEM_NORMAL = 0
MENU_ITEM_ALIAS = 1
MENU_ITEM_SUB_MENU = 2

def DebugPrint(object) :
    #print(object)
    return
    
#定义字典管理类：
class DictsManager():             

    def __init__(self) -> None:
        #--Dict----------------------------------------------------------------------------------------------------------------------------
        #-全局别名字典-
        self.MenuAliasDict = {}                                                  #<alias>字段字典
        self.MenuAliasIndex = 0                                                  #<alias>字段字典索引
        
        self.MenuCommDict = {}
        self.MenuCommTable = []
        self.MenuCommTableIndex = 0
        
        # 全局菜单项
        self.MenuItemList = []

        self.config : class_comm_device_config= menu.comm_device_config
        
        self.encode_type = 'utf-8'
        if hasattr(self.config, "is_gb2312") :
            if self.config.is_gb2312() :
                self.encode_type = 'gb2312'
            
        self.alias_table = self.config.get_alias_table()
        self.menu_top    = self.config.get_menu_top()
        self.menu_description = self.config.get_menu_caption_info()
        
        self.MenuDescriptionTable = []
        
        
        self.comm_table, self.func_comm_table_trigger_check  = self.config.get_comm_table()
    
        #-全局字符串字典-
        self.MenuStringDict = {}                                                 #菜单字符串表
        self.MenuStringOffset = 0                                                #菜单字符串表索引

        #-<xx>字段字典->Format,Unit,Action
        self.MenuScaleFormatDict = {}                                            #<format>字段字典
        self.MenuScaleFormatIndex = 0                                            #<format>字段字典索引
        self.MenuScaleFormatTable = []
        
        self.MenuUnitDict = {}                                                   #<unit>字段字典
        self.MenuUnitIndex = 0                                                   #<unit>字段字典索引

        self.MenuActionDict = {}                                                 #<action>字段字典
        self.MenuActionIndex = 0                                                 #<action>字段字典索引
        
        #--Table---------------------------------------------------------------------------------
        #-根据MenuAliasDict字典创建的MenuAliasTable
        #-别名表
        self.MenuAliasTable = []                                                        #一级别名表
        self.MenuAliasTableIndex = 0                                                    #一级表索引
        
        self.MenuAliasTable2 = []                                                       #二级别名表
        self.MenuAliasTable2Index = 0                                                   #二级表索引

        self.MenuLimitDict = {}
        self.MenuLimitTable = []
        self.MenuLimitIndex = 0
        
        self.MenuRegAddrDict = {}
        self.MenuRegAddrTable = []
        self.MenuRegAddrIndex = 0
        
        self.MenuSubMenuDict = {}

        #菜单表
        self.MenuMenuTable = []                                                        #一级菜单表
        self.MenuMenuTableIndex = 0
        self.MenuMenuTable2 = []                                                       #二级菜单表
        self.MenuMenuTable2Index = 0

        self.MenuTopIndex = 0
        self.MenuProcessedList = []   #已经完成处理的菜单项，防止递归电压
        
        #self.MenuJsonDict
        
        #--PackedTable---------------------------------------------------------------------------------
        #-全局字符串字典MenuStringDict打包后的字符表
        self.Packed_MenuStringTable = bytes()     

        #-<Unit>字典MenuUnitTable打包后的字符表
        self.Packed_MenuUnitTable = bytes()

        #-<Format>字典MenuScaleFormatTable打包后的字符表
        self.Packed_MenuScaleFormatTable = bytes()

        #-<Action>字典MenuActionTable打包后的字符表
        self.Packed_MenuActionTable = bytes()
        
        #-<Limit>字典MenuLimitTable打包后的字符表
        self.Packed_MenuLimitTable = bytes()
        
        #-<Comm>字典MenuCommTable打包后的字符表
        self.Packed_MenuCommTable = bytes()


        #--Buf---------------------------------------------------------------------------------
        self.Packed_AliasBuf = bytes()
        self.Packed_AliasBuf2 = bytes()

        self.Packed_MenuBuf = bytes()
        self.Packed_MenuBuf2 = bytes()
        
        self.Packed_MenuDescription = bytes()

        #-
                                                        #字符串打包时设置的编码格式

        pass

    #--内部API-----------------------------------------------------------------------------------------------------------------------------
    #从列表中获取字典------------------
    def GetDict_Alias(self,alias_str):                                            #从列表alias_table中，获取参数alias_str指定的字典
        for item in self.alias_table:                                                  #[1]遍历列表中的所有字典
            if alias_str in item.keys():                                          #[2]判断alias_str指定的字典是否存在
                return item                                                       #[3]字典存在，将其返回<string,<int,string>>,存储字典的字典
        return None                                                               #[4]列表遍历完毕后字典未找到，返回None

    #填充MenuStringDict---------------
    def AddKeyTo_MenuStringDict(self,info_str) :                                  #填充<Menu_StringDict>:将字符串及其对应的序号填入
        if self.MenuStringOffset == 0:
            self.MenuStringDict[DEFAULT_EMPTY_STR] = self.MenuStringOffset
            self.MenuStringOffset += len(DEFAULT_EMPTY_STR.encode(self.encode_type)) + 1
        if info_str not in self.MenuStringDict.keys():                            #首先判断要添加的info_str是否已经存在
            self.MenuStringDict[info_str] = self.MenuStringOffset                 #添加键值对儿:<info_str - Menu_StringOffset>
            self.MenuStringOffset += len(info_str.encode(self.encode_type)) + 1   #序号自增：字符串索引的长度+1  以0分割？

    #查询MenuStringDict---------------
    def GetOffsetFrom_MenuStringDict(self,info_str):                              #从<Menu_StringDict>中，查询info_str对应的偏移值
        offset = 0
        if info_str in self.MenuStringDict.keys():                                #[1]首先判断要查询的info_str是否存在
            offset = self.MenuStringDict[info_str]                                  #[2]返回字典中的记录：info_str对应的偏移值
        return offset
    
    def GetStringFromOffset(self, offset) :
        my_list = (list(filter(lambda k1: self.MenuStringDict[k1] == offset, self.MenuStringDict)))
        
        if (len(my_list)== 1) :
            return my_list[0]
        return None
    
    def menu_get_str_key(self, str1, str2) :
        return str1 + "," + str2

    #填充MenuScaleFormatDict--------------- 
    def AddKeyTo_MenuScaleFormatDict(self, scale_str, format_str) :                   #填充<Menu_FormatDict>:将字符串及其对应的序号填入
        str_key = self.menu_get_str_key(scale_str, format_str)

        if self.MenuScaleFormatIndex == 0 :
            self.MenuScaleFormatDict[DEFAULT_EMPTY_STR] = self.MenuScaleFormatIndex
            self.MenuScaleFormatTable.append([0, 0])
            self.MenuScaleFormatIndex += 1                                            #序号自增1

        self.AddKeyTo_MenuStringDict(scale_str)                                       #将<scale>字段值存储到 Menu_StringDict
        self.AddKeyTo_MenuStringDict(format_str)                                      #将<format>字段值存储到 Menu_StringDict
        if str_key not in self.MenuScaleFormatDict.keys():                            #首先判断要添加的info_str是否已经存在了
            self.MenuScaleFormatDict[str_key] = self.MenuScaleFormatIndex             #添加键值对儿:<info_str - Menu_FormatIndex>
            scale_str_off  = self.GetOffsetFrom_MenuStringDict(scale_str)
            format_str_off = self.GetOffsetFrom_MenuStringDict(format_str)
            self.MenuScaleFormatTable.append([scale_str_off, format_str_off])
            self.MenuScaleFormatIndex += 1                                             #序号自增1


    def Get_ScaleFormatTableIndex(self, scale, format) :
        index = 0
        str_key = self.menu_get_str_key(scale, format)
        if  str_key in self.MenuScaleFormatDict.keys():
            index = self.MenuScaleFormatDict[str_key]
        return index
    
    #填充MenuUnitDict-----------------
    def AddKeyTo_MenuUnitDict(self,info_str) :                                    #填充<Menu_UnitDict>:将字符串及其对应的序号填入
        if self.MenuUnitIndex == 0 :
            self.MenuUnitDict[DEFAULT_EMPTY_STR] = self.MenuUnitIndex
            self.MenuUnitIndex += 1
        if info_str not in self.MenuUnitDict.keys():                              #首先判断要添加的info_str是否已经添加了
            self.MenuUnitDict[info_str] = self.MenuUnitIndex                      #添加键值对儿:<info_str - Menu_UnitIndex>
            self.MenuUnitIndex += 1                                               #序号自增1

    def AddKeyTo_MenuAddrDict(self, reg_addr_str) :
        if self.MenuRegAddrIndex == 0:
            self.MenuRegAddrDict[DEFAULT_EMPTY_STR] = self.MenuRegAddrIndex
            self.MenuRegAddrIndex += 1
            
        if reg_addr_str not in self.MenuRegAddrDict.keys() :
            self.MenuRegAddrDict[reg_addr_str] = self.MenuRegAddrIndex
            self.MenuRegAddrIndex += 1    

    #填充MenuLimitDict-----------------
    def AddKeyTo_LimitDict(self, min_str, max_str) :                              #填充<Menu_UnitDict>:将字符串及其对应的序号填入
        if self.MenuLimitIndex == 0 :
            self.MenuLimitIndex += 1
            self.MenuLimitTable.append([0, 0])
        
        self.AddKeyTo_MenuStringDict(min_str)
        self.AddKeyTo_MenuStringDict(max_str)
        str_key = self.menu_get_str_key(min_str, max_str)

        if  str_key not in self.MenuLimitDict.keys() :
            self.MenuLimitDict[str_key] = self.MenuLimitIndex
            min_str_off = self.GetOffsetFrom_MenuStringDict(min_str)
            max_str_off = self.GetOffsetFrom_MenuStringDict(max_str)
            self.MenuLimitTable.append([min_str_off, max_str_off])
            self.MenuLimitIndex += 1
    
    def Get_LimitTableIndex(self, min_str, max_str) :
        index = 0
        key_str = self.menu_get_str_key(min_str, max_str)
        if  key_str in self.MenuLimitDict.keys() :
            index = self.MenuLimitDict[key_str]

        return index
            
    #填充MenuActionDict---------------
    def AddKeyTo_MenuActionDict(self,info_str) :                                  #构造<Menu_ActionDict>:将字符串及其对应的序号填入
        if self.MenuActionIndex == 0:
            self.MenuActionDict[DEFAULT_EMPTY_STR] = self.MenuActionIndex
            self.MenuActionIndex += 1
        if info_str not in self.MenuActionDict.keys():                            #首先判断要添加的info_str是否已经添加了
            self.MenuActionDict[info_str] = self.MenuActionIndex                  #添加键值对儿:<info_str - Menu_ActionIndex>
            self.MenuActionIndex += 1                                             #序号自增1

    #别名字典alias_dict填充Menu_StringDict----------
    def StuffDict_MenuStringDict_ByAliasDict(self):                               #把别名表中的最底层字典的Value（所有别名）存储到Menu_StringDict
        for alias_dict in self.alias_table :
            for alias_name, value_dict in alias_dict.items():    
                if isinstance(alias_name, Enum):
                    alias_name = alias_name.name
                self.AddKeyTo_MenuStringDict(alias_name)

        for alias_dict in self.alias_table :                                      #遍历alias_table表
            for alias_name, value_dict in alias_dict.items() :                     #遍历alias_table表中的每个字典
                for key, value_str in value_dict.items() :                        #遍历字典中的字典
                    self.AddKeyTo_MenuStringDict(value_str)                       #将所有别名值存入Menu_StringDict
        DebugPrint("<Dict>MenuStringDict->")  
        DebugPrint(self.MenuStringDict)


#--CreateTable-----------------------------------------------------------------------------------------------------------------------------
    def menu_get_min_max_index(self, min_value_str, max_value_str) :
        index = 0
        str_key = self.menu_get_str_key(min_value_str, max_value_str)
        if str_key in self.MenuLimitDict.keys() :
            index = self.MenuLimitDict[str_key]
        return index
    
    def menu_item_get_reg_addr_str(self, menu_item) :
        reg_addr_str  = DEFAULT_EMPTY_STR
        reg_addr = None

        if "addr" in menu_item.keys() :
            reg_addr = menu_item["addr"]
        
        if isinstance(reg_addr, float) :
            reg_addr_str = str(reg_addr)
        elif isinstance(reg_addr, int) :
            reg_addr_str = str(reg_addr)
        elif isinstance(reg_addr, str) :
            reg_addr_str = reg_addr

        return reg_addr_str
    
    def menu_item_remap_addr(self, menu_item) :
        remap_addr = utils.dict_or_object_get_attr(menu_item, "remap_addr", 0)
        return remap_addr
        
    def menu_item_get_min_max_str(self, menu_item) :
        min_value_str  = DEFAULT_EMPTY_STR
        max_value_str  = DEFAULT_EMPTY_STR
    
        min_value  = utils.dict_or_object_get_attr(menu_item, "min", None)
        max_value  = utils.dict_or_object_get_attr(menu_item, "max", None)
        format_str = utils.dict_or_object_get_attr(menu_item, "format", "%05.0f")
        
        if isinstance(min_value, float) :
            min_value_str = format_str%(min_value)
        elif isinstance(min_value, int) :
            min_value = min_value * 1.0
            min_value_str = format_str%(min_value)
        elif isinstance(min_value, str) :
            min_value_str = min_value

        if isinstance(max_value, float) :
            max_value_str = format_str%(max_value)
        elif isinstance(max_value, int) :
            max_value = max_value * 1.0
            max_value_str = format_str%(max_value)
        elif isinstance(max_value, str) :
            max_value_str = max_value

        return min_value_str, max_value_str
                        
    def menu_item_get_scale_format(self, menu_item) :
        scale_str  = str(1.0)
        format_str = DEFAULT_EMPTY_STR
        format_value = None
        scale_value = None
        
        if "format" in menu_item.keys() :
            format_value = menu_item["format"]
        if "scale" in menu_item.keys() :
            scale_value = menu_item["scale"]
            
        if isinstance(format_value, float) :
            format_str = str(format_value)
        elif isinstance(format_value, str) :
            format_str = format_value
    
        if isinstance(scale_value, float) :
            scale_str = str(scale_value)
        elif isinstance(scale_value, str) :
            scale_str = scale_value
            
        return scale_str, format_str
    
    #根据菜单内容，填充各个字段字典->MenuUnitDict,MenuScaleFormatDict,MenuActionDict---
    def StuffDict_MenuDict(self,menu, lead):                                      #填充一个菜单对应的各个字典，menu:指定的菜单，lead:要添加信息的各个属性字段字典
        if menu == None :
            return
        for menu_item in menu :                                                   #遍历菜单的各个菜单项
            if lead == "scale_format" :                                           #处理<scale format>字段：
                scale_str, format_str = self.menu_item_get_scale_format(menu_item)
                self.AddKeyTo_MenuScaleFormatDict(scale_str, format_str)          #将<scale format>字段值存储到 Menu_FormatDict                
            if lead == "min_max" :
                min_value_str, max_value_str = self.menu_item_get_min_max_str(menu_item)
                self.AddKeyTo_LimitDict(min_value_str, max_value_str)
            if lead == "remap_addr" :
                remap_addr = self.menu_item_remap_addr(menu_item)
            if lead == "addr":
                reg_addr_key_str = self.menu_item_get_reg_addr_str(menu_item)
                self.AddKeyTo_MenuStringDict(reg_addr_key_str) 
                self.AddKeyTo_MenuAddrDict (reg_addr_key_str)  
            if lead in menu_item.keys() :                                         #检测菜单项是否包含lead指定的字段
                if lead == "name" :                                               #处理<name>字段：
                    self.AddKeyTo_MenuStringDict(menu_item["name"])               #将<name>字段值存储到 Menu_StringDict
                if lead == "unit" :                                               #处理<unit>字段：
                    self.AddKeyTo_MenuStringDict(menu_item["unit"])               #将<unit>字段值存储到 Menu_StringDict
                    self.AddKeyTo_MenuUnitDict(menu_item["unit"])                 #将<unit>字段值存储到 Menu_UnitDict
                if lead == "action" :                                             #处理<action>字段：
                    self.AddKeyTo_MenuStringDict(menu_item["action"])             #将<action>字段值存储到 Menu_StringDict
                    self.AddKeyTo_MenuActionDict(menu_item["action"])             #将<action>字段值存储到 Menu_ActionDict
                if lead == "default" :
                    default_str = "%s"%(menu_item["default"])
                    self.AddKeyTo_MenuStringDict(default_str)

    def Create_MenuInfo(self) :    
        for item_dict in self.menu_description :
            menu_object = utils.dict_or_object_get_attr(item_dict, "menu", None)
            if menu_object != None :
                self.StuffDict_MenuDict(menu_object, "addr")                                             #处理<addr>字段  
                self.StuffDict_MenuDict(menu_object, "unit")                                             #处理<unit>字段  
                self.StuffDict_MenuDict(menu_object, "scale_format")                                     #处理<scale_format>字段 
                self.StuffDict_MenuDict(menu_object, "action")                                           #处理<action>字段 
                self.StuffDict_MenuDict(menu_object, "name")                                             #处理<name>字段 
                self.StuffDict_MenuDict(menu_object, "min_max")                                          #处理<最小最大值>字段 
                self.StuffDict_MenuDict(menu_object, "remap_addr")                                       #处理重映射字段
                self.StuffDict_MenuDict(menu_object, "default")                                          #处理重映射字段

    #填充<别名字典>,创建2张别名表------
    def Create_MenuAliasTables(self):
        self.StuffDict_MenuStringDict_ByAliasDict()                                               #首先把别名表数值填充到Menu_StringDict字典中
        DebugPrint("MenuStringDict->" + str(self.MenuStringDict))
        DebugPrint("MenuAliasDict->" + str(self.alias_table))
        
        for alias_dict in self.alias_table :                                                           #遍历别名字典表alias_table
            for alias_name, value_dict in alias_dict.items():                                     #遍历表中单独的一个字典alias_dict
                
                if isinstance(alias_name, Enum):
                    alias_name = alias_name.name
                    
                if alias_name not in self.MenuAliasDict.keys() :                                 #因为是空字典，所以会执行
                    self.MenuAliasDict[alias_name] = self.MenuAliasTableIndex                   #填充Menu_AliasDict，将alias_name存储：<alias_bool:0,alias_voltage:1,alias_enable:2,..>
                    DebugPrint("Dict:"+ alias_name + " GetIndex->" + str(self.MenuAliasTableIndex))

                self.MenuAliasTable.append([self.MenuAliasTable2Index, len(value_dict)])        #构造一级别名表:将[2级表索引,字典长度]存储
                DebugPrint("MenuAliasDict-> [地址偏移，字典大小]->" + str(self.MenuAliasTable))                                                       #[起始地址，内容长度]
                self.MenuAliasTableIndex += 1                                                    #索引+1
                
                
                sorted_list_turple = sorted(value_dict.items(), key=lambda x: x[0] if isinstance(x[0], Enum) == False else x[0].value[0])
                
                for each in sorted_list_turple:
                    if isinstance(each[0], Enum) :
                        key_value = each[0].value[0]
                    else :
                        key_value = each[0]
                    key_string = each[1]
                    key_string_offset = self.GetOffsetFrom_MenuStringDict(key_string)            #查询Menu_StringDict,找到对应的偏移值：'关闭'->
                    self.MenuAliasTable2.append([key_value, key_string_offset])                  #构造二级别名表：
                    self.MenuAliasTable2Index += 1                                               #索引+1
                    DebugPrint("MenuAliasDict2->[数值，别名偏移]->" + str(self.MenuAliasTable2))               #[别名索引,在字符串表中偏移]
                             

                #for key_value, key_string in value_dict.items():                                  #遍历字典值：别名内容 {0: '关闭', 1: '打开'} #{'alias_bool': {0: '关闭', 1: '打开'}},
                #    key_string_offset = self.GetOffsetFrom_MenuStringDict(key_string)            #查询Menu_StringDict,找到对应的偏移值：'关闭'->
                #    self.MenuAliasTable2.append([key_value, key_string_offset])                  #构造二级别名表：
                #    self.MenuAliasTable2Index += 1                                               #索引+1
                #    DebugPrint("MenuAliasDict2->[数值，别名偏移]->" + str(self.MenuAliasTable2))               #[别名索引,在字符串表中偏移]
                    #第一个表Menu_AliasTable存储的是  ：[字典1的起始地址,字典1大小]，[字典2的起始地址,字典2大小]，[字典3的起始地址,字典3大小].
                    #第二个表Menu_AliasTable2存储的是 ：[别名索引,在字符串表中偏移]，[别名索引,在字符串表中偏移]，[别名索引,在字符串表中偏移].

    def Create_MenuCommTables(self) :
        if self.MenuCommTableIndex == 0 :
            self.MenuCommTable.append([0, 0, 0, 0])
            self.MenuCommTableIndex += 1

        for comm_dict in self.comm_table :                  #遍历通讯表comm_table
            comm_group_name = utils.dict_or_object_get_attr(comm_dict, "name", None)
            if comm_group_name not in self.MenuCommDict.keys() :
                self.MenuCommDict[comm_group_name] = self.MenuCommTableIndex         
                DebugPrint("Dict:"+ comm_group_name + " GetIndex->" + str(self.MenuCommTableIndex))

            reg_addr = utils.dict_or_object_get_attr(comm_dict, "reg_addr", 0)
            reg_count = utils.dict_or_object_get_attr(comm_dict, "reg_count", 0)
            cycle = utils.dict_or_object_get_attr(comm_dict, "cycle", 0)
            mqtt_pack_object = utils.dict_or_object_get_attr(comm_dict, "mqtt_pack", None)
            mqtt_pack_name   = self.get_menu_object_name(mqtt_pack_object)
            mqtt_menu_index = utils.dict_or_object_get_attr(self.MenuSubMenuDict, mqtt_pack_name, 0)
            self.MenuCommTable.append([reg_addr, reg_count, cycle, mqtt_menu_index])
            self.MenuCommTableIndex += 1                                               #索引+1

        DebugPrint("MenuCommDict2->[寄存器, 数量, 周期, 菜单索引]->" + str(self.MenuCommTable))        #[别名索引,在字符串表中偏移]

    def get_menu_object_name(self, menu_object) :
        for item_dict in self.menu_description :
            object = utils.dict_or_object_get_attr(item_dict, "menu", None)
            if object == menu_object :
                return utils.dict_or_object_get_attr(item_dict, "name", None)
        return None
    
    def Create_MenuNameDict(self):
        menu_index = 0
        self.MenuSubMenuDict[DEFAULT_EMPTY_STR] = menu_index
        menu_index += 1
        
        has_same_name = False

        for item_dict in self.menu_description :
            action_name = utils.dict_or_object_get_attr(item_dict, "action", None)
            if action_name != None:
                self.AddKeyTo_MenuStringDict(action_name)             #将<action>字段值存储到 Menu_StringDict
                self.AddKeyTo_MenuActionDict(action_name)             #将<action>字段值存储到 Menu_ActionDict

            menu_name = utils.dict_or_object_get_attr(item_dict, "name", None)
            if menu_name != None :
                if menu_name not in self.MenuSubMenuDict.keys() :
                    self.MenuSubMenuDict[menu_name] = menu_index
                else :
                    has_same_name = True
                    print_error_msg("有相同的菜单名(%s)"%(menu_name))
            menu_index += 1
            
        if has_same_name :
            exit(0)

        menu_top = self.config.get_menu_top()
        menu_top_name = self.config.get_menu_name(menu_top)        
        self.MenuTopIndex     = utils.dict_or_object_get_attr(self.MenuSubMenuDict, menu_top_name, 0)
        
    def Create_MenuDescriptionTable(self) :
        self.MenuDescriptionTable.append([0, 0, 0, 0, 0, 0, 0, 0, 0])
        
        for item_dict in self.menu_description :
            menu_name = utils.dict_or_object_get_attr(item_dict, "name", None)

            prev_menu_object = utils.dict_or_object_get_attr(item_dict, "prev", None)
            prev_menu_name = self.get_menu_object_name(prev_menu_object)
            if prev_menu_name == None :
                prev_menu_name = menu_name
            else :
                DebugPrint(prev_menu_name)
                
            next_menu_object = utils.dict_or_object_get_attr(item_dict, "next", None)
            next_menu_name = self.get_menu_object_name(next_menu_object)
            if next_menu_name == None :
                next_menu_name = menu_name
            else :
                DebugPrint(next_menu_name)
            
            display_menu_object = utils.dict_or_object_get_attr(item_dict, "display", None)
            display_menu_name = self.get_menu_object_name(display_menu_object)

            caption_name = utils.dict_or_object_get_attr(item_dict, "caption", DEFAULT_EMPTY_STR)
            display_page = utils.dict_or_object_get_attr(item_dict, "page", 0)
            max_menu_item = utils.dict_or_object_get_attr(item_dict, "max_items", 0)
            
            active_index  = 0
            
            '''
            action_name  = utils.dict_or_object_get_attr(item_dict, "action", None)
            if action_name == None :
                active_index  = 0
            else :
                active_index = utils.dict_or_object_get_attr(self.MenuActionDict, action_name, 0)
            '''
            self.AddKeyTo_MenuStringDict(menu_name) 
            self.AddKeyTo_MenuStringDict(caption_name) 
            
            menu_index = utils.dict_or_object_get_attr(self.MenuSubMenuDict, menu_name, 0)
            prev_menu_index = utils.dict_or_object_get_attr(self.MenuSubMenuDict, prev_menu_name, 0)
            next_menu_index = utils.dict_or_object_get_attr(self.MenuSubMenuDict, next_menu_name, 0)
            display_menu_index = utils.dict_or_object_get_attr(self.MenuSubMenuDict, display_menu_name, 0)
            
            menu_name_str_off = self.GetOffsetFrom_MenuStringDict(menu_name)
            caption_str_off  = self.GetOffsetFrom_MenuStringDict(caption_name)
            self.MenuDescriptionTable.append([menu_index, display_menu_index, next_menu_index, prev_menu_index, display_page, max_menu_item, active_index, menu_name_str_off, caption_str_off])
    
    #创建2张菜单表create_menu_item_talbe(Menu_Top)
    def Create_MenuItemTable(self, menu, self_menu_str) :                    #创建菜单表，菜单本身由字典列表描述
        #自身菜单索引写入到菜单字典中
        #self_menu_str = self.config.get_menu_name(menu)
        self_menu_index = self.MenuSubMenuDict[self_menu_str]
        start_index = self.MenuMenuTable2Index               #设置起始索引

        for menu_item_dict in menu :                         #遍历字典
            alias_index = 0                                  #
            unit_index = 0 
            name_offset = 0
            is_alias = 0
            action_index = 0
            sub_menu_index = 0
            comm_index = 0
            
            min_value_str, max_value_str = self.menu_item_get_min_max_str(menu_item_dict)
            limit_index = self.menu_get_min_max_index(min_value_str, max_value_str)
            
            scale_str, format_str = self.menu_item_get_scale_format(menu_item_dict)
            scale_format_index = self.Get_ScaleFormatTableIndex(scale_str, format_str)

            remap_addr = utils.dict_or_object_get_attr(menu_item_dict, "remap_addr", 0)
            menu_property = utils.dict_or_object_get_attr(menu_item_dict, "property", 1)
            
            for key, value in menu_item_dict.items():         #遍历字典中的键值对         "name": "电流设置",
                if key == "alias" :                           #
                    if isinstance(value, Enum) :
                        value = value.name
                    
                    if value in self.MenuAliasDict.keys() :
                        alias_index = self.MenuAliasDict[value]   #查询到对应的在别名表的偏移
                        is_alias = 1
                    else :
                        alias_index = 0
                elif key == "unit" :
                    unit_index = self.MenuUnitDict[value]
                elif key == "name" :
                    name_offset = self.GetOffsetFrom_MenuStringDict(value)
                elif key == "action" :
                    action_index = self.MenuActionDict[value]
                elif key == "comm" :
                    comm_index = self.MenuCommDict[value]
                elif key == "sub_menu" :
                    sub_menu_str = value
                    if isinstance(sub_menu_str, Enum) :
                        sub_menu_str = sub_menu_str.name
                        
                    sub_menu_index = utils.dict_or_object_get_attr(self.MenuSubMenuDict, sub_menu_str, 0)

            reg_addr_key_str = self.menu_item_get_reg_addr_str(menu_item_dict)
            reg_addr_key_index = self.GetOffsetFrom_MenuStringDict(reg_addr_key_str)
            
            
            self.MenuMenuTable2Index += 1
            self.MenuItemList.append([menu_item_dict, self.MenuMenuTable2Index])
            
            self.MenuMenuTable2.append([reg_addr_key_index, name_offset, is_alias, unit_index, alias_index, scale_format_index, action_index, sub_menu_index, limit_index, comm_index, remap_addr, menu_property])
        
        end_index = self.MenuMenuTable2Index
        if len(self.MenuMenuTable) == 0 :
            self.MenuMenuTable.insert(0, [0, 0])
        self.MenuMenuTable.insert(self_menu_index, [start_index, end_index - start_index])      #MenuMenuTable表存储

        DebugPrint("MenuMenuTable->" + str(self.MenuMenuTable))                                     #
        DebugPrint("----")   #
        DebugPrint("MenuMenuTable2->" + str(self.MenuMenuTable2))                                   #
        DebugPrint("    ")   #

        #第一个表Menu_MenuTable存储的是  ：[[0, 4], [4, 5], [9, 4]] :[起始地址,项数]，.
        #第二个表MMenu_MenuTable2存储的是 ：[2000, 46, 0, 0, 0, 0, 0, 0], [2001, 59, 0, 1, 0, 1, 0, 0].

    def Create_AllMenuItemTable(self) :                    #创建菜单表，菜单本身由字典列表描述
        for item_dict in self.menu_description :
            menu_object = utils.dict_or_object_get_attr(item_dict, "menu", None)
            menu_name   = utils.dict_or_object_get_attr(item_dict, "name", None)
            if menu_object != None and menu_name != None:
                self.Create_MenuItemTable(menu_object, menu_name)

#--Packing------------------------------------------------------------------------------------------------------------------------------------------------------

    #对数据包补零处理------------------
    #API_Align_PackBuf()                                              
    def Align_PackBuf(self,pack_buf) :                                            #保证4字节对齐，对不满足的进行补零操作
        remain = len(pack_buf) % 4                                                #计算要补零的个数
        if remain == 1 :                                                             
            return pack_buf + struct.pack("BBB", 0, 0, 0)                         #补3个0
        elif remain == 2 :
            return pack_buf + struct.pack("BB", 0, 0)                             #补2个0
        elif remain == 3 :
            return pack_buf + struct.pack("B", 0)                                 #补1个0
        return pack_buf                                                           #返回补零处理后的包

    #将MenuStringDict中的键打包--------------------
    #API_Pack_MeunStringDict()
    def Pack_MeunStringDict(self):                                                                #打包<字符串表>                                                          
        for str_key in self.MenuStringDict.keys() :                                               #遍历Menu_StringDict字典的索引
            str_format = str(len(str_key.encode(self.encode_type)) + 1) + 's'                      #要打包的格式字符：每条索引的字符长度+1
            self.Packed_MenuStringTable += struct.pack(str_format, str_key.encode(self.encode_type))     #将每个索引打包进Pack_StringTable
        self.Packed_MenuStringTable = struct.pack("I", len(self.Packed_MenuStringTable)) + self.Packed_MenuStringTable

        for str_key, str_off in self.MenuStringDict.items() :                                     #遍历Menu_StringDict，将存储的键值对<string,int>打印<额定电流 : 94>
            object_str = "name=" + str_key + ": offset=" + str(str_off)
            DebugPrint(object_str)                                          #打印键值对：<额定电流 : 94>

        DebugPrint("-----------------------------------")  
        DebugPrint("<Packed_Dict>Pack_MenuStringTable->")  
        DebugPrint(self.Packed_MenuStringTable)

    #打包字典MenuUnitDict得到Menu_UnitTable :单位在字符表中的偏移--------------------------------------------------
    def Pack_MenuUnitDict(self):
        MenuUnitTurpleSort = sorted(self.MenuUnitDict.items(), key=lambda x:x[1],  reverse=False)     #先对Menu_UnitDict字典的索引排序
        MenuUnitDictSort = dict(MenuUnitTurpleSort)                                                   #由排序好的tuple生成新的字典
        self.Packed_MenuUnitTable = struct.pack("I", len(self.MenuUnitDict))                                     #打包长度
        for key in MenuUnitDictSort.keys() :                                                           #遍历单位字典中所有项目
            key_offset = self.GetOffsetFrom_MenuStringDict(key)                                        #从字符串字典中 查询偏移值
            self.Packed_MenuUnitTable += struct.pack("H", key_offset)                                             #
        self.Packed_MenuUnitTable = self.Align_PackBuf(self.Packed_MenuUnitTable)                                           #打包
        DebugPrint("Origin:MenuUnitDictSort->" + str(MenuUnitDictSort))                                     #
        DebugPrint("Packed:Packed_MenuUnitTable->" + str(self.Packed_MenuUnitTable))                                     #

    #打包字典MenuScaleFormatDict得到Packed_MenuScaleFormatTable:动作在字符表中的偏移----------------------------------------------------
    def Pack_MenuScaleFormatDict(self):
        self.Packed_MenuScaleFormatTable = struct.pack("I", len(self.MenuScaleFormatTable))
        for item in self.MenuScaleFormatTable :
            self.Packed_MenuScaleFormatTable += struct.pack("HH", item[0], item[1])
        self.Packed_MenuScaleFormatTable = self.Align_PackBuf(self.Packed_MenuScaleFormatTable)
        DebugPrint("Origin:MenuScaleFormatDict->" + str(self.MenuScaleFormatDict))      
        DebugPrint("Origin:MenuScaleFormatTable->" + str(self.MenuScaleFormatTable))      
        DebugPrint("Packed:MenuScaleFormatTable->" + str(self.Packed_MenuScaleFormatTable))

    #打包字典MenuScaleFormatDict得到Packed_MenuScaleFormatTable:动作在字符表中的偏移----------------------------------------------------
    def Pack_MenuCaptionInfoDict(self):
        '''
        struct TMenuDescriptionItem
        {
            uint16_t menu_index       : 8;
            uint16_t next_menu_index  : 8;
            uint16_t prev_menu_index  : 8;
            uint16_t display_page     : 8;
            uint16_t max_menu_item    : 8;
            uint16_t action_index     : 8;
            uint16_t menu_name_str_offset;
            uint16_t description_str_off;
            uint16_t display_menu_index : 8;
            uint16_t rsv                : 8;
        };
        '''
        self.Packed_MenuDescription = struct.pack("I", len(self.MenuDescriptionTable))

        for item in self.MenuDescriptionTable :
            value  = 0
            value2 = 0
           
            value |= item[0]
            
            display_menu_index = item[1]
            next_menu_index = item[2]
            value |= (next_menu_index << 8)
            prev_menu_index = item[3]
            value |= (prev_menu_index << 16)
            page  = item[4]
            value |= (page << 24)

            max_items = item[5]
            value2 |= (max_items << 0)
            
            action_index = item[6]
            value2 |= (action_index << 8)
            
            menu_name_off = item[7]
            caption_str_off = item[8]
            
            self.Packed_MenuDescription += struct.pack("IHHHBB", value, value2, menu_name_off, caption_str_off, display_menu_index, 0)

        self.Packed_MenuDescription = self.Align_PackBuf(self.Packed_MenuDescription)


    #打包字典Pack_MenuActionDict得到Packed_MenuActionTable:动作在字符表中的偏移----------------------------------------------------
    def Pack_MenuActionDict(self):
        Menu_actionTurpleSort = sorted(self.MenuActionDict.items(), key=lambda x:x[1],  reverse=False)
        MenuactionDictSort = dict(Menu_actionTurpleSort)
        self.Packed_MenuActionTable = struct.pack("I", len(self.MenuActionDict))
        DebugPrint("01-Packed_MenuActionTable->" + str(self.Packed_MenuActionTable))                                            #
        for key in MenuactionDictSort.keys() :
            key_offset = self.GetOffsetFrom_MenuStringDict(key)
            DebugPrint("02-offset->" + str(key_offset))                                                           #
            self.Packed_MenuActionTable += struct.pack("H", key_offset)
            DebugPrint("02-Current:Packed_MenuActionTable->" + str(self.Packed_MenuActionTable))                                 #
        self.Packed_MenuActionTable = self.Align_PackBuf(self.Packed_MenuActionTable)
        DebugPrint("03-Current:MenuActionTable   ->" + str(self.MenuActionDict))                                #
        DebugPrint("04-Sorted :MenuactionDictSort->" + str(MenuactionDictSort))                                 #
        DebugPrint("05-Packed:Packed_MenuActionTable->" + str(self.Packed_MenuActionTable))                                   #

    def Pack_MenuLimitDict(self):    
        self.Packed_MenuLimitTable = struct.pack("I", len(self.MenuLimitTable))
        for item in self.MenuLimitTable:
            self.Packed_MenuLimitTable += struct.pack("HH", item[0], item[1])
    def Pack_MenuCommDict(self):
        self.Packed_MenuCommTable = struct.pack("I", len(self.MenuCommTable))
        for item in self.MenuCommTable:
            self.Packed_MenuCommTable += struct.pack("IHHHH", item[0], item[1], item[2], item[3], 0)   
        
    #打包2张别名表Menu_AliasTable Menu_AliasTable2-------------------
    def Pack_MenuAliasTables(self):
        self.Packed_AliasBuf  = struct.pack("I", len(self.MenuAliasTable))                #将Menu_AliasDict菜单别字典打包，先将长度填充
        for item in self.MenuAliasTable:                                                   #将Menu_AliasTable菜单别名表打包[[0, 2], [2, 3], [5, 2]]
            self.Packed_AliasBuf += struct.pack("HH", item[0], item[1])                    #[0,2] -> x00\x00\x02\x00     [2,3] -> x02\x00\x03\x00  
        self.Packed_AliasBuf = self.Align_PackBuf(self.Packed_AliasBuf)                           #补零处理
        DebugPrint("Origin:MenuAliasTable->" + str(self.MenuAliasTable))                       #
        DebugPrint("Packed:MenuAliasDict->" + str(self.Packed_AliasBuf))                       #

        self.Packed_AliasBuf2 = struct.pack("I", len(self.MenuAliasTable2))               #[[0, 1], [1, 8], [0, 15], [1, 20], [2, 25], [0, 1], [1, 31]]打包，填充长度占4个字节长度
        for item in self.MenuAliasTable2:                                                  #遍历每一项[x,x]
            if isinstance(item[0], Enum) :
                value = item[0].value[0]    
            else :
                value = item[0]
            self.Packed_AliasBuf2 += struct.pack("HH", value, item[1])                   #[0,1] -> x00\x00\x01\x00\    [1,8] -> x01\x00\x08\x00\
        
        self.Packed_AliasBuf2 = self.Align_PackBuf(self.Packed_AliasBuf2)                         #补零处理
        DebugPrint("Origin:MenuAliasTable2->" + str(self.MenuAliasTable2))                       #
        DebugPrint("Packed:MenuAliasDict->" + str(self.Packed_AliasBuf2))                       #

    '''
    typedef enum EMenuItemInfoType
    {
        MENU_ITEM_NORMAL,
        MENU_ITEM_ALIAS,
        MENU_ITEM_SUB_MENU,
    } EMenuItemInfoType;

    typedef struct TMenuItemInfoTypeCommon
    {
        uint32_t type                 : 2; 
        uint32_t rsv                  : 22;
        uint32_t action_index         : 8;
    } TMenuItemInfoTypeCommon;

    typedef struct TMenuItemInfoTypeAlias
    {
        uint32_t type                 : 2; 
        uint32_t rsv                  : 14;
        uint32_t alias_index          : 8;
        uint32_t action_index         : 8;
    } TMenuItemInfoTypeAlias;

    typedef struct TMenuItemInfoTypeNormal
    {
        uint32_t type                 : 2; 
        uint32_t scale_format_index   : 8;
        uint32_t limit_index          : 8;
        uint32_t unit_index           : 6;
        uint32_t action_index         : 8;
    } TMenuItemInfoTypeNormal;

    typedef struct TMenuItemInfoTypeSubMenu
    {
        uint32_t type                 : 2; 
        uint32_t rsv                  : 14;
        uint32_t sub_menu_index       : 8;
        uint32_t action_index         : 8;
    } TMenuItemInfoTypeSubMenu;

    typedef enum EMenuProperty
    {
        MENU_PROP_READ_ONLY = 0,
        MENU_PRIO_USER,
        MENU_PRIO_ENGINEER,
    } EMenuProperty;

    //每个菜单项12字节
    struct TMenuItemInfo
    {
        uint16_t comm_str_offset;
        uint16_t name_offset;
        uint16_t comm_group_index : 8;
        uint16_t menu_property    : 8;   //EMenuProperty
        uint16_t remap_addr;
        union {
            TMenuItemInfoTypeCommon  common;
            TMenuItemInfoTypeAlias   alias;
            TMenuItemInfoTypeNormal  normal;
            TMenuItemInfoTypeSubMenu sub_menu;
        } info;
    };
    '''

    #打包菜单表MenuMenuTable :格式在字符表中的偏移
    def Pack_MenuMenuTable(self):
        self.Packed_MenuBuf   = struct.pack("HH", len(self.MenuSubMenuDict), self.MenuTopIndex)
        for item in self.MenuMenuTable:
            self.Packed_MenuBuf += struct.pack("HH", item[0], item[1])

        self.Packed_MenuBuf2 = struct.pack("I", len(self.MenuMenuTable2))                 #菜单包2组包，构造字节流，首先添加长度信息
        for item in self.MenuMenuTable2:                                                  #在一个循环中将各个信息流填入buf中
            reg_addr_key_index = item[0]
            name_offset = item[1]
            is_alias = item[2]
            unit_index = item[3]
            alias_index = item[4]
            scale_format_index = item[5]
            action_index = item[6]
            sub_menu_index = item[7]
            limit_index = item[8]
            comm_index = item[9]
            remap_addr = item[10]
            menu_property = item[11]
            
            menu_item_prop = 0
            menu_item_prop |= (action_index & 0xFF) << 24
            
            if is_alias :
                menu_item_prop |= (MENU_ITEM_ALIAS << 0)
                menu_item_prop |= ((alias_index & 0xFF) << 16)
            elif sub_menu_index > 0 :
                menu_item_prop |= (MENU_ITEM_SUB_MENU << 0)
                menu_item_prop |= ((sub_menu_index & 0xFF) << 16)
            else :
                menu_item_prop |= (MENU_ITEM_NORMAL << 0)
                menu_item_prop |= ((scale_format_index & 0xFF) << 2)
                menu_item_prop |= ((limit_index & 0xFF) << 10)
                menu_item_prop |= ((unit_index & 0x3F) << 18)

            self.Packed_MenuBuf2 += struct.pack("HHBBHI", reg_addr_key_index,  name_offset, comm_index, menu_property, remap_addr, menu_item_prop)

        self.Packed_MenuBuf = self.Align_PackBuf(self.Packed_MenuBuf)
        self.Packed_MenuBuf2 = self.Align_PackBuf(self.Packed_MenuBuf2)
        self.Packed_MenuDescription = self.Align_PackBuf(self.Packed_MenuDescription)               
        self.Packed_AliasBuf = self.Align_PackBuf(self.Packed_AliasBuf)
        self.Packed_AliasBuf2 = self.Align_PackBuf(self.Packed_AliasBuf2)
        self.Packed_MenuScaleFormatTable = self.Align_PackBuf(self.Packed_MenuScaleFormatTable)
        self.Packed_MenuUnitTable = self.Align_PackBuf(self.Packed_MenuUnitTable)
        self.Packed_MenuStringTable = self.Align_PackBuf(self.Packed_MenuStringTable)
        self.Packed_MenuLimitTable  = self.Align_PackBuf(self.Packed_MenuLimitTable)
        self.Packed_MenuCommTable   = self.Align_PackBuf(self.Packed_MenuCommTable)
        self.Packed_MenuActionTable     = self.Align_PackBuf(self.Packed_MenuActionTable)

        DebugPrint("01-Origin:Menu_MenuTable->" + str(self.MenuMenuTable))                                     #
        DebugPrint("<->")                                     #
        DebugPrint("01-Packed:Pack_MenuBuf->" + str(self.Packed_MenuBuf))                                     #
        DebugPrint("...........................")   #
        DebugPrint("02-Origin:Menu_MenuTable2->" + str(self.MenuMenuTable2))                                     #
        DebugPrint("<->")                                     #
        DebugPrint("02-Packed:Pack_MenuBuf2->" + str(self.Packed_MenuBuf2))                                     #

    #打包整体
    def Pack_All(self):

        PackData = self.Packed_MenuBuf
        PackData = PackData + self.Packed_MenuBuf2
        PackData = PackData + self.Packed_MenuDescription
        PackData = PackData + self.Packed_AliasBuf 
        PackData = PackData + self.Packed_AliasBuf2
        PackData = PackData + self.Packed_MenuScaleFormatTable
        PackData = PackData + self.Packed_MenuUnitTable
        PackData = PackData + self.Packed_MenuLimitTable
        PackData = PackData + self.Packed_MenuCommTable
        PackData = PackData + self.Packed_MenuActionTable
        PackData = PackData + self.Packed_MenuStringTable
        
        #crc_function = crcmod.mkCrcFun(0x104c11db7, initCrc=0xFFFFFFFF, xorOut=0xFFFFFFFF)                                                           #获取计算CRC校验的函数->crc_function
        #data_crc_value = crc_function(PackData)    
        
        data_crc_value = 0
        data_crc_value = zlib.crc32(PackData, data_crc_value)
        data_crc_value &= 0xFFFFFFFF
     
        PackHeader   = struct.pack("8s", "PackV0.1".encode(self.encode_type))                                              #将"PackV0.1"8个字符编码后填入buf中
        header_size  = 80
        PackHeader   += struct.pack("I", header_size)       #文件头长度

        pack_offset        = 0                                                                                                           #菜单包1偏移 = 64
        
        PackHeader += struct.pack("I", pack_offset)
        DebugPrint("00-<菜单表1偏移>-menu_pack_offset  ->" + str(pack_offset))                                     
        pack_offset = pack_offset + len(self.Packed_MenuBuf)                                                                     #菜单包2偏移 = 菜单包1偏移 + 菜单包1长度
        PackHeader += struct.pack("I", pack_offset)

        DebugPrint("01-<菜单表2偏移>-menu_pack2_offset ->" + str(pack_offset))               
        pack_offset = pack_offset + len(self.Packed_MenuBuf2)                                                                     #菜单包2偏移 = 菜单包1偏移 + 菜单包1长度
        PackHeader += struct.pack("I", pack_offset)

        DebugPrint("02-<菜单描述偏移>-menu_desc_offset ->" + str(pack_offset))               
        pack_offset = pack_offset + len(self.Packed_MenuDescription)                                                             #菜单包2偏移 = 菜单包1偏移 + 菜单包1长度
        PackHeader += struct.pack("I", pack_offset)
 
        DebugPrint("03-<别名表1偏移>-alias_pack_offset ->" + str(pack_offset))                                     
        pack_offset = pack_offset + len(self.Packed_AliasBuf)                                                                    #别名包1偏移 = 菜单包2偏移 + 菜单包2长度
        PackHeader += struct.pack("I", pack_offset)

        DebugPrint("04-<别名表2偏移>-alias_pack2_offset->" + str(pack_offset))                                     
        pack_offset = pack_offset + len(self.Packed_AliasBuf2)                                                                    #别名包2偏移 = 别名包1偏移 + 别名包1长度
        PackHeader += struct.pack("I", pack_offset)
        
        DebugPrint("05-<format表偏移>-format_table_offset->" + str(pack_offset))           
        pack_offset = pack_offset + len(self.Packed_MenuScaleFormatTable) 
        PackHeader += struct.pack("I", pack_offset)
        
        DebugPrint("06-<unit表偏移>-unit_table_offset->" + str(pack_offset))   
        pack_offset = pack_offset + len(self.Packed_MenuUnitTable) 
        PackHeader += struct.pack("I", pack_offset)

        DebugPrint("07-<limit表偏移>-limit_table_offset->" + str(pack_offset))   
        pack_offset = pack_offset + len(self.Packed_MenuLimitTable) 
        PackHeader += struct.pack("I", pack_offset)

        DebugPrint("08-<Comm表偏移>-comm_table_offset->" + str(pack_offset))   
        pack_offset = pack_offset + len(self.Packed_MenuCommTable) 
        PackHeader += struct.pack("I", pack_offset)

        DebugPrint("09-<Action表偏移>-action_table_offset->" + str(pack_offset))   
        pack_offset = pack_offset + len(self.Packed_MenuActionTable) 
        PackHeader += struct.pack("I", pack_offset)
           
        DebugPrint("10-<string表偏移>-string_table_offset->" + str(pack_offset))   
        pack_offset = pack_offset + len(self.Packed_MenuStringTable) 

        PackHeader += struct.pack("III", 0, 0, 0)     #保留
        
        PackHeader += struct.pack("I", len(PackData))
        PackHeader += struct.pack("I", data_crc_value)
        
        #head_crc_value = crc_function(PackHeader)     
        head_crc_value = 0
        head_crc_value = zlib.crc32(PackHeader, head_crc_value)
        head_crc_value &= 0xFFFFFFFF
        
        PackHeader += struct.pack("I", head_crc_value)

        header_len = len(PackHeader)
        DebugPrint("04-<文件头长度 >-PackHeaderLen          ->" + str(header_len)) 

        PackFile = PackHeader + PackData                                                                                                    #文件 = 文件头 + 文件数据
        file_len = len(PackFile)
        DebugPrint("04-<文件总长度 >-PackFileLen          ->" + str(file_len)) 

        DebugPrint(" ")                                                   
        DebugPrint("01-<文件头部>PackHeader->")   
        DebugPrint(repr(PackHeader))  
        DebugPrint(" ")  
   
        DebugPrint("03-<文件整体>PackFile->")   
        DebugPrint(len(PackFile))
        DebugPrint(repr(PackFile))   
        DebugPrint(" ")   
        return PackFile
        
    def PackSave(self, file_name, pack_file) :
        with open(file_name,'wb') as file:
            file.write(pack_file)
            file.close()
            
    def PackSaveC(self, file_name, pack_file) :
        index = 0
        with open(file_name,'w', encoding='utf-8') as file:
            current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            file.write("/" + "/" + file_name + "  create date: " + current_time + "\n")
            
            file.write("#include <stdint.h>\n")
            
            file.write("__attribute__((aligned(4)))\n")
            file.write("const char menu_data[] = {\n")
            for each in pack_file :
                if index == 0 :
                    file.write("    ")
                index += 1
                file.write("0x%02x, "%(each))
                if index >= 16 :
                  index = 0
                  file.write("\n")
            if index > 0 :  
                file.write("\n")
            file.write("};\n")
            
            file.write("const uint16_t menu_data_buf_size = sizeof(menu_data);\n")

            file.close()
            

def get_comm_str_info(comm_str : str) : 
    splits = comm_str.split('#')
    total_len = len(splits)
    base      = 0
    bit       = -1
    sign      = 1
    
    if comm_str == DEFAULT_EMPTY_STR :
        return base, bit, sign
    
    if total_len >= 1 :
        bit_splits = splits[0].split('.')
        if len(bit_splits) == 2:
            base = int(bit_splits[0])
            bit  = int(bit_splits[1])            
        else :
            base  = int(bit_splits[0])
    return base, bit, sign

def caculate_comm_str_compare(comm_str : str) : 
    base, bit, sign = get_comm_str_info(comm_str)
    if bit < 0:
        return base * 16
    else :
        return base * 16 + bit
    
def get_variable_info(comm_str : str, name_str : str, alias_str : str = DEFAULT_EMPTY_STR) :
    name = ""
    is_float = "#f" in comm_str
    is_sign  = "#s" in comm_str
    is_data_32  = "#2" in comm_str
    base, bit, sign = get_comm_str_info(comm_str)
    
    if alias_str != DEFAULT_EMPTY_STR:
        type = alias_str
    elif is_float :
        type = "float"
    elif bit >= 0:
        type = "uint16_t"
    elif is_sign :
        type = "int32_t" if is_data_32 else "int16_t"
    else :
        type = "uint32_t" if is_data_32 else "uint16_t"
        
    name = get_variable_name(name_str)
    return type, name


COMM_STRUCT_PROP_STR_DEF = """
typedef struct TCommTable
{
    uint32_t comm_addr;
    uint16_t offset;
    uint16_t default_str_off;
    uint16_t is_measure       : 1;
    uint16_t menu_item_index  : 12;
    uint16_t data_size        : 3;
} TCommTable; \n
"""
COMM_PARA_STRUCT_ITEM_INIT = """
    {
        //%s
        .comm_addr= %d,
        .offset = offsetof(TSystemPara, %s),
        .is_measure      = false,
        .default_str_off = %d,
        .menu_item_index = %d,
        .data_size = sizeof(((TSystemPara *)0)->%s),
    },"""

COMM_MEASURE_STRUCT_ITEM_INIT = """
    {
        //%s
        .comm_addr= %d,
        .offset = offsetof(TMeasureValue, %s),
        .is_measure      = true,
        .default_str_off = %d,
        .menu_item_index = %d,
        .data_size = sizeof(((TMeasureValue *)0)->%s),
    },"""


class CommTableCreate():             
    def __init__(self) -> None:
        self.CommStringList = []
        self.STRUCT_PROP_DEF = COMM_STRUCT_PROP_STR_DEF

    def CommFileCreate(self, file_name, dictManager: DictsManager) :
        
        for menu_item_info in dictManager.MenuItemList :
            each_dict  = menu_item_info[0]
            menu_index = menu_item_info[1]
            
            scale_str  = utils.dict_or_object_get_attr(each_dict, "scale", "1.0")
            format_str = utils.dict_or_object_get_attr(each_dict, "format", "%5.0f")
            unit_str   = utils.dict_or_object_get_attr(each_dict, "unit",   DEFAULT_EMPTY_STR)
            name_str = utils.dict_or_object_get_attr(each_dict, "name",   DEFAULT_EMPTY_STR)
            comm_str = utils.dict_or_object_get_attr(each_dict, "addr",   DEFAULT_EMPTY_STR)
            min_str  = utils.dict_or_object_get_attr(each_dict, "min",   DEFAULT_EMPTY_STR)
            max_str  = utils.dict_or_object_get_attr(each_dict, "max",   DEFAULT_EMPTY_STR)
            alias_str = utils.dict_or_object_get_attr(each_dict, "alias",   DEFAULT_EMPTY_STR)
            default_str =  utils.dict_or_object_get_attr(each_dict, "default",  DEFAULT_EMPTY_STR)
            is_measure  = utils.dict_or_object_get_attr(each_dict, "measure", False)

            default_str =  "%s"%(default_str)
            
            if comm_str != DEFAULT_EMPTY_STR :
                aleady_exist = False                
                for item_list in self.CommStringList :
                    if comm_str == item_list[0] :
                        aleady_exist = True
                        break
                if aleady_exist == False:
                    self.CommStringList.append([comm_str, name_str, scale_str, format_str, unit_str, min_str, max_str, alias_str, menu_index, default_str, is_measure])
        
        print ("Sorted Table: ")
        sorted_comm_items = sorted(self.CommStringList, key=lambda x: caculate_comm_str_compare(x[0]))
        
        file_name_h             = file_name.replace(".c", ".h")
        base_name: str          = os.path.basename(file_name_h)
        FILE_H_HEADER           = base_name.replace(".h", "_H").upper()
        
        with open(file_name_h,'w', encoding='utf-8') as file:
            current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            file.write("/" + "/" + file_name + "  create date: " + current_time + "\n")
            file.write("#ifndef %s\n"%(FILE_H_HEADER))
            file.write("#define %s\n"%(FILE_H_HEADER)) 
            file.write("\n#include <stdint.h>\n")
            
            #定义别名枚举类型
            for alias_dict in dictManager.alias_table :
                for alias_name, value_dict in alias_dict.items():    
                    if isinstance(alias_name, Enum):
                        alias_name = alias_name.name
                    
                    enum_define = True
                    for key_value, value_str in value_dict.items() :
                        if isinstance(key_value, Enum):
                            enum_define = False
                            break
                    
                    if enum_define :
                        file.write("\ntypedef enum %s { \n"%(alias_name))
                        for key_str, value_str in value_dict.items() :
                            enum_item_str = alias_name.upper() + "_" + get_variable_name(value_str).upper()
                            caption_str   = value_str
                            main_str  = "%s = %d,"%(enum_item_str, key_str)   
                            write_str = "    %-40s//%s\n"%(main_str, caption_str)
                            file.write(write_str)
                        file.write("} %s; \n"%(alias_name))
                                       
            #创建.h文件
            para_def_list = []
            measure_def_list = []
            for items in sorted_comm_items:
                is_measure           = items[10]
                unit_str             = "(%s)"%(items[4])
                scale_format_str     = "%s, %s"%(items[2], items[3])
                if items[5] != DEFAULT_EMPTY_STR and items[6] != DEFAULT_EMPTY_STR:
                    min_max_str          = "[%s, %s]"%(items[5], items[6])
                else :
                    min_max_str          = DEFAULT_EMPTY_STR
                alias_str = items[7]
                if isinstance(alias_str, Enum):
                    alias_str = alias_str.name
                        
                para_type, para_name = get_variable_info(items[0], items[1], alias_str)
                para_name            = para_name
                caption              = '//%-15s%-10s%-20s%-30s'%(scale_format_str, unit_str, min_max_str, items[1])
                para_type_name       = "%-20s %s;"%(para_type, para_name)
                
                if is_measure :
                    measure_def_list.append("    %-50s %s"%(para_type_name, caption) + "\n")
                else :
                    para_def_list.append("    %-50s %s"%(para_type_name, caption) + "\n")

            sorted_para_def_list = sorted(para_def_list, key=lambda x: x, reverse=True)
            sorted_measure_def_lit = sorted(measure_def_list, key=lambda x: x, reverse=True)
            
            file.write("\ntypedef struct TSystemPara  { \n")
            for items in sorted_para_def_list:
                file.write(items)
            file.write("} TSystemPara; \n")
            
            
            file.write("\ntypedef struct TMeasureValue  { \n")
            for items in sorted_measure_def_lit:
                file.write(items)
            file.write("} TMeasureValue; \n")   
            
            file.write("\n#endif //%s\n"%(FILE_H_HEADER))
            file.close()
        
        #创建.c文件
        with open(file_name,'w', encoding='utf-8') as file:
            current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            file.write("/" + "/" + file_name + "  create date: " + current_time + "\n")
            file.write("#include <%s>\n"%(base_name))
            

            file.write(self.STRUCT_PROP_DEF)
            file.write("\nconst TCommTable  CommTable[] = { \n")
            
            for items in sorted_comm_items:
                comm_str             = items[0]
                menu_item_index      = items[8]
                default_str          = items[9]
                caption_str          = items[1]
                is_measure           = items[10]
                if default_str == DEFAULT_EMPTY_STR :
                    default_str_offset = 0
                else :
                    default_str_offset   = utils.dict_or_object_get_attr(dictManager.MenuStringDict, default_str, 0)
                    
                comm_addr, bit, sign = get_comm_str_info(items[0])
                para_name = get_variable_name(items[1])

                if is_measure :
                    file.write(COMM_MEASURE_STRUCT_ITEM_INIT%(caption_str, comm_addr, para_name, default_str_offset, menu_item_index, para_name))
                else :
                    file.write(COMM_PARA_STRUCT_ITEM_INIT%(caption_str, comm_addr, para_name, default_str_offset, menu_item_index, para_name))
            file.write("\n};")

            file.close()


if __name__ == "__main__":

    modify_value = 1.0
    #把浮点数转换成4字节数, 然后转化成32位整数
    bs = struct.pack("f", modify_value)
    
    print("%02x%02x%02x%02x"%(bs[0], bs[1], bs[2], bs[3]))
                
    dictManager = DictsManager()

    #[01]打印<别名字典列表alias_table>全部内容                                                                           --> DebugPrint(alias_table)
    #[02]将所有别名字符串存储到<全局字符串字典MenuStringDict>,根据<别名字典列表alias_table>创建2张别名表                    -->  Create_MenuAliasTables()->StuffDict_MenuStringDict_ByAliasDict()
    #[03]根据菜单内容，填充<全局字符串字典MenuStringDict>和各个字段字典<MenuUnitDict>,<MenuScaleFormatDict>,<MenuActionDict>    --> StuffDict_MenuDict()
    #[04]根据菜单结构，创建2张菜单表                                                                                     --> Create_MenuItemTable()
    #[05]打包<MenuStringDict>                            得到Packed_MenuStringTable                                     --> Pack_MeunStringDict()
    #[06]打包<MenuUnitDict>                              得到Packed_MenuUnitTable                                       --> Pack_MenuUnitDict()
    #[07]打包<MenuScaleFormatDict>                       得到Packed_MenuScaleFormatTable                                --> Pack_MenuScaleFormatDict()
    #[08]打包<MenuActionDict>                            得到Packed_MenuActionTable                                     --> Pack_MenuActionDict()
    #[09]打包2张别名表<MenuAliasTable>和<MenuAliasTable2> 得到Packed_AliasBuf和Packed_AliasBuf2                          --> Pack_MenuAliasTables()
    #[10]打包2张菜单表<MenuMenuTable>和<MenuMenuTable2>   得到Packed_MenuBuf和Packed_MenuBuf2                            --> Pack_MenuMenuTable()
    #[11]打包全部

    DebugPrint("↓---------------------------------------------------S(打印<别名字典列表alias_table>全部内容)---------------------------------------------↓")
    DebugPrint("Step_01")
    DebugPrint(dictManager.alias_table)
    DebugPrint("Step_01")
    DebugPrint("↑--------------------alias_table------------------------------------------------------------------------------------------------------------------↑")
    DebugPrint("|")

    DebugPrint("↓---------------------------------------S(将所有别名字符串存储到<全局字符串字典MenuStringDict>)--------------------------------------------↓")
    DebugPrint("↓--------------------------------------------S(根据<别名字典列表alias_table>创建2张别名表)------------------------------------------------↓")

    DebugPrint("Step_02")
    dictManager.Create_MenuAliasTables()
    DebugPrint("__________MenuStringDict___________>"+ str(dictManager.MenuStringDict))
    DebugPrint("Step_02")
    DebugPrint("↑--------------------------------------------------------------------------------------------------------------------------------------↑")
    DebugPrint("|")

    dictManager.Create_MenuNameDict()

    dictManager.Create_MenuCommTables()
    
    DebugPrint("↓-----------S(根据菜单内容，填充<全局字符串字典MenuStringDict>和各个字段字典<MenuUnitDict>,<MenuScaleFormatDict>,<MenuActionDict>)--------------↓")
    DebugPrint("Step_03")
        
    dictManager.Create_MenuInfo()
    
    DebugPrint("↓--------------------------------------------S(根据菜单结构,创建2张菜单表)-----------------------------------------------------------------------↓")
    DebugPrint("Step_04")
    dictManager.Create_AllMenuItemTable()
    DebugPrint("Step_04")
    DebugPrint("↑----------------------------------------------------------------------------------------------------------------------------------------------↑")
    DebugPrint("|")


    dictManager.Create_MenuDescriptionTable()
    DebugPrint("<Dict>MenuDescriptionTable->")  
    DebugPrint(dictManager.MenuDescriptionTable)
    DebugPrint(" ")  
    
    DebugPrint("<Dict>MenuUnitDict->")  
    DebugPrint(dictManager.MenuUnitDict)
    DebugPrint(" ")  
    DebugPrint("<Dict>MenuScaleFormatDict->")  
    DebugPrint(dictManager.MenuScaleFormatDict)
    DebugPrint(" ")  
    DebugPrint("<Dict>MenuActionDict->")  
    DebugPrint(dictManager.MenuActionDict)
    DebugPrint(" ")  
    DebugPrint("<Dict>MenuStringDict->")  
    DebugPrint(dictManager.MenuStringDict)
    DebugPrint("Step_03")
    DebugPrint("↑----------------------------------------------------------------------------------------------------------------------------------------------↑")
    DebugPrint("|")


    DebugPrint("↓--------------------------------------------S(打包<MenuStringDict> 得到Packed_MenuStringTable )------------------------------------------------↓")
    DebugPrint("↓--------------------------------------------S(打包<MenuUnitDict>   得到Packed_MenuUnitTable   )------------------------------------------------↓")
    DebugPrint("↓--------------------------------------------S(打包<MenuScaleFormatDict> 得到Packed_MenuScaleFormatTable )--------------------------------------↓")
    DebugPrint("↓--------------------------------------------S(打包<MenuActionDict> 得到Packed_MenuActionTable )------------------------------------------------↓")
    DebugPrint("Step_05")
    dictManager.Pack_MeunStringDict()
    dictManager.Pack_MenuUnitDict()
    dictManager.Pack_MenuScaleFormatDict()
    dictManager.Pack_MenuActionDict()
    dictManager.Pack_MenuCaptionInfoDict()
    dictManager.Pack_MenuLimitDict()
    dictManager.Pack_MenuCommDict()
    DebugPrint("Step_05")
    DebugPrint("↑----------------------------------------------------------------------------------------------------------------------------------------------↑")
    DebugPrint("|")

    DebugPrint("↓--------------------------------S(打包<MenuAliasTable>和<MenuAliasTable2> 得到Packed_AliasBuf和Packed_AliasBuf2)-------------------------------↓")
    DebugPrint("TEST_06")
    dictManager.Pack_MenuAliasTables()
    DebugPrint("TEST_06")
    DebugPrint("↑---------------------------------------------------------------------------------------------------------------------------------------------↑")
    DebugPrint("|")

    DebugPrint("↓--------------------------------S(打包<MenuMenuTable>和<MenuMenuTable2> 得到Packed_MenuBuf和Packed_MenuBuf2)-------------------------------↓")
    DebugPrint("TEST_07")
    dictManager.Pack_MenuMenuTable()
    DebugPrint("TEST_07")
    DebugPrint("↑---------------------------------------------------------------------------------------------------------------------------------------------↑")
    DebugPrint("|")

    DebugPrint("↓-------------------------------------------------------------------S(打包全部)-----------------------------------------------------------------↓")
    DebugPrint("TEST_08")
    pack_file_buf = dictManager.Pack_All()
    DebugPrint("TEST_08")
    DebugPrint("↑---------------------------------------------------------------------------------------------------------------------------------------------↑")
    DebugPrint("|")

    file_name = sys.path[0] + "/menu.dat"
    print(file_name)
    dictManager.PackSave(file_name, pack_file_buf)
    
    file_name = sys.path[0] + "/menu_dat.c"
    print(file_name)
    dictManager.PackSaveC(file_name, pack_file_buf)
    
    print("%s"%(1.23))
    name1 = get_variable_name("系统电压")
    name2 = get_variable_name("Ia 校正")
    name3 = get_variable_name("Ib 校正")
    name4 = get_variable_name("馈电设备")

    table_create = CommTableCreate()
    file_name = sys.path[0] + "/CommTable.c"
    table_create.CommFileCreate(file_name, dictManager)
