Jump to content

Recommended Posts

Geschrieben

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.

  • Replies 68
  • Created
  • Letzte Antwort

Top Posters In This Topic

Top Posters In This Topic

Posted Images

Geschrieben
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

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

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

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

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

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
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

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 ?

Clipboard02.thumb.png.431b930a155bf8701fc3e40a7b5854aa.png

Geschrieben

@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.

Clipboard02.png.5e1a59d4968793393024a0cf44b979de.png

  • 2 weeks later...
Geschrieben

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.

  • 1 month later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Gast
Reply to this topic...

×   Du hast formatierten Text eingefügt.   Formatierung jetzt entfernen

  Only 75 emoji are allowed.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Clear editor

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.


×
×
  • Neu erstellen...