Geschrieben July 17, 2012 at 07:3317. Jul 2012 Du sagtest du reagierst in deinem Programm dynamisch auf ab- und anstecken von Bricks an USB mittels des Enumerate Callback. Im Falle des Absteckens kommt ein Enumerate Callback mit isNew = false. Ich rate jetzt ins Blaue und sage, dass du im Callback dann die GUI Elemente für diesen Brick wieder entfernst. Oder vielleicht es auch nur aus deinem Listenfenster entfernst. Der Backtrace den glibc da ausgibt besagt, dass dein Programm gtk_widget_queue_draw aufruft. Dieser Aufruf führt im Endeffekt zu einem "double free or corruption". Typische Ursache für so etwas ist, dass du eine GTK Funktion auf einen ungültiges Pointer aufgerufen hast, oder dass GTK es dier hier übel nimmst dass du aus einem nicht-GUI Thread (dem Callback Thread) mit dem GUI interagierst.
Geschrieben July 17, 2012 at 11:2317. Jul 2012 Autor Du sagtest du reagierst in deinem Programm dynamisch auf ab- und anstecken von Bricks an USB mittels des Enumerate Callback. Ja, aber er reagiert überhaupt nicht darauf auf das ab und anstecken von Bricks m Falle des Absteckens kommt ein Enumerate Callback mit isNew = false. So habe ich es auch gedacht, es kommt aber nichts. Kein Event wird ausgelöst. Ich rate jetzt ins Blaue und sage, dass du im Callback dann die GUI Elemente für diesen Brick wieder entfernst. Oder vielleicht es auch nur aus deinem Listenfenster entfernst. Falsch geraten*G*. nein, ich fülle nur eine Liste erst einmal und mache meine Panels sichtbar, mehr nicht und das mache ich auch nicht im Event, wäre eine Gute Idee allerdings. hier mal mein Code: procedure TForm1.BitBtn1Click(Sender: TObject); // aktualisieren function FindBricklet(const aName:String):string; var i:integer; begin result:=''; for i:=0 to ListView1.Items.Count-1 do begin if Pos(aName,ListView1.Items[i].Caption) > 0 then begin result:=ListView1.Items[i].SubItems[0]; break; end; end; // for i end; // FindBricklet var str:string; Found:Boolean; begin ListView1.BeginUpdate; ListView1.Items.Clear; if Assigned(ipcon) then begin ipcon.Free; ipcon:=nil; end; ipcon:=TIPConnection.Create('localhost', 4223); ipcon.Enumerate(@EnumerateCB); sleep(100); // 100ms warten, damit die ListView gefüllt wird ListView1.EndUpdate; Found:=False; poti:=nil; t:=nil; al:=nil; lcd:=nil; Panel4.Visible:=False; Panel9.Visible:=False; Panel10.Visible:=False; Panel5.Visible:=False; Panel11.Visible:=False; Height:=Panel1.Height; str:=FindBricklet('Rotary Poti Bricklet'); if str <> '' then begin poti:=TBrickletRotaryPoti.Create(str); ipcon.AddDevice(poti); poti.OnPosition := {$ifdef FPC}@{$endif}PositionCB; poti.SetPositionCallbackPeriod(50); Label10.Caption:=IntTostr(poti.GetPosition); Panel4.Visible:=True; Panel9.Visible:=True; Found:=True; end; str:=FindBricklet('Temperature Bricklet'); if str <> '' then begin t:=TBrickletTemperature.Create(str); ipcon.AddDevice(t); t.OnTemperature:=@TemperatureCB; Label3.Caption:=Format('%f °C',[t.GetTemperature / 100]); Panel4.Visible:=True; Panel7.Visible:=True; Found:=True; end; str:=FindBricklet('Ambient Light Bricklet'); if str <> '' then begin al:=TBrickletAmbientLight.Create(str); ipcon.AddDevice(al); al.setIlluminanceCallbackPeriod(1000); al.OnIlluminance:=@AmbientLightCB; Label7.Caption:=Format('%f Lux',[al.GetIlluminance / 10]); Panel4.Visible:=True; Panel10.Visible:=True; Found:=True; end; str:=FindBricklet('LCD 20x4 Bricklet'); if str <> '' then begin lcd:=TBrickletLCD20x4.Create(str); ipcon.AddDevice(lcd); lcd.OnButtonPressed:=@ButtonPressed; lcd.OnButtonReleased:=@ButtonReleased; CheckBox1.Checked:=LCD.IsBacklightOn; lcd.WriteLine(3,0,' '); Panel5.Visible:=True; Found:=True; end; str:=FindBricklet('Distance IR Bricklet'); if str <> '' then begin dist:=TBrickletDistanceIR.Create(str); ipcon.AddDevice(dist); dist.OnDistance:=@NotifyDistance; dist.setDistanceCallbackPeriod(200); Panel4.Visible:=True; Panel11.Visible:=True; Found:=True; end; if Panel4.Visible then Height:=Height+Panel4.Height; if Panel5.Visible then Height:=Height+194; if not Found then begin ShowMessage('Kein Brick angeschlossen!'); ipcon.Free; ipcon:=nil; end; end; im besagten Event mache ich das hier: procedure TForm1.EnumerateCB(const uid: string; const aname: string; const stackID: byte; const isNew: boolean); begin with ListView1.Items.Add do begin Caption:=aname; SubItems.Add(uid); end; // with end; Typische Ursache für so etwas ist, dass du eine GTK Funktion auf einen ungültiges Pointer aufgerufen hast, oder dass GTK es dier hier übel nimmst dass du aus einem nicht-GUI Thread (dem Callback Thread) mit dem GUI interagierst. Wäre Denkbar. Aber solange es angeschlossen ist geht es Prima. Ich denke, dass der Thread nicht beendet wird, sobald es kein Gerät mehr gibt. Ich müsste mal klären ob es vielleicht an den Senoren liegt, die ja öfter Werte liefern als das LCD. Ach so, dass EnumerateCB sollte darüber informieren ob z.b. der Master Brick abgesteckt wird oder angesteckt wird.Ich konnte jedoch wie gesagt, keine Reaktion feststellen.
Geschrieben July 17, 2012 at 13:2017. Jul 2012 Ach so, dass EnumerateCB sollte darüber informieren ob z.b. der Master Brick abgesteckt wird oder angesteckt wird.Ich konnte jedoch wie gesagt, keine Reaktion feststellen. Exakt das ist die Aufgabe des Enumerate Callbacks. Nehmen wir mal dein GUI aus der Gleichung raus. Der Preview liegt eine Example.pas bei die die Verwendung des Enumerate Callbacks demonstriert. Teste doch mal bitte diese Programm. Es sollte dich über das an- und abstecken von Bricks an USB informieren.
Geschrieben July 17, 2012 at 13:4217. Jul 2012 Autor Interessantes verhalten: Wenn ich den Masterbrick abnehme, wird ein Device Remove geschrieben, wenn ich es wieder anschließe kommt ein New Device. Wenn ich jetzt jedoch einzelne Bricks abnehme oder dran stecke, bemerkt er nicht. Ich nehme an, dafür müsste ich auf den Rest Knopf drücken. Komisch, nur dass die GUI darauf anders reagiert.
Geschrieben July 17, 2012 at 13:5617. Jul 2012 Autor Gibt es noch eine andere Möglichkeit um an die Angeschlossenden Bricks zu kommen als Enumerate? Ich habe versucht, dass ganze im CallBack zu verschieben, da gab es Fehler Meldungen, wegen Multi-Thread zugriff. Das mag X leider nicht. Scheinbar. Im Moment mache ich das so, dass ich 100 ms Warte, bevor ich bevor ich die Methode(BitBtn1Click) Fortsetzte.
Geschrieben July 17, 2012 at 14:4217. Jul 2012 Wenn ich jetzt jedoch einzelne Bricks abnehme oder dran stecke, bemerkt er nicht. Ich nehme an, dafür müsste ich auf den Rest Knopf drücken. Du meinst einzelne Bricklets oder Bricks am Stack an- und abstecken, also nicht USB? Es gibt kein Hotplug im Stack. Enumerate ist nur für USB an- und abstecken.
Geschrieben July 17, 2012 at 14:4717. Jul 2012 Gibt es noch eine andere Möglichkeit um an die Angeschlossenden Bricks zu kommen als Enumerate? Ich habe versucht, dass ganze im CallBack zu verschieben, da gab es Fehler Meldungen, wegen Multi-Thread zugriff. Das mag X leider nicht. Scheinbar. Im Moment mache ich das so, dass ich 100 ms Warte, bevor ich bevor ich die Methode(BitBtn1Click) Fortsetzte. Das ist das nicht-GUI Thread Problem das ich meinte. Du kannst mit dem GUI nicht aus einem nicht-GUI Thread interagieren. Du brauchst einen Mechanismus mit dem du vom Callback Thread sauber mit dem GUI Thread interagieren kann. In Qt kann man Signal/Slot dafür benutzen, GTK wird da auch eine Lösung für haben.
Geschrieben July 17, 2012 at 16:1617. Jul 2012 Autor Du kannst mit dem GUI nicht aus einem nicht-GUI Thread interagieren. Normalerweise geht das recht gut. Schau mal hier: http://wiki.freepascal.org/Multithreaded_Application_Tutorial/de Da steht aber auch, dass die LCL nicht Thread Sicher sei.... könnte daran liegen.
Geschrieben July 25, 2012 at 12:1025. Jul 2012 Autor Wie sieht es eigentlich mit den Pascal Bindings aus?
Geschrieben July 25, 2012 at 15:0125. Jul 2012 Die sind fertig, ich habe sie gerade released. +1 Nur eine Kleinigkeit: Die Callbacks z.b. im Brickstepper sind unter private deklariert, somit sind sie für den Nachfahren unsichtbar und können nicht überschrieben bzw. erweitert werden. Ich habe z.B. in meiner Ableitung folgendes: function TBrickStepperEx.CallbackPositionReached(data:TBaseArray): Integer; begin result := inherited CallbackPositionReached(data); ... end; Die Callbacks habe ich beim Vorfahren ins protected geshifted, um dann in der Ableitung zu überschreiben: function CallbackPositionReached(data:TBaseArray): Integer; override;
Geschrieben July 25, 2012 at 16:5325. Jul 2012 Autor Warum möchtest du eigentlich von den Brick Klassen unbedingt ableiten?
Geschrieben July 25, 2012 at 19:5525. Jul 2012 Meine Anwendung lässt sich prima mit den neuen Bindings kompilieren und ausführen. Einziger Showstopper: TThread.CurrentThread im IpConnection.Destroy ist in Delphi 7 unbekannt. PS: Wieso hast du statt den Out-Parameter nicht Records verwendet ?
Geschrieben July 26, 2012 at 10:0026. Jul 2012 @TF TThread.CurrentThread gibt es erst seit Delphi2009. Ersatzweise kann man aber auch Windows.GetCurrentThreadId <> callbackThread/receiveThread.ThreadId ähnlich wie im FPC Teil setzen. Wäre schön wenn diese beiden Zeilen angepasst werden könnten und die Callbacks unter protected wandern. Ansonsten kann ich die Bindings ohne Anpassungen nicht unter meine Kapselung legen.
Geschrieben July 26, 2012 at 16:5026. Jul 2012 Das mit TThread.CurrentThread habe ich nicht bemerkt, da ich hier mit Delphi XE2 getestet habe. Ist jetzt korrigiert. Die Callback Wrapper sind jetzt protected und virtual.
Geschrieben August 6, 2012 at 09:426. Aug 2012 Den Pascal-Bindings fehlt noch die Docu/Kommentare im SourceCode. Da kann man eigentlich analog zu den C#-Bindings verfahren und deren Doku ohne Einschränkungen in die Pascal-Bind. kopieren. Ab Delphi2006 wird XML-CodeDocu. wie in .NET unterstützt.
Geschrieben August 6, 2012 at 11:246. Aug 2012 Ah, das war mir nicht bewusst, dass da C# XML Doku geht. Ist auf die TODO Liste gesetzt.
Geschrieben September 26, 2012 at 14:3126. Sep 2012 Delphi Bindings 1.0.4 haben jetzt Inline Code Dokumentation.
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.