/*----- PROTECTED REGION ID(USB2.cpp) ENABLED START -----*/ //============================================================================= // // file : USB2.cpp // // description : C++ source for the USB2 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 // USB2 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.5 $ // $Date: 2018-10-24 08:12:41 $ // // $HeadURL: $ // //============================================================================= // This file is generated by POGO // (Program Obviously used to Generate tango Object) //============================================================================= #include <USB2.h> #include <USB2Class.h> #include <csignal> /*----- PROTECTED REGION END -----*/ // USB2.cpp /** * USB2 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 USB2_ns { /*----- PROTECTED REGION ID(USB2::namespace_starting) ENABLED START -----*/ // static initializations /*----- PROTECTED REGION END -----*/ // USB2::namespace_starting //-------------------------------------------------------- /** * Method : USB2::USB2() * Description: Constructors for a Tango device * implementing the classUSB2 */ //-------------------------------------------------------- USB2::USB2(Tango::DeviceClass *cl, std::string &s) : TANGO_BASE_CLASS(cl, s.c_str()) { /*----- PROTECTED REGION ID(USB2::constructor_1) ENABLED START -----*/ init_device(); /*----- PROTECTED REGION END -----*/ // USB2::constructor_1 } //-------------------------------------------------------- USB2::USB2(Tango::DeviceClass *cl, const char *s) : TANGO_BASE_CLASS(cl, s) { /*----- PROTECTED REGION ID(USB2::constructor_2) ENABLED START -----*/ init_device(); /*----- PROTECTED REGION END -----*/ // USB2::constructor_2 } //-------------------------------------------------------- USB2::USB2(Tango::DeviceClass *cl, const char *s, const char *d) : TANGO_BASE_CLASS(cl, s, d) { /*----- PROTECTED REGION ID(USB2::constructor_3) ENABLED START -----*/ init_device(); /*----- PROTECTED REGION END -----*/ // USB2::constructor_3 } //-------------------------------------------------------- USB2::~USB2() { delete_device(); } //-------------------------------------------------------- /** * Method : USB2::delete_device() * Description: will be called at device destruction or at init command */ //-------------------------------------------------------- void USB2::delete_device() { DEBUG_STREAM << "USB2::delete_device() " << device_name << std::endl; /*----- PROTECTED REGION ID(USB2::delete_device) ENABLED START -----*/ // Delete device allocated objects close(); /*----- PROTECTED REGION END -----*/ // USB2::delete_device delete[] attr_InputLength_read; delete[] attr_OutputLength_read; delete[] attr_Reconnections_read; } //-------------------------------------------------------- /** * Method : USB2::init_device() * Description: will be called at device initialization. */ //-------------------------------------------------------- void USB2::init_device() { DEBUG_STREAM << "USB2::init_device() create device " << device_name << std::endl; /*----- PROTECTED REGION ID(USB2::init_device_before) ENABLED START -----*/ // Initialization before get_device_property() call reconnections = 0; ctx = NULL; dev_handle = NULL; init_error.clear(); conn_state = 0; /*----- PROTECTED REGION END -----*/ // USB2::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(USB2::init_device) ENABLED START -----*/ // Disabling SIGPIPE signal if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) init_error = "Fail to ignore SIGPIPE signal"; // Initialize device if (init_error.empty()) { open(); check_state(); } /*----- PROTECTED REGION END -----*/ // USB2::init_device } //-------------------------------------------------------- /** * Method : USB2::get_device_property() * Description: Read database to initialize property data members. */ //-------------------------------------------------------- void USB2::get_device_property() { /*----- PROTECTED REGION ID(USB2::get_device_property_before) ENABLED START -----*/ // Initialize property data members /*----- PROTECTED REGION END -----*/ // USB2::get_device_property_before mandatoryNotDefined = false; // Read device properties from database. Tango::DbData dev_prop; dev_prop.push_back(Tango::DbDatum("Timeout")); dev_prop.push_back(Tango::DbDatum("VendorID")); dev_prop.push_back(Tango::DbDatum("ProductID")); dev_prop.push_back(Tango::DbDatum("Interface")); dev_prop.push_back(Tango::DbDatum("EndpointUP")); dev_prop.push_back(Tango::DbDatum("EndpointDOWN")); dev_prop.push_back(Tango::DbDatum("MaxPacketSize")); // 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 USB2Class to get class property Tango::DbDatum def_prop, cl_prop; USB2Class *ds_class = (static_cast<USB2Class *>(get_device_class())); int i = -1; // 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 VendorID from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> vendorID; else { // Try to initialize VendorID from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> vendorID; } // And try to extract VendorID value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> vendorID; // Property StartDsPath is mandatory, check if has been defined in database. check_mandatory_property(cl_prop, dev_prop[i]); // Try to initialize ProductID from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> productID; else { // Try to initialize ProductID from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> productID; } // And try to extract ProductID value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> productID; // Property StartDsPath is mandatory, check if has been defined in database. check_mandatory_property(cl_prop, dev_prop[i]); // Try to initialize Interface from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> interface; else { // Try to initialize Interface from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> interface; } // And try to extract Interface value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> interface; // Property StartDsPath is mandatory, check if has been defined in database. check_mandatory_property(cl_prop, dev_prop[i]); // Try to initialize EndpointUP from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> endpointUP; else { // Try to initialize EndpointUP from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> endpointUP; } // And try to extract EndpointUP value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> endpointUP; // Property StartDsPath is mandatory, check if has been defined in database. check_mandatory_property(cl_prop, dev_prop[i]); // Try to initialize EndpointDOWN from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> endpointDOWN; else { // Try to initialize EndpointDOWN from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> endpointDOWN; } // And try to extract EndpointDOWN value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> endpointDOWN; // Property StartDsPath is mandatory, check if has been defined in database. check_mandatory_property(cl_prop, dev_prop[i]); // Try to initialize MaxPacketSize from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> maxPacketSize; else { // Try to initialize MaxPacketSize from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty()==false) def_prop >> maxPacketSize; } // And try to extract MaxPacketSize value from database if (dev_prop[i].is_empty()==false) dev_prop[i] >> maxPacketSize; // Property StartDsPath is mandatory, check if has been defined in database. check_mandatory_property(cl_prop, dev_prop[i]); } /*----- PROTECTED REGION ID(USB2::get_device_property_after) ENABLED START -----*/ // Check device property data members init vid = stoi(vendorID, NULL, 16); pid = stoi(productID, NULL, 16); ep_up = stoi(endpointUP, NULL, 16); ep_down = stoi(endpointDOWN, NULL, 16); if (timeout <= 0) timeout = 1000; DEBUG_STREAM << "Connecting to " << productID << " of the " << vendorID << " using " << interface << " with MaxPacketSize " << maxPacketSize << " on "<< endpointUP << " " << endpointDOWN << " with a timeout of " << timeout << " ms "<< endl; timeout_timeval.tv_sec = timeout / 1000; timeout_timeval.tv_usec = timeout % 1000 * 1000; /*----- PROTECTED REGION END -----*/ // USB2::get_device_property_after } //-------------------------------------------------------- /** * Method : USB2::check_mandatory_property() * Description: For mandatory properties check if defined in database. */ //-------------------------------------------------------- void USB2::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(USB2::check_mandatory_property) ENABLED START -----*/ cerr << tms.str() << " for " << device_name << endl; /*----- PROTECTED REGION END -----*/ // USB2::check_mandatory_property } } //-------------------------------------------------------- /** * Method : USB2::always_executed_hook() * Description: method always executed before any command is executed */ //-------------------------------------------------------- void USB2::always_executed_hook() { DEBUG_STREAM << "USB2::always_executed_hook() " << device_name << std::endl; if (mandatoryNotDefined) { Tango::Except::throw_exception( (const char *)"PROPERTY_NOT_SET", get_status().c_str(), (const char *)"USB2::always_executed_hook()"); } /*----- PROTECTED REGION ID(USB2::always_executed_hook) ENABLED START -----*/ // code always executed before all requests tout = timeout_timeval; if (! init_error.empty()) { set_state(Tango::FAULT); set_status(init_error); DEBUG_STREAM << init_error << endl; return; } check_state(); /*----- PROTECTED REGION END -----*/ // USB2::always_executed_hook } //-------------------------------------------------------- /** * Method : USB2::read_attr_hardware() * Description: Hardware acquisition for attributes */ //-------------------------------------------------------- void USB2::read_attr_hardware(TANGO_UNUSED(std::vector<long> &attr_list)) { DEBUG_STREAM << "USB2::read_attr_hardware(std::vector<long> &attr_list) entering... " << std::endl; /*----- PROTECTED REGION ID(USB2::read_attr_hardware) ENABLED START -----*/ // Add your own code /*----- PROTECTED REGION END -----*/ // USB2::read_attr_hardware } //-------------------------------------------------------- /** * Read attribute InputLength related method * * * Data type: Tango::DevLong * Attr type: Scalar */ //-------------------------------------------------------- void USB2::read_InputLength(Tango::Attribute &attr) { DEBUG_STREAM << "USB2::read_InputLength(Tango::Attribute &attr) entering... " << std::endl; /*----- PROTECTED REGION ID(USB2::read_InputLength) ENABLED START -----*/ // Set the attribute value Tango::AttrQuality qual; long len = input_queue_length(); if (len >= 0) { qual = Tango::ATTR_VALID; attr_InputLength_read[0] = len + data.size(); } else { qual = Tango::ATTR_INVALID; attr_InputLength_read[0] = data.size(); } attr.set_value_date_quality(attr_InputLength_read, time(NULL), qual); /*----- PROTECTED REGION END -----*/ // USB2::read_InputLength } //-------------------------------------------------------- /** * Read attribute OutputLength related method * * * Data type: Tango::DevLong * Attr type: Scalar */ //-------------------------------------------------------- void USB2::read_OutputLength(Tango::Attribute &attr) { DEBUG_STREAM << "USB2::read_OutputLength(Tango::Attribute &attr) entering... " << std::endl; /*----- PROTECTED REGION ID(USB2::read_OutputLength) ENABLED START -----*/ // Set the attribute value Tango::AttrQuality qual; long len = output_queue_length(); if (len >= 0) { qual = Tango::ATTR_VALID; attr_OutputLength_read[0] = len; } else { qual = Tango::ATTR_INVALID; attr_OutputLength_read[0] = 0; } attr.set_value_date_quality(attr_OutputLength_read, time(NULL), qual); /*----- PROTECTED REGION END -----*/ // USB2::read_OutputLength } //-------------------------------------------------------- /** * Read attribute Reconnections related method * * * Data type: Tango::DevLong * Attr type: Scalar */ //-------------------------------------------------------- void USB2::read_Reconnections(Tango::Attribute &attr) { DEBUG_STREAM << "USB2::read_Reconnections(Tango::Attribute &attr) entering... " << std::endl; /*----- PROTECTED REGION ID(USB2::read_Reconnections) ENABLED START -----*/ // Set the attribute value attr_Reconnections_read[0] = reconnections; attr.set_value(attr_Reconnections_read); /*----- PROTECTED REGION END -----*/ // USB2::read_Reconnections } //-------------------------------------------------------- /** * Method : USB2::add_dynamic_attributes() * Description: Create the dynamic attributes if any * for specified device. */ //-------------------------------------------------------- void USB2::add_dynamic_attributes() { /*----- PROTECTED REGION ID(USB2::add_dynamic_attributes) ENABLED START -----*/ // Add your own code to create and add dynamic attributes if any /*----- PROTECTED REGION END -----*/ // USB2::add_dynamic_attributes } //-------------------------------------------------------- /** * Command Write related method * * * @param argin */ //-------------------------------------------------------- void USB2::write(const Tango::DevVarCharArray *argin) { DEBUG_STREAM << "USB2::Write() - " << device_name << std::endl; /*----- PROTECTED REGION ID(USB2::write) ENABLED START -----*/ vector<unsigned char> argin_data; argin_data << *argin; size_t bytes_total = 0, bytes_to_write = argin_data.size(); if (! init_error.empty()) { sleep(tout); Tango::Except::throw_exception( "", init_error.c_str(), __PRETTY_FUNCTION__); } if (max(output_queue_length(), 0) != 0 || ! dev_handle) goto error; while (bytes_total < bytes_to_write) { int bytes_written; conn_state = libusb_bulk_transfer(dev_handle, ep_down, argin_data.data() + bytes_total, bytes_to_write - bytes_total, &bytes_written, timeout); if (conn_state == LIBUSB_ERROR_TIMEOUT) goto timeout; if ( bytes_written > 0) { bytes_total += bytes_written; } else if (bytes_written == 0) { goto error; } else { /* bytes_written < 0 */ goto error; } } timeval twait; timerclear(&twait); twait.tv_usec = 1000; while (max(output_queue_length(), 0) != 0) { if (! sleep(twait)) goto timeout; timeradd(&twait, &twait, &twait); } return; error: check_state(); sleep(tout); timeout: Tango::Except::throw_exception( "", "Timeout expired", __PRETTY_FUNCTION__); /*----- PROTECTED REGION END -----*/ // USB2::write } //-------------------------------------------------------- /** * Command Read related method * * * @param argin * @returns */ //-------------------------------------------------------- Tango::DevVarCharArray *USB2::read(Tango::DevLong argin) { Tango::DevVarCharArray *argout; DEBUG_STREAM << "USB2::Read() - " << device_name << std::endl; /*----- PROTECTED REGION ID(USB2::read) ENABLED START -----*/ if (! init_error.empty()) { sleep(tout); Tango::Except::throw_exception( "", init_error.c_str(), __PRETTY_FUNCTION__); } if (argin < 0) { sleep(tout); Tango::Except::throw_exception( "", "Out of limit", __PRETTY_FUNCTION__); } _read(argin); argout = new Tango::DevVarCharArray(); vector<unsigned char> transfer(data.begin(), data.begin() + argin); data.erase(data.begin(), data.begin() + argin); *argout << transfer; /*----- PROTECTED REGION END -----*/ // USB2::read return argout; } //-------------------------------------------------------- /** * Command ReadUntil related method * * * @param argin * @returns */ //-------------------------------------------------------- Tango::DevVarCharArray *USB2::read_until(const Tango::DevVarCharArray *argin) { Tango::DevVarCharArray *argout; DEBUG_STREAM << "USB2::ReadUntil() - " << device_name << std::endl; /*----- PROTECTED REGION ID(USB2::read_until) ENABLED START -----*/ if (! init_error.empty()) { sleep(tout); Tango::Except::throw_exception( "", init_error.c_str(), __PRETTY_FUNCTION__); } if (argin->length() != 1) { sleep(tout); Tango::Except::throw_exception( "", "Delimiter has to be exactly one byte", __PRETTY_FUNCTION__); } char delim = (*argin)[0]; size_t pos = 0, dsize; bool found = false; do { dsize = data.size(); for (; pos < dsize; ++pos) { if (memcmp(&data[pos], &delim, 1) == 0) { found = true; break; } } if (found) break; _read(dsize + 1); } while (true); argout = new Tango::DevVarCharArray(); vector<unsigned char> transfer(data.begin(), data.begin() + pos +1); data.erase(data.begin(), data.begin() + pos + 1); *argout << transfer; /*----- PROTECTED REGION END -----*/ // USB2::read_until return argout; } //-------------------------------------------------------- /** * Method : USB2::add_dynamic_commands() * Description: Create the dynamic commands if any * for specified device. */ //-------------------------------------------------------- void USB2::add_dynamic_commands() { /*----- PROTECTED REGION ID(USB2::add_dynamic_commands) ENABLED START -----*/ // Add your own code to create and add dynamic commands if any /*----- PROTECTED REGION END -----*/ // USB2::add_dynamic_commands } /*----- PROTECTED REGION ID(USB2::namespace_ending) ENABLED START -----*/ // Additional Methods bool USB2::sleep(timeval tv) { if (! timerisset(&tout)) return false; if (timercmp(&tout, &tv, <)) { ::sleep(tout.tv_sec); usleep(tout.tv_usec); timerclear(&tout); } else { // tout >= tv ::sleep(tv.tv_sec); usleep(tv.tv_usec); timersub(&tout, &tv, &tout); assert(tout.tv_sec >= 0 && tout.tv_usec >= 0); } return true; } void USB2::open() { DEBUG_STREAM << "Opening USB device..." << endl; if(libusb_init(&ctx) < 0) { ERROR_STREAM << "Failed to initialize libusb" << endl; return; } #ifndef NDEBUG libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_WARNING); #endif dev_handle = libusb_open_device_with_vid_pid(ctx, vid, pid); if(dev_handle == NULL) { libusb_exit(ctx); ERROR_STREAM << "Unable to open device" << endl; return; } int ret = libusb_claim_interface(dev_handle, interface); if(ret < 0) { libusb_release_interface(dev_handle, interface); libusb_close(dev_handle); libusb_exit(ctx); ERROR_STREAM << "Failed to claim interface" << endl; return; } } int USB2::input_queue_length() { return data.size(); } int USB2::output_queue_length() { return 0; } void USB2::close() { DEBUG_STREAM << "Closing USB device..." << endl; int output_len = max(output_queue_length(), 0); int input_len = max(input_queue_length(), 0) + data.size(); if(input_len + output_len) { WARN_STREAM << " Bytes dropped: " << input_len << " input, " << output_len << " output" << endl; } if(dev_handle) { libusb_release_interface(dev_handle, interface); libusb_close(dev_handle); libusb_exit(ctx); dev_handle = NULL; } data.clear(); } void USB2::_read(size_t bytes_to_read) { unsigned char buffer[10000]; size_t bytes_total = data.size(); int bytes_readed; if (! dev_handle) goto error; while (bytes_total < bytes_to_read) { conn_state = libusb_bulk_transfer(dev_handle, ep_up, buffer, maxPacketSize, &bytes_readed, timeout); if (conn_state == LIBUSB_ERROR_TIMEOUT) goto timeout; if (bytes_readed > 0) { data.insert(data.end(), &buffer[0], &buffer[bytes_readed]); bytes_total += bytes_readed; } else if (bytes_readed == 0) { goto error; } else { /* bytes_readed < 0 */ goto error; } } return; error: check_state(); sleep(tout); timeout: Tango::Except::throw_exception( "", "Timeout expired", __PRETTY_FUNCTION__); } void USB2::check_state() { string mesg; switch(conn_state) { case 0: /* Success */ set_state(Tango::ON); set_status("Connected"); return; case LIBUSB_ERROR_TIMEOUT: return; case LIBUSB_ERROR_PIPE: mesg = "Pipe error"; break; case LIBUSB_ERROR_OVERFLOW: mesg = "Overflow error"; break; case LIBUSB_ERROR_NO_DEVICE: mesg = "No device error"; break; case LIBUSB_ERROR_BUSY: mesg = "Busy error"; break; case LIBUSB_ERROR_INVALID_PARAM: mesg = "Invalid parameter error"; break; default: ERROR_STREAM << "USB error " << conn_state << " not handled!" << endl; assert(false); break; } set_state(Tango::INIT); set_status("Reconnecting due: " + mesg); DEBUG_STREAM << "Reconnecting due: " << mesg << endl; close(); open(); reconnections += 1; } /*----- PROTECTED REGION END -----*/ // USB2::namespace_ending } // namespace