0

This is a follow up question to this original post:

RaspberryPi RS-232 trouble

I made changes to my code per the accepted answer, the terminal is now set up for blocking and canonical input. The read() now works as expected, with the exception of the very first read(which is typically some extra random symbols mixed with some good data) I get single lines of data from the laser range finder representing exactly what I expect to see.

However, I now have an issue that if I do too many reads, the laser range finder is put into a non-operating state, stops communication, and can only be reset by doing a power cycle. This has happened with as few as 4 reads on the device, and I haven't been able to do more than 8 reads. It doesn't matter if the reads are all at once, or spanned across several program starts.

int main(){
    int uart0_filestream = -1;
    int loop, i, sentBytes;
    int isError, rx_length;
    unsigned char rx_buffer[256];

    uart0_filestream = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY);
    fcntl(uart0_filestream, F_SETFL, 0);

    if(uart0_filestream == -1){
        printf("ERROR: Unable to open UART\n");
        checkError(errno);
        exit(1);
    }

    struct termios options;

    isError = tcgetattr(uart0_filestream, &options);

    if(isError < 0){
        printf("ERROR: tcgetattr failed.\n");
        checkError(errno);
        exit(1);
    }

    //set c ontrol options and baud
    options.c_cflag |= (CLOCAL | CREAD);
    cfsetispeed(&options, B19200);
    cfsetospeed(&options, B19200);

    //set 8 data bits, 1 stop bit, no parity
    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;

    //set input options
    options.c_iflag |= (INPCK | ISTRIP);        //strip parity
    options.c_iflag &= ~(IXON | IXOFF | IXANY); //turn off software flow control

    //set canonical input processing
    options.c_lflag |= (ICANON | ECHO | ECHOE);

    tcflush(uart0_filestream, TCIFLUSH);
    isError = tcsetattr(uart0_filestream, TCSANOW, &options);

    if(isError < 0){
        printf("ERROR: tcsetattr failed.\n");
        checkError(errno);
        exit(1);
    }

    //read() successfully returns expected data, with the exception of the first 
    //read. Reading more than 6-8 times, regardless of same session or restarting
    //program puts LRF in non-working state which requires a power cycle to fix
    for(i=0; i<4;i++ ){
        rx_length = read(uart0_filestream, (void*)rx_buffer, 255);

        if(rx_length < 0){
            printf("ERROR: read() failed.\n");
            checkError(errno);
        }

        if(rx_length > 0){
            printf("rx_lentgh = %i:\t ", rx_length);
            for(loop=0; loop<rx_length; loop++){
                printf("%c", rx_buffer[loop]);
            }
            printf("\n");
        }
    }

    //writing once has no affect, sending command has no affect
    //looping the write, eventually 'something' gets to the LRF
    //but it puts it in the same state as when reading too many
    //times and have to power cycle
    for(i = 0; i<8; i++){
        sentBytes = write(uart0_filestream, "o\n", 2);

        if(sentBytes < 2){
            printf("ERROR: write() failed.\n");
            checkError(errno);
        }   
    }

    close(uart0_filestream);
}

I don't believe it is the range finder, as I can run minicom and it will continuously display the output successfully.

As noted in the comments of my code, I also have trouble writing any commands to the laser range finder. Each command consists of a single character, followed by a new line. One write has no affect, but looping several times can put the device in the same state as reading too many times.

I have read Posix Serial Programming Guide, and tried different combinations of flags that I believe might affect either the reading or writing, but have had no success.

Community
  • 1
  • 1
jrpharis
  • 81
  • 1
  • 1
  • 11
  • Put some checks to get the error status of `uart0_filestream` before doing the `read()`. See if an error condition pre-dates the hang. – chux - Reinstate Monica Oct 04 '13 at 22:01
  • How is the communication with this laser range finder supposed to work? Most devices work on a simple command/response basis: the host (the master) sends a command, and the device (the slave) responds with a reply message. The slave device only responds to a command; it never sends anything spontaneously or unsolicited. Your program expects to read 4 lines, and then sends a command 8 times. Can you simulate that with `minicom`? – sawdust Oct 05 '13 at 09:35
  • When in a measuring mode, the range finder sends data at a rate of 10 Hz or 200 Hz, depending on the mode it is in. It sends the data constantly, no command is required to get the data. The code I have so far is just for testing. I just want to prove I can read the data as much as I want, and can successfully send commands. Minicom doesn't have the ability for me to explicitly do a read() 4 times. It just continuously reads what is coming in. Sending data just interrupts the process of reading the data. – jrpharis Oct 05 '13 at 14:24
  • What is the purpose of sending the same command eight times? (1) Simulate the 8 `write()`s in `minicom` by creating a plain text file of 16 bytes equivalent to "ooo..." and then use 'send ASCII file' to transfer the text just like your program. Or (2) stop sending the command 8 times. Send it just once. – sawdust Oct 06 '13 at 00:06
  • Sending the command 8 times is a test. There is no purpose other than that. When I send it once, nothing happens. So I looped it to see if sending it more than once did anything. Which it does. So far, I have had 0 successful attempts at sending the range finder a command. Ideally, of course, I only need to send the command once. In minicom, I only need to send a command once. – jrpharis Oct 06 '13 at 02:06

1 Answers1

0

[Edit] This lead suggestion is my embarrassment - thought the string was "o/n".

The amount of data sent is short by 1.

// sentBytes = write(uart0_filestream, "o\n", 2);
// if(sentBytes < 2){
sentBytes = write(uart0_filestream, "o\n", 3);
if(sentBytes < 3){

Minor: Unclear why read buffer is reduced by 1 (sizeof rx_buffer is 256). read() is not going to append a \0 and neither does this code. Code nicely treats the incoming data as an array of bytes. Although in printf("%c"... something could be done if !isgraph(rx_buffer[loop])`.

// rx_length = read(uart0_filestream, (void*)rx_buffer, 255)
rx_length = read(uart0_filestream, (void*)rx_buffer, sizeof rx_buffer)
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256