Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Daten von einem anderen Programm "auffangen" und verarbeiten (https://www.delphipraxis.net/148739-daten-von-einem-anderen-programm-auffangen-und-verarbeiten.html)

schweindi 7. Mär 2010 15:57


Daten von einem anderen Programm "auffangen" und v
 
sodala, wieder mal ich :)

mit großer Hilfe habe ich endlich mein Programm, dass mit einem Modem kommunizieren kann, fertiggestellt (174522).

Jetzt bin ich mir garnicht sicher, ob die folgende Frage hier reinpasst, aber irgendwie hat sie doch mit Win API zu tun, denke ich.
Wie ich schon in der oben genannten Frage geschrieben habe, ist die Software die wir verwenden alt und nicht kompatibel mit dem neuen Modem.
Jetzt hab ich mir gedacht es müsste doch möglich sein, mit einem Programm die Daten/ Befehle die dieses SMS-Programm an den Com Anschluss sendet "abzufangen" und dann richtig verarbeitet weiterzuschicken.
Leider fallen mir da auf Anhieb kaum gute Wege ein.

Hat jemand vielleicht eine Idee, wie man das -eher leicht- machen könnte?

(Ich hab mir mal angeschaut, wie leicht es wäre einen "virtuellen" com Anschluss zu erstellen und die Software auf diesen einzustellen um die empfangenen Daten dann ans richtige Modem weiterzusenden, doch das sah auf den ersten Blick extrem aufwendig aus, da man einen eigenen Driver bräuchte)

Danke im Voraus

thkerkmann 7. Mär 2010 16:27

Re: Daten von einem anderen Programm "auffangen" u
 
Hi,

Es gibt eine OpenSource software, die heisst Com0Com, das könnte dich interessieren.

Diese simuliert zwei serielle Schnittstellen, die miteinander verbunden sind.
Wenn Programm A mit einer dieser Schnittstellen spricht, könnte Programm B die Gegenstelle auf der anderen Schnittstelle sein, und dein Modem hängt dann tatsächlich an der realen Schnittstelle C, und wird von Programm B versorgt.

Gruss

schweindi 7. Mär 2010 16:29

Re: Daten von einem anderen Programm "auffangen" u
 
das klingt ausgezeichnet, könnte genau das sein, was ich suche - danke ich schaus mir mal an :)

schweindi 8. Mär 2010 16:14

Re: Daten von einem anderen Programm "auffangen" u
 
jop, danke es war genau das was ich gesucht habe.

Ich hab zwar noch bisschen Probleme die Timeouts mit dem anderen Programm übereinzustimmen, deshalb werden manche Antworten schon gesendet, obwohl die Anfrage noch nicht ganz empfangen wurde, aber das mach ich noch. Mit sleep() und die Timeouts richtig einstellen, dann sollte es gehen. danke!

schweindi 9. Mär 2010 00:21

Re: Daten von einem anderen Programm "auffangen" u
 
hmm.. jetzt geht mir das ganze doch schon ziemlich auf die Nerven, manchmal geht das Programm manchmal nicht und ich hab eig keine Ahnung, was ich verändert habe, damit es ging.

Folgendes Problem:

Wenn ich mein Programm starte soll es zuerst "at+cfun=1" ans modem schicken, dann die Antwort des Modems abwarten und dann "at" schicken, wieder die Antwort abwarten. Klingt extrem einfach, doch irgendwie bin ich unfähig!

mein Versuch:
Delphi-Quellcode:
procedure TForm1.Button2Click(Sender: TObject);
var StartIni : TIniFile;
begin
ComPort1.Port:=Edit1.Text;
//Ini File
StartIni:=TIniFile.Create(ChangeFileExt(Application.ExeName,'.INI'));
try
StartIni.writeString('Com1','Name',Edit1.Text);
finally
  StartIni.Free;
