unit dllHauptunit;


interface

uses Vcl.Dialogs, sysutils, math,
     AntriebsKonstanten, FahrleitungsTypen;

   // alle Einheiten in SI (m, N, m/s, kg, s)

   // die Funktion sollte eine Messagebox starten, die als kurze Doku zur Funktion
   // der dll für den Fahrzeugbauer liefert
   procedure Info; stdcall;

   // die dll kann mehrere Varianten enthalten, es muss mindestens 1 zurückgegeben werden
   function AnzahlVarianten:Word; stdcall;

   // Für jede Variante soll ein kurzer String als Beschreibung zurückgegeben werden
   // Die strings werden im Fahrzeugeditor in die Combobox gefüllt
   // index beginnt bei 0 für die 1. Variante
   function VariantenName(index:integer):PWideChar; stdcall;

   // Diese Funktion wird beim Start der Fahrt einmal aufgerufen, um der dll
   // mitzuteilen, welche der Varianten berechnet werden soll
   // index beginnt bei 0 für die 1. Variante
   // Rückgabe ist eine Adresse, über die die dll bei mehrfacher Verwendung erkennen
   // kann, welche Instanz gerade gefragt ist. Der hier zurückgegebene Wert wird
   // von Zusi bei allen Aufrufen als "Instanz" wieder übergeben
   function VarianteAktivieren(index:integer):Pointer; stdcall;

   // Antriebstyp gemäß TCP-Doku 0002 000A 008E 0001 0025 0001
   function LeseAntriebstyp(Instanz:Pointer):byte; stdcall;

   // ruft der Sim einmal pro Rechenschritt für das selbstgefahrene Fahrzeug und
   // für Fahrzeuge im Mehrfachtraktionsmodus im selbstgefahrenen Zug auf,
   // um die Führerstandsbedienung zu übertragen
   procedure Bedienung(Instanz:Pointer; AntriebsRenderModus:TAntriebsRenderModus; var Prot:TProtokollFst; sp:single); stdcall;

   // ruft der Sim einmal pro Rechenschritt auf, dort sollen die Berechnungen erfolgen
   // wird nur für das selbstgefahrene Fahrzeug und für Fahrzeuge im
   // Mehrfachtraktionsmodus im selbstgefahrenen Zug aufgerufen
   // HSGesperrt teilt der dll mit, ob der Antrieb z.B. über einen Client gesperrt ist
   procedure Berechnung(Instanz:Pointer; dt:double; AntriebsRenderModus:TAntriebsRenderModus; var Mehrfachtraktionsdaten:TMehrfachtraktionsdaten; HSGesperrt:Boolean); stdcall;

   // das wird für Fahrzeuge einmal pro Rechenschritt aufgerufen, die im eigenen
   // Zug im Modus "eigener Tf" fahren und für alle Fahrzeuge im Autopilotmodus
   // es muss hier eine vereinfachte, schnelle Berechnung durchgeführt werden
   // komplexe Rechenmanöver können die Performance beeinflussen, da sehe viele Züge
   // mit diesem Modus im fahrplan unterwegs sein können
   procedure VorspanntraktionsdatenSetzen(Instanz:Pointer; sp, SollLeistungNormiert:single); stdcall;

   // wird vom Sim aufgerufen, wenn ein Nullstellungszwang durch das Antriebssystem
   // erfolgen muss
   procedure Nullstellungszwang(Instanz:Pointer); stdcall;

   // wird vom Sim aufgerufen, wenn sich der Modus des HS ändern soll
   // modus:  0: HS ein, 1: HS aus, 2: Spannung frisch an, 3: HS frisch ein
   procedure SetzeHauptschalterzustand(Instanz:Pointer; modus:Byte); stdcall;

   // die bei der angegebenen Geschwindigkeit max. mögliche Zugkraft
   function LeseMaxAntriebskraft(Instanz:Pointer; spAkt:single):single; stdcall;

   // div. Fahrgrößen
   function LeseAntriebskraft(Instanz:Pointer):single; stdcall;
   function LeseAntriebskraftSollNormiert(Instanz:Pointer):single; stdcall;
   function LeseOberstrom(Instanz:Pointer):single; stdcall;
   function LeseMotorstrom(Instanz:Pointer):single; stdcall;
   function LeseMotorspannung(Instanz:Pointer):single; stdcall;
   function LeseAchsen(Instanz:Pointer):integer; stdcall;
   function LeseSollZugkraft(Instanz:Pointer):single; stdcall;
   function LeseMotordrehzahl(Instanz:Pointer):single; stdcall;
   function LeseMotormoment(Instanz:Pointer):single; stdcall;
   function LeseMotorlast(Instanz:Pointer):single; stdcall;
   function LeseFahrstufe(Instanz:Pointer):single; stdcall;

   // C-Druck für Druckluftergänzungsbremse o.ä. soll Druckluft-Bremse überstimmen
   // -1 keine Vorgabe
   function LeseZylSolldruck(Instanz:Pointer):single; stdcall;

   // muss true zurückgeben, wenn das Schaltwerk auf 0 steht
   function PruefeFahrstufe0(Instanz:Pointer):Boolean; stdcall;

   // muss true zurückgeben, wenn aus Sicht des Antriebsmodells ein
   // Nullstellungszwang aktiv ist
   function NullstellungszwangAktiv(Instanz:Pointer):Boolean; stdcall;

   // muss true zurückgeben, wenn aus Sicht des Antriebsmodells eine
   // Hauptschalterauslösung nötig ist wegen unpassender Fahrleitungsspannung
   // Spannungsfaktor ist 1, wenn die Fahrleitungsspannung genau dem Sollwert entspricht
   function HauptschalterWgOLEnde(Instanz:Pointer; FahrlTyp:TFahrleitungstyp; Spannungsfaktor:single):Boolean; stdcall;

   // muss true zurückgeben, wenn aus Sicht des Antriebsmodells eine
   // Hauptschalterauslösung wg. Oberstromüberschreitung nötig ist.
   // für diesen Antrieb muss sich die dll selbst um die Auswirkungen kümmern
   // Die Funktion teilt das hier nur z.B. den anderen Einheiten einer Mehrfachtraktion mit
   function HauptschalterWgOberstrom(Instanz:Pointer):Boolean; stdcall;

   // Angabe gemäß Doku zu Führerstands-ID x0013
   function Hauptschalterstatus(Instanz:Pointer):Byte; stdcall;

