ein mekrwürdiges Problem

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Antworten
siro
Beiträge: 490
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 10
CPU-Target: 64Bit
Wohnort: Berlin

ein mekrwürdiges Problem

Beitrag von siro »

Hallo zusammen,

Wohin mit dem Problem ? also einfach mal hier rein:

Ich programmiere grade eine Software für meine elektronische Last KEL103 von KORAD.
Das Gerät kann mittels SCPI Kommandos ferngesteuert werden.
Dies tätige ich mittels RS232 (Juchu...Ich hab sowas noch auf meinem Motherboard.... :mrgreen: )
Läuft aber auch über den USB des Gerätes (als virtuellen Comport COM8).

Die Grundfunktionen, Kommandos, sind jetzt gut getestet und laufen.
über den virtuellen Comport genauso wie über die originale RS232.

Nun möchte ich den Batterietestmodus überwachen, bzw. beim Entladen eines Akkus die Spannungskurve aufzeichnen und in "Echtzeit" darstellen.
Das Gerät soll mir also kontinuierlich die aktuelle Spannung zurück senden.

Da stellt sich schon das erste Problem: "kontinuierlich"
Mit kontinuierlich meinte ich eigentlich Zeitsynchron, aber das gibt es nicht wenn man ein Betriebssystem hat.

Beim TTimer habe ich eine minimalsten Intervall von 16 Millisekunden gemessen, egal was ich da einstelle.
Mal abgesehen davon, dass er Parkinson hat, das habe ich mir mit dem Oszilloskop angesehen...

Vor einige Zeit hatte ich mir aber schon eine Timer Komponente mittels MMSystem unter Windows gebaut und diese
funktioniert wesentlich genauer. (Meistens :roll: )

Wie dem auch sei, beim experimentieren habe ich nun mehrfach einen Fehler erhalten, den ich irgendwie garnicht zuordnen kann:

Siehe Bild:
e_01.jpg
e_01.jpg (15.1 KiB) 548 mal betrachtet
dann der "merkwürdige" Code dazu:
E02.jpg
E02.jpg (125.62 KiB) 548 mal betrachtet
Der Fehler tritt meist so nach 14000 Messwerten auf, was natürlich ärgerlich ist, da war ich mitten in der Akkuentladung....

Meinen Code jetzt hier rein zu packen gibt meiner Meinung nach nicht wirklich Sinn, da hier so ziemlich alles aus eigenen
Komponenten besteht. Timer, Serielle, Kurvendarstellung...

Mich wundert nur wo der Fehler herkommt und so habe ich natürlich schon so Einges getestet
und dann lief es doch plötzlich über eine halbe Milion Meßwerte völlig einwanfrei.
Nach 600.000 Messungen (hab ich dann abgebrochen) und mehrfachen Akkutest ausgeführt, das Problem "scheint" behoben.

Das Wort "Scheint" gibt es aber bei mir nicht, also guckte ich, was ich denn verändert habe.
Eigentlich habe ich nur eine unnötige Testzeile ausgeklammert.

Also wieder rein damit und prüfen.
Jo, wieder Absturz :shock:

Die vermeintliche Testzeile ist folgende:
Form_Main.Label_Voltage.caption:=data;

klammere ich die aus, geht es einwandfrei, ist sie drin kommt ein zeitnaher Absturz.

Das Programm läuft jetz grad wieder schon seit 2 Stunden (800.000 Messwerte) völlig ohne Probleme ohne dieser Zeile
ich kann auch nebenbei im Internet surfen usw. Kein Problem.
So läuft das Programm grade weiter, während ich euch grade hier schreibe.

Das verblüffende ist ja, dass ich die "vermeintliche" Absturzzeile ähnlich sogar ein zweites Mal ausführe,
was aber anscheinend kein Problem darstellt. Oder umgekehrt, wenn ich zweimal auf den Label zugreife gibt es ein Problem ???
Deshalb mal doch noch etwas Code:

Code: Alles auswählen

