Code Search for Developers
 
 
  

UsbMonitor.cpp from Make Controller at Krugle


Show UsbMonitor.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 "UsbMonitor.h"
#include "BoardArrivalEvent.h"

#ifdef Q_WS_WIN // Windows-only
#include <initguid.h>
DEFINE_GUID( GUID_MAKE_CTRL_KIT, 0x4D36E978, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 );
#endif

UsbMonitor::UsbMonitor( ) : QThread( )
{
	
}

void UsbMonitor::run( )
{
	while( 1 )
	{
		QList<PacketInterface*>* newBoards = new QList<PacketInterface*>;
		scan( newBoards );
		if( newBoards->count( ) > 0 )
		{
			BoardArrivalEvent* event = new BoardArrivalEvent( Board::UsbSerial );
			event->pInt = newBoards;
			application->postEvent( mainWindow, event );
		}
		else
			delete newBoards;
		sleep( 1 ); // check once a second
	}
}

UsbMonitor::Status UsbMonitor::scan( QList<PacketInterface*>* arrived )
{
	FindUsbDevices( arrived );  // fill up our list of connectedDevices, if there are any out there.
	return OK;
}

void UsbMonitor::closeAll( )
{	// app is shut down - close everything out.
	QHash<QString, PacketUsbCdc*>::iterator i  = connectedDevices.begin( );
	while( i != connectedDevices.end( ) )
	{
		i.value( )->close( );
		++i;
	}
}

void UsbMonitor::setInterfaces( MessageInterface* messageInterface, QApplication* application, McHelperWindow* mainWindow )
{
	this->messageInterface = messageInterface;
	this->application = application;
	this->mainWindow = mainWindow;
}