//   function Zugstatus(FzgNode:TTreenode):byte; stdcall;

   // Zustand angeben für Luftpresser-Steuerung
   function HauptschalterDrin(Instanz:Pointer):Boolean; stdcall;
   function DieselmotorLaeuft(Instanz:Pointer):Boolean; stdcall;

exports
   Info,
   AnzahlVarianten,
   VariantenName,
   VarianteAktivieren,
   LeseAntriebstyp,
   Bedienung,
   Berechnung,
   VorspanntraktionsdatenSetzen,
   Nullstellungszwang,
   SetzeHauptschalterzustand,
   LeseMaxAntriebskraft,
   LeseAntriebskraft,
   LeseAntriebskraftSollNormiert,
   LeseOberstrom,
   LeseMotorstrom,
   LeseMotorspannung,
   LeseAchsen,
   LeseSollZugkraft,
   LeseMotordrehzahl,
   LeseMotormoment,
   LeseMotorlast,
   LeseFahrstufe,
   LeseZylSolldruck,
   PruefeFahrstufe0,
   NullstellungszwangAktiv,
   HauptschalterWgOLEnde,
   HauptschalterWgOberstrom,
   Hauptschalterstatus,
//   Zugstatus,
   HauptschalterDrin,
   DieselmotorLaeuft;

