Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Eigene Ereignisse auslösen (https://www.delphipraxis.net/180510-eigene-ereignisse-ausloesen.html)

akurka 25. Mai 2014 15:38

Eigene Ereignisse auslösen
 
Hallo
Folgende Situation :
//----------------------------------
T_CNCStatus = packed record
Kopf :byte;
ZBETR :byte;
ZREFE :byte;
FLAG :byte;
//
//usw. total 16 Byte
SMAXH :byte;
end; //record
//--------------------------------
var Status :T_Status;{Status-Satz}
//----------------------------------------
Wie kann ich ein Ereigniss erzeugen wenn sich der Wert des Bytes im
Status.ZBETR ändert ?
Die var Status wurde beschrieben durch Daten die von rs232 kommen.
mfg Anton

zeras 25. Mai 2014 15:58

AW: Eigene Ereignisse auslösen
 
Kommt der Packed record als Array of Byte aus der RS232 und wird dann in record abgelegt? Oder wird jeder einzelne Wert von "Irgendwem" beschrieben?

akurka 25. Mai 2014 17:06

AW: Eigene Ereignisse auslösen
 
Hallo Zeras
Ja, der Record wird ausschliesslich durch RS232 abgefüllt . Allerdings
kann es passieren (in Mehrheit der Fälle), dass die Daten exakt die gleichen
sind. Der ZBETR = Betriebswahl ändert nicht so schnell, ich soll aber nur bei einer Aenderung ein Erreignis (OnChange ) haben.
Gruss Anton

zeras 25. Mai 2014 17:17

AW: Eigene Ereignisse auslösen
 
Wenn die Daten über die RS232 reinkommen, musst du diese ja bewerten.
Beispiel: Wenn 16 Zeichen im Puffer sind, dass du dann was machst. Wenn weniger Zeichen da sind, dann noch warten, bis 16 Zeichen im Puffer sind. Erst dann die Bewertung machen. Nebenbei solltest du noch einen Timeout nutzen, damit, wenn einmal zu wenig Zeichen kommen, diese dann verworfen werden und neu angefragt werden.
Ich weiß zwar nicht, welche RS232 Unit du hast, aber bei den meisten kann man abfragen, wieviel Zeichen im Puffer sind.
Wenn dann diese 16 Zeichen ausgewertet sind, kannst du dich auf dein Byte konzentrieren, welches du prüfen willst.

akurka 25. Mai 2014 17:45

AW: Eigene Ereignisse auslösen
 
Hallo Zeras
Ja, dass ist im bisherigem (pascal)Programm so, aber das ist nicht umbedingt
OOP like(resp Delphi like). Ich soll vielleicht erwähnen das der Status eine Globale var ist. Ausserdem befinde ich mich in x_te Menü(x_te Form) und die Componente für Async32(auch Ereignis gesteuert) läuft völlig autonom. Ich möchte nicht wieder in das alte Schema von Polling hinein kommen.
Ich möchte nur feststellen können, ob sich die Betriebswahl geändert hat, und falls es so war, wird in das y_te Menue(y_te Form) gewechselt.
Uebrigens läuft die Komponennte Async32(rs232) auf dem Form1 (also Haupt programm).
mfg Anton

zeras 25. Mai 2014 18:11

AW: Eigene Ereignisse auslösen
 
Wie liest du denn die Daten von Async aus?
Dann kannst du dich doch nur in die Empfangsroutine mit reinhängen und dann prüfen. Von allein wird da kein Ereignis kommen.
Vielleicht hilft ein wenig Code von dir weiter.

himitsu 25. Mai 2014 18:33

AW: Eigene Ereignisse auslösen
 
Zitat:

Zitat von zeras (Beitrag 1260183)
Dann kannst du dich doch nur in die Empfangsroutine mit reinhängen und dann prüfen. Von allein wird da kein Ereignis kommen.

Im Prinzip muß also der alte Status gespeichert sein.

Nach Empfang und Auswertung des aktuellen Records wird dessen Inhalt z.B. in sowas wie
Delphi-Quellcode:
FLastCNCStatus: T_CNCStatus;
gespeichert. (falls die einzelnen Statuswerte nicht schon irgendwo existieren)
Bei der Auswertung kann man nun die Alten mit den neuen Werten vergleichen und bei einem Unterschied dann das gewünschte Ereignis auslösen.

akurka 25. Mai 2014 21:15

AW: Eigene Ereignisse auslösen
 
Hallo Himitsu,

Soviel ich in der letzte Zeit gelesen habe, soll Delphi eine Ereigniss orientierte Sprache.
Selbstverständlich kann man es mit Vergleich alt/neu
lösen, das ist sogar bereits im meinem uraltem Pascalprogramm so realisiert.
Aber ich will es ja neu schreiben.

Ich meinte, ahnlich wie die standard Ereignisse wie z.Bsp OnClick sollte man
auch eigene Ereigniss "OnChange" für die Variableaenderung definieren können.
Das wäre doch eleganter. Die Menues Umschaltung wird dann nur durch
das Ereigniss gestartete Methode bewerkstelligt.
Sollte das nicht durch überschreiben der Standard Ereignisse aus TControl
möglich sein ? Durch die Definition eines eigenen Typs ?
Nun bin ich da ein bisschen überfordert, wie es da weiter gehen soll.
Vielleicht weisst Du ein ähnliches Beispiel ?
mfg Anton

zeras 25. Mai 2014 21:34

AW: Eigene Ereignisse auslösen
 
Überlege mal, wie man zu einem Ereignis kommt.
Man muss intern überprüfen und dann sehen, ob der Status sich geändert hat. Der beste Zeitpunkt ist, wie schon oben beschrieben, die Empfangsorutine. Die läuft ereignisgesteuert. Und da wirst du dich reinhängen müssen.
Soweit, wie ich weiß, läuft bei den RS232 Units um Hintergrund ein schneller Timer, der prüft, ob neue Daten im Hardwareempfangspuffer liegen und holt diese dann ab. Damit werden dann Ereignisse wie OnReceived etc. erstellt.
Prüfe also im Ereignis OnReceived oder ähnlich ab, ob 16 Bytes da sind und lege diese in einem separaten Puffer ab. Wenn dann wieder 16 Bytes da sind, vergleichst du dann die neuen Daten mit den Alten Daten und wenn sich der Status geändert hat, machst du dann deine Routine.

himitsu 26. Mai 2014 01:53

AW: Eigene Ereignisse auslösen
 
Ja, Delphi ist im Grunde eine objekt-orientierte Programmiersprache (OOP), welche viel mit Events arbeitet, aber von Alleine passiert das auch nichts.

Was man machen kann, ist seinen Code in entsprechende Klassen aufzuteilen und die Events/Property entsprechend auszulegen.
Also z.B. gibt es dann irgendwo ein SMAXH-Property, welches im Setter prüft, ob sich der aktuelle Wert ändert und wenn ja, dann wird ein entsprechendes Ereignis ausgelöst.

Delphi-Quellcode:
procedure DoChange; // hier drin wird das OnChange-Event ausgelöst

FMyProp: Integer;
procedure SetMyProp(Value: Integer);
property MyProp: Integer read FMyProp write SetMyProp;

function GetMyPropX(Index: Integer): Integer; // man kann auch einen Getter/Setter für mehrere Property benutzen
procedure SetMyPropX(Index, Value: Integer);
property MyPropA: Integer index 1 read GetMyPropX write SetMyPropX;
property MyPropB: Integer index 2 read GetMyPropX write SetMyPropX;
property MyPropC: Integer index 3 read GetMyPropX write SetMyPropX;

procedure TMyClass.SetMyProp(Value: Integer);
begin
  if Value = MyProp then
    Exit;
  FMyProp := Value;
  DoChange;
end;
(nun nur noch alle nötigen Werte entsprechend dieser Property-Vorlage anlegen)

Jonas Shinaniganz 26. Mai 2014 08:02

AW: Eigene Ereignisse auslösen
 
Wenn du T_CNCStatus anfassen kannst, wovon ich ausgehe, ist folgendes denkbar:

1. Erweiterung von T_CNCStatus um Property
2. Erweiterung von T_CNCStatus um Event

Delphi-Quellcode:
type
  T_CNCStatus = packed record
  private
    FZbetr: byte;
    procedure SetZbetr(const Value: byte);
  public
    OnZbetrChange : TNotifyEvent;
    Kopf : byte;
    property Zbetr : byte read FZbetr write SetZbetr;
  end;

implementation

procedure T_CNCStatus.SetZbetr(const Value: byte);
begin
  // hier könntest du vorher überprüfen ob sich der Wert wirklich geändert hat.
  FZbetr := Value;
  if Assigned(OnZbetrChange) then
    OnZbetrChange(nil);
end;

akurka 26. Mai 2014 08:29

AW: Eigene Ereignisse auslösen
 
Hallo Jonas, vielen Dank , das ist es, was ich gesucht habe !
Die übrige Bytes aus Status records werden zwar benötigt, aber müssen
keine ereignis auslösen. Ist es richtig, dass die Typendeklaration für Status
dann insgesamt wie folgt aussehen wird :

T_CNCStatus =packed record
private
FZbetr: byte;
procedure SetZbetr(const Value: byte);
public
OnZbetrChange : TNotifyEvent;
Kopf :byte;
Zbetr :byte;
ZREFE :byte;
FLAG :byte;
POSA1 :byte;
POSA2 :byte;
STACK :byte;
ZAUTO :byte;
ZOUT1 :byte;
ZOUT2 :byte;
ZINP1 :byte;
ZINP2 :byte;
VORSL :byte; {VORSCHUB}
VORSH :byte;
DAOUTL :byte; {DA1}
DAOUTH :byte;
SMAXH :byte;
property Zbetr : byte read FZbetr write SetZbetr;
end; {record}

mfg Anton

himitsu 26. Mai 2014 08:52

AW: Eigene Ereignisse auslösen
 
Wenn du diesen Record aber vom Comport oder einem Stream einliest, dann wird direkt auf den Speicher zugegriffen und das Property umgangen.
Der Setter wird nur benutzt, wenn über das Property etwas zugewiesen wird.

akurka 26. Mai 2014 10:26

AW: Eigene Ereignisse auslösen
 
Hallo Himitsu,
danke für den Hinweis, wenn ich also Dein Beispiel auf meine
Anwendung anpasse, ist es so Richtig :

//zuerst Typendeklaration
TMyClass = procedure DoChange; // hier drin wird das OnChange-Event ausgelöst
FMyProp: Byte;
procedure SetMyProp(Value: Byte);
property MyProp: Byte read FMyProp write SetMyProp;

(* ich benötige nur ZBETR für Ereigniss auslösen, also darf ich es weglassen
function GetMyPropX(Index: Integer): Integer; // man kann auch einen Getter/Setter für mehrere Property benutzen
procedure SetMyPropX(Index, Value: Integer);
property MyPropA: Integer index 1 read GetMyPropX write SetMyPropX;
property MyPropB: Integer index 2 read GetMyPropX write SetMyPropX;
property MyPropC: Integer index 3 read GetMyPropX write SetMyPropX;
*)

Implementation
procedure TMyClass.SetMyProp(Value: Byte);
begin
if Value = MyProp then
Exit;
FMyProp := Status.ZBETR;
DoChange;
end;

Sir Rufo 26. Mai 2014 11:25

AW: Eigene Ereignisse auslösen
 
Also an den Record selber würde ich keinerlei Events binden.

Statt dessen würde ich eine Klasse (z.B. abgeleitet von
Delphi-Quellcode:
TThread
) nehmen, welche die Nachrichten empfängt und dann den gesamten Record bei einer Änderung weiterreicht.

Ein Beispiel hatte ich in einem anderen Zusammenhang schon mal geschrieben
http://www.delphipraxis.net/179188-g...a-threads.html
Das Beispiel funktioniert zwar so nicht mit Delphi 7 beschreibt aber die generelle Vorgehensweise.

Jonas Shinaniganz 26. Mai 2014 11:46

AW: Eigene Ereignisse auslösen
 
Zitat:

Wenn du diesen Record aber vom Comport oder einem Stream einliest, dann wird direkt auf den Speicher zugegriffen und das Property umgangen.
Der Setter wird nur benutzt, wenn über das Property etwas zugewiesen wird.
Wie ist es möglich, den Setter zu umgehen und auf FZbetr zu schreiben?

Mal ganz von den bisherigen Beiträgen abgesehen. Das Vorhaben mutet an wie die Bastellösung eines seriellen TDatapackage. Welches über Events verfügt und auch ansonsten eigentlich keine Wünsche offen lässt.

edt: Und noch eine Anmerkung. Da du einen Record verwendest gehe ich davon aus das die Daten des Records zusammengehörig sind. Wenn du jetzt bei Änderung von Zbetr auf ein OnChance reagierst sind vielleicht die anderen Felder noch nicht neu belegt. Du verwendest also in deiner Aktualisierungs/Verarbeitung-Routine eventuell Daten die noch zur Hälfte aus den alten Werten bestehen.

himitsu 26. Mai 2014 12:20

AW: Eigene Ereignisse auslösen
 
Zitat:

Zitat von Jonas Shinaniganz (Beitrag 1260232)
Wie ist es möglich, den Setter zu umgehen und auf FZbetr zu schreiben?

Indem man z.B. das TMyClass weiterhin als Record belässt und dann z.B. über ComPort.Read oder TStream.Read direkt in den Speicher der Record-Variable schreibt.

Dann geht der Wert direkt in das Feld und wird nicht über das Property umgeleitet.

akurka 26. Mai 2014 12:30

AW: Eigene Ereignisse auslösen
 
Hallo,
Da der Record nur durch RS232 abgefüllt wird, werde ich
beim Empfang fertig ein Flag setzen, und beim beginn des Empfangs
natürlich rücksetzen. Dies lässt sich leicht lösen in der OnRXBuff procedur.
Das wäre dann die Freigabe um die Daten zu lesen.
(die Status Daten von der CNC werden nur gelesen).
Es scheint mir, dass Ihr Experten euch nicht ganz einig sind, ist das so ?
mfg Anton

Sir Rufo 26. Mai 2014 12:50

AW: Eigene Ereignisse auslösen
 
Zitat:

Zitat von akurka (Beitrag 1260238)
Hallo,
Da der Record nur durch RS232 abgefüllt wird, werde ich
beim Empfang fertig ein Flag setzen, und beim beginn des Empfangs
natürlich rücksetzen. Dies lässt sich leicht lösen in der OnRXBuff procedur.
Das wäre dann die Freigabe um die Daten zu lesen.
(die Status Daten von der CNC werden nur gelesen).

Das ist eigentlich unnötig, denn diese Zugriffe kannst du erheblich besser mit einer CriticalSection absichern.
Delphi-Quellcode:
type
  TMyClass = class( TThread )
  private
    FCS : TCriticalSection;
    FStatus : TCNCStatus;
    procedure SetStatus( const Value : TCNCStatus );
    function GetStatus : TCNCStatus;
  protected
    procedure Execute; override;
  public
    property Status : TCNCStatus read GetStatus;
  end;

procedure TMyClass.Execute;
var
  LStatus : TCNCStatus;
begin
  inherited;
  while not Terminated do
    begin
      // Warten auf ein Empfangs-Signal

      // Irgendwie den Status empfangen
      LStatus := ...

      // öffentlichen Status setzen
      SetStatus( LStatus );
    end;
end;

procedure TMyClass.SetStatus( const Value : TCNCStatus );
begin
  FCS.Enter;
  try
    FStatus := Value;
  finally
    FCS.Leave;
  end;
end;

function TMyClass.GetStatus : TCNCStatus;
begin
  FCS.Enter;
  try
    Result := FStatus;
  finally
    FCS.Leave;
  end;
end;
Der Trick hierbei ist es, die möglichen zeitlichen Überschneidungen so gering wie nur möglich zu halten. Da die Daten aber zunächst in eine lokale Variable geschrieben werden reduziert sich die Überschneidung auf das Auslesen/Setzen des Record-Inhalts und ist daher sehr kurz.

Jonas Shinaniganz 26. Mai 2014 13:23

AW: Eigene Ereignisse auslösen
 
Zitat:

Dann geht der Wert direkt in das Feld und wird nicht über das Property umgeleitet.
Stimmt hatte vergessen "strict private" drauß zu machen, aber man müsste schon explizit FZbetr beschreiben um den Setter zu umgehen.

Zitat:

Da der Record nur durch RS232 abgefüllt wird, werde ich
beim Empfang fertig ein Flag setzen, und beim beginn des Empfangs
natürlich rücksetzen.
Wie hilft denn hier ein Flag? Das OnChance hätte ja schon aufgerufen werden müssen, wenn du das Flag zurück setzt. Das wird dadurch nur komplizierter.

Ich empfehle serielle Datenpakete zu verwenden. AsyncPro bietet das kostenlos. Stichwort Songbeamer

Sir Rufo 26. Mai 2014 13:25

AW: Eigene Ereignisse auslösen
 
Zitat:

Zitat von Jonas Shinaniganz (Beitrag 1260254)
Zitat:

Dann geht der Wert direkt in das Feld und wird nicht über das Property umgeleitet.
Stimmt hatte vergessen "strict private" drauß zu machen, aber man müsste schon explizit FZbetr beschreiben um den Setter zu umgehen.

Und das ändert jetzt was? :gruebel:

Jonas Shinaniganz 26. Mai 2014 13:31

AW: Eigene Ereignisse auslösen
 
Reden wir aneinander vorbei? Den Setter kann man nicht umgehen, es handelt sich doch um eine globale Version des Records. Oder wird die komplette Record-Variable überschrieben?

Sir Rufo 26. Mai 2014 13:37

AW: Eigene Ereignisse auslösen
 
Zitat:

Zitat von Jonas Shinaniganz (Beitrag 1260263)
Den Setter kann man nicht umgehen, es handelt sich doch um eine globale Version des Records. Oder wird die komplette Record-Variable überschrieben?

Der Speicherbereich des Records wird überschrieben und da kannst du die Variablen so
Delphi-Quellcode:
strict private
machen wie du möchtest, sie werden trotzdem ohne den Setter zu benutzen geändert.

Jonas Shinaniganz 26. Mai 2014 13:40

AW: Eigene Ereignisse auslösen
 
Ja aber an irgendeiner Stelle muss ja der Record belegt werden, ob jetzt dann oder davor. In dem Moment fliegt dann das Event.

Delphi-Quellcode:
  TMyRec = record
  strict private
    FNichtBeschreibbar: Boolean;
    procedure SetNichtBeschreibbar(const Value: Boolean);
  public
    property NichtBeschreibbar : Boolean read FNichtBeschreibbar write SetNichtBeschreibbar;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ bla }

procedure TMyRec.SetNichtBeschreibbar(const Value: Boolean);
begin
  FNichtBeschreibbar := Value;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  MyRec : TMyRec;
  MyRec2 : TMyRec;
begin
  MyRec.NichtBeschreibbar := True;
  MyRec2.NichtBeschreibbar := False; // dann halt hier

  MyRec := MyRec2; // und nicht hier

end;
Aber das hilft jetzt glaube ich nicht wirklich dem Suchenden

akurka 26. Mai 2014 13:40

AW: Eigene Ereignisse auslösen
 
Hallo Sir Rufo
Danke für Dein Vorschlag, etwas ist mir nicht ganz klar.

Zitat:

procedure TMyClass.Execute;
var
LStatus : TCNCStatus;
begin
inherited;
while not Terminated do
begin
// Warten auf ein Empfangs-Signal

// Irgendwie den Status empfangen
LStatus := ...

// öffentlichen Status setzen
SetStatus( LStatus );
end;
end;
Heisst es, dass ich die Komponente für ComPort(TVaComm) gar nicht benützen muss und direkt WinAPI funktionen brauchen an diesen Stellen ??
(// Warten auf ein Empfangs-Signal resp. // Irgendwie den Status empfangen)

Nur taucht da ein anderes Problem auf.
Von der CNC kommt nicht nur Status, sondern auch andere Meldungen mit
unterschiedliche länge, die müssen dann in den etsprechenden Records gespeichert werden (für spätere Anzeige)
wobei dies natürlich auch im Hintergund soll ablaufen.
Die Reihenfolge der Meldungen ist beliebig !
Gruss
Anton

Sir Rufo 26. Mai 2014 13:41

AW: Eigene Ereignisse auslösen
 
Zitat:

Zitat von Jonas Shinaniganz (Beitrag 1260267)
Aber das hilft jetzt glaube ich nicht wirklich dem Suchenden

Vor allem weil er den Record so nicht befüllt!

Jonas Shinaniganz 26. Mai 2014 13:45

AW: Eigene Ereignisse auslösen
 
akurka, poste doch mal bitte wo du den Record befüllst, wenn das möglich ist.

Ich empfehle dir nochmals (weil es eine wirklich durchdachte Implementation ist) einen Blick in die AsyncPro Bibliothek zu werfen (speziell Datapackages). Es gibt auch eine gute Dokumentation dazu.

Sir Rufo 26. Mai 2014 13:53

AW: Eigene Ereignisse auslösen
 
Zitat:

Zitat von Jonas Shinaniganz (Beitrag 1260272)
akurka, poste doch mal bitte wo du den Record befüllst, wenn das möglich ist.

Ich empfehle dir nochmals (weil es eine wirklich durchdachte Implementation ist) einen Blick in die AsyncPro Bibliothek zu werfen (speziell Datapackages). Es gibt auch eine gute Dokumentation dazu.

Es ist völlig unerheblich, wie er den Record befüllt. So sollte man das definitiv nicht machen (es sei denn man möchte sich unkontrollierte Probleme einhandeln).
Wenn du dem Record einen Event spendierst und dann den Record aus einem Stream lädst, dann ist auch die Zuweisung für den Event entweder leer (im besten Fall) oder der Event zeigt irgendwo ins Nirwana und die Hütte fliegt dir um die Ohren.

Betrachte einen Record so, wie du einen einfachen Typen wie z.B. Delphi-Referenz durchsucheninteger betrachtest (als einen einfachen Wert).

Sir Rufo 26. Mai 2014 14:06

AW: Eigene Ereignisse auslösen
 
@akurka

Im OOP-Geschäft muss man etwas abstrakter denken (damit das auch Sinn macht und das Leben vereinfacht).

z.B. Die Komponente für den Com-Port sorgt für den Datenaustausch (Protokoll) und nicht mehr.
Sie weiß, wie groß die Pakete sind (ist Bestandteil des Protokolls) und übergibt diese Pakete an eine weitere Instanz, die weiß, wie man aus diesen Paketen (eine Handvoll Bytes) sinnvolle Strukturen erzeugt.

Etwas Ähnliches (mit Klassen) gibt es hier http://www.delphipraxis.net/180297-b...iebereien.html

Delphi-Quellcode:
unit BaseDataFactory;

interface

uses
  System.Generics.Collections,
  System.Classes,
  System.SysUtils,
  BaseData;

type
  TBaseDataClass = class of TBaseData;

  TBaseDataFactory = class
  private
    class var _Types : TDictionary<Byte, TBaseDataClass>;
  protected
    class constructor Create;
    class destructor Destroy;
  public
    class function CreateFromStream( AStream : TStream ) : TBaseData;
    class procedure RegisterType( AType : Byte; AClass : TBaseDataClass );
  end;

implementation

{ TBaseDataFactory }

class constructor TBaseDataFactory.Create;
begin
  _Types := TDictionary<Byte, TBaseDataClass>.Create;
end;

class function TBaseDataFactory.CreateFromStream( AStream : TStream ) : TBaseData;
var
  LType : Byte;
  LSize : Byte;
  LData : TBytes;
  LClass : TBaseDataClass;
begin
  AStream.Read( LType, SizeOf( LType ) );
  AStream.Read( LSize, SizeOf( LSize ) );
  SetLength( LData, LSize );
  AStream.Read( LData, LSize );

  LClass := _Types[LType]; // Bei einem unbekannten Typen wird hier eine Exception geworfen
  Result := LClass.Create( LData );
end;

class destructor TBaseDataFactory.Destroy;
begin
  _Types.Free;
end;

class procedure TBaseDataFactory.RegisterType( AType : Byte; AClass : TBaseDataClass );
begin
  _Types.AddOrSetValue( AType, AClass );
end;

end.
In die andere Richtung geht es genauso (nur umgekehrt).

Einer weiß, wie man aus einer Informationsstruktur (z.B. ein Record) eine Byte-Folge machen kann, übergibt diese Byte-Folge an jemand anderes, der Byte-Folgen versenden kann, der wiederum weiß, dass das über den Com-Port erfolgen muss.

Jonas Shinaniganz 26. Mai 2014 14:08

AW: Eigene Ereignisse auslösen
 
Okay vielleicht fällt es mir auch nur zu schwer, mich da in etwas hineinzudenken was ich nicht sehe :) In dem was du sagst stimme ich zu.

