function define_swarm_buses(N_VEH, L)
%DEFINE_SWARM_BUSES  Crea i Simulink.Bus per architettura swarm decentralizzata.
%
% Crea nel base workspace:
%
%   VehicleState
%   ValuesBus
%
%   PathTracker
%   SpeedGovernor
%   PlannerPath
%
%   PlannerOutBusSingle
%       id1..idN, ciascuno = PlannerPath
%
%   PlannerOutBusGlobal
%       com_from_1..com_from_N, ciascuno = PlannerOutBusSingle
%
%   AccelSterzo

%% --- 1. VehicleState
VS = Simulink.Bus;
VS.Elements = [ ...
    mkElem('x',          1, 'double'), ...
    mkElem('y',          1, 'double'), ...
    mkElem('psi',        1, 'double'), ...
    mkElem('vel_totale', 1, 'double') ...
];
assignin('base', 'VehicleState', VS);
%% --- 2. WheelData
WD = Simulink.Bus;
WD.Elements = [ ...
    mkElem('slip_vect',  4, 'double'), ...
    mkElem('w_r_vect',   4, 'double'), ...
    mkElem('alpha_wheel',4, 'double'), ...
    mkElem('delta_vect', 4, 'double'), ...
    mkElem('u_cr',       4, 'double'), ...
    mkElem('v_cr',       4, 'double'), ...
    mkElem('Fx',         4, 'double'), ...
    mkElem('Fy',         4, 'double'), ...
    mkElem('Cm',         4, 'double'), ...
    mkElem('Fz',         4, 'double') ...
];
assignin('base', 'WheelData', WD);
%% --- 3. ValuesBus: id1..idN, ciascuno = VehicleState
VB = Simulink.Bus;
elems = repmat(Simulink.BusElement, 1, N_VEH);

for k = 1:N_VEH
    elems(k) = mkElem(sprintf('id%d', k), 1, 'Bus: VehicleState');
end

VB.Elements = elems;
assignin('base', 'ValuesBus', VB);

%% --- 4. PathTracker
PT = Simulink.Bus;
PT.Elements = [ ...
    mkElem('path_x', [L 1], 'double'), ...
    mkElem('path_y', [L 1], 'double'), ...
    mkElem('n',       1,    'double') ...
];
assignin('base', 'PathTracker', PT);

%% --- 5. SpeedGovernor
SG = Simulink.Bus;
SG.Elements = [ ...
    mkElem('mu_next',       1, 'double'), ...
    mkElem('unknown_ratio', 1, 'double') ...
];
assignin('base', 'SpeedGovernor', SG);

%% --- 6. PlannerPath: dati destinati a un singolo veicolo
PP = Simulink.Bus;
PP.Elements = [ ...
    mkElem('to_path_tracker',   1, 'Bus: PathTracker'), ...
    mkElem('to_speed_governor', 1, 'Bus: SpeedGovernor') ...
];
assignin('base', 'PlannerPath', PP);

%% --- 7. PlannerOutBusSingle
% Messaggio prodotto da UN Agent.
% Contiene id1..idN, cioè i dati destinati a ciascun veicolo.
POS = Simulink.Bus;
elems = repmat(Simulink.BusElement, 1, N_VEH);

for k = 1:N_VEH
    elems(k) = mkElem(sprintf('id%d', k), 1, 'Bus: PlannerPath');
end

POS.Elements = elems;
assignin('base', 'PlannerOutBusSingle', POS);

%% --- 8. PlannerOutBusGlobal
% Bus globale raccolto nel top model.
% Contiene com_from_1..com_from_N, cioè i messaggi prodotti dai vari Agent.
POG = Simulink.Bus;
elems = repmat(Simulink.BusElement, 1, N_VEH);

for k = 1:N_VEH
    elems(k) = mkElem(sprintf('com_from_%d', k), 1, 'Bus: PlannerOutBusSingle');
end

POG.Elements = elems;
assignin('base', 'PlannerOutBusGlobal', POG);

%% --- 9. AccelSterzo
AS = Simulink.Bus;
AS.Elements = [ ...
    mkElem('Out_alpha',    1, 'double'), ...
    mkElem('delta_sterzo', 1, 'double') ...
];
assignin('base', 'AccelSterzo', AS);
%% -- 10. PlotVeicolo
PV=Simulink.Bus;
PV.Elements=[mkElem('values',1,'Bus: VehicleState'), ...
    mkElem('AccelSterzo',1,'Bus: AccelSterzo'),mkElem('WheelData',1,'Bus: WheelData'), ...
    mkElem('heading_err',1,'double'), mkElem('psi_err',1,'double'), ...
    mkElem('obstacle_brake_flag',1,'double'),...
    mkElem('hold_flag',1,'double'), ...
    mkElem('mu_next',1,'double'), ...
    mkElem('unknown_ratio',1,'double'), ...
    mkElem('ABS_flag',4,'uint8'), mkElem('v_ref_raw',1,'double'),mkElem('v_ref_filtered',1,'double')];
assignin('base','PlotVeicolo',PV);
%% --- 11. PlotSingle
PLS=Simulink.Bus;
PLS.Elements=[mkElem('plotveicolo',1,'Bus: PlotVeicolo'),mkElem('ranking',N_VEH,'double'),mkElem('pct_known',1,'double')];
assignin('base','PlotSingle',PLS);
%% --- 12. PlotGlobal
PLG=Simulink.Bus;
elems2 = repmat(Simulink.BusElement, 1, N_VEH);

for k = 1:N_VEH
    elems2(k) = mkElem(sprintf('pl_%d', k), 1, 'Bus: PlotSingle');
end
PLG.Elements = elems2;
assignin('base', 'PlotGlobal', PLG);

%% --- 10. Log
% fprintf(['[bus] Creati:\n', ...
%          '  VehicleState\n', ...
%          '  ValuesBus(id1..id%d)\n', ...
%          '  PathTracker\n', ...
%          '  SpeedGovernor\n', ...
%          '  PlannerPath\n', ...
%          '  PlannerOutBusSingle(id1..id%d)\n', ...
%          '  PlannerOutBusGlobal(com_from_1..com_from_%d)\n', ...
%          '  AccelSterzo\n'], ...
%          N_VEH, N_VEH, N_VEH);

end


function e = mkElem(name, dims, dtype)
%MKELEM  Crea un Simulink.BusElement con i parametri minimi.

e = Simulink.BusElement;
e.Name       = name;
e.Dimensions = dims;
e.DataType   = dtype;
e.Complexity = 'real';

end