type
  TNachlaufsteuerung = class
  strict private
    //"Konstanten"
    FAnzahlSchaltstufen:integer;
    FSchaltwerkGeschwAuf,
    FSchaltwerkGeschwAb:single; //Stufen/sec

    // Aktuelle Zustände
    FZielstufe:integer;
    FStufeAktuellFloat:double;
  public
    constructor Create;
    procedure Berechnen(dt:double);
    function Stufe:integer;
    procedure SetzeZiel(Stufe:integer);
    property Anzahlstufen:integer read FAnzahlSchaltstufen;
  end;

  TKennfeldpunkt = record
    Geschw:single;
    Kraft:single;
  end;

  TKennlinie = class
  protected
    //"Konstanten"
    Punkte:array of TKennfeldpunkt;
  public
    constructor Create;
    function WertAblesen(Geschw:single):single;
  end;


  TdllBasisfunktion = class
  private
  protected
    FVarianteAktuell:integer;
    FZugkraftAktuell:single;
    FNachlaufsteuerung:TNachlaufsteuerung;
    FKraftkennlinie:TKennlinie;
    Fsp:single;
    FHauptschalter:byte;
  public
    constructor Create;
    destructor Destroy; override;
    procedure VarianteAktivieren(index:integer); virtual;
    function LeseAntriebstyp:Byte; virtual; abstract;
    procedure Nullstellungszwang; virtual;
    procedure Bedienung(AntriebsRenderModus:TAntriebsRenderModus; var Prot:TProtokollFst; sp:single); virtual;
    procedure Berechnung(dt:double; AntriebsRenderModus:TAntriebsRenderModus; var Mehrfachtraktionsdaten:TMehrfachtraktionsdaten; HSGesperrt:Boolean); virtual;
    procedure SetzeHauptschalterzustand(modus:Byte); virtual;
    procedure VorspanntraktionsdatenSetzen(sp, SollLeistungNormiert:single); virtual;
    function LeseMaxAntriebskraft(spAkt:single):single; virtual;
    function LeseAntriebskraft:single; virtual;
    function LeseAntriebskraftSollNormiert:single; virtual;
    function LeseOberstrom:single; virtual;
    function LeseMotorstrom:single; virtual;
    function LeseMotorspannung:single; virtual;
    function LeseAchsen:integer; virtual;
    function LeseSollZugkraft:single; virtual;
    function LeseMotordrehzahl:single; virtual;
    function LeseMotormoment:single; virtual;
    function LeseMotorlast:single; virtual;
    function LeseFahrstufe:single; virtual;
    function LeseZylSolldruck:single; virtual;
    function PruefeFahrstufe0:Boolean; virtual;
    function NullstellungszwangAktiv:Boolean; virtual;
    function HauptschalterWgOLEnde(FahrlTyp:TFahrleitungstyp; Spannungsfaktor:single):Boolean; virtual;
    function HauptschalterWgOberstrom:Boolean; virtual;
    function Hauptschalterstatus:Byte; virtual;
//    function Zugstatus(FzgNode:TTreenode):byte; virtual;
    function HSDrin:Boolean; virtual;
    function DMLaeuft:Boolean; virtual;
  end;


  TdllAntrieb = class(TdllBasisfunktion)
  public
    function LeseAntriebstyp:Byte; override;
    procedure Bedienung(AntriebsRenderModus:TAntriebsRenderModus; var Prot:TProtokollFst; sp:single); override;
    procedure Berechnung(dt:double; AntriebsRenderModus:TAntriebsRenderModus; var Mehrfachtraktionsdaten:TMehrfachtraktionsdaten; HSGesperrt:Boolean); override;
    function Hauptschalterstatus:Byte; override;
  end;


  TdllBremse = class(TdllBasisfunktion)
  public
    function LeseAntriebstyp:Byte; override;
    procedure Bedienung(AntriebsRenderModus:TAntriebsRenderModus; var Prot:TProtokollFst; sp:single); override;
    procedure Berechnung(dt:double; AntriebsRenderModus:TAntriebsRenderModus; var Mehrfachtraktionsdaten:TMehrfachtraktionsdaten; HSGesperrt:Boolean); override;
  end;

var
  Funktionen:array of TdllBasisfunktion;

implementation

// dll -------------------------------------------------------------------------

procedure Info; stdcall;
begin
  MessageDlg('Demo-Antrieb', mtInformation, [mbOK], 0);
end;

