%% CARSIM_AUTO_CONFIG - 自动配置CarSim倒车入库仿真场景
% 兼容版本：MATLAB R2016b + CarSim 2019.0
% 功能：通过MATLAB自动化配置CarSim参数
%
% 作者：LiHongwei
% 日期：2026-05-29

clear; clc;

fprintf('========================================\n');
fprintf('  CarSim 2019.0 自动配置工具\n');
fprintf('========================================\n\n');

%% ==================== 配置参数 ====================

% 道路参数
road.length = 50;              % 道路长度 [m]
road.width = 6;                % 道路宽度 [m]
road.num_lanes = 2;            % 车道数
road.lane_width = 3;           % 单车道宽度 [m]

% 车位参数
parking.spot_length = 5;       % 车位长度 [m]
parking.spot_width = 2.5;      % 车位宽度 [m]
parking.num_spots = 10;        % 车位数量
parking.target_spot = 5;       % 目标车位（空置）
parking.occupancy = [1, 1, 1, 1, 0, 1, 1, 1, 1, 1]; % 车位占用情况

% 车辆初始条件
vehicle.init_x = 45;           % 初始X位置 [m]
vehicle.init_y = 3;            % 初始Y位置 [m]
vehicle.init_yaw = 0;          % 初始航向角 [deg]
vehicle.init_speed = 5;        % 初始速度 [km/h]
vehicle.init_gear = 1;         % 初始档位 (D1)

% 仿真参数
sim.total_time = 60;           % 总仿真时间 [s]
sim.approach_time = 10;        % 接近阶段时间 [s]
sim.prepare_time = 2;          % 准备阶段时间 [s]
sim.reverse_time = 38;         % 倒车阶段时间 [s]

fprintf('[1/6] 配置参数加载完成\n');

%% ==================== 生成CarSim数据集文件 ====================

% CarSim数据集文件路径
carsim_dataset_file = 'Parking_Reversing.cfg';

% 生成配置文件
generate_carsim_dataset(carsim_dataset_file, road, parking, vehicle, sim);

fprintf('[2/6] CarSim数据集文件生成完成: %s\n', carsim_dataset_file);

%% ==================== 生成道路配置文件 ====================

% 道路几何文件
road_geom_file = 'road_geometry.cfg';
generate_road_geometry(road_geom_file, road);

fprintf('[3/6] 道路配置文件生成完成: %s\n', road_geom_file);

%% ==================== 生成车位障碍物文件 ====================

% 障碍物配置文件
obstacles_file = 'parking_obstacles.cfg';
generate_parking_obstacles(obstacles_file, parking);

fprintf('[4/6] 车位障碍物文件生成完成: %s\n', obstacles_file);

%% ==================== 生成停放车辆文件 ====================

% 停放车辆配置文件
static_vehicles_file = 'static_vehicles.cfg';
generate_static_vehicles(static_vehicles_file, parking);

fprintf('[5/6] 停放车辆文件生成完成: %s\n', static_vehicles_file);

%% ==================== 生成Simulink接口配置文件 ====================

% Simulink接口文件
simulink_config_file = 'simulink_interface.cfg';
generate_simulink_interface(simulink_config_file);

fprintf('[6/6] Simulink接口配置文件生成完成: %s\n', simulink_config_file);

%% ==================== 生成导入脚本 ====================

% 生成一键导入MATLAB脚本
import_script = 'import_to_carsim.m';
generate_import_script(import_script, carsim_dataset_file, road_geom_file, ...
    obstacles_file, static_vehicles_file, simulink_config_file);

fprintf('\n========================================\n');
fprintf('  所有配置文件生成完成！\n');
fprintf('========================================\n\n');

fprintf('生成的文件列表：\n');
fprintf('  1. %s (主数据集)\n', carsim_dataset_file);
fprintf('  2. %s (道路几何)\n', road_geom_file);
fprintf('  3. %s (车位障碍物)\n', obstacles_file);
fprintf('  4. %s (停放车辆)\n', static_vehicles_file);
fprintf('  5. %s (Simulink接口)\n', simulink_config_file);
fprintf('  6. %s (导入脚本)\n', import_script);

fprintf('\n使用方法：\n');
fprintf('  1. 打开CarSim 2019.0\n');
fprintf('  2. 运行 import_to_carsim.m\n');
fprintf('  3. 或手动导入上述.cfg文件\n');

%% ==================== 辅助函数 ====================

function generate_carsim_dataset(filename, road, parking, vehicle, sim)
% 生成CarSim主数据集配置文件

    fid = fopen(filename, 'w');

    fprintf(fid, '# CarSim Dataset Configuration\n');
    fprintf(fid, '# Parking Reversing Simulation\n');
    fprintf(fid, '# Generated by MATLAB\n');
    fprintf(fid, '# Date: %s\n\n', datestr(now));

    fprintf(fid, '[DATASET]\n');
    fprintf(fid, 'Name=Parking_Reversing\n');
    fprintf(fid, 'Description=倒车入库仿真场景\n');
    fprintf(fid, 'Template=Sedan\n\n');

    fprintf(fid, '[ROAD]\n');
    fprintf(fid, 'Length=%.1f\n', road.length);
    fprintf(fid, 'Width=%.1f\n', road.width);
    fprintf(fid, 'NumLanes=%d\n', road.num_lanes);
    fprintf(fid, 'LaneWidth=%.1f\n', road.lane_width);
    fprintf(fid, 'Surface=DryAsphalt\n');
    fprintf(fid, 'Friction=0.85\n\n');

    fprintf(fid, '[PARKING]\n');
    fprintf(fid, 'SpotLength=%.1f\n', parking.spot_length);
    fprintf(fid, 'SpotWidth=%.1f\n', parking.spot_width);
    fprintf(fid, 'NumSpots=%d\n', parking.num_spots);
    fprintf(fid, 'TargetSpot=%d\n', parking.target_spot);
    fprintf(fid, 'Occupancy=%s\n\n', num2str(parking.occupancy));

    fprintf(fid, '[VEHICLE_INITIAL]\n');
    fprintf(fid, 'X=%.1f\n', vehicle.init_x);
    fprintf(fid, 'Y=%.1f\n', vehicle.init_y);
    fprintf(fid, 'Yaw=%.1f\n', vehicle.init_yaw);
    fprintf(fid, 'Speed=%.1f\n', vehicle.init_speed);
    fprintf(fid, 'Gear=%d\n\n', vehicle.init_gear);

    fprintf(fid, '[SIMULATION]\n');
    fprintf(fid, 'TotalTime=%.1f\n', sim.total_time);
    fprintf(fid, 'TimeStep=0.001\n');
    fprintf(fid, 'Solver=FixedStep\n');
    fprintf(fid, 'OutputRate=100\n\n');

    fprintf(fid, '[EVENTS]\n');
    fprintf(fid, 'Event1=Approach,0,%.1f,5,D1\n', sim.approach_time);
    fprintf(fid, 'Event2=Prepare,%.1f,%.1f,0,N\n', ...
        sim.approach_time, sim.approach_time + sim.prepare_time);
    fprintf(fid, 'Event3=Reverse,%.1f,%.1f,-2,R\n', ...
        sim.approach_time + sim.prepare_time, sim.total_time);

    fclose(fid);

end

function generate_road_geometry(filename, road)
% 生成道路几何配置文件

    fid = fopen(filename, 'w');

    fprintf(fid, '# Road Geometry Configuration\n');
    fprintf(fid, '# Generated by MATLAB\n\n');

    fprintf(fid, '[ROAD_GEOMETRY]\n');
    fprintf(fid, 'Type=FlatRoad\n');
    fprintf(fid, 'Length=%.1f\n', road.length);
    fprintf(fid, 'Width=%.1f\n', road.width);
    fprintf(fid, 'NumLanes=%d\n', road.num_lanes);
    fprintf(fid, 'LaneWidth=%.1f\n', road.lane_width);
    fprintf(fid, 'SurfaceType=DryAsphalt\n');
    fprintf(fid, 'FrictionCoefficient=0.85\n');
    fprintf(fid, 'Roughness=Smooth\n\n');

    fprintf(fid, '[CROSS_SECTION]\n');
    fprintf(fid, 'LeftWidth=%.1f\n', road.width / 2);
    fprintf(fid, 'RightWidth=%.1f\n', road.width / 2);
    fprintf(fid, 'TotalWidth=%.1f\n', road.width);

    fclose(fid);

end