akurka, schau einmal hier in den Guide. In der Sektion Datapackages. http://tpapro.sourceforge.net/docs/A...renceGuide.pdf

Diese Bibliothek ist so mächtig das der serielle Stream vor ihr erzittert :]

Sir Rufo 26. Mai 2014 14:35

AW: Eigene Ereignisse auslösen
 
Betrachten wir das doch mal ganz abstrakt aus der Sicht der Anwendung:

Es gibt da so einige Daten-Pakete, die empfangen und gesendet werden können. Mehr interessiert die Anwendung an diesem Punkt nicht. Wann und warum ist egal. Wenn, dann muss die Anwendung reagieren und wenn die Anwendung etwas senden will, dann muss das auch einfach passieren. Wie das passiert, ist der Anwendung an diesem Punkt auch egal.

Damit kann man jetzt eine abstrakte Klasse definieren, die diese Anforderungen (Senden von Daten und Events beim Empfang von Daten) erfüllt.
Delphi-Quellcode:
type
  TCNC_Data1 = record
  ...
  end;

  TCNC_Data2 = record
  ...
  end;

  TCNC_Command1 = record
  ...
  end;

  TCNC_Command2 = record
  ...
  end;

  TCNC_Data1_Event = procedure ( Sender : TObject; Value : TCNC_Data1 ) of object;
  TCNC_Data2_Event = procedure ( Sender : TObject; Value : TCNC_Data2 ) of object;

  TAbstractCNC_Talker = class abstract
  private
    FOnReceiveData1 : TCNC_Data1_Event;
    FOnReceiveData2 : TCMC_Data2_Event;
  public
    procedure Send( Value : TCNC_Command1 ); overload; virtual; abstract;
    procedure Send( Value : TCNC_Command2 ); overload; virtual; abstract;

    property OnReceiveData1 : TCNC_Data1_Event read FOnReceiveData1 write FOnReceiveData1;
    property OnReceiveData2 : TCNC_Data2_Event read FOnReceiveData2 write FOnReceiveData2;
  end;