//---------------------------------------------------------------------------
// Hier wird der Empfangsstring ausgewertet und zugeordnet
// Meine Vermutung: hier sollten keine Zugriffe auf andere Komponenten erfolgen,
// das führt unter Umständen zu abstürzen.
// der übergebene String hat bei Messwerten die Form : '1.2345V'
// das V für Volt wird rausgebastelt und der Wert in einen Float gewandelt und in den Kurvenspeicher übertragen

procedure DispatchRx(data:String);
var value:single; res:integer;
begin
  if length(data) = 0 then exit;      // Leerstring ignorieren
  case DataMode of
    Data_Unknown  : ;
    Data_Voltage  : begin

//                    Form_Main.Label_Voltage.caption:=data;   // <==== Problem, merkwürdiger Absturz ???

                      val(data,value,res);                     // versuchen in Zahl zu wandeln
                      if res > 0 then begin                    // hat nicht geklappt, dann
                        data:=copy(data,1,length(data)-1);     // den String kopieren bis zum falschen Character
                      end;                                     // damit sollte das "V" für Voltage verschwunden sein
                      val(data,value,res);                     // Die Zahlenwandlung sollte nun klappen
                      Form_Main.Label_Voltage.caption:=data;   // <===== hier gibt es KEINE Probleme ?????
                      Form_Curve.Curve1.Add(value);            // den Wert in den Kurvenspeicher übernehmen
                    end;
    Data_Current  : ;
    Data_Input    : ;
    Data_Capacity : Form_Main.Label_Capacity.caption:=data;
    Data_Time     : Form_Main.Label_Time.caption:=data;
    Data_Ident    : Form_Main.Label_DeviceIdent.caption:=data;
  end;
end;
//------------------------------------------------------------------------------------------
// wird von meiner seriellen Komponente aufgerufen, wenn sich Daten im Receivepuffer befinden
// hier wird solange der "globale" RxStr String zusammengesetzt bis ein LineFeed auftaucht
// dann wird dieser String der Procedure DispatchRx übergeben
procedure TFormMain.SerialRxData(RxCount: cardinal; TxCount: cardinal;
  Error: DWORD);
var b:char;
begin
  while RxCount > 0 do begin
    Serial.ReadByte(b);             // ein Byte aus dem Empfangspuffer laden
    dec(RxCount);                   // Anzahl empfangener Bytes -1
    if b = ' ' then continue;       // Leerzeichen ignorieren
    if b = chr($0D) then continue;  // Carriage Return ignorieren
    if b = LineFeed then begin      // Endezeichen ($0A) erkannt, Empfangsstring ist komplett
      DispatchRx(RxStr);
//      ListBox1.Items.Add(RxStr);  // Den String nun verarbeiten, speichern oder was auch immer
      RxStr:='';                    // !! muss sein, weil evtl. mehrere Strings getrennt mit LF existieren
    end else begin
      if length(RxStr) < 50 then RxStr:=RxStr+b    // Empfangszeichen hinten anhängen, length Abfrage nur testweise
                            else Halt;             // passierte nie auch nicht nach 600.000 Messwerten
    end; // else
  end;
end;               
Wenn Ihr Ideen zu diesem Problem habt, würde ich mich über eine Rückmeldung freuen.
Übrigens was ist denn das für eine merkwürdige Softwarezeile in der Unit LazTracer ???

Siro
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

sstvmaster
Beiträge: 481
Registriert: Sa 22. Okt 2016, 23:12
OS, Lazarus, FPC: W10, L 2.0.12
CPU-Target: 32+64bit
Wohnort: Dresden

Re: ein mekrwürdiges Problem

Beitrag von sstvmaster »

Ein Bug der doch noch drin ist? -> https://bugs.freepascal.org/view.php?id=36786

Oder die unti heaptrc in den uses? -> https://forum.lazarus.freepascal.org/in ... ic=45561.0
Windows 10, Lazarus 2.0.12 + Lazarus Trunk (main)
LG Maik

Benutzeravatar
Winni
Beiträge: 980
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.0.12, fpc 3.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: ein mekrwürdiges Problem

Beitrag von Winni »

