0

I'm trying to make a program which will listen to a serial port (gps antena) for logs sent by it every second. The program works as expected, but when I start listening with pygpsclient the termios settings are modified so I set them in my program. The problem is that my settings are not set in termios until I unplug the gps antena and plug it back, I noticed that with stty command. The problem is after running pygpsclient the program read only one byte char from the gps and my program is made to read a row at a time and parse it so it will crash. If need more info, please tell me, I'm quite new to C++. Any help would be appreciated.

class Read_Class
{
public:
    using LineCallback = std::function<void(std::string &)>;

    int openSerial()
    {

        const int serial_port = open("/dev/ttyUSB0", O_RDWR);

        if (serial_port < 0)
        {
            std::cout << "serial port: " << serial_port << std::endl;
            std::cerr << "Error opening serial port." << std::endl;
        }
        else
        {
            fcntl(serial_port, F_SETFL, 0);
        }
        // close(serial_port);
        return (serial_port);
    }
    void configPort(int sp)
    {
        struct termios tty;

        // config the tty flags
        tty.c_cc[VMIN] = 1;

        tty.c_iflag |= ICRNL;
        tty.c_iflag |= IXON;

        tty.c_oflag |= OPOST;
        tty.c_oflag |= ONLCR;

        tty.c_lflag |= ISIG;
        tty.c_lflag |= ICANON;
        tty.c_lflag |= IEXTEN;
        tty.c_cflag |= ECHO;
        tty.c_lflag |= ECHOE;
        tty.c_lflag |= ECHOK;
        tty.c_lflag |= ECHOCTL;
        tty.c_lflag |= ECHOKE;

        if (tcgetattr(sp, &tty) != 0)
        {
            std::cerr << "Error getting serial port atributes" << std::endl;
        }

        // set baud rate
        cfsetispeed(&tty, B9600); // input baud rate
        cfsetospeed(&tty, B9600); // output baud rate

        if (tcsetattr(sp, TCSANOW, &tty) != 0)
        {
            std::cerr << "Error setting serial port attributes." << std::endl;
            return;
        }
    }

    void readLogs(int sp, LineCallback callback)
    {
        const int buff_size = 200;
        char buffer[buff_size];
        // ssize_t bytesRead = 0;
        memset(buffer, '\0', buff_size);

        struct pollfd fds[1];
        fds[0].fd = sp;
        fds[0].events = POLLIN;

        while (true)
        {
            int pollResult = poll(fds, 1, 200);
            if (pollResult > 0 && (fds[0].revents & POLLIN))
            {
                ssize_t bytesRead = read(sp, buffer, sizeof(buffer));
                if (bytesRead > 0)
                {
                    // std::cout << "----------->>>>>>> " << bytesRead << std::endl;
                    std::string line = std::string(buffer, bytesRead);
                    callback(line);
                    // std::cout << line;
                    memset(buffer, '\0', buff_size);
                    bytesRead = 0;
                }
            }
            else if (pollResult == -1)
            {
                break;
            }
        }
    }
};

and this is main

int main()
{
    Read_Class rc;
    const int serial = rc.openSerial();
    rc.configPort(serial);
    if (serial >= 0)
    {
        rc.readLogs(serial, [&sc_dt](std::string &line)
                    {
                if (!line.empty() && line.substr(0,1).compare("$") == 0)
                {
                    std::cout << line << std::endl;
                } });
    }
    close(serial);
    return 0;
}

MBI
  • 15
  • 4
  • Since you open the device from your C++ program, where does `pygpsclient` come into the setup? What happens if you don't run `pygpsclient` at all? – Ted Lyngmo Jul 21 '23 at 08:23
  • So I run pygpsclient only for it's GUI, separately from my program in another terminal, I don't actually need to run pygpsclient at all, but I was wondering why the termios setting doesn't reset after closing pygpsclient, even if I set my own settings in my program, unless I unplug the gps and plug it back. – MBI Jul 21 '23 at 08:32
  • I would guess that it depends on in which order you connect, open, close, disconnect from the two programs that are competing to do the settings. I recommend only connecting one program unless the documentation says you should be able to have multiple programs connect to the device via `/dev/ttyUSB0`. – Ted Lyngmo Jul 21 '23 at 08:42
  • "*The program works as expected, but ...*" -- Which is surprising considering that your termios settings are very broken. You use/modify an uninitialized structure. You set the baudrate, but not frame size, parity nor stop bit(s). You enable echo!!!??? "*my program is made to read a row at a time*" -- Don't you mean a *line* rather than a "*row*"? See https://stackoverflow.com/questions/57152937/canonical-mode-linux-serial-port/57155531#57155531 for sample code that configures termios to read lines from a serial terminal connection. – sawdust Jul 24 '23 at 05:03
  • "*why the termios setting doesn't reset*" -- The termios settings are persistent for each serial terminal. A well-behaved program would have to restore the termios configuration before it terminated. For such an example using a `savetty` stucture, see https://stackoverflow.com/questions/12437593/how-to-read-a-binary-data-over-serial-terminal-in-c-program/12457195#12457195 – sawdust Jul 24 '23 at 05:08

0 Answers0