From 239fd2ca11e33179177bfe8594a604dba3460c29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=95=20=E6=B3=BD=E9=9A=86?= Date: Sun, 3 Nov 2024 16:58:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E5=B7=A5=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + .vscode/launch.json | 35 ++ .vscode/tasks.json | 54 ++ requirements.txt | Bin 0 -> 278 bytes sample/param_code_automation.py | 931 ++++++++++++++++++++++++++++ sample/task.json | 405 ++++++++++++ source/CBB/Param.py | 21 + source/PV_Inverter/CodeGenerator.py | 44 ++ source/main.py | 63 ++ 9 files changed, 1555 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 requirements.txt create mode 100644 sample/param_code_automation.py create mode 100644 sample/task.json create mode 100644 source/CBB/Param.py create mode 100644 source/PV_Inverter/CodeGenerator.py create mode 100644 source/main.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3dc920a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# 生成文件 +**/__pycache__ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..a898e70 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,35 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "CBB-Param 代码生成", + "type": "debugpy", + "request": "launch", + "program": "source/main.py", + "console": "integratedTerminal", + "args": [ + "test/param_input.xlsx", + "-t=CBB_Param", + "-d=PV_INV30", + ] + }, + { + "name": "COMM-ARM 代码生成", + "type": "debugpy", + "request": "launch", + "program": "source/main.py", + "console": "integratedTerminal", + "args": [ + // "${command:pickArgs}", + "test/光伏逆变器2.1_通信地址表_V01.xlsx", + "-t=COMM_ARM", + "-d=PV_INV30" + ], + // "preLaunchTask": "deEncrpyt", + // "postDebugTask": "delFile", + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..0fd8e4a --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,54 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "echo", + "type": "shell", + "command": "echo Hello" + }, + { + "label": "deEncrpyt", + "type": "shell", + "command": "de_encrypt", + "args": [ + "test/光伏逆变器2.1_通信地址表_V01.xlsx", + ], + + "problemMatcher": [], + "presentation":{ + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared", + "showReuseMessage": true, + "clear": false + }, + "group": { + "kind": "none" + } + }, + { + "label": "delFile", + "type": "shell", + "command": "rm", + "args": [ + "test/光伏逆变器2.1_通信地址表_V01_dec.dec", + ], + + "problemMatcher": [], + "presentation":{ + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared", + "showReuseMessage": true, + "clear": false + }, + "group": { + "kind": "none" + } + } + ] +} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..575349407fb7fb389b8eb97fe33ce90311e5809c GIT binary patch literal 278 zcmY+9(F(#a6hreY_$eE8bAk_kj9^8 +#include + + +#define %s_PARAM_NUM (%s) + + +''' + file_end_formate = ''' +#endif /* ----- #ifndef __PARAM_%s_DEFINATION_H__ ----- */ +''' + + for key, value in self.config_set.items(): + + file_name = file_name_formate % key.lower(); + + ret_str = "" + ret_str = ret_str + file_title_formate%(key.lower(), time.strftime("%d/%m/%Y %H:%M:%S"), key.upper(),key.upper(),key.upper(),value["param_num"]["参数个数"]) + + format_str = "#define {:<50} {}\n" + + max_line_len = 0 + + for size_item in value["param_info_list"]: + curr_line = key.upper()+"_PARAM_"+size_item[0].name.upper()+"_SIZE" + if len(curr_line) > max_line_len : + max_line_len = len(curr_line) + + if size_item[0].store_type == "PARAM_ARRAY": + ret_str = ret_str + format_str.format(curr_line, '('+str(size_item[0].size)+')') + if size_item[0].store_type == "PARAM_FLOAT": + ret_str = ret_str + format_str.format(curr_line, '(sizeof(float))') + if size_item[0].store_type == "PARAM_UINT8": + ret_str = ret_str + format_str.format(curr_line, '(sizeof(uint8_t))') + if size_item[0].store_type == "PARAM_INT8": + ret_str = ret_str + format_str.format(curr_line, '(sizeof(int8_t))') + if size_item[0].store_type == "PARAM_UINT16": + ret_str = ret_str + format_str.format(curr_line, '(sizeof(uint16_t))') + if size_item[0].store_type == "PARAM_INT16": + ret_str = ret_str + format_str.format(curr_line, '(sizeof(int16_t))') + if size_item[0].store_type == "PARAM_UINT32": + ret_str = ret_str + format_str.format(curr_line, '(sizeof(uint32_t))') + if size_item[0].store_type == "PARAM_INT32": + ret_str = ret_str + format_str.format(curr_line, '(sizeof(int32_t))') + if size_item[0].store_type == "PARAM_UINT64": + ret_str = ret_str + format_str.format(curr_line, '(sizeof(uint64_t))') + if size_item[0].store_type == "PARAM_INT64": + ret_str = ret_str + format_str.format(curr_line, '(sizeof(int64_t))') + if size_item[0].store_type == "PARAM_DOUBLE": + ret_str = ret_str + format_str.format(curr_line, '(sizeof(double))') + + size_item[0].size_string = "%s_PARAM_%s_SIZE"%(key.upper(), size_item[0].name.upper()) + + ret_str = ret_str + "\n\n" + format_str = " {:<%s}/* {} */\n"%(2*max_line_len) + + ret_str = ret_str + """typedef struct\n{\n""" + + for size_item in value["param_info_list"]: + if size_item[0].store_type == "PARAM_ARRAY": + ret_str = ret_str + format_str.format ("uint8_t "+size_item[0].name+"["+size_item[0].size_string+"];", size_item[0].str_name) + if size_item[0].store_type == "PARAM_FLOAT": + ret_str = ret_str + format_str.format ("float "+size_item[0].name+";", size_item[0].str_name) + if size_item[0].store_type == "PARAM_UINT8": + ret_str = ret_str + format_str.format ("uint8_t "+size_item[0].name+";", size_item[0].str_name) + if size_item[0].store_type == "PARAM_INT8": + ret_str = ret_str + format_str.format ("int8_t "+size_item[0].name+";", size_item[0].str_name) + if size_item[0].store_type == "PARAM_UINT16": + ret_str = ret_str + format_str.format ("uint16_t "+size_item[0].name+";", size_item[0].str_name) + if size_item[0].store_type == "PARAM_INT16": + ret_str = ret_str + format_str.format ("int16_t "+size_item[0].name+";", size_item[0].str_name) + if size_item[0].store_type == "PARAM_UINT32": + ret_str = ret_str + format_str.format ("uint32_t "+size_item[0].name+";", size_item[0].str_name) + if size_item[0].store_type == "PARAM_INT32": + ret_str = ret_str + format_str.format ("int32_t "+size_item[0].name+";", size_item[0].str_name) + if size_item[0].store_type == "PARAM_UINT64": + ret_str = ret_str + format_str.format ("uint64_t "+size_item[0].name+";", size_item[0].str_name) + if size_item[0].store_type == "PARAM_INT64": + ret_str = ret_str + format_str.format ("int64_t "+size_item[0].name+";", size_item[0].str_name) + if size_item[0].store_type == "PARAM_DOUBLE": + ret_str = ret_str + format_str.format ("double "+size_item[0].name+";", size_item[0].str_name) + ret_str = ret_str + "} %s_param_t;\n\n"%key.lower() + + ret_str = ret_str + file_end_formate%(key.upper()) + + + with open("%s/"%self.file_path+file_name, 'w', encoding="utf-8") as f: + f.write(ret_str) + + + def __generate_internal_definations(self): + '''生成.h''' + file_name_formate = "param_%s.h" + file_title_formate = '''/* + * ===================================================================================== + * + * Filename: param_%s.h + * + * Description: + * + * Version: 1.0 + * Created: %s + * Revision: none + * Compiler: gcc + * + * Author: Autogenerated + * Organization: Topscomm + * + * ===================================================================================== + */ + +#ifndef __PARAM_%s_H__ +#define __PARAM_%s_H__ + +#include + +#include "./param_config.h" +#include "../param_functional/param_block.h" +#include "./param_%s_defination.h" + +#define %s_PARAM_STORE_ADDR (%s) + + +''' + file_end_formate = ''' + +#if ENABLE_PARAM_IN_RAM +#if ENABLE_PARAM_PRESET +typedef struct +{ + %s_param_t preset_table; +} update_%s_param_t; +#endif +#endif + +extern param_info_table_t %s_PARAM_INFO; + +#endif /* ----- #ifndef __PARAM_%s_H__ ----- */ +''' + + for key, value in self.config_set.items(): + + file_name = file_name_formate%key.lower() + + ret_str = "" + ret_str = ret_str + file_title_formate%(key.lower(), time.strftime("%d/%m/%Y %H:%M:%S"), key.upper(),key.upper(),key.lower(),key.upper(), value["param_storage_addr"]["存储区域基地址"]) + + format_str = "#define {:<%s} {}\n" + index = 0 + last_str = "" + + max_line_len = 0 + for size_item in value["param_info_list"]: + if max_line_len <= len("%s_PARAM_%s_SIZE"%(key.upper(), size_item[0].name.upper())): + max_len_len = len("%s_PARAM_%s_SIZE"%(key.upper(), size_item[0].name.upper())) + + format_str = format_str%(max_len_len + 5) + + for size_item in value["param_info_list"]: + size_item[0].size_string = "%s_PARAM_%s_SIZE"%(key.upper(), size_item[0].name.upper()) + + if index == 0: + ret_str = ret_str + format_str.format(key.upper()+"_PARAM_"+size_item[0].name.upper()+"_OFFSET", '0') + else: + ret_str = ret_str + format_str.format(key.upper()+"_PARAM_"+size_item[0].name.upper()+"_OFFSET", last_str) + index = index + 1 + last_str = ('({:<%s} + {:<%s} + PARAM_INFO_SIZE)' %(2*max_line_len, 3*max_line_len)).format(key.upper()+"_PARAM_"+size_item[0].name.upper()+"_OFFSET", + key.upper()+"_PARAM_"+size_item[0].name.upper()+"_SIZE") + + ret_str = ret_str + "\n" + ret_str = ret_str + '''#define %s_PARAM_STORAGE_SIZE\t\t%s\n\n''' % (key.upper(), last_str) + + ret_str = ret_str + file_end_formate%(key.lower(), key.lower(), key.upper(),key.upper()) + + + with open("%s/"%self.file_path+file_name, 'w', encoding="utf-8") as f: + f.write(ret_str) + + def __generate_infomatin(self): + '''生成.c''' + file_name_formate = "param_%s.c" + file_title_formate = '''/* + * ===================================================================================== + * + * Filename: param_%s.c + * + * Description: + * + * Version: 1.0 + * Created: %s + * Revision: none + * Compiler: gcc + * + * Author: Autogenerated + * Organization: Topscomm + * + * ===================================================================================== + */ + +#include + +#include "plm_type_def.h" +#include "../param_export.h" + +#include "./param_%s.h" + + +#if ENABLE_PARAM_IN_RAM +#if ENABLE_PARAM_PRESET +update_%s_param_t g_update_%s_param_info; /*预存参数数据缓冲区 */ +#endif + +%s_param_t g_%s_param_in_ram; /*参数ram缓冲区*/ +uint16_t g_check_%s_param_crc[%s_PARAM_NUM]; /*用于记录参数的校验crc结果*/ +#endif + +PARAM_CHANGE_FLAG_E g_%s_param_change_flag[%s_PARAM_NUM]; /*用于记录参数的修改标记*/ + +const %s_param_t %s_PARAM_DEFAULT_VALUE_TABLE = +{ +''' + file_end_formate = ''' + +param_info_table_t %s_PARAM_INFO = +{ +#if ENABLE_PARAM_MUTEX + .ptr_mutex = &g_param_resouce.param_mutex, +#endif + .ptr_category_name = %s_REGION_NAME, + .ptr_default_value_table = (void*)&%s_PARAM_DEFAULT_VALUE_TABLE, //默认参数值 + .ptr_index_table = (void*)%s_PARAM_INDEX_TABLE, //参数索引表 + .param_num = %s_PARAM_NUM, //参数个数 + .param_data_size = %s_PARAM_STORAGE_SIZE, //数据长度 + .param_base_addr = %s_PARAM_STORE_ADDR, //参数存储页地址 +#if ENABLE_PARAM_IN_RAM +#if ENABLE_PARAM_PRESET + .ptr_preset_dataset = (void*)&g_update_%s_param_info.preset_table,//预设参数表 +#endif + .ptr_param_in_ram = (void*)&g_%s_param_in_ram, //参数ram缓冲区 + .ptr_crc_in_ram = g_check_%s_param_crc, //参数crc校验值 +#endif + .ptr_change_flag = g_%s_param_change_flag, //参数变更标记 + .backup_offset = %s, //备份之间的偏移 + .idx_min = %s, //参数索引最小值 + .idx_max = %s, //参数索引最大值 + .ptr_exchange_unit = &g_param_resouce.ptr_param_unit_buff, //参数写入缓冲区 + .exchange_size = %s, //按页写入的缓冲区的大小 +}; + +''' + + for key, value in self.config_set.items(): + + file_name = file_name_formate%key.lower() + + ret_str = "" + ret_str = ret_str + file_title_formate%(key.lower(), time.strftime("%d/%m/%Y %H:%M:%S"), key.lower(), key.lower(), key.lower(), key.lower(), key.lower(), key.lower(), key.upper(), key.lower(), key.upper(), key.lower(), key.upper()) + + format_str = " .{:<20} = {:<40} //{}\n" + for size_item in value["param_info_list"]: + if size_item[0].store_type == "PARAM_ARRAY": + ret_str = ret_str + format_str.format(size_item[0].name, "{"+str(size_item[0].default_value)+"},", size_item[0].str_name) + else: + ret_str = ret_str + format_str.format(size_item[0].name, str(size_item[0].default_value)+",", size_item[0].str_name) + + ret_str = ret_str + "};\n\n\n" + + + ret_str = ret_str + "const param_info_t %s_PARAM_INDEX_TABLE[%s_PARAM_NUM] =\n{\n"%(key.upper(),key.upper()) + + format_str = "{:<40} {:<30} {:<30} {:<30} {:<40} {:<50} {:<20} {:<20} {:<20} {:<30} {:<30} {:<40}\n" + for size_item in value["param_info_list"]: + ret_str = ret_str + format_str.format(" {.idx=PARA_IDX_%s"%size_item[0].name.upper()+",", ".identity="+str(size_item[0].DI)+",", + ".store_type="+size_item[0].store_type+",", ".local_type="+str(size_item[0].local_type)+",", + ".size="+size_item[0].size_string+",", ".offset="+"offsetof(%s_param_t, %s)"%(key.lower(),size_item[0].name)+",", + ".ratio="+str(size_item[0].ratio)+",", ".min="+str(size_item[0].min)+",", ".max="+str(size_item[0].max)+",", + ".check_func="+size_item[0].check_func+",", ".update_func="+size_item[0].updata_func+",},", "//"+size_item[0].str_name) + ret_str = ret_str + "};\n\n\n" + + file_end = file_end_formate % (key.upper(), key.upper(),key.upper(),key.upper(),key.upper(),key.upper(),key.upper(),key.lower(),key.lower(),key.lower(),key.lower(), + value["param_data_unit"]["存储区域单分区大小"], + "PARA_IDX_%s"%value["param_info_list"][0][0].name.upper(), + "PARA_IDX_%s"%value["param_info_list"][value['param_num']["参数个数"]-1][0].name.upper(), + value["param_storage_unit"]["存储区域擦写单元"]) + ret_str = ret_str + file_end + + + with open("%s/"%self.file_path+file_name, 'w', encoding="utf-8") as f: + f.write(ret_str) + + def __generate_export(self): + '''生成interface.h的部分内容''' + file_title_formate = '''/* + * ===================================================================================== + * + * Filename: param_defination.h + * + * Description: + * + * Version: 1.0 + * Created: %s + * Revision: none + * Compiler: gcc + * + * Author: Autogenerated + * Organization: Topscomm + * + * ===================================================================================== + */ + + +#ifndef __PARAM_DEFINATION_H__ +#define __PARAM_DEFINATION_H__ + +#include + +/* ##### LOCAL INCLUDES #################################################### */ +''' + file_title_formate = file_title_formate%(time.strftime("%d/%m/%Y %H:%M:%S")) + + for t_item in self.config_set.items(): + file_title_formate = file_title_formate + '#include {:<55} {}\n'.format('"param_defination/param_%s_defination.h"'%t_item[0].lower(), "/* %s参数个数及参数数据域大小 */" % t_item[0]) + + file_title_formate = file_title_formate + "\n/* ##### EXPORTED MACROS ######################################################## */\n" + + ret_str = file_title_formate + + for key, value in self.config_set.items(): + ret_str = ret_str + "#define {:<25} {:<30} /* {}存储区域名 */\n".format(key.upper()+"_REGION_NAME", value['param_storage_name']['存储区域命名'], key.upper()) + + category_format = ''' + +/* ##### EXPORTED DATA TYPES #################################################### */ + +typedef enum +{ + %s + PARAM_CATEGORY_MAX, /*参数表个数*/ +}PARAM_CATEGORY_E; /* ---------- end of enum PARAM_CATEGORY_E ---------- */ + +''' + cat_str = "" + for key, value in self.config_set.items(): + cat_str = cat_str + "{:<25} /*{}*/\n ".format(key.upper() + "_PARAM,",key) + + ret_str = ret_str + category_format%cat_str + + index_format = ''' +typedef enum +{ + %s + PARA_IDX_MAX, /*参数索引总个数*/ +}PARAM_IDX_E; /* ---------- end of enum PARAM_IDX_E ---------- */ + +''' + index_str = "" + for key, value in self.config_set.items(): + index_str = index_str + "\n /* %s */\n "%key + for size_item in value["param_info_list"]: + index_str = index_str + "{:<45} //{}\n ".format("PARA_IDX_"+size_item[0].name.upper()+",", size_item[0].str_name) + + + file_end = ''' +#endif /* ----- #ifndef __PARAM_DEFINATION_H__ ----- */ + + ''' + + ret_str = ret_str + index_format%index_str + file_end + + with open("%s/param_defination.h"%self.file_path, 'w', encoding="utf-8") as f: + f.write(ret_str) + + def __generate_storage(self): + '''生成param_storage_config.c的部分内容''' + file_title_formate = '''/* + * ===================================================================================== + * + * Filename: param_storage_config.c + * + * Description: + * + * Version: 1.0 + * Created: %s + * Revision: none + * Compiler: gcc + * + * Author: Autogenerated + * Organization: Topscomm + * + * ===================================================================================== + */ + +#include "../param_storage/norflash_operation.h" +#include "../param_storage/eeprom_operation.h" +#include "../param_storage/file_system_operation.h" +#include "../param_storage/param_storage.h" + +#if FILE_SYSTEM_EXIST +const char g_param_file_path_prefix[FILE_NAME_MAX_LEN]="%s"; /*存放参数文件的路径前缀*/ + +#define FILE_MAX_LEN (%s) /*文件最大长度*/ +#endif + +/* ##### VARIABLES - LOCAL TO THIS SOURCE FILE ################################ */ + + +static const storage_info_t all_storage_info_table[PARAM_CATEGORY_MAX] = +{ +''' + item_format=''' /* %s */ + { + .ptr_name = %s_REGION_NAME, + .region = %s_PARAM, + #if FILE_SYSTEM_EXIST + .max_addr = 0+FILE_MAX_LEN - 1, + .min_addr = 0, + #else + .max_addr = %s, + .min_addr = %s, + #endif + + .storage_read = %s_read, + .storage_write = %s_write, + .storage_clean = %s_clean, + }, +''' + + for t_item in self.config_set.items(): + file_title_formate = file_title_formate%(time.strftime("%d/%m/%Y %H:%M:%S"),t_item[1]['file_path_prefix']['参数文件路径'],str(t_item[1]['param_data_unit']['存储区域单分区大小'])+ "*3") + break + + for t_item in self.config_set.items(): + file_title_formate = file_title_formate + item_format % (t_item[0].upper(),t_item[0].upper(), t_item[0].upper(), + str(t_item[1]['param_storage_addr']['存储区域基地址']) + "+" + str(t_item[1]['param_data_unit']['存储区域单分区大小'])+ "*3 - 1", + t_item[1]['param_storage_addr']['存储区域基地址'], + t_item[1]['storage_type']['存储器类型'], + t_item[1]['storage_type']['存储器类型'], + t_item[1]['storage_type']['存储器类型']) + + + file_end = ''' +}; + + +/* ##### FUNCTION DEFINITIONS - EXPORTED FUNCTIONS ############################ */ + + +/* + * === FUNCTION ====================================================================== + * Name: param_storage_get_info_table + * Description: 获取所有存储区域的汇总表,用于对存储区域进行检索 + * ===================================================================================== + */ +const storage_info_t* param_storage_get_info_table() +{ + return &all_storage_info_table[0]; +} /* ----- end of function param_storage_get_info_table ----- */ + +''' + ret_str = "" + ret_str = file_title_formate + file_end + + with open("%s/param_storage_config.c"%self.file_path, 'w', encoding="utf-8") as f: + f.write(ret_str) + + def generate_code_files(self, path): + ''' + 实际执行excel转代码,生成.c、.h、defination.h、param_export.h、 + ''' + self.file_path = path + self.__generate_definations() + self.__generate_internal_definations() + self.__generate_infomatin() + self.__generate_export() + self.__generate_storage() + +def gen_param_info(content): + items = {} + + match = re.search(r"offset=offsetof\(.*\)", content) + if match != None: + group_list = match.group().split("=") + items[group_list[0]] = group_list[1].split(", ")[1].strip(')') + else: + items["offset"] = "" + + content = content.replace(".offset=offsetof(", "") + + for item in content.split(","): + match = re.search(r"\..*=.*", item) + if match != None: + key_value = match.group().strip("}").strip(".").split('=') + items[key_value[0]] = key_value[1] + + return items + +class ParamCategory(object): + ''' + 用于存储从代码文件中读出的信息 + cat_name:业务参数类型名称 + base_addr:参数存储的基地址 + data_size:参数数据存储的总大小(暂未使用) + param_num:当前类型中,参数的个数 + backup_offset:备份之间的偏移 + param_name_list:标识符列表 + param_name_str_list:参数名称列表(汉字) + default_value:默认参数字典 + index_table:默认索引表 + exchange_size:存储区域擦写单元 + ''' + def __init__(self, cat_name): + ''' + 初始化代码文件信息,仅传入参数类型名,构造空的参数信息体 + ''' + self.cat_name = cat_name.upper() + self.base_addr = "" + self.data_size = 0 + self.param_num = 0 + self.backup_offset = "" + self.param_name_list=[] + self.param_name_str_list=[] + self.default_value={} + self.index_table=[] + self.storage_name='' + self.exchange_size = "" + + def __str__(self): + ''' + 将对象转换为可打印的字符串 + ''' + ret = "" + ret = ret + "cat_name:\t" + self.cat_name + "\n" + ret = ret + "storage_name:\t" + self.storage_name + "\n" + ret = ret + "base_addr:\t"+ self.base_addr + "\n" + ret = ret + "data_size:\t"+ str(self.data_size) + "\n" + ret = ret + "param_num:\t"+ str(self.param_num) + "\n" + ret = ret + "backup_offset:\t"+ self.backup_offset + "\n" + ret = ret + "param_name_list"+ str(self.param_name_list) + "\n" + ret = ret + "param_name_str_list"+ str(self.param_name_str_list) + "\n" + ret = ret + "default_value"+ str(self.default_value) + "\n" + ret = ret + "index_table"+ str(self.index_table) + "\n" + ret = ret + "exchange_size:\t"+ self.exchange_size + "\n" + + return ret + +class CodeGeneration(object): + ''' + 将代码文件还原为excel文件 + ''' + categary_pattern = r'param_[a-z]*\.c' + + def __find_param_category(self, path): + ''' + 找到path目录下可被逆向解析的文件,将可解析的文件构造成参数类型 + ''' + file_list = os.listdir(path) + cat_list = [] + cat_temp_list = [] + for file_item in os.listdir(path): + categary_pattern = r'param_[a-z]*\.c' + matches = re.search(categary_pattern, file_item) + if matches != None : + cat_temp_list.append(matches.group()[6:-2]) + + for cat_idx in cat_temp_list: + if "param_"+cat_idx+"_defination.h" in os.listdir(path) and "param_"+cat_idx+".h" in os.listdir(path): + cat_list.append(cat_idx) + + return cat_list + + def __build_local_info(self, path, cat_name): + ''' + 读取.h文件,通过.h文件构建存储基地址 + ''' + with open("%s/param_%s.h"%(path,cat_name.lower()), 'r', encoding="utf-8") as f: + param_h = f.read() + state = 0 + for line in param_h.split('\n'): + line.strip() + + if line.find("_PARAM_STORE_ADDR") != -1: + self.categorys[cat_name].base_addr = line.split("(")[1].split(')')[0].strip() + + def __build_extern_info(self, path, cat_name): + ''' + 读取_defination.h文件,通过_defination.h文件构建各个参数的数据域大小 + ''' + with open("%s/param_%s_defination.h"%(path, cat_name.lower()), 'r', encoding="utf-8") as f: + param_h = f.read() + item_index = 0 + state = 0 + for line in param_h.split('\n'): + line.strip() + + if line.find("_PARAM_NUM") != -1: + self.categorys[cat_name].param_num = int(line.split("(")[1].split(')')[0].strip()) + + categary_pattern = r'#define.*_SIZE.*\(' + matches = re.search(categary_pattern, line) + if matches != None : + if self.categorys[cat_name].index_table[item_index]['size'] == line.split(' ')[1].split('(')[0].strip() : + if line.find("(sizeof(uint8_t))") != -1: + self.categorys[cat_name].index_table[item_index]['size'] = 1 + elif line.find("(sizeof(int8_t))") != -1: + self.categorys[cat_name].index_table[item_index]['size'] = 1 + elif line.find("(sizeof(uint16_t))") != -1: + self.categorys[cat_name].index_table[item_index]['size'] = 2 + elif line.find("(sizeof(int16_t))") != -1: + self.categorys[cat_name].index_table[item_index]['size'] = 2 + elif line.find("(sizeof(uint32_t))") != -1: + self.categorys[cat_name].index_table[item_index]['size'] = 4 + elif line.find("(sizeof(int32_t))") != -1: + self.categorys[cat_name].index_table[item_index]['size'] = 4 + elif line.find("(sizeof(uint64_t))") != -1: + self.categorys[cat_name].index_table[item_index]['size'] = 8 + elif line.find("(sizeof(int64_t))") != -1: + self.categorys[cat_name].index_table[item_index]['size'] = 8 + elif line.find("(sizeof(float))") != -1: + self.categorys[cat_name].index_table[item_index]['size'] = 4 + elif line.find("(sizeof(double))") != -1: + self.categorys[cat_name].index_table[item_index]['size'] = 8 + else: + self.categorys[cat_name].index_table[item_index]['size'] = int(line.split('(')[1].split(')')[0]) + item_index = item_index + 1 + + + def __build_list(self, path, cat_name): + ''' + 读取.c文件,通过.c文件构建各个参数的数据域的名称、名字、各索引项、默认值等 + ''' + with open("%s/param_%s.c"%(path, cat_name.lower()), 'r', encoding="utf-8") as f: + param_h = f.read() + state = 0 + for line in param_h.split('\n'): + line.strip() + + if line.find(".backup_offset") != -1: + self.categorys[cat_name].backup_offset = int(line.split(",")[0].split('=')[1].strip()) + + if line.find(".exchange_size") != -1: + self.categorys[cat_name].exchange_size = int(line.split(",")[0].split('=')[1].strip()) + + if state == 1 : + if line.startswith("};") != True : + if line.startswith("{") != True: + if line.find("}") == -1: + self.categorys[cat_name].default_value[line.split('=')[0].strip().strip(".")] = line.split("=")[1].split(",")[0].strip() + self.categorys[cat_name].param_name_str_list.append(line.split(',')[1].strip().strip("/")) + else: + self.categorys[cat_name].default_value[line.split('=')[0].strip().strip(".")] = line.split("{")[1].split("}")[0] + self.categorys[cat_name].param_name_str_list.append(line.split('},')[1].strip().strip("/")) + self.categorys[cat_name].param_name_list.append(line.split('=')[0].strip().strip(".")) + else: + state = 0 + + if state == 2 : + if line.startswith("};") != True : + if line.startswith("{") != True: + self.categorys[cat_name].index_table.append(gen_param_info(line)) + else: + state = 0 + + if line.startswith("const") and line.find("PARAM_DEFAULT_VALUE_TABLE") != -1: + state = 1 + + if line.startswith("const") and line.find("PARAM_INDEX_TABLE") != -1: + state = 2 + + def __build_export(self, path): + with open("%s/param_defination.h"%(path), 'r', encoding="utf-8") as f: + param_h = f.read() + state = 0 + for line in param_h.split('\n'): + line.strip() + + if line.find("_REGION_NAME") != -1: + self.storage_name_list[line.split("_REGION_NAME")[0].strip().split(' ')[1].lower()] = line.split("_REGION_NAME")[1].strip().split(' ')[0] + if line.find("_PARAM,") != -1: + self.cat_list.append(line.strip().split(',')[0].split('_')[0].upper()) + + def __build_storage(self, path): + with open("%s/param_storage_config.c"%(path), 'r', encoding="utf-8") as f: + param_c = f.read() + state = 0 + self.storage_type = param_c.split("};")[0].split("all_storage_info_table")[1].split("},")[0].split(".storage_read")[1].split(".storage_write")[0].strip('= ').split("_read")[0] + self.file_path_prefix = param_c.split("]=\"")[1].split("\";")[0] + + def __init__(self, path): + ''' + 传入路径path,解析路径下的代码文件,找到能够解析成参数类型的三种文件:param_*.h、param_*_defination.h、param_*.c + 将找到的可被解析的文件构造成参数类型信息体,并写入到excel文件中。 + ''' + cat_list = self.__find_param_category(path) + self.cat_list = [] + self.storage_name_list = {} + self.categorys = {} + self.storage_type = {} + self.__build_export(path) + self.__build_storage(path) + for cat_name in cat_list: + self.categorys[cat_name] = ParamCategory(cat_name) + self.__build_list(path, cat_name) + self.__build_extern_info(path, cat_name) + self.__build_local_info(path, cat_name) + + def gen_data_file(self): + ''' + 实际执行将读取到的参数信息写入到xlsx文件中,文件名为"param_output.xlsx" + ''' + wb = openpyxl.Workbook() + + wb.remove(wb[wb.sheetnames[0]]) + + ''' 单元格填充黄色 ''' + fill = openpyxl.styles.PatternFill("solid", fgColor="FFFF00") + + cell_name_list = ["序号", "唯一码(DI、点号等)", "参数名", "参数标识符", "参数存储类型", "参数数据大小(字节数)", "默认值", "对象解析类型", "缩放倍数", "参数最小值", "参数最大值", "参数标记", "参数有效性检查", "参数配置后回调", "注释"] + for sheet in codes.cat_list: + if sheet not in wb.sheetnames: + wb.create_sheet(sheet) + + wb[sheet]["C1"].value = '存储区域基地址' + wb[sheet]["D1"].value = self.categorys[sheet.lower()].base_addr + wb[sheet]["C2"].value = '存储区域命名' + wb[sheet]["D2"].value = self.storage_name_list[sheet.lower()] + wb[sheet]["C3"].value = '存储区域擦写单元' + wb[sheet]["D3"].value = self.categorys[sheet.lower()].exchange_size + wb[sheet]["C4"].value = '存储区域单分区大小' + wb[sheet]["D4"].value = self.categorys[sheet.lower()].backup_offset + wb[sheet]["C5"].value = '参数个数' + wb[sheet]["D5"].value = self.categorys[sheet.lower()].param_num + wb[sheet]["C6"].value = '是否需要RAM参数对象' + wb[sheet]["D6"].value = 'true/false' + wb[sheet]["C7"].value = '存储器类型' + wb[sheet]["D7"].value = self.storage_type + wb[sheet]["C8"].value = '参数文件路径' + wb[sheet]["D8"].value = self.file_path_prefix + wb[sheet]["E8"].value = '注释:当存储器类型为fs时,需要填写参数文件路径' + + ''' 单元格填充黄色 ''' + wb[sheet]["C1"].fill = fill + wb[sheet]["C2"].fill = fill + wb[sheet]["C3"].fill = fill + wb[sheet]["C4"].fill = fill + wb[sheet]["C5"].fill = fill + wb[sheet]["C6"].fill = fill + wb[sheet]["C7"].fill = fill + wb[sheet]["C8"].fill = fill + + for i in range(1, 16): + wb[sheet].cell(row = 11, column = i, value = cell_name_list[i-1]) + wb[sheet].cell(row = 11, column = i).fill = fill + + for i in range(0, int(self.categorys[sheet.lower()].param_num)): + wb[sheet].cell(row = 12+i, column = 1, value = i+1) + wb[sheet].cell(row = 12+i, column = 2, value = self.categorys[sheet.lower()].index_table[i]['identity']) + wb[sheet].cell(row = 12+i, column = 3, value = self.categorys[sheet.lower()].param_name_str_list[i]) + wb[sheet].cell(row = 12+i, column = 4, value = self.categorys[sheet.lower()].param_name_list[i]) + wb[sheet].cell(row = 12+i, column = 5, value = self.categorys[sheet.lower()].index_table[i]['store_type']) + wb[sheet].cell(row = 12+i, column = 6, value = self.categorys[sheet.lower()].index_table[i]['size']) + wb[sheet].cell(row = 12+i, column = 7, value = self.categorys[sheet.lower()].default_value[self.categorys[sheet.lower()].index_table[i]['offset']]) + wb[sheet].cell(row = 12+i, column = 8, value = self.categorys[sheet.lower()].index_table[i]['local_type']) + wb[sheet].cell(row = 12+i, column = 9, value = self.categorys[sheet.lower()].index_table[i]['ratio']) + wb[sheet].cell(row = 12+i, column = 10, value = self.categorys[sheet.lower()].index_table[i]['min']) + wb[sheet].cell(row = 12+i, column = 11, value = self.categorys[sheet.lower()].index_table[i]['max']) + wb[sheet].cell(row = 12+i, column = 12, value = "0") + wb[sheet].cell(row = 12+i, column = 13, value = self.categorys[sheet.lower()].index_table[i]['check_func']) + wb[sheet].cell(row = 12+i, column = 14, value = self.categorys[sheet.lower()].index_table[i]['update_func']) + wb[sheet].cell(row = 12+i, column = 15, value = "") + + wb.save("tools/param_output.xlsx") + + +if __name__ == '__main__': + try: + opts, args = getopt.getopt(sys.argv[1:],"hgr") + except getopt.GetoptError: + print('param_code_automation.py -h -g -r') + sys.exit(2) + for opt, arg in opts: + if opt == '-h': + print('param_code_automation.py -h -g -r') + print(' -h for help') + print(' -g for generate param code, need param_input.xlsx') + print(' -r for generate excel, output file name is param_output.xlsx\n') + sys.exit() + elif opt in ("-g"): + #执行以下代码,从param_input.xlsx生成代码 + storage_cofnig = StorageConfig() + storage_cofnig.generate_code_files("tools/param_code_generation/param/param_defination") + sys.exit() + elif opt in ("-r"): + ##执行一下代码,从讲代码目录逆向为param_output.xlsx + codes = CodeGeneration("param/param_defination") + codes.gen_data_file() + sys.exit() diff --git a/sample/task.json b/sample/task.json new file mode 100644 index 0000000..35bf403 --- /dev/null +++ b/sample/task.json @@ -0,0 +1,405 @@ +interface TaskConfiguration extends BaseTaskConfiguration { + /** + * The configuration's version number + */ + version: '2.0.0'; + + /** + * Windows specific task configuration + */ + windows?: BaseTaskConfiguration; + + /** + * macOS specific task configuration + */ + osx?: BaseTaskConfiguration; + + /** + * Linux specific task configuration + */ + linux?: BaseTaskConfiguration; +} + +interface BaseTaskConfiguration { + /** + * The type of a custom task. Tasks of type "shell" are executed + * inside a shell (e.g. bash, cmd, powershell, ...) + */ + type: 'shell' | 'process'; + + /** + * The command to be executed. Can be an external program or a shell + * command. + */ + command: string; + + /** + * Specifies whether a global command is a background task. + */ + isBackground?: boolean; + + /** + * The command options used when the command is executed. Can be omitted. + */ + options?: CommandOptions; + + /** + * The arguments passed to the command. Can be omitted. + */ + args?: string[]; + + /** + * The presentation options. + */ + presentation?: PresentationOptions; + + /** + * The problem matcher to be used if a global command is executed (e.g. no tasks + * are defined). A tasks.json file can either contain a global problemMatcher + * property or a tasks property but not both. + */ + problemMatcher?: string | ProblemMatcher | (string | ProblemMatcher)[]; + + /** + * The configuration of the available tasks. A tasks.json file can either + * contain a global problemMatcher property or a tasks property but not both. + */ + tasks?: TaskDescription[]; +} + +/** + * Options to be passed to the external program or shell + */ +export interface CommandOptions { + /** + * The current working directory of the executed program or shell. + * If omitted the current workspace's root is used. + */ + cwd?: string; + + /** + * The environment of the executed program or shell. If omitted + * the parent process' environment is used. + */ + env?: { [key: string]: string }; + + /** + * Configuration of the shell when task type is `shell` + */ + shell: { + /** + * The shell to use. + */ + executable: string; + + /** + * The arguments to be passed to the shell executable to run in command mode + * (e.g ['-c'] for bash or ['/S', '/C'] for cmd.exe). + */ + args?: string[]; + }; +} + +/** + * The description of a task. + */ +interface TaskDescription { + /** + * The task's name + */ + label: string; + + /** + * The type of a custom task. Tasks of type "shell" are executed + * inside a shell (e.g. bash, cmd, powershell, ...) + */ + type: 'shell' | 'process'; + + /** + * The command to execute. If the type is "shell" it should be the full + * command line including any additional arguments passed to the command. + */ + command: string; + + /** + * Whether the executed command is kept alive and runs in the background. + */ + isBackground?: boolean; + + /** + * Additional arguments passed to the command. Should be used if type + * is "process". + */ + args?: string[]; + + /** + * Defines the group to which this task belongs. Also supports to mark + * a task as the default task in a group. + */ + group?: 'build' | 'test' | { kind: 'build' | 'test'; isDefault: boolean }; + + /** + * The presentation options. + */ + presentation?: PresentationOptions; + + /** + * The problem matcher(s) to use to capture problems in the tasks + * output. + */ + problemMatcher?: string | ProblemMatcher | (string | ProblemMatcher)[]; + + /** + * Defines when and how a task is run. + */ + runOptions?: RunOptions; +} + +interface PresentationOptions { + /** + * Controls whether the task output is reveal in the user interface. + * Defaults to `always`. + */ + reveal?: 'never' | 'silent' | 'always'; + + /** + * Controls whether the command associated with the task is echoed + * in the user interface. Defaults to `true`. + */ + echo?: boolean; + + /** + * Controls whether the panel showing the task output is taking focus. + * Defaults to `false`. + */ + focus?: boolean; + + /** + * Controls if the task panel is used for this task only (dedicated), + * shared between tasks (shared) or if a new panel is created on + * every task execution (new). Defaults to `shared`. + */ + panel?: 'shared' | 'dedicated' | 'new'; + + /** + * Controls whether to show the `Terminal will be reused by tasks, + * press any key to close it` message. + */ + showReuseMessage?: boolean; + + /** + * Controls whether the terminal is cleared before this task is run. + * Defaults to `false`. + */ + clear?: boolean; + + /** + * Controls whether the task is executed in a specific terminal + * group using split panes. Tasks in the same group (specified by a string value) + * will use split terminals to present instead of a new terminal panel. + */ + group?: string; +} + +/** + * A description of a problem matcher that detects problems + * in build output. + */ +interface ProblemMatcher { + /** + * The name of a base problem matcher to use. If specified the + * base problem matcher will be used as a template and properties + * specified here will replace properties of the base problem + * matcher + */ + base?: string; + + /** + * The owner of the produced VS Code problem. This is typically + * the identifier of a VS Code language service if the problems are + * to be merged with the one produced by the language service + * or 'external'. Defaults to 'external' if omitted. + */ + owner?: string; + + /** + * A human-readable string describing the source of this problem. + * E.g. 'typescript' or 'super lint'. + */ + source?: string; + + /** + * The severity of the VS Code problem produced by this problem matcher. + * + * Valid values are: + * "error": to produce errors. + * "warning": to produce warnings. + * "info": to produce infos. + * + * The value is used if a pattern doesn't specify a severity match group. + * Defaults to "error" if omitted. + */ + severity?: string; + + /** + * Defines how filename reported in a problem pattern + * should be read. Valid values are: + * - "absolute": the filename is always treated absolute. + * - "relative": the filename is always treated relative to + * the current working directory. This is the default. + * - ["relative", "path value"]: the filename is always + * treated relative to the given path value. + * - "autodetect": the filename is treated relative to + * the current workspace directory, and if the file + * does not exist, it is treated as absolute. + * - ["autodetect", "path value"]: the filename is treated + * relative to the given path value, and if it does not + * exist, it is treated as absolute. + * - "search": performs a deep (and, possibly, heavy) file system + * search within the directories. + * - ["search", {include: ["${workspaceFolder}"]}]: performs + * a deep search among the directories given in the "include" array. + * - ["search", {include: ["${workspaceFolder}"], exclude: []}]: + * performs a deep search among the directories given in the "include" + * array, excluding those named in the "exclude" array. + */ + fileLocation?: string | string[] | ['search', { include?: string[]; exclude?: string[] }]; + + /** + * The name of a predefined problem pattern, the inline definition + * of a problem pattern or an array of problem patterns to match + * problems spread over multiple lines. + */ + pattern?: string | ProblemPattern | ProblemPattern[]; + + /** + * Additional information used to detect when a background task (like a watching task in Gulp) + * is active. + */ + background?: BackgroundMatcher; +} + +/** + * A description to track the start and end of a background task. + */ +interface BackgroundMatcher { + /** + * If set to true the watcher is in active mode when the task + * starts. This is equals of issuing a line that matches the + * beginPattern. + */ + activeOnStart?: boolean; + + /** + * If matched in the output the start of a background task is signaled. + */ + beginsPattern?: string; + + /** + * If matched in the output the end of a background task is signaled. + */ + endsPattern?: string; +} + +interface ProblemPattern { + /** + * The regular expression to find a problem in the console output of an + * executed task. + */ + regexp: string; + + /** + * Whether the pattern matches a problem for the whole file or for a location + * inside a file. + * + * Defaults to "location". + */ + kind?: 'file' | 'location'; + + /** + * The match group index of the filename. + */ + file: number; + + /** + * The match group index of the problem's location. Valid location + * patterns are: (line), (line,column) and (startLine,startColumn,endLine,endColumn). + * If omitted the line and column properties are used. + */ + location?: number; + + /** + * The match group index of the problem's line in the source file. + * Can only be omitted if location is specified. + */ + line?: number; + + /** + * The match group index of the problem's column in the source file. + */ + column?: number; + + /** + * The match group index of the problem's end line in the source file. + * + * Defaults to undefined. No end line is captured. + */ + endLine?: number; + + /** + * The match group index of the problem's end column in the source file. + * + * Defaults to undefined. No end column is captured. + */ + endColumn?: number; + + /** + * The match group index of the problem's severity. + * + * Defaults to undefined. In this case the problem matcher's severity + * is used. + */ + severity?: number; + + /** + * The match group index of the problem's code. + * + * Defaults to undefined. No code is captured. + */ + code?: number; + + /** + * The match group index of the message. Defaults to 0. + */ + message: number; + + /** + * Specifies if the last pattern in a multi line problem matcher should + * loop as long as it does match a line consequently. Only valid on the + * last problem pattern in a multi line problem matcher. + */ + loop?: boolean; +} + +/** + * A description to when and how run a task. + */ +interface RunOptions { + /** + * Controls how variables are evaluated when a task is executed through + * the Rerun Last Task command. + * The default is `true`, meaning that variables will be re-evaluated when + * a task is rerun. When set to `false`, the resolved variable values from + * the previous run of the task will be used. + */ + reevaluateOnRerun?: boolean; + + /** + * Specifies when a task is run. + * + * Valid values are: + * "default": The task will only be run when executed through the Run Task command. + * "folderOpen": The task will be run when the containing folder is opened. + */ + runOn?: string; +} diff --git a/source/CBB/Param.py b/source/CBB/Param.py new file mode 100644 index 0000000..f1acf90 --- /dev/null +++ b/source/CBB/Param.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +''' +参数管理模块代码生成 + +此脚本提供参数管理模块代码生成相关类与功能函数。 + + + +''' + +import numpy as np +from pandas import DataFrame + + +def code_cbb_param(sheet: DataFrame) -> str|None: + """ 参数页代码生成 """ + pass + +def code_cbb_params(sheets: dict[str, DataFrame]) -> str|None: + """ 完整参数模块配置代码生成 """ + pass \ No newline at end of file diff --git a/source/PV_Inverter/CodeGenerator.py b/source/PV_Inverter/CodeGenerator.py new file mode 100644 index 0000000..5cbaa72 --- /dev/null +++ b/source/PV_Inverter/CodeGenerator.py @@ -0,0 +1,44 @@ +import numpy as np +from pandas import DataFrame + + +def code_param_arm(sheet: DataFrame) -> str|None: + """ 生成所需代码内容 """ + + result = "" + result += "#include \n" + result += "#include \n" + result += "\n" + object_list = [] + + serises_variable = sheet['变量名'].dropna() + serises_name = sheet['协议结构名称'].dropna() + serises_name[serises_variable.index[-1]+1] = 'endline' + for index in range(serises_name.shape[0]-1): + meta_object = {} + meta_object['name'] = serises_name.iloc[index] + meta_object['range'] = (serises_name.index[index], serises_name.index[index+1]-1) + meta_object['member'] = sheet.loc[serises_name.index[index]: serises_name.index[index+1]-1] + + code_object = f"typedef struct tag_{meta_object['name']}" + "\n" + code_object += "{" + "\n" + list_codes = [] + for id, item in meta_object['member'].iterrows(): + if item['变量名'] is np.nan: + continue + code_veriable = f" uint16_t " + code_veriable += f"a" if item['数据长度'] > 1 else "" + code_veriable += f"{item['变量名']}" + code_veriable += f"[{item['数据长度']}];" if item['数据长度'] > 1 else ";" + code_comment = f"/*{item['地址']} {item['数据项名称']}*/" + list_codes.append((index, code_veriable, code_comment)) + code_len_max = max((len(line[1]) for line in list_codes)) + 2 + code_len_max = code_len_max if code_len_max > 65 else 65 + for id, line_prefix, line_suffix in list_codes: + code_object += line_prefix + " " * (code_len_max - len(line_prefix)) + line_suffix + "\n" + code_object += "}" + f"{meta_object['name']};" + "\n" + + result += code_object + "\n" + + + return result \ No newline at end of file diff --git a/source/main.py b/source/main.py new file mode 100644 index 0000000..7abffa5 --- /dev/null +++ b/source/main.py @@ -0,0 +1,63 @@ +import re +import argparse +import subprocess +import pandas as pd +from pathlib import Path + +from PV_Inverter.CodeGenerator import code_param_arm +from CBB.Param import code_cbb_params + +def save_file(content: str, path_file: Path): + if not path_file.parent.exists(): + path_file.parent.mkdir(parents=True) + + return path_file.write_text(content) + +def main(args: argparse.Namespace) -> bool: + """ 核心执行函数 """ + global type_list, dev_list + file_excel = Path(args.path) + code_folder = Path(args.output) if args.output else (file_excel.parent / "result") + + # 读取Excel文件 + if file_excel.exists(): + if file_excel.suffix in ['.dec', '.xlsx']: + dataframes = pd.read_excel(file_excel, sheet_name=None) + elif file_excel.suffix == '.xls': + dataframes = pd.read_excel(file_excel, sheet_name=None, engine='xlrd') + else: + raise ValueError("File format Unsupported.") + else: + raise ValueError("File does not exist.") + + if args.type == 'COMM_ARM': + # 光伏逆变器-ARM数据结构体生成 + content_code = code_param_arm(dataframes['ARM地址表']) + elif args.type == 'CBB_Param': + content_code = code_cbb_params(dataframes) + save_file(content_code, code_folder / 'param_arm_struct.h') + +if __name__ == "__main__": + type_list = ['COMM_DSP', 'COMM_ARM', 'CBB_Param'] + dev_list = ['PV_INV30', 'PV_INV40', 'PV_INV50'] + parser = argparse.ArgumentParser() + parser.add_argument("path") + parser.add_argument( + "-t", "--type", + choices=type_list, + help=f"Specify the Code Generate type [{', '.join(type_list)}]", + required=True + ) + parser.add_argument( + "-d", "--device", + choices=dev_list, + help=f"Specify the device type [{', '.join(dev_list)}]", + required=True + ) + + parser.add_argument("-i", "--ignore") + parser.add_argument("-o", "--output") + args = parser.parse_args() + + main(args) +