I'm trying to create two classes in C++. Each class implements different serial and its function that is called when it receives a data on the serial port.

Class 1:

    int serialLn = open("/dev/ttyS2", O_RDWR | O_NONBLOCK | O_NOCTTY);
    struct termios options;
    struct serial_struct serInfo;
    struct sigaction saio;

    //Serial speed for loconet
    int rate = 16666;

    saio.sa_handler = loconetInterruptRX;
    sigemptyset(&saio.sa_mask);
    saio.sa_flags = 0;
    sigaction(SIGIO,&saio,NULL);

    fcntl(serialLn, F_SETFL, FASYNC);
    fcntl(serialLn, F_SETOWN, getpid());

    // Custom divisor 
    serInfo.reserved_char[0] = 0;
    ioctl(serialLn, TIOCGSERIAL, &serInfo);
    serInfo.flags &= ~ASYNC_SPD_MASK;
    serInfo.flags |= ASYNC_SPD_CUST;
    serInfo.custom_divisor = (serInfo.baud_base + (rate / 2)) / rate;

    options.c_cflag = B38400 | (CS8 | CREAD);
    options.c_iflag = 0;
    options.c_oflag = 0;
    options.c_lflag = 0;
    options.c_cc[VMIN] = 0;
    options.c_cc[VTIME] = 0;

    tcsetattr(serialLn, TCSANOW, &options);
    tcflush(serialLn, TCIFLUSH);

Class 2:

    int serialCZ = open("/dev/ttyS1", O_RDWR | O_NONBLOCK | O_NOCTTY);
    struct termios options;
    struct serial_struct serInfo;
    struct sigaction saio;

    saio.sa_handler = cz1InterruptRX;
    sigemptyset(&saio.sa_mask);
    saio.sa_flags = 0;
    sigaction(SIGIO, &saio, NULL);

    fcntl(serialCZ, F_SETFL, FASYNC);
    fcntl(serialCZ, F_SETOWN, getpid());

    //Serial setting
    options.c_cflag = B115200 | (CS8 | CREAD);
    options.c_iflag = 0;
    options.c_oflag = 0;
    options.c_lflag = 0;
    options.c_cc[VMIN] = 0;
    options.c_cc[VTIME] = 0;

    tcsetattr(serialCZ, TCSANOW, &options);
    tcflush(serialCZ, TCIFLUSH);

The problem is: When sending data on a serial ttyS2 (class 1) the called method is cz1InterruptRX of Class 2 (and not loconetInterruptRX).

If I do not include in the execution class 2 the progam is working properly.

How can I fix?
thanks

IMO you need to rethink how you are implementing this. You should have only one class that does serial port stuff, not two classes unless the two classes act as one class. One of the members of the class could be the serial port number so that the instance of that class can be assigned to a specific serial port. There are serial port cards that support anywhere from 4 to 64 (or more) serial ports on the same computer, and you wouldn't want to create a new class for each of them.

Second, you should have each instance of the serial port class in its own thread so that they can all work concurrently.

Edited 3 Years Ago by Ancient Dragon

thanks for the reply. I created a new class which configures both of the two serial ports. It shows the same problem, if you get some data on the serial ttyS2 the method called is cz1InterruptRX (instead of loconetInterruptRX).

This is the class:

#include <fcntl.h>
#include <sys/signal.h>
#include <termio.h>
#include <unistd.h>
#include <linux/serial.h>
#include <iostream>

Interfaces::Interfaces(){
    int serialLn = openSerial("/dev/ttyS2", loconetInterruptRX, 16666);
    int serialCZ = openSerial("/dev/ttyS1", cz1InterruptRX, 1);
}

/**
 * Open new serial connection
 * ----------- SPEED LEGEND -----------
 * 0:38400
 * 1:115200
 */
int Interfaces::openSerial(const char *port, void sigHand(int), int rate){

    struct termios options;
    struct serial_struct serInfo;
    struct sigaction saio;

    int serial = open(port, O_RDWR | O_NONBLOCK | O_NOCTTY);

    //Configuration interrupt
    saio.sa_handler = sigHand;
    sigemptyset(&saio.sa_mask);
    saio.sa_flags = 0;
    sigaction(SIGIO,&saio,NULL);

    fcntl(serial, F_SETFL, FASYNC);

    if(rate > 1){
        // Custom divisor 
        serInfo.reserved_char[0] = 0;
        ioctl(serial, TIOCGSERIAL, &serInfo);
        serInfo.flags &= ~ASYNC_SPD_MASK;
        serInfo.flags |= ASYNC_SPD_CUST;
        serInfo.custom_divisor = (serInfo.baud_base + (rate / 2)) / rate;
    }

    //Set serial speed
    switch(rate){
        case 1: options.c_cflag = B115200 | (CS8 | CREAD); break;
        default: options.c_cflag = B38400 | (CS8 | CREAD); break;
    }
    //Serial setting
    options.c_iflag = 0;
    options.c_oflag = 0;
    options.c_lflag = 0;
    options.c_cc[VMIN] = 0;
    options.c_cc[VTIME] = 0;

    tcsetattr(serial, TCSANOW, &options);
    tcflush(serial, TCIFLUSH);

    return serial;
}

//Serial interrupt rx
void Interfaces::loconetInterruptRX(int status){
    std::cout <<  "LOCONET" << std::endl;
}
//Serial interrupt rx
void Interfaces::cz1InterruptRX(int status){
    std::cout <<  "XBEE" << std::endl;
}

Edited 3 Years Ago by zampi91

This article has been dead for over six months. Start a new discussion instead.