photron Posted July 17, 2012 at 07:33 AM Posted July 17, 2012 at 07:33 AM 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. Quote
pluto Posted July 17, 2012 at 11:23 AM Author Posted July 17, 2012 at 11:23 AM 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. Quote
photron Posted July 17, 2012 at 01:20 PM Posted July 17, 2012 at 01:20 PM 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. Quote
pluto Posted July 17, 2012 at 01:42 PM Author Posted July 17, 2012 at 01:42 PM 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. Quote
pluto Posted July 17, 2012 at 01:56 PM Author Posted July 17, 2012 at 01:56 PM 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. Quote
photron Posted July 17, 2012 at 02:42 PM Posted July 17, 2012 at 02:42 PM 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. Quote
photron Posted July 17, 2012 at 02:47 PM Posted July 17, 2012 at 02:47 PM 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. Quote
pluto Posted July 17, 2012 at 04:16 PM Author Posted July 17, 2012 at 04:16 PM 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. Quote
pluto Posted July 25, 2012 at 12:10 PM Author Posted July 25, 2012 at 12:10 PM Wie sieht es eigentlich mit den Pascal Bindings aus? Quote
photron Posted July 25, 2012 at 12:55 PM Posted July 25, 2012 at 12:55 PM Die sind fertig, ich habe sie gerade released. Quote
pluto Posted July 25, 2012 at 01:00 PM Author Posted July 25, 2012 at 01:00 PM Prima. Noch gar nicht gesehen. Quote
Nic Posted July 25, 2012 at 03:01 PM Posted July 25, 2012 at 03:01 PM 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; Quote
pluto Posted July 25, 2012 at 04:53 PM Author Posted July 25, 2012 at 04:53 PM Warum möchtest du eigentlich von den Brick Klassen unbedingt ableiten? Quote
Nic Posted July 25, 2012 at 07:55 PM Posted July 25, 2012 at 07:55 PM 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 ? Quote
Nic Posted July 26, 2012 at 10:00 AM Posted July 26, 2012 at 10:00 AM @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. Quote
photron Posted July 26, 2012 at 04:50 PM Posted July 26, 2012 at 04:50 PM 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. Quote
Nic Posted August 6, 2012 at 09:42 AM Posted August 6, 2012 at 09:42 AM 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. Quote
photron Posted August 6, 2012 at 11:24 AM Posted August 6, 2012 at 11:24 AM Ah, das war mir nicht bewusst, dass da C# XML Doku geht. Ist auf die TODO Liste gesetzt. Quote
photron Posted September 26, 2012 at 02:31 PM Posted September 26, 2012 at 02:31 PM Delphi Bindings 1.0.4 haben jetzt Inline Code Dokumentation. Quote
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.