import sys import json from DBC_Converter_Data_Parsing import load_dbc_file #============================== Generate TX Globals ==============================# def generate_tx_globals(signals, output_file, header_file): if not signals: print("[WARNING] No signals to generate TX globals for.") return with open(output_file, 'w') as f: 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_TX_GLOBALS_H\n") f.write("#define GENERATED_TX_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_TX_GLOBALS_H\n") print(f"[INFO] TX globals written to {output_file} and {header_file}") #============================== Generate TX Functions ==============================# def generate_tx_functions(signals, channel, output_file): if not signals: print("[WARNING] No signals to generate TX 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 Output_Data_Set_{message_name}_CH{channel}_{hex_id}(void)" f.write(f"{function_name}\n{{\n") for signal in message_info["Signals"]: factor_str = f"/ {signal['Factor']}" if signal["Factor"] != 1.0 else "" offset_str = f"- {signal['Offset']}" if signal["Offset"] != 0.0 else "" mask = f"_{signal['Length']}bit" f.write( f" VCU.TX.CH{channel}_{message_name}_{hex_id}.{signal['Signal name']} = " f"(int)((GV_{signal['Signal name']} {offset_str}) {factor_str}) & {mask};\n" ) f.write("}\n\n") print(f"[INFO] TX functions written to {output_file}") #============================== Generate TX Initialization ==============================# def generate_tx_initialization(signals, channel, output_file): if not signals: print("[WARNING] No TX signals found for initialization generation.") return with open(output_file, 'w') as f: f.write("void Initialize_TX_Signals(void)\n{\n") for message_name, message_info in signals.items(): hex_id = message_info["ID"] f.write(f" // {message_name} ({hex_id})\n") for signal in message_info["Signals"]: f.write(f" VCU.TX.CH{channel}_{message_name}_{hex_id}.{signal['Signal name']} = 0;\n") f.write("\n") f.write("}\n") print(f"[INFO] TX initialization function written to {output_file}") #============================== Generate TX Enum ==============================# def generate_tx_enum(signals, channel, output_file, cycle): if not signals: print("[WARNING] No TX messages found for enum generation.") return with open(output_file, 'w') as f: f.write("typedef enum {\n") for idx, message_name in enumerate(signals.keys()): enum_name = f"VCU_CH{channel}_TX_{message_name}_{cycle}" f.write(f" {enum_name} = {idx},\n") f.write(f" NUMBER_OF_VCU_CH{channel}_TX_MESSAGE,\n") f.write(f"} VCU_CH{channel}_TX;\n") print(f"[INFO] TX enum written to {output_file}") #============================== Generate TX C File ==============================# def generate_vcu_can_transmit_single_c_file(signals, channel, output_file): if not signals: print("[ERROR] No signals to generate VCU CAN transmit functions for.") return # Initialize the header of the C file c_file_content = """ #include "can.h" """ # Iterate through all messages in the signals for message_name, message_info in signals.items(): # 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 # Add the function definition for the message c_file_content += f""" void Transmit_{message_name}_CH{channel}_{message_info['ID']}(void) {{ """ # Iterate through signals and generate bit-packing logic buffer_assignments = [""] * message_info["DLC"] for signal in message_info["Signals"]: start_byte = signal["msb"] // 8 start_bit = signal["msb"] % 8 signal_length = signal["Length"] signal_name = f"VCU.TX.CH{channel}_{message_name}_{message_info['ID']}.{signal['Signal name']}" # Handle 8-bit chunks while signal_length > 0: bits_in_byte = min(8 - start_bit, signal_length) shift_amount = (signal["Length"] - signal_length) if signal["Byte order"] == 0: # Motorola (Big Endian) if bits_in_byte == 8: shift_expr = f"({signal_name} >> shift{shift_amount})" else: shift_expr = f"({signal_name} << shift{start_bit})" if start_bit > 0 else f"({signal_name} >> shift{shift_amount})" else: # Intel (Little Endian) shift_expr = f"({signal_name} >> shift{shift_amount}) << shift{start_bit}" if start_bit > 0 else f"({signal_name} >> shift{shift_amount})" buffer_index = start_byte # Ensure buffer_index is within the range of buffer_assignments if buffer_index >= len(buffer_assignments): print(f"[ERROR] Buffer index {buffer_index} out of range for message {message_name}") break # Add to the buffer assignments if buffer_assignments[buffer_index]: buffer_assignments[buffer_index] += f"\n | {shift_expr}" else: buffer_assignments[buffer_index] = f"{shift_expr}" # Update pointers signal_length -= bits_in_byte start_byte += 1 start_bit = 0 # Write buffer assignments to the function for i, assignment in enumerate(buffer_assignments): if assignment: c_file_content += f" CAN_ch[{channel}].tx.buf[{i}] = ({assignment}) & _8bit;\n" # Add the send function call c_file_content += f""" can_send_config(CAN_INST_0, g_messageObjectConf_VCU_{channel}ch_TX[VCU_CH{channel}_TX_{message_name}_10ms]); }} """ # 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 C file with all VCU messages: {output_file}") #============================== Main ==============================# if __name__ == "__main__": dbc_file_path = sys.argv[1] output_dir = sys.argv[2] channel = sys.argv[3] channel = json.loads(channel) if list(channel.values())[-1] == "CH0": channel = 0 elif list(channel.values())[-1] == "CH1": channel = 1 elif list(channel.values())[-1] == "CH2": channel = 2 elif list(channel.values())[-1] == "CH3": channel = 3 elif list(channel.values())[-1] == "CH4": channel = 4 elif list(channel.values())[-1] == "CH5": channel = 5 else: print("[ERROR] Invalid channel specified. Must be one of CH0, CH1, CH2, CH3, CH4, or CH5.") output_structs_file = f"{output_dir}/generated_TX_structs.h" output_globals_file = f"{output_dir}/generated_TX_globals.c" output_globals_header = f"{output_dir}/generated_TX_globals.h" output_tx_functions_file = f"{output_dir}/generated_TX_output.c" output_tx_initialization = f"{output_dir}/generated_TX_init.c" output_enum_file = f"{output_dir}/generated_TX_enum.h" output_c_file = f"{output_dir}/generated_TX_transmit.c" # Replace with your desired output file name cycle_time = "10ms" signals = load_dbc_file(dbc_file_path) if signals is None: print(f"[ERROR] Failed to load DBC file: {dbc_file_path}") sys.exit(1) generate_tx_globals(signals, output_globals_file, output_globals_header) generate_tx_functions(signals, channel, output_tx_functions_file) generate_tx_initialization(signals, channel, output_tx_initialization) generate_tx_enum(signals, channel, output_enum_file, cycle_time) generate_vcu_can_transmit_single_c_file(signals, channel, output_c_file)