如何在循环发送更多数据之前等待 COM 端口接收事件

发布于 2024-12-29 10:45:40 字数 988 浏览 0 评论 0原文

我正在开发一个小组件,用于使用旧的索尼爱立信手机编写和读取 AT 命令。 向手机发送和写入数据完全没有问题,但是我希望能够暂停 SendATCmd 函数并等待 COM 端口组件通过通知事件通知我,然后再次恢复 SendATCmd 函数。

场景:我想获取手机中短信的数量。 通常我只是告诉电话:嘿,你有多少条短信? 并且手机会在通知事件中回复。 这一切都很好。

但我真正想做的是类似于

if SendATCmd('CountSMS')>0 then
  for 0 to SMSCount do
    AddSMSToList;

SendATCmd 的代码如下所示:

function TSE_Z1010.SendATCmd(Cmd: string): TATResult;
begin
  fCOMPort.PutString(Cmd); //Sending AT command

  //Here is where I would like to pause this function
  //wait for the fCOMPort to notify me when data is available
  //and then resume this function again.

  result:=fTMPATResult;

end;

我尝试使用 while 循环、暂停等,但除了一件事之外没有任何效果,那就是当我将 ShowMessage 放在暂停应该是。 我不知道 ShowMessage 内部是如何工作的,但它似乎不会像 while 循环和暂停那样停止程序。

====================

已修复。

我所要做的就是在uses子句中添加Forms,然后添加 while fTMPATResult.Full=false do Application.ProcessMessages;在我想暂停程序的部分。

“fTMPATResult”是组件内全局存储传入 COM 端口数据的变量。

I'm working on a small component for writing and reading AT Commands using an old Sony Ericsson phone.
Sending and writing to/from the phone is no problem at all, however I would like to be able to pause my SendATCmd function and wait for the COM Port component to notify me with a Notification Event, and then resume the SendATCmd function again.

Scenario: I want to get the count of SMS messages in the phone.
Normally I'd just tell the phone: Hey, how many SMS messages do you have?
and the phone would reply in the notification event.
Thats all good.

But what I really want to do is something like

if SendATCmd('CountSMS')>0 then
  for 0 to SMSCount do
    AddSMSToList;

The code for SendATCmd looks like this:

function TSE_Z1010.SendATCmd(Cmd: string): TATResult;
begin
  fCOMPort.PutString(Cmd); //Sending AT command

  //Here is where I would like to pause this function
  //wait for the fCOMPort to notify me when data is available
  //and then resume this function again.

  result:=fTMPATResult;

end;

I've tried using a while-loop, pause, etc etc, but nothing's worked except for one thing, and that's when I put a ShowMessage where the pause should be.
I don't know how ShowMessage works internally but it seems that it doesn't halt the program like while-loop and pause do.

====================

Fixed it.

All I had to do was to add Forms in the uses clause, and then I added while fTMPATResult.Full=false do Application.ProcessMessages; in the part where I wanted to pause the procedure.

"fTMPATResult" is the variable where the incoming COM Port data is stored, globally within the component.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

如此安好 2025-01-05 10:45:40

虽然 AsyncPro 确实有一些解决方案(ontriggerdata),但它们是基于事件的,使得代码难以阅读/理解。

这里是带有 AsyncPro 的 SendAndWaitForResponse (就像 Remy 建议的那样):

TForm1 = class(TForm)
 ...
private
    IOEvent           : THandle; // used for IO events
    IORx              : string;
    Comport           : TapdComport;
...


procedure TForm1.ComportTriggerAvail(CP: TObject; Count: Word);

var i       : integer;

begin
 for i:=1 to Count do
  IORx:=IORx+Comport.GetChar;
 SetEvent(IOEvent);
end;

function TForm1.SerialSAWR(tx : string; TimeOut : integer) : boolean;
begin
 Result := False;
 try
  IORx := ''; // your global var
  ResetEvent(IOEvent);
  Comport.PutString(tx);
  Result := WaitForSingleObject(IOEvent, TimeOut) = WAIT_OBJECT_0;
 except
  on E : Exception do
   // dosomething with exception
 end;
end;

// constructor part
IOEvent := CreateEvent(nil, True, False, nil);
// destructor part
 if IOEvent <> 0 then
  CloseHandle(IOEvent);

最好的解决方案是创建一个带有 comport 的线程,这样你的 GUI 就不会被阻塞。
我有几个使用 Asyncpro 的应用程序在生产中,它的工作方式就像一个魅力......

While AsyncPro does have some solutions for this (ontriggerdata), they are event based and make code difficult to read/understand.

here is SendAndWaitForResponse with AsyncPro (like Remy suggested):

TForm1 = class(TForm)
 ...
private
    IOEvent           : THandle; // used for IO events
    IORx              : string;
    Comport           : TapdComport;
...


procedure TForm1.ComportTriggerAvail(CP: TObject; Count: Word);

var i       : integer;

begin
 for i:=1 to Count do
  IORx:=IORx+Comport.GetChar;
 SetEvent(IOEvent);
end;

function TForm1.SerialSAWR(tx : string; TimeOut : integer) : boolean;
begin
 Result := False;
 try
  IORx := ''; // your global var
  ResetEvent(IOEvent);
  Comport.PutString(tx);
  Result := WaitForSingleObject(IOEvent, TimeOut) = WAIT_OBJECT_0;
 except
  on E : Exception do
   // dosomething with exception
 end;
end;

// constructor part
IOEvent := CreateEvent(nil, True, False, nil);
// destructor part
 if IOEvent <> 0 then
  CloseHandle(IOEvent);

Best solution is to create a thread with the comport so your GUI won't be blocked.
I have several applications in production with Asyncpro this way and it works like a charm...

轮廓§ 2025-01-05 10:45:40

每当您需要手动调用 Application.ProcessMessages() 时,您都需要重新考虑代码设计。在循环中调用它时更是如此。

我不知道 Asynch Pro 是如何工作的,但是 Win32 API 有一个 WaitCommEvent() 函数可以完成您所要求的操作。您调用该函数来向串行端口请求所需事件的通知,然后您可以使用 WaitForOverlappedResult()WaitForSingleObject() 来等待这些事件实际发生的情况取决于串行端口是否工作在重叠模式下。不需要消息处理。如果 Asynch Pro 没有以某种方式公开该功能,我会感到惊讶。

Any time you need to call Application.ProcessMessages() manually, you need to rethink your code design. Doubly so when calling it in a loop.

I do not know how Asynch Pro works, but the Win32 API has a WaitCommEvent() function that does what you are asking for. You call that function to ask the serial port for notification of the desired event(s) and then you can use either WaitForOverlappedResult() or WaitForSingleObject() to wait for those events to actually occur, depending on whether the serial port is operating in overlapped mode or not. No message processing is needed. I would be surprised if Asynch Pro does not somehow expose that functionality.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文