import sys import json from DBC_Converter_Data_Parsing import load_dbc_file #============================== Generate Globals ==============================# def generate_globals(signals, C_file, header_file): if not signals: print("[WARNING] No signals to generate globals for.") return with open(C_file, 'w') as f: f.write("#include \n") for message_name, message_info in signals.items(): for signal in message_info["Signals"]: if signal["Length"] > 32: f.write(f"float GV_{signal['Signal name']} = 0.0f;\n") else: f.write(f"uint32_t GV_{signal['Signal name']} = 0;\n") with open(header_file, 'w') as f: f.write("#ifndef GENERATED_GLOBALS_H\n") f.write("#define GENERATED_GLOBALS_H\n\n") f.write("#include \n\n") for message_name, message_info in signals.items(): for signal in message_info["Signals"]: if signal["Length"] > 32: f.write(f"extern float GV_{signal['Signal name']};\n") else: f.write(f"extern uint32_t GV_{signal['Signal name']};\n") f.write("\n#endif // GENERATED_GLOBALS_H\n") print(f"[INFO] Globals and extern declarations written to {C_file} and {header_file}") #============================== Generate VCU RX Function ==============================# def generate_vcu_rx_function_with_factors(signals, channel, output_file): if not signals: print("[ERROR] No signals to generate VCU RX functions for.") return # Initialize the header of the C file c_file_content = """ #include "can.h" // Declare Factors and Offsets for signals """ # Collect unique Factors and Offsets factors_offsets = {} for message_name, message_info in signals.items(): for signal in message_info["Signals"]: factor_name = f"Factor_{str(signal['Factor']).replace('.', '_')}" offset_name = f"Offset_m_{abs(signal['Offset']):.0f}" if signal['Factor'] != 1: factors_offsets[factor_name] = signal['Factor'] if signal['Offset'] != 0: factors_offsets[offset_name] = signal['Offset'] # Add Factor and Offset variable declarations for name, value in factors_offsets.items(): c_file_content += f"const float {name} = {value};\n" # Add a newline for separation c_file_content += "\n" # Iterate through all messages in the signals for message_name, message_info in signals.items(): # Define the temporary struct temp_struct_name = f"{message_name}_temp" # Check if any signal in the message has RX ECU name as VCU has_vcu_signal = any(signal["RX ECU name"] == "VCU" for signal in message_info["Signals"]) if not has_vcu_signal: continue # Skip this message if no signal has RX ECU name as VCU c_file_content += f""" void Receive_{message_name}_{message_info['ID']}(void) {{ struct {{ """ # Add temporary variables to the struct for signal in message_info["Signals"]: if signal["RX ECU name"] != "VCU": continue # RX ECU name이 VCU가 아닌 경우 건너뜁니다. if signal["Sign"] == "-": signal_type = "signed int" elif signal["Sign"] == "+": signal_type = "unsigned int" c_file_content += f" {signal_type} {signal['Signal name']}_temp : {signal['Length']};\n" c_file_content += f" }} {temp_struct_name};\n\n" # Add temp assignments for signal in message_info["Signals"]: if signal["RX ECU name"] != "VCU": continue # RX ECU name이 VCU가 아닌 경우 건너뜁니다. start_byte = signal["msb"] // 8 start_bit = signal["msb"] % 8 signal_length = signal["Length"] if signal["Byte order"] == 0: # Motorola (Big Endian) lsb = signal["msb"] + 8*(signal_length // 8) - (signal_length % 8 - 1) if signal_length > 8: # Handle multi-byte signals shift_expr = f"(CAN_ch[{channel}].rx.buf[{start_byte}] << shift{7 - start_bit})" multi_byte_expr = [] for i in range((signal_length + 7) // 8): byte_shift = (7 - start_bit) + (i * 8) if i == 0: multi_byte_expr.append(f"(CAN_ch[{channel}].rx.buf[{start_byte + i}] << shift{7 - start_bit})") else: multi_byte_expr.append(f"(CAN_ch[{channel}].rx.buf[{start_byte + i}] >> shift{byte_shift})") shift_expr = " | ".join(multi_byte_expr) else : shift_expr = f"(CAN_ch[{channel}].rx.buf[{start_byte}] >> shift{lsb % 8})" else: # Intel (Little Endian) shift_expr = f"(CAN_ch[{channel}].rx.buf[{start_byte}] >> shift{start_bit})" if signal_length > 8: # Handle multi-byte signals multi_byte_expr = [] for i in range((signal_length + 7) // 8): byte_shift = i * 8 if i == 0: multi_byte_expr.append(f"(CAN_ch[{channel}].rx.buf[{start_byte + i}] >> shift{start_bit})") else: multi_byte_expr.append(f"(CAN_ch[{channel}].rx.buf[{start_byte + i}] << shift{byte_shift})") shift_expr = " | ".join(multi_byte_expr) c_file_content += f" {temp_struct_name}.{signal['Signal name']}_temp = ({shift_expr}) & _{signal_length}bit;\n" c_file_content += "\n" # Assign to final ECU variables for signal in message_info["Signals"]: if signal["RX ECU name"] != "VCU": continue # RX ECU name이 VCU가 아닌 경우 건너뜁니다. factor_name = f"Factor_{str(signal['Factor']).replace('.', '_')}" offset_name = f"Offset_m_{abs(signal['Offset']):.0f}" factor = f" * {factor_name}" if signal['Factor'] != 1 else "" offset = f" + {offset_name}" if signal['Offset'] != 0 else "" temp_var = f"{temp_struct_name}.{signal['Signal name']}_temp" c_file_content += f" VCU.RX.{message_name}_{message_info['ID']}.{signal['Signal name']} = ({temp_var}{factor}){offset};\n" c_file_content += "}\n" # Write the generated code to a single C file with open(output_file, "w") as c_file: c_file.write(c_file_content) print(f"Generated RX function C file with Factors and Offsets: {output_file}") #============================== Generate Input Function ==============================# def generate_input_functions(signals, channel, output_file): if not signals: print("[WARNING] No signals to generate Input functions for.") return with open(output_file, 'w') as f: for message_name, message_info in signals.items(): hex_id = message_info["ID"] function_name = f"void Input_Data_Set_{message_name}_CH{channel}_{hex_id}(void)" f.write(f"{function_name}\n{{\n") for signal in message_info["Signals"]: f.write(f" GV_{signal['Signal name']} = VCU.RX.CH{channel}_RX_{message_name}_{hex_id}.{signal['Signal name']};\n") f.write("}\n\n") print(f"[INFO] Input functions written to {output_file}") #============================== Generate Initialization ==============================# def generate_initialization(signals, channel, output_file): if not signals: print("[WARNING] No signals to generate initialization for.") return with open(output_file, 'w') as f: f.write("void VCU_Data_Init(void)\n{\n") for message_name, message_info in signals.items(): hex_id = message_info["ID"] struct_prefix = f"VCU.RX.CH{channel}_RX_{message_name}_{hex_id}" for signal in message_info["Signals"]: if signal["Offset"] != 0.0: if signal["Length"] <= 32: f.write(f" {struct_prefix}.{signal['Signal name']} = {signal['Offset']};\n") else: f.write(f" {struct_prefix}.{signal['Signal name']} = {signal['Offset']}f;\n") else: if signal["Length"] <= 32: f.write(f" {struct_prefix}.{signal['Signal name']} = 0;\n") else: f.write(f" {struct_prefix}.{signal['Signal name']} = 0.0f;\n") f.write("\n") f.write("}\n") print(f"[INFO] Initialization function written to {output_file}") #============================== Main ==============================# if __name__ == "__main__": dbc_file_path = sys.argv[1] output_dir = sys.argv[2] channel = sys.argv[3] if channel == "CH0": channel = 0 elif channel == "CH1": channel = 1 elif channel == "CH2": channel = 2 elif channel == "CH3": channel = 3 elif channel == "CH4": channel = 4 elif channel == "CH5": channel = 5 else: print("[ERROR] Invalid channel specified. Must be one of CH0, CH1, CH2, CH3, CH4, or CH5.") output_globals_C_file = f"{output_dir}/generated_RX_globals.c" output_globals_header_file = f"{output_dir}/generated_RX_globals.h" output_c_file = f"{output_dir}/generated_RX_receive.c" output_input_file = f"{output_dir}/generated_RX_input.c" output_initialization_file = f"{output_dir}/generated_RX_init.c" signals = load_dbc_file(dbc_file_path) generate_globals(signals, output_globals_C_file, output_globals_header_file) generate_vcu_rx_function_with_factors(signals, channel, output_c_file) generate_input_functions(signals, channel, output_input_file) generate_initialization(signals, channel, output_initialization_file)