Sir Rufo 26. Mai 2014 14:44

AW: Eigene Ereignisse auslösen
 
In diesem Zuge wäre es auch interessant zu wissen, was exakt über die serielle Schnittstelle hineinkommt und welche Records (Struktur/Inhalt) dabei rauskommen sollen. Das gleiche auch für den umgekehrten Fall (die Anwendung sendet).

Daraus kann man sich dann auch sehr schön Test-Szenarios bauen, wo man den Com-Port durch etwas ersetzt, was diese Daten liefert/entgegennimmt und dann schaut, ob das Erwartete auch am anderen Ende herauskommt. Dann spart man sich den Aufbau einer kompletten CNC-Maschine mit Com-Anschluss :)

akurka 26. Mai 2014 15:52

AW: Eigene Ereignisse auslösen
 
Liste der Anhänge anzeigen (Anzahl: 2)
Hallo
Vielen Dank für Euere Bemühungen aber meine Verwirrung ist jetzt definitiv
komplett.
Ich glaube am besten statt tropfenweise Informationen, sende ich
zugleich die Beschreibung der gesammte Programmstruktur wie es jetzt im altem Pascal Programm ablauft. Siehe Beilage(Globale Variablen :NC__09= hier sollen die div.Meldungen von der CNC gespeichert, CNC_PC_comm.txt = Gesamtbeschreib der Kommunikation CNC zu PC).
Mein Ziel ist das ganze in Delphi zu portieren. Was nicht geändert werden kann sind die Meldungen von der CNC (ist zwahr auch von mir(grosste Teil VHDL) aber das möchte ich lieber nicht anfassen).
Ich habe einige der Async Pakete angeschaut und u.a das ProfAsync, damit auch einige Testprogramme gemacht. Jetzt bin anfänglich bei der Version 7 aber immer noch nicht brauchbars.
Ich wäre froh, wenn eine von Euch Experten mir ein Vorschlag macht für das Gesamtkonzept, weil ich langsamm überzeugt bin das es an dem mangelt.
Gruss Anton