void UsbMonitor::FindUsbDevices( QList<PacketInterface*>* arrived )
{
  #ifdef Q_WS_MAC
	io_iterator_t serialPortIterator = 0;
	
	io_object_t modemService;
		char productName[50] = "";
    kern_return_t kernResult = KERN_FAILURE;
    // Initialize the returned path
		int maxPathSize = sizeof(portName);
    char* path = portName;
		*path = '\0';
	
	CFMutableDictionaryRef bsdMatchingDictionary;
	
	// create a dictionary that looks for all BSD modems
	bsdMatchingDictionary = IOServiceMatching( kIOSerialBSDServiceValue );
	if (bsdMatchingDictionary == NULL)
		printf("IOServiceMatching returned a NULL dictionary.\n");
	else
		CFDictionarySetValue(bsdMatchingDictionary, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDModemType));
	
	// then create the iterator with all the matching devices
	kernResult = IOServiceGetMatchingServices( kIOMasterPortDefault, bsdMatchingDictionary, &serialPortIterator );    
	if ( KERN_SUCCESS != kernResult )
	{
		printf("IOServiceGetMatchingServices returned %d\n", kernResult);
		return;
	}
	
	// Iterate through all modems found. In this example, we bail after finding the first modem.
	while( (modemService = IOIteratorNext(serialPortIterator) ) )
	{
		CFTypeRef bsdPathAsCFString;
		CFTypeRef productNameAsCFString;
		// check the name of the modem's callout device
		bsdPathAsCFString = IORegistryEntrySearchCFProperty(modemService,
																													kIOServicePlane,
																													CFSTR(kIOCalloutDeviceKey),
																													kCFAllocatorDefault,
																													0);
		// then, because the callout device could be any old thing, and because the reference to the modem returned by the
		// iterator doesn't include much device specific info, look at its parent, and check the product name
		io_registry_entry_t parent;  
		kernResult = IORegistryEntryGetParentEntry( modemService,	kIOServicePlane, &parent );																										
		productNameAsCFString = IORegistryEntrySearchCFProperty(parent,
																													kIOServicePlane,
																													CFSTR("Product Name"),
																													kCFAllocatorDefault,
																													0);
		
		if( bsdPathAsCFString )
		{
			Boolean result;      
			result = CFStringGetCString( (CFStringRef)bsdPathAsCFString,
																	path,
																	maxPathSize, 
																	kCFStringEncodingUTF8);
			
			if( productNameAsCFString )
			{
			result = CFStringGetCString( (CFStringRef)productNameAsCFString,
																	productName,
																	maxPathSize, 
																	kCFStringEncodingUTF8);
			}
			if (result)
			{
				if( (strcmp( productName, "Make Controller Ki") == 0) )
				{
					QString portNameKey( path );
					if( !connectedDevices.contains( portNameKey ) ) // make sure we don't already have this board in our list
					{
						PacketUsbCdc* device = new PacketUsbCdc( );
						device->setportName( path );
						device->setInterfaces( messageInterface, application, this );
						if( PacketInterface::OK == device->open( ) )
						{
							connectedDevices.insert( portNameKey, device );  // stick it in our own list of boards we know about
							arrived->append( device ); // then stick it on the list of new boards that's been requested
							msleep( 10 );
							device->start( );
						}
						else
							delete device;
					}
					productName[0] = 0; // clear this out for the next time around
					CFRelease(bsdPathAsCFString);
					IOObjectRelease(parent);
				}
				else
					*path = '\0';  // clear this, since this is checked above.
			}
			(void) IOObjectRelease(modemService);
		}
	}
	return;
	#endif // Mac-only FindUsbDevices( )
	
	
	#ifdef Q_WS_WIN // Windows only
	HANDLE hOut;
  HDEVINFO                 hardwareDeviceInfo;
  SP_INTERFACE_DEVICE_DATA deviceInfoData;
  ULONG                    i = 0;
  
  // Open a handle to the plug and play dev node.
  // SetupDiGetClassDevs() returns a device information set that contains info on all
  // installed devices of a specified class.
  hardwareDeviceInfo = SetupDiGetClassDevs (
                         (LPGUID)&GUID_MAKE_CTRL_KIT,
                         NULL,            // Define no enumerator (global)
                         NULL,            // Define no
                         (DIGCF_PRESENT | // Only Devices present
                         DIGCF_INTERFACEDEVICE)); // Function class devices.

  deviceInfoData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
  
  while( true ) 
  {
	  if(SetupDiEnumDeviceInterfaces (hardwareDeviceInfo,
	                                      0, // We don't care about specific PDOs
	                                      (LPGUID)&GUID_MAKE_CTRL_KIT,
	                                      i++,
	                                      &deviceInfoData))
	  {
	  	char portName[ 8 ];
	  	hOut = GetDeviceInfo( hardwareDeviceInfo, &deviceInfoData, portName );
	    if(hOut != INVALID_HANDLE_VALUE && portName != NULL ) 
	    {
	      QString portNameKey( portName );
	      if( !connectedDevices.contains( portNameKey ) ) // make sure we don't already have this board in our list
	      {
	      	PacketUsbCdc* device = new PacketUsbCdc( );
	     		device->deviceHandle = hOut;
	     		device->setportName( portName );
	     		device->setInterfaces( messageInterface, application, this );
					device->setWidget( mainWindow );
	     		if( PacketInterface::OK == device->open( ) )
	     		{
	     			connectedDevices.insert( portNameKey, device );  // stick it in our own list of boards we know about
		      	arrived->append( device ); // then stick it on the list of new boards that's been requested
		      	device->start( );
	     		}
	     		else
	     			delete device;
	      }
	    }
	  }
	  else 
	  {
	    if(ERROR_NO_MORE_ITEMS == GetLastError()) 
	       break;
	  }
  }
  // destroy the device information set and free all associated memory.
  SetupDiDestroyDeviceInfoList(hardwareDeviceInfo);
  return;
	#endif // Windows-only FindUsbDevices( )
}

