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 프로그램을 설명하도록 하겠습니다.