Sir Rufo 26. Mai 2014 16:05

AW: Eigene Ereignisse auslösen
 
Zitat:

Zitat von akurka (Beitrag 1260305)
Ich glaube am besten statt tropfenweise Informationen, sende ich
zugleich die Beschreibung der gesammte Programmstruktur wie es jetzt im altem Pascal Programm ablauft. Siehe Beilage(Globale Variablen :NC__09= hier sollen die div.Meldungen von der CNC gespeichert, CNC_PC_comm.txt = Gesamtbeschreib der Kommunikation CNC zu PC).

Es fehlt eigentlich die Beschreibung, was wirklich über die Com-Schnittstelle ankommt.
Ich würde ja mal vermuten, dass da ein Header (wie groß?) kommt und danach die Daten, oder wie erkennst du, was für Daten du gerade bekommst?

akurka 26. Mai 2014 16:14

AW: Eigene Ereignisse auslösen
 
Hallo ,
Noch ein Zusatz : Das ZBETR im Status Meldung (Record Status) entscheidet darüber in welchem Menü man sich befindet (es hat 16 mögliche Betriebswahl
stellungen). Bei der Aenderung von ZBETR soll möglist schnell in ein anderes
Menü gewechselt werden. Darum meine Frage wegen eigene Ereignisse.
Gruss Anton

akurka 26. Mai 2014 16:42

AW: Eigene Ereignisse auslösen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Sir Rufo,
So kompliziert ist es nicht :
im erste Byte (MldgTyp) wird definiert, um was für Meldung es sich handelt (ist eine Nummer). Diese entscheidet darüber, wie lang die Meldung sein wird.
Siehe getblk, Putblk, Hauptprogr.
Diese Meldungen werden in verschiedenen Records gespeichert und sollen
aus allen Menüs zugreiffbar sein (Global var)
In der Beilage eine kurze Beschreibung der Empfangs/Sende proceduren.
Gruss Anton

Jonas Shinaniganz 26. Mai 2014 23:05

AW: Eigene Ereignisse auslösen
 
Also noch mal etwas ausführlicher, gerne morgen auch mit Codebeispiel.

1. Die Async-Pro Bibliothek bietet dir die Klasse TComport und TDatapacket (der Rest aus der Bibliothek ist für dieses Projekt nicht nötig).

2. Du kannst zur Designzeit ein TComport und ein TDatapacket auf das leere Formular eines neuen Projektes ziehen. Das TComport Objekt mit den nötigen Werten, die vereinbart sind, belegen. Dem TDatapacket sein Comport zuweisen.

3. Das TDatapacket schnappen, dort deine Start und End Kondition angeben (Das ist meist der einzig kniffelige Teil, je nach dem wie gut das Protokoll ist).
Wenn du aber eine Start-Kondition hast, hast du schon mal das Glück das du durch deine Struktur genau sagen kannst wie viele Byte-Daten du erwartest. Es wäre also möglich das Packet Ende durch die Package-Size zu bestimmen. Damit wäre dem erkennen des Paketes im seriellen Stream genüge getan.

