Synaser jak utworzyć zdarzenie

0

Witam Forumowiczów.
Chciałem wykorzystać w swoim programie klasę TBlockSerial (można pobrać http://synapse.ararat.cz/ zwie się synaser ) do obsługi portu Com (rs232),
doszedłem jak wysyłać dane na port ale nie potrafię odczytać danych które przyszły na port.
Klasa TBlockSerial posiada metodę począwszy od Recvstring poprzez RecvBlock, ale nie wiem w którym momencie ją wywołać, dlatego myślałem nad zdarzeniem które zostanie wywołane jak przyjdą dane na port,
moje pytanie brzmi: w jaki sposób mogę takie zdarzenie utworzyć, proszę o jakiś przykład nie koniecznie związany z Synaser-em.

Zamieszczam kawałek kodu w jaki sposób próbowałem rozwiązać problem.

unit Unit1; 

interface

uses
  Classes, SysUtils, LResources, Forms,
  Controls, Graphics, Dialogs, StdCtrls,
  synaser, Buttons, ExtCtrls;

type



  TMain = class(TForm)
    Button1: TButton;
    Button2: TButton;
    CheckBox1: TCheckBox;
    ComboBox1: TComboBox;
    ComboBox2: TComboBox;
    Edit1: TEdit;
    GroupBox1: TGroupBox;
    GroupBox2: TGroupBox;
    Label1: TLabel;
    Label2: TLabel;
    Memo1: TMemo;
    Timer1: TTimer;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end; 

var
  Main: TMain;
  PortCom: TBlockSerial;
  TimeOut: integer;
  
  const ligneMax = 30;

implementation




procedure TMain.FormCreate(Sender: TObject);
var l: string;
    p: integer;
begin
    l := GetSerialPortNames;

  if l >'' then repeat
    begin
    p :=  pos(',',l);
    if p > 0 then
      begin
      ComboBox1.Items.Add(copy(L,1,p-1));
      delete(L,1,p);
      end
    else
      ComboBox1.Items.Add(L);
    end;
    until p = 0;

end;



procedure TMain.Timer1Timer(Sender: TObject);
var ligne: string;
     WD: integer;
begin
   timer1.Enabled := false;
   WD := PortCom.WaitingData;
   if WD  > 0 then  Memo1.Lines.Add(PortCom.RecvBlock(TimeOut));
   timer1.Enabled := true;
end;




procedure TMain.Button1Click(Sender: TObject);
var bauds: integer;
const ligneMax = 30;
begin
     PortCom := TBlockSerial.Create;
     PortCom.RaiseExcept := false;
     PortCom.Connect(ComboBox1.Text);
     bauds := StrToInt(ComboBox2.Text);
     PortCom.Config(bauds,8,'N',0,false,false);
     TimeOut := LigneMax*10000 div bauds;
     timer1.enabled := true;
end;




procedure TMain.Button2Click(Sender: TObject);
var
SendText : String;
begin
  SendText:=Edit1.Text;
  if CheckBox1.Checked = true then
     SendText:=SendText + #13#10;
  PortCom.SendString(SendText);

end;

initialization
  {$I unit1.lrs}

end.
0

Możesz też np. użyć timera, który co kilka sekund(minut) będzie sprawdzał port com. Co do zdarzenia to nie mam pojęcia czy jest i jak się nazywa zdarzenie odpowiedzialne za przyjście danych na com.

0

Witaj "Oleksy_Adam", dziękuje za wypowiedz i sugestię, jak pewnie widzisz w kodzie który zamieściłem użyłem właśnie timera ale z żaden sposób nie potrafię pobrać danych poprzez metodę RecvString, RecvBlock.
Moje pytanie nadal jest aktualne, jak dopisać zdarzenie które zostanie wywołane po odebraniu danych ?
Pozdrawiam.

0

Bez dodania watku sprawdzajacego/czekajacego na dane sie nie obejdzie.

chyba latwiej bedzie wybrac inny komponent posiadajacy cos na ksztalt OnRecive

0

"reichel" dzięki za podpowiedź z wątkiem, myślałem też nad tym, ale czy aby to nie podobne rozwiązanie jak z tym timerem?
A co do innych komponentów to raczej nie mam dużego pola manewru ponieważ mój program ma docelowo działać na linuxie a program pisze na Lazarus-ie, z tego co udało mi się wygooglować na sieci to chyba Synaser jest jedyną słuszną drogą obsługi Com-a w Lazarusie pod linuxem.

Proszę o dalsze sugestie i porady.
Pozdrawiam

0

Wydaje mi sie, ze w FP (free pascal) musisz dokonac tylko kilku zmian i inne komponenty tez pojda (pewnie bedzie trzeba utworzyc klase TThread - jakas najprostsza bez synchronizacji itp).

tu takie wynuzenia pod FP (te z dzialu delphi tez mozna skompilowac pod FP, kwestia kilku zmian typ zmiennych)
http://rudy.mif.pg.gda.pl/~reichel/showcat.php?id=21

co do watku pod FP(czyli Lazarus)
to zalatwialem to linijka (no moze kilkoma :) ):

 ReadCommH := CreateThread(nil,0,@ReadCommProc,nil,
                    CREATE_SUSPENDED,idRCP);

Zapomnialem dopowiedziec:
czy to nie podobnie jak z timerem ? teoretycznie tak ale timer mozna ustawic na przedzial co 1ms a to duzooooo, w watku mozna ustawic petle repeat ... until (), dodatkowo mozna dodawac Eventy i ustawiac bardziej dowolnie wszystko (WaitFor*) (komponenty do sprzetu sa dobre do czasu, no chyba ze sie ma swoj wlasny :) )

0

Witam forumowiczów,
wznawiam temacik posiłkując się "Waszymi" sugestiami próbuje wykorzystać wątek do przejęcia danych z portu com, więc tak utworzyłem wątek który ma za zadanie przepisać dane z portu com do memo, watek startuje w momencie otwarcia portu com czyli tak jak by nasłuchiwał, efekt jest bardzo nieciekawy po chwili program obciąża procesor w granicach 100%, tak jak by ten wątek nie spełniał swojej roli... bardzo możliwe że ja źle go obsługuje ale nie wiem jak można inaczej.
Proszę o rady jak rozwiązać ten problem.
Pozdrawiam

a tu kod programu:

unit Unit1; 

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LResources, Forms,
  Controls, Graphics, Dialogs, StdCtrls,
  synaser, Buttons, ExtCtrls;

type

  TWatek = class(TThread)
  private
  protected
    procedure Execute; override;
  end;

  { TMain }

  TMain = class(TForm)
    Button1: TButton;
    Button2: TButton;
    CheckBox1: TCheckBox;
    ComboBox1: TComboBox;
    ComboBox2: TComboBox;
    Edit1: TEdit;
    GroupBox1: TGroupBox;
    GroupBox2: TGroupBox;
    Label1: TLabel;
    Label2: TLabel;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end; 

var
  Main: TMain;
  PortCom: TBlockSerial;
  TimeOut: integer;
  
  Watek: Twatek;
  
  const ligneMax = 30;

implementation

{ TMain }

procedure Twatek.Execute;
var
WD: integer;
begin
  // FreeOnTerminate := True;  //konczy watek po wynonaniu procedury
  while not (Application.Terminated) or (Terminated) do
  begin
   WD := PortCom.WaitingData;
   if WD  > 0 then
   Main.Memo1.Lines.Add(PortCom.RecvBlock(TimeOut));
  end;
end;


procedure TMain.FormCreate(Sender: TObject);
var l: string;
    p: integer;
begin
    l := GetSerialPortNames;

  if l >'' then repeat
    begin
    p :=  pos(',',l);
    if p > 0 then
      begin
      ComboBox1.Items.Add(copy(L,1,p-1));
      delete(L,1,p);
      end
    else
      ComboBox1.Items.Add(L);
    end;
    until p = 0;



end;






procedure TMain.Button1Click(Sender: TObject);
var
bauds: integer;
const ligneMax = 30;
begin
     PortCom := TBlockSerial.Create;
     PortCom.RaiseExcept := false;
     PortCom.Connect(ComboBox1.Text);
     bauds := StrToInt(ComboBox2.Text);
     PortCom.Config(bauds,8,'N',0,false,false);
     TimeOut := LigneMax*10000 div bauds;
     
     Watek := TWatek.Create(False);
end;




procedure TMain.Button2Click(Sender: TObject);
var
SendText : String;
begin
  SendText:=Edit1.Text;
  if CheckBox1.Checked = true then
     SendText:=SendText + CRLF; //#13#10
  PortCom.SendString(SendText);

