home *** CD-ROM | disk | FTP | other *** search
Text File | 2005-11-16 | 29.9 KB | 1,080 lines |
- /*
- macam - webcam app and QuickTime driver component
- Copyright (C) 2002 Matthias Krauss (macam@matthias-krauss.de)
-
- This program 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 2 of the License, or
- (at your option) any later version.
-
- This program 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 this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- $Id: MyCameraDriver.m,v 1.14 2005/10/18 17:50:24 hxr Exp $
- */
-
- #import "MyCameraDriver.h"
- #import "MyCameraCentral.h"
- #import "Resolvers.h"
- #import "MiniGraphicsTools.h"
- #import "MiscTools.h"
- #include <unistd.h> //usleep
-
- @implementation MyCameraDriver
-
- + (unsigned short) cameraUsbProductID {
- NSAssert(0,@"You must override cameraUsbProductID or cameraUsbDescriptions");
- return 0;
- }
-
- + (unsigned short) cameraUsbVendorID {
- NSAssert(0,@"You must override cameraUsbVendorID or cameraUsbDescriptions");
- return 0;
- }
-
- + (NSString*) cameraName {
- NSAssert(0,@"You must override cameraName or cameraUsbDescriptions");
- return @"";
- }
-
- + (NSArray*) cameraUsbDescriptions {
- NSDictionary* dict=[NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithUnsignedShort:[self cameraUsbProductID]],@"idProduct",
- [NSNumber numberWithUnsignedShort:[self cameraUsbVendorID]],@"idVendor",
- [self cameraName],@"name",NULL];
- return [NSArray arrayWithObject:dict];
- }
-
- - (id) initWithCentral:(id)c {
- //init superclass
- self=[super init];
- if (self==NULL) return NULL;
- //setup simple defaults
- central=c;
- dev=NULL;
- intf=NULL;
- brightness=0.0f;
- contrast=0.0f;
- saturation=0.0f;
- gamma=0.0f;
- shutter=0.0f;
- gain=0.0f;
- autoGain=NO;
- hFlip=NO;
- compression=0;
- whiteBalanceMode=WhiteBalanceLinear;
- blackWhiteMode = FALSE;
- isStarted=NO;
- isGrabbing=NO;
- shouldBeGrabbing=NO;
- isShuttingDown=NO;
- isShutDown=NO;
- isUSBOK=YES;
- lastImageBuffer=NULL;
- lastImageBufferBPP=0;
- lastImageBufferRowBytes=0;
- nextImageBuffer=NULL;
- nextImageBufferBPP=0;
- nextImageBufferRowBytes=0;
- nextImageBufferSet=NO;
- imageBufferLock=[[NSLock alloc] init];
- //allocate lock
- if (imageBufferLock==NULL) {
- #ifdef VERBOSE
- NSLog(@"MyCameraDriver:init: cannot instantiate imageBufferLock");
- #endif
- return NULL;
- }
- stateLock=[[NSLock alloc] init];
- //allocate lock
- if (stateLock==NULL) {
- #ifdef VERBOSE
- NSLog(@"MyCameraDriver:init: cannot instantiate stateLock");
- #endif
- [imageBufferLock release];
- return NULL;
- }
- doNotificationsOnMainThread=[central doNotificationsOnMainThread];
- mainThreadRunLoop=[NSRunLoop currentRunLoop];
- mainThreadConnection=NULL;
- decodingThreadConnection=NULL;
- return self;
- }
-
- - (CameraError) startupWithUsbLocationId:(UInt32)usbLocationId {
- CameraResolution r;
- short fr;
- WhiteBalanceMode wb;
- r=[self defaultResolutionAndRate:&fr];
- wb=[self defaultWhiteBalanceMode];
- [self setResolution:r fps:fr];
- [self setWhiteBalanceMode:wb];
- isStarted=YES;
- return CameraErrorOK;
- }
-
- - (void) shutdown {
- BOOL needsShutdown;
- [stateLock lock];
- isShuttingDown=YES;
- shouldBeGrabbing=NO;
- needsShutdown=!isShutDown;
- [stateLock unlock];
- [imageBufferLock lock]; //Make sure no external image buffer is used after this method returns
- nextImageBufferSet=NO;
- nextImageBuffer=NULL;
- [imageBufferLock unlock];
- if (!needsShutdown) return;
- if (![self stopGrabbing]) { //We can handle it here - if not, do it on the end of the decodingThread
- [self usbCloseConnection];
- [stateLock lock];
- isShutDown=YES;
- [stateLock unlock];
- [self mergeCameraHasShutDown];
- }
- }
-
- - (void) dealloc {
- if (imageBufferLock!=NULL) [imageBufferLock release]; imageBufferLock=NULL;
- [super dealloc];
- }
-
- - (id) delegate {
- return delegate;
- }
-
- - (void) setDelegate:(id)d {
- delegate=d;
- }
-
- - (void) enableNotifyOnMainThread {
- doNotificationsOnMainThread=YES;
- }
-
- - (void) setCentral:(id)c {
- central=c;
- }
-
- - (id) central {
- return central;
- }
-
- - (BOOL) realCamera { //Returns if the camera is a real image grabber or a dummy
- return YES; //By default, subclasses are real cams. Dummys should override this
- }
-
- - (BOOL) hasSpecificName { // Returns is the camera has a more specific name (derived from USB connection perhaps)
- return NO;
- }
-
- - (NSString *) getSpecificName {
- return @"Error!: Name has not been specified";
- }
-
- //Image / camera properties get/set
- - (BOOL) canSetBrightness {
- return NO;
- }
-
- - (float) brightness {
- return brightness;
- }
-
- - (void) setBrightness:(float)v {
- brightness=v;
- }
-
- - (BOOL) canSetContrast {
- return NO;
- }
-
- - (float) contrast {
- return contrast;
- }
-
- - (void) setContrast:(float)v {
- contrast=v;
- }
-
- - (BOOL) canSetSaturation {
- return NO;
- }
-
- - (float) saturation {
- return saturation;
- }
-
- - (void) setSaturation:(float)v {
- saturation=v;
- }
-
- - (BOOL) canSetGamma {
- return NO;
- }
-
- - (float) gamma {
- return gamma;
- }
-
- - (void) setGamma:(float)v {
- gamma=v;
- }
-
- - (BOOL) canSetSharpness {
- return NO;
- }
-
- - (float) sharpness {
- return sharpness;
- }
-
- - (void) setSharpness:(float)v {
- sharpness=v;
- }
-
- - (BOOL) canSetGain {
- return NO;
- }
-
- - (float) gain {
- return gain;
- }
-
- - (void) setGain:(float)v {
- gain=v;
- }
-
- - (BOOL) canSetShutter {
- return NO;
- }
-
- - (float) shutter {
- return shutter;
- }
-
- - (void) setShutter:(float)v {
- shutter=v;
- }
-
- - (BOOL) canSetAutoGain { //Gain and shutter combined (so far - let's see what other cams can do...)
- return NO;
- }
-
- - (BOOL) isAutoGain {
- return autoGain;
- }
-
- - (void) setAutoGain:(BOOL)v{
- autoGain=v;
- }
-
- - (BOOL) canSetHFlip {
- return NO;
- }
-
- - (BOOL) hFlip {
- return hFlip;
- }
-
- - (void) setHFlip:(BOOL)v {
- hFlip=v;
- }
-
- - (short) maxCompression {
- return 0;
- }
-
- - (short) compression {
- return compression;
- }
-
- - (void) setCompression:(short)v {
- [stateLock lock];
- if (!isGrabbing) compression=CLAMP(v,0,[self maxCompression]);
- [stateLock unlock];
- }
-
- - (BOOL) canSetWhiteBalanceMode {
- return NO;
- }
-
- - (BOOL) canSetWhiteBalanceModeTo:(WhiteBalanceMode)newMode {
- return (newMode==[self defaultWhiteBalanceMode]);
- }
-
- - (WhiteBalanceMode) defaultWhiteBalanceMode {
- return WhiteBalanceLinear;
- }
-
- - (WhiteBalanceMode) whiteBalanceMode {
- return whiteBalanceMode;
- }
-
- - (void) setWhiteBalanceMode:(WhiteBalanceMode)newMode {
- if ([self canSetWhiteBalanceModeTo:newMode]) {
- whiteBalanceMode=newMode;
- }
- }
-
-
- // ============== Color Mode ======================
-
- - (BOOL) canBlackWhiteMode {
- return NO;
- }
-
-
- - (BOOL) blackWhiteMode {
- return blackWhiteMode;
- }
-
- - (void) setBlackWhiteMode:(BOOL)newMode {
- if ([self canBlackWhiteMode]) {
- blackWhiteMode=newMode;
- }
- }
-
-
- //================== Light Emitting Diode
-
- - (BOOL) canSetLed {
- return NO;
- }
-
-
- - (BOOL) isLedOn {
- return LEDon;
- }
-
- - (void) setLed:(BOOL)v {
- if ([self canSetLed]) {
- LEDon=v;
- }
- }
-
-
- // =========================
-
- - (short) width { //Current image width
- return WidthOfResolution(resolution);
- }
-
- - (short) height { //Current image height
- return HeightOfResolution(resolution);
- }
-
- - (CameraResolution) resolution { //Current image predefined format constant
- return resolution;
- }
-
- - (short) fps { //Current frames per second
- return fps;
- }
-
- - (BOOL) supportsResolution:(CameraResolution)r fps:(short)fr { //Does this combination work?
- return NO;
- }
- - (void) setResolution:(CameraResolution)r fps:(short)fr { //Set a resolution and frame rate. Returns success.
- if (![self supportsResolution:r fps:fr]) return;
- [stateLock lock];
- if (!isGrabbing) {
- resolution=r;
- fps=fr;
- }
- [stateLock unlock];
- }
-
- - (CameraResolution) findResolutionForWidth:(short)width height:(short) height {
- //Find the largest resolution that is supported and smaller than the given dimensions
- CameraResolution res=ResolutionVGA;
- BOOL found=NO;
- while ((!found)&&(res>=(ResolutionSQSIF))) {
- if (WidthOfResolution(res)<=width) {
- if (HeightOfResolution(res)<=height) {
- if ([self findFrameRateForResolution:res]>0) {
- found=YES;
- }
- }
- }
- if (!found) res=(CameraResolution)(((short)res)-1);
- }
- //If there is no smaller resolution: Find the smallest availabe resolution
- if (!found) {
- res=ResolutionSQSIF;
- while ((!found)&&(res<=(ResolutionVGA))) {
- if ([self findFrameRateForResolution:res]>0) found=YES;
- if (!found) res=(CameraResolution)(((short)res)+1);
- }
- }
- if (!found) {
- #ifdef VERBOSE
- NSLog(@"MyCameraDriver:findResolutionForWidth:height: Cannot find any resolution");
- #endif
- return ResolutionQSIF;
- }
- return res;
- }
-
- - (short) findFrameRateForResolution:(CameraResolution)res {
- short fpsRun=30;
- while (fpsRun>=5) {
- if ([self supportsResolution:res fps:fpsRun]) return fpsRun;
- else fpsRun-=5;
- }
- return 0;
- }
-
- - (CameraResolution) defaultResolutionAndRate:(short*)dFps { //Just some defaults. You should always override this.
- if (dFps) *dFps=5;
- return ResolutionSQSIF;
- }
-
- //Grabbing
- - (BOOL) startGrabbing { //start async grabbing
- id threadData=NULL;
- BOOL needStartUp=YES;
- BOOL ret=NO;
- [stateLock lock];
- needStartUp=isStarted&&(!isShuttingDown)&&(!isGrabbing);
- if (needStartUp) { //update driver state
- shouldBeGrabbing=YES;
- isGrabbing=YES;
- }
- ret=isGrabbing;
- [stateLock unlock];
- if (!needStartUp) return ret;
- if (doNotificationsOnMainThread) {
- NSPort* port1=[NSPort port];
- NSPort* port2=[NSPort port];
- mainThreadConnection=[[NSConnection alloc] initWithReceivePort:port1 sendPort:port2];
- [mainThreadConnection setRootObject:self];
- threadData=[NSArray arrayWithObjects:port2,port1,NULL];
- }
- [NSThread detachNewThreadSelector:@selector(decodingThreadWrapper:) toTarget:self withObject:threadData]; //start decodingThread
- return ret;
- }
-
- - (BOOL) stopGrabbing { //Stop async grabbing
- BOOL res;
- [stateLock lock];
- if (isGrabbing) shouldBeGrabbing=NO;
- res=isGrabbing;
- [stateLock unlock];
- return res;
- }
-
- - (BOOL) isGrabbing { // Returns if the camera is grabbing
- BOOL res;
- [stateLock lock];
- res = shouldBeGrabbing;
- [stateLock unlock];
- return res;
- }
-
- - (void) decodingThreadWrapper:(id)data {
- CameraError err;
- NSConnection* myMainThreadConnection; //local copies for the end where possibly a new thread is using the object's variables
- NSConnection* myDecodingThreadConnection;
- NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init];
- if (data) {
- decodingThreadConnection=[[NSConnection alloc] initWithReceivePort:[data objectAtIndex:0] sendPort:[data objectAtIndex:1]];
- }
- err=[self decodingThread];
- myMainThreadConnection=mainThreadConnection;
- myDecodingThreadConnection=decodingThreadConnection;
- [stateLock lock]; //We have to lock because other tasks rely on a constant state within their lock
- isGrabbing=NO;
- [stateLock unlock];
- [self mergeGrabFinishedWithError:err];
- if (isShuttingDown) {
- [self usbCloseConnection];
- [self mergeCameraHasShutDown];
- [stateLock lock];
- isShutDown=YES;
- [stateLock unlock];
- }
- if (myDecodingThreadConnection) [myDecodingThreadConnection release];
- if (myMainThreadConnection) [myMainThreadConnection release];
- [pool release];
- [NSThread exit];
- }
-
- - (CameraError) decodingThread {
- return CameraErrorInternal;
- }
-
- - (void) setImageBuffer:(unsigned char*)buffer bpp:(short)bpp rowBytes:(long)rb {
- if (((bpp!=3)&&(bpp!=4))||(rb<0)) return;
- [imageBufferLock lock];
- if ((!isShuttingDown)&&(!isShutDown)) { //When shutting down, we don't accept buffers any more
- nextImageBuffer=buffer;
- } else {
- nextImageBuffer=NULL;
- }
- nextImageBufferBPP=bpp;
- nextImageBufferRowBytes=rb;
- nextImageBufferSet=YES;
- [imageBufferLock unlock];
- }
-
- - (unsigned char*) imageBuffer {
- return lastImageBuffer;
- }
-
- - (short) imageBufferBPP {
- return lastImageBufferBPP;
- }
-
- - (long) imageBufferRowBytes {
- return lastImageBufferRowBytes;
- }
-
- - (BOOL) canStoreMedia {
- return NO;
- }
-
- - (long) numberOfStoredMediaObjects {
- return 0;
- }
-
- - (NSDictionary*) getStoredMediaObject:(long)idx {
- return NULL;
- }
-
- - (BOOL) canGetStoredMediaObjectInfo {
- return NO;
- }
-
- - (NSDictionary*) getStoredMediaObjectInfo:(long)idx {
- return NULL;
- }
-
- - (BOOL) canDeleteAll {
- return NO;
- }
-
- - (CameraError) deleteAll {
- return CameraErrorUnimplemented;
- }
-
- - (BOOL) canDeleteOne {
- return NO;
- }
-
- - (CameraError) deleteOne:(long)idx {
- return CameraErrorUnimplemented;
- }
-
- - (BOOL) canDeleteLast {
- return NO;
- }
-
- - (CameraError) deleteLast {
- return CameraErrorUnimplemented;
- }
-
- - (BOOL) canCaptureOne {
- return NO;
- }
-
- - (CameraError) captureOne {
- return CameraErrorUnimplemented;
- }
-
-
- - (BOOL) supportsCameraFeature:(CameraFeature)feature {
- BOOL supported=NO;
- switch (feature) {
- case CameraFeatureInspectorClassName:
- supported=YES;
- break;
- default:
- break;
- }
- return supported;
- }
-
- - (id) valueOfCameraFeature:(CameraFeature)feature {
- id ret=NULL;
- switch (feature) {
- case CameraFeatureInspectorClassName:
- ret=@"MyCameraInspector";
- break;
- default:
- break;
- }
- return ret;
- }
-
- - (void) setValue:(id)val ofCameraFeature:(CameraFeature)feature {
- switch (feature) {
- default:
- break;
- }
- }
-
-
- //Merging Notification forwarders - use these if you want to notify from decodingThread
-
- - (void) mergeGrabFinishedWithError:(CameraError)err {
- if (doNotificationsOnMainThread) {
- if ([NSRunLoop currentRunLoop]!=mainThreadRunLoop) {
- [(id)[decodingThreadConnection rootProxy] mergeGrabFinishedWithError:err];
- return;
- }
- }
- [self grabFinished:self withError:err];
- }
-
- - (void) mergeImageReady {
- if (doNotificationsOnMainThread) {
- if ([NSRunLoop currentRunLoop]!=mainThreadRunLoop) {
- [(id)[decodingThreadConnection rootProxy] mergeImageReady];
- return;
- }
- }
- [self imageReady:self];
- }
-
- - (void) mergeCameraHasShutDown {
- if (doNotificationsOnMainThread) {
- if ([NSRunLoop currentRunLoop]!=mainThreadRunLoop) {
- [(id)[decodingThreadConnection rootProxy] mergeCameraHasShutDown];
- return;
- }
- }
- [self cameraHasShutDown:self];
- }
-
- //Simple Notification forwarders
-
- - (void) imageReady:(id)sender {
- if (delegate!=NULL) {
- if ([delegate respondsToSelector:@selector(imageReady:)]) {
- [delegate imageReady:sender];
- }
- }
- }
-
- - (void) grabFinished:(id)sender withError:(CameraError)err{
- if (delegate!=NULL) {
- if ([delegate respondsToSelector:@selector(grabFinished:withError:)]) [delegate grabFinished:sender withError:err];
- }
- }
-
- - (void) cameraHasShutDown:(id)sender {
- if (delegate!=NULL) {
- if ([delegate respondsToSelector:@selector(cameraHasShutDown:)]) [delegate cameraHasShutDown:sender];
- }
- if (central) {
- [central cameraHasShutDown:self];
- }
- }
-
- - (void) cameraEventHappened:(id)sender event:(CameraEvent)evt {
- if (delegate!=NULL) {
- if ([delegate respondsToSelector:@selector(cameraEventHappened:event:)]) {
- [delegate cameraEventHappened:sender event:evt];
- }
- }
- }
-
- - (MyCameraInfo*) getCameraInfo {
- return cameraInfo;
- }
-
- - (void) setCameraInfo:(MyCameraInfo *)info {
- cameraInfo = info;
- }
-
- //USB Tool functions for subclasses
-
- //Sends a generic command
- - (BOOL) usbCmdWithBRequestType:(UInt8)bReqType bRequest:(UInt8)bReq wValue:(UInt16)wVal wIndex:(UInt16)wIdx buf:(void*)buf len:(short)len {
- IOReturn err;
- IOUSBDevRequest req;
- req.bmRequestType=bReqType;
- req.bRequest=bReq;
- req.wValue=wVal;
- req.wIndex=wIdx;
- req.wLength=len;
- req.pData=buf;
- if ((!isUSBOK)||(!intf)) return NO;
- err=(*intf)->ControlRequest(intf,0,&req);
- #ifdef LOG_USB_CALLS
- NSLog(@"usb command reqType:%i req:%i val:%i idx:%i len:%i ret:%i",bReqType,bReq,wVal,wIdx,len,err);
- if (len>0) DumpMem(buf,len);
- #endif
- CheckError(err,"usbCmdWithBRequestType");
- if ((err==kIOUSBPipeStalled)&&(intf)) (*intf)->ClearPipeStall(intf,0);
- return (!err);
- }
-
- //sends a USB IN|VENDOR|DEVICE command
- - (BOOL) usbReadCmdWithBRequest:(short)bReq wValue:(short)wVal wIndex:(short)wIdx buf:(void*)buf len:(short)len {
- return [self usbCmdWithBRequestType:USBmakebmRequestType(kUSBIn, kUSBVendor, kUSBDevice)
- bRequest:bReq
- wValue:wVal
- wIndex:wIdx
- buf:buf
- len:len];
- }
-
- //sends a USB IN|VENDOR|INTERFACE command
- - (BOOL) usbReadVICmdWithBRequest:(short)bReq wValue:(short)wVal wIndex:(short)wIdx buf:(void*)buf len:(short)len {
- return [self usbCmdWithBRequestType:USBmakebmRequestType(kUSBIn, kUSBVendor, kUSBInterface)
- bRequest:bReq
- wValue:wVal
- wIndex:wIdx
- buf:buf
- len:len];
- }
-
- //sends a USB OUT|VENDOR|DEVICE command
- - (BOOL) usbWriteCmdWithBRequest:(short)bReq wValue:(short)wVal wIndex:(short)wIdx buf:(void*)buf len:(short)len {
- return [self usbCmdWithBRequestType:USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBDevice)
- bRequest:bReq
- wValue:wVal
- wIndex:wIdx
- buf:buf
- len:len];
- }
-
- //sends a USB OUT|VENDOR|INTERFACE command
- - (BOOL) usbWriteVICmdWithBRequest:(short)bReq wValue:(short)wVal wIndex:(short)wIdx buf:(void*)buf len:(short)len {
- return [self usbCmdWithBRequestType:USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface)
- bRequest:bReq
- wValue:wVal
- wIndex:wIdx
- buf:buf
- len:len];
- }
-
- - (BOOL) usbSetAltInterfaceTo:(short)alt testPipe:(short)pipe {
- IOReturn err;
- BOOL ok=YES;
- if ((!isUSBOK)||(!intf)) ok=NO;
- if (ok) {
- err=(*intf)->SetAlternateInterface(intf,alt); //set alternate interface
- CheckError(err,"setAlternateInterface");
- if (err) ok=NO;
- }
- if ((!isUSBOK)||(!intf)) ok=NO;
- if (ok&&(alt!=0)&&(pipe!=0)) {
- err=(*intf)->GetPipeStatus(intf,pipe); //is the pipe ok?
- CheckError(err,"getPipeStatus");
- if (err) ok=NO;
- }
- #ifdef LOG_USB_CALLS
- if (ok) NSLog(@"alt interface switch to %i ok");
- else NSLog(@"alt interface switch to %i failed");
- #endif
- return ok;
- }
-
- - (CameraError) usbConnectToCam:(UInt32)usbLocationId configIdx:(short)configIdx{
- IOReturn err;
- IOCFPlugInInterface **iodev; // requires <IOKit/IOCFPlugIn.h>
- SInt32 score;
- UInt8 numConf;
- IOUSBConfigurationDescriptorPtr confDesc;
- IOUSBFindInterfaceRequest interfaceRequest;
- io_iterator_t iterator;
- io_service_t usbInterfaceRef;
- short retries;
- kern_return_t ret;
- io_service_t usbDeviceRef=IO_OBJECT_NULL;
- mach_port_t masterPort;
- CFMutableDictionaryRef matchingDict;
-
- //Get a master port (we should release it later...) *******
-
- ret=IOMasterPort(MACH_PORT_NULL,&masterPort);
- if (ret) {
- #ifdef VERBOSE
- NSLog(@"usbConnectToCam: Could not get master port (err:%08x)",ret);
- #endif
- return CameraErrorInternal;
- }
-
- //Search device with given location Id
- matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
- if (!matchingDict) {
- #ifdef VERBOSE
- NSLog(@"usbConnectToCam: Could not build matching dict");
- #endif
- return CameraErrorNoMem;
- }
- ret = IOServiceGetMatchingServices(masterPort,
- matchingDict,
- &iterator);
-
- if ((ret)||(!iterator)) {
- #ifdef VERBOSE
- NSLog(@"usbConnectToCam: Could not build iterate services");
- #endif
- return CameraErrorNoMem;
- }
-
- //Go through results
-
- while (usbDeviceRef=IOIteratorNext(iterator)) {
- UInt32 locId;
-
- err = IOCreatePlugInInterfaceForService(usbDeviceRef, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
- CheckError(err,"usbConnectToCam-IOCreatePlugInInterfaceForService");
- if ((!iodev)||(err)) return CameraErrorInternal; //Bail - find better error code ***
-
- //ask plugin interface for device interface
- err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID)&dev);
- //IOPlugin interface is done
- (*iodev)->Release(iodev);
- if ((!dev)||(err)) return CameraErrorInternal; //Bail - find better error code ***
- CheckError(err,"usbConnectToCam-QueryInterface1");
-
- ret = (*dev)->GetLocationID(dev,&locId);
- if (ret) {
- #ifdef VERBOSE
- NSLog(@"could not get location id (err:%08x)",ret);
- #endif
- (*dev)->Release(dev);
- return CameraErrorUSBProblem;
- }
- if (usbLocationId==locId) break; //We found our device
- else {
- (*dev)->Release(dev);
- IOObjectRelease(usbDeviceRef);
- dev=NULL;
- }
- }
-
- IOObjectRelease(iterator); iterator=IO_OBJECT_NULL;
-
- if (!dev) return CameraErrorNoCam;
-
- //Now we should have the correct device interface.
-
- //open device interface. Retry this to get it from Classic (see ClassicUSBDeviceArb.html - simplified mechanism)
- for (retries=10;retries>0;retries--) {
- err = (*dev)->USBDeviceOpen(dev);
- CheckError(err,"usbConnectToCam-USBDeviceOpen");
- if (err!=kIOReturnExclusiveAccess) break; //Loop only if the device is busy
- usleep(500000);
- }
- if (err) { //If soneone else has our device, bail out as if nothing happened...
- err = (*dev)->Release(dev);
- CheckError(err,"usbConnectToCam-Release Device (exclusive access)");
- dev=NULL;
- return CameraErrorBusy;
- }
-
- if (configIdx>=0) { //Set configIdx to -1 if you don't want a config to be selected
- //do a device reset. Shouldn't harm.
- err = (*dev)->ResetDevice(dev);
- CheckError(err,"usbConnectToCam-ResetDevice");
- //Count configurations
- err = (*dev)->GetNumberOfConfigurations(dev, &numConf);
- CheckError(err,"usbConnectToCam-GetNumberOfConfigurations");
- if (numConf<configIdx) {
- NSLog(@"Invalid configuration index");
- err = (*dev)->Release(dev);
- dev=NULL;
- return CameraErrorInternal;
- }
- err = (*dev)->GetConfigurationDescriptorPtr(dev, configIdx, &confDesc); CheckError(err,"usbConnectToCam-GetConfigurationDescriptorPtr");
- retries=3;
- do {
- err = (*dev)->SetConfiguration(dev, confDesc->bConfigurationValue);
- CheckError(err,"usbConnectToCam-SetConfiguration");
- if (err==kIOUSBNotEnoughPowerErr) { //no power?
- err = (*dev)->Release(dev);
- CheckError(err,"usbConnectToCam-Release Device (low power)");
- dev=NULL;
- return CameraErrorNoPower;
- }
- } while((err)&&((--retries)>0));
- if (err) { //error opening interface?
- err = (*dev)->Release(dev);
- CheckError(err,"usbConnectToCam-Release Device (low power)");
- dev=NULL;
- return CameraErrorUSBProblem;
- }
- }
-
- interfaceRequest.bInterfaceClass = kIOUSBFindInterfaceDontCare; // requested class
- interfaceRequest.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; // requested subclass
- interfaceRequest.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; // requested protocol
- interfaceRequest.bAlternateSetting = kIOUSBFindInterfaceDontCare; // requested alt setting
-
- //take an iterator over the device interfaces...
- err = (*dev)->CreateInterfaceIterator(dev, &interfaceRequest, &iterator);
- CheckError(err,"usbConnectToCam-CreateInterfaceIterator");
-
- //and take the first one
- usbInterfaceRef = IOIteratorNext(iterator);
- assert (usbInterfaceRef);
-
- //we don't need the iterator any more
- IOObjectRelease(iterator);
- iterator = 0;
-
- //get a plugin interface for the interface interface
- err = IOCreatePlugInInterfaceForService(usbInterfaceRef, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
- CheckError(err,"usbConnectToCam-IOCreatePlugInInterfaceForService");
- assert(iodev);
- IOObjectRelease(usbInterfaceRef);
-
- //get access to the interface interface
- err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)&intf);
- CheckError(err,"usbConnectToCam-QueryInterface2");
- assert(intf);
- (*iodev)->Release(iodev); // done with this
-
- //open interface
- err = (*intf)->USBInterfaceOpen(intf);
- CheckError(err,"usbConnectToCam-USBInterfaceOpen");
-
- //set alternate interface
- err = (*intf)->SetAlternateInterface(intf,0);
- CheckError(err,"usbConnectToCam-SetAlternateInterface");
-
- return CameraErrorOK;
- }
-
- - (void) usbCloseConnection {
- IOReturn err;
- if (intf) { //close our interface interface
- if (isUSBOK) {
- err = (*intf)->USBInterfaceClose(intf);
- }
- err = (*intf)->Release(intf);
- CheckError(err,"usbCloseConnection-Release Interface");
- intf=NULL;
- }
- if (dev) { //close our device interface
- if (isUSBOK) {
- err = (*dev)->USBDeviceClose(dev);
- }
- err = (*dev)->Release(dev);
- CheckError(err,"usbCloseConnection-Release Device");
- dev=NULL;
- }
- }
-
- - (BOOL) usbGetSoon:(UInt64*)to { //Get a bus frame number in the near future
- AbsoluteTime at;
- IOReturn err;
- UInt64 frame;
-
- if ((!to)||(!intf)||(!isUSBOK)) return NO;
- err=(*intf)->GetBusFrameNumber(intf, &frame, &at);
- CheckError(err,"usbGetSoon");
- if (err) return NO;
- *to=frame+100; //give it a little time to start
- return YES;
- }
-
- //Other tool functions
- - (BOOL) makeErrorImage:(CameraError) err {
- switch (err) {
- case CameraErrorOK: return [self makeOKImage]; break;
- default: return [self makeMessageImage:[central localizedCStrForError:err]]; break;
- }
- }
-
- - (BOOL) makeMessageImage:(char*) msg {
- BOOL draw;
- [imageBufferLock lock];
- lastImageBuffer=nextImageBuffer;
- lastImageBufferBPP=nextImageBufferBPP;
- lastImageBufferRowBytes=nextImageBufferRowBytes;
- draw=nextImageBufferSet;
- nextImageBufferSet=NO;
- if (draw) {
- if (lastImageBuffer) {
- memset(lastImageBuffer,0,lastImageBufferRowBytes*[self height]);
- MiniDrawString(lastImageBuffer,lastImageBufferBPP,lastImageBufferRowBytes,10,10,msg);
- }
- [imageBufferLock unlock];
- [self mergeImageReady]; //notify delegate about the image. perhaps get a new buffer
- } else {
- [imageBufferLock unlock];
- }
- return draw;
- }
-
- - (BOOL) makeOKImage {
- BOOL draw;
- char cstr[20];
- short x,bar,y,width,height,barend;
- UInt8 r,g,b;
- UInt8* bufRun;
- BOOL alpha;
- CFTimeInterval time;
- short h,m,s,f;
- [imageBufferLock lock];
- lastImageBuffer=nextImageBuffer;
- lastImageBufferBPP=nextImageBufferBPP;
- lastImageBufferRowBytes=nextImageBufferRowBytes;
- draw=nextImageBufferSet;
- nextImageBufferSet=NO;
- [imageBufferLock unlock];
- if (draw) {
- if (lastImageBuffer) {
- //Draw color stripes
- alpha=lastImageBufferBPP==4;
- width=[self width];
- height=[self height];
- bufRun=lastImageBuffer;
- for (y=0;y<height;y++) {
- x=0;
- for (bar=0;bar<8;bar++) {
- switch (bar) {
- case 0: r=255;g=255;b=255;break;
- case 1: r=255;g=255;b=0 ;break;
- case 2: r=255;g=0 ;b=255;break;
- case 3: r=0 ;g=255;b=255;break;
- case 4: r=255;g=0 ;b=0 ;break;
- case 5: r=0 ;g=255;b=0 ;break;
- case 6: r=0 ;g=0 ;b=255;break;
- default:r=0 ;g=0 ;b=0 ;break;
- }
- barend=((bar+1)*width)/8;
- while (x<barend) {
- if (alpha) bufRun++;
- *(bufRun++)=r;
- *(bufRun++)=g;
- *(bufRun++)=b;
- x++;
- }
- }
- bufRun+=lastImageBufferRowBytes-width*lastImageBufferBPP;
- }
- time=CFAbsoluteTimeGetCurrent();
- h=(((long long)time)/(60*60))%24;
- m=(((long long)time)/(60))%60;
- s=((long long)time)%60;
- time*=100.0;
- f=((long long)(time))%100;
- sprintf(cstr,"%02i:%02i:%02i:%02i",h,m,s,f);
- MiniDrawString(lastImageBuffer,lastImageBufferBPP,lastImageBufferRowBytes,10,10,cstr);
- MiniDrawString(lastImageBuffer,lastImageBufferBPP,lastImageBufferRowBytes,10,23,
- (char*)[[[self getCameraInfo] cameraName] cString]);
- }
- [self mergeImageReady]; //notify delegate about the image. perhaps get a new buffer
- }
- return draw;
- }
-
-
- - (void) stopUsingUSB {
- isUSBOK=NO;
- }
-
- @end
-