Code Search for Developers
 
 
  

UsbSerial.cpp from Make Controller at Krugle


Show UsbSerial.cpp syntax highlighted

/*********************************************************************************

 Copyright 2006 MakingThings

 Licensed under the Apache License, 
 Version 2.0 (the "License"); you may not use this file except in compliance 
 with the License. You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0 
 
 Unless required by applicable law or agreed to in writing, software distributed
 under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 CONDITIONS OF ANY KIND, either express or implied. See the License for
 the specific language governing permissions and limitations under the License.

*********************************************************************************/

#include "UsbSerial.h"
#include <QMutexLocker> 

#ifdef Q_WS_WIN
#include <dbt.h>
#endif 

UsbSerial::UsbSerial( )
{
	deviceOpen = false;
	readInProgress = false;
	#ifdef Q_WS_MAC
	kern_return_t err;
	masterPort = 0;
	if( ( err = IOMasterPort( MACH_PORT_NULL, &masterPort ) ) ) 
		printf( "could not create master port, err = %08x\n", err );
	#endif
	#ifdef Q_WS_WIN
	deviceHandle = INVALID_HANDLE_VALUE;
	#endif
}

UsbSerial::UsbStatus UsbSerial::setportName( char* filePath )
{
	char *result = NULL;
	result = strncpy( portName, filePath, strlen( filePath )+1 );
	if( result != NULL )
		return OK;
	else
		return ALLOC_ERROR;
}

UsbSerial::UsbStatus UsbSerial::usbOpen( )
{
  QMutexLocker locker( &usbOpenMutex );
  
  	if( deviceOpen )  //if it's already open, do nothing.
	  return ALREADY_OPEN;
  
  // Linux Only
  #if (defined(Q_WS_LINUX))
	  printf( "OSC over USB not implemented in Linux\n" );
    return NOT_OPEN;
  #endif

  //Mac-only
	#ifdef Q_WS_MAC
		deviceHandle = ::open( portName, O_RDWR | O_NOCTTY | O_NDELAY ); 
		if ( deviceHandle < 0 )
	    return NOT_OPEN;
	  else
		{
			usleep( 10000 );
			deviceOpen = true;
			return OK;
	  }
	#endif //Mac-only UsbSerial::open( )
	
  //-----------------------------------------------------------------
  //                  Windows-only usbOpen( )
  //-----------------------------------------------------------------
	#ifdef Q_WS_WIN
	if( deviceHandle == INVALID_HANDLE_VALUE )
		return NOT_OPEN;
	UsbStatus result = openDevice( (TCHAR*)deviceHandle );
	if( result == OK )
	{
		// messageInterface->message( 1, "Usb> Make Controller connected at %s\n", portName );
		Sleep( 10 );  // wait after opening it before trying to read/write
		deviceOpen = true;
		DoRegisterForNotification( ); // now set up to get called back when it's unplugged
		return OK;
	}
	if( result == ALREADY_OPEN )
		return result;

	return NOT_OPEN;
	#endif //Windows-only UsbSerial::open( )
}

void UsbSerial::usbClose( )
{
  if( deviceOpen )
	{
    // Linux Only
    #if (defined(Q_WS_LINUX))
    #endif
  	  //Mac-only
		#ifdef Q_WS_MAC
		::close( deviceHandle );
		deviceHandle = -1;
		deviceOpen = false;
		#endif
	  //-----------------------------------------------------------------
  	  //                  Windows-only usbClose( )
  	  //-----------------------------------------------------------------
	  #ifdef Q_WS_WIN
	  CloseHandle( deviceHandle );
	  deviceHandle = INVALID_HANDLE_VALUE;
	  deviceOpen = false;
	  UnregisterDeviceNotification( notificationHandle );
		#endif //Windows-only UsbSerial::close( )
		//messageInterface->messageThreadSafe( "Usb> Make Controller disconnected." );
	}
}

int UsbSerial::usbRead( char* buffer, int length )
{
  // make sure we're open
  if( !deviceOpen )
  {
    UsbStatus portIsOpen = usbOpen( );
    if( portIsOpen != OK )
		{
			usbClose( );
			return NOT_OPEN;
		}
  }
  
  // Linux Only
  #if (defined(Q_WS_LINUX))
  // make sure we're open
  //if( !deviceOpen )
    return NOT_OPEN;
  #endif

  //Mac-only
	#ifdef Q_WS_MAC
	int count;
		
	count = ::read( deviceHandle, buffer, length );
	if( count > 1 )
		return count;
	else
	{
		switch ( count )
		{
			case 0:
			return ERROR_CLOSE; // EOF; possibly file was closed
				break;

			case -1:
				if ( errno == EAGAIN )
					return NOTHING_AVAILABLE;
				else
					return IO_ERROR;
				break;
		}
	}
	return 0; // should never get here
	#endif //Mac-only UsbSerial::read( )
	
  //Windows-only///////////////////////////////////////////////////////////////////////
  #ifdef Q_WS_WIN
  DWORD count;
  int retval = -1;
  DWORD numTransferred;
    
  retval = OK;  
  readInProgress = false;
  overlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

  // reset the read overlapped structure
  overlappedRead.Offset = overlappedRead.OffsetHigh = 0;
  
  if ( !ReadFile( deviceHandle, buffer, length, &count, &overlappedRead ) )
  {
  	DWORD lastError = GetLastError();
		// messageInterface->message( 1, "USB Read Error: %d \n", lastError );
	  if ( lastError != ERROR_IO_PENDING)     // read not delayed?
	  {
	    usbClose( );
	    //messageInterface->message( 1, "Closed trying to read the file\n" );
	    retval = -1; //UNKNOWN_ERROR;
	  }
	  else
	    readInProgress = true;
  }
  else          	
  	retval = count;


  if( readInProgress )
  {
  	DWORD r;
	  do
	  {
	    r = WaitForSingleObject( overlappedRead.hEvent, 1000 );	 
	  } while ( r == WAIT_TIMEOUT );
	  switch( r )
		{
		  case WAIT_FAILED:
		    usbClose( );
		    retval = -1; //UNKNOWN_ERROR;
	      break;
		  case WAIT_TIMEOUT:
		    retval = -1; // NOTHING_AVAILABLE;
		    break;
		  case WAIT_OBJECT_0:
	  		// check to see if the pending operation completed
        	if( !GetOverlappedResult( deviceHandle, &overlappedRead, &numTransferred, FALSE )  ) // don't wait
			{
		      usbClose( );
		      SetEvent( overlappedRead.hEvent );
		      retval = -1; //IO_ERROR;
		      break;
			}
  			retval = numTransferred;
			  break; 
		  case WAIT_ABANDONED:
		  default:
		    usbClose( );
		    retval = -1; //IO_ERROR;
			  break;
		} // end of switch
  }
  
  CloseHandle( overlappedRead.hEvent );
  return retval;
  	
  #endif //Windows-only UsbSerial::read( )//////////////////////////////////////////////////////////////
}

UsbSerial::UsbStatus UsbSerial::usbWrite( char* buffer, int length )
{
  if( !deviceOpen )
  {
    UsbStatus portIsOpen = usbOpen( );
    if( portIsOpen != OK )
		{
				usbClose( );
			return NOT_OPEN;
		}
  }
  
  // Linux Only
  #if (defined(Q_WS_LINUX))
    return NOT_OPEN;
  #endif

  //Mac-only
	#ifdef Q_WS_MAC
 
	int size = ::write( deviceHandle, buffer, length );
	if ( length == size )
    return OK;
	else if( errno == EAGAIN )
	  return NOTHING_AVAILABLE;
  else
    return IO_ERROR;
	
	#endif //Mac-only UsbSerial::write( )

  //Windows-only
  #ifdef Q_WS_WIN
  DWORD cout, ret, numWritten;
  bool success;
  UsbSerial::UsbStatus retval = OK;
  
  overlappedWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  
	// reset the write overlapped structure
  overlappedWrite.Offset = overlappedWrite.OffsetHigh = 0;
  
  success = WriteFile( deviceHandle, buffer, length, &cout, &overlappedWrite );
  if( !success )
  {
  	if ( GetLastError() == ERROR_IO_PENDING)
	  {
	  	int waitCount = 0;
		  do
		  {
	  		if( waitCount++ > 5 )
	  			break;
		  	ret = WaitForSingleObject( overlappedWrite.hEvent, 100 );
		  }  while ( ret == WAIT_TIMEOUT );
	
	    if ( ret == WAIT_OBJECT_0 )
	    {			
				//do
				//{
					GetOverlappedResult( deviceHandle, &overlappedWrite, &numWritten, TRUE);
					//read = numWritten;
				//} while( read != length );
				if( numWritten == (DWORD)length )
					retval = OK;
				else
				  retval = IO_ERROR;
	    }
	    else
	      retval = IO_ERROR;
	  }
	  else
	  {
	    //usbClose( );
	    retval = IO_ERROR;
	  }
  }
  
  CloseHandle( overlappedWrite.hEvent );
  return retval;
  
  #endif //Windows-only UsbSerial::write( )
}

int UsbSerial::numberOfAvailableBytes( )
{
    int n;
		
		#ifdef Q_WS_MAC
		if( ::ioctl( deviceHandle, FIONREAD, &n ) < 0 )
			return IO_ERROR;
		#endif // Mac-only numberOfAvailableBytes( )
		
		#ifdef Q_WS_WIN
		COMSTAT status;
    unsigned long state;

    if (deviceHandle != INVALID_HANDLE_VALUE)
    {
        bool success = false;
        success = ClearCommError( deviceHandle, &state, &status);
        n = status.cbInQue;
    }
		#endif // Windows-only numberOfAvailableBytes( )
    return(n);
}

// do the real opening of the device
//Windows-only
#ifdef Q_WS_WIN
UsbSerial::UsbStatus UsbSerial::openDevice( TCHAR* deviceName )
{
  DCB dcb;
  COMMTIMEOUTS timeouts;

  // if it's already open, do nothing
  if( deviceOpen )
    return ALREADY_OPEN;

  // Open the port
  deviceHandle = CreateFile( deviceName, 
			GENERIC_READ | GENERIC_WRITE, 
			0, 
			0, 
			OPEN_EXISTING, 
			FILE_FLAG_OVERLAPPED, 
			0 );
  
  if ( deviceHandle == INVALID_HANDLE_VALUE )
    return ERROR_CLOSE; 

  // initialize the overlapped structures
  overlappedRead.Offset  = overlappedWrite.Offset = 0; 
  overlappedRead.OffsetHigh = overlappedWrite.OffsetHigh = 0; 
  overlappedRead.hEvent  = CreateEvent(0, TRUE, FALSE, 0);
  overlappedWrite.hEvent  = CreateEvent(0, TRUE, FALSE, 0);

  if (!overlappedRead.hEvent || !overlappedWrite.hEvent )
  {
  	deviceHandle = INVALID_HANDLE_VALUE;
    return ERROR_CLOSE;
  }

  GetCommState( deviceHandle, &dcb );
  dcb.BaudRate = CBR_115200;
  dcb.ByteSize = 8;
  dcb.Parity = NOPARITY;
  dcb.StopBits = ONESTOPBIT;
  dcb.fOutxCtsFlow = TRUE;
  dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
  dcb.fAbortOnError = TRUE;
  dcb.fDtrControl = DTR_CONTROL_ENABLE; // magic testing...
  if( !SetCommState( deviceHandle, &dcb ) )
  {
  	deviceHandle = INVALID_HANDLE_VALUE;
		return ERROR_CLOSE;
  }

/*
  From MSDN:
  If an application sets ReadIntervalTimeout and ReadTotalTimeoutMultiplier to MAXDWORD and sets 
  ReadTotalTimeoutConstant to a value greater than zero and less than MAXDWORD, one of the following 
  occurs when the ReadFile function is called:

  * If there are any bytes in the input buffer, ReadFile returns immediately with the bytes in the buffer.
  * If there are no bytes in the input buffer, ReadFile waits until a byte arrives and then returns immediately.
  * If no bytes arrive within the time specified by ReadTotalTimeoutConstant, ReadFile times out.
*/
  timeouts.ReadIntervalTimeout = MAXDWORD;
  timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
  timeouts.ReadTotalTimeoutConstant = 500;
  timeouts.WriteTotalTimeoutMultiplier = 0;
  timeouts.WriteTotalTimeoutConstant = 0;   
  if( ! SetCommTimeouts( deviceHandle, &timeouts ) )
  {
  	deviceHandle = INVALID_HANDLE_VALUE;
  	return ERROR_CLOSE;
  }

  EscapeCommFunction( deviceHandle, SETDTR );

  return OK;
}
#endif //Windows-only UsbSerial::openDevice( )


//Windows-only
#ifdef Q_WS_WIN
 // make sure to do this only once the device has been opened,
 // since it relies on the deviceHandle to register for the call.
bool UsbSerial::DoRegisterForNotification( )
{
	DEV_BROADCAST_HANDLE NotificationFilter;
	
	ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) );
	NotificationFilter.dbch_size = sizeof( DEV_BROADCAST_HANDLE );
	NotificationFilter.dbch_devicetype = DBT_DEVTYP_HANDLE;
	NotificationFilter.dbch_handle = deviceHandle;  // class variable
	HWND winId = mainWindow->winId( );

    notificationHandle = RegisterDeviceNotification( winId, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE );

    if(!notificationHandle) 
    {
        qDebug( "RegisterDeviceNotification failed: %ld\n", GetLastError());
        return false;
    }
    qDebug( "RegisterDeviceNotification success\n" );
    return true;
}

#endif 







See more files for this project here

Make Controller

The Make Controller is an open microcontroller platform for Makers of all kinds, by MakingThings. This project maintains the official firmware for the board and source for the software tools used with the board.

Project homepage: http://sourceforge.net/projects/makingthings
Programming language(s): C,C#,C++
License: other

  layouts/
    mchelper.ui
    mchelperPrefs.ui
  linux_driver/
    Makefile
    at91.c
    at91.mod.c
  Board.cpp
  Board.h
  BoardArrivalEvent.h
  IconPackageOSX.icns
  McHelperWindow.cpp
  McHelperWindow.h
  MessageEvent.cpp
  MessageEvent.h
  MessageInterface.h
  MonitorInterface.h
  NetworkMonitor.cpp
  NetworkMonitor.h
  Osc.cpp
  Osc.h
  OscXmlServer.cpp
  OscXmlServer.h
  OutputWindow.cpp
  OutputWindow.h
  PacketInterface.h
  PacketReadyInterface.h
  PacketUdp.cpp
  PacketUdp.h
  PacketUsbCdc.cpp
  PacketUsbCdc.h
  ReadMe.rtf
  Samba.cpp
  Samba.h
  SambaMonitor.cpp
  SambaMonitor.h
  UploaderThread.cpp
  UploaderThread.h
  UsbMonitor.cpp
  UsbMonitor.h
  UsbSerial.cpp
  UsbSerial.h
  guid829.h
  loader256_data.h
  main.cpp
  mchelper.pro
  mchelper.qrc
  mchelper.rc
  mchelper_icon.ico
  mticon128.png