end;

initialization
  {$I unit1.lrs}

end.
0

Cześć,
chcę wykorzystać w swoim programie synaser-a i też stoję przed tym samym problemem co ty, czy rozwiązałeś już problem z wątkiem, jeśli tak to proszę zamieść kod.

0
TobiaszK napisał(a)

Cześć,
chcę wykorzystać w swoim programie synaser-a i też stoję przed tym samym problemem co ty, czy rozwiązałeś już problem z wątkiem, jeśli tak to proszę zamieść kod.

Siemanko jak na razie jestem "w polu" to co naskrobalem jest zamieszczone w tym temacie.

Ps. Prosze o porady bo moja wiedza jest zbyt mala aby rozwiazac ten problem.
Pozdrawiam

0

Witam jeszcze raz, po poscie czytelnika tego forum dostalem mobilizacji, i przysiadlem nad kodem,
przeczytalem z kompediium Pana Adama Boducha tekst o watkach
http://4programmers.net/Delphi/Kompendium/Rozdzia%C5%82_8 i chcialem zastosowac Synchronize, po zastosowaniu przepisu na watek i na Synchronize mam taki kod:

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LResources, Forms,
  Controls, Graphics, Dialogs, StdCtrls,
  synaser, Buttons, ExtCtrls;

type

{
 TSynaserEvent = procedure of object;


  TExtendSynaser = class(TBlockSerial)
    private
     FOnReadPort : TSynaserEvent;
    protected
    published
       property OnReadPort : TSynaserEvent read FReadPort write FReadPort;
  end;
}


  TWatek = class(TThread)
  private
    procedure GetData;
  protected
    procedure Execute; override;
  end;

  { TMain }

  TMain = class(TForm)
    Button1: TButton;
    Button2: TButton;
    CheckBox1: TCheckBox;
    ComboBox1: TComboBox;
    ComboBox2: TComboBox;
    Edit1: TEdit;
    GroupBox1: TGroupBox;
    GroupBox2: TGroupBox;
    Label1: TLabel;
    Label2: TLabel;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Main: TMain;
  PortCom: TBlockSerial;
  TimeOut: integer;

  Watek: Twatek;

  const ligneMax = 30;

implementation

{ TMain }


procedure Twatek.GetData;
var
WD: integer;
begin
   FreeOnTerminate := True;  //konczy watek po wynonaniu procedury
   
  while not (Application.Terminated) or (Terminated) do
   begin
    WD := PortCom.WaitingData;
     if WD  > 0 then
      Main.Memo1.Lines.Add(PortCom.RecvBlock(TimeOut));
   end;
end;



procedure Twatek.Execute;
begin
  Synchronize(GetData);
end;



procedure TMain.FormCreate(Sender: TObject);
var l: string;
    p: integer;
begin
    l := GetSerialPortNames;

  if l >'' then repeat
    begin
    p :=  pos(',',l);
    if p > 0 then
      begin
      ComboBox1.Items.Add(copy(L,1,p-1));
      delete(L,1,p);
      end
    else
      ComboBox1.Items.Add(L);
    end;
    until p = 0;
end;


procedure TMain.Button1Click(Sender: TObject);
var
bauds: integer;
const ligneMax = 30;
begin
     PortCom := TBlockSerial.Create;
     PortCom.RaiseExcept := false;
     PortCom.Connect(ComboBox1.Text);
     bauds := StrToInt(ComboBox2.Text);
     PortCom.Config(bauds,8,'N',0,false,false);
     TimeOut := LigneMax*10000 div bauds;

     Watek := TWatek.Create(False);
end;


procedure TMain.Button2Click(Sender: TObject);
var
SendText : String;
begin
  SendText:=Edit1.Text;
  if CheckBox1.Checked = true then
     SendText:=SendText + CRLF; //#13#10
  PortCom.SendString(SendText);

end;


initialization
  {$I unit1.lrs}

end.

Zamieszczony kod nie przechodzi kompilacji, staje na linijce z Synchronize z opisem:
"Unit1.pas(90,22) Error: Incompatible type for arg no. 1: Got "untyped", expected "<procedure variable type of procedure of object;Register>""

Moje pytanie, gdzie popeniam blad, jak to obejsc ?
Pozdrawiam

1 użytkowników online, w tym zalogowanych: 0, gości: 1