function AnzahlVarianten:Word; stdcall;
begin
  Result:=2;
end;

function VariantenName(index:integer):PWideChar; stdcall;
begin
  if      index=0 then Result:='Test-Antrieb Fahrstufe'
  else if index=1 then Result:='Test-Antrieb Zugkraft'
  else Result:='error';
end;


function VarianteAktivieren(index:integer):Pointer; stdcall;
begin
  // Neue Instanz gefragt
  setlength(Funktionen, length(Funktionen)+1);
  Funktionen[length(Funktionen)-1]:=TdllAntrieb.Create;
  Funktionen[length(Funktionen)-1].VarianteAktivieren(index);
  Result:=Funktionen[length(Funktionen)-1];
end;

function LeseAntriebstyp(Instanz:Pointer):byte; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).LeseAntriebstyp
                  else Result:=0;
end;

procedure VorspanntraktionsdatenSetzen(Instanz:Pointer; sp, SollLeistungNormiert:single); stdcall;
begin
  if Instanz<>nil then TdllBasisfunktion(Instanz).VorspanntraktionsdatenSetzen(sp, SollLeistungNormiert);
end;

procedure Bedienung(Instanz:Pointer; AntriebsRenderModus:TAntriebsRenderModus; var Prot:TProtokollFst; sp:single); stdcall;
begin
  if Instanz<>nil then TdllBasisfunktion(Instanz).Bedienung(AntriebsRenderModus, Prot, sp);
end;

procedure Berechnung(Instanz:Pointer; dt:double; AntriebsRenderModus:TAntriebsRenderModus; var Mehrfachtraktionsdaten:TMehrfachtraktionsdaten; HSGesperrt:Boolean); stdcall;
begin
  if Instanz<>nil then TdllBasisfunktion(Instanz).Berechnung(dt, AntriebsRenderModus, Mehrfachtraktionsdaten, HSGesperrt);
end;

procedure Nullstellungszwang(Instanz:Pointer); stdcall;
begin
  if Instanz<>nil then TdllBasisfunktion(Instanz).Nullstellungszwang;
end;

procedure SetzeHauptschalterzustand(Instanz:Pointer; modus:Byte); stdcall;
begin
  if Instanz<>nil then TdllBasisfunktion(Instanz).SetzeHauptschalterzustand(modus);
end;

function LeseMaxAntriebskraft(Instanz:Pointer; spAkt:single):single; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).LeseMaxAntriebskraft(spAkt)
                  else Result:=0;
end;

function LeseAntriebskraft(Instanz:Pointer):single; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).LeseAntriebskraft
                  else Result:=0;
end;

function LeseAntriebskraftSollNormiert(Instanz:Pointer):single; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).LeseAntriebskraftSollNormiert
                  else Result:=0;
end;

function LeseOberstrom(Instanz:Pointer):single; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).LeseOberstrom
                  else Result:=0;
end;

function LeseMotorstrom(Instanz:Pointer):single; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).LeseMotorstrom
                  else Result:=0;
end;

function LeseMotorspannung(Instanz:Pointer):single; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).LeseMotorspannung
                  else Result:=0;
end;

function LeseAchsen(Instanz:Pointer):integer; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).LeseAchsen
                  else Result:=0;
end;

function LeseSollZugkraft(Instanz:Pointer):single; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).LeseSollZugkraft
                  else Result:=0;
end;

function LeseMotordrehzahl(Instanz:Pointer):single; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).LeseMotordrehzahl
                  else Result:=0;
end;

function LeseMotormoment(Instanz:Pointer):single; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).LeseMotormoment
                  else Result:=0;
end;

function LeseMotorlast(Instanz:Pointer):single; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).LeseMotorlast
                  else Result:=0;
end;

function LeseFahrstufe(Instanz:Pointer):single; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).LeseFahrstufe
                  else Result:=0;
end;

function LeseZylSolldruck(Instanz:Pointer):single; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).LeseZylSolldruck
                  else Result:=0;
end;

function PruefeFahrstufe0(Instanz:Pointer):Boolean; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).PruefeFahrstufe0
                  else Result:=false;
end;

function NullstellungszwangAktiv(Instanz:Pointer):Boolean; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).NullstellungszwangAktiv
                  else Result:=false;
end;

function HauptschalterWgOLEnde(Instanz:Pointer; FahrlTyp:TFahrleitungstyp; Spannungsfaktor:single):Boolean; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).HauptschalterWgOLEnde(FahrlTyp, Spannungsfaktor)
                  else Result:=false;
end;

function HauptschalterWgOberstrom(Instanz:Pointer):Boolean; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).HauptschalterWgOberstrom
                  else Result:=false;
end;

function Hauptschalterstatus(Instanz:Pointer):Byte; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).Hauptschalterstatus
                  else Result:=0;
end;

//function Zugstatus(FzgNode:TTreenode):byte; stdcall;
//begin
//  Result:=TdllBasisfunktion(Instanz).;
//end;

function HauptschalterDrin(Instanz:Pointer):Boolean; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).HSDrin
                  else Result:=false;
end;

function DieselmotorLaeuft(Instanz:Pointer):Boolean; stdcall;
begin
  if Instanz<>nil then Result:=TdllBasisfunktion(Instanz).DMLaeuft
                  else Result:=false;
end;



//    procedure VeraenderteWerteZugverband(kn:TTCPPaketKnoten); override;
//    procedure VeraenderteWerteZugFahrdaten(kn:TTCPPaketKnoten); override;

// TKennlinie ----------------------------------------------------------

constructor TKennlinie.Create;
const Leistung = 3500*1000;
      vMax = 200/3.6;
      FMax = 150*1000;
var a:integer;
begin
  inherited;
  SetLength(Punkte, 14);
  for a:=0 to length(Punkte)-1 do
  begin
    Punkte[a].Geschw:=a*vMax/(length(Punkte)-1);
    if Leistung/Punkte[a].Geschw>0 then Punkte[a].Kraft:=min(FMax, Leistung/Punkte[a].Geschw)
                                   else Punkte[a].Kraft:=FMax;
  end;
end;

function TKennlinie.WertAblesen(Geschw:single):single;
var a:integer;
begin
  a:=0;
  Result:=0;
  repeat
    if (Geschw>=Punkte[a].Geschw) and (Geschw<Punkte[a+1].Geschw) then Result:=Punkte[a].Kraft + (Punkte[a+1].Kraft-Punkte[a].Kraft) * (Geschw - Punkte[a].Geschw)/(Punkte[a+1].Geschw - Punkte[a].Geschw);
    inc(a);
  until (a=Length(Punkte)-2) or (Result<>0);
end;


// TNachlaufsteuerung ----------------------------------------------------------


constructor TNachlaufsteuerung.Create;
begin
  FAnzahlSchaltstufen:=40;
  FSchaltwerkGeschwAuf:=10;
  FSchaltwerkGeschwAb:=10;

  FZielstufe:=0;
  FStufeAktuellFloat:=0;
end;

procedure TNachlaufsteuerung.Berechnen(dt:double);
begin
  if      FStufeAktuellFloat<FZielstufe then FStufeAktuellFloat:=min(FStufeAktuellFloat + dt*FSchaltwerkGeschwAuf, FZielstufe)
  else if FStufeAktuellFloat>FZielstufe then FStufeAktuellFloat:=max(FStufeAktuellFloat - dt*FSchaltwerkGeschwAb, FZielstufe);
end;

function TNachlaufsteuerung.Stufe:integer;
begin
  Result:=round(FStufeAktuellFloat);
end;

procedure TNachlaufsteuerung.SetzeZiel(Stufe:integer);
begin
  FZielstufe:=Stufe
end;


// TdllBasisfunktion -----------------------------------------------------------

constructor TdllBasisfunktion.Create;
begin
  inherited;
  FZugkraftAktuell:=0;
  FVarianteAktuell:=0;
  FNachlaufsteuerung:=TNachlaufsteuerung.Create;
  FKraftkennlinie:=TKennlinie.Create;
  Fsp:=0;
  FHauptschalter:=0;
end;

destructor TdllBasisfunktion.Destroy;
begin
  FKraftkennlinie.Free;
  FNachlaufsteuerung.Free;
  inherited;
end;

procedure TdllBasisfunktion.VarianteAktivieren(index:integer);
begin
  FVarianteAktuell:=index;
  if index>1 then MessageDlg('Antrieb hat nicht die angeforderte Variante '+IntToStr(index), mtError, [mbOK], 0);
  if index<0 then MessageDlg('Antrieb-Variante nicht definiert', mtError, [mbOK], 0);
end;

procedure TdllBasisfunktion.Nullstellungszwang;
begin

end;

procedure TdllBasisfunktion.Bedienung(AntriebsRenderModus:TAntriebsRenderModus; var Prot:TProtokollFst; sp:single);
begin
end;

procedure TdllBasisfunktion.VorspanntraktionsdatenSetzen(sp, SollLeistungNormiert:single);
begin
  FZugkraftAktuell:=SollLeistungNormiert * FKraftkennlinie.WertAblesen(sp);
end;

procedure TdllBasisfunktion.Berechnung(dt:double; AntriebsRenderModus:TAntriebsRenderModus; var Mehrfachtraktionsdaten:TMehrfachtraktionsdaten; HSGesperrt:Boolean);
begin
  Fsp:=Mehrfachtraktionsdaten.Grundfahrdaten.spAkt;
  FNachlaufsteuerung.Berechnen(dt);
end;

procedure TdllBasisfunktion.SetzeHauptschalterzustand(modus:Byte);
begin
end;

function TdllBasisfunktion.LeseMaxAntriebskraft(spAkt:single):single;
begin
  Result:=FKraftkennlinie.WertAblesen(spAkt);
end;

function TdllBasisfunktion.LeseAntriebskraft:single;
begin
  Result:=FZugkraftAktuell;
end;

function TdllBasisfunktion.LeseAntriebskraftSollNormiert:single;
begin
  Result:=0;
end;

function TdllBasisfunktion.LeseOberstrom:single;
begin
  Result:=0;
end;

function TdllBasisfunktion.LeseMotorstrom:single;
begin
  Result:=0;
end;

function TdllBasisfunktion.LeseMotorspannung:single;
begin
  Result:=0;
end;

function TdllBasisfunktion.LeseAchsen:integer;
begin
  Result:=0;
end;

function TdllBasisfunktion.LeseSollZugkraft:single;
begin
  Result:=0;
end;

function TdllBasisfunktion.LeseMotordrehzahl:single;
begin
  Result:=0;
end;

function TdllBasisfunktion.LeseMotormoment:single;
begin
  Result:=0;
end;

function TdllBasisfunktion.LeseMotorlast:single;
begin
  Result:=0;
end;

function TdllBasisfunktion.LeseFahrstufe:single;
begin
  Result:=FNachlaufsteuerung.Stufe;
end;

function TdllBasisfunktion.LeseZylSolldruck:single;
begin
  Result:=-1;
end;

function TdllBasisfunktion.PruefeFahrstufe0:Boolean;
begin
  Result:=true;
end;

function TdllBasisfunktion.NullstellungszwangAktiv:Boolean;
begin
  Result:=false;
end;

function TdllBasisfunktion.HauptschalterWgOLEnde(FahrlTyp:TFahrleitungstyp; Spannungsfaktor:single):Boolean;
begin
  Result:=false;
end;

function TdllBasisfunktion.HauptschalterWgOberstrom:Boolean;
begin
  Result:=false;
end;

function TdllBasisfunktion.Hauptschalterstatus:Byte;
begin
  Result:=0;
end;

//function TdllBasisfunktion.Zugstatus(FzgNode:TTreenode):byte;
//begin
//  Result:=0;
//end;

function TdllBasisfunktion.HSDrin: Boolean;
begin
  Result:=true;
end;

function TdllBasisfunktion.DMLaeuft: Boolean;
begin
  Result:=false;
end;

// TdllAntrieb -----------------------------------------------------------------



function TdllAntrieb.LeseAntriebstyp:Byte;
begin
  Result:=1;
