Comm-port reader
От: Mag Россия  
Дата: 28.05.03 14:02
Оценка:
Помогите с чтением из com-порта. Вот тривиальная задача.
Создаётся отдельный поток. Он выполняет следующие действия.
1. Открыть com-порт (CreateFile... — здесь всё просто).
2. Настроили порт, как надо (тут тоже не проблема).

Цикл:
3. Организуем ожидание события принятия байта из com-порта. Вот тут ключевая проблема. Должно быть что-то с WaitForSingleObject, WaitCommEvent или что-то ещё.
4. По принятию байта помещаем его в массив.

5. Закрываем com-порт.

Хитрость задачи состоит в том, что количество принимаемых байт не определено. Т.е. процесс приёма непрерывен: есть что-то — принимаем. Может есть у кого реально работающий кусок кода, реализующий поставленную задачу. Буду премного благодарен.
... << RSDN@Home 1.0 beta 7a >>
Re: Comm-port reader
От: Аноним  
Дата: 28.05.03 14:16
Оценка: 2 (1) +1
Здравствуйте, Mag, Вы писали:

Mag>Помогите с чтением из com-порта. Вот тривиальная задача.

Mag>Создаётся отдельный поток. Он выполняет следующие действия.
Mag>1. Открыть com-порт (CreateFile... — здесь всё просто).
Mag>2. Настроили порт, как надо (тут тоже не проблема).

Mag>Цикл:

Mag>3. Организуем ожидание события принятия байта из com-порта. Вот тут ключевая проблема. Должно быть что-то с WaitForSingleObject, WaitCommEvent или что-то ещё.
Mag>4. По принятию байта помещаем его в массив.

Mag>5. Закрываем com-порт.


Mag>Хитрость задачи состоит в том, что количество принимаемых байт не определено. Т.е. процесс приёма непрерывен: есть что-то — принимаем. Может есть у кого реально работающий кусок кода, реализующий поставленную задачу. Буду премного благодарен.




Простите, а в чем все таки проблема? Количество байт неопределено, но у Вас есть настраиваемый параметр сомм-порта ReadIntervalTimeout. Как только он истек, процедура чтения завершена. Параметр сколько байт надо прочитать из порта в функции ReadFile пусть будет большим, например размер буфера приемника. По окончании таймаута все что принято — все Ваше. Обработайте и возвращайтесь к ожиданию события приема символа и так бесконечно. А порт можно закрывать когда завершится поток чтения.
Второй вариант: как только случилось EV_RXCHAR вызовите ClearCommError и прочтите сколько байт уже поступило во "внутренний буфер" сомм-порта. Вызовите ReafFile с полученным параметром.


void CCommPort::InThread()
{
BOOL fSuccess=0;
DWORD nBytesRead=0,dwEvtMask=0,dwError=0,error=0,fRes=0;
COMSTAT Comstatus;
OVERLAPPED overlapped;

memset(&overlapped,0,sizeof(OVERLAPPED));
memset(&Comstatus ,0,sizeof(COMSTAT));

overlapped.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL);

m_InBufNotEmpty =CreateEvent(NULL, TRUE, FALSE, NULL);
m_OutBufNotEmpty =CreateEvent(NULL, TRUE, FALSE, NULL);

m_InThreadIsLive=1;
m_nBytesRead=0;

int Ind = 0;

CRotorApp *pApp=NULL;
pApp=(CRotorApp *)AfxGetApp();

if(pApp==NULL)
{
//Ваша заглушка ошибки
return;
}

for(;)
{
nBytesRead=0;

m_Repeat=FALSE;

m_InThreadIsLive=1;

fRes=0;
fSuccess=0;

if(!ResetEvent(overlapped.hEvent))

{
//Ваша заглушка ошибки
}

if(!ResetEvent(m_InBufNotEmpty))
{
//Ваша заглушка ошибки
}

if(!WaitCommEvent(m_PortHandle, &dwEvtMask, &overlapped))
{
if(GetLastError()!=ERROR_IO_PENDING)
{
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf, 0, NULL );
AfxMessageBox((LPCTSTR)lpMsgBuf, MB_OK | MB_ICONINFORMATION );
FinishInThread();
}
WaitForSingleObject(overlapped.hEvent,INFINITE);
}

if (dwEvtMask & EV_BREAK)
{
//Ваша заглушка ошибки
}
else
if (dwEvtMask & EV_RXCHAR)
{
ClearCommError(m_PortHandle,&dwError,&Comstatus);

if(!ResetEvent(overlapped.hEvent))
{
//Ваша заглушка ошибки
}

if(!ReadFile(m_PortHandle,
&m_InBuffer[Ind],
MAX_BUFFER_SIZE,//Comstatus.cbInQue,
&nBytesRead,
&overlapped))
{
if(GetLastError()!=ERROR_IO_PENDING)
{
//Ваша заглушка ошибки
}

fRes=WaitForSingleObject(overlapped.hEvent,7000);

switch(fRes)
{
case WAIT_OBJECT_0:
if(!GetOverlappedResult(m_PortHandle, &overlapped, &nBytesRead, FALSE))
{
//Ваша заглушка ошибки
}
break;
case WAIT_TIMEOUT:
break;
default:
//Ваша заглушка ошибки
break;
}
}


if(!ResetEvent(overlapped.hEvent))
{
//Ваша заглушка ошибки
}
if(nBytesRead>0)
{
//Можно обрабатывать сообщение
}
}
}
}
Re: Comm-port reader
От: dandy  
Дата: 29.05.03 02:08
Оценка:
Здравствуйте, Mag, Вы писали:

Mag>Помогите с чтением из com-порта. Вот тривиальная задача.

Mag>Создаётся отдельный поток. Он выполняет следующие действия.
Mag>1. Открыть com-порт (CreateFile... — здесь всё просто).
Mag>2. Настроили порт, как надо (тут тоже не проблема).

Mag>Цикл:

Mag>3. Организуем ожидание события принятия байта из com-порта. Вот тут ключевая проблема. Должно быть что-то с WaitForSingleObject, WaitCommEvent или что-то ещё.
Mag>4. По принятию байта помещаем его в массив.

Mag>5. Закрываем com-порт.


Mag>Хитрость задачи состоит в том, что количество принимаемых байт не определено. Т.е. процесс приёма непрерывен: есть что-то — принимаем. Может есть у кого реально работающий кусок кода, реализующий поставленную задачу. Буду премного благодарен.



dandy>

Попробуй посмотреть на codeproject.com, там есть несколько классов для
работы с comm — port, к тому же в некоторых статьях довольно подробно все обьясняется.
Успехов!
Re: Comm-port reader
От: lyudmil_selin Болгария  
Дата: 03.09.03 09:58
Оценка:
Здравствуйте, Mag, Вы писали:

Mag>Помогите с чтением из com-порта. Вот тривиальная задача.

Mag>Создаётся отдельный поток. Он выполняет следующие действия.
Mag>1. Открыть com-порт (CreateFile... — здесь всё просто).
Mag>2. Настроили порт, как надо (тут тоже не проблема).

Mag>Цикл:

Mag>3. Организуем ожидание события принятия байта из com-порта. Вот тут ключевая проблема. Должно быть что-то с WaitForSingleObject, WaitCommEvent или что-то ещё.
Mag>4. По принятию байта помещаем его в массив.

Mag>5. Закрываем com-порт.


Mag>Хитрость задачи состоит в том, что количество принимаемых байт не определено. Т.е. процесс приёма непрерывен: есть что-то — принимаем. Может есть у кого реально работающий кусок кода, реализующий поставленную задачу. Буду премного благодарен.


Я из Болгарии; с русской киррилице у меня не совсем в порядке, некоторие букви нету, но надеюсь и так поймете:
1; тред приема — должна бит глобальная в приложении и поставь в коде перед ее визовом
//------------------------------------------------------------------------
static HANDLE hRxThread;
FILE *hf;

DWORD WINAPI RxThread(LPVOID dl)
{
CEsaDlg *cpdlg=(CEsaDlg *)dl;
HANDLE hComm = cpdlg->hComm;

DWORD dResult=1;
DWORD dBytes;
DWORD dNumberOfBytes;
unsigned char Buffer[100];
BOOL bSuccess;

while (cpdlg->nThr_cmd)
{
Sleep (1);

dNumberOfBytes=21;
bSuccess=ReadFile (hComm, Buffer, dNumberOfBytes, &dBytes, NULL);
if (!bSuccess) continue;

if (dBytes)
{
cpdlg->ReceiveData (Buffer, (int)dBytes);
}
}
return dResult;
}
//----------------------------------------------------------------------
dNumberOfBytes — количество байтов, которие принимаешь, лучше принимай по одному если пакети произвольной длини
*cpdlg — указатель, необходим для доступа к функциям и переменним класса /он у меня називается CEsaDlg/
ReceiveData (Buffer, (int)dBytes) — член-функция класса, где обрабативаесх принйатие байти

ниже инициализация порта

//------------------------------------------------------------------------
int CEsaDlg::InitComPort(int nPort)
{
char port[10]="COM";
char Digit[2];
COMMTIMEOUTS to;
DCB dcb;
DWORD dThreadID;

itoa (nPort,Digit,10);
strcat (port,Digit);

hComm = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

if (hComm == INVALID_HANDLE_VALUE)
{
return 1;
}

to.ReadIntervalTimeout = 1;
to.ReadTotalTimeoutMultiplier = 1;
to.ReadTotalTimeoutConstant = 1;

to.WriteTotalTimeoutMultiplier = 1;
to.WriteTotalTimeoutConstant = 1;
SetCommTimeouts(hComm, &to);

GetCommState(hComm, &dcb);

dcb.fParity = FALSE;
dcb.BaudRate = 57600;
//dcb.BaudRate = 115200;
//dcb.BaudRate = 256000;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.fBinary = TRUE;

SetCommState(hComm, &dcb);

nThr_cmd = 1; // enable trhead

hRxThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RxThread,(LPVOID)this,0,&dThreadID);
return 0;
}
//----------------------------------------------------------------------

ниже функция обработки принятих байтов
//------------------------------------------------------------------------
void CEsaDlg::ReceiveData(unsigned char *Buffer, int Bytes)
{
// код напиши сам
}

ниже функция закрития порта, необходимо когда надо открить другой порт не закривая приложение
//------------------------------------------------------------------------
void CEsaDlg::CloseComPort()
{
if (hComm != INVALID_HANDLE_VALUE)
{
nThr_cmd = 0; // disable thread
PurgeComm(hComm, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
WaitForSingleObject(RxThread, INFINITE);
CloseHandle(hComm);
CloseHandle(RxThread);
}
}
//------------------------------------------------------------------------

у меня ето работает отлично;
если проблеми — пиши — lyudmil_selin@yahoo.com
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.