Передача данных через модем (TAPI)
, Не работает передача, счетчик переданных байт всегда 0.
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
| [216.73.216.5] |
|
|
Соблюдайте общие правила форума
MSDN Library
FAQ раздела
Поиск по разделу
Как правильно задавать вопросы
Передача данных через модем (TAPI)
, Не работает передача, счетчик переданных байт всегда 0.
|
Сообщ.
#1
,
|
|
|
|
Пытаюсь работать с модемом через TAPI.
Все более или менее работает. Номер набирается, соединение устанавливается... Хэндл, для передачи данных получается. Покрайней мере ошибок не возникает. Хэндл получаю так: ![]() ![]() procedure TiaFlowmeterModemTAPIProvider.afterConnected; var vVarString: LPVARSTRING; begin try try vVarString := AllocMem(1024); vVarString.dwTotalSize := 1024; {$WARNINGS OFF} TapiCheck(LineGetID(0, 0, fCall, LINECALLSELECT_CALL, vVarString, 'comm/datamodem')); fCommHandle := PInteger(PChar(vVarString) + vVarString.dwStringOffset)^; {$WARNINGS ON} finally FreeMem(vVarString); end; except self.Close(); raise; end; end; Здесь в fCommHandle выставляется некий хэндл, через который я потом пытаюсь писать данные вот так: ![]() ![]() Var vOutBufLen: Cardinal; vWritedCount: Cardinal; begin If Not GetActive then raise EiaModemTAPIProviderError.Create(ERR_TP_PROVIDERINACTIVE, ERR_TP_PROVIDERINACTIVE_UIN, ERR_TP_PROVIDERINACTIVE_UIN); vOutBufLen := Length(aData); WriteFile(fCommHandle, aData[0], vOutBufLen, vWritedCount, nil); If vOutBufLen <> vWritedCount then raise EiaModemTAPIProviderError.Create(ERR_TP_WRITEDATAERROR, ERR_TP_WRITEDATAERROR_UIN, ERR_TP_WRITEDATAERROR_UIN); vOutBufLen всегда не равна vWritedBufLen, которая всегда равна 0. На той стороне тоже ничего не приходит! Пробовал посылать просто текстовую строку... Как правильно сделать??? |
|
Сообщ.
#2
,
|
|
|
|
почяему не проверяешь, что возвращает WriteFile?
|
|
Сообщ.
#3
,
|
|
|
|
Хм... не знаю. Не подумал об этом. Взял кусок из старого проекта где с ком-портом прога работала...
Посмотрю в ближайшее время, как получится с напарником состыковаться для дозвона, что она там возвращает... А пока, мне пришла в голову одна мысль... Вроде как этот хэндл должен быть открыть асинхронно... А в асинхронном режиме, вроде как этот счетчик и должне равняться нулю... Как можно открыть этот хендл в синхронном режиме? Т.к. асинхронный режим мне вообще не нужен! Только лишнее усложнение ![]() ЗЫЖ Почему в сетевое то? Уж тогда в работу с железом или АПИ |
|
Сообщ.
#4
,
|
|
|
|
Цитата Felan @ Хм... не знаю. Не подумал об этом. Знаешь, а тут думать не надо. Есть четкое правило - ВСЕГДА проверять коды возврата. Добавлено Цитата Felan @ Как можно открыть этот хендл в синхронном режиме? Т.к. асинхронный режим мне вообще не нужен! Только лишнее усложнение никак. TAPI сама открывает порт, ты на это никак повлиять не можешь.. |
|
Сообщ.
#5
,
|
|
|
|
Цитата Felan @ А пока, мне пришла в голову одна мысль... Вроде как этот хэндл должен быть открыть асинхронно... Цитата jack128 @ никак. TAPI сама открывает порт, ты на это никак повлиять не можешь.. Цитата Felan @ А в асинхронном режиме, вроде как этот счетчик и должне равняться нулю... GetOverlappedResult ?????? |
|
Сообщ.
#6
,
|
|
|
|
Так... Попробовал я посмотреть, что возвращается...
Делал так: ![]() ![]() procedure TiaFlowmeterModemTAPIProvider.Send(aData: TiaBuf; const aDoSuccessEvent, aManageErrorEvent, aDoErrorEvent: Boolean); Var vOutBufLen: Cardinal; vWritedCount: Cardinal; vWFResult: Boolean; vError: Cardinal; vOvr: TOverlapped; vS: String; Len: Integer; Buffer: array[0..255] of Char; begin If Not GetActive then raise EiaModemTAPIProviderError.Create(ERR_TP_PROVIDERINACTIVE, ERR_TP_PROVIDERINACTIVE_UIN, ERR_TP_PROVIDERINACTIVE_UIN); vOutBufLen := Length(aData); SetLastError(0); vWFResult := false; vWFResult := WriteFile(fCommHandle, aData[0], vOutBufLen, vWritedCount, {@vOvr} nil); vError := GetLastError; Len := FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_ARGUMENT_ARRAY, nil, vError, 0, Buffer, SizeOf(Buffer), nil); while (Len > 0) and (Buffer[Len - 1] in [#0..#32, '.']) do Dec(Len); SetString(vS, Buffer, Len); vS := IntToStr(vError) + ': ' + vS; if not vWFResult then showmessage(vS); If vOutBufLen <> vWritedCount then raise EiaModemTAPIProviderError.Create(ERR_TP_WRITEDATAERROR, ERR_TP_WRITEDATAERROR_UIN, ERR_TP_WRITEDATAERROR_UIN); end; WriteFile возвращает всевремя false. Если в ней вместо vOvr, стоит nil то возвращается 87. Судя по MSDN это ERROR_INVALID_PARAMETER. Исли указать оверлаппед структуру, то возвращается 6 - ERROR_INVALID_HANDLE. 1. Если я правильно понял, то писать данные синхронно нелзя совсем? ![]() 2. Как тогда правильно получить хэндл, в который писать данные? |
|
Сообщ.
#7
,
|
|
|
|
Вроде разобрался с этим всем. Все работает и передается.
Есть еще такой вопрос. Когда делаем дисконнект почему не закрывается хэндл ком-порта(хэндл через который идет передача fCommHandle из поста #1)? Если он открывается неявно, то почему его надо закрывать самому? Получается, что если при дисконнекте(закрытии) соединения не сделать ему closehandle то в следующий раз соединение не устанавливаетя по "неизвестной причине", код тапи ...000048. Если же его закрыть, то вроде все работает... |
|
Сообщ.
#8
,
|
|
|
|
Цитата Felan @ почему его надо закрывать самому? потому что так написано в sdk ;-) |
|
Сообщ.
#9
,
|
|
|
|
Блин...
Где же я это пропустил-то... ![]() Аж интересно прям теперь самому прочитать... Счас посмотрел по быстрому, опять не нашел.. |
|
Сообщ.
#10
,
|
|
|
|
Следующая проблема.
На данном этапе все работает соединяется и передается. Но, когда циклически происходит опрос, и когда много раз... В моем случае это чтение записей архива устройства чтение очень часто зависает. Т.е. read попадает на (ERROR_IO_PENDING, она кстати всегда на нее попадает, но это вроде как нормально обрабатывается...) и этот пендинг никогда не заканчивается. Чтение сделал так: ![]() ![]() procedure TiaFlowmeterModemTAPIProvider.Receive(var aData: TiaBuf; aCount: Cardinal; var aReadedCount: Cardinal; const aDoSuccessEvent, aManageErrorEvent, aDoErrorEvent: Boolean); Var vOvr: TOverlapped; vError: Cardinal; begin If Not GetActive then raise EiaModemTAPIProviderError.Create(ERR_TP_PROVIDERINACTIVE, ERR_TP_PROVIDERINACTIVE_UIN, ERR_TP_PROVIDERINACTIVE_UIN); SetLength(aData, aCount); SetLastError(0); vOvr.hEvent := CreateEvent(nil, false, false, nil); //Читаем try {$WARNINGS OFF} if ReadFile(fCommHandle, aData[0], aCount, aReadedCount, @vOvr) then begin //Проверка на правильность отправки if not GetOverlappedResult(fCommHandle, vOvr, aReadedCount, true) then showErrorMessage(GetLastError); end else begin vError := GetLastError; if (vError <> ERROR_IO_PENDING) then showErrorMessage(vError) else begin if WaitForSingleObject(vOvr.hEvent, INFINITE) = WAIT_OBJECT_0 then begin begin //Проверка на правильность отправки if not GetOverlappedResult(fCommHandle, vOvr, aReadedCount, true) then begin vError := GetLastError; if (vError <> ERROR_IO_PENDING) then showErrorMessage(vError); end; end end else begin if (vError <> ERROR_IO_PENDING) then showErrorMessage(vError) end; end; end; {$WARNINGS ON} finally CloseHandle(vOvr.hEvent); end; //Проверка на правильность принятия If aCount <> aReadedCount then raise EiaModemTAPIProviderError.Create(ERR_TP_READANSWERERROR, ERR_TP_READANSWERERROR_UIN, ERR_TP_READANSWERERROR_UIN); end; Так вот совершенно в случайном месте ожидание WaitForSingleObject(vOvr.hEvent, INFINITE) зависает до бесконечности... Если вместо INFINITE поставить таймаут, то ессно по его истечению программа продолжает работать, и ессно получаем ошибку, т.к. не все байты приняты. Так вот вопросы следующие: 1 При работе через модем нет никакого подтверждения доставки как в сокетах? Т.е. получается, что то что мне послали, впринципе может и не прийти, даже если соединение модемы не разорвали и надо еще раз повторить запрос? 2 Почему все время readFile попадает на ERROR_IO_PENDING? Даже в том случае, если чтение происходит первый раз, т.е. я псылаю первую команду, и пытаюсь читать ответ? Понятно, что при посылке я жду не опустожения буфера передачи, а момента, когда в этот буфер будет записано все, что я хочу передать, но ведь вроде полный дуплекс? Получается, что сначала надо дождаться, что бы передалось, а потом уже принимать? 3 Как вообще правильно поступать при приеме данных с модема? Как определить, что это какой-то случайная ошибка, что бы потом перезапросить данные? |
|
Сообщ.
#11
,
|
|
|
|
Цитата Felan @ 1 При работе через модем нет никакого подтверждения доставки как в сокетах? Т.е. получается, что то что мне послали, впринципе может и не прийти, даже если соединение модемы не разорвали и надо еще раз повторить запрос? Felan зачем ты заморачиваешься такой проблемой??? Ты отправил запрос и будь уверен, если канал связи налажен - то твой запрос дойдет. Как - это проблема модема. Если не получается отправить (рухнул канал) модем вернет ошибку связи, которую ты должен словить и обработать. Цитата Felan @ 2 Почему все время readFile попадает на ERROR_IO_PENDING? Ну вообще то сей флаг указывает что процедура Overlapped нормально стартовала и не закончена, т.е. число переданных/принятых байт не равно числу запрашиваемых тобой при вызове функции Read/Write. Определять, что процедура Overlapped завершена (считано/записано нужное тебе количество байт) необходимо по установке евента, дескриптор которого ты передаешь в данную процедуру. И про GetOverlappedResult не забывать, она позволяет контролировать ход отправки получения. Если, например, в течении определенного времени число принятых байт остается равным, то проверяй состояние модема (статус) - может он уже орет тебе об ошибке канала и необходимо повторить либо установку связи, либо повторно отправить запрос на прием и т.д. |
|
Сообщ.
#12
,
|
|
|
|
Суть то понятно. Я другое че-то никак не осмыслю. Связь то не рвется. А прием не заканчивается. Т.е. удаленный модем отправил данные, а они не все пришли... потерялись где-то по дороге или из-за ошибок или ище почему-то... Как это определить? Если сам модем это определяет, то что именно он говорит в таких случаях?
Я что-то смотрел в МСДН, но не понял, как это должно обрабатываться... Если не трудно по подробнее объясни? |