1
votes

I'm trying to connect via RS232 connection.

Communication parameters:

*Transmission rate: 1200 baud

*Character coding: 8-bit ASCII

*Parity: None

*Stop bits: 1

Commands are composed of two byte codes with the following format

Transmit format

CODE + "FFh"

    Hex code

Receive format

CODE + "FFh"

    Hex code

I tried various initializations but I still fail to read anything from the port the following code is one of them:

//RS232test.c
//Transmission rate: 1200 Baud
//8 bit, no parity 1 stop bits.
//Transmit format: CODE + "FFh"
//Receive format: CODE + "FFh"

//Last edited: 23/08/2014

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h> 
#include <termios.h> 
#include <unistd.h> 
#include <string.h>
#include <sys/ioctl.h>


#define BAUDRATE B1200

#define MULTI "/dev/ttyS0"
//#define MULTI "/dev/ttyUSB0"

int open_port(struct termios *,struct termios *);
int setDtrRts(int, int);
void close_port(int, struct termios *);

int open_port(struct termios *tty, struct termios *tty_old)
//This opens the tty port for linux saves old port setting
//and saves the new ones
{
    int fd; //file descriptor   
    fd = open(MULTI, O_RDWR | O_NOCTTY);
    if (fd < 0) {
        perror(MULTI);
        printf("failed to open port\n");
        exit(-1);
        }
    //get previous port settings so it can be restored on exit
    tcgetattr(fd,tty_old);
    //get port settings so they can be set
    tcgetattr(fd,tty);
    //Set baud rates to 1200
    cfsetispeed(tty, BAUDRATE);
    cfsetospeed(tty, BAUDRATE);
    //ICANON -choosing canonical input. 
    tty->c_lflag |= (ICANON);
    //tty->c_lflag &= ~(ISIG);
    //unselecting echo
    tty->c_lflag &= ~(ECHO | ECHOE);
    //CLOCAL - setting local mode, CREAD - enabling receiver
    tty->c_cflag |= (CLOCAL | CREAD);
    //close doesn't change signals
    tty->c_cflag &= ~HUPCL;
    //8N1 no parity 1 stop bit
    tty->c_cflag |= CS8;
    //tty->c_cflag &= ~(PARENB | CSTOPB | CSIZE);
    tty->c_cflag &= ~(PARENB | PARODD /**/| CSIZE);
    tty->c_cflag &= ~CSTOPB;
    //Raw output mode
    tty->c_oflag &= ~OPOST;
    //Enable hardware handshaking
    //tty->c_cflag &= ~CRTSCTS;
    //tty->c_iflag &= ~(IXON | IXOFF | IXANY); //*
    //Flushing communication buffer and changing port setting 
    //tcflush(fd, TCIFLUSH);
    //tcsetattr(fd, TCSANOW, tty);
    tcsetattr(fd, TCSAFLUSH, tty);
    setDtrRts(fd,1);
    return fd;
}

int setDtrRts(int fd, int set)
//sets or clears the dtr and rts
//the needs both set during operation
//otherwise it switches off after approx. 20 seconds
{
    int setbits; 
    setbits |= (TIOCM_DTR | TIOCM_RTS);
    if(set)
        return(ioctl(fd, TIOCMBIC, &setbits));
    else
        return(ioctl(fd, TIOCMBIS, &setbits));
}

void close_port(int fd, struct termios *tty_old)
//closing port
{
    //reset to old options
    //tcsetattrb(fd, TCSANOW, tty_old);
    setDtrRts(fd,0);
    close(fd);
}