end;

procedure TdllAntrieb.Bedienung(AntriebsRenderModus:TAntriebsRenderModus; var Prot:TProtokollFst; sp:single);
begin
  inherited;
  if Prot.Rischa.Funktion in [KSF_RischaR, KSF_RischaV] then
  begin
    if FVarianteAktuell=0 then
    begin
      if Prot.SchaltstufenSteller.Funktion=KSF_FahrstufeX then FNachlaufsteuerung.SetzeZiel(round(Prot.SchaltstufenSteller.Parameter * FNachlaufsteuerung.Anzahlstufen));
    end
    else if FVarianteAktuell=1 then
    begin
      if Prot.ZugkraftSteller.Funktion=KSF_ZugkraftX then FNachlaufsteuerung.SetzeZiel(round(Prot.ZugkraftSteller.Parameter * FNachlaufsteuerung.Anzahlstufen));
    end;
  end
  else FNachlaufsteuerung.SetzeZiel(0);

  if      Prot.Hauptschalter.Funktion in [KSF_HauptschalterAus] then FHauptschalter:=1
  else if Prot.Hauptschalter.Funktion in [KSF_HauptschalterEin] then
  begin
    // nur HS einlegen, wenn das Schaltwerk abgelaufen ist und der Fahrschalter in 0 steht
    if FVarianteAktuell=0 then
    begin
      if (FNachlaufsteuerung.Stufe=0) and ((Prot.SchaltstufenSteller.Funktion=KSF_FahrstufeSchnellAus) or ((Prot.SchaltstufenSteller.Funktion=KSF_FahrstufeX) and (Prot.SchaltstufenSteller.Parameter=0))) then FHauptschalter:=0
    end
    else if FVarianteAktuell=1 then
    begin
      if (FNachlaufsteuerung.Stufe=0) and ((Prot.ZugkraftSteller.Funktion=KSF_ZugkraftSchnellAus) or ((Prot.ZugkraftSteller.Funktion=KSF_ZugkraftX) and (Prot.ZugkraftSteller.Parameter=0))) then FHauptschalter:=0
    end;
  end;

  // der LM auf fahrzeugintern19 soll beispielhaft leuchten wenn das System Zugkraft erzeugt
  Prot.FtdIntern[19]:=byte(LeseAntriebskraft<>0);

  // den Sound auf fahrzeugintern20 ansteuern (irgendein sinnfreies Beispiel)
  Prot.FtdIntern[20]:=sqrt(abs(sp));

end;


procedure TdllAntrieb.Berechnung(dt:double; AntriebsRenderModus:TAntriebsRenderModus; var Mehrfachtraktionsdaten:TMehrfachtraktionsdaten; HSGesperrt:Boolean);
begin
  inherited;

  if FHauptschalter=0 then FZugkraftAktuell:=FNachlaufsteuerung.Stufe/FNachlaufsteuerung.Anzahlstufen * FKraftkennlinie.WertAblesen(Fsp)
                      else FZugkraftAktuell:=0;

  // Hauptschalter soll beispielhaft über 50 km/h rausfliegen
  if Fsp>50/3.6 then FHauptschalter:=1;
end;

function TdllAntrieb.Hauptschalterstatus:Byte;
begin
  Result:=FHauptschalter;
end;


// TdllBremse ------------------------------------------------------------------


function TdllBremse.LeseAntriebstyp:Byte;
begin
  Result:=0;
end;

procedure TdllBremse.Bedienung(AntriebsRenderModus:TAntriebsRenderModus; var Prot:TProtokollFst; sp:single);
begin
  inherited
end;

procedure TdllBremse.Berechnung(dt:double; AntriebsRenderModus:TAntriebsRenderModus; var Mehrfachtraktionsdaten:TMehrfachtraktionsdaten; HSGesperrt:Boolean);
begin
  inherited
end;



initialization


finalization
var a:integer;

  for a:=0 to length(Funktionen)-1 do
  begin
    if Funktionen[a]<>nil then Funktionen[a].Free;
  end;
  setlength(Funktionen, 0);

end.
