Why can not get data from " read" into uint8_t array?

1.2k views Asked by At

Please advise me. I would like to make the code get data from serial port such as tty/USB0. So,need to make this code read the data from serial protocol as showing below.

uint8_t recBlk; // receive blk from chunk
ret = read(serial_fd, &recBlk, sizeof(recBlk));
printf("Block Num is %d\n", recBlk);
fflush(stdout);
if (ret != sizeof(recBlk)) {
    perror("read");
    return -errno;
}

However I didn't get it why this lines showing below is not working,but occuring error "read: invalid argument"

How do I get array data from read function?

uint8_t recData[1024]; // receive data from chunk
ret = read(serial_fd, (void *)&recData, sizeof(recData));
    printf("Data buffer is %c\n", &recData);
    fflush(stdout);
if (ret != sizeof(recData)) {
     printf("Can't fetch the Data length!");
     perror("read");
     return -errno;
}

enter image description here

This code showing below is my implementing function.

static int xmodem_receive(int serial_fd, char* filename, int _crc, int use_crc){
    int skip = 0;
    uint8_t sdCRC = 'C'; // Request-To-Send
    uint8_t sdACK = X_ACK; //
    uint8_t eof = X_EOF;
    uint8_t sdNAK = X_NAK;
    uint8_t recSTX; // receive SOH from chunk
    uint8_t recBlk; // receive blk from chunk
    uint8_t recNegBlk; // receive blk negative from chunk
    uint8_t recData[1024]; // receive data from chunk
    uint16_t recChksum;
 
    uint8_t expected_blkno;
 
    FILE *fp;
    int ret, fd;
    struct stat stat;
    // If we want to receive, We have to send NAK to Sendor.
 
    if (use_crc)
        use_crc = MAX_RETRY + 1;
 
        /* Writing as binary */
    fp = fopen(filename, "wb");
    //Send NAK still read SOH that header of one data chunks
    /*
    CRC 16
    Sending C
    Sending NAK
 
    */
    while(use_crc){
        char status;
        printf("Waiting for sender ping ...");
        fflush(stdout);
        //
        if(_crc){
            printf("Send C ping....\n");
            ret = write(serial_fd, &sdCRC, sizeof(sdCRC));
        }else{
            // send NAK before read SOH
            printf("Send NAK ping....\n");
            ret = write(serial_fd, &sdNAK, sizeof(sdNAK));
        }    // after sending NAK,receiving SOH from chunk
        fflush(stdout);
        ret = read(serial_fd, &recSTX, sizeof(recSTX));
 
 
        if(recSTX == X_STX){
            printf("STX is %c\n", &recSTX);
            break;
        }else{
            printf("Garabage payload %c\n", &recSTX);
        }
        fflush(stdout);
        if (ret != sizeof(recSTX)) {
                printf("Not working");
                fflush(stdout);
                perror("read");
                return -errno;
        }
        use_crc--;
    }
 
    expected_blkno = 1;
 
    while(ret != EOF){
        //So next, receiving blk
        ret = read(serial_fd, &recBlk, sizeof(recBlk));
        printf("Block Num is %d\n", recBlk);
        fflush(stdout);
        if (ret != sizeof(recBlk)) {
            perror("read");
            return -errno;
        }
        ret = read(serial_fd, &recNegBlk, sizeof(recNegBlk));
        printf("Negative Block Num is %d\n", recNegBlk);
        fflush(stdout);
        if (ret != sizeof(recNegBlk)) {
            perror("read");
            return -errno;
        }
        ret = read(serial_fd, (void *)&recData, sizeof(recData));
        printf("Data buffer is %c\n", &recData);
        fflush(stdout);
        if (ret != sizeof(recData)) {
            printf("Can't fetch the Data length!");
            perror("read");
            return -errno;
        }
        ret = read(serial_fd, &recChksum, sizeof(recChksum));
        printf("Check sum is %c", &recChksum);
        fflush(stdout);
        if (ret != sizeof(recChksum)) {
            printf("Can't fetch the Check sum");
            perror("read");
            return -errno;
        }
        // data block number check
        if(recBlk == 0xff - recNegBlk){
            printf("Can't fetch the Block !");
            perror("read");
 
            return -errno;
        }
        // data integrity check
        if(recChksum == swap16(crc16(recData, sizeof(recData)))){
            perror("read");
            return -errno;
        }
        // check of appended "0xff" from end of data to  end of chunk in chunk
        unsigned char *ptr = recData;
        ptr += sizeof(recData);
        while(*ptr == 0xff){
            ptr--;
        }
        fwrite(recData, (ptr - recData),1,fp); // write Datas bytes from our buffer
        // set skip flag or end connect
        ret = write(serial_fd, &eof, sizeof(uint8_t));
        if (ret != sizeof(eof) || ret != sizeof(X_STX)){
            return -errno;
        }else{
            if(ret == X_STX){
                skip = 1;
                printf("next chunk");
                fflush(stdout);
                expected_blkno++;
            }else if(ret == EOF){
                printf("EOF ...");
                ret = write(serial_fd, &sdACK, sizeof(sdACK));
                break;
            }else{
                return -errno;
            }
        }
 
    }
    printf("done.\n");
    fclose(fp);
    return 0;
 
}

termous setting is here.

static int open_serial(const char *path, int baud)
{
        int fd;
        struct termios tty;

        fd = open(path, O_RDWR | O_SYNC);
        if (fd < 0) {
                perror("open");
                return -errno;
        }

        memset(&tty, 0, sizeof(tty));
        if (tcgetattr(fd, &tty) != 0) {
                perror("tcgetattr");
                return -errno;
        }

        cfsetospeed(&tty, baud);
        cfsetispeed(&tty, baud);

        tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;     // 8-bit chars
        tty.c_iflag &= ~IGNBRK;                         // disable break processing
        tty.c_lflag = 0;                                // no signaling chars, no echo,
                                                        // no canonical processing
        tty.c_oflag = 0;                                // no remapping, no delays
        tty.c_cc[VMIN]  = 1;                            // read doesn't block
        tty.c_cc[VTIME] = 5;                            // 0.5 seconds read timeout

        tty.c_iflag &= ~(IXON | IXOFF | IXANY);         // shut off xon/xoff ctrl

        tty.c_cflag |= (CLOCAL | CREAD);                // ignore modem controls,
                                                        // enable reading
        tty.c_cflag &= ~(PARENB | PARODD);              // shut off parity
        tty.c_cflag &= ~CSTOPB;
        tty.c_cflag &= ~CRTSCTS;

        if (tcsetattr(fd, TCSANOW, &tty) != 0) {
                perror("tcsetattr");
                return -errno;
        }

        return fd;
}
1

There are 1 answers

1
sawdust On BEST ANSWER

The code that is producing the "error" is:

    uint8_t recData[1024]; // receive data from chunk
  ...
        ret = read(serial_fd, (void *)&recData, sizeof(recData));
        printf("Data buffer is %c\n", &recData);
        fflush(stdout);
        if (ret != sizeof(recData)) {
            printf("Can't fetch the Data length!");
            perror("read");
            return -errno;
        }

1.) The first issue is C syntax.
recData is the address of an array, and in the read() and printf() calls, the address of this address is passed as the second argument.
The address-of operation on the array address is incorrect.

2.) The second issue is evaluation of the return value.
The man page describes the possible return values of the read() syscall.

2a.) The errno variable is only valid when the return value is -1.
However perror() in your code would be called whenever the return value is not equal the byte count of an array.
Therefore the "read: Invalid argument" message is likely to be bogus.

2b.) The read() syscall is not required to satisfy the requested length argument.
Your termios configuration specifies a minimum read of 1 byte.
So the read() syscall will return with at least one byte, and only as much data as currently received by the serial port driver, up the maximum of the requested length.
So whenever the full read of 1024 bytes cannot be accomplished (which is likely to be always), your program will abort with a bogus error.