function generate_parking_obstacles(filename, parking)
% 生成车位障碍物配置文件

    fid = fopen(filename, 'w');

    fprintf(fid, '# Parking Spot Obstacles Configuration\n');
    fprintf(fid, '# Generated by MATLAB\n\n');

    fprintf(fid, '[OBSTACLES]\n');
    fprintf(fid, 'NumObstacles=%d\n\n', parking.num_spots * 4); % 每个车位4条边

    obstacle_id = 1;

    for i = 1:parking.num_spots
        % 车位边界坐标
        x_start = (i - 1) * parking.spot_length;
        x_end = i * parking.spot_length;
        y_start = -parking.spot_width;
        y_end = 0;

        fprintf(fid, '[OBSTACLE_%d]\n', obstacle_id);
        fprintf(fid, 'Type=Barrier\n');
        fprintf(fid, 'Length=%.1f\n', parking.spot_length);
        fprintf(fid, 'Width=0.15\n');
        fprintf(fid, 'Height=0.05\n');
        fprintf(fid, 'Color=White\n');
        fprintf(fid, 'X=%.2f\n', (x_start + x_end) / 2);
        fprintf(fid, 'Y=%.2f\n', y_start);
        fprintf(fid, 'Yaw=0\n\n');
        obstacle_id = obstacle_id + 1;

        fprintf(fid, '[OBSTACLE_%d]\n', obstacle_id);
        fprintf(fid, 'Type=Barrier\n');
        fprintf(fid, 'Length=%.1f\n', parking.spot_length);
        fprintf(fid, 'Width=0.15\n');
        fprintf(fid, 'Height=0.05\n');
        fprintf(fid, 'Color=White\n');
        fprintf(fid, 'X=%.2f\n', (x_start + x_end) / 2);
        fprintf(fid, 'Y=%.2f\n', y_end);
        fprintf(fid, 'Yaw=0\n\n');
        obstacle_id = obstacle_id + 1;

        fprintf(fid, '[OBSTACLE_%d]\n', obstacle_id);
        fprintf(fid, 'Type=Barrier\n');
        fprintf(fid, 'Length=%.1f\n', parking.spot_width);
        fprintf(fid, 'Width=0.15\n');
        fprintf(fid, 'Height=0.05\n');
        fprintf(fid, 'Color=White\n');
        fprintf(fid, 'X=%.2f\n', x_start);
        fprintf(fid, 'Y=%.2f\n', (y_start + y_end) / 2);
        fprintf(fid, 'Yaw=90\n\n');
        obstacle_id = obstacle_id + 1;

        fprintf(fid, '[OBSTACLE_%d]\n', obstacle_id);
        fprintf(fid, 'Type=Barrier\n');
        fprintf(fid, 'Length=%.1f\n', parking.spot_width);
        fprintf(fid, 'Width=0.15\n');
        fprintf(fid, 'Height=0.05\n');
        fprintf(fid, 'Color=White\n');
        fprintf(fid, 'X=%.2f\n', x_end);
        fprintf(fid, 'Y=%.2f\n', (y_start + y_end) / 2);
        fprintf(fid, 'Yaw=90\n\n');
        obstacle_id = obstacle_id + 1;
    end

    fclose(fid);

end

function generate_static_vehicles(filename, parking)
% 生成停放车辆配置文件

    fid = fopen(filename, 'w');

    fprintf(fid, '# Static Vehicles Configuration\n');
    fprintf(fid, '# Generated by MATLAB\n\n');

    fprintf(fid, '[STATIC_VEHICLES]\n');
    fprintf(fid, 'NumVehicles=%d\n\n', sum(parking.occupancy));

    vehicle_id = 1;

    for i = 1:parking.num_spots
        if parking.occupancy(i) == 1
            % 车位中心坐标
            x_center = (i - 0.5) * parking.spot_length;
            y_center = -parking.spot_width / 2;

            fprintf(fid, '[VEHICLE_%d]\n', vehicle_id);
            fprintf(fid, 'Type=Sedan\n');
            fprintf(fid, 'Motion=Stationary\n');
            fprintf(fid, 'X=%.2f\n', x_center);
            fprintf(fid, 'Y=%.2f\n', y_center);
            fprintf(fid, 'Yaw=90\n');
            fprintf(fid, 'Speed=0\n\n');

            vehicle_id = vehicle_id + 1;
        end
    end

    fclose(fid);

end

function generate_simulink_interface(filename)
% 生成Simulink接口配置文件

    fid = fopen(filename, 'w');

    fprintf(fid, '# Simulink Interface Configuration\n');
    fprintf(fid, '# Generated by MATLAB\n\n');

    fprintf(fid, '[SIMULINK_INTERFACE]\n');
    fprintf(fid, 'ExportSFunction=1\n');
    fprintf(fid, 'SFunctionName=sf_car_sim\n');
    fprintf(fid, 'OutputFormat=mexw64\n\n');

    fprintf(fid, '[INPUT_CHANNELS]\n');
    fprintf(fid, 'NumInputs=4\n\n');

    fprintf(fid, 'Channel1=IMP_STEER_SW,deg,0\n');
    fprintf(fid, 'Channel2=IMP_PBK_CON,kPa,0\n');
    fprintf(fid, 'Channel3=IMP_THROTTLE,%%,0\n');
    fprintf(fid, 'Channel4=IMP_GEARCHANGE,-,0\n\n');

    fprintf(fid, '[OUTPUT_CHANNELS]\n');
    fprintf(fid, 'NumOutputs=6\n\n');

    fprintf(fid, 'Channel1=XCG,m\n');
    fprintf(fid, 'Channel2=YCG,m\n');
    fprintf(fid, 'Channel3=YAW,rad\n');
    fprintf(fid, 'Channel4=VX,km/h\n');
    fprintf(fid, 'Channel5=VY,km/h\n');
    fprintf(fid, 'Channel6=AVZ,deg/s\n');

    fclose(fid);

