[문의] 시리얼 포트가 제대로 열릴 때가 있고, 그렇지 않을 때가 있네요..

liveeasily의 이미지

시리얼 통신을 이용한 프로그램을 짜고 있습니다.

시리얼 포트를 열면 쓰레드가 생성됩니다.

그 쓰레드는 select 를 통하여 수신할 데이트가 도착하면 큐에 저장해 둡니다.

그리고 응용해서 필요할 때 그 큐에서 읽어가는 방식으로 짜보았습니다.

문제는 프로그램을 실행해 보면 정상작동할 때가 있고, 그렇지 않은 경우가 있습니다.

소스는 다음과 같습니다.

#include "CSerial.h"
#include <errno.h>
 
/* ---------------------------------------------------------------- */
//	description : 생성자
/* ---------------------------------------------------------------- */
CSerial::CSerial()
{
	m_bConnect = FALSE;
	//signal(SIGINT, HandlerSignal);
}
 
/* ---------------------------------------------------------------- */
//	description : 소멸자
/* ---------------------------------------------------------------- */
CSerial::~CSerial()
{ 
	printf("called destructor\n");
 
	if( FALSE == m_bConnect	)
		ClosePort();
 
	pthread_cancel(m_tidWatchPort);
}
 
/* ---------------------------------------------------------------- */
//	description : 시리얼 포트를 연다.
/* ---------------------------------------------------------------- */
int CSerial::OpenPort(char *szDevName, int nBaud)
{
	int nBaudBit;
 
	m_fdSerial = open(szDevName, O_RDWR | O_NOCTTY | O_NONBLOCK);
	if( m_fdSerial < 0 ) {
		printf("%s open failed.. \n", szDevName);
		return FALSE;
	}
 
	printf("m_fdSerial = %d\n", m_fdSerial);
 
	tcgetattr(m_fdSerial, &m_tioOld);
 
	if( -1 == (nBaudBit = ConvertBaud(nBaud)) ) {
		printf("wrong baud rate.. \n");
		return FALSE;
	}
	m_tioNew.c_cflag = nBaudBit | CRTSCTS | CS8 | CLOCAL | CREAD;
	m_tioNew.c_iflag = IGNPAR;
	m_tioNew.c_oflag = m_tioNew.c_lflag = 0;
	m_tioNew.c_cc[VMIN] = 1;
	m_tioNew.c_cc[VTIME] = 0;
	tcflush(m_fdSerial, TCIFLUSH);
	tcsetattr(m_fdSerial, TCSANOW, &m_tioNew);
 
	m_bConnect = TRUE;
 
	if( (pthread_create(&m_tidWatchPort, NULL, ThreadWatchPort, this)) < 0 ) {
		printf("thread create failed..\n");
		tcsetattr(m_fdSerial, TCSANOW, &m_tioOld);
		return FALSE;
	}
 
	return TRUE;
}
 
/* ---------------------------------------------------------------- */
//	description : 시리얼 포트를 닫는다.
/* ---------------------------------------------------------------- */
void CSerial::ClosePort()
{
	tcsetattr(m_fdSerial, TCSANOW, &m_tioOld);
 
	if( TRUE == m_bConnect)
		close(m_fdSerial);
 
	m_fdSerial = 0;
 
	m_bConnect = FALSE;
}
 
/* ---------------------------------------------------------------- */
//	description : 정수형으로 된 baud 를 c_cflag 용 bit로 변환하여 반환
/* ---------------------------------------------------------------- */
int CSerial::ConvertBaud(int nBaud)
{
	switch( nBaud ) {
	case 9600:
		return B9600;
	case 19200:
		return B19200;
	case 38400:
		return B38400;
	case 57600:
		return B57600;
	case 115200:
		return B115200;
	}
 
	return -1;
}
 
/* ---------------------------------------------------------------- */
//	description : 큐 버퍼로 부터 데이터를 읽는다.
/* ---------------------------------------------------------------- */
int CSerial::Read(char *pBuff, int nToRead)
{
	int i;
	int nRead;							// 실제 읽은 바이트 수
	int nQueueSize = m_quRead.GetSize();
 
	if( nQueueSize < nToRead )
		nToRead = nQueueSize;
 
	for( i=0; i<nToRead; i++ )
	{
		if( FALSE == m_quRead.GetByte(pBuff+i) ) {
			printf("get data from queue failed..\n");
			return 0;
		}
	}
 
	return <!--break-->nToRead;
}
 
 
/* ---------------------------------------------------------------- */
//	description : 시리얼 포트로 데이터를 전송시킨다.
/* ---------------------------------------------------------------- */
int CSerial::Write(char *pBuff, int nToWrite)
{
	int nWrite;			// 실제 전송한 바이트 수
 
	nWrite = write(m_fdSerial, pBuff, nToWrite);
 
	return nWrite;
} 
 
/* ---------------------------------------------------------------- */
//	description : 시리얼 포트를 감시하는 스레드
/* ---------------------------------------------------------------- */
void* ThreadWatchPort(void* arg)
{
	fd_set readSet;
	int fdSerial;
	int nRead, i;
	char buf[255] = "";
	CSerial *serial = (CSerial*)arg;
	extern int errno;		
 
	fdSerial= serial->GetFD();
	FD_ZERO(&readSet);
	FD_SET(fdSerial, &readSet);	
 
	while( serial->isConnect() ) {
 
		printf("select.....\n");
 
		if( select(fdSerial+1, &readSet, NULL, NULL, NULL) == -1 ) {
			perror("fdSerial");
			printf("errno = %d\n", errno);
			printf("fd = %d\n", fdSerial);
			return FALSE;
		}
 
		if( FD_ISSET(fdSerial, &readSet) != 0 ) {
			printf("fd_isset.....\n");
			nRead = read(fdSerial, buf, 255);
			printf("read in thread %d byte : %s\n", nRead, buf);
			for( i=0; i<nRead; i++) {
				if( FALSE == serial->m_quRead.PutByte(buf[i]) ) {
					return FALSE;
				}
			}
			memset(buf, 0, 255);
		}
 
	}
 
	printf("thread end\n");
 
	return (void*)TRUE;
}

에러 발생시 쓰레드의 select 부분에서 발생합니다. 리턴값이 -1이며 errno=29 입니다.

정상적으로 실행이 안되는 경우에는 포트가 제대로 열리지 않은 것으로 추측해봤지만,

fd 값이 양수값(보통 3으로 잡히더군요) 인 것으로 보아 그 문제는 아닌 것으로 판단했습니다.

아무리 생각해도 무엇이 문제인지 잘 모르겠습니다.

조언 부탁드리겠습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.