하드웨어
C221-S3C6410 보드에 있는 CAN으로 들어오는 데이터를 RS232로보내는 프로그램은 다음과 같습니다.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/poll.h> #include <net/if.h> #include <linux/can.h> #include <linux/can/raw.h> #include <termios.h> #include <fcntl.h> #define BUFF_SIZE 1024 int main(int argc, char *argv[]) { int fd_sock; struct sockaddr_can addr; struct can_filter rfilter[4]; struct ifreq ifr; int ifindex; char can_port[BUFF_SIZE]; char rs_port[BUFF_SIZE]; if (3 > argc) { printf("인수가 모자릅니다. 시리얼 포트를 입력하여 주시오\n"); printf("실행방법: ]$ ./app_can_to_rs232 can0 /dev/ttySAC3\n"); exit(0); } sprintf(can_port, argv[1]); sprintf(rs_port, argv[2]); // can 포트를 open if (0 > (fd_sock = socket(PF_CAN, SOCK_RAW, CAN_RAW))) { perror("socket"); return 1; } rfilter[0].can_id = 0x32; rfilter[0].can_mask = CAN_SFF_MASK; rfilter[1].can_id = 0x200; rfilter[1].can_mask = 0x700; rfilter[2].can_id = 0x80123456; rfilter[2].can_mask = 0x1FFFF000; rfilter[3].can_id = 0x80333333; rfilter[3].can_mask = CAN_EFF_MASK; setsockopt(fd_sock, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter)); strcpy(ifr.ifr_name, can_port); // 사용할 CAN 번호 ioctl(fd_sock, SIOCGIFINDEX, &ifr); ifindex = ifr.ifr_ifindex; addr.can_family = AF_CAN; addr.can_ifindex = ifindex; if (bind(fd_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("bind"); return 1; } // rs232 통신 포트 초기화 int fd_rs232; struct termios newtio; fd_rs232 = open(rs_port, O_RDWR | O_NOCTTY | O_NONBLOCK); memset(&newtio, 0, sizeof(newtio)); newtio.c_cflag = B115200; // 통신 속도 115200 newtio.c_cflag |= CS8; // 데이터 비트가 8bit newtio.c_cflag |= CLOCAL; // 외부 모뎀을 사용하지 않고 내부 통신 포트 사용 newtio.c_cflag |= CREAD; // 쓰기는 기본, 읽기도 가능하게 newtio.c_iflag = 0; // parity 비트는 없음 newtio.c_oflag = 0; newtio.c_lflag = 0; newtio.c_cc[VTIME] = 0; newtio.c_cc[VMIN] = 1; tcflush(fd_rs232, TCIFLUSH); tcsetattr(fd_rs232, TCSANOW, &newtio); // 포트에 대한 통신 환경을 설정합니다. // poll 초기화 및 등록 struct pollfd poll_events; // 체크할 event 정보를 갖는 struct int poll_state; poll_events.fd = fd_sock; poll_events.events = POLLIN | POLLERR; // 수신된 자료가 있는지, 에러가 있는지 poll_events.revents = 0; // 자료 송수신 while (1) { poll_state = poll( // poll()을 호출하여 event 발생 여부 확인 (struct pollfd*) &poll_events, // event 등록 변수 1, // 체크할 pollfd 개수 1000 // time out 시간 ); if (0 < poll_state) // 발생한 event 가 있음 { if (poll_events.revents & POLLIN) // event 가 자료 수신? { struct can_frame frame; int rd_size; rd_size = read(fd_sock, &frame, sizeof(struct can_frame)); if (0 > rd_size) { fprintf(stderr, "read error"); } else if (rd_size < sizeof(struct can_frame)) { fprintf(stderr, "read: incomplete CAN frame\n"); return 1; } else { char tx_buff[BUFF_SIZE + 1]; int ndx; if (frame.can_id & CAN_EFF_FLAG) printf("%8X ", frame.can_id & CAN_EFF_MASK); else printf("%3X ", frame.can_id & CAN_SFF_MASK); if (frame.can_id & CAN_RTR_FLAG) printf("remote request"); printf(" [%d] ", frame.can_dlc); for (ndx = 0; ndx < frame.can_dlc; ndx++) { printf("%02X ", frame.data[ndx]); tx_buff[ndx] = frame.data[ndx]; } printf("\n"); write(fd_rs232, tx_buff, ndx); // rs232 port로 수신 데이터 전송 } } if (poll_events.revents & POLLERR) // event 가 에러? { printf("통신 라인에 에러가 발생, 프로그램 종료"); break; } } } close(fd_sock); close(fd_rs232); return 0; } |
CAN Filter 를 사용하지 않을 경우에는 다음과 같이 해 주면 됩니다.
setsockopt( fd_sock, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0 );
CAN Filter를 사용할 경우 filter의 사이즈가 맞지 않으면 데이터가 중복되어 들어오는 경우가 발생합니다.
따라서 filter 와 사이즈를 일치 시켜 줘야 합니다.
다음 강좌에서는 rs232 to can 프로그램을 설명하도록 하겠습니다.