Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Асинхроный I/O с COM портом


Автор: Com123 14.9.2005, 19:50
У меня такая трабла. Начал писать прогу асинхронного I/O - типа терминалки. Алгоритм стандартный OVERLAPPED. В главном потоке приложения отправляю AT комманду WriteFile'ом. Для чтения (ReadFile) из порта запускаю отдельный поток. Процедура треда выглядит более или менее стандартно у всех:

Код

procedure TSimpleThread.Execute;
var
  Overlapped : TOverlapped;
begin
  FillChar(Overlapped,SizeOf(TOverlapped),0);
  Overlapped.hEvent:= CreateEvent(nil,True,False,nil);
  ...
  ...
  while not Terminated do
  begin
    if not WaitCommEvent(hCom,EventMask,@Overlapped) then begin
      if GetLastError = ERROR_IO_PENDING then  begin
          Signal := WaitForSingleObject(Overlapped.hEvent,INFINITE);
        if (Signal = WAIT_OBJECT_0 + 1)
         then GetOverlappedResult(hCom,Overlapped,Readed,False)
      end;
    end;
    ClearCommError(hCom, ErrorMask, @CStat);
    if (EventMask and EV_RXCHAR)=EV_RXCHAR then        //Если пришли данные...
    begin
       Quelen := CStat.cbInQue;
       ReadFile(hCom,Buff,Quelen,Readed,@Overlapped);  // ...то читаем их в Buff
       if Readed > 0 then                              // Если это что-то ненулевое
       begin
        Move(Buff,RecivBuff[CntByte],Readed);         //..то мы его накопляем в RecivBuff
        Inc(CntByte,Readed);              //увеличить счётчик принятых
        ...
        ...
      end;                                   
    end;
  end;
...
...
end;



Все это вроде бы работает. Из порта приходят данные и копятся в RecivBuff (array[0..255] of Char), НО ответ на AT команду приходит не за одно событие EV_RXCHAR, а за несколько (каждый раз по разному) например сначала может прийти 2 байта потом 40 потом 12 smile Проблема: как в потоке чтения узнать что данные пришедшие за несколько EV_RXCHAR все вместе составляют ответ на АТ команду. Т.е. TSimpleThread.Execute должен передать в главный поток готовую строку ответа а не кусок строки(как это сделано во многих примерах). КАК??? или может че то не так понял...

p.s. В исходниках XModem и некоторых других я видел какие то действия с таймером и GetTickCount но до конца не разобрался. Хочется написать самому поэтому не хочу пользовать готовые компоненты и библиотеки.

Автор: Петрович 15.9.2005, 10:45
Обычно, модем дает ответ сразу. Однако, его прием и правда может разбиваться на несколько EV_RXCHAR.
Я в своей программе использую следующий алгоритм: Если очередной байт (событие EV_RXCHAR) не приходит в течении времени t, то считаю что принял все что хотел сказать мне модем. Величина t выбирается в зависимости от установленной скорости COM-порта, и равна времени передачи/приема 5-10 байт. Т.е. например при скорости 19200: t = 5 * (1+8+1)/19200
Ну и конечно можно использовать знание о командах и ответах. Если установлен вербальный режим, то на большинство комманд, модем отвечает одной строкой завершающейся символом ^M. Вот его-то и можно в таком случае считать признаком конца ответа. Не забывая конечно про эхо команды, если оно включено. Есть правда режим кодов, в нем нет признака конца. Ну и естественно есть команды, на которые некоторые модемы могут ответить несколькими строками.
В общем, я предпочитаю первый вариант.

Автор: Com123 15.9.2005, 16:23
Опять не догнал - что такое 5 * (1+8+1) ?

Автор: Петрович 16.9.2005, 08:07
Цитата(Com123 @ 15.9.2005, 17:23)
Опять не догнал - что такое 5 * (1+8+1) ?

5 - число байт
1 - Стартовый бит
8 - биты данных (байт)
1 - Стоповый бит.
В последовательном интерфейсе, используемом в RS-232 стандарте по которому работает COM-порт, байт предваряется одним дополнительным битом (стартовым), и завершается еще одним (стоповым). По ним осуществляется синхронизация приемника и передатчика.
Если быть более точным, то стоповых битов может быть больше (1, 1.5 или 2). Но, обычно используется 1. Кроме того, может добавляться еще один бит - бит проверки на четность/нечетность. Это тоже теперь почти не используется.

Автор: Гость_Serg 16.9.2005, 17:49
Приятно следить за беседой профессионалов smile .
Извините, что отвлекаю, но очень нужно подключить весы к компу, а информация очень скудная.
Знаю только, что применяется протокол Long. Для получения данных на весы предварительно необходимо отослать сигнал(ENQ=(AFh; S I CR LF) – информация из тех. документации к весам). Для записи в порт применяю WriteFile(hPort,MyBuff,Length(Str),ByteWritten,Nil). Как заполнить переменную MyBuff? smile smile

М
 
Гость_Serg, в следующий раз вопрос задавайте в отдельной теме!
Ответ на вопрос:
Код
const ENQ : array [0..4] of byte = ($AF, Ord('S'), Ord('I'), 13, 10);
WriteFile (hPort, ENQ, SizeOf(ENQ), ByteWritten, Nil)
либо
Код
var MyBuff : string;
MyBuff := #$AF + 'SI' + #13 + #10;
WriteFile(hPort,PChar(MyBuff)^,Length(MyBuff),ByteWritten,Nil);

Автор: Гость_Serg 17.9.2005, 11:08
Спасибо за помощь smile
(на счет отдельной темы я тоже все понял - в следующий раз учту smile )

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)