AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Jobliste Kommunikation mit externem Gerät

Ein Thema von DelphiManiac · begonnen am 17. Nov 2006 · letzter Beitrag vom 23. Nov 2006
Antwort Antwort
Seite 1 von 2  1 2      
DelphiManiac

Registriert seit: 5. Dez 2005
742 Beiträge
 
#1

Jobliste Kommunikation mit externem Gerät

  Alt 17. Nov 2006, 15:15
Hallo,

ich bin zurzeit dabei eine Software für ein externen Gerät zu entwickeln.
Dieses Gerät kann sowohl seriell über RS232 als auch USB angesteuert werden angesteuert.
Als USB-Controller ist ein FTDI FT232BM eingebaut.

Nun meine Frage, ich kommuniziere mit dem Gerät folgendermaßen:
Ich habe ein Objekt vom Typ (TGeraet)

Geraet.GetStatus(Status:boolean);
Geraet.GetMesswert(Status:boolean);

Jede Funktion durchläuft bei mir ein Kommunikationsmodul,
dass zB.:
-->den Buffer mit dem Befehl füllt.
-->den Befehl abschicken
-->auf eine Antwort warten (pollen bis 7 Bytes am Port sind)
-->falls 7 Bytes da sind, diese vom Port lesen und bewerten
-->wenn nach einer bestimmten Zeit keine Antwort dann, rausspringen mit Fehlermeldung

Diese Kommunikation läuft bei mir nun im Hauptthread und wenn ich mehrer Befehle (GetXYT, SetSeriennummer....)
ausführe, dann hängt meine Anwendung zeitweise.
Ich habe versucht diese in einen extra Thread zu packen, denn ich von aussen anstosse, aber irgendwie klappt das nicht wie gewollt. Habe auch schon Luckies Tutorial zum Thema Thread gelesen.
Ich würde gerne eine Art Jobliste machen, die in einem Thread abläuft und immerwieder die Jobs (GetXYZ...) abarbeitet
und ich sie von aussen fülle.

