Zum Inhalt

ASTVariable(Of T) -- Generische Variable mit automatischer Aenderungserkennung

Uebersicht

ASTVariable(Of T) ist eine generische Wrapper-Klasse aus der ASTLibrary, die eine beliebige Variable kapselt und bei Wertaenderungen automatisch reagiert. Die Klasse loest drei moegliche Aktionen aus, wenn sich der Wert aendert:

  1. Automatisches Senden ueber INetClient.DataTX an den ASTServer
  2. Callback-Aufruf einer benutzerdefinierten Action(Of T)
  3. Event ValueChanged fuer beliebige Subscriber

Diese drei Mechanismen koennen einzeln oder kombiniert genutzt werden. Dadurch entfaellt die manuelle Pruefung auf Wertaenderungen -- der Code schreibt einfach .Value = neuerWert und die Klasse uebernimmt den Rest.

Quelldatei: ASTLibrary/ASTLibrary/ASTVariable.vb

Klassendiagramm

classDiagram
    class ASTVariable~T~ {
        -T _value
        -INetClient _inetClient
        -Integer _cmd
        -Action~T~ _onChange
        +T Value
        +Event ValueChanged(sender, newValue)
        +New(initialValue : T)
        +New(initialValue : T, inetClient : INetClient, cmd : Integer)
        +New(initialValue : T, onChange : Action~T~)
        +New(initialValue : T, inetClient : INetClient, cmd : Integer, onChange : Action~T~)
    }

    class INetClient {
        +DataTX(CMD : Integer, ToModule : Byte, data : String)
        +DataTXBit(CMD : Integer, ToModule : Byte, BitID : Byte, value : Byte)
    }

    ASTVariable~T~ --> INetClient : sendet via DataTX

Konstruktoren

Die Klasse bietet vier Konstruktoren fuer unterschiedliche Einsatzszenarien:

Konstruktor Beschreibung
New(initialValue) Nur Anfangswert, ohne Auto-Senden oder Callback. Nuetzlich wenn nur das ValueChanged-Event verwendet wird.
New(initialValue, inetClient, cmd) Automatisches Senden ueber INetClient.DataTX bei jeder Wertaenderung. Der cmd-Parameter ist die INET-Register-Nummer.
New(initialValue, onChange) Ruft bei Wertaenderung die uebergebene Action(Of T) Callback-Methode auf.
New(initialValue, inetClient, cmd, onChange) Kombiniert automatisches Senden und Callback.

Aenderungserkennung (HasChanged-Mechanismus)

Die zentrale Logik liegt im Setter der Value-Property. Bei jeder Zuweisung wird geprueft, ob sich der Wert tatsaechlich geaendert hat:

Public Property Value As T
    Get
        Return _value
    End Get
    Set(value As T)
        ' Pruefung ob sich der Wert tatsaechlich geaendert hat
        If Not EqualityComparer(Of T).Default.Equals(_value, value) Then
            _value = value

            ' 1. ValueChanged Event ausloesen
            RaiseEvent ValueChanged(Me, value)

            ' 2. Falls InetClient definiert: DataTX aufrufen
            If _inetClient IsNot Nothing Then
                _inetClient.DataTX(_cmd, 0, value.ToString())
            End If

            ' 3. Falls Callback definiert: Callback aufrufen
            If _onChange IsNot Nothing Then
                _onChange.Invoke(value)
            End If
        End If
    End Set
End Property

Ablauf bei Wertzuweisung

flowchart TD
    A["variable.Value = neuerWert"] --> B{"Wert geaendert?<br/>EqualityComparer(Of T).Default.Equals"}
    B -- Nein --> Z["Nichts tun"]
    B -- Ja --> C["_value = neuerWert"]
    C --> D["RaiseEvent ValueChanged"]
    D --> E{"INetClient<br/>vorhanden?"}
    E -- Ja --> F["inetClient.DataTX(cmd, 0, wert)"]
    E -- Nein --> G{"Callback<br/>vorhanden?"}
    F --> G
    G -- Ja --> H["onChange.Invoke(wert)"]
    G -- Nein --> Z2["Fertig"]
    H --> Z2

Wichtig: Wenn der zugewiesene Wert identisch mit dem aktuellen Wert ist, passiert gar nichts -- kein Event, kein Senden, kein Callback. Das verhindert unnoetige Netzwerk-Pakete und redundante Verarbeitung.

Kommunikation mit dem ASTServer

Wenn eine ASTVariable mit einem INetClient und einer CMD-Nummer konfiguriert ist, wird bei jeder Wertaenderung DataTX aufgerufen:

inetClient.DataTX(cmd, 0, value.ToString())

Die DataTX-Methode des INetClient unterscheidet dabei zwei Faelle:

  • CMD >= 2000: Sendet einen Frame mit der CMD-Nummer direkt als Frame-Typ
  • CMD < 2000: Verpackt die CMD-Nummer fuenfstellig als Praefix in einen Frame vom Typ 5340