#ifdef Q_WS_WIN
//-----------------------------------------------------------------
//                  Windows-only GetDevicePath( )
//-----------------------------------------------------------------
HANDLE UsbMonitor::GetDeviceInfo(HDEVINFO HardwareDeviceInfo, 
								PSP_INTERFACE_DEVICE_DATA DeviceInfoData, 
								char* portName  )
{
  PSP_INTERFACE_DEVICE_DETAIL_DATA functionClassDeviceData = NULL;
  ULONG                            predictedLength = 0;
  ULONG                            requiredLength = 0;
  
  // allocate a function class device data structure to receive the
  // goods about this particular device.
  SetupDiGetInterfaceDeviceDetail(HardwareDeviceInfo,
                                  DeviceInfoData,
                                  NULL,  // probing so no output buffer yet
                                  0,     // probing so output buffer length of zero
                                  &requiredLength,
                                  NULL); // not interested in the specific dev-node

  predictedLength = requiredLength;
  
  SP_DEVINFO_DATA deviceSpecificInfo;
  deviceSpecificInfo.cbSize = sizeof(SP_DEVINFO_DATA);

  functionClassDeviceData = (PSP_INTERFACE_DEVICE_DETAIL_DATA) malloc (predictedLength);
  functionClassDeviceData->cbSize = sizeof (SP_INTERFACE_DEVICE_DETAIL_DATA);

  // Retrieve the information from Plug and Play.
  if (! SetupDiGetInterfaceDeviceDetail(HardwareDeviceInfo,
                                        DeviceInfoData,
                                        functionClassDeviceData,
                                        predictedLength,
                                        &requiredLength,
                                        &deviceSpecificInfo))
  {
    free(functionClassDeviceData);
    return INVALID_HANDLE_VALUE;
  }
  
  if( checkFriendlyName( HardwareDeviceInfo, &deviceSpecificInfo, portName ) )
  	return functionClassDeviceData->DevicePath;
  else
	return INVALID_HANDLE_VALUE; 
}

//-----------------------------------------------------------------
//                  Windows-only checkFriendlyName( )
//-----------------------------------------------------------------
bool UsbMonitor::checkFriendlyName( HDEVINFO HardwareDeviceInfo, 
									PSP_DEVINFO_DATA deviceSpecificInfo, 
									char* portName )
{
	DWORD DataT;
    LPTSTR buffer = NULL;
    DWORD buffersize = 0;
    
    while (!SetupDiGetDeviceRegistryProperty(
               HardwareDeviceInfo,
               deviceSpecificInfo,
               SPDRP_FRIENDLYNAME,
               &DataT,
               (PBYTE)buffer,
               buffersize,
               &buffersize))
   {
       if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) // then change the buffer size.
       {
           if (buffer) LocalFree(buffer);
           // Double the size to avoid problems on W2k MBCS systems per KB 888609.
           buffer = (TCHAR*)LocalAlloc(LPTR, buffersize * 2);
       }
       else
           break;
   }  
	if (buffer)
	{	// if the friendly name is Make Controller Kit, then that's us.
		if(!_tcsncmp(TEXT("Make Controller Kit"), buffer, 19))
		{
			// zip through the buffer to find the COM port number - between parentheses
			TCHAR *ptr = buffer;
			char* namePtr = portName;
			while( *ptr++ != '(' ) {};
			while( *ptr != ')' )
				*namePtr++ = *ptr++;
			*namePtr = '\0'; // null terminate the string
			return true;
		}
			
		LocalFree(buffer);
	}
		
	return false;
}

// zip through our list of devices, and check if the HANDLE from the DEVICEREMOVED broadcast matches any of them
void UsbMonitor::removalNotification( HANDLE handle )
{  
	QHash<QString, PacketUsbCdc*>::iterator i = connectedDevices.begin( );
	while( i != connectedDevices.end( ) )
	{
		if( i.value( )->deviceHandle == handle )
		{
			i.value( )->close( );
			mainWindow->removeDeviceThreadSafe( i.key() );
			i = connectedDevices.erase( i );
		}
		else
			++i;
	}
}

#endif // Windows-only stuff

void UsbMonitor::deviceRemoved( QString key )
{
	if( connectedDevices.contains( key) )
	{
		PacketUsbCdc* usb = connectedDevices.value( key );
		connectedDevices.remove( key );
		if( usb->isOpen() )
			usb->close( );
		mainWindow->removeDeviceThreadSafe( key );
	}
}

















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