SrcToA2L/main.cpp
2025-06-27 14:13:23 +08:00

688 lines
27 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <iostream>
extern "C"
{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
}
#define SEGMENT_BUFF_LENGTH 1000 // 行段长度
#define ELEMENT_INFO_NAME_LENGTH 50 // 变量名长度上限
#define ELEMENT_INFO_TYPE_STR_LENTH 20 // 变量类型字符串长度上限
#define ELEMENT_INFO_LIMIT_STR_LENTH 20 // 变量上下限字符串长度上限
// 输入输出文件指针
FILE *Input_Source = nullptr;
FILE *Input_Reference = nullptr;
FILE *Input_Map = nullptr;
FILE *Output_Target = nullptr;
// 相关识别串
const char measurement_begin[] = "// ##begin_measurement";
const char measurement_end[] = "// ##end_measurement";
const char calibration_begin[] = "// ##begin_calibration";
const char calibration_end[] = "// ##end_calibration";
const char a2l_module_end[] = "/end MODULE";
// 段输出标识串
const char auto_generated_measurement_start[] = "\r\n/*********** Start of auto generated measurement blocks ***********/\r\n\r\n";
const char auto_generated_measurement_end[] = "\r\n/*********** End of auto generated measurement blocks ***********/\r\n\r\n";
const char auto_generated_calibration_start[] = "\r\n/*********** Start of auto generated calibration blocks ***********/\r\n\r\n";
const char auto_generated_calibration_end[] = "\r\n/*********** End of auto generated calibration blocks ***********/\r\n\r\n";
// 变量类型枚举
typedef enum
{
TYPE_NOT_SUPPORTED, // 不支持的类型
UBYTE, // uint8_t,bool
UWORD, // uint16_t
ULONG, // uint32_t
SBYTE, // int8_t
SWORD, // int16_t
SLONG, // int32_t
FLOAT32, // float
FLOAT64, // double
} Element_Type_Enum;
// 元素信息结构体
typedef struct
{
char name[ELEMENT_INFO_NAME_LENGTH] = {'\0'}; // 变量名
size_t count = 0; // 变量成员数(仅数组>1
size_t element_len = 0; // 单元素长度(单位:字节)
uint32_t addr = 0x00000000; // 元素起始地址
Element_Type_Enum type = TYPE_NOT_SUPPORTED; // 变量类型
char type_str[ELEMENT_INFO_TYPE_STR_LENTH] = {'\0'}; // 类型字符串
char max_limit_str[ELEMENT_INFO_LIMIT_STR_LENTH] = {'\0'}; // 上限字符串
char min_limit_str[ELEMENT_INFO_LIMIT_STR_LENTH] = {'\0'}; // 下限字符串
} Element_Info;
// 文件链表
typedef struct File_List_Struct
{
const char *file_name = nullptr; // 文件名
File_List_Struct *p_next = nullptr; // 下一表
} File_List;
// 获取文件的一行成功时返回字符串指针失败文件结尾or超出长度时回退文件指针
char *f_getline(FILE *file, char *s, size_t len)
{
size_t count = 0;
while (true)
{
char ch = fgetc(file);
if (count >= len) // 超长
{
fseek(file, -count, SEEK_CUR);
printf("[- WARN -] single line out of length\n");
return nullptr;
}
if (ch == EOF && count == 0) // 仅文件结尾
return nullptr;
if (ch == '\n' || ch == EOF) // 成功换行or文件结尾
{
s[count] = '\n';
return s;
}
s[count] = ch;
count++;
}
}
// 获取类型
Element_Type_Enum get_element_type(const char *str)
{
if (!strcmp(str, "bool"))
return UBYTE;
if (!strcmp(str, "uint8_t"))
return UBYTE;
if (!strcmp(str, "uint16_t"))
return UWORD;
if (!strcmp(str, "uint32_t"))
return ULONG;
if (!strcmp(str, "int8_t"))
return SBYTE;
if (!strcmp(str, "int16_t"))
return SWORD;
if (!strcmp(str, "int32_t"))
return SLONG;
if (!strcmp(str, "float"))
return FLOAT32;
if (!strcmp(str, "double"))
return FLOAT64;
return TYPE_NOT_SUPPORTED;
}
// 解析元素类型
Element_Info solve_element(const char *str)
{
Element_Info info;
// 读取前段内容并获取元素类型
char buff[ELEMENT_INFO_NAME_LENGTH] = {'\0'};
sscanf(str, "%s", buff);
info.type = get_element_type(buff);
// 更新字符串信息
switch (info.type)
{
case UBYTE:
sprintf(info.type_str, "UBYTE");
sprintf(info.min_limit_str, "0");
sprintf(info.max_limit_str, "255");
info.element_len = 1;
break;
case UWORD:
sprintf(info.type_str, "UWORD");
sprintf(info.min_limit_str, "0");
sprintf(info.max_limit_str, "65535");
info.element_len = 2;
break;
case ULONG:
sprintf(info.type_str, "ULONG");
sprintf(info.min_limit_str, "0");
sprintf(info.max_limit_str, "4294967295");
info.element_len = 4;
break;
case SBYTE:
sprintf(info.type_str, "SBYTE");
sprintf(info.min_limit_str, "-128");
sprintf(info.max_limit_str, "127");
info.element_len = 1;
case SWORD:
sprintf(info.type_str, "SWORD");
sprintf(info.min_limit_str, "-32768");
sprintf(info.max_limit_str, "32767");
info.element_len = 2;
break;
case SLONG:
sprintf(info.type_str, "SLONG");
sprintf(info.min_limit_str, "-2147483648");
sprintf(info.max_limit_str, "2147483647");
info.element_len = 4;
break;
case FLOAT32:
sprintf(info.type_str, "FLOAT32_IEEE");
sprintf(info.min_limit_str, "-3.4E+38");
sprintf(info.max_limit_str, "3.4E+38");
info.element_len = 4;
break;
case FLOAT64:
sprintf(info.type_str, "FLOAT64_IEEE");
sprintf(info.min_limit_str, "-1.7E+308");
sprintf(info.max_limit_str, "1.7E+308");
info.element_len = 8;
break;
default:
sprintf(info.type_str, "UNSUPPORTED");
sprintf(info.min_limit_str, "0");
sprintf(info.max_limit_str, "0");
info.element_len = 0;
}
// 读取后段内容
sscanf(str + strlen(buff), "%s", buff);
// 获取名字和长度
for (int count = 0; count < ELEMENT_INFO_NAME_LENGTH; count++)
{
if (buff[count] == '[') // 识别到数组
{
for (int n = count; n < ELEMENT_INFO_NAME_LENGTH; n++)
{
if (buff[n] == ']')
break;
if (isdigit(buff[n]))
info.count = info.count * 10 + buff[n] - '0';
}
break;
}
if (buff[count] == ' ' || buff[count] == '=' || buff[count] == ';') // 是单个变量
break;
info.name[count] = buff[count]; // 复制变量名
}
return info;
}
// 获取元素地址
Element_Info get_element_addr(Element_Info info, FILE *map_file)
{
// 回到文件头
fseek(map_file, 0, SEEK_SET);
// 段缓冲区
char segment_buff[SEGMENT_BUFF_LENGTH] = {'\0'};
bool find = false;
// 读取并复制参考文件直到 a2l MODULE 结尾
while (f_getline(map_file, segment_buff, sizeof(segment_buff)) != nullptr && !find)
{
// 匹配到变量名称
if (strstr(segment_buff, info.name))
{
char *lpTarget = strstr(segment_buff, info.name);
size_t len = strlen(info.name);
// 匹配到的名称是后段中的子段内容---> xxxxx[name]xx
if (lpTarget[len] != ' ' && lpTarget[len] != '\r' && lpTarget[len] != '\n')
continue;
// 匹配到的名称是前段中的字段内容---> xx[name]xxxxx
if (*(lpTarget - 1) != '_' && *(lpTarget - 1) != ' ' && *(lpTarget - 1) != '@')
continue;
find = true;
char buff[20];
sscanf(segment_buff, "%*s%s", &buff);
// 16进制转换
for (int count = 0; count < 20; count++)
{
if (buff[count] == '+')
break;
if (isalpha(buff[count]))
info.addr = info.addr * 16 + toupper(buff[count]) - 'A' + 10;
else
info.addr = info.addr * 16 + buff[count] - '0';
}
}
// 清空段缓冲区
memset(segment_buff, '\0', sizeof(segment_buff));
}
return info;
}
// 入口
int main(int m_argc, char *m_argv[])
{
// int m_argc = 9;
// char str[m_argc][20] = {
// {".\\new.exe"},
// {".\\input.c"},
// {".\\inputB.c"},
// {"-r"},
// {".\\PVER.a2l"},
// {"-l"},
// {".\\PVER.map"},
// // {"-o"},
// // {".\\[NEW]PVER.a2l"},
// };
// char *(m_argv[m_argc]);
// for (int count = 0; count < m_argc; count++)
// m_argv[count] = str[count];
// 文件列表初始
File_List *list = (File_List *)malloc(sizeof(File_List));
list->file_name = nullptr;
list->p_next = nullptr;
File_List *listHead = list;
// 处理输入部分
{
const char *reference_name = nullptr; // 参考文件名
const char *output_name = nullptr; // 输出文件名
// 循环处理指令
for (int count = 1; count < m_argc; count++)
{
// 匹配到参考a2l文件
if (!strcmp(m_argv[count], "-r"))
{
if (count + 1 >= m_argc)
break;
Input_Reference = fopen(m_argv[count + 1], "rb");
if (Input_Reference == nullptr)
{
printf("[- FAIL -] Input reference file <%s> open failed.\n", m_argv[count + 1]);
break;
}
// 获取不带路径的文件名
reference_name = m_argv[count + 1] + strlen(m_argv[count + 1]);
while (reference_name + 1 != m_argv[count + 1] && *reference_name != '\\' && *reference_name != '/')
reference_name--;
reference_name++;
printf("[- OK -] %-31s %s\n", "Input reference .a2l file:", m_argv[count + 1]);
count++;
continue;
}
// 匹配到链接map文件
else if (!strcmp(m_argv[count], "-l"))
{
if (count + 1 >= m_argc)
break;
Input_Map = fopen(m_argv[count + 1], "rb");
if (Input_Map == nullptr)
{
printf("[- FAIL -] Input link file <%s> open failed.\n", m_argv[count + 1]);
break;
}
printf("[- OK -] %-31s %s\n", "Input link .map file:", m_argv[count + 1]);
count++;
continue;
}
// 匹配到自定义输出文件名
else if (!strcmp(m_argv[count], "-o"))
{
if (count + 1 >= m_argc)
break;
output_name = m_argv[count + 1];
printf("[- OK -] %-31s %s\n", "Set output filename:", m_argv[count + 1]);
count++;
continue;
}
// 其它输入作为源文件输入
printf("[- OK -] %-31s %s\n", "Input source filename:", m_argv[count]);
list->file_name = m_argv[count];
list->p_next = (File_List *)malloc(sizeof(File_List));
list = list->p_next;
list->file_name = nullptr;
list->p_next = nullptr;
}
// 检查文件列表状态
if (listHead->file_name == nullptr)
{
printf("[- FAIL -] No source file input.\n");
free(listHead);
fcloseall();
return 0;
}
// 检查参考文件输入文件状态
if (Input_Reference == nullptr)
{
printf("[- FAIL -] No reference .a2l file input.\n");
fcloseall();
return 0;
}
// 检查map链接文件文件状态
if (Input_Map == nullptr)
printf("[- WARN -] No link .map file input.\n");
// 处理输出文件名称
if (output_name != nullptr)
Output_Target = fopen(output_name, "wb+");
else if (reference_name != nullptr)
{
// 拼接默认的输出文件名
const char *prefix = "[NEW]";
char *buffer = (char *)malloc(strlen(reference_name) + strlen(prefix) + 1);
sprintf(buffer, "%s%s", prefix, reference_name);
printf("[> NOTE <] %-31s %s\n", "Default output filename:", buffer);
Output_Target = fopen(buffer, "wb+");
// 释放临时指针
free(buffer);
}
}
// 打开输入源文件(二进制形式否则RF/CRLF引发计数问题)
Input_Source = fopen("./input.c", "rb");
// 段缓冲区
char segment_buff[SEGMENT_BUFF_LENGTH] = {'\0'};
// 读取并复制参考文件直到 a2l MODULE 结尾
while (f_getline(Input_Reference, segment_buff, sizeof(segment_buff)) != nullptr)
{
// 当前行为 a2l MODULE 结尾
if (strstr(segment_buff, a2l_module_end))
{
// 回退文件指针到上一行结尾
fseek(Input_Reference, -2, SEEK_CUR);
while (fgetc(Input_Reference) != '\n')
fseek(Input_Reference, -2, SEEK_CUR);
break;
}
// 输出行到文件
// fprintf(Output_Target, segment_buff); // 太大300会段溢出
for (int count = 0; count < SEGMENT_BUFF_LENGTH; count++) // 逐个输出
{
fputc(segment_buff[count], Output_Target);
if (segment_buff[count] == '\n')
break;
}
// 清空段缓冲区
memset(segment_buff, '\0', sizeof(segment_buff));
}
list = listHead;
// 循环处理输入文件链表
while (list->p_next != nullptr)
{
Input_Source = fopen(list->file_name, "rb");
if (Input_Source == nullptr)
{
printf("[< FAIL >] Soure file \"%s\" load failed.\n", list->file_name);
fclose(Input_Source);
list = (File_List *)list->p_next;
continue;
}
printf("\n\n[- OK -] Soure file \"%s\" load succeed.\n", list->file_name);
// 循环获取输入文件行
while (f_getline(Input_Source, segment_buff, sizeof(segment_buff)) != nullptr)
{
// 当前行为观测量起始位行
if (strstr(segment_buff, measurement_begin))
{
printf("\n%s\n\n", measurement_begin);
fprintf(Output_Target, auto_generated_measurement_start);
// 清空段缓冲区
memset(segment_buff, '\0', sizeof(segment_buff));
while (true)
{
// 获取下一行
f_getline(Input_Source, segment_buff, sizeof(segment_buff));
// 观测量结束行
if (strstr(segment_buff, measurement_end))
{
printf("\n%s\n\n", measurement_end);
fprintf(Output_Target, auto_generated_measurement_end);
break;
}
// 解析元素变量信息
{
Element_Info info = solve_element(segment_buff);
// 成功解析
if (info.type != TYPE_NOT_SUPPORTED)
{
// 获取地址
info = get_element_addr(info, Input_Map);
// 调试信息
if (info.addr != 0)
{
if (info.count == 0)
printf("[- OK -] 0x%08x %-20s %s;\n", info.addr, info.type_str, info.name);
else
printf("[- OK -] 0x%08x %-20s %s[%d];\n", info.addr, info.type_str, info.name, info.count);
}
else
{
if (info.count == 0)
printf("[< WARN >] 0x%08x %-20s %s;\n", info.addr, info.type_str, info.name);
else
printf("[< WARN >] 0x%08x %-20s %s[%d];\n", info.addr, info.type_str, info.name, info.count);
}
// 单变量
if (info.count == 0)
{
fprintf(Output_Target, "%s\r\n\r\n", "/begin MEASUREMENT"); // 观测量头
fprintf(Output_Target, " %s\r\n", info.name); // 名称
fprintf(Output_Target, " \"auto generated\"\r\n"); // 描述
fprintf(Output_Target, " %s\r\n", info.type_str); // 数据类型
fprintf(Output_Target, " %s\r\n", "NO_COMPU_METHOD"); // 转换式(保留原始值)
fprintf(Output_Target, " %s\r\n", "0"); // 分辨率
fprintf(Output_Target, " %s\r\n", "0"); // 精度误差
fprintf(Output_Target, " %s\r\n", info.min_limit_str); // 下限
fprintf(Output_Target, " %s\r\n", info.max_limit_str); // 上限
fprintf(Output_Target, " %s 0x%08x\r\n\r\n", "ECU_ADDRESS", info.addr); // ECU 地址
fprintf(Output_Target, "%s\r\n\r\n", "/end MEASUREMENT"); // 观测量尾
}
else
{
for (int count = 0; count < info.count; count++)
{
fprintf(Output_Target, "%s\r\n\r\n", "/begin MEASUREMENT"); // 观测量头
fprintf(Output_Target, " %s[%d]\r\n", info.name, count); // 名称
fprintf(Output_Target, " \"auto generated\"\r\n"); // 描述
fprintf(Output_Target, " %s\r\n", info.type_str); // 数据类型
fprintf(Output_Target, " %s\r\n", "NO_COMPU_METHOD"); // 转换式(保留原始值)
fprintf(Output_Target, " %s\r\n", "0"); // 分辨率
fprintf(Output_Target, " %s\r\n", "0"); // 精度误差
fprintf(Output_Target, " %s\r\n", info.min_limit_str); // 下限
fprintf(Output_Target, " %s\r\n", info.max_limit_str); // 上限
fprintf(Output_Target, " %s 0x%08x\r\n\r\n", "ECU_ADDRESS", info.addr + count * info.element_len); // ECU 地址
fprintf(Output_Target, "%s\r\n\r\n", "/end MEASUREMENT"); // 观测量尾
}
}
}
else if (info.name[0] != '\0') // 解析失败且变量名不为空
{
if (info.count == 0)
printf("[< FAIL >] 0x%08x %-20s %s;\n", info.addr, info.type_str, info.name);
else
printf("[< FAIL >] 0x%08x %-20s %s[%d];\n", info.addr, info.type_str, info.name, info.count);
}
}
// 清空段缓冲区
memset(segment_buff, '\0', sizeof(segment_buff));
}
}
// 当前行为标定量起始位行
if (strstr(segment_buff, calibration_begin))
{
printf("\n%s\n\n", calibration_begin);
fprintf(Output_Target, auto_generated_calibration_start);
// 清空段缓冲区
memset(segment_buff, '\0', sizeof(segment_buff));
while (true)
{
// 获取下一行
f_getline(Input_Source, segment_buff, sizeof(segment_buff));
// 标定量结束行
if (strstr(segment_buff, calibration_end))
{
printf("\n%s\n\n", calibration_end);
fprintf(Output_Target, auto_generated_calibration_end);
break;
}
// 解析元素变量信息
{
Element_Info info = solve_element(segment_buff);
// 成功解析
if (info.type != TYPE_NOT_SUPPORTED)
{
// 获取地址
info = get_element_addr(info, Input_Map);
// 调试信息
if (info.addr != 0)
{
if (info.count == 0)
printf("[- OK -] 0x%08x %-20s %s;\n", info.addr, info.type_str, info.name);
else
printf("[- OK -] 0x%08x %-20s %s[%d];\n", info.addr, info.type_str, info.name, info.count);
}
else
{
if (info.count == 0)
printf("[< WARN >] 0x%08x %-20s %s;\n", info.addr, info.type_str, info.name);
else
printf("[< WARN >] 0x%08x %-20s %s[%d];\n", info.addr, info.type_str, info.name, info.count);
}
// 单变量
if (info.count == 0)
{
fprintf(Output_Target, "%s\r\n\r\n", "/begin CHARACTERISTIC"); // 标定量头
fprintf(Output_Target, " %s\r\n", info.name); // 名称
fprintf(Output_Target, " \"auto generated\"\r\n"); // 描述
fprintf(Output_Target, " %s\r\n", "VALUE"); // 值类型(数值、数组、曲线)
fprintf(Output_Target, " 0x%08x\r\n", info.addr); // ECU 地址
fprintf(Output_Target, " Scalar_%s\r\n", info.type_str); // 数据类型
fprintf(Output_Target, " %s\r\n", "0"); // 允许最大差分
fprintf(Output_Target, " %s\r\n", "NO_COMPU_METHOD"); // 转换式(保留原始值)
fprintf(Output_Target, " %s\r\n", info.min_limit_str); // 下限
fprintf(Output_Target, " %s\r\n\r\n", info.max_limit_str); // 上限
fprintf(Output_Target, "%s\r\n\r\n", "/end CHARACTERISTIC"); // 标定量尾
}
else
{
for (int count = 0; count < info.count; count++)
{
fprintf(Output_Target, "%s\r\n\r\n", "/begin CHARACTERISTIC"); // 标定量头
fprintf(Output_Target, " %s[%d]\r\n", info.name, count); // 名称
fprintf(Output_Target, " \"auto generated\"\r\n"); // 描述
fprintf(Output_Target, " %s\r\n", "VALUE"); // 值类型(数值、数组、曲线)
fprintf(Output_Target, " 0x%08x\r\n", info.addr + count * info.element_len); // ECU 地址
fprintf(Output_Target, " Scalar_%s\r\n", info.type_str); // 数据类型
fprintf(Output_Target, " %s\r\n", "0"); // 允许最大差分
fprintf(Output_Target, " %s\r\n", "NO_COMPU_METHOD"); // 转换式(保留原始值)
fprintf(Output_Target, " %s\r\n", info.min_limit_str); // 下限
fprintf(Output_Target, " %s\r\n\r\n", info.max_limit_str); // 上限
fprintf(Output_Target, "%s\r\n\r\n", "/end CHARACTERISTIC"); // 标定量尾
}
}
}
else if (info.name[0] != '\0') // 解析失败且变量名不为空
{
if (info.count == 0)
printf("[< FAIL >] 0x%08x %-20s %s;\n", info.addr, info.type_str, info.name);
else
printf("[< FAIL >] 0x%08x %-20s %s[%d];\n", info.addr, info.type_str, info.name, info.count);
}
}
// 清空段缓冲区
memset(segment_buff, '\0', sizeof(segment_buff));
}
}
}
fclose(Input_Source);
list = (File_List *)list->p_next;
}
// 清空段缓冲区
memset(segment_buff, '\0', sizeof(segment_buff));
// 输出参考文件的剩余部分
// 读取并复制参考文件直到 a2l MODULE 结尾
while (f_getline(Input_Reference, segment_buff, sizeof(segment_buff)) != nullptr)
{
// 输出行到文件
fprintf(Output_Target, segment_buff);
// 清空段缓冲区
memset(segment_buff, '\0', sizeof(segment_buff));
}
// 关闭文件
fcloseall();
// 释放文件指针
list = listHead;
while (list != nullptr)
{
File_List *next = (File_List *)list->p_next;
free(list);
list = next;
}
return 0;
}