Das TDatapacket könne also als Variablenname z.B. heißen wie dein Record + Datapacket.

4. Das OnPacket des TDatapacket belegen und dort auf die richtige Oberfläche wechseln.

Ich rate dir an dieser Stelle von Sir Rufos (wie immer sehr wertvollen Beiträgen) ab, empfehle dir weiterhin, eine sehr gut durchdachte und fertige Bibliothek zu nehmen. Auch wenn es sicherlich für die Programmierpraxis und den Weg deutlich besser wäre, Sir Rufos Ansatz zu verfolgen.
Das was ich beschrieben habe, kann man sich in 30 min zusammenklicken.

Gruß

akurka 27. Mai 2014 08:54

AW: Eigene Ereignisse auslösen
 
Hallo Jonas,
vielen Dank für Deine Empfehlung.
Habe zuerst mal die Bibliothek & Guide downloaded.
Die Doku ist sehr umfangreich, nun will ich mir zuerst ein Ueberblick
veschaffen. Heute mache ich sowieso nicht viel ( ist mein Trainingstag in der Kletterhalle).
Ich bin gespannt auf Dein Codebeispiel.
Es ist so, dass die Kommunikation über RS232 bei dem CNC-Bedienprogramm ein Schlüsselelement ist.
Darf ich annehmen, dass mittels AsyncPro sich die Meldungs
Records im Hintergrund abfüllen lassen,unabhhängig von uebrigem Programm ?

Das jeweils aktuelle Menü soll nur erfahren das eine neue Meldung(z.Bsp Istwert u.a.) vorhanden ist und dann anzeigen. So stelle ich es mir vor.

Bis jetzt hat man das mittels Vergleich alt/neu gemacht, ich denke mit dem
AsycPro lässt sich das aber eleganter lösen oder ?

Was das bestehende Pascal Programm macht ( den ich umschreiben will) ist ersichtlich in der Bedienungsanleitung, siehe :
http://www.antonkurka.ch/KurkaAGSeiten/Kurka_AG.htm => Bedienungsnleitung

Gruss Anton

Jonas Shinaniganz 27. Mai 2014 19:15

AW: Eigene Ereignisse auslösen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Okay also hast du die Komponenten schon installiert?
Der Rest ist soweit richtig.

Hier das Beispiel. Anhang 41263

Bei Fragen, gerne.:-D

akurka 1. Jun 2014 09:17

AW: Eigene Ereignisse auslösen
 
Hallo Jonas,
Vielen Dank für den Code Beispiel.
Etschuldige, dass ich mich so lange nicht gemeldet habe.
Im moment habe ich ein Problem mit FPGA(VHDL) der schnellstens
gelöst sein muss.
Beim ersten Durchsicht vom AsycProf suchte ich vergebens nach
"onCts" Event. Den brauche ich um nachfolgend den ersten Byte
einzulesen, weil dort die Information ist wie lang die gesamte Meldung ist.
Folgende Problem:
Zitat:

Form1 : TForm1;
// Dein Globaler Datensatz. Dein Design solltest du ändern, damit der Datensatz nicht mehr gobal ist.
// Hier könnte man den Datensatz auch einfach in die Klasse TForm verschieben
GloDatensatz : TDatensatz;
Ist es so zu verstehen, dass ich aus anderen Units(Form1,2..X) gar kein Zugriff habe auf die Meldungs Daten ?
Dann geht es so nicht, ich muss von überall die Daten der Meldungen Vergleichen / resp. Anzeigen.
Ein Event brauche ich nur für den einzigen Fall, nämlich
wenn sich der Status.ZBETR ändert. Die Daten aus anderen
Meldungen müssen nur im Hintergrund empfangen werden
und für die momentan aktive Form.. zugänglich sein.Natürlich
muss ich wissen ob sich die Daten geändert haben, aber das wird
bereits in den jeweiligen Units bereits getan.
Ich habe eine generelle Frage:
Die bisherige Programm Modulle arbeiten alle nach dem Prinzip:
repeat...
//Hier werden die empfangene Meldungen Angezeigt..
// verglichen mit div. Konstanten und fals eine Eingabe
// erfolgt, diese als Meldung über RS232 an den CNC zu //senden.
until Status.BETR = StatusAlt.Betr.
Es ist mir klar, dass dies dem Windows Konzept wiederspricht.


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:36 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz