Find the answer to your Linux question:
Results 1 to 2 of 2
Hi, I'm writing a program that fetches 38 byte samples via the serial port. After each fetch I print out the amount of bytes read and then print out the ...
  1. #1
    Just Joined!
    Join Date
    Jul 2008
    Posts
    7

    serial port not waiting to fill the buffer

    Hi, I'm writing a program that fetches 38 byte samples via the serial port. After each fetch I print out the amount of bytes read and then print out the hex representation of the array of characters. I throw away 4 bytes from the beginning of each sample therefore I only want to read 34 bytes each pass through the program.

    During a run, most of the new byte counts are 34 however some of them are 33, 7 etc. In addition, when I print the hex representation not all of the characters print. For example for a 34 byte character array, only 13 bytes printed out.

    I have the serial port setup for non-canonical reading however...i followed a tutorial so I do not know the if I am setting up a serial port properly for my application.

    I have a feeling that it has to do with the serial port forcing itself to return before 34 bytes are read. And the printf is taking too long so the program stops it and moves on.

    I would like to make sure that I am reading sold 34 bytes each pass and would like to print them to the screen for debugging.

    Any pointers would be greatly appreciated!

    I have pasted my configuration code and read code below. init_port is the function called to do the configuration.

    Code:
    int main()
    {
    char port_name[] = "/dev/ttyUSB0";	//set port name here.
    int fd;
    
    //-------------open ports---------------------------------
    fd = open(port_name, O_RDWR | O_NOCTTY | O_NDELAY);
    
    if (fd == -1){
    	perror("unable to open /dev/ttyUSB0\n");
    	return 1;
    }
    else
    {
    	printf("Connected to %s\n",port_name);
    	fcntl(fd,F_SETFL,0);
    }
    //----------------------------------------------------------
    
    //initialize the port for use.
    initport(fd);
    
    char received[READ_BYTES+1];
    
    while (1)
    {
    //printf("--------------------------------------------------------------------------\n");
    find_sync_bytes(fd);
    readport(fd,received);
    print_str_to_hex(received);		//print the string in hex form.
    }
    //-----------------------------------------------------------
    //close the serial port.
    close(fd);
    return 0;
    }
    Code:
    int readport(int fd, unsigned char *result){
    	int new_bytes,bytes_read_tot;
    	new_bytes=0;
    	result[0]=0x00;	//clear buffer before reading it.
    
    	new_bytes = read(fd,result,READ_BYTES);
    	printf("new_bytes: %d\n",new_bytes);
    	if(new_bytes<0){
    			if(errno == EAGAIN){
    				printf("SERIAL EAGAIN ERROR\n");
    				return 0;
    			}	
    			else{
    				printf("SERIAL read error %d %s\n",errno,strerror(errno));
    				return 0;
    			}
    		}//end if.
    //	}//end for.
    	result[new_bytes] = 0x00;	//terminate string.
    	//result[bytes_read_tot] = 0x00;	//terminate string.
    
    	return 1;
    }//end readport function.
    
    int initport(int fd){
    	struct termios options;
    	tcgetattr(fd, &options);	//get the current options for the port.
    	cfsetispeed(&options, B115200);	//set baud rate for input port.
    	cfsetospeed(&options, B115200);	//set baud rate for output port.
    
    	//enable the receiver and set local mode.
    	options.c_cflag |= (CLOCAL | CREAD);
    
    	options.c_cflag &= ~PARENB;
    	options.c_cflag &= ~CSTOPB;
           	options.c_cflag &= ~CSIZE;
    	options.c_cflag |= CS8;
    
    	//raw input set.
    	options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    
    	//set the new options for the port.
    	tcsetattr(fd, TCSANOW, &options);
    
    	return 1;	
    }//end initport function.
    
    void print_str_to_hex(unsigned char *char_string){
    	int i;
    	printf("hex representation:\n");
    	for(i=0;char_string[i]!=0x00;i++){
    		printf("%02X ",char_string[i]);	
    	}//end for.
    	printf("\n");
    }//end of str_to_hex function.
    
    int find_sync_bytes(int fd){
    	int read_count =0;		//initialize read count to zero.
    	int sync_count =0;		//initialize sync characters to zero.
    	int in_sync =0;			//assume that the buffer is not yet insync.
    	unsigned char buffer[10];
    	//while four sync bytes have not been read and max read count has not been exceeded...
    	while((read_count<MAX_TRIES) && (sync_count<4)){
    		buffer[0]=0x00;		//set first element to \0.
    		read(fd,buffer,1);	//read and store a single byte.
    	if(buffer[0]==0xFF)		//if char is sync char...
    		sync_count++;
    	else
    		sync_count=0;
    	if(sync_count==4)		//if sync count is four...
    		in_sync=1;		//raise in_sync flag.
    	else
    		in_sync=0;		//otherwise keep the flag low.
    	read_count++;
    	}//end while.
    	if(read_count>=MAX_TRIES)
    		printf("Can't find sync characters.\n");	//let user know can't find sync chars.
    return 0;
    }//end find_sync_bytes function.

  2. #2
    Linux Engineer wje_lf's Avatar
    Join Date
    Sep 2007
    Location
    Mariposa
    Posts
    1,192
    Ok, here we go. Initialization:
    1. In options.cflag, I'd definitely set CRTSCTS. I'd also seriously consider HUPCL.
    2. Your handling of options.lflag looks ok, though my style would have been simply to set all the flags to zero, plain and simple.
    3. Your code doesn't seem to look at options.iflag. I'd turn on IGNBRK, and turn off all other flags, except you may want to consider PARMRK, depending on how you want to handle framing errors.
    4. Your code doesn't seem to look at options.oflag. I'd turn off all those flags.
    5. Your code doesn't seem to look at options.c_cc. I'd set options.c_cc[VTIME] to 0. And the way your code is currently written, reading 38 bytes at a time, I'd set options.c_cc[VMIN] to 38. But I'd really recommend you rewrite your code so that you have a loop reading 38 characters one at a time, and set options.c_cc[VMIN] to 1. This way, if your program somehow gets out of sync with the device, you can debug the situation more easily.

    And just to be nice, do another tcsetattr() at the end to reset things to the way you found them, using the flags as you originally received them with tcgetattr().
    the printf is taking too long so the program stops it and moves on.
    Things don't work that way at all.

    If you're reading exactly 38 bytes at a time, I'm guessing this is binary data. I'm also guessing that sometimes a byte can be zero.

    A "string" is conventionally filled with ASCII data, or something from one of the newer extended character sets. This convention calls for a NUL byte (one with all bits off) after the final byte of the string, to mark the string's end.

    If you're dealing with binary data, you're not dealing with strings in that sense. Your function to print the data in hex should have as one of its parameters the number of bytes to output, which you should set to the number of bytes you read.

    Hope this helps.
    --
    Bill

    Old age and treachery will overcome youth and skill.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
...