end

function generate_import_script(filename, varargin)
% 生成MATLAB导入脚本

    fid = fopen(filename, 'w');

    fprintf(fid, '%% IMPORT_TO_CARSIM - 一键导入配置到CarSim\n');
    fprintf(fid, '%% 兼容版本：MATLAB R2016b + CarSim 2019.0\n');
    fprintf(fid, '%%\n');
    fprintf(fid, '%% 作者：LiHongwei\n');
    fprintf(fid, '%% 日期：%s\n\n', datestr(now));

    fprintf(fid, 'clear; clc;\n\n');

    fprintf(fid, 'fprintf(''========================================\\n'');\n');
    fprintf(fid, 'fprintf(''  CarSim 配置导入工具\\n'');\n');
    fprintf(fid, 'fprintf(''========================================\\n\\n'');\n\n');

    fprintf(fid, '%% 配置文件列表\n');
    fprintf(fid, 'config_files = {\n');
    for i = 1:length(varargin)
        fprintf(fid, '    ''%s''', varargin{i});
        if i < length(varargin)
            fprintf(fid, ',\n');
        else
            fprintf(fid, '\n');
        end
    end
    fprintf(fid, '};\n\n');

    fprintf(fid, '%% 检查文件是否存在\n');
    fprintf(fid, 'fprintf(''检查配置文件...\\n'');\n');
    fprintf(fid, 'all_exist = true;\n');
    fprintf(fid, 'for i = 1:length(config_files)\n');
    fprintf(fid, '    if exist(config_files{i}, ''file'')\n');
    fprintf(fid, '        fprintf(''  ✓ %s\\n'', config_files{i});\n');
    fprintf(fid, '    else\n');
    fprintf(fid, '        fprintf(''  ✗ %s (未找到)\\n'', config_files{i});\n');
    fprintf(fid, '        all_exist = false;\n');
    fprintf(fid, '    end\n');
    fprintf(fid, 'end\n\n');

    fprintf(fid, 'if ~all_exist\n');
    fprintf(fid, '    error(''配置文件不完整，请先运行 carsim_auto_config.m'');\n');
    fprintf(fid, 'end\n\n');

    fprintf(fid, 'fprintf(''\\n所有配置文件检查通过！\\n\\n'');\n\n');

    fprintf(fid, '%% CarSim COM接口连接\n');
    fprintf(fid, 'try\n');
    fprintf(fid, '    fprintf(''连接CarSim...\\n'');\n');
    fprintf(fid, '    % 注意：需要CarSim已打开\n');
    fprintf(fid, '    % carsim = actxserver(''CarSim.Application'');\n');
    fprintf(fid, '    fprintf(''请手动在CarSim中导入以下文件：\\n\\n'');\n');
    fprintf(fid, 'catch\n');
    fprintf(fid, '    fprintf(''无法通过COM连接CarSim，请手动导入\\n\\n'');\n');
    fprintf(fid, 'end\n\n');

    fprintf(fid, '%% 显示导入说明\n');
    fprintf(fid, 'fprintf(''导入步骤：\\n'');\n');
    fprintf(fid, 'fprintf(''1. 打开CarSim 2019.0\\n'');\n');
    fprintf(fid, 'fprintf(''2. File → Import Dataset\\n'');\n');
    fprintf(fid, 'fprintf(''3. 选择 Parking_Reversing.cfg\\n'');\n');
    fprintf(fid, 'fprintf(''4. 确认导入\\n'');\n');
    fprintf(fid, 'fprintf(''\\n'');\n');
    fprintf(fid, 'fprintf(''或使用以下快捷步骤：\\n'');\n');
    fprintf(fid, 'fprintf(''1. 导航到 Procedure → Road Geometry\\n'');\n');
    fprintf(fid, 'fprintf(''2. 导入 road_geometry.cfg\\n'');\n');
    fprintf(fid, 'fprintf(''3. 导航到 Environment → Obstacles\\n'');\n');
    fprintf(fid, 'fprintf(''4. 导入 parking_obstacles.cfg\\n'');\n');
    fprintf(fid, 'fprintf(''5. 导航到 Environment → Moving Objects\\n'');\n');
    fprintf(fid, 'fprintf(''6. 导入 static_vehicles.cfg\\n'');\n');
    fprintf(fid, 'fprintf(''7. 导航到 Settings → Simulink\\n'');\n');
    fprintf(fid, 'fprintf(''8. 导入 simulink_interface.cfg\\n'');\n');
    fprintf(fid, 'fprintf(''\\n'');\n');
    fprintf(fid, 'fprintf(''配置完成！\\n'');\n');

    fclose(fid);

end