int main(void)
{
    int fd=0; //system file number
    int buff_size; //no of characters in buffer
    int bytes; //no of bytes in buffer
    int ctr=0; //general counter
    char in_buffer[] = "F3\xFF";
    char out_buffer[255]; //serial character buffer
    //new port setting and a structure to keep the old ones
    struct termios tty,tty_old;
    //checking if root
    if (getuid()){
        printf("You must be root to use this program.\n");
        exit(-4);
    }
    printf("fd = %d\n",fd);
    //opening port for reading and writing
    fd = open_port(&tty,&tty_old);
    printf("fd = %d\n",fd);
    //flushing
    tcflush(fd,TCIOFLUSH);
    //sending command to serial port
    //strcpy(in_buffer, "F3\xFF"); //placing a command in the buffer
    printf("%s",in_buffer);
    if((buff_size = write(fd, in_buffer, strlen(in_buffer))) < 0){
        printf("Error while sending message\nBuffer contents:\t%s\n",in_buffer);
        return -2;
    }
    usleep(50000); //delay for 50ms
    out_buffer[0] = '\0';
    ioctl(fd,FIONREAD,&bytes);
    printf("\nThere are %d bytes in the buffer\n",bytes);
    if(bytes > 0) {
        //reading response from serial port
        if((buff_size = read(fd, out_buffer,sizeof(out_buffer))) < 0){
            printf("Error while reading message\n");
            return -3;
        } 
        //printing the decimal ASCII values of the response
        printf("Multimeter response:\t");
        while(out_buffer[ctr] != '\0')
        {
            printf("%i ",out_buffer[ctr]);
            ctr++;
        }
        printf("\n%s\n",out_buffer);
    } else printf("Buffer Empty\n");
    //wrap things up
    close_port(fd, &tty_old);
    exit(0);
}

The programs output is as follows:

fd = 0

fd = 3

F3�h

There are 0 bytes in the buffer

Buffer Empty

Toyed around with several suggestions in previous posts but did not succeed.

2

2 Answers

4
votes

The protocol you describe is not line oriented, so using canonical input mode is wrong. You should use the good old raw mode, defined as :

tty->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
               | INLCR | IGNCR | ICRNL | IXON);
tty->c_oflag &= ~OPOST;
tty->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty->c_cflag &= ~(CSIZE | PARENB);
tty->c_cflag |= CS8;

In canonical mode, characters are only made available for a read after the eol has been received to allow line edition, which is not what you want here. (reference : man termios)

-1
votes

following code is written by myself, and it's working on my embedded system all the time.

int wrap_uart_init(char *port, int baudrate, int datab, int parity, int stopb){
    int fd=open_and_init_tty(port);
    if (fd==-1) {
        perror("cannot open device");
        return fd;
    }
    set_baudrate(fd,baudrate);
    set_dataformat(fd,datab,parity,stopb);
    swflow_ctrl(fd);
    return fd;
}

call this function like this:

int fd = wrap_uart_init("/dev/ttyUSB0", 1200, 8, 'N', 1);

super easy to use. it's even not important that what the physical layer protocol is, as long as Linux has masked the device into a tty file.

#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>

static struct termios origin_attrs;
static struct termios old_attrs;

int open_tty(const char *dev){
    int fd=open(dev, O_RDWR | O_NOCTTY | O_NDELAY | O_SYNC);
    if (fd==-1)
        perror(FILE_OPEN_ERROR);
    if (fcntl(fd, F_SETFL, 0)<0){
        perror("fcntl error!");
        close(fd);
        fd=-1;
    }
    if (!isatty(STDIN_FILENO)){
        perror("standard input error! ");
        close(fd);
        fd=-1;
    }
    return fd;
}

void close_tty(int fd){
    if  (tcsetattr(fd,TCSANOW,&old_attrs)) { 
        perror(GET_ATTR_ERROR);
    }
    close(fd);
}

int open_and_init_tty(const char *dev){
    int fd=open_tty(dev);
    if (fd==-1){
        perror(FILE_OPEN_ERROR);
        return -1;
    }
    if  (tcgetattr(fd,&old_attrs)) { 
        perror(GET_ATTR_ERROR);
        return -1;
    }
    struct termios opt;
    int br=B9600;
    cfsetispeed(&opt, br);
    cfsetospeed(&opt, br); 
    opt.c_cflag = (CS8 | CLOCAL | CREAD);
    opt.c_iflag = (IGNPAR | IXON | IXOFF | IXANY);
    opt.c_lflag = 0;
    opt.c_oflag = 0;
    opt.c_cc[VTIME] = 30;
    opt.c_cc[VMIN] = 5;
    tcflush(fd, TCIOFLUSH);
    if (tcsetattr(fd,TCSANOW,&opt) != 0) {
        perror(SET_ATTR_ERROR);   
        return -1;
    }
    return fd;
}

int set_baudrate(int fd, int baud){
    int br;
    int status;
    struct termios opt;
    if (tcgetattr(fd, &opt)) {
        perror(GET_ATTR_ERROR);
        return -1;
    }
    switch (baud) {
        case 115200:    br=B115200;break;
//      case 76800:     br=B76800; break;
        case 57600:     br=B57600; break;
        case 38400:     br=B38400; break;
        case 19200:     br=B19200; break;
        case 9600:  br=B9600;  break;
        case 4800:  br=B4800;  break;
        case 2400:  br=B2400;  break;
        case 1200:  br=B1200;  break;
        case 600:   br=B600;   break;
        case 300:   br=B300;   break;
        default:    perror("Wrong Baud rate!");
                return -1;
    }
    tcflush(fd, TCIOFLUSH);
    cfsetispeed(&opt, br);
    cfsetospeed(&opt, br);   
    status = tcsetattr(fd, TCSANOW, &opt);  
    if (status) {        
        perror(BAUD_RATE_ERROR);  
        return -2;
    }
    tcflush(fd,TCIOFLUSH);   
    return 0;
}

int set_dataformat(int fd,int databits,int parity,int stopbits){ 
    struct termios options; 
    if  (tcgetattr(fd,&options)) { 
        perror(GET_ATTR_ERROR);     
        return -1;
    }
    options.c_cflag &= ~CSIZE; 
    switch (databits) {
    case 5:
        options.c_cflag |= CS5; 
        break;
    case 6:
        options.c_cflag |= CS6; 
        break;
    case 7: 
        options.c_cflag |= CS7; 
        break;
    case 8: 
        options.c_cflag |= CS8;
        break;   
    default:    
        perror("Unsupported data size");
        return -2;  
    }
    switch (parity) {
    case 'n':       //no parity check
    case 'N':
        options.c_cflag &= ~PARENB;
        options.c_iflag &= ~INPCK;
        break;  
    case 'o':       //odd check
    case 'O':
        options.c_cflag |= (PARODD | PARENB);
        options.c_iflag |= (INPCK | ISTRIP);
        break;  
    case 'e':       //even check
    case 'E':
        options.c_cflag |= PARENB;
        options.c_cflag &= ~PARODD;
        options.c_iflag |= (INPCK | ISTRIP);
        break;
    default:   
        perror("Unsupported parity");    
        return -3;  
    }  
    switch (stopbits) {
    case 1:         //1 stop bit
        options.c_cflag &= ~CSTOPB;  
        break;  
    case 2:         //2 stop bits
        options.c_cflag |= CSTOPB;  
        break;
    default:    
        perror("Unsupported stop bits");  
        return -4; 
    } 
    tcflush(fd,TCIFLUSH);
    options.c_cc[VTIME] = 50;
    options.c_cc[VMIN] = 1;
    if (tcsetattr(fd,TCSANOW,&options) != 0) {
        perror(SET_ATTR_ERROR);   
        return -1;
    }
    return 0;
}

int set_databit(int fd, int databits){
    struct termios options; 
    if  (tcgetattr(fd,&options)) { 
        perror(GET_ATTR_ERROR);     
        return -1;
    }
    options.c_cflag &= ~CSIZE; 
    switch (databits) {
    case 5:
        options.c_cflag |= CS5; 
        break;
    case 6:
        options.c_cflag |= CS6; 
        break;
    case 7: 
        options.c_cflag |= CS7; 
        break;
    case 8: 
        options.c_cflag |= CS8;
        break;   
    default:    
        perror("Unsupported data size");
        return -1;  
    }
    tcflush(fd,TCIFLUSH);
    if (tcsetattr(fd,TCSANOW,&options) != 0) {
        perror(SET_ATTR_ERROR);   
        return -2;
    }
    return 0;
}

int set_parity(int fd, int parity) {
    struct termios options; 
    if  (tcgetattr(fd,&options)) { 
        perror(GET_ATTR_ERROR);     
        return -1;
    }
    options.c_cflag &= ~CSIZE; 
    switch (parity) {
    case 'n':       //no parity check
    case 'N':
        options.c_cflag &= ~PARENB;
        options.c_iflag &= ~INPCK;
        break;  
    case 'o':       //odd check
    case 'O':
        options.c_cflag |= (PARODD | PARENB);
        options.c_iflag |= (INPCK | ISTRIP);
        break;  
    case 'e':       //even check
    case 'E':
        options.c_cflag |= PARENB;
        options.c_cflag &= ~PARODD;
        options.c_iflag |= (INPCK | ISTRIP);
        break;
    default:   
        perror("Unsupported parity");    
        return -1;  
    }
    tcflush(fd,TCIFLUSH);
    if (tcsetattr(fd,TCSANOW,&options) != 0) {
        perror(SET_ATTR_ERROR);   
        return -2;
    }
    return 0;
}

int set_stopbit(int fd, int stopbits) {
    struct termios options; 
    if  (tcgetattr(fd,&options)) { 
        perror(GET_ATTR_ERROR);     
        return -1;
    }
    options.c_cflag &= ~CSIZE; 
    switch (stopbits) {
    case 1:         //1 stop bit
        options.c_cflag &= ~CSTOPB;  
        break;  
    case 2:         //2 stop bits
        options.c_cflag |= CSTOPB;  
        break;
    default:    
        perror("Unsupported stop bits");  
        return -1; 
    }
    tcflush(fd,TCIFLUSH);
    if (tcsetattr(fd,TCSANOW,&options) != 0) {
        perror(SET_ATTR_ERROR);   
        return -2;
    }
    return 0;
}

int hwflow_ctrl(int fd){
    struct termios options;
    if  (tcgetattr(fd,&options)) { 
        perror(GET_ATTR_ERROR);     
        return -1;
    }
    options.c_cflag |= CRTSCTS;
    options.c_iflag &= ~(IXON | IXOFF | IXANY);
    tcflush(fd,TCIFLUSH);
    if (tcsetattr(fd,TCSANOW,&options) != 0) {
        perror(SET_ATTR_ERROR);   
        return -2;
    }
    return 0;
}

int swflow_ctrl(int fd){
    struct termios options;
    if  (tcgetattr(fd,&options)) { 
        perror(GET_ATTR_ERROR);     
        return -1;
    }
    options.c_cflag &= ~CRTSCTS;
    options.c_iflag |= (IXON | IXOFF | IXANY);
    tcflush(fd,TCIFLUSH);
    if (tcsetattr(fd,TCSANOW,&options) != 0) {
        perror(SET_ATTR_ERROR);   
        return -2;
    }
    return 0;
}

int store_termios(int fd){
    if  (tcgetattr( fd,&origin_attrs)) { 
        perror(GET_ATTR_ERROR);
        return -1;
    }
    return 0;
}
int recover_termios(int fd){
    tcflush(fd, TCIOFLUSH);
    if (tcsetattr(fd,TCSANOW,&origin_attrs)) {
        perror(SET_ATTR_ERROR);
        return -1;
    }
    tcflush(fd, TCIOFLUSH);
    return 0;
}