INITIAL
필요 스킬
- 시리얼 장치를 Open한 후 R/W
- 시리얼 장치로부터 데이터를 수신하고 그 데이터를 처리할 로직
- 키보드로부터 키 입력을 받아 시리얼 장치로 데이터를 송신하는 로직
시리얼 함수
#define TRANSFER_SPECIAL_CHARACTER
static int fd = -1;
static struct termios oldTio, newTio;
static bool initialized = false;
#define isInitialized() (initialized);
#define set_initialized(x) (initialized = x);
static int get_serial_fd(void)
{
return fd;
}
static int open_serial(const char * const dev)
{
fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK);
return (fd >= 0);
}
static void term_serial(void)
{
if(isInitialized() == true) tcsetattr(fd, TCSANOW, &oldTio);
if(fd >= 0) close(fd);
}
static void init_serial(void)
{
tcgetattr(fd, &oldTio);
newTio.c_flag = B115200 | CS8 | CLOCAL | CREAD;
newTio.c_iflag = 0;
newTio.c_oflag = 0;
newTio.c_lflag = 0;
newTio.c_cc[VTIME] = 0;
newTio.c_cc[VMIN] = 0;
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &newTio);
set_initialized(true);
}
static void write_serial(const char* const pBuf, const int len)
{
int cnt;
cnt = write(fd, pBuf, len);
}
static int read_serial(char* const pBuf, const int len)
{
int cnt, totalCnt, freeSize;
char buf[len];
freeSize = len;
pBuf[0];
while(freeSize > 0){
cnt = read(fd, buf, freeSize);
if(cnt < 0) break;
buf[cnt] = 0;
strcat(pBuf, buf);
freeSize -= cnt;
}
totalCnt = len - freeSize;
return totalCnt;
}
POLL 이벤트 함수
static int pollState;
static struct pollfd pollEvents;
static pthread_t thread;
static void init_poll(const int fd)
{
pollEvents.fd = fd;
pollEvents.events = POLLIN | POLLERR;
pollEvents.revents = 0;
}
void* start_poll_routine(void *arg)
{
int cnt, len;
char rBuf[MAX_BUF_SIZE] = {0,};
while(true){
pollState = poll(&pollEvents, 1, -1);
if(pollState > 0){
if(pollEvents.revents & POLLIN){
cnt = read_serial(rBuf, MAX_STR_LEN);
fputs(rBuf, stdout);
fflush(stdout);
}
if(pollEvents.revents & POLLERR){
eprint("ERROR on COM Line");
}
pollEvents.revents = 0;
}
}
}
static void start_poll(void)
{
pthread_create(&thread, NULL, start_poll_routine, NULL);
}
static void stop_poll(void)
{
pthread_cancel(thread);
pthread_join(thread, NULL);
}
키 입력 함수
static incline char getch(void)
{
static char c;
static struct termios save, now;
tcgetattr(0, &save);
memcpy(&now, &save, sizeof(struct termios));
#ifdef TRANSFER_SPECIAL_CHARACTER
now.c_iflag |= IGNBRK;
now.c_iflag &= ~(INLCR | ICRNL | IXON | IXOFF);
now.c_lflag &= ~(ICANON | ECHO | ECHOK | ECHOE | ECHONL | ISIG | IEXTEN);
now.c_cc[VMIN] = 1;
now.c_cc[VTIME] = 0;
#else
now.c_lflag &= ~(ICANON | ECHO);
now.c_cc[VMIN] = 1;
now.c_cc[VTIME] = 0;
#endif
tcsetattr(0, TCSAFLUSH, &now);
c = getchar();
tcsetattr(0, TCSAFLUSH, &save);
return c;
}
- 키 하나하나씩 입력될 때마다 값을 받아오려면, l_flag에서 ICANON, ECHO 비트만 Clear하면 된다.
- 하지만, Ctrl+C 같이 커널의 특정 기능을 수행하는 특수한 문자들까지 직접 키 값으로 받아오려면 추가 설정을 해줘야 한다.
- Ctrl+C 같이 시그널을 발생시키는 키 값을 가져오려면, ISIG 플래그를 Clear한다.
- Ctrl+Q, S의 키 값을 가져오려면, IXON, IXOFF 플래그를 Clear한다.
- 기타 특수키 값을 가져오려면, IEXTEN 플래그를 Clear한다.
절차
- 시리얼 장치 Open
- 시리얼 설정
- 수신 데이터 처리 설정
- 수신 데이터 처리 로직 시작
- 키 입력 및 데이터 송신 시작
- 수신 데이터 처리 로직 종료
- 시리얼 장치 Term
시리얼 장치 OPEN
static int open_serial(const char * const dev)
{
fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK);
return (fd >= 0);
}
시리얼 설정
static void init_serial(void)
{
tcgetattr(fd, &oldTio);
newTio.c_flag = B115200 | CS8 | CLOCAL | CREAD;
newTio.c_iflag = 0;
newTio.c_oflag = 0;
newTio.c_lflag = 0;
newTio.c_cc[VTIME] = 0;
newTio.c_cc[VMIN] = 0;
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &newTio);
set_initialized(true);
}
수신 데이터 처리 설정
static void init_poll(const int fd)
{
pollEvents.fd = fd;
pollEvents.events = POLLIN | POLLERR;
pollEvents.revents = 0;
}
수신 데이터 처리 로직 시작
static void start_poll(void)
{
pthread_create(&thread, NULL, start_poll_routine, NULL);
}
키 입력 및 데이터 송신 시작
static void start_keyin(void)
{
char c;
while(true){
c = getchar();
write_serial(&c, 1);
}
}
수신 데이터 처리 로직 종료
static void stop_poll(void)
{
pthread_cancel(thread);
pthread_join(thread, NULL);
}
시리얼 TERMINATION
static void term_serial(void)
{
if(isInitialized() == true) tcsetattr(fd, TCSANOW, &oldTio);
if(fd >= 0) close(fd);
}