Skip to content
Snippets Groups Projects
Commit bbf88d71 authored by Alessio Igor Bogani's avatar Alessio Igor Bogani
Browse files

Improve a lot the code

parent c8fcde83
No related branches found
No related tags found
No related merge requests found
NAME_SRV = usb2-srv
CXXFLAGS =
LDFLAGS = -lusb-1.0
CXXFLAGS +=
LDFLAGS += -lusb-1.0
include ../makefiles/Make-9.3.3.in
......@@ -42,6 +42,8 @@
#include <USB2.h>
#include <USB2Class.h>
#include <csignal>
/*----- PROTECTED REGION END -----*/ // USB2.cpp
/**
......@@ -87,7 +89,6 @@ USB2::USB2(Tango::DeviceClass *cl, std::string &s)
: TANGO_BASE_CLASS(cl, s.c_str())
{
/*----- PROTECTED REGION ID(USB2::constructor_1) ENABLED START -----*/
reconnections = -1;
init_device();
/*----- PROTECTED REGION END -----*/ // USB2::constructor_1
......@@ -97,7 +98,6 @@ USB2::USB2(Tango::DeviceClass *cl, const char *s)
: TANGO_BASE_CLASS(cl, s)
{
/*----- PROTECTED REGION ID(USB2::constructor_2) ENABLED START -----*/
reconnections = -1;
init_device();
/*----- PROTECTED REGION END -----*/ // USB2::constructor_2
......@@ -107,7 +107,6 @@ 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 -----*/
reconnections = -1;
init_device();
/*----- PROTECTED REGION END -----*/ // USB2::constructor_3
......@@ -129,8 +128,8 @@ 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();
delete[] buffer;
/*----- PROTECTED REGION END -----*/ // USB2::delete_device
delete[] attr_InputLength_read;
......@@ -150,11 +149,11 @@ void USB2::init_device()
/*----- PROTECTED REGION ID(USB2::init_device_before) ENABLED START -----*/
// Initialization before get_device_property() call
reconnections = 0;
ctx = NULL;
dev_handle = NULL;
buffer = NULL;
init_error.clear();
conn_state = 0;
/*----- PROTECTED REGION END -----*/ // USB2::init_device_before
......@@ -170,21 +169,16 @@ void USB2::init_device()
/*----- PROTECTED REGION ID(USB2::init_device) ENABLED START -----*/
// Initialize device
try
{
buffer = new unsigned char[maxPacketSize];
// Disabling SIGPIPE signal
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
init_error = "Fail to ignore SIGPIPE signal";
// Initialize device
if (init_error.empty()) {
resolve();
open();
check_state(true);
}
catch (Tango::DevFailed &e)
{
init_error = "Initialization failed: " + string(e.errors[0].desc);
}
catch (...)
{
init_error = "Initialization failed: Unknown error";
}
/*----- PROTECTED REGION END -----*/ // USB2::init_device
}
......@@ -329,6 +323,17 @@ void USB2::get_device_property()
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
}
//--------------------------------------------------------
......@@ -377,29 +382,14 @@ void USB2::always_executed_hook()
/*----- PROTECTED REGION ID(USB2::always_executed_hook) ENABLED START -----*/
// code always executed before all requests
if (! init_error.empty())
{
set_state(Tango::FAULT);
set_status(init_error);
return;
}
if (! timeout) {
set_state(Tango::FAULT);
set_status("Invalid timeout");
return;
}
tout = timeout_timeval;
try {
if (! dev_handle) {
open();
}
} catch(Tango::DevFailed &e) {
set_state(Tango::FAULT);
set_status(string(e.errors[0].desc));
} catch(...) {
if (! init_error.empty()) {
set_state(Tango::FAULT);
set_status("The device is in FAULT state for unknown reason");
set_status(init_error);
DEBUG_STREAM << init_error << endl;
} else {
check_state(true);
}
/*----- PROTECTED REGION END -----*/ // USB2::always_executed_hook
......@@ -435,9 +425,16 @@ 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
attr_InputLength_read[0] = input_queue_length();
attr.set_value(attr_InputLength_read);
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
}
//--------------------------------------------------------
......@@ -454,9 +451,16 @@ 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
attr_OutputLength_read[0] = output_queue_length();
attr.set_value(attr_OutputLength_read);
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
}
//--------------------------------------------------------
......@@ -507,44 +511,64 @@ void USB2::write(const Tango::DevVarCharArray *argin)
{
DEBUG_STREAM << "USB2::Write() - " << device_name << std::endl;
/*----- PROTECTED REGION ID(USB2::write) ENABLED START -----*/
check_init();
vector<unsigned char> argin_data;
argin_data << *argin;
size_t bytes_total = 0, bytes_to_write = argin_data.size();
unsigned char *argin_data = new unsigned char[argin->length()];
for(unsigned int i=0; i<argin->length(); ++i)
{
argin_data[i] = (*argin)[i];
if (! init_error.empty()) {
sleep(tout);
Tango::Except::throw_exception(
"", init_error.c_str(), __PRETTY_FUNCTION__);
}
int bytes_total = 0, bytes_to_write = argin->length();
while(bytes_total != bytes_to_write) {
int bytes_written;
int ret = libusb_bulk_transfer(dev_handle,
ep_down, argin_data + bytes_total,
bytes_to_write - bytes_total, &bytes_written, timeout);
if(ret != 0 || bytes_written != bytes_to_write - bytes_total) {
delete argin_data;
close();
open();
string error_mesg = "Unable to send request to device";
DEBUG_STREAM << error_mesg << endl;
set_state( Tango::FAULT );
set_status( error_mesg );
// TODO have we to wait? timeout is decreased?
if (max(output_queue_length(), 0) != 0) {
close();
resolve();
open();
reconnections += 1;
goto error;
}
Tango::Except::throw_exception( "",
error_mesg,
"USB2::write()");
while (bytes_total < bytes_to_write) {
int s = select(WRITE);
if (s == 0)
goto timeout;
else if (s < 0)
goto error;
else { /* s > 0 */ }
ssize_t bytes_written = _write(
argin_data.data() + bytes_total,
bytes_to_write - bytes_total);
if ( bytes_written > 0) {
bytes_total += bytes_written;
} else if (bytes_written == 0) {
if (multiplexing == SELECT)
goto error;
/* Continue if multiplexing == SLEEP */
} else { /* bytes_written < 0 */
goto error;
}
bytes_total += bytes_written;
}
delete argin_data;
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(false);
sleep(tout);
timeout:
Tango::Except::throw_exception(
"", "Timeout expired", __PRETTY_FUNCTION__);
/*----- PROTECTED REGION END -----*/ // USB2::write
}
//--------------------------------------------------------
......@@ -561,41 +585,24 @@ 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 -----*/
check_init();
if (argin < 0)
{
Tango::Except::throw_exception("",
"Input has to be in positive range",
"USB2::read()");
if (! init_error.empty()) {
sleep(tout);
Tango::Except::throw_exception(
"", init_error.c_str(), __PRETTY_FUNCTION__);
}
while( (size_t)argin > data.size() )
{
int bytes_readed;
int ret = libusb_bulk_transfer(dev_handle, ep_up, buffer,
maxPacketSize, &bytes_readed, timeout);
if(ret != 0 || bytes_readed == 0) {
string error_mesg( "No response from device" );
DEBUG_STREAM << error_mesg << endl;
Tango::Except::throw_exception("",
error_mesg, "USB2::read()");
}
for(int i=0;i<bytes_readed;++i) {
data.push_back(buffer[i]);
}
if (argin < 0) {
sleep(tout);
Tango::Except::throw_exception(
"", "Out of limit", __PRETTY_FUNCTION__);
}
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 );
_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;
}
......@@ -613,56 +620,39 @@ 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 -----*/
check_init();
if (argin->length() != 1)
{
Tango::Except::throw_exception("",
"Delimiter has to be one byte length",
"USB2::read_until()");
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;
size_t pos;
while( ! found )
{
for( pos = 0; pos < data.size(); ++pos )
{
if (memcmp(&data[pos], &delim, 1) == 0)
{
do {
dsize = data.size();
for (; pos < dsize; ++pos) {
if (memcmp(&data[pos], &delim, 1) == 0) {
found = true;
break;
}
}
if ( ! found )
{
int bytes_readed;
int ret = libusb_bulk_transfer(dev_handle, ep_up, buffer,
maxPacketSize, &bytes_readed, timeout);
if(ret != 0 || bytes_readed == 0) {
string error_mesg( "No response from device" );
DEBUG_STREAM << error_mesg << endl;
Tango::Except::throw_exception("",
error_mesg, "USB2::read_until()");
}
for(int i=0;i<bytes_readed;++i) {
data.push_back(buffer[i]);
}
}
}
if (found)
break;
_read(dsize + 1);
} while (true);
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 );
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;
}
......@@ -685,15 +675,22 @@ void USB2::add_dynamic_commands()
/*----- PROTECTED REGION ID(USB2::namespace_ending) ENABLED START -----*/
// Additional Methods
void USB2::check_init()
bool USB2::sleep(timeval tv)
{
if (! init_error.empty() )
{
DEBUG_STREAM << init_error << endl;
Tango::Except::throw_exception( "",
init_error.c_str(),
"USB2::check_init()");
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()
......@@ -701,58 +698,51 @@ void USB2::open()
DEBUG_STREAM << "Opening USB device..." << endl;
if(libusb_init(&ctx) < 0) {
string error_mesg = "Failed to initialize libusb";
ERROR_STREAM << error_mesg << endl;
assert( false);
Tango::Except::throw_exception( "",
error_mesg,
"USB2::open()");
ERROR_STREAM << "Failed to initialize libusb" << endl;
return;
}
#ifndef NDEBUG
libusb_set_debug(ctx, LIBUSB_LOG_LEVEL_WARNING);
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);
string error_mesg = "Unable to open device";
ERROR_STREAM << error_mesg << endl;
assert( false);
Tango::Except::throw_exception( "",
error_mesg,
"USB2::open()");
ERROR_STREAM << "Unable to open device" << endl;
return;
}
if(libusb_claim_interface(dev_handle, interface) < 0) {
int ret = libusb_claim_interface(dev_handle, interface);
if(ret < 0) {
libusb_release_interface(dev_handle, interface);
libusb_close(dev_handle);
libusb_exit(ctx);
string error_mesg = "Failed to claim interface";
ERROR_STREAM << error_mesg << endl;
assert( false);
Tango::Except::throw_exception( "",
error_mesg,
"USB2::open()");
ERROR_STREAM << "Failed to claim interface" << endl;
return;
}
DEBUG_STREAM << "USB device opened." << endl;
reconnections++;
set_state(Tango::ON);
set_status("The device in ON state");
}
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 input_len = input_queue_length();
int output_len = output_queue_length();
int output_len = max(output_queue_length(), 0);
int input_len = max(input_queue_length(), 0) + data.size();
if( input_len + output_len)
if(input_len + output_len)
{
WARN_STREAM << " Bytes dropped: " << input_len << " input, "
<< output_len << " output" << endl;
......@@ -768,19 +758,104 @@ void USB2::close()
}
data.clear();
}
DEBUG_STREAM << "USB device closed" << endl;
ssize_t USB2::_write(unsigned char *buf, size_t count)
{
int bytes_written;
conn_state = libusb_bulk_transfer(dev_handle,
ep_down, buf, count, &bytes_written, timeout);
return bytes_written;
}
int USB2::input_queue_length()
void USB2::_read(size_t bytes_to_read)
{
return data.size();
unsigned char buffer[10000];
size_t bytes_total = data.size();
int bytes_readed;
while (bytes_total < bytes_to_read) {
int s = select(READ);
if (s == 0)
goto timeout;
else if (s < 0)
goto error;
else { /* s > 0 */ }
conn_state = libusb_bulk_transfer(dev_handle, ep_up, buffer,
maxPacketSize, &bytes_readed, 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(true);
sleep(tout);
timeout:
Tango::Except::throw_exception(
"", "Timeout expired", __PRETTY_FUNCTION__);
}
int USB2::output_queue_length()
void USB2::check_state(bool forcing)
{
return 0;
string mesg;
(void)forcing;
switch(conn_state)
{
case 0: /* Success */
set_state(Tango::ON);
set_status("Connected");
return;
case LIBUSB_ERROR_TIMEOUT:
mesg = "Timeout error";
break;
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();
resolve();
open();
reconnections += 1;
}
int USB2::select(event_type et)
{
return 1;
}
void USB2::resolve() {}
/*----- PROTECTED REGION END -----*/ // USB2::namespace_ending
} // namespace
......@@ -76,14 +76,19 @@ class USB2 : public TANGO_BASE_CLASS
string init_error;
libusb_context *ctx;
int vid, pid, ep_up, ep_down;
int vid, pid, ep_up, ep_down; // FIXME
libusb_device_handle *dev_handle;
int conn_state;
enum event_type {READ, WRITE};
unsigned char *buffer;
vector<unsigned char> data;
long long reconnections;
int reconnections;
enum {SLEEP, SELECT} multiplexing;
timeval timeout_timeval, tout;
/*----- PROTECTED REGION END -----*/ // USB2::Data Members
// Device property data members
......@@ -256,14 +261,16 @@ public:
/*----- PROTECTED REGION ID(USB2::Additional Method prototypes) ENABLED START -----*/
// Additional Method prototypes
void check_init();
bool sleep(timeval);
void open();
void close();
int input_queue_length();
int output_queue_length();
void close();
ssize_t _write(unsigned char*, size_t);
void _read(size_t);
void check_state(bool);
int select(event_type);
void resolve();
/*----- PROTECTED REGION END -----*/ // USB2::Additional Method prototypes
};
......
......@@ -39,11 +39,13 @@
/*----- PROTECTED REGION END -----*/ // USB2::USB2StateMachine.cpp
//================================================================
// States | Description
// States | Description
//================================================================
// ON | Connected
// FAULT | Connection failed
// INIT |
// ALARM |
// FAULT | Connection failed
// INIT |
// ON | Connected
// UNKNOWN |
namespace USB2_ns
......@@ -113,14 +115,10 @@ bool USB2::is_Reconnections_allowed(TANGO_UNUSED(Tango::AttReqType type))
//--------------------------------------------------------
bool USB2::is_Write_allowed(TANGO_UNUSED(const CORBA::Any &any))
{
// Compare device state with not allowed states.
if (get_state()==Tango::INIT)
{
// Not any excluded states for Write command.
/*----- PROTECTED REGION ID(USB2::WriteStateAllowed) ENABLED START -----*/
/*----- PROTECTED REGION END -----*/ // USB2::WriteStateAllowed
return false;
}
return true;
}
......@@ -132,14 +130,10 @@ bool USB2::is_Write_allowed(TANGO_UNUSED(const CORBA::Any &any))
//--------------------------------------------------------
bool USB2::is_Read_allowed(TANGO_UNUSED(const CORBA::Any &any))
{
// Compare device state with not allowed states.
if (get_state()==Tango::INIT)
{
// Not any excluded states for Read command.
/*----- PROTECTED REGION ID(USB2::ReadStateAllowed) ENABLED START -----*/
/*----- PROTECTED REGION END -----*/ // USB2::ReadStateAllowed
return false;
}
return true;
}
......@@ -151,14 +145,10 @@ bool USB2::is_Read_allowed(TANGO_UNUSED(const CORBA::Any &any))
//--------------------------------------------------------
bool USB2::is_ReadUntil_allowed(TANGO_UNUSED(const CORBA::Any &any))
{
// Compare device state with not allowed states.
if (get_state()==Tango::INIT)
{
// Not any excluded states for ReadUntil command.
/*----- PROTECTED REGION ID(USB2::ReadUntilStateAllowed) ENABLED START -----*/
/*----- PROTECTED REGION END -----*/ // USB2::ReadUntilStateAllowed
return false;
}
return true;
}
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment