asker
|
|
« : 17-05-2007 07:54 » |
|
Всем привет! Не ругайтесь , что снов а завожу тему про работу с com-портом. Я просмотрел все материалы, которые нашел на сайте и в Ин тернете (не всеБ конечно, т.к. это невозможно). В общем такая ситуация: Я работаю с портом в асинхронном режиме. У меня есть поток, который читает данные и основной процесс, в котором я пишу данные в порт. В итоге он постоянно мне выводит "Протекает наложенное событие ввода-вывода". Даже если он отправляет в порт, то не читает. Я этот класс давно написал, и раньше вроде все работало, а сейчас... Да, когда писал , основывался в основном на книге Агурова Привожу код: Инициализирую: // чистка структуры memset(&m_dcb,0,sizeof(m_dcb)); // заносим значения по умолчанию m_dcb.DCBlength = sizeof(m_dcb); m_dcb.BaudRate = CBR_9600; m_dcb.ByteSize = 8; m_dcb.fParity = NOPARITY; m_dcb.StopBits = ONESTOPBIT; // Windows поддерживает только бинарный режим работы m_dcb.fBinary = 1;
// Устанавливаем тайм-ауты по умолчанию m_commTimeouts.ReadIntervalTimeout = MAXDWORD; // MAXDWORD m_commTimeouts.ReadTotalTimeoutConstant = 0; m_commTimeouts.ReadTotalTimeoutMultiplier = 0; m_commTimeouts.WriteTotalTimeoutConstant = 0; //200 m_commTimeouts.WriteTotalTimeoutMultiplier = 0;
Открываю порт void CComPort::DoOpenPort() { CString comName;
// Если порт открыт, то выходим if (GetConnected()) return;
// Имя порта comName.Format("\\\\.\\COM%-d", m_nComNumber);
// Открытие последовательного порта m_handle = CreateFile(comName, GENERIC_READ | GENERIC_WRITE, 0, // неразделяемый ресурс NULL, // нет атрибутов защиты OPEN_EXISTING, // вернуть ошибку, если ресурс не существует FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // асинхронный режим доступа NULL // должно быть NULL для COM-портов ); // Если ошибка открытия порта, то генерируем сообщение "Отказано в доступе" if (!GetConnected()) throw ERROR_ACCESS_DENIED; // Инициализация порта ApplyComSettings(); ApplyComTimeouts(); }
Пишу в буфер bool CComPort::WriteBuffer(const BYTE* buffer, const int size) { DWORD realWrite, signaled, bytesTrans, mask; OVERLAPPED writeOL; // структура для асинхронной записи bool ret;
// создание событие для асинхронной записи memset(&writeOL, 0, sizeof(writeOL)); writeOL.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); // начало асинхронной записи if (WriteFile(m_handle, buffer, size, &realWrite, &writeOL) == 0) if (GetLastError() != ERROR_IO_PENDING) { CloseHandle(writeOL.hEvent); return false; } // ожидание завершения асихронной операции и получение результата signaled = WaitForSingleObject(writeOL.hEvent, INFINITE); ret = signaled == WAIT_OBJECT_0 && GetOverlappedResult(m_handle, &writeOL, &bytesTrans, FALSE); // Закрытие дескриптора сигнального объекта CloseHandle(writeOL.hEvent); return ret; }
И, наконец, читаю UINT ReadDataFromPortOfGSMModem(LPVOID pParam) { DWORD avaibleBytes, // Число полученных, но не прочитанных байт errCode, // Код ошибки realRead, signaled, mask, bytesTrans, // Не испльзуется для WaitCommEvent dwCurSizeBuf = 0; // Текущий размер буфера, т.е. сколько байт данных в буфере OVERLAPPED readOL; // Структура для асинхронного чтения BYTE inBuffer[MAX_SIZE_BUFFER]; // Буфер приема COMSTAT currentState; UINT ret = 0; CSmsSender* pSender = (CSmsSender*) pParam; CComPort* pPort = (CComPort*) pSender->GetPort();
try { // очистка буфера memset(inBuffer, 0, sizeof inBuffer); // создание событие для асинхронного чтения readOL.Internal = readOL.InternalHigh = readOL.Offset = readOL.OffsetHigh = 0; readOL.hEvent = CreateEvent(NULL,// аттрибуты защиты такие же как и у родительского процесса TRUE, // режим управления событием ручной TRUE, // в сигнальном состоянии NULL); // безымянный
while (pPort->GetConnected()) { // пока порт открыт // Маска событий, которые будет отслеживать читающий поток // Пока это только получение символа SetCommMask(pPort->GetHandle(), EV_RXCHAR);// | EV_TXEMPTY // Ждем одно из событий WaitCommEvent(pPort->GetHandle(), &mask, &readOL); // Ждем пока завершится операция чтения signaled = WaitForSingleObject(readOL.hEvent, INFINITE); switch (signaled) { case WAIT_OBJECT_0: if (GetOverlappedResult(pPort->GetHandle(), &readOL, &bytesTrans, FALSE)) { // После GetOverlappedResult в переменной mask, которая передавалась в WaitCommEvent, // появятся флаги произошедших событий, либо 0 в случае ошибки if (( mask & EV_RXCHAR ) != 0) { // получаем состояние порта (линий и модема) currentState = pPort->GetState(errCode); // Число полученных, но не прочитанных байт avaibleBytes = currentState.cbInQue; if (avaibleBytes > 0) { if (ReadFile(pPort->GetHandle(), (inBuffer + dwCurSizeBuf), avaibleBytes, &realRead, &readOL)) { dwCurSizeBuf += avaibleBytes; if (pSender->IsDataReceived(dwCurSizeBuf, inBuffer)) { // Пакет получен полностью, предварительная обработка pSender->GetCritSectWS_Buf()->Lock(); pSender->CopyToBuffer(dwCurSizeBuf, inBuffer); pSender->GetCritSectWS_Buf()->Unlock(); // Установить событие pSender->SetEvent(); // Обнулить текущий размер буфера, т.е. буфер пуст dwCurSizeBuf = 0; // очистка буфера memset(inBuffer, 0, sizeof inBuffer); } } } } } break; case WAIT_TIMEOUT: // Действия, которые необходимо сделать, если превышен интервал ожидания break; case WAIT_FAILED: // Ошибка вызова WaitForSingleObject break; } } } catch(...) { ret = 1; } // Закрытие дескриптора сигнального объекта CloseHandle(readOL.hEvent); // Сброс события и маски ожидания SetCommMask(pPort->GetHandle(), 0);
return ret; }
Подскажите, пожалуйста.
|
|
« Последнее редактирование: 14-04-2010 05:23 от Sel »
|
Записан
|
С уважением, asker
|
|
|
korbian
Гость
|
|
« Ответ #1 : 17-05-2007 10:57 » |
|
asker, полный код приведи. Я схожую логику при работе с ком портом использую. И ничего подозрительного не вижу.
|
|
|
Записан
|
|
|
|
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии
Offline
Пол:
Бодрый птах
|
|
« Ответ #2 : 17-05-2007 21:39 » |
|
При асинхронной работе все операции чтения и записи ставятся в очередь... В том числе и ожидание... Пока ждешь запись и чтение не работают...
Происходит блокировка Пользуйся CancelIO & Purge такими вот командами для очистки очереди при принудительном чтении и семафорами для общей памяти.
|
|
|
Записан
|
А птичку нашу прошу не обижать!!!
|
|
|
asker
|
|
« Ответ #3 : 18-05-2007 01:26 » |
|
korbian, я почти полный код и привел, если несчитать методов типа Запуска, останова, приостанова потока и методов типа Set и Get. Код метода pSender->IsDataReceived(dwCurSizeBuf, inBuffer): int j; short i, k = m_strWaitingStr.GetLength(); bool fl = (m_strWaitingStr != "DEFAULT");
static int i1 = 0; TRACE("IsDataReceived :: %d, buf = %s, ret = ", i1++, (char*) pBuffer);
for(i = 0, j = 0; i < dwSize; i++) { if (i + 4 < dwSize) { if (pBuffer[i] == 'E' && pBuffer[i + 1] == 'R' && pBuffer[i + 2] == 'R' && pBuffer[i + 3] == 'O' && pBuffer[i + 4] == 'R') { TRACE("true\n"); return true; // нашли ERROR } } else if (i + 1 < dwSize) { if (pBuffer[i] == 'O' && pBuffer[i + 1] == 'K') { TRACE("true\n"); return true; // нашли OK } } else if (fl && i + k < dwSize) { for( ; (j < k && pBuffer[i + j] == m_strWaitingStr[j]); j++); if (j == k) { TRACE("true\n"); return true; // нашли строку, которую ждем } else j = 0; } else { TRACE("false\n"); return false; // мы ничего не нашли } } TRACE("false\n"); return false;
Что же касается этого куска, то: в строчках 1 и 3 получается указатель на критическую секцию CCriticalSection и выполняется блокировка и разблокировка. pSender->GetCritSectWS_Buf()->Lock(); pSender->CopyToBuffer(dwCurSizeBuf, inBuffer); pSender->GetCritSectWS_Buf()->Unlock(); Метод CopyToBuffer(dwCurSizeBuf, inBuffer) выглядит так: void CSmsSender::CopyToBuffer(const DWORD dwSize, const char* pBuffer) { m_strBuffer = pBuffer; }
CString m_strBuffer; - член класса. korbian, ты этот код имел ввиду или что-то другое. Просто если весь приводить то очень много получится. Гром я не совсем понял что ты сказал. Ведь с лучае записи я жду, чтобы данные отправились. Значит в этот момент мне прием данных и не нужен. Потом когда я должен пользоваться Purge ведь я могу дать команду на отчистку, а до этой команды пришедшие данные уже в буфере и у меня будет потеря или я не все отправил и даю команду Purge, то же потеря. Тоже самое с CancelIO. А у меня еще пару вопросов: ( mask & EV_RXCHAR ) != 0 - это правильно, вроде да, но... Когда я должен пользоваться флагом EV_TXEMPTY при записи или чтении. Вроде при записи. Тогда перед WriteFile я должен написать SetCommMask(m_handle, EV_TXEMPTY), а после WriteFile и перед WFSO - WaitCommEvent(...). if (mask & EV_TXEMPTY) {WFSO...}. Так ведь? И последнее (правда это не совсем по теме). Как мне узнать используемые параметры (DCB, тайм-ауты) порта на втором конце. Т.е. я посылаю команды и жду данные от мобильника. Мобильник подключается к USB. Я связываюсь с мобильником через виртуальный com-порт. Может все дело в настройках?
|
|
|
Записан
|
С уважением, asker
|
|
|
asker
|
|
« Ответ #4 : 18-05-2007 02:27 » |
|
Сейчас попробовал с обычным модемом, здесь все нормально. Т.е. отсылает и принимает. Так что похоже действительно все ошибки связаны с настройками порта. Если работать через hyperTerminal с мобильником и воспользоваться прогой PortMon, то терминал устанавливает следующие параметры: bufInsize=8192 bufOutSize=8192 size = 0 Stopbits: 1 Parity: None LenWord: 8 EOF: 0 ERR: 0 BRK: 0 EVT: 0 XON: 11 XOFF: 13 SHAKE: 80000009 REPLACE: 80000080 XonLimit: 80 XoffLimit: 200 RI: 10 RM: 0 RC: 0 WM: 0 WC: 5000 MASK RLSD ERR
Что такое SHAKE и REPLACE. В DCB структуре есть поле frtsControl, которое может принимать значение RTS_CONTROL_HANDSHAKE. Но когда я его установил SHAKE: 80 REPLACE: 00 (помойму либо тоже 80). Или это настройки HyperTerminal'а и они так связываются со всеми - сейчас посмотрю..., придется отключиться. - да терминал и для моего модема тоже самое поставил. так что... Подскажите... Я вчера до того дошел, что у меня комп при чтении из порта на функции получения статуса модема шел на перезагрузку ... и это не один раз, а раза 4.
|
|
|
Записан
|
С уважением, asker
|
|
|
vegor
Интересующийся
Offline
|
|
« Ответ #5 : 01-03-2010 10:07 » |
|
здравствуйте всем,я в форумах в первие ,и просил бы не судить очень строго. помогите пожалуйста , хочу реализовать приложение работающую с <COM> портом.А для проверки работы приложения коротко замыкаю(к.з.) ножки RD(Вх.) и TD(Вых.) , чтобы WriteFile дала данные а ReadFile считало бы те же данные с того же порта. сначало создаю диологовое приложение <bbb> а потом например в OnInitDialog()-е создаю COM-порт { ...
OVERLAPPED ovr;
hCOM = CreateFileA("COM1", GENERIC_READ |GENERIC_WRITE, // создание синхронного порта 0,NULL,OPEN_EXISTING,NULL,NULL); PurgeComm(hCOM,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); ///restart GetCommState(hCOM,&dcb); SetCommState(hCOM,&dcb); SetCommTimeouts(hCOM,&to);
SetupComm(hCOM,in,out);
//memset(&ovr,0,sizeof(ovr)); //ovr.hEvent =::CreateEventA(NULL,FALSE,FALSE,NULL);
PurgeComm(hCOM,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); ///restart
int in = 0; int out = 0;
return TRUE; // return TRUE unless you set the focus to a control } потом создаю кнопку и в нем создаю поток ... CbbbDlg* lpMyObject = new CbbbDlg; AfxBeginThread(MyFunction, lpMyObject,0,0,0,0);
а в MyFunction-е ... UINT MyFunction(LPVOID pParam); UINT MyFunction(LPVOID pParam) { CbbbDlg* lpObject = (CbbbDlg*)pParam; // CSingleLock FirstLock(&(lpObject->m_Critic)) ; /// что то для синхронизации
lpObject->OnBnClickedButtonWrite(); // в нем WriteFile
return 0;
} а в void CbbbDlg::OnBnClickedButtonWrite() { out = 20; /// например out = 20 while(1) WriteFile(hCOM,(LPCVOID)&out,sizeof(out),&dw,&ovr);
}
и создаю кнопку для чтения из порта void CbbbDlg::OnBnClickedButtonReadCom() ///кнопка {
ReadFile(hCOM , (LPVOID)&in , sizeof(in) , &dw , &ovr); m_edit_int = in; /// m_edit_int это <edit control> где должен отображатся <in> UpdateData(FALSE); }
а в конце void CbbbDlg::OnBnClickedButtonCancel() /// Cancel { PurgeComm(hCOM,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); ///restart CloseHandle(hCOM);
OnOK(); }
не какой ошибки не дает а после запуска приложения когда нажимаю кнопку OnBnClickedButtonReadCom() в <edit control>-е ничего не изменяется , результат <0>
|
|
« Последнее редактирование: 29-03-2010 08:12 от Вад »
|
Записан
|
|
|
|
vegor
Интересующийся
Offline
|
|
« Ответ #6 : 29-03-2010 07:46 » |
|
УРА, получилась после двуx месяцев: спасибо большое за помошь<Алексей1153++>,<resource>,<RXL>,<lag> и всем другим <Алексей1153++> той книгой была книга Секунова "VC++.NET" самоучитель. И ТАК оказывается, что проблема была в обьявлений порта . Сначало надо было обьявить <событье> об обязательности которого я нигде не встричал. Когда внедрял в прогу эти строки только тогда и получилось , и без какого либо создания, нового потока(но этим думаю тоже можно ): ovr.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); И упомяну, что надо обязательно для своей страxовки в ручную установить обьем информационного баита(по своему расчетному протоколу для обмена информаций),потому что сначало сделал DCB структуру по умолчанию(dcb.ByteSize = 8;) а оно на самом деле взял dcb.ByteSize = 7; и больше числа (pow(2,7)==128) 127 уже передавал неправильно. И интересно то что на самом деле данные из передающего(приемного) буфера не теряются до поступления новой информации.В обшем структура такая ///hCOM = CreateFileA("COM1", GENERIC_READ |GENERIC_WRITE, ///так давал проблемы /// 0,NULL,OPEN_EXISTING,NULL,NULL); ////chi linum hCOM = CreateFileA("COM1", GENERIC_READ |GENERIC_WRITE, ///sozdanie 0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL); PurgeComm(hCOM,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); ///restart DCB dcb;
bSuccess = GetCommState(hCOM,&dcb); dcb.BaudRate = CBR_9600; ////aragutyun@ dcb.ByteSize = 8; ///informacion biteri qanak@ I/O bayteri mech /* dcb.DCBlength; ///dcb -i erkarutyunn e bayterov dcb.EofChar; ///dannineri prcnel@ cuyc tvox simvol dcb.ErrorChar = 0; ////zuygutyan simvoli sxal lineln e cuyc talis dcb.EvtChar; dcb.fAbortOnError = 0; ///ete ka sxal read/write -n kasecnum e dcb.fBinary; /// <1> dcb.fDsrSensitivity = 0; ///DSR -i handep sarqi zgayunutyunn e stugum dcb.fDtrControl; ////DTR signalin xekavarelu rejim dcb.fDummy2; /// == <0> chi ogtagorcvum dcb.fErrorChar; dcb.fInX; ///////talis e XON/XOFF xekavarum <xoffLim,xonLim simvolneri het > dcb.fNull; /// <o>-yakan bayt@ den e netum dcb.fOutX; ////talis e XON/XOFF xekavarum <xoffChar,xonChar simvolneri het > dcb.fOutxCtsFlow= 0; ////miacnum e CTS-in hetevelu rejim@ dcb.fOutxDsrFlow; ////miacnim e DSR....... dcb.fParity = 0; ////miacnum e bit chotnsti-n dcb.fRtsControl ; ///RTS -ic kaxvac patoki xekavarum e anum //dcb.fTXContinueOnXoff = 1; ////@ndunox buferi lcweluc , haxordman verchanaln e stugum dcb.Parity = NOPARITY; ///// kam=0 , kam=1 dcb.StopBits = ONESTOPBIT; //// 0 , 1 ,2 == <1>bit <1,5>bit <2>bit dcb.wReserved; ////chi ogtagorcvum dcb.wReserved1; ////chi ogtagorcvum dcb.XoffChar; /// XOFF simvoln e dcb.XoffLim; ////max -al simvolneri qanak@ @ndunox buferum XOFF-ic arach dcb.XonChar; /// XONN simvoln e dcb.XonLim; ////min -al simvolneri qanak@ @ndunox buferum XON-ic arach
*/
SetCommState(hCOM,&dcb);
if(!SetCommState(hCOM,&dcb)) { MessageBoxA(NULL,"не может установить конфигурацию","Заголовок потока",NULL); }
bSuccess = SetCommMask(hCOM, (DWORD)( EV_BREAK | EV_RXCHAR )); if (!bSuccess) { MessageBoxA(NULL,"SetCommMask -@ ustanowka chi exel","Заголовок потока",MB_OK); return -1; }
PurgeComm(hCOM,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); ///restart
SetCommTimeouts(hCOM,&to);
//SetupComm(hCOM,1024,1024); ///не обезательно в маленькиx буфераx
ovr.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
ovr.Internal = 0; ovr.InternalHigh = 0; ovr.Offset = 0 ; ovr.OffsetHigh = 0 ; //ovr.Pointer ;
PurgeComm(hCOM,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); ///restart
а потом где то в OnBnClickedButtonwrite() ///write -е (кнопка)
{ in = 0; out = edit_write;
BYTE* a = (BYTE*)(&out); ////побаитовое передача/прием BYTE a0 = a[0]; BYTE a1 = a[1]; BYTE a2 = a[2]; BYTE a3 = a[3]; //WriteFile(hCOM,(LPCVOID)&out,sizeof(out),&dw,&ovr); /// можно и так //Sleep(80); /// можно и так //ReadFile(hCOM , (LPVOID)&in , sizeof(in) , &dw , &ovr); /// можно и так BYTE* b = (BYTE*)(&in); ////побаитовое передача/прием BYTE b0 = b[0]; BYTE b1 = b[1]; BYTE b2 = b[2]; BYTE b3 = b[3];
for(int i=0 ; i<4 ; i++) { WriteFile(hCOM,(LPCVOID)&a[i],sizeof(a[i]),&dw,&ovr);
//out = 0; Sleep(80); ReadFile(hCOM , (LPVOID)&b[i] , sizeof(b[i]) , &dw , &ovr); } ///// ptr_in это указатель (&ptr_in) ptr_in = (int*)&b[0]; in = *ptr_in ; edit_int = in; UpdateData(FALSE);
PurgeComm(hCOM,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); ///restart
edit_write = 0; UpdateData(FALSE);
}
теперь один косметический момент: В передаюшем <edit box> -е когда все числа стираю передоется сообшение "Enter an Integer" Как? нзбежать этого . Использовал событье EN_CHENGE: void CMy200310Dlg::OnEnChangeEditWrite() { UpdateData(TRUE); } и просил бы если сможете подскажите как? можно например BMP фаил разделить на баиты, потом каким то своим законом кодировать и отправить ... потом получатель смог бы тем же самым законом преобразовать в BMP фаил, чтоб другие смогли взять и смотреть картинку. СНОВА СПОСИБО за ПОМОЩ. Пусть БОГ благославит вас всеx.
|
|
« Последнее редактирование: 29-03-2010 07:58 от Алексей1153++ »
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #7 : 29-03-2010 08:03 » |
|
упомяну, что надо обязательно для своей страxовки в ручную установить
вообще-то, инициализировать структуру DCB удобно при помощи GetCommState, а потом поверх расставить свои поправки Как передать файл (вообще любой файл) - открываешь файл (CreateFile) , делаешь с массивом байтов что нужно, передаёшь какими нужно кусочками. На том конце всё в обратном порядке делаешь - и файл передан Использовал событье EN_CHENGE:
а ты не используй событие - бери данные из окошка тогда, когда жмут на кнопку
|
|
|
Записан
|
|
|
|
vegor
Интересующийся
Offline
|
|
« Ответ #8 : 08-04-2010 12:24 » |
|
какым способом можно в рабочем потоке написать функций которые не я создал , например UpdateData() , Sleep(50) , ReadFile(),... У меня задает ошибки ,почему так получается ,может кто небуть обьяснить? , так должно и быть?. И это для того чтобы во время приема - передачи данных главный поток не был занят этим...
|
|
|
Записан
|
|
|
|
Kivals
|
|
« Ответ #9 : 08-04-2010 13:10 » |
|
Попытаюсь догадаться: проблема с синхронизацией потоков. Если это так - читай теорию про многопоточную синхронизацию (события, семафоры, мьютексы, ...)
|
|
|
Записан
|
|
|
|
|