In beiden Faellen wird der Wert als String uebertragen. Der ToModule-Parameter wird von ASTVariable immer als 0 (Broadcast an alle Module) uebergeben.

Verwendung im Code

Praxisbeispiel: FMA-Array im FCU-Modul

Das A320 FCU-Modul nutzt ASTVariable fuer die 15 Flight Mode Annunciator (FMA) Werte. Jeder FMA-Slot ist an ein eigenes INET-Register (CMD 2263-2277) gebunden:

' Aus A320_FCU/Module/FCULogic/modVariablesFCULogic.vb

Public FMA As ASTLibrary.ASTVariable(Of Integer)() = {
    New ASTLibrary.ASTVariable(Of Integer)(0, MainFormInstance.INetClient1, 2263),
    New ASTLibrary.ASTVariable(Of Integer)(0, MainFormInstance.INetClient1, 2264),
    New ASTLibrary.ASTVariable(Of Integer)(0, MainFormInstance.INetClient1, 2265),
    New ASTLibrary.ASTVariable(Of Integer)(0, MainFormInstance.INetClient1, 2266),
    New ASTLibrary.ASTVariable(Of Integer)(0, MainFormInstance.INetClient1, 2267),
    New ASTLibrary.ASTVariable(Of Integer)(0, MainFormInstance.INetClient1, 2268),
    New ASTLibrary.ASTVariable(Of Integer)(0, MainFormInstance.INetClient1, 2269),
    New ASTLibrary.ASTVariable(Of Integer)(0, MainFormInstance.INetClient1, 2270),
    New ASTLibrary.ASTVariable(Of Integer)(0, MainFormInstance.INetClient1, 2271),
    New ASTLibrary.ASTVariable(Of Integer)(0, MainFormInstance.INetClient1, 2272),
    New ASTLibrary.ASTVariable(Of Integer)(0, MainFormInstance.INetClient1, 2273),
    New ASTLibrary.ASTVariable(Of Integer)(0, MainFormInstance.INetClient1, 2274),
    New ASTLibrary.ASTVariable(Of Integer)(0, MainFormInstance.INetClient1, 2275),
    New ASTLibrary.ASTVariable(Of Integer)(0, MainFormInstance.INetClient1, 2276),
    New ASTLibrary.ASTVariable(Of Integer)(0, MainFormInstance.INetClient1, 2277)
}

Wenn die FCU-Logik einen FMA-Modus aendert, reicht eine einfache Zuweisung:

' Aus A320_FCU/modFCULogic.vb -- Autopilot-Modus setzen

FMA(AP_ROW1).Value = FMA_AP1_       ' Sendet automatisch via CMD 2263 + Offset
FMA(SPD_ROW1).Value = NONE_         ' Sendet nur wenn Wert sich aendert
FMA(AP_ROW3).Value = FMA_ATHR_STBY_ ' Kein manueller DataTX-Aufruf noetig

Der Vorteil: Der TEMP_FMA-Vergleich (der alte VB6-Ansatz mit manueller Pruefung) wird durch die eingebaute Aenderungserkennung der ASTVariable ersetzt.

Weitere Konstruktor-Varianten (aus der XML-Dokumentation)

' Automatisches Senden ueber InetClient an ASTServer:
Public Altitude As New ASTVariable(Of Integer)(0, myInetClient, 100)

' Mit Callback-Sub:
Public Heading As New ASTVariable(Of Integer)(0, AddressOf OnHeadingChanged)

' Beides kombiniert:
Public VertSpeed As New ASTVariable(Of Integer)(0, myInetClient, 102, AddressOf OnVSChanged)

' Verwendung:
Altitude.Value = 10000  ' Sendet automatisch via myInetClient.DataTX(100, 0, "10000")

Typparameter

Da ASTVariable(Of T) generisch ist, kann jeder Datentyp verwendet werden. Die Aenderungserkennung nutzt EqualityComparer(Of T).Default, was fuer alle Standard-.NET-Typen korrekt funktioniert:

Typ Typischer Einsatz
Integer FMA-Modi, Geschwindigkeiten, Hoehen, Heading
Double Praezise Werte (EPR, Koordinaten, Winkel)
String Textuelle Daten (Wegpunkt-Namen, Meldungen)
Boolean Flags und Schalter

Designentscheidungen

  • Keine Synchronisation: Die Klasse ist nicht thread-safe. In der Akka.NET-Architektur des FMGC ist das korrekt, da jeder Actor seine eigenen Variablen in seinem eigenen Thread verarbeitet.
  • ToString()-Serialisierung: Der Wert wird immer via value.ToString() als String gesendet. Das entspricht dem VB6 INET-Protokoll, das ausschliesslich String-basiert ist.
  • Broadcast (ToModule = 0): ASTVariable sendet immer an alle Module (ToModule = 0). Fuer gerichtetes Senden an ein bestimmtes Modul muss DataTX direkt aufgerufen werden.