Beispiel:
Joblist.Add(Get_YXZ)
Joblist.Add(SetSeriennummer('SN9090');

so dass ich Design von Logik trennen kann und es in einem extra Joblist Thread abläuft.

Hoffentlich könnt ihr mir dabei helfen...
Danke schonmal im Vorraus!!!

Gruß
DelphiManiac
  Mit Zitat antworten Zitat
Reinhard Kern

Registriert seit: 22. Okt 2006
772 Beiträge
 
#2

Re: Jobliste Kommunikation mit externem Gerät

  Alt 18. Nov 2006, 02:34
Zitat von DelphiManiac:
Hallo,

ich bin zurzeit dabei eine Software für ein externen Gerät zu entwickeln.
Dieses Gerät kann sowohl seriell über RS232 als auch USB angesteuert werden angesteuert.
Als USB-Controller ist ein FTDI FT232BM eingebaut.

Nun meine Frage, ich kommuniziere mit dem Gerät folgendermaßen:
Ich habe ein Objekt vom Typ (TGeraet)

Geraet.GetStatus(Status:boolean);
Geraet.GetMesswert(Status:boolean);

Jede Funktion durchläuft bei mir ein Kommunikationsmodul,
dass zB.:
-->den Buffer mit dem Befehl füllt.
-->den Befehl abschicken
-->auf eine Antwort warten (pollen bis 7 Bytes am Port sind)
-->falls 7 Bytes da sind, diese vom Port lesen und bewerten
-->wenn nach einer bestimmten Zeit keine Antwort dann, rausspringen mit Fehlermeldung

Diese Kommunikation läuft bei mir nun im Hauptthread und wenn ich mehrer Befehle (GetXYT, SetSeriennummer....)
ausführe, dann hängt meine Anwendung zeitweise.
Ich habe versucht diese in einen extra Thread zu packen, denn ich von aussen anstosse, aber irgendwie klappt das nicht wie gewollt. Habe auch schon Luckies Tutorial zum Thema Thread gelesen.
Ich würde gerne eine Art Jobliste machen, die in einem Thread abläuft und immerwieder die Jobs (GetXYZ...) abarbeitet
und ich sie von aussen fülle.

Beispiel:
Joblist.Add(Get_YXZ)
Joblist.Add(SetSeriennummer('SN9090');

so dass ich Design von Logik trennen kann und es in einem extra Joblist Thread abläuft.

Hoffentlich könnt ihr mir dabei helfen...
Danke schonmal im Vorraus!!!

Gruß
DelphiManiac
Hallo,

was du als erstes brauchst, ist eine Statusmaschine für jeden Job, etwa in der Art:

Idle - SendHeader - Senddata - SendCRC - WaitforAnswer - RecvHeader - RecvData - RecvCRC

die Events verzweigen dann je nach Status und UnterStatus, z.B. RecvCRC -> CRCByte1, CRCByte2, CRCByte3, CRCByte4, hier werden die CRCs geprüft und wenn Ok -> Idle, usw. usw.

Die Jobliste kann dann den nächsten Job anleiern, wenn der Zustand Idle ist, indem sie das erste Byte in das Transmit Register schreibt und den Zustand auf SendHeader setzt, oder indem sie einen String übergibt (mit Header,Daten,CRC) und einen Writebefehl ans Com-Port schickt und den Status auf Sending setzt - ganz wie das System es erfordert.

Die Statusmaschine(n) sorgen dann selbst dafür, dass ein Job komplett abgewickelt wird, solange kein Fehler auftritt. Zweckmässig ist es, das ganze in eine Matrix aufzunehmen bzw. in eine Sprungtabelle, dann kann man auch keine Kombination vergessen:
Delphi-Quellcode:
  (zur besseren Formatierung)

Event-> Char Sent Char Recvd V24Error Timeout

Status:
Idle ??? ??? ??? ??? {should not happen}

SendHeader next Char rep Error rep Error rep Error
             Header done? -> Idle -> Idle -> Idle
             y->SendData

SendData next Char rep Error rep Error rep Error
             Data done? -> Idle -> Idle -> Idle
             y->SendCRC

.....
unvollständig, ich hoffe man erkennt das Prinzip. Zweckmässig ist eine Tabelle mit einer Routine für jede Kombination aus Status und Event. Die ist zugleich eine gute Dokumentation, auch genormte Protokolle werden vorzugsweise mit Statusmaschinen beschrieben.

Gruss Reinhard
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#3

Re: Jobliste Kommunikation mit externem Gerät

  Alt 18. Nov 2006, 11:05
Zitat von DelphiManiac:
Ich habe versucht diese in einen extra Thread zu packen, denn ich von aussen anstosse, aber irgendwie klappt das nicht wie gewollt. Habe auch schon Luckies Tutorial zum Thema Thread gelesen.
Ich würde gerne eine Art Jobliste machen, die in einem Thread abläuft und immerwieder die Jobs (GetXYZ...) abarbeitet
und ich sie von aussen fülle.
Hi,
klingt ein wenig so, als ob etwas dabei nicht ganz geklappt hat (schließe ich aus klappt nicht wie gewollt), aber du sagst nicht was genau anders läuft. Wäre schön wenn du also noch sagen würdest, was du probiert hast und was dabei passiert ist.

An sich denke ich kannst du hier einfach einen Thread nehmen, der eine Methode besitzt, mit der ihm von außen Jobs hinzugefügt werden und ggf. natürlich einer weiteren, die Ergebnisse nach außen reicht.
Dazu wäre der imho sauberste Weg, dass du eine abstrakte Klasse Job schaffst, die einfach eine Methode zum abarbeiten des Jobs besitzt. Ist diese Methode abstrakt, kann jeder Nachfahre sie beliebig implementieren. Der Vorteil ist damit natürlich, dass diese Liste für jede Art von Job geeignet ist.
Die Jobs kannst du dann im Thread in einer TObjectList speichern. Im einfachsten Fall besteht dann die Execute-Methode des Threads einfach nur in einer Endlosschleife, die schaut ob die Job-Liste leer ist und sonst den ersten Job (oder dringensten oder oder) Job aus der Liste nimmt und ausführt. Ok, das Pollen ist an der Stelle nicht so schön, da könntest du sicher auch mit Signalen arbeiten, aber für einen ersten Test dürfte es reichen. Später dann einfach den Thread schlafen legen, so dass der auf ein Signal reagiert, dass du immer dann setzt, wenn du etwas in die Liste einfügst.

Beim einfügen in die Liste solltest du dann unbedingt synchronisieren. Also hier meine ich die Verwendung eines Sperrobjekts, da du insbesondere beim pollen sonst das Problem bekommen kannst, wann ein Objekt eingefügt wurde und wann die Abfrage nach dem Füllstand der Liste erfolgt.

Hoffe ist grob klar, wie ich das meine. Letztlich wäre es aber wichtig zu wissen, was du bisher versucht hast und woran du eigentlich wirklich scheiterst um dir zu helfen. Deshalb erstmal nicht mehr dazu, frag einfach noch mal genauer nach

Gruß Der Unwissende
  Mit Zitat antworten Zitat
DelphiManiac

Registriert seit: 5. Dez 2005
742 Beiträge
 
#4

Re: Jobliste Kommunikation mit externem Gerät

  Alt 21. Nov 2006, 10:03
Hallo erstmal super vielen Dank @Reinhard Kern und @Der_Unwissende !!!

@Reinhard Kern:
Das mit der Statusmaschine ist mir leider nicht so ganz klar geworden wie ich soetwas umsetzte


@Der_Unwissende
Danke für deine ausführliche(n) Antwort(en)!!

Nunja ich weiss ehrlich gesagt nicht wie ich so eine Jobliste erstellen soll.
TObjectlist ist ja eine Klasse, die Zeiger speichert, sehe ich doch richtig, oder?

Wenn ich nun meiner Objektliste vom Typ TObjeclist eine Funktion übergeben will, wie mache ich dass denn?
Objekliste.Add(Set_Serialnumber('SeriennummerXYZ'));

Ich habe es zurzeit recht statisch gelöst, aber bin nicht sehr glücklich drüber.

Mein Thread arbeitet statische Lese Methoden ab, je nach Parameter, den ich von aussen vorgebe.

Wenn ich dann eine Schreiboperation abgebe, dann stoppe ich den Thread vorher und lasse ihn dann weiterlaufen. (Dass finde ich sehr unschön)

folgenden Thread-Code habe ich bisher:

Delphi-Quellcode:
procedure TWorkThread.Execute;
(* ----------------------------------------- *)
var
  com: Integer;
  Identifier: Integer;
  I: Integer;
begin
  { Thread-Code hier einfügen }
// FSTKObj.OnCommunicate:=UpdateCaption;
  isStopped:=false;
  FSTKObj.Get_Device_Identify (Identifier);
{ TODO : LÖSCHEN }
  Identifier:=1000;
  while NOT(Terminated) do
  begin
    fCS.Enter;
      LeseZyklischeDaten;
    fCS.Leave;

  case FCommand of
    STOPP_THREAD:
      begin
        isStopped:=true;
        Self.Suspend;
// isStopped:=false;
      end;
    READ_HERSTELLERDATEN :
      begin
        Synchronize(ZeigeSandUhr);
        LeseStammdaten;
        Synchronize(UpdateStammdaten);
        if ((FSTKObj.IsMulti) or (FSTKObj.IsMaster)) then
        begin
          fCS.Enter;
          LeseStammdatenMaster;
          Synchronize(UpdateStammdatenMaster);
          fCS.Leave;
        end;
        Synchronize(VersteckeSandUhr);
      end;
    READ_ANALOGOUT :
      begin
        fCS.Enter;
        FSTKObj.Set_CalConfig(false);
        try
          fCS.Enter;
          FSTKObj.Set_CalibDaten(frmMain.editKalibrierwert.Value);
          fCS.Leave;
        except
          fCS.Leave;
          FSTKObj.Set_CalibDaten(0);
        end;
....
Abhängig von FCommand führe ich meine Lesebefehle aus.

Aber ich will ja so eine schöne Jobliste,
der ich auch Schreiboperationen mit Parameter übergabe aus dem Hauptthread übergeben kann.

Vielleicht kannst du mir ja mal ein Code Schnippsel schreiben, wäre super, stehe nämlich ganz schön aufm Schlauch.

DANKE!!!
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#5

Re: Jobliste Kommunikation mit externem Gerät

  Alt 21. Nov 2006, 10:32
Zitat von DelphiManiac:
TObjectlist ist ja eine Klasse, die Zeiger speichert, sehe ich doch richtig, oder?
Nicht ganz. Also ist nicht direkt falsch, aber es sind sehr spezielle Zeiger. Du speicherst vielmehr Referenzen. Eine Referenz ist ein Zeiger auf ein Objekt, und damit halt immer auf einen Nachfahren von TObject. Jedes Objekt muss damit z.B. die Methode Free besitzen, so dass diese Liste den Speicher der Elemente in ihr auch selbst frei geben kann, wenn sie zerstört wird.

An sich ist hier dann die Idee, dass du dir einfach ein Abstraktes BasisObjekt schaffst.

Delphi-Quellcode:
type
  TBaseJob = class(TObject)
    public
      procedure doJob; virtual; abstract;
  end;
Dieses Objekt hat eine Methode doJob, die hier aber abstrakt (nicht implementiert) ist. Du hast somit nur festgelegt, dass jeder Nachfahre eine solche doJob Methode besitzen muss, die irgendwie implemntiert werden kann.
Damit hast du auch schon die Basis für alle Jobs:

Delphi-Quellcode:
type
  TStopJob = class(TBaseJob)
    public
      procedure doJob; override;
  end;

  TReadHerstellerDatenJob = class(TBaseJob)
    public
      procedure doJob; override;
  end;

...

procedure TStopJob.doJob;
begin
  // konkrete Implementierung
end;
...
Ok, soweit hast du erstmal nur eine Menge von Klassen und vielleicht auch eine Menge an Overhead. Wo liegt jetzt also der Sinn? Ganz einfach, du kannst nun eine Liste von TBaseJobs verwalten. Vererbung kann in der Programmierung auch als Erweiterung oder Spezialisierung beschrieben werden. TStopJob und TReadHerstellerDatenJob sind Erben von TBaseJob. Das heißt, dass sie mindestens dass können, was auch TBaseJob kann. Du kannst sie also auch als TBaseJob behandeln. So kann dein TStopJob noch 10 weitere Funktionen haben, behandelst du ihn als TBaseJob, kannst du nur auf die Funktion doJob zugreifen (weil das alles ist, was ein TBaseJob hat). Diese Funktion kann aber natürlich auf alle anderen Funktionen von TStopJob zugreifen und alle Variablen lesen (usw).

So, nun erzeugst du zu einfach die speziellen Jobs, die du benötigst und tust die in eine TObjectList. Die TObjectList speichert hier alles was du reintust als TObject ab. Wenn du also einen Job rausnimmst, musst du ihn casten. Da für alle Jobs eine Basis existiert, castest du in ein TBaseJob (muss für alle Jobs klappen) und rufst von diesem TBaseJob die Methode doJob auf. Damit ist es egal was für einen Job du gerade aus der Liste genommen hast, du musst keine Details über diesen Job kennen, du weißt dass er eine Methode doJob hat und die verwendest du:

Delphi-Quellcode:
// hinzufügen von neuen Jobs:
self.objectList.Add(TStopJob.Create(...));
self.objectList.Add(TReaderHerstellerAngabenJob.Create(...));
self.objectList.Add(TStopJob.Create(...));
...
Delphi-Quellcode:
var buffer : TBaseJob;
// Abarbeitung der Jobs
while (self.objectList.Count > 0) do
begin
  buffer := TBaseJob(self.objectList[0]);
  buffer.doJob;

  self.ojectList.remove(0); // hier musst du schauen ob die Funktion so heißt, kann auch delete sein
end;
Ja, ist jetzt hier etwas aus eine bestimmten Prozedur rausgenommen, aber ich hoffe die Idee ist so klar.
Die eigentliche Implementierung, wie man einen Job stoppt oder eben hinzufügt steckt nun in den Hüllklassen (Wrapper), hier wären dass TStopJob usw. Die beerben alle eine Basisklasse, die einfach die Signatur einer Methode festlegt, die alle Nachfahren besitzen müssen.
Die JobListe macht wiederum nichts anderes als den ersten enthaltenen Job zu entnehmen und abzuarbeiten. Was für ein Job das genau ist, ist der Liste egal. Die Logik steckt in der Instanz, die diese Methode überschrieben hat.
Diese Vorgehensweise entspricht ein wenig dem Kommando-Pattern.

Gruß Der Unwissende
  Mit Zitat antworten Zitat
DelphiManiac

Registriert seit: 5. Dez 2005
742 Beiträge
 
#6

Re: Jobliste Kommunikation mit externem Gerät

  Alt 21. Nov 2006, 11:34
@Der_WISSENDE

Hallo, cool, was für eine schnell (und noch dazu ausführliche Antwort)!!

Habe den Ansatz mit den verschiedenen JobKlassen verstanden,

also es gibt eine BasisJobKlasse, die eine nicht implementierte doJob Methode besitzt.
Diese wird in den abgeleiteten Klassen implementiert.

Meine Frage ist jetzt folgende:
ich habe ja eine Klasse die ungefähr 50-60 Kommunikationsmethoden implemetiert:
Beispiel:
Delphi-Quellcode:
TGeraet.Get_Temperatur(var Temp:integer);
TGeraet.Set_Temperatur(Temp:integer);
TGerat.Get_SerialNumber(var SN:String);
TGeraet.Set_SerialNumber(SN:String);
Wie soll ich nun meinem Job sagen, dass er die Funktion Set_Temperatur ausführen soll?
Sollte ich eine Parameterübergabe ( ich benötige ja den Parameter Temp, da ich ihn ja an die Funktion übergeben muss)
per Konstruktor machen, oder wüsstest du eine bessere Methode?

ich habe einige Jobs, die immer (zyklisch) ausgeführt werden müssen, wie z.B.: dass Lesen der Messwerte,
hast du eine Ahnung, wie ich das am besten bewerkstellige, sollte ich einen Timer laufen lassen, der die Jobliste dann wieder und wieder mit dem gleichen Job füllt?

Vielen Dank schonmal für deine Mühe!!
Gruß
DelphiManiac
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#7

Re: Jobliste Kommunikation mit externem Gerät

  Alt 21. Nov 2006, 12:08
Zitat von DelphiManiac:
Wie soll ich nun meinem Job sagen, dass er die Funktion Set_Temperatur ausführen soll?
Sollte ich eine Parameterübergabe ( ich benötige ja den Parameter Temp, da ich ihn ja an die Funktion übergeben muss)
per Konstruktor machen, oder wüsstest du eine bessere Methode?
Also ich würde es einfach über einen Konstruktor machen. Ist der imho einfachste Weg und ich sehe da keinen Nachteil gegenüber anderen Möglichkeiten.

Zitat von DelphiManiac:
ich habe einige Jobs, die immer (zyklisch) ausgeführt werden müssen, wie z.B.: dass Lesen der Messwerte,
hast du eine Ahnung, wie ich das am besten bewerkstellige, sollte ich einen Timer laufen lassen, der die Jobliste dann wieder und wieder mit dem gleichen Job füllt?
Hm, klingt auch gut. Also ich meine es ist definitiv ein funktionierender Ansatz, würde ich auch so machen. Sehr viel schönere Lösungen würden mir auch hier nicht einfallen.
  Mit Zitat antworten Zitat
DelphiManiac

Registriert seit: 5. Dez 2005
742 Beiträge
 
#8

Re: Jobliste Kommunikation mit externem Gerät

  Alt 21. Nov 2006, 12:46
@Der_Unwissende:

Ist die TObjectlist denn Threadsafe, habe nämlich bei der Ausführung ein paar Probleme.

Danke.
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#9

Re: Jobliste Kommunikation mit externem Gerät

  Alt 21. Nov 2006, 12:53
Zitat von Der_Unwissende:
Beim einfügen in die Liste solltest du dann unbedingt synchronisieren. Also hier meine ich die Verwendung eines Sperrobjekts, da du insbesondere beim pollen sonst das Problem bekommen kannst, wann ein Objekt eingefügt wurde und wann die Abfrage nach dem Füllstand der Liste erfolgt.
Um mich mal selbst zu zitieren. Nein, es ist natürlich überhaupt nicht Threadsafe!!! Hätte ich noch mal deutlicher sagen sollen, als ich die Beispiele gepostet habe. Du musst bevor du ein Objekt in die Liste einfügst oder eines entnimmst unbeding ein Speerobjekt verwenden (z.B. TCriticalSection) und wenn du aus dem Thread auf VCL-Komponenten zugreifst, dann musst du dies synchronisieren (im Delphi-Sinne, die Methode synchronize verwenden).
  Mit Zitat antworten Zitat
DelphiManiac

Registriert seit: 5. Dez 2005
742 Beiträge
 
#10

Re: Jobliste Kommunikation mit externem Gerät

  Alt 21. Nov 2006, 13:01
Hi,

Ja das mit dem Sperrobjekt habe ich mir gedacht.

Reicht es wenn ich ein Sperrobjekt lokal erzeuge (wahrscheinlich nicht, oder)?
oder muss es über jede Unit eingebunden sein?

Wo genau im Code deklariert man denn am besten so ein Sperrobjekt (bzw die CriticalSection).

Danke schonmal
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:40 Uhr.
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