1

I'm making a c++ serial class in Linux. I'm trying to register an event when incoming data is received.

I'm working on a Olimex Lime2 board. gcc version 4.6.3 (Debian 4.6.3-14)

This is the error i get when trying to compile. conSerial.cpp: In function ‘void signal_handler_IO(int)’: conSerial.cpp:15:6: error: ‘EventHandler’ was not declared in this scope

I think this means that it doesn't have access to the class. Perhaps I've gone about this the wrong way. Any advice would be appreciated.

Thank you,

Steve

Header File

#ifndef CONSERIAL_H_
#define CONSERIAL_H_

#include "termios.h"
#include <sys/signal.h>
class conSerialEvents
{
    public:
        virtual void onReceive();
};
class conSerial
{
    public:
        conSerial(const char *port_, termios *options_, conSerialEvents *EventHandler_);
        conSerial(const char *port_, termios *options_);
        int open_port(void);
        int send(const char *s, size_t len);
        void close_port( void );
    private:

        conSerialEvents *EventHandler;
        static const int PORT_OPEN = 0;
        termios *options;
        const char *port;
        int fd;
        struct sigaction saio;  
};

#endif

Class File

#include <stdio.h>      //Standard input/output definitions
#include <string.h>     //String function definitions
#include <unistd.h>     //UNIX standard function definitions
#include <fcntl.h>      //File control definitions
#include <errno.h>      //Error number definitions
#include <termios.h>    //POSIX terminal control definitions
#include <iostream>     //Input-Output Streams
#include "conSerial.h"  //Header for this file
using namespace std;
void signal_handler_IO (int status);
void signal_handler_IO (int status)
{
    std::cout << "Signal" << std::endl;
    //This section fails because it can't see the class I think.
    if (EventHandler)
    {
        EventHandler->onReceive();
    }
    //End this section

}

conSerial::conSerial(const char *port_, termios *options_)
{
    this->EventHandler = 0L;
    const char *port;
    termios *options;
    fd = -1;

}

conSerial::conSerial(const char *port_, termios *options_, conSerialEvents *EventHandler_)
{
    this->EventHandler = EventHandler_;
    const char *port;
    termios *options;
    fd = -1;
} 

int conSerial::open_port(void){

    struct termios options;

    fd = open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NDELAY);

    if (fd == -1){
        //Could not open the port.
        std::cout << "Port Failed to Open";
    }else{
        saio.sa_handler = signal_handler_IO;
        sigemptyset(&saio.sa_mask);
        saio.sa_flags = 0;
        saio.sa_flags = SA_NODEFER;
        saio.sa_restorer = NULL;
        sigaction(SIGIO,&saio,NULL);

        fcntl(fd, F_SETOWN, getpid());      
        fcntl(fd, F_SETFL, FNDELAY); // Sets the read() function to return NOW and not wait for data to enter buffer if there isn't anything there.

        //Configure port for 8N1 transmission
        tcgetattr(fd, &options);                    //Gets the current options for the port
        cfsetispeed(&options, B38400);              //Sets the Input Baud Rate
        cfsetospeed(&options, B38400);              //Sets the Output Baud Rate
        options.c_cflag |= (CLOCAL | CREAD);        //? all these set options for 8N1 serial operations
        options.c_cflag |= PARENB;                  //? 
        options.c_cflag &= ~CSTOPB;                 //?
        options.c_cflag &= ~CSIZE;                  //?
        options.c_cflag |= CS7;                     //?

        tcsetattr(fd, TCSANOW, &options);           //Set the new options for the port "NOW"

        std::cout << "seems like everything is ok, keep going\n";
    };

    return (fd);
};

int conSerial::send(const char *s, size_t len){
    int written;
    written = 0;
    if (fd==-1){    //
        // If this is -1 it means that the port is not open.
        std::cout << "The port is not open." << std::endl;
    }else{
        // The port is open
        tcdrain(fd);
        written = write(fd, s, len);
    }
    return written;
}

void conSerial::close_port( void ){
    if (fd !=-1){
        close(fd);
    }
}
Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105

1 Answers1

0

In your "Class File", you declared a function:

void signal_handler_IO (int status)

which refers to some object called "EventHandler".

No such object is declared anywhere, hence the compilation error. It's as simple as that.

It is true that you declared a class named "conSerial", which happens to have a class member called "EventHandler".

However, that's a class right there. And a class member. The fact that you have some class that happens to declare a class member of the same name makes absolutely no difference, whatsoever. C++ doesn't work this way. signal_handler_IO is not a method in the same class. It is not even a static class function in that class. To access a class member you need one of two things: either an instance of a class, somewhere, in order to access its member; or access it from a non-static method in the same class, which automatically access the corresponding member of whatever class instance whose method it is. That's how C++ works.

And that's the fundamental explanation for your compilation error.

It is true that in a different class method called "open_port", you take a pointer to this signal_handler_IO function, and install it as a signal handler for SIGIO. Again, that doesn't really change anything.

It appears that you intend your conSerial class to be a singleton. In that case, the cleanest solution for your conundrum is:

  1. Refactor the class so that it's construction and destruction uses the singleton design pattern, as much as possible.

  2. Install the signal handler in the class's constructor, and uninstall the signal handler in its destructor.

  3. Have the constructor save a pointer to this in a private static class member, before installing the signal handler.

  4. Move the bulk of signal_handler_IO into a static class method, and have signal_handler_IO do nothing except invoke the static class method.

  5. Have you static class method use the pointer that was set up in step 3 access the actual instance of your singleton class. Now, it can do whatever it wants to do with its "EventHandler" class member.

Community
  • 1
  • 1
Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148