/*----- PROTECTED REGION ID(Serial2.cpp) ENABLED START -----*/ //============================================================================= // // file : Serial2.cpp // // description : C++ source for the Serial2 class and its commands. // The class is derived from Device. It represents the // CORBA servant object which will be accessed from the // network. All commands which can be executed on the // Serial2 are implemented in this file. // // project : // // This file is part of Tango device class. // // Tango is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Tango is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Tango. If not, see <http://www.gnu.org/licenses/>. // // $Author: alessio $ // // $Revision: 1.25 $ // $Date: 2019-01-10 15:58:39 $ // // $HeadURL: $ // //============================================================================= // This file is generated by POGO // (Program Obviously used to Generate tango Object) //============================================================================= #include <Serial2.h> #include <Serial2Class.h> #include <fcntl.h> #include <sys/ioctl.h> #include <csignal> #include <termios.h> /*----- PROTECTED REGION END -----*/ // Serial2.cpp /** * Serial2 class description: * */ //================================================================ // The following table gives the correspondence // between command and method names. // // Command name | Method name //================================================================ // Write | write // Read | read // ReadUntil | read_until //================================================================ //================================================================ // Attributes managed are: //================================================================ // InputLength | Tango::DevLong Scalar // OutputLength | Tango::DevLong Scalar // Reconnections | Tango::DevLong Scalar //================================================================ namespace Serial2_ns { /*----- PROTECTED REGION ID(Serial2::namespace_starting) ENABLED START -----*/ // static initializations /*----- PROTECTED REGION END -----*/ // Serial2::namespace_starting //-------------------------------------------------------- /** * Method : Serial2::Serial2() * Description: Constructors for a Tango device * implementing the classSerial2 */ //-------------------------------------------------------- Serial2::Serial2(Tango::DeviceClass *cl, std::string &s) : TANGO_BASE_CLASS(cl, s.c_str()) { /*----- PROTECTED REGION ID(Serial2::constructor_1) ENABLED START -----*/ reconnections = -1; connecting = false; init_device(); /*----- PROTECTED REGION END -----*/ // Serial2::constructor_1 } //-------------------------------------------------------- Serial2::Serial2(Tango::DeviceClass *cl, const char *s) : TANGO_BASE_CLASS(cl, s) { /*----- PROTECTED REGION ID(Serial2::constructor_2) ENABLED START -----*/ reconnections = -1; connecting = false; init_device(); /*----- PROTECTED REGION END -----*/ // Serial2::constructor_2 } //-------------------------------------------------------- Serial2::Serial2(Tango::DeviceClass *cl, const char *s, const char *d) : TANGO_BASE_CLASS(cl, s, d) { /*----- PROTECTED REGION ID(Serial2::constructor_3) ENABLED START -----*/ reconnections = -1; connecting = false; init_device(); /*----- PROTECTED REGION END -----*/ // Serial2::constructor_3 } //-------------------------------------------------------- Serial2::~Serial2() { delete_device(); } //-------------------------------------------------------- /** * Method : Serial2::delete_device() * Description: will be called at device destruction or at init command */ //-------------------------------------------------------- void Serial2::delete_device() { DEBUG_STREAM << "Serial2::delete_device() " << device_name << std::endl; /*----- PROTECTED REGION ID(Serial2::delete_device) ENABLED START -----*/ // Delete device allocated objects close(); /*----- PROTECTED REGION END -----*/ // Serial2::delete_device delete[] attr_InputLength_read; delete[] attr_OutputLength_read; delete[] attr_Reconnections_read; } //-------------------------------------------------------- /** * Method : Serial2::init_device() * Description: will be called at device initialization. */ //-------------------------------------------------------- void Serial2::init_device() { DEBUG_STREAM << "Serial2::init_device() create device " << device_name << std::endl; /*----- PROTECTED REGION ID(Serial2::init_device_before) ENABLED START -----*/ // Initialization before get_device_property() call init_error.clear(); /*----- PROTECTED REGION END -----*/ // Serial2::init_device_before // Get the device properties from database get_device_property(); attr_InputLength_read = new Tango::DevLong[1]; attr_OutputLength_read = new Tango::DevLong[1]; attr_Reconnections_read = new Tango::DevLong[1]; // No longer if mandatory property not set. if (mandatoryNotDefined) return; /*----- PROTECTED REGION ID(Serial2::init_device) ENABLED START -----*/ // Initialize device try { set_state( Tango::INIT ); set_status( "Connecting..." ); if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { ERROR_STREAM << "Fail to ignore SIGPIPE" << endl; } open(); } catch (Tango::DevFailed &e) { init_error = "Initialization failed: " + string(e.errors[0].desc); } catch (...) { init_error = "Initialization failed: Unknown error"; } if( init_error.empty() ) { check_connection( ); } /*----- PROTECTED REGION END -----*/ // Serial2::init_device } //-------------------------------------------------------- /** * Method : Serial2::get_device_property() * Description: Read database to initialize property data members. */ //-------------------------------------------------------- void Serial2::get_device_property() { /*----- PROTECTED REGION ID(Serial2::get_device_property_before) ENABLED START -----*/ // Initialize property data members /*----- PROTECTED REGION END -----*/ // Serial2::get_device_property_before mandatoryNotDefined = false; // Read device properties from database. Tango::DbData dev_prop; dev_prop.push_back(Tango::DbDatum("Serialline")); dev_prop.push_back(Tango::DbDatum("Charlength")); dev_prop.push_back(Tango::DbDatum("Parity")); dev_prop.push_back(Tango::DbDatum("Baudrate")); dev_prop.push_back(Tango::DbDatum("Stopbits")); dev_prop.push_back(Tango::DbDatum("Flowcontrol")); dev_prop.push_back(Tango::DbDatum("Timeout")); dev_prop.push_back(Tango::DbDatum("IOMultiplexing")); // is there at least one property to be read ? if (dev_prop.size()>0) { // Call database and extract values if (Tango::Util::instance()->_UseDb==true) get_db_device()->get_property(dev_prop); // get instance on Serial2Class to get class property Tango::DbDatum def_prop, cl_prop; Serial2Class *ds_class = (static_cast<Serial2Class *>(get_device_class())); int i = -1; // Try to initialize Serialline from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> serialline; else { // Try to initialize Serialline from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> serialline; } // And try to extract Serialline value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> serialline; // Property StartDsPath is mandatory, check if has been defined in database. check_mandatory_property(cl_prop, dev_prop[i]); // Try to initialize Charlength from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> charlength; else { // Try to initialize Charlength from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> charlength; } // And try to extract Charlength value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> charlength; // Property StartDsPath is mandatory, check if has been defined in database. check_mandatory_property(cl_prop, dev_prop[i]); // Try to initialize Parity from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> parity; else { // Try to initialize Parity from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> parity; } // And try to extract Parity value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> parity; // Property StartDsPath is mandatory, check if has been defined in database. check_mandatory_property(cl_prop, dev_prop[i]); // Try to initialize Baudrate from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> baudrate; else { // Try to initialize Baudrate from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> baudrate; } // And try to extract Baudrate value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> baudrate; // Property StartDsPath is mandatory, check if has been defined in database. check_mandatory_property(cl_prop, dev_prop[i]); // Try to initialize Stopbits from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> stopbits; else { // Try to initialize Stopbits from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> stopbits; } // And try to extract Stopbits value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> stopbits; // Property StartDsPath is mandatory, check if has been defined in database. check_mandatory_property(cl_prop, dev_prop[i]); // Try to initialize Flowcontrol from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> flowcontrol; else { // Try to initialize Flowcontrol from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> flowcontrol; } // And try to extract Flowcontrol value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> flowcontrol; // Property StartDsPath is mandatory, check if has been defined in database. check_mandatory_property(cl_prop, dev_prop[i]); // Try to initialize Timeout from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> timeout; else { // Try to initialize Timeout from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> timeout; } // And try to extract Timeout value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> timeout; // Property StartDsPath is mandatory, check if has been defined in database. check_mandatory_property(cl_prop, dev_prop[i]); // Try to initialize IOMultiplexing from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> iOMultiplexing; else { // Try to initialize IOMultiplexing from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> iOMultiplexing; } // And try to extract IOMultiplexing value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> iOMultiplexing; } /*----- PROTECTED REGION ID(Serial2::get_device_property_after) ENABLED START -----*/ // Check device property data members init transform(iOMultiplexing.begin(), iOMultiplexing.end(), iOMultiplexing.begin(), ::tolower); if (iOMultiplexing == "sleep") { multiplexing = SLEEP; DEBUG_STREAM << "Using sleep IO multiplexing type" << endl; } else { multiplexing = SELECT; DEBUG_STREAM << "Using select IO multiplexing type" << endl; } /*----- PROTECTED REGION END -----*/ // Serial2::get_device_property_after } //-------------------------------------------------------- /** * Method : Serial2::check_mandatory_property() * Description: For mandatory properties check if defined in database. */ //-------------------------------------------------------- void Serial2::check_mandatory_property(Tango::DbDatum &class_prop, Tango::DbDatum &dev_prop) { // Check if all properties are empty if (class_prop.is_empty() && dev_prop.is_empty()) { TangoSys_OMemStream tms; tms << std::endl <<"Property \'" << dev_prop.name; if (Tango::Util::instance()->_UseDb==true) tms << "\' is mandatory but not defined in database"; else tms << "\' is mandatory but cannot be defined without database"; append_status(tms.str()); mandatoryNotDefined = true; /*----- PROTECTED REGION ID(Serial2::check_mandatory_property) ENABLED START -----*/ cerr << tms.str() << " for " << device_name << endl; /*----- PROTECTED REGION END -----*/ // Serial2::check_mandatory_property } } //-------------------------------------------------------- /** * Method : Serial2::always_executed_hook() * Description: method always executed before any command is executed */ //-------------------------------------------------------- void Serial2::always_executed_hook() { DEBUG_STREAM << "Serial2::always_executed_hook() " << device_name << std::endl; if (mandatoryNotDefined) { Tango::Except::throw_exception( (const char *)"PROPERTY_NOT_SET", get_status().c_str(), (const char *)"Serial2::always_executed_hook()"); } /*----- PROTECTED REGION ID(Serial2::always_executed_hook) ENABLED START -----*/ // code always executed before all requests if (! init_error.empty()) { set_state(Tango::FAULT); set_status(init_error); return; } tout.tv_sec = timeout / 1000; tout.tv_usec = timeout % 1000 * 1000; if ( ! timerisset( &tout ) ) { set_state(Tango::FAULT); set_status("Invalid timeout"); } else { check_connection( ); } /*----- PROTECTED REGION END -----*/ // Serial2::always_executed_hook } //-------------------------------------------------------- /** * Method : Serial2::read_attr_hardware() * Description: Hardware acquisition for attributes */ //-------------------------------------------------------- void Serial2::read_attr_hardware(TANGO_UNUSED(std::vector<long> &attr_list)) { DEBUG_STREAM << "Serial2::read_attr_hardware(std::vector<long> &attr_list) entering... " << std::endl; /*----- PROTECTED REGION ID(Serial2::read_attr_hardware) ENABLED START -----*/ // Add your own code /*----- PROTECTED REGION END -----*/ // Serial2::read_attr_hardware } //-------------------------------------------------------- /** * Read attribute InputLength related method * * * Data type: Tango::DevLong * Attr type: Scalar */ //-------------------------------------------------------- void Serial2::read_InputLength(Tango::Attribute &attr) { DEBUG_STREAM << "Serial2::read_InputLength(Tango::Attribute &attr) entering... " << std::endl; /*----- PROTECTED REGION ID(Serial2::read_InputLength) ENABLED START -----*/ // Set the attribute value attr_InputLength_read[0] = input_queue_length() + data.size(); attr.set_value(attr_InputLength_read); /*----- PROTECTED REGION END -----*/ // Serial2::read_InputLength } //-------------------------------------------------------- /** * Read attribute OutputLength related method * * * Data type: Tango::DevLong * Attr type: Scalar */ //-------------------------------------------------------- void Serial2::read_OutputLength(Tango::Attribute &attr) { DEBUG_STREAM << "Serial2::read_OutputLength(Tango::Attribute &attr) entering... " << std::endl; /*----- PROTECTED REGION ID(Serial2::read_OutputLength) ENABLED START -----*/ // Set the attribute value attr_OutputLength_read[0] = output_queue_length(); attr.set_value(attr_OutputLength_read); /*----- PROTECTED REGION END -----*/ // Serial2::read_OutputLength } //-------------------------------------------------------- /** * Read attribute Reconnections related method * * * Data type: Tango::DevLong * Attr type: Scalar */ //-------------------------------------------------------- void Serial2::read_Reconnections(Tango::Attribute &attr) { DEBUG_STREAM << "Serial2::read_Reconnections(Tango::Attribute &attr) entering... " << std::endl; /*----- PROTECTED REGION ID(Serial2::read_Reconnections) ENABLED START -----*/ // Set the attribute value attr_Reconnections_read[0] = reconnections; attr.set_value(attr_Reconnections_read); /*----- PROTECTED REGION END -----*/ // Serial2::read_Reconnections } //-------------------------------------------------------- /** * Method : Serial2::add_dynamic_attributes() * Description: Create the dynamic attributes if any * for specified device. */ //-------------------------------------------------------- void Serial2::add_dynamic_attributes() { /*----- PROTECTED REGION ID(Serial2::add_dynamic_attributes) ENABLED START -----*/ // Add your own code to create and add dynamic attributes if any /*----- PROTECTED REGION END -----*/ // Serial2::add_dynamic_attributes } //-------------------------------------------------------- /** * Command Write related method * * * @param argin */ //-------------------------------------------------------- void Serial2::write(const Tango::DevVarCharArray *argin) { DEBUG_STREAM << "Serial2::Write() - " << device_name << std::endl; /*----- PROTECTED REGION ID(Serial2::write) ENABLED START -----*/ check_init(); char *argin_data = new char[ argin->length() ]; for( unsigned int i=0; i<argin->length(); ++i ) { argin_data[i] = (*argin)[i]; } int bytes_total = 0, bytes_to_write = argin->length(); while (bytes_total != bytes_to_write && wait_for( WRITE, &tout ) ) { int bytes_written; bytes_written = ::write(fd, argin_data + bytes_total, bytes_to_write - bytes_total); if (bytes_written < 0) { DEBUG_STREAM << strerror( errno ) << " (" << errno << ")" << endl; if( errno == EINTR ) { continue; } if( errno == ECONNREFUSED ) { delete argin_data; close(); open(); string error_mesg = "Connection refused"; DEBUG_STREAM << error_mesg << endl; set_state( Tango::FAULT ); set_status( error_mesg ); sleep( tout.tv_sec ); usleep( tout.tv_usec ); timerclear( &tout ); Tango::Except::throw_exception( "", error_mesg, "Serial2::write()"); } ERROR_STREAM << "write() error not handled:" << endl; assert( false ); } else if( bytes_written == 0 ) { assert( false ); } else /* bytes_written > 0 */ { bytes_total += bytes_written; } } delete argin_data; timeval time_to_wait; time_to_wait.tv_sec = 0; time_to_wait.tv_usec = 1000; while ( output_queue_length() ) { timeval newtimeout; timersub( &tout, &time_to_wait, &newtimeout ); if( newtimeout.tv_sec >= 0 && newtimeout.tv_usec >= 0 ) { sleep( time_to_wait.tv_sec ); usleep( time_to_wait.tv_usec ); tout = newtimeout; timeradd( &time_to_wait, &time_to_wait, &time_to_wait ); } else { sleep( tout.tv_sec ); usleep( tout.tv_usec ); timerclear( &tout ); break; } } if( (bytes_total - output_queue_length()) != bytes_to_write ) { close(); open(); string error_mesg = "Unable to send request to device"; DEBUG_STREAM << error_mesg << endl; set_state( Tango::FAULT ); set_status( error_mesg ); Tango::Except::throw_exception( "", error_mesg, "Serial2::write()"); } /*----- PROTECTED REGION END -----*/ // Serial2::write } //-------------------------------------------------------- /** * Command Read related method * * * @param argin * @returns */ //-------------------------------------------------------- Tango::DevVarCharArray *Serial2::read(Tango::DevLong argin) { Tango::DevVarCharArray *argout; DEBUG_STREAM << "Serial2::Read() - " << device_name << std::endl; /*----- PROTECTED REGION ID(Serial2::read) ENABLED START -----*/ check_init(); if (argin < 0) { Tango::Except::throw_exception("", "Input has to be in positive range", "Serial2::read()"); } while( (size_t)argin > data.size() ) { if ( ! wait_for( READ, &tout ) ) { string mesg( "No response from device" ); DEBUG_STREAM << mesg << endl; Tango::Except::throw_exception("", mesg, "Serial2::read()"); } } argout = new Tango::DevVarCharArray(); argout->length(argin); for( int i=0; i<argin; ++i ) { (*argout)[i] = data[i]; } data.erase( data.begin(), data.begin() + argin ); /*----- PROTECTED REGION END -----*/ // Serial2::read return argout; } //-------------------------------------------------------- /** * Command ReadUntil related method * * * @param argin * @returns */ //-------------------------------------------------------- Tango::DevVarCharArray *Serial2::read_until(const Tango::DevVarCharArray *argin) { Tango::DevVarCharArray *argout; DEBUG_STREAM << "Serial2::ReadUntil() - " << device_name << std::endl; /*----- PROTECTED REGION ID(Serial2::read_until) ENABLED START -----*/ check_init(); if (argin->length() != 1) { Tango::Except::throw_exception("", "Delimiter has to be one byte length", "Serial2::read_until()"); } char delim = (*argin)[0]; bool found = false; size_t pos; while( ! found ) { for( pos = 0; pos < data.size(); ++pos ) { if (memcmp(&data[pos], &delim, 1) == 0) { found = true; break; } } if ( ! found && ! wait_for( READ, &tout ) ) { string mesg( "No response from device" ); DEBUG_STREAM << mesg << endl; Tango::Except::throw_exception("", mesg, "Serial2::read_until()"); } } argout = new Tango::DevVarCharArray(); argout->length( pos+1 ); for( size_t i = 0; i < pos + 1; ++i ) { (*argout)[i] = data[i]; } data.erase( data.begin(), data.begin() + pos + 1 ); /*----- PROTECTED REGION END -----*/ // Serial2::read_until return argout; } //-------------------------------------------------------- /** * Method : Serial2::add_dynamic_commands() * Description: Create the dynamic commands if any * for specified device. */ //-------------------------------------------------------- void Serial2::add_dynamic_commands() { /*----- PROTECTED REGION ID(Serial2::add_dynamic_commands) ENABLED START -----*/ // Add your own code to create and add dynamic commands if any /*----- PROTECTED REGION END -----*/ // Serial2::add_dynamic_commands } /*----- PROTECTED REGION ID(Serial2::namespace_ending) ENABLED START -----*/ // Additional Methods void Serial2::check_init() { if (! init_error.empty() ) { DEBUG_STREAM << init_error << endl; Tango::Except::throw_exception( "", init_error.c_str(), "Serial2::check_init()"); } } void Serial2::open() { DEBUG_STREAM << "Creating the file descriptor..." << endl; if ((fd = ::open(serialline.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK)) == -1) { string error_mesg = "Open device node failed: " + string(strerror( errno )); ERROR_STREAM << error_mesg << endl; assert( false); Tango::Except::throw_exception( "", error_mesg, "Serial2::open()"); } // Common struct termios options; memset(&options, 0, sizeof(struct termios)); options.c_cflag |= (CLOCAL | CREAD); options.c_oflag &= ~OPOST; options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | IEXTEN); options.c_iflag &= ~(INPCK | ISTRIP); // Baud rate map<unsigned long, speed_t> baudrates_db; baudrates_db[4000000] = B4000000; baudrates_db[3500000] = B3500000; baudrates_db[3000000] = B3000000; baudrates_db[2500000] = B2500000; baudrates_db[2000000] = B2000000; baudrates_db[1500000] = B1500000; baudrates_db[1000000] = B1000000; baudrates_db[921600] = B921600; baudrates_db[576000] = B576000; baudrates_db[500000] = B500000; baudrates_db[460800] = B460800; baudrates_db[230400] = B230400; baudrates_db[115200] = B115200; baudrates_db[57600] = B57600; baudrates_db[38400] = B38400; baudrates_db[19200] = B19200; baudrates_db[9600] = B9600; baudrates_db[4800] = B4800; baudrates_db[2400] = B2400; baudrates_db[1800] = B1800; baudrates_db[1200] = B1200; baudrates_db[600] = B600; baudrates_db[300] = B300; baudrates_db[200] = B200; baudrates_db[150] = B150; baudrates_db[134] = B134; baudrates_db[110] = B110; baudrates_db[75] = B75; baudrates_db[50] = B50; cfsetispeed(&options, baudrates_db[baudrate]); cfsetospeed(&options, baudrates_db[baudrate]); // Data bits map<unsigned short, tcflag_t> databits_db; databits_db[8] = CS8; databits_db[7] = CS7; databits_db[6] = CS6; databits_db[5] = CS5; options.c_cflag &= ~CSIZE; options.c_cflag |= databits_db[charlength]; // Stop bits switch (stopbits) { case 1: options.c_cflag &= ~CSTOPB; break; case 2: options.c_cflag |= CSTOPB; break; default: { string error_mesg = "Error setting stop bits parameter!" + string(strerror( errno )); ERROR_STREAM << error_mesg << endl; assert( false); Tango::Except::throw_exception( "", error_mesg, "Serial2::open()"); } } // Parity bits transform(parity.begin(), parity.end(), parity.begin(), ::tolower); if (parity == "even") { options.c_cflag |= PARENB; options.c_cflag &= ~PARODD; } else if (parity == "odd") { options.c_cflag |= PARENB; options.c_cflag |= PARODD; } else if (parity == "none" ) { options.c_cflag &= ~PARENB; } else { string error_mesg = "Error setting parity bits parameter!" + string(strerror( errno )); ERROR_STREAM << error_mesg << endl; assert( false); Tango::Except::throw_exception( "", error_mesg, "Serial2::open()"); } // Flow control transform(flowcontrol.begin(), flowcontrol.end(), flowcontrol.begin(), ::tolower); options.c_iflag &= ~(IXON | IXOFF | IXANY); options.c_cflag &= ~CRTSCTS; if (flowcontrol == "xonxoff") { options.c_iflag |= (IXON | IXOFF | IXANY); } else if (flowcontrol == "rtscts") { options.c_cflag |= CRTSCTS; } else if (flowcontrol == "dtrdsr") { string error_mesg = "Flow control DTRDSR isn't supported yet!" + string(strerror( errno )); ERROR_STREAM << error_mesg << endl; assert( false); Tango::Except::throw_exception( "", error_mesg, "Serial2::open()"); } else if (flowcontrol == "none") { // Make nothing } else { string error_mesg = "Error setting flow control parameter!" + string(strerror( errno )); ERROR_STREAM << error_mesg << endl; assert( false); Tango::Except::throw_exception( "", error_mesg, "Serial2::open()"); } // Set necessary serial parameters if (tcsetattr(fd, TCSADRAIN, &options) == -1) { string error_mesg = "Error setting all serial parameters!" + string(strerror( errno )); ERROR_STREAM << error_mesg << endl; assert( false); Tango::Except::throw_exception( "", error_mesg, "Serial2::open()"); } connecting = true; } void Serial2::close() { DEBUG_STREAM << "Closing the file descriptor..." << endl; connecting = false; int input_len = input_queue_length() + data.size(); int output_len = output_queue_length(); if( input_len + output_len) { WARN_STREAM << " Bytes dropped: " << input_len << " input, " << output_len << " output" << endl; } if (::close(fd) == -1) { ERROR_STREAM << "Error closing file descriptor: " << strerror(errno) << endl; } data.clear(); DEBUG_STREAM << "File descriptor closed" << endl; } int Serial2::input_queue_length() { int len; if (ioctl(fd, FIONREAD, &len) == -1) { len = 0; } return len; } int Serial2::output_queue_length() { int len; if (ioctl(fd, TIOCOUTQ, &len) == -1) { len = 0; } return len; } void Serial2::check_connection( ) { timeval tv; timerclear( &tv ); if( wait_for( WRITE, &tv ) ) { if( connecting ) { reconnections++; connecting = false; } set_state( Tango::ON ); set_status( "Connected" ); } } bool Serial2::read(timeval *tv) { int bytes_total = 0, bytes_to_read = input_queue_length(); do { int len = (bytes_to_read - bytes_total) > BUFFER_SIZE? BUFFER_SIZE : (bytes_to_read - bytes_total); int bytes_readed = ::read(fd, buffer, len); if( bytes_readed < 0 ) { DEBUG_STREAM << strerror( errno ) << " (" << errno << ")" << endl; if( errno == EINTR) { continue; } } else if( bytes_readed == 0 ) { close(); open(); string error_mesg = "Server shutting down"; DEBUG_STREAM << error_mesg << endl; set_state(Tango::FAULT); set_status(error_mesg); sleep( tv->tv_sec ); usleep( tv->tv_usec ); timerclear( tv ); return false; } else /* bytes_readed > 0 */ { data.insert(data.end(), &buffer[0], &buffer[bytes_readed]); bytes_total += bytes_readed; } } while (bytes_total != bytes_to_read); return true; } bool Serial2::wait_for( event_type et, timeval *tv ) { switch(multiplexing) { case SLEEP: return wait_for_with_sleep(et, tv); default: return wait_for_with_select(et, tv); } } bool Serial2::wait_for_with_sleep( event_type et, timeval *tv ) { struct timeval sleep_time; sleep_time.tv_sec = 0; sleep_time.tv_usec = 10000; /* 10 ms */ do { switch( et ) { case WRITE: if( output_queue_length() == 0 ) { #ifndef NDEBUG DEBUG_STREAM << "Ready to write" << endl; #endif return true; } break; case READ: if( input_queue_length() != 0 ) { #ifndef NDEBUG DEBUG_STREAM << "Ready to read" << endl; #endif return read(tv); } break; } int usleep_ret = usleep(sleep_time.tv_usec); #ifndef NDEBUG DEBUG_STREAM << "usleep(): " << usleep_ret << endl; #else (void)usleep_ret; #endif timersub(tv, &sleep_time, tv); } while (timerisset(tv)); return false; } bool Serial2::wait_for_with_select( event_type et, timeval *tv ) { FD_ZERO(&errorfds); FD_ZERO(&readfds); FD_ZERO(&writefds); FD_SET(fd, &errorfds); switch( et ) { case WRITE: FD_SET(fd, &writefds); break; case READ: FD_SET(fd, &readfds); break; } int select_ret = select( fd + 1, &readfds, &writefds, &errorfds, tv ); #ifndef NDEBUG DEBUG_STREAM << "select(): " << select_ret << endl; #endif if( select_ret == -1 ) { ERROR_STREAM << "Select() error " << select_ret << " not handled:" << strerror( errno ) << endl; assert( false ); } else if( select_ret == 0 ) { return false; } if (FD_ISSET(fd, &errorfds)) { ERROR_STREAM << "Select() error event not handled!" << endl; assert( false ); } if (FD_ISSET(fd, &writefds)) { #ifndef NDEBUG DEBUG_STREAM << "Ready to write" << endl; #endif } if (FD_ISSET(fd, &readfds)) { #ifndef NDEBUG DEBUG_STREAM << "Ready to read" << endl; #endif return read(tv); } return true; } /*----- PROTECTED REGION END -----*/ // Serial2::namespace_ending } // namespace