Hallo!

Ich bin auch schon mal an diesem ominösen Stück Code gelandet.
Nach langem Gesuche stellte sich raus, dass das Autosize von Komponenten einen unendlichen Loop veranstaltete.

Nachdem ich das bei einigen Komponenten abgestellt hatte, war der Spuk vorbei.

Winni

siro
Beiträge: 490
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 10
CPU-Target: 64Bit
Wohnort: Berlin

Re: ein mekrwürdiges Problem

Beitrag von siro »

Ersteinmal vielen Dank für die Rückmeldungen:

@sstvmaster:
ich habe mir die LINKs mal angesehen.

Ich glaube das geht in die richtige Richtung mit dem Fehler.
Meine Vermutung und einige Experimente sind schon länger der Meinung,
dass die Windows Callback Funktionen nicht unbedingt kompatibel mit dem Verhalten vom Lazarus (speziell dem .Canvas) sind.

Der DC (Device Context) im Windows System scheint eine recht komplexe Angelegenheit zu sein.
Zugriffe dürfen natürlich auch nur erfolgen, wenn der HDC (Handle) gültig ist.
Ein TLabel (bzw. generell abgeleitetet Komponenten von TGrahicControl) haben aber gar keinen DC sondern benutzen den DC des übergeordneten Fensters,
sofern ich das bisher verstanden habe.

Zugriffe auf Caption des Formulars hingehgen scheinen kein Problem darzustellen, warum auch immer....

Daher liegt es also recht nahe, dass ein Problem durch meinen MMSystem Timer entstehen kann,
der mal mehr oder weniger in Erscheinung tritt.

Eventuell muss man das irgendwie synchronisieren wie bei Thread.Sychronize
Zumindest sollte ich bei OnTimer vom MMSystem Timer dann keine Zugriffe tätigen die im Zusammenhang mit dem canvas stehen.
Ich werde dazu gleich nochmal einige Versuche tätigen.

@Winni:
Das ist mir auch schon passiert mit dem Autosize, sogar bei meiner eigenen Kompontente.
Wenn ich width setze sollte Height angepasst werden, wenn dann heigth angepasst wurde....
Gibt ne hübsche Rekursion....Kann und MUSS man natürlich abfangen.

Aktuelle Lage:
Ein Dauertest über Nacht läuft jetzt schon über 15 Stunden, insgesamt 5,5 Millionen Messwerte empfangen und gespeichert.
Alles einwandfrei.

Ich breche jetzt ab und werde andere Versuche starten.

Siro
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

siro
Beiträge: 490
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 10
CPU-Target: 64Bit
Wohnort: Berlin

Re: ein mekrwürdiges Problem

Beitrag von siro »

Jo, da issa: genau der gleiche Fehler.

Ich habe mit einem "minimal Programm" den Fehler provozieren können:

Mein Timer und 2 Label die im 1ms Takt aktualisiert werden.

Mit einem Label ging das noch.
Mit dem zweiten vorerts auch.
dann haben beide einen anderen Font bekommen
und dann tritt der Fehler recht schnell auf.

Wieder LazTracer Line 50.

Dann ist das Problem jetzt eindeutig identifiziert und ich werde gegensteuern.

Neue Lösung:

in meiner eigenen Windows Timer Komponente bei OnTimer werden jetzt nur noch "globale Strings" gesetzt, nicht mehr die Labels selber.
Aufs Formular kommt ein zusätzlicher TTimer aus der Palette System.
Bei diesem zusätzlichen OnTimer werden die globalen Strings an die Labels.caption übergeben.
Das funktioniert einwandfrei. Ich kann den TTimer, bei Bedarf, auch wesentlich langsamer laufen lassen 100ms reichen ja auch
weil das sind immer noch 10 Aktualisierungen pro Sekunde, es geht aber auch problemlos wenn ich den TTimer auf 1ms setzte.

Mein "präziserer" MMSystem Timer steuert also nur noch die serielle Abfrage, den Zeittakt für die Messwertabfrage vom Gerät.

Siro
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Antworten