/* 本程序符合GPL条约
* Beneboy 2003-5-16 */ #include <stdio.h> // printf #include <fcntl.h> // open #include <string.h> // bzero #include <stdlib.h> // exit #include <sys/times.h> // times #include <sys/types.h> // pid_t #include <termios.h> //termios, tcgetattr(), tcsetattr() #include <unistd.h> #include <sys/ioctl.h> // ioctl #include "MyCom.h" #define TTY_DEV "/dev/ttyS" //端口路径 //接收超时 #define TIMEOUT_SEC(buflen,baud) (buflen*20/baud+2) #define TIMEOUT_USEC 0 /******************************************* * 获得端口名称 ********************************************/ char *get_ptty(pportinfo_t pportinfo) { char *ptty;switch(pportinfo->tty){
case '0':{ ptty = TTY_DEV"0"; }break; case '1':{ ptty = TTY_DEV"1"; }break; case '2':{ ptty = TTY_DEV"2"; }break; } return(ptty); }/*******************************************
* 波特率转化转换函数 ********************************************/ int convbaud(unsigned long int baudrate) { switch(baudrate){ case 2400: return B2400; case 4800: return B4800; case 9600: return B9600; case 19200: return B19200; case 38400: return B38400; case 57600: return B57600; case 115200: return B115200; default: return B9600; } }/*******************************************
* Setup comm attr * fdcom: 串口文件描述符, pportinfo: 待设置的端口信息s * ********************************************/ int PortSet(int fdcom, const pportinfo_t pportinfo) { struct termios termios_old, termios_new; int baudrate, tmp; char databit, stopbit, parity, fctl;bzero(&termios_old, sizeof(termios_old));
bzero(&termios_new, sizeof(termios_new)); cfmakeraw(&termios_new); tcgetattr(fdcom, &termios_old); //get the serial port attributions/*------------设置端口属性----------------*/
//baudrates
baudrate = convbaud(pportinfo -> baudrate); cfsetispeed(&termios_new, baudrate); //填入串口输入端波特率 cfsetospeed(&termios_new, baudrate); //填入串口输出端波特率 termios_new.c_cflag |= CLOCAL; //控制模式, 保证程序不会成为端口的占有者 termios_new.c_cflag |= CREAD; //控制模式, 使能端口读取输入的数据 // 控制模式, flow control fctl = pportinfo-> fctl; switch(fctl){ case '0':{ termios_new.c_cflag &= ~CRTSCTS; //no flow control }break; case '1':{ termios_new.c_cflag |= CRTSCTS; //hardware flow control }break; case '2':{ termios_new.c_iflag |= IXON | IXOFF |IXANY; //software flow control }break; }//控制模式, data bits
termios_new.c_cflag &= ~CSIZE; //控制模式, 屏蔽字符大小位 databit = pportinfo -> databit; switch(databit){ case '5': termios_new.c_cflag |= CS5; case '6': termios_new.c_cflag |= CS6; case '7': termios_new.c_cflag |= CS7; default: termios_new.c_cflag |= CS8; }//控制模式 parity check
parity = pportinfo -> parity; switch(parity){ case '0':{ termios_new.c_cflag &= ~PARENB; //no parity check }break; case '1':{ termios_new.c_cflag |= PARENB; //odd check termios_new.c_cflag &= ~PARODD; }break; case '2':{ termios_new.c_cflag |= PARENB; //even check termios_new.c_cflag |= PARODD; }break; }//控制模式, stop bits
stopbit = pportinfo -> stopbit; if(stopbit == '2'){ termios_new.c_cflag |= CSTOPB; //2 stop bits } else{ termios_new.c_cflag &= ~CSTOPB; //1 stop bits }//other attributions default
termios_new.c_oflag &= ~OPOST; //输出模式, 原始数据输出termios_new.c_cc[VMIN] = 1; //控制字符, 所要读取字符的最小数量
termios_new.c_cc[VTIME] = 1; //控制字符, 读取第一个字符的等待时间, unit: (1/10)secondtcflush(fdcom, TCIFLUSH); //溢出的数据可以接收,但不读
tmp = tcsetattr(fdcom, TCSANOW, &termios_new); //设置新属性, TCSANOW: 所由改变立即生效 tcgetattr(fdcom, &termios_old); return(tmp); }/*******************************************
* Open serial port * tty: 端口号 ttyS0, ttyS1, .... * 返回值为串口文件描述符 ********************************************/ int PortOpen(pportinfo_t pportinfo) { int fdcom; //串口文件描述符 char *ptty;ptty = get_ptty(pportinfo);
//fdcom = open(ptty, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY); fdcom = open(ptty, O_RDWR | O_NOCTTY | O_NONBLOCK);return (fdcom);
}/*******************************************
* Close serial port ********************************************/ void PortClose(int fdcom) { close(fdcom); }/********************************************
* send data * fdcom: 串口描述符, data: 待发送数据, datalen: 数据长度 * 返回实际发送长度 *********************************************/ int PortSend(int fdcom, char *data, int datalen) { int len = 0;len = write(fdcom, data, datalen); //实际写入的长度
if(len == datalen){ return (len); } else{ tcflush(fdcom, TCOFLUSH); return -1; } }/*******************************************
* receive data * 返回实际读入的字节数 * ********************************************/ int PortRecv(int fdcom, char *data, int datalen, int baudrate) { int readlen, fs_sel; fd_set fs_read; struct timeval tv_timeout;FD_ZERO(&fs_read);
FD_SET(fdcom, &fs_read); tv_timeout.tv_sec = TIMEOUT_SEC(datalen, baudrate); tv_timeout.tv_usec = TIMEOUT_USEC;fs_sel = select(fdcom+1, &fs_read, NULL, NULL, &tv_timeout);
if(fs_sel){ readlen = read(fdcom, data, datalen); return(readlen); } else{ return(-1); }return (readlen);
}//*************************Test*********************************
int main(int argc, char *argv[]) { int fdcom, i, SendLen, RecvLen; struct termios termios_cur; char RecvBuf[256]; char writeBuf[256]; portinfo_t portinfo ={ '0', // print prompt after receiving 9600, // baudrate: 9600 '8', // databit: 8 '0', // debug: off '0', // echo: off '2', // flow control: software '0', // default tty: COM1 '0', // parity: none '1', // stopbit: 1 0 // reserved };if(argc != 2){
printf("Usage: <type 0 -- send 1 -- receive>\n"); printf(" eg:"); printf(" MyPort 0"); exit(-1); }fdcom = PortOpen(&portinfo);
if(fdcom<0){ printf("Error: open serial port error.\n"); exit(1); }PortSet(fdcom, &portinfo);
while(1)
if(atoi(argv[1]) == 0) { //send data //for(i=0; i<1000; i++) { //fgets(writeBuf,256,stdin); scanf("%s",writeBuf); SendLen = PortSend(fdcom, writeBuf, strlen(writeBuf)); if(SendLen>0) { //printf("send data %s", writeBuf); } else { printf("Error: send failed.\n"); }if(strncmp(writeBuf,"exit",4)==0)
break; sleep(1); } //PortClose(fdcom); } else { //for(;;) { RecvLen = PortRecv(fdcom, RecvBuf, 256, portinfo.baudrate); if(RecvLen>0) { /*for(i=0; i<RecvLen; i++) { printf("Receive data No %d is %x.\n", i, RecvBuf[i]); }//*/ RecvBuf[RecvLen] = '\0'; printf("read data %s\n",RecvBuf);if(strncmp(RecvBuf,"exit",4)==0)
break; } else { //printf("Error: receive error.\n"); } sleep(1); } } PortClose(fdcom); return 0; }