Search code examples
carduinoserial-port

Character \r transforms to \n when transmitting through serial port in c


I'm transmitting data trough the serial port using only the write function. For some reason when I receive this data back \r (0x0d) transforms to \n (0x0a). This is probably due to the termios options I use when opening the port but I can't figure out what I can change.

I wrote code to open a binary image save it's data to a uint8_t array and send the data using the write system call and read it using the read system call.

Both the transmitting port and the receiving port are opened with the same options.

All the bytes that are received only differ on the exact same bytes every time and they are all the \r bytes. No data is being lost.

For some extra context: I'm transmitting data over serial port using 2 arduinos with RX0 connected to TX0 and TX0 connected to RX0. I'm also shorting ground. Basically I'm using the arduinos to separate the TX and RX signals and I'm not really using the actual arduino chip or anything.

I'm allocating the right amount of memory for both the receiving buffer and the transmitting buffer

#include <termios.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
int serialport_init(const char* serialport, int baud) {
    struct termios toptions;
    int fd;
    fd = open(serialport, O_RDWR | O_NONBLOCK);

    if (fd == -1) {
        return -1;
    }

    if (tcgetattr(fd, &toptions) < 0) {
        return -1;
    }
    speed_t brate = baud;
    brate = B115200;
    cfsetispeed(&toptions, brate);
    cfsetospeed(&toptions, brate);

    // 8N1 - * bits no parity
    toptions.c_cflag &= ~PARENB;
    toptions.c_cflag &= ~CSTOPB;
    toptions.c_cflag &= ~CSIZE;
    toptions.c_cflag |= CS8;

    toptions.c_cflag |= CREAD | CLOCAL;  // turn on READ & ignore ctrl lines
    toptions.c_iflag &= ~(IXON | IXOFF | IXANY);  // turn off s/w flow ctrl

    toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);  // make raw
    toptions.c_oflag &= ~OPOST;                           // make raw

    toptions.c_cc[VMIN] = 0;
    toptions.c_cc[VTIME] = 0;

    tcsetattr(fd, TCSANOW, &toptions);
    if (tcsetattr(fd, TCSAFLUSH, &toptions) < 0) {
        return -1;
    }

    return fd;
}


int serialport_write_bytes(int fd, const uint8_t* bytes, size_t n_bytes) {
    ssize_t n;
    size_t bytes_written = 0;

    while (bytes_written < (size_t)n_bytes) {
        n = write(fd, &bytes[bytes_written], n_bytes - bytes_written);
        if (n == -1) continue;
        if (n == 0) {
            continue;
        }
        bytes_written += n;
        printf("wrote total of: %ld bytes n=%ld\n", bytes_written, n);
        tcflush(fd, TCIOFLUSH);  // Flush port - same result if not used
        usleep(10 * 1000);       // wait 1 msec try again. Maybe can remove
    }
    printf("Total bytes written: %ld\n", bytes_written);
    return 0;
}


int serialport_read_bytes(int fd, uint8_t* buf, int n_bytes, int millis) {
    ssize_t n;
    size_t bytes_read = 0;

    while (bytes_read < (size_t)n_bytes) {
        n = read(fd, &buf[bytes_read], n_bytes - bytes_read);
        if (n == -1) return -1;  // couldn't read
        if (n == 0) {
            usleep(millis * 1000);  // wait 1 msec try again
            continue;
        }
        printf("read total: %ld bytes\n", bytes_read);
        bytes_read += n;
    }
    printf("Total bytes read: %ld\n", bytes_read);
    return 0;
}

Solution

  • I think you need to unset the ICRNL flag as well.

    See https://viewsourcecode.org/snaptoken/kilo/02.enteringRawMode.html#fix-ctrl-m

    toptions.c_iflag &= ~ICRNL;