Конференция "WinAPI" » COM порт Win API. Проблемы с приёмом. [D7, WinXP]
 
  • PooHer (06.07.09 23:58) [0]
    Умные люди, не бросьте в беде :)!
    Совсем уже нет мыслей по чему такое может может произойти.
    Создаю поток, в котором ожидаю приёма, но ничего не принимается (слушаю эхо). Передача проходит корректно (проверено).
    procedure TComRead.Execute;
    var
    ComStat: TComStat;
    dwMask, dwError: DWORD;
    OverRead: TOverlapped;
    Buf: array[0..20] of char;
    dwRead: DWORD;
    dd: string;
    begin
    FreeOnTerminate := True;
    while not Terminated do
    begin
    dwMask:=0;
    WaitCommEvent(CId, dwMask, @OverRead);
    if dwMask = EV_RXCHAR then
    begin
    ClearCommError(CId, dwError, @ComStat);
    dwRead := ComStat.cbInQue;
    if dwRead > 0 then
    begin
    ReadFile(CId, Buf, dwRead, dwRead, @OverRead);
    Form2.Panel1.Caption:=string(Buf);
    end;
    end; {while}
    end;
    end;


    Всё упрощено, но по моему работать должно??
  • KilkennyCat © (07.07.09 00:03) [1]
    а проконтролировать выполнение условий?
  • KilkennyCat © (07.07.09 00:10) [2]
    И вообще, не маловат ли Buf?
    И не стоит ли его очищать перед приемом?
    И каким макаром выбран именно этот компорт, а не какой-нить еще, коих в системе дофига может быть? И где его инициализация?
  • PooHer (07.07.09 00:17) [3]

    > И вообще, не маловат ли Buf?

    Передаю и принимаю 1 байт.

    > И каким макаром выбран именно этот компорт, а не какой-нить
    > еще, коих в системе дофига может быть? И где его инициализация?
    >

    Инициализация в основном потоке, я хе говорил, передача происходит корректно.
    > а проконтролировать выполнение условий?

    Контроль убран уже от безысходности. С ним тоже ничего не работает.
  • KilkennyCat © (07.07.09 00:19) [4]
    А, я подумал, что имеется ввиду передача от того, кто передает...
  • Германн © (07.07.09 02:21) [5]

    > PooHer   (07.07.09 00:17) [3]
    >
    >
    > > И вообще, не маловат ли Buf?
    >
    > Передаю и принимаю 1 байт.

    Уууу. Опять "идиотская" синхронная работа с асинхронным по своей сути устройством.
  • KilkennyCat © (07.07.09 03:38) [6]

    > Германн ©

    а с чего ты решил, что устройство асинхронно? только из-за протокола? Так это очень и очень спорно. Зависит от параметров синхронности. предположим, раз в год в течении суток. Что, асинхронность передачи в этом случае будет так заметна и как-то влиять?
    Да и синхронность тут тоже совершенно не видна.
  • Вариант (07.07.09 08:01) [7]

    > PooHer   (06.07.09 23:58)


    > dwMask:=0;
    > WaitCommEvent(CId, dwMask, @OverRead);

    Я так понимаю, ты открыл порт указав флаг  FILE_FLAG_OVERLAPPED?
    WaitCommEvent  у тебя использует OverRead и вернется не ожидая событий. Для ожидания событий надо вызвать  WaitForXXX функцию и/или GetOverlappedResult. И ты не проверяешь результат возврата WaitCommEvent (false/true + GetLastError  в случае ошибки). Может быть и ошибка, но указывающая , что идет  операция перекрытого ввода/вывода (это нормально) или другая.... И кстати, а SetCommMask ты вызывал?
  • Сергей М. © (07.07.09 09:24) [8]
    + и опять те же грабли с обращением к VCL-контролам в доп.потоке
  • Сергей М. © (07.07.09 09:32) [9]
    Черным же по белому в справке написано:

    If hFile was opened with FILE_FLAG_OVERLAPPED, the lpOverlapped parameter must .. point to a valid OVERLAPPED structure


    > Контроль убран уже от безысходности


    Вот если бы ты не убирал контроль результатов вызовов WinAPI-функций (сомневаюсь что он вообще у тебя был), то он бы сразу показал тебе, что WaitCommEvent() вернула отказ по причине очевидной инвалидности переданного ей параметра OverRead.
  • Сергей М. © (07.07.09 09:34) [10]
    То же самое касается вызова ReadFile - те же грабли в ту же точку приложения)
  • PooHer (07.07.09 11:19) [11]
    Чтение изначально было такое:
    procedure TReadThread.Execute;
    var
    ComStat: TComStat;
    dwMask, dwError: DWORD;
    OverRead: TOverlapped;
    Buf: array[0..$FF] of Byte;
    dwRead: DWORD;
    begin
    OverRead.hEvent := CreateEvent(nil, True, False, nil);
    if OverRead.hEvent = Null then
    raise Exception.Create('Error creating read event');

    FreeOnTerminate := True;

    while not Terminated do
    begin
    if not WaitCommEvent(cId, dwMask, @OverRead) then
    begin
    if GetLastError = ERROR_IO_PENDING then
    WaitForSingleObject(OverRead.hEvent, INFINITE)
    else
    raise Exception.Create('Error waiting port event');
    end;

    if not ClearCommError(cId, dwError, @ComStat) then
    raise Exception.Create('Error clearing port');

    dwRead := ComStat.cbInQue;

    if dwRead > 0 then
    begin
    if not ReadFile(cId, Buf, dwRead, dwRead, @OverRead) then
    raise Exception.Create('Error reading port');
    // В Buf находятся прочитанные байты
    // Далее идет обработка принятых байтов
    end;
    end;
    end;



    Инициализация:
    cId:= CreateFile(‘COM1’, GENERIC_READ or GENERIC_WRITE, 0, nil,
    OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
    if cId= INVALID_HANDLE_VALUE then
    raise Exception.Create('Error opening port');

    if not GetCommState(cId, Dcb) then
    raise Exception.Create('Error setting port state');

    Dcb.BaudRate := CBR_9600;
    Dcb.Parity := NOPARITY;
    Dcb.ByteSize := 8;
    Dcb.StopBits := ONESTOPBIT;

    if not SetCommState(cId, Dcb) then
    raise Exception.Create('Error setting port state');
    if not PurgeComm(cId, PURGE_TXCLEAR or PURGE_RXCLEAR) then
    raise Exception.Create('Error purging port');

  • Сергей М. © (07.07.09 11:34) [12]

    > Чтение изначально было такое


    И что же подвигло тебя убрать проверки (пусть даже элементарные), фигурировашие в изначальном варианте ?
  • PooHer (07.07.09 11:43) [13]

    > И что же подвигло тебя убрать проверки (пусть даже элементарные),
    >  фигурировашие в изначальном варианте ?

    Да то, что не работает ничего, замучался уже.
    Во втором потоке программа крутится на ожидании звента, фактически данные отправляются и приходят в порт на 100%.
  • PooHer (07.07.09 11:47) [14]
    Вообще, с Delphi только начинаю работать. Проектирую устройства на микроконтроллерах, пишу на АСМе. Встал вопрос о сопряжении МК и ПК. С Delphi последний раз общался лет 8 назад, забыл всё что знал, а знал мало :)
    То, что данные уходят корректно проверено на железяке(МК).
  • PooHer (07.07.09 11:53) [15]
    100% рабочий пример кода есть у кого? Пусть даже самый простой, без проверок(сам допишу). Просто мне кажется, что у меня какая-то ПРИНЦИПИАЛЬНАЯ ошибка в коде, но в виду отсутствия опыта, определить её не представляется возможным.
    Можно, конечно, использовать готовые библиотеки, но очень хочется познать суть (Собственно по этому и пишу для МК на АСМе, а не на Си или Баскоме).
  • Сергей М. © (07.07.09 12:07) [16]

    > не работает ничего


    И в этом, надо понимать, виноваты те самые проверки, которые ты убрал ?

    Но ведь если изначально эти проверки тобой выполнялись, то значит ты же ожидал увидеть хоть какой-либо результат их "деятельности"  ?
    А вместо ожидаемого сообщения 'Error при попытке выполнения такой-то конкретно функции', ты, значит,  увидел сообщение "Не работает ничего ! Да ну их нафих эти проверки, все равно толку от них ноль !", потому и убрал проверки ? Я правильно логику твоих действий понимаю ?)
  • Вариант (07.07.09 13:00) [17]

    > PooHer   (07.07.09 11:19) [15]

    Как уже писали выше - этот вариант в [11] ближе к нормальному. Но и в нем нет SetCommMask - и какие тогда события ты хочешь отслеживать, если не указал это? ПРочитай про SetCommMask, поставь это в инициализации  порта и мне кажется что-то у тебя уже должно заработать.
  • Вариант (07.07.09 13:08) [18]
    Кстати и про SetCommTimeouts тоже стоит почитать
    Посмотри статьи на
    http://www.delphikingdom.com/asp/section.asp?id=2
    http://www.delphikingdom.com/asp/itemq.asp?Mode=1&ItemID=151
    На том же сайте можешь поискать статьи
    "Работа с портами ввода-вывода в DELPHI"
  • Вариант (07.07.09 13:19) [19]
    И снова не все увидел, у тебя в [11] вообще нет обработки событий порта. Зачем тебе тогда WaitCommStatus? Ладно, почитай статьи....
  • PooHer (07.07.09 14:58) [20]
    cId := CreateFile(PChar('COM'+IntToStr(Num)),GENERIC_READ or GENERIC_WRITE,0,nil,OPEN_EXISTING,
                       FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED,0);

    SetCommMask(cId, EV_RXCHAR);


    Вот так было.
  • Сергей М. © (07.07.09 15:23) [21]

    > PooHer   (07.07.09 14:58) [20]


    Работа с маской событий вообще не нужна, равно как и Wait/ClearCommEvent
    Равно как лишен смысла и overlapped ввод-вывод в доп.потоке, не делающем более ничего существенного, кроме собственно ввода-вывода из/в СОМ-порт
  • PooHer (07.07.09 15:50) [22]

    > Работа с маской событий вообще не нужна, равно как и Wait/ClearCommEvent

    Ну а как тогда работать?
  • Вариант (07.07.09 15:55) [23]

    > PooHer   (07.07.09 15:50) [22]

    Если не нужна специфика работы с портом и подробная расшифровка специфичных ошибок, то достаточно ReadFile и WriteFile. Но настройка порта нужна.
  • Вариант (07.07.09 15:57) [24]

    > PooHer   (07.07.09 15:50) [22]

    Статьий глянь, их много в интернете. На королевстве дельфи посмотри, ссылки давал
  • PooHer (07.07.09 18:51) [25]
    Ну если просто вот так, в цикле сразу после передачи читать, должно работать?
    (Не смеяться, это просто в качестве эксперимента.
    procedure TForm2.Button4Click(Sender: TObject);

    var
    datas: string;
    dwWrite: DWORD;
    OverWrite: TOverlapped;
    //WriteBytes: array of Byte;
    //********************************
    Buf: array[0..1] of Char;
    dwRead, Read: DWORD;
    i: integer;
    //********************************
    begin
    //передача
    datas:='a';
    //dwWrite:=datas;
    OverWrite.hEvent := CreateEvent(nil, True, False, nil);
    if OverWrite.hEvent = Null then
    raise Exception.Create('Error creating write event');

    if (not WriteFile(cId, datas, SizeOf(datas),
    dwWrite, @OverWrite))
    and (GetLastError <> ERROR_IO_PENDING) then
    raise Exception.Create('Îøèáêà îòïðàâêè');

    //********************************
    //цикл приёма
    for i:=1 to 2000 do
    begin
    dwRead:=10;
    buf:='0';
    ReadFile(cId, Buf, dwRead, Read, nil);
    if Buf[0] <> '0' then
    panel1.caption:=string(Buf);
    end;
    //********************************
    end;

  • Вариант (08.07.09 06:48) [26]

    > PooHer   (07.07.09 18:51) [25]

    Не смеюсь.Нет, работать не будет. " В одну телегу впрячь не можно. Коня и трепетную лань." (с) А. С. Пушкин - это к тому, что есди ты используешь перектрытый ввод/вывод, открыл порт с флагом FILE_FLAG_OVERLAPPED, то и запись и чтение у тебя должны быть overlapped, а ты читать пытаешься синхронно.
    И потом, если ты делаешь overlapped(перекрытую) операцию ввода/вывода, то где -то и как-то надо получить и результат ее завершения - это значит использовать или GetOverlappedResult и/или WaitForSingleObject или WaitForMultipleObjects. И ты не читал статей ?

    Прочитай, выбери один какой-то вариант работы и доводи его до ума. А то у тебя тут куча вариантов, все разные. И ошибки появляются снова и не уходят из-за этого.
  • Сергей М. © (08.07.09 10:26) [27]

    > PooHer   (07.07.09 18:51) [25]


    Зачем тебе overlapped ввод-вывод ?
    Не нужен он тебе вообще.
    Не усложняй себе жизнь.
 
Конференция "WinAPI" » COM порт Win API. Проблемы с приёмом. [D7, WinXP]
Есть новые Нет новых   [134433   +24][b:0][p:0.002]