初始化工程
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# 生成文件
|
||||
**/__pycache__
|
||||
35
.vscode/launch.json
vendored
Normal file
35
.vscode/launch.json
vendored
Normal file
@@ -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",
|
||||
}
|
||||
]
|
||||
}
|
||||
54
.vscode/tasks.json
vendored
Normal file
54
.vscode/tasks.json
vendored
Normal file
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
requirements.txt
Normal file
BIN
requirements.txt
Normal file
Binary file not shown.
931
sample/param_code_automation.py
Normal file
931
sample/param_code_automation.py
Normal file
@@ -0,0 +1,931 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import openpyxl
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import sys
|
||||
import getopt
|
||||
|
||||
STORAGE_DICS = [
|
||||
["PARAM_STORE_ADDR", "C1", "存储区域基地址", "D1",],
|
||||
["PARAM_STORE_NAME", "C2", "存储区域命名", "D2",],
|
||||
["PARAM_STORE_UNIT", "C3", "存储区域擦写单元", "D3",],
|
||||
["PARAM_DATA_UNIT", "C4", "存储区域单分区大小", "D4",],
|
||||
["PARAM_NUM", "C5", "参数个数", "D5",],
|
||||
["PARAM_RAM", "C6", "是否需要RAM参数对象", "D6",],
|
||||
["PARAM_STORAGE_TYPE","C7", "存储器类型", "D7",],
|
||||
["PARAM_FILE_PATH", "C8", "参数文件路径", "D8",],
|
||||
]
|
||||
|
||||
class ParamItem(object):
|
||||
'''
|
||||
从excel表格中读取到的参数信息体
|
||||
index:参数索引
|
||||
DI:参数唯一编码
|
||||
str_name:参数名称(汉字)
|
||||
name:参数标识符
|
||||
store_type:参数存储类型
|
||||
size:参数数据域大小
|
||||
default_val:参数默认值
|
||||
local_type:参数本地使用类型
|
||||
ratio:缩放倍率
|
||||
min:参数范围-最小值
|
||||
max:参数范围-最大值
|
||||
flag:参数标记
|
||||
check_func:参数修改前的有效性检查函数
|
||||
updata_func:参数更新后的回调函数
|
||||
infomation:当前参数注释
|
||||
offset:当前参数的内存对象偏移
|
||||
offset_str:当前参数的存储偏移
|
||||
size_string:参数的数据域大小宏定义
|
||||
'''
|
||||
def __init__(self, row):
|
||||
'''
|
||||
将excel中的一行数据转换为参数信息体
|
||||
'''
|
||||
self.index = row[0].value
|
||||
self.DI = row[1].value
|
||||
self.str_name = row[2].value
|
||||
self.name = row[3].value
|
||||
self.store_type = row[4].value
|
||||
self.size = row[5].value
|
||||
self.default_value = row[6].value
|
||||
self.local_type = row[7].value
|
||||
self.ratio = row[8].value
|
||||
self.min = row[9].value
|
||||
self.max = row[10].value
|
||||
self.flag = row[11].value
|
||||
self.check_func = row[12].value
|
||||
self.updata_func = row[13].value
|
||||
self.infomation = row[14].value
|
||||
self.offset = ""
|
||||
self.offset_str = ""
|
||||
self.size_string = ""
|
||||
def __str__(self):
|
||||
return "%s,\t%s,\t%s,\t%s,\t%s,\t%s,\t%s,\t%s,\t%s,\t%s,\t%s,\t%s,\t%s,\t%s,\t%s"%(
|
||||
self.index, self.DI, self.str_name, self.name, self.store_type, self.size, self.default_value,
|
||||
self.local_type, self.ratio, self.min, self.max, self.flag, self.check_func, self.updata_func, self.infomation)
|
||||
|
||||
class StorageConfig(object):
|
||||
'''
|
||||
读取excel中的所有sheet,将sheet中的数据转换为参数信息结构体
|
||||
'''
|
||||
def __init__(self):
|
||||
self.workbook = openpyxl.load_workbook("tools/param_input.xlsx", data_only=True)
|
||||
self.config_set = {}
|
||||
self.param_index = ""
|
||||
for sheet_name in self.workbook.sheetnames:
|
||||
self.config_set[sheet_name] = {}
|
||||
self.config_set[sheet_name]["name"] = sheet_name
|
||||
sheet = self.workbook[sheet_name]
|
||||
self.config_set[sheet_name]["param_storage_addr"] = {sheet["C1"].value:sheet["D1"].value}
|
||||
self.config_set[sheet_name]["param_storage_name"] = {sheet["C2"].value:sheet["D2"].value}
|
||||
self.config_set[sheet_name]["param_storage_unit"] = {sheet["C3"].value:sheet["D3"].value}
|
||||
self.config_set[sheet_name]["param_data_unit"] = {sheet["C4"].value:sheet["D4"].value}
|
||||
self.config_set[sheet_name]["param_num"] = {sheet["C5"].value:sheet["D5"].value}
|
||||
self.config_set[sheet_name]["param_ram"] = {sheet["C6"].value:sheet["D6"].value}
|
||||
self.config_set[sheet_name]["storage_type"] = {sheet["C7"].value:sheet["D7"].value}
|
||||
self.config_set[sheet_name]["file_path_prefix"] = {sheet["C8"].value:sheet["D8"].value}
|
||||
|
||||
cell_table = sheet["A11":"O%d"%(11+self.config_set[sheet_name]['param_num']["参数个数"])]
|
||||
self.config_set[sheet_name]["param_info_list"] = []
|
||||
offset = 0
|
||||
for row_cel in cell_table[1:]:
|
||||
param = ParamItem(row_cel)
|
||||
offset = offset + int(param.size) + 7 #PARAM_INFO_SIZE
|
||||
param.offset = "%s_PARAM_%s_OFFSET"%(sheet_name.upper(), param.name.upper())
|
||||
param.size_string = "%s_PARAM_%s_SIZE"%(sheet_name.upper(), param.name.upper())
|
||||
self.config_set[sheet_name]["param_info_list"].append([param,offset])
|
||||
|
||||
def data_check(self):
|
||||
for sheet in self.workbook:
|
||||
for item in STORAGE_DICS:
|
||||
if sheet[item[1]].value != item[2]:
|
||||
print(item,sheet[item[1]].value, item[2], "bad file")
|
||||
|
||||
|
||||
def __generate_definations(self):
|
||||
'''生成defination.h'''
|
||||
|
||||
file_name_formate = "param_%s_defination.h"
|
||||
|
||||
file_title_formate = '''/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: param_%s_defination.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: %s
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Autogenerated
|
||||
* Organization: Topscomm
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef __PARAM_%s_DEFINATION_H__
|
||||
#define __PARAM_%s_DEFINATION_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
#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 <stdint.h>
|
||||
|
||||
#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 <stddef.h>
|
||||
|
||||
#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 <stdint.h>
|
||||
|
||||
/* ##### 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()
|
||||
405
sample/task.json
Normal file
405
sample/task.json
Normal file
@@ -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;
|
||||
}
|
||||
21
source/CBB/Param.py
Normal file
21
source/CBB/Param.py
Normal file
@@ -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
|
||||
44
source/PV_Inverter/CodeGenerator.py
Normal file
44
source/PV_Inverter/CodeGenerator.py
Normal file
@@ -0,0 +1,44 @@
|
||||
import numpy as np
|
||||
from pandas import DataFrame
|
||||
|
||||
|
||||
def code_param_arm(sheet: DataFrame) -> str|None:
|
||||
""" 生成所需代码内容 """
|
||||
|
||||
result = ""
|
||||
result += "#include <stdint.h>\n"
|
||||
result += "#include <stdbool.h>\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
|
||||
63
source/main.py
Normal file
63
source/main.py
Normal file
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user