photron Geschrieben July 17, 2012 at 07:33 Geschrieben July 17, 2012 at 07:33 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. Zitieren
pluto Geschrieben July 17, 2012 at 11:23 Autor Geschrieben July 17, 2012 at 11:23 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. Zitieren
photron Geschrieben July 17, 2012 at 13:20 Geschrieben July 17, 2012 at 13:20 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. Zitieren
pluto Geschrieben July 17, 2012 at 13:42 Autor Geschrieben July 17, 2012 at 13:42 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. Zitieren
pluto Geschrieben July 17, 2012 at 13:56 Autor Geschrieben July 17, 2012 at 13:56 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. Zitieren
photron Geschrieben July 17, 2012 at 14:42 Geschrieben July 17, 2012 at 14:42 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. Zitieren
photron Geschrieben July 17, 2012 at 14:47 Geschrieben July 17, 2012 at 14:47 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. Zitieren
pluto Geschrieben July 17, 2012 at 16:16 Autor Geschrieben July 17, 2012 at 16:16 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. Zitieren
pluto Geschrieben July 25, 2012 at 12:10 Autor Geschrieben July 25, 2012 at 12:10 Wie sieht es eigentlich mit den Pascal Bindings aus? Zitieren
photron Geschrieben July 25, 2012 at 12:55 Geschrieben July 25, 2012 at 12:55 Die sind fertig, ich habe sie gerade released. Zitieren
pluto Geschrieben July 25, 2012 at 13:00 Autor Geschrieben July 25, 2012 at 13:00 Prima. Noch gar nicht gesehen. Zitieren
Nic Geschrieben July 25, 2012 at 15:01 Geschrieben July 25, 2012 at 15:01 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; Zitieren
pluto Geschrieben July 25, 2012 at 16:53 Autor Geschrieben July 25, 2012 at 16:53 Warum möchtest du eigentlich von den Brick Klassen unbedingt ableiten? Zitieren
Nic Geschrieben July 25, 2012 at 19:55 Geschrieben July 25, 2012 at 19:55 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 ? Zitieren
Nic Geschrieben July 26, 2012 at 10:00 Geschrieben July 26, 2012 at 10:00 @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. Zitieren
photron Geschrieben July 26, 2012 at 16:50 Geschrieben July 26, 2012 at 16:50 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. Zitieren
Nic Geschrieben August 6, 2012 at 09:42 Geschrieben August 6, 2012 at 09:42 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. Zitieren
photron Geschrieben August 6, 2012 at 11:24 Geschrieben August 6, 2012 at 11:24 Ah, das war mir nicht bewusst, dass da C# XML Doku geht. Ist auf die TODO Liste gesetzt. Zitieren
photron Geschrieben September 26, 2012 at 14:31 Geschrieben September 26, 2012 at 14:31 Delphi Bindings 1.0.4 haben jetzt Inline Code Dokumentation. Zitieren
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.