end;
ComPort1.Open;
Memo_text.Lines.Add('-------');
Memo_text.Lines.Add('Connected to '+Edit1.text);
Memo_text.Lines.Add('-------');
Writeln(Logf, 'Connected to '+Edit1.text);  //logfile
//set +cfun=1
ComPort1.WriteStr('AT+CFUN=1');
ComPort1.TransmitChar(#13);
Writeln(Logf, 'SEND: AT+CFUN=');
sleep(sleeptime);
Application.ProcessMessages;
//send status
ComPort1.WriteStr('AT');
ComPort1.TransmitChar(#13);
Writeln(Logf, 'SEND: AT');
sleep(sleeptime);
Application.ProcessMessages;           //brauch ich da noch eines?
So sleeptime hab ich 10ms,50ms,100ms und 1000ms probiert, es hilft natürlich nichts.
So siehts im Monitor aus:
Code:
REQUEST                  Port       Result       Other

IOCTL_SERIAL_GET_MODEMSTATUS   USBER000    SUCCESS
IRP_MJ_WRITE                   USBER000    SUCCESS   Length 9: AT+CFUN=1
IOCTL_SERIAL_WAIT_ON_MASK      USBER000    SUCCESS
IOCTL_SERIAL_WAIT_ON_MASK      USBER000    SUCCESS
IOCTL_SERIAL_GET_COMMSTATUS    USBER000    SUCCESS
IRP_MJ_READ                    USBER000    SUCCESS   Length 16: AT+CFUN=1...OK..
IOCTL_SERIAL_GET_COMMSTATUS    USBER000    SUCCESS
IRP_MJ_WRITE                   USBER000    SUCCESS   Length 2: AT
daraus schließe ich, dass in der zeile IRP_MJ_READ at+cfun=1 vom modem zurückgesendet wurde und drangehängt "...OK.." wenn ich nach diesem Button dann manuell zb AT eingebe, passiert nichts, keine Antwort vom Modem kein Wait nichts.

Interessant: wenn ich disconnect klicke (ComPort1.Close;) und dann wieder connecte steht vor der Ausgabe "Answer: OK" dh das Event OnPacket von TComPort1 hat sich eingeschaltet... also ich blicke da nicht mehr durch und kenne mich anscheinend zu wenig aus :S

Was möchte ich?
1) Das Programm soll erst den nächsten Befehl senden, (in dem Fall "AT") wenn es vom Modem eine Antwort bekommen hat
2) Wenn es zum Timeout kommt, soll der Befehl erneut versendet werden.

Danke für jede Hilfe!
Gruß Schweindi

thkerkmann 9. Mär 2010 07:38

Re: Daten von einem anderen Programm "auffangen" u
 
Hi,

ich würde dafür nicht TComport nehmen. Dies ist eine Ereignisgesteuerte Komponente. Wenn man warten will/muss, sollte man einen blockierenden Ansatz verwenden.

Synaser ist da meine Wahl. Dort kannst du genau festlegen wie es wann weitergeht. Ein sleep ist dafür völlig ungeeignet.

Gruss

schweindi 9. Mär 2010 16:19

Re: Daten von einem anderen Programm "auffangen" u
 
jop danke - jetzt hab ich das ganze mal mit Synaser umgeschrieben... folgendes:

Delphi-Quellcode:
procedure TForm1.Button2Click(Sender: TObject);
var StartIni : TIniFile;
    Answer : string;
begin
ComPort1.Connect(Edit1.Text);
//Ini File
StartIni:=TIniFile.Create(ChangeFileExt(Application.ExeName,'.INI'));
try
StartIni.writeString('Com1','Name',Edit1.Text);
finally
  StartIni.Free;
end;
//Modem Configuration
ComPort1.Config(com_rate, com_bits, Char(com_parity), com_stop, com_softflow, com_hardflow);
Memo_text.Lines.Add('-------');
Memo_text.Lines.Add('Connected to '+Edit1.text);
Memo_text.Lines.Add('-------');
Writeln(Logf, 'Connected to '+Edit1.text);
//Modem status
ComPort1.SendString('AT'+#13#10);
Writeln(Logf, 'SEND: AT');
Answer := ComPort1.RecvString(readtotal);
if (Answer = 'OK') then
begin
  if Logout then
    Writeln(Logf, 'RECIEVED: '+Answer);
  if Memoout then
    Memo_text.Lines.Add('RECIEVED: '+Answer);
end else
  begin
  Memo_text.Lines.Add('RECIEVED: no answer!');
  Memo_text.Lines.Add('ERROR: '+IntToStr(ComPort1.LastError));
  end;
ComPort1.Flush;
//set +cfun=1
ComPort1.SendString('AT+CFUN=1'+#13+#10);
Writeln(Logf, 'SEND: AT+CFUN=1');
Answer := ComPort1.Recvstring(readtotal);
if (Answer = 'OK') then
begin
  if Logout then
    Writeln(Logf, 'RECIEVED: '+Answer);
  if Memoout then
    Memo_text.Lines.Add('RECIEVED: '+Answer);
end else
  begin
  Memo_text.Lines.Add('RECIEVED: no answer!');
  Memo_text.Lines.Add('ERROR: '+IntToStr(ComPort1.LastError));
  end;
end;
das wird ausgeführt, wenn man den ConnectButton klickt.
Readtotal : Integer -> da hab ich zb 500 bzw 1000 eingegeben und es ging eigentlich.
aber nach "AT+CFUN=1" bekomme ich keine Antwrot mehr... und wenn ich manuell die Befehle eingebe:

Delphi-Quellcode:
procedure TForm1.Button4Click(Sender: TObject);
var Str: String;
begin
//write to port
Str := Edit2.Text;
ComPort1.SendString(str+#13+#10); // string type variable
if logout then
  Writeln(Logf, '(ComPort1) SEND: '+str+' #13 #10');
if memoout then
  Memo_text.Lines.Add('SEND: '+str+' #13 #10');
ComPort1.RecvString(readtotal);
  if memoout then
  Memo_text.Lines.Add('Answer: '+str);
Edit2.Clear;
end;
dann wird zwar der Befehl geschickt: (monitor) "COM Bridge.exe IRP_MJ_WRITE USBER000 SUCCESS AT+CFUN=1.."
aber ich bekomme keine Antwort zurück.........

und allgemein, wie kann ich, wie bei TComPort das Programm warten lassen, so dass es sofort, wenn es einen Input bekommt etwas macht...
Klartext: Programm startet -> connect drücken (den code oben ausführen) -> Programm ist fertig, es bleibt offen -> Modem sendet irgendwas -> Programm "wacht auf" und macht was mit dem Befehl, den es bekommen hat.

wie könnte das gehen?

thkerkmann 9. Mär 2010 19:26

Re: Daten von einem anderen Programm "auffangen" u
 
Ich kenne jetzt TComPort nicht im Detail, aber ich denke es hat dafür ein Event
Sowas wie OnReadData oder so

Schau mal im OI auf die Events - da sollte was dabei sein.

Gruss

P.S.
Nochwas zu Synaser
Wenn Du ReadString (timeout:integer) verwendest, dann ist der timeout in millisekunden.
Du solltest wirklich mal ein Terminalprogramm (Hyperterm oder so) verwenden, und testen, ob deine Annahmen bzgl. des Timings stimmen.

Gruss

schweindi 9. Mär 2010 19:37

Re: Daten von einem anderen Programm "auffangen" u
 
naja ich verwende ja Synaser.

Stimmt der gepostete code so?

ja ich weiß, dass es sich um ms handelt. Ich hab auch schon im hyperterm alle meine Befehle durchprobiert, um zu sehen, wie die Antworten des Modems sein werden. Aber wie bekomme ich die genauen timings?? Ich wollte nämlich genau die einstellungen von hyperterm nachahmen, da die ja sichtlich funktioniert haben.

thkerkmann 9. Mär 2010 20:03

Re: Daten von einem anderen Programm "auffangen" u
 
Ansich sieht das gut aus, was du da machst.

Ich kenne die AT Befehle nicht, die Du da verwendest. Was sollte denn deiner Meinung nach dem AT+CFUN=1 passieren ?
Es kommt ja nicht darauf an, die genaue Zeit zu warten, es geht um eine maximale Zeit.
Also 5000 msec wären nicht zuviel, wenn die Daten früher einlaufen, werden sie auch früher geliefert und das Programm geht weiter.

Noch ein Tipp zu Comport.Config ()

Die Stoppbits solltest Du mithilfe der Konstanten aus Synaser einstellen, denn:

0 = 1 stoppbit
1 = 1,5 stoppbits
2 = 2 stoppbits

Synaser kennt SB1, SB1andHalf, SB2 das kann schonmal sehr wichtig werden.

Gruss

schweindi 9. Mär 2010 20:22

Re: Daten von einem anderen Programm "auffangen" u
 
ahso, ja :)
also wir verwenden ein Nokia CS-15 umts/gsm gateway und man muss die "telephone function of sim" erstmal einschalten, damit das ganze funktioniert.
Auszug aus AT-Commands Revision A:
Code:
Set phone functionality +CFUN
Command syntax: AT+CFUN=<functionality level>
AT+CFUN=0 (ähnlich: AT+CPOF - power off)
AT+CFUN=1 (start oder wenns schon gestartet ist modem reset)
ja ich habe gerade in hyperterm geschaut:
RI:10 - Readinterval?
RM:0 - Read Multiplier?
RC:0 - Read Konstante?
WM:0 - Write Multiplier?
WC:5000 - Write Konstante?

also wenn meine Annahmen stimmen, hat hyperterm kein read timeout oder? naja ich denke die Befehle sollten, wie du gesagt hast, nie mehr als 5 Sekunden brauchen -> ich mach Read: 5000 ReadIntervall: 10 und Write: 5000 - das sollte dann passen...

Danke für den Tipp, werde ich berücksichtigen. Ich probier das ganze umgeschrieben mal aus.

schweindi 10. Mär 2010 16:38

Re: Daten von einem anderen Programm "auffangen" u
 
So sieht der traffic am Port gerade aus:#
Code:
Software: AT
Modem: OK..
S: AT+CFUN=1
M: . ERROR (Timeout)
(so das wäre der "connect" teil)
wenn ich jetzt manuell weitere Befehle sende:
S: AT
M: AT+CFUN=1..+CFUN=1..OK..OK
S: AT+CNMI?
M: .
S: (irgendein Befehl)
M: AT+CNMI?..+CNMI=2,2,0,1,0..OK..OK
S: (irgendein Befehl)
M: .
usw usw
Wie man sieht, nachdem ich cfun=1 eingegeben habe, kam ein Zeichen nur . (= #13) und dann egal welchen Befehl ich verschickt habe, kam jeweils die Antwort auf den vorigen Befehl zurück... Da verstehe ich leider garnicht!
Was kann das bewirken?

P.S.: "at+cfun=1..+CFUN=1..OK..OK" mein Befehl wird als echo zurück gesendet, da ATE ein ist..

shmia 10. Mär 2010 17:28

Re: Daten von einem anderen Programm "auffangen" u
 
Du solltest dich nicht darauf verlassen, dass Antworten ein bestimmtes Timing haben.
Stattdessen würde ich das abschliessende #13 als Endezeichen betrachten.

Der Algorithmus sieht so aus:
Es gibt einen Empfangspuffer (string).
Bei jedem OnRead-Event werden die empfangen Daten zuerst an den Empfangspuffer angehängt.
Dann schaut man nach, ob im Empfangspuffer eine ganze Zeile steht indem man nach dem Endezeichen sucht. (*)
Die Antwort (inklusive Endezeichen) wird aus dem Empfangspuffer ausgeschnitten.
Dann wird die Antwort (ohne Endezeichen) einer Procedure übergeben die dann entsprechend reagiert.
Es könnte aber noch eine weitere Antwort im Empfangspuffer stehen; deshalb zurück zur mit (*) markierten Zeile.

schweindi 10. Mär 2010 17:45

Re: Daten von einem anderen Programm "auffangen" u
 
hmm ja das ist dann das prinzip vom TComPort, ich will es jetzt aber mit den methoden von synaser machen!

ich hab da etwas gefunden:

ComPort1.RecvBlock(timeout);
Das liest ja genau soviel aus, wie viel am anfang der zeile angegeben wird.
Mein Modem schickt zb:
Lenght:4 OK..
dh 4 = anzahl der elemente und soviel müsste er auslesen, das Problem ist nur, wenn ich das ausprobiere, und ich schreibe im Hyperterm "4 OK" dann bekomme ich nachdem ich "O" geschrieben habe einen "Out of memory error"!? das ist jetzt schon eigenartig

shmia 10. Mär 2010 17:56

Re: Daten von einem anderen Programm "auffangen" u
 
Zitat:

Zitat von schweindi
...und ich schreibe im Hyperterm "4 OK" dann bekomme ich nachdem ich "O" geschrieben habe einen "Out of memory error"!? das ist jetzt schon eigenartig

Und wie schnell kannst du schreiben?
Ein kurze Pause zwischen dem O und dem K und schon kommt .RecvBlock() mit einem unvollständigem Ergebnis zurück.
Du musst dir klarmachen, dass du dich von einem Timeout ganz lösen musst.
Ob jetzt alle zwei Sekunden eine einziges Zeichen hereinkommt oder ob alle Zeichen auf einen Rutsch eintreffen darf für dein Programm keine Rolle spielen.

PS
habe gerade gesehen, dass es bei Synaser die Methode RecvTerminated() gibt.
Delphi-Quellcode:
antwort := synaser.RecvTerminated(5000, #13);

schweindi 10. Mär 2010 17:59

Re: Daten von einem anderen Programm "auffangen" u
 
ich habe tiomeout auf 20000 gesetzt - 20 Sekunden sollten reichen für mich :)

ich habe schon das Problem gefunden:
ich habe eingegeben: "4 OK" aber eig sollte es sein "0004 OK" da er ja 4 byte braucht.

Jetzt muss ich nur noch herausfinden, wie ich 4 in byte darstellen kann, da, wenn ich 0004 eingeben kommt als Wert 8755723296 und nicht 4 heraus!

shmia 10. Mär 2010 18:07

Re: Daten von einem anderen Programm "auffangen" u
 
Zitat:

Zitat von schweindi
ich habe eingegeben: "4 OK" aber eig sollte es sein "0004 OK" da er ja 4 byte braucht.

Die 4 Bytes werden binär ausgewertet (siehe function TBlockSerial.RecvInteger).
Du kannst RecvBlock() daher so nicht verwenden.
Aber gehe mal einen Betrag zurück und lies noch mein PS.

schweindi 10. Mär 2010 18:16

Re: Daten von einem anderen Programm "auffangen" u
 
ah sorry, hab das nicht mehr gesehen... okay, na dann verwende ich das mal.
also das Modem antwortet mit "OK"+CR+LF dh endstring ist immer #10?

schweindi 10. Mär 2010 19:33

Re: Daten von einem anderen Programm "auffangen" u
 
okay, super funzt das alles jetzt.
Ich hab nur noch ein problem, das Modem sendet jeden Input als echo zurück. Wie kann ich diese Echos auslesen und somit aus dem Input löschen?

Gelöst! Jetzt will ich aber, dass sobald er auf dem Port Daten bekommt, etwas macht. Bei TComPort war das OnRxChar. Wie geht das hier mit dem? bzw wie kann ich es machen, dass sobald er etwas im Input hat, eine procedure ausgeführt wird?

schweindi 11. Mär 2010 13:52

Re: Daten von einem anderen Programm "auffangen" u
 
Alternative:
wäre es leichter das Windows Event: SERIAL_EV_RXCHAR zu verwenden und daraus ein (eigenes) Event zu machen.

Ich habe zwar noch nie Events selber gemacht, aber ich denke mir, irgendwo muss im Endeffekt doch auf ein Windows Event verwiesen werden. Z.B. in der TComPort Unit wird jedem Event property zugeschrieben und irgendwann kommt "If Assigned(TEVENT) then ... .DOStatus" also das ist bezogen auf Serielle Anschlüsse.
Aber ich sehe nirgendwo eine für mich verständliche Zuordnung, in der ein Windows Event irgendwie verwendet wird... also ist ein RxChar Event leicht selber machbar?

schweindi 13. Mär 2010 20:04

Re: Daten von einem anderen Programm "auffangen" u
 
hat keiner eine Idee??

Mir fehlt nur noch eine Möglichkeit EV_RxChar einzubinden, dann müsste das ganze Programm funktionieren!


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:09 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz