home *** CD-ROM | disk | FTP | other *** search
/ MacAddict 114 / macaddict114.cdr / Software / Utilities / macam.0.8.4.dmg / macam sources / driver_core / MyCameraDriver.m < prev    next >
Encoding:
Text File  |  2005-11-16  |  29.9 KB  |  1,080 lines

  1. /*
  2.     macam - webcam app and QuickTime driver component
  3.     Copyright (C) 2002 Matthias Krauss (macam@matthias-krauss.de)
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 2 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  $Id: MyCameraDriver.m,v 1.14 2005/10/18 17:50:24 hxr Exp $
  19. */
  20.  
  21. #import "MyCameraDriver.h"
  22. #import "MyCameraCentral.h"
  23. #import "Resolvers.h"
  24. #import "MiniGraphicsTools.h"
  25. #import "MiscTools.h"
  26. #include <unistd.h>        //usleep
  27.  
  28. @implementation MyCameraDriver
  29.  
  30. + (unsigned short) cameraUsbProductID {
  31.     NSAssert(0,@"You must override cameraUsbProductID or cameraUsbDescriptions");
  32.     return 0;
  33. }
  34.  
  35. + (unsigned short) cameraUsbVendorID {
  36.     NSAssert(0,@"You must override cameraUsbVendorID or cameraUsbDescriptions");
  37.     return 0;
  38. }
  39.  
  40. + (NSString*) cameraName {
  41.     NSAssert(0,@"You must override cameraName or cameraUsbDescriptions");
  42.     return @"";
  43. }
  44.  
  45. + (NSArray*) cameraUsbDescriptions {
  46.     NSDictionary* dict=[NSDictionary dictionaryWithObjectsAndKeys:
  47.         [NSNumber numberWithUnsignedShort:[self cameraUsbProductID]],@"idProduct",
  48.         [NSNumber numberWithUnsignedShort:[self cameraUsbVendorID]],@"idVendor",
  49.         [self cameraName],@"name",NULL];
  50.     return [NSArray arrayWithObject:dict];
  51. }
  52.  
  53. - (id) initWithCentral:(id)c {
  54. //init superclass
  55.     self=[super init];
  56.     if (self==NULL) return NULL;
  57. //setup simple defaults
  58.     central=c;
  59.     dev=NULL;
  60.     intf=NULL;
  61.     brightness=0.0f;
  62.     contrast=0.0f;
  63.     saturation=0.0f;
  64.     gamma=0.0f;
  65.     shutter=0.0f;
  66.     gain=0.0f;
  67.     autoGain=NO;
  68.     hFlip=NO;
  69.     compression=0;
  70.     whiteBalanceMode=WhiteBalanceLinear;
  71.     blackWhiteMode = FALSE;
  72.     isStarted=NO;
  73.     isGrabbing=NO;
  74.     shouldBeGrabbing=NO;
  75.     isShuttingDown=NO;
  76.     isShutDown=NO;
  77.     isUSBOK=YES;
  78.     lastImageBuffer=NULL;
  79.     lastImageBufferBPP=0;
  80.     lastImageBufferRowBytes=0;
  81.     nextImageBuffer=NULL;
  82.     nextImageBufferBPP=0;
  83.     nextImageBufferRowBytes=0;
  84.     nextImageBufferSet=NO;
  85.     imageBufferLock=[[NSLock alloc] init];
  86.     //allocate lock
  87.     if (imageBufferLock==NULL) {
  88. #ifdef VERBOSE
  89.         NSLog(@"MyCameraDriver:init: cannot instantiate imageBufferLock");
  90. #endif
  91.         return NULL;
  92.     }
  93.     stateLock=[[NSLock alloc] init];
  94.     //allocate lock
  95.     if (stateLock==NULL) {
  96. #ifdef VERBOSE
  97.         NSLog(@"MyCameraDriver:init: cannot instantiate stateLock");
  98. #endif
  99.         [imageBufferLock release];
  100.         return NULL;
  101.     }
  102.     doNotificationsOnMainThread=[central doNotificationsOnMainThread];
  103.     mainThreadRunLoop=[NSRunLoop currentRunLoop];
  104.     mainThreadConnection=NULL;
  105.     decodingThreadConnection=NULL;
  106.     return self;    
  107. }
  108.  
  109. - (CameraError) startupWithUsbLocationId:(UInt32)usbLocationId {
  110.     CameraResolution r;
  111.     short fr;
  112.     WhiteBalanceMode wb;
  113.     r=[self defaultResolutionAndRate:&fr];
  114.     wb=[self defaultWhiteBalanceMode];
  115.     [self setResolution:r fps:fr];
  116.     [self setWhiteBalanceMode:wb];
  117.     isStarted=YES;
  118.     return CameraErrorOK;
  119. }
  120.  
  121. - (void) shutdown {
  122.     BOOL needsShutdown;
  123.     [stateLock lock];
  124.     isShuttingDown=YES;
  125.     shouldBeGrabbing=NO;
  126.     needsShutdown=!isShutDown;
  127.     [stateLock unlock];
  128.     [imageBufferLock lock];    //Make sure no external image buffer is used after this method returns
  129.     nextImageBufferSet=NO;
  130.     nextImageBuffer=NULL;
  131.     [imageBufferLock unlock];
  132.     if (!needsShutdown) return;
  133.     if (![self stopGrabbing]) {    //We can handle it here - if not, do it on the end of the decodingThread
  134.         [self usbCloseConnection];
  135.         [stateLock lock];
  136.         isShutDown=YES;
  137.         [stateLock unlock];
  138.         [self mergeCameraHasShutDown];
  139.     }
  140. }    
  141.  
  142. - (void) dealloc {
  143.     if (imageBufferLock!=NULL) [imageBufferLock release]; imageBufferLock=NULL;
  144.     [super dealloc];
  145. }
  146.  
  147. - (id) delegate {
  148.     return delegate;
  149. }
  150.  
  151. - (void) setDelegate:(id)d {
  152.     delegate=d;
  153. }
  154.  
  155. - (void) enableNotifyOnMainThread {
  156.     doNotificationsOnMainThread=YES;
  157. }
  158.  
  159. - (void) setCentral:(id)c {
  160.     central=c;
  161. }
  162.  
  163. - (id) central {
  164.     return central;
  165. }
  166.  
  167. - (BOOL) realCamera {    //Returns if the camera is a real image grabber or a dummy
  168.     return YES;        //By default, subclasses are real cams. Dummys should override this
  169. }
  170.  
  171. - (BOOL) hasSpecificName { // Returns is the camera has a more specific name (derived from USB connection perhaps)
  172.     return NO;
  173. }
  174.  
  175. - (NSString *) getSpecificName {
  176.     return @"Error!: Name has not been specified";
  177. }
  178.  
  179. //Image / camera properties get/set
  180. - (BOOL) canSetBrightness {
  181.     return NO;
  182. }
  183.  
  184. - (float) brightness {
  185.     return brightness;
  186. }
  187.  
  188. - (void) setBrightness:(float)v {
  189.     brightness=v;
  190. }
  191.  
  192. - (BOOL) canSetContrast {
  193.     return NO;
  194. }
  195.  
  196. - (float) contrast {
  197.     return contrast;
  198. }
  199.  
  200. - (void) setContrast:(float)v {
  201.     contrast=v;
  202. }
  203.  
  204. - (BOOL) canSetSaturation {
  205.     return NO;
  206. }
  207.  
  208. - (float) saturation {
  209.     return saturation;
  210. }
  211.  
  212. - (void) setSaturation:(float)v {
  213.     saturation=v;
  214. }
  215.  
  216. - (BOOL) canSetGamma {
  217.     return NO;
  218. }
  219.  
  220. - (float) gamma {
  221.     return gamma;
  222. }
  223.  
  224. - (void) setGamma:(float)v {
  225.     gamma=v;
  226. }
  227.  
  228. - (BOOL) canSetSharpness {
  229.     return NO;
  230. }
  231.  
  232. - (float) sharpness {
  233.     return sharpness;
  234. }
  235.  
  236. - (void) setSharpness:(float)v {
  237.     sharpness=v;
  238. }
  239.  
  240. - (BOOL) canSetGain {
  241.     return NO;
  242. }
  243.  
  244. - (float) gain {
  245.     return gain;
  246. }
  247.  
  248. - (void) setGain:(float)v {
  249.     gain=v;
  250. }
  251.  
  252. - (BOOL) canSetShutter {
  253.     return NO;
  254. }
  255.  
  256. - (float) shutter {
  257.     return shutter;
  258. }
  259.  
  260. - (void) setShutter:(float)v {
  261.     shutter=v;
  262. }
  263.  
  264. - (BOOL) canSetAutoGain {    //Gain and shutter combined (so far - let's see what other cams can do...)
  265.     return NO;
  266. }
  267.  
  268. - (BOOL) isAutoGain {
  269.     return autoGain;
  270. }
  271.  
  272. - (void) setAutoGain:(BOOL)v{
  273.     autoGain=v;
  274. }
  275.  
  276. - (BOOL) canSetHFlip {
  277.     return NO;
  278. }
  279.  
  280. - (BOOL) hFlip {
  281.     return hFlip;
  282. }
  283.  
  284. - (void) setHFlip:(BOOL)v {
  285.     hFlip=v;
  286. }
  287.  
  288. - (short) maxCompression {
  289.     return 0;
  290. }
  291.  
  292. - (short) compression {
  293.     return compression;
  294. }
  295.  
  296. - (void) setCompression:(short)v {
  297.     [stateLock lock];
  298.     if (!isGrabbing) compression=CLAMP(v,0,[self maxCompression]);
  299.     [stateLock unlock];
  300. }
  301.  
  302. - (BOOL) canSetWhiteBalanceMode {
  303.     return NO;
  304. }
  305.  
  306. - (BOOL) canSetWhiteBalanceModeTo:(WhiteBalanceMode)newMode {
  307.     return (newMode==[self defaultWhiteBalanceMode]);
  308. }
  309.  
  310. - (WhiteBalanceMode) defaultWhiteBalanceMode {
  311.     return WhiteBalanceLinear;
  312. }
  313.  
  314. - (WhiteBalanceMode) whiteBalanceMode {
  315.     return whiteBalanceMode;
  316. }
  317.  
  318. - (void) setWhiteBalanceMode:(WhiteBalanceMode)newMode {
  319.     if ([self canSetWhiteBalanceModeTo:newMode]) {
  320.         whiteBalanceMode=newMode;
  321.     }
  322. }
  323.  
  324.  
  325. // ============== Color Mode ======================
  326.  
  327. - (BOOL) canBlackWhiteMode {
  328.     return NO;
  329. }
  330.  
  331.  
  332. - (BOOL) blackWhiteMode {
  333.     return blackWhiteMode;
  334. }
  335.  
  336. - (void) setBlackWhiteMode:(BOOL)newMode {
  337.     if ([self canBlackWhiteMode]) {
  338.         blackWhiteMode=newMode;
  339.     }
  340. }
  341.  
  342.  
  343. //================== Light Emitting Diode
  344.  
  345. - (BOOL) canSetLed {
  346.     return NO;
  347. }
  348.  
  349.  
  350. - (BOOL) isLedOn {
  351.     return LEDon;
  352. }
  353.  
  354. - (void) setLed:(BOOL)v {
  355.     if ([self canSetLed]) {
  356.         LEDon=v;
  357.     }
  358. }
  359.  
  360.  
  361. // =========================
  362.  
  363. - (short) width {                        //Current image width
  364.     return WidthOfResolution(resolution);
  365. }
  366.  
  367. - (short) height {                        //Current image height
  368.     return HeightOfResolution(resolution);
  369. }
  370.  
  371. - (CameraResolution) resolution {                //Current image predefined format constant
  372.     return resolution;
  373. }
  374.  
  375. - (short) fps {                            //Current frames per second
  376.     return fps;
  377. }
  378.  
  379. - (BOOL) supportsResolution:(CameraResolution)r fps:(short)fr {    //Does this combination work?
  380.     return NO;
  381. }
  382. - (void) setResolution:(CameraResolution)r fps:(short)fr {    //Set a resolution and frame rate. Returns success.
  383.     if (![self supportsResolution:r fps:fr]) return;
  384.     [stateLock lock];
  385.     if (!isGrabbing) {
  386.         resolution=r;
  387.         fps=fr;
  388.     }
  389.     [stateLock unlock];
  390. }
  391.  
  392. - (CameraResolution) findResolutionForWidth:(short)width height:(short) height {
  393. //Find the largest resolution that is supported and smaller than the given dimensions
  394.     CameraResolution res=ResolutionVGA;
  395.     BOOL found=NO;
  396.     while ((!found)&&(res>=(ResolutionSQSIF))) {
  397.         if (WidthOfResolution(res)<=width) {
  398.             if (HeightOfResolution(res)<=height) {
  399.                 if ([self findFrameRateForResolution:res]>0) {
  400.                     found=YES;
  401.                 }
  402.             }
  403.         }
  404.         if (!found) res=(CameraResolution)(((short)res)-1);
  405.     }
  406.     //If there is no smaller resolution: Find the smallest availabe resolution
  407.     if (!found) {
  408.         res=ResolutionSQSIF;
  409.         while ((!found)&&(res<=(ResolutionVGA))) {
  410.             if ([self findFrameRateForResolution:res]>0) found=YES;
  411.             if (!found) res=(CameraResolution)(((short)res)+1);
  412.         }
  413.     }
  414.     if (!found) {
  415. #ifdef VERBOSE
  416.         NSLog(@"MyCameraDriver:findResolutionForWidth:height: Cannot find any resolution");
  417. #endif
  418.         return ResolutionQSIF;
  419.     }
  420.     return res;
  421. }
  422.  
  423. - (short) findFrameRateForResolution:(CameraResolution)res {
  424.     short fpsRun=30;
  425.     while (fpsRun>=5) {
  426.         if ([self supportsResolution:res fps:fpsRun]) return fpsRun;
  427.         else fpsRun-=5;
  428.     }
  429.     return 0;
  430. }
  431.  
  432. - (CameraResolution) defaultResolutionAndRate:(short*)dFps {    //Just some defaults. You should always override this.
  433.     if (dFps) *dFps=5;
  434.     return ResolutionSQSIF;
  435. }
  436.  
  437. //Grabbing
  438. - (BOOL) startGrabbing {                    //start async grabbing
  439.     id threadData=NULL;
  440.     BOOL needStartUp=YES;
  441.     BOOL ret=NO;
  442.     [stateLock lock];
  443.     needStartUp=isStarted&&(!isShuttingDown)&&(!isGrabbing);
  444.     if (needStartUp) { //update driver state
  445.         shouldBeGrabbing=YES;
  446.         isGrabbing=YES;
  447.     }
  448.     ret=isGrabbing;    
  449.     [stateLock unlock];
  450.     if (!needStartUp) return ret;
  451.     if (doNotificationsOnMainThread) {
  452.         NSPort* port1=[NSPort port];
  453.         NSPort* port2=[NSPort port];
  454.         mainThreadConnection=[[NSConnection alloc] initWithReceivePort:port1 sendPort:port2];
  455.         [mainThreadConnection setRootObject:self];
  456.         threadData=[NSArray arrayWithObjects:port2,port1,NULL];
  457.     }
  458.     [NSThread detachNewThreadSelector:@selector(decodingThreadWrapper:) toTarget:self withObject:threadData];    //start decodingThread
  459.     return ret;
  460. }
  461.  
  462. - (BOOL) stopGrabbing {        //Stop async grabbing
  463.     BOOL res;
  464.     [stateLock lock];
  465.     if (isGrabbing) shouldBeGrabbing=NO;
  466.     res=isGrabbing;
  467.     [stateLock unlock];
  468.     return res;
  469. }
  470.  
  471. - (BOOL) isGrabbing {    // Returns if the camera is grabbing
  472.     BOOL res;
  473.     [stateLock lock];
  474.         res = shouldBeGrabbing;
  475.     [stateLock unlock];
  476.     return res;
  477. }
  478.  
  479. - (void) decodingThreadWrapper:(id)data {
  480.     CameraError err;
  481.     NSConnection* myMainThreadConnection;    //local copies for the end where possibly a new thread is using the object's variables
  482.     NSConnection* myDecodingThreadConnection;
  483.     NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init];
  484.     if (data) {
  485.         decodingThreadConnection=[[NSConnection alloc] initWithReceivePort:[data objectAtIndex:0] sendPort:[data objectAtIndex:1]];
  486.     }
  487.     err=[self decodingThread];
  488.     myMainThreadConnection=mainThreadConnection;
  489.     myDecodingThreadConnection=decodingThreadConnection;
  490.     [stateLock lock];    //We have to lock because other tasks rely on a constant state within their lock
  491.     isGrabbing=NO;
  492.     [stateLock unlock];
  493.     [self mergeGrabFinishedWithError:err];
  494.     if (isShuttingDown) {
  495.         [self usbCloseConnection];
  496.         [self mergeCameraHasShutDown];
  497.         [stateLock lock];
  498.         isShutDown=YES;
  499.         [stateLock unlock];
  500.     }
  501.     if (myDecodingThreadConnection) [myDecodingThreadConnection release]; 
  502.     if (myMainThreadConnection) [myMainThreadConnection release];
  503.     [pool release];
  504.     [NSThread exit];
  505. }
  506.  
  507. - (CameraError) decodingThread {
  508.     return CameraErrorInternal;
  509. }
  510.  
  511. - (void) setImageBuffer:(unsigned char*)buffer bpp:(short)bpp rowBytes:(long)rb {
  512.     if (((bpp!=3)&&(bpp!=4))||(rb<0)) return;
  513.     [imageBufferLock lock];
  514.     if ((!isShuttingDown)&&(!isShutDown)) {    //When shutting down, we don't accept buffers any more
  515.         nextImageBuffer=buffer;
  516.     } else {
  517.         nextImageBuffer=NULL;
  518.     }
  519.     nextImageBufferBPP=bpp;
  520.     nextImageBufferRowBytes=rb;
  521.     nextImageBufferSet=YES;
  522.     [imageBufferLock unlock];
  523. }
  524.  
  525. - (unsigned char*) imageBuffer {
  526.     return lastImageBuffer;
  527. }
  528.  
  529. - (short) imageBufferBPP {
  530.     return lastImageBufferBPP;
  531. }
  532.  
  533. - (long) imageBufferRowBytes {
  534.     return lastImageBufferRowBytes;
  535. }
  536.  
  537. - (BOOL) canStoreMedia {
  538.     return NO;
  539. }
  540.  
  541. - (long) numberOfStoredMediaObjects {
  542.     return 0;
  543. }
  544.  
  545. - (NSDictionary*) getStoredMediaObject:(long)idx {
  546.     return NULL;
  547. }
  548.  
  549. - (BOOL) canGetStoredMediaObjectInfo {
  550.     return NO;
  551. }
  552.  
  553. - (NSDictionary*) getStoredMediaObjectInfo:(long)idx {
  554.     return NULL;
  555. }
  556.  
  557. - (BOOL) canDeleteAll {
  558.     return NO;
  559. }
  560.  
  561. - (CameraError) deleteAll {
  562.     return CameraErrorUnimplemented;
  563. }
  564.  
  565. - (BOOL) canDeleteOne {
  566.     return NO;
  567. }
  568.  
  569. - (CameraError) deleteOne:(long)idx {
  570.     return CameraErrorUnimplemented;
  571. }
  572.  
  573. - (BOOL) canDeleteLast {
  574.     return NO;
  575. }
  576.  
  577. - (CameraError) deleteLast {
  578.     return CameraErrorUnimplemented;
  579. }
  580.  
  581. - (BOOL) canCaptureOne {
  582.     return NO;
  583. }
  584.  
  585. - (CameraError) captureOne {
  586.     return CameraErrorUnimplemented;
  587. }
  588.  
  589.  
  590. - (BOOL) supportsCameraFeature:(CameraFeature)feature {
  591.     BOOL supported=NO;
  592.     switch (feature) {
  593.         case CameraFeatureInspectorClassName:
  594.             supported=YES;
  595.             break;
  596.         default:
  597.             break;
  598.     }
  599.     return supported;
  600. }
  601.  
  602. - (id) valueOfCameraFeature:(CameraFeature)feature {
  603.     id ret=NULL;
  604.     switch (feature) {
  605.         case CameraFeatureInspectorClassName:
  606.             ret=@"MyCameraInspector";
  607.             break;
  608.         default:
  609.             break;
  610.     }
  611.     return ret;
  612. }
  613.  
  614. - (void) setValue:(id)val ofCameraFeature:(CameraFeature)feature {
  615.     switch (feature) {
  616.         default:
  617.             break;
  618.     }
  619. }
  620.  
  621.  
  622. //Merging Notification forwarders - use these if you want to notify from decodingThread
  623.  
  624. - (void) mergeGrabFinishedWithError:(CameraError)err {
  625.     if (doNotificationsOnMainThread) {
  626.         if ([NSRunLoop currentRunLoop]!=mainThreadRunLoop) {
  627.             [(id)[decodingThreadConnection rootProxy] mergeGrabFinishedWithError:err];
  628.             return;
  629.         }
  630.     }
  631.     [self grabFinished:self withError:err];
  632. }
  633.  
  634. - (void) mergeImageReady {
  635.     if (doNotificationsOnMainThread) {
  636.         if ([NSRunLoop currentRunLoop]!=mainThreadRunLoop) {
  637.             [(id)[decodingThreadConnection rootProxy] mergeImageReady];
  638.             return;
  639.         }
  640.     }
  641.     [self imageReady:self];
  642. }
  643.  
  644. - (void) mergeCameraHasShutDown {
  645.     if (doNotificationsOnMainThread) {
  646.         if ([NSRunLoop currentRunLoop]!=mainThreadRunLoop) {
  647.             [(id)[decodingThreadConnection rootProxy] mergeCameraHasShutDown];
  648.             return;
  649.         }
  650.     }
  651.     [self cameraHasShutDown:self];
  652. }
  653.  
  654. //Simple Notification forwarders
  655.  
  656. - (void) imageReady:(id)sender {
  657.     if (delegate!=NULL) {
  658.         if ([delegate respondsToSelector:@selector(imageReady:)]) {
  659.             [delegate imageReady:sender];
  660.         }
  661.     }
  662. }
  663.  
  664. - (void) grabFinished:(id)sender withError:(CameraError)err{
  665.     if (delegate!=NULL) {
  666.         if ([delegate respondsToSelector:@selector(grabFinished:withError:)]) [delegate grabFinished:sender withError:err];
  667.     }
  668. }
  669.  
  670. - (void) cameraHasShutDown:(id)sender {
  671.     if (delegate!=NULL) {
  672.         if ([delegate respondsToSelector:@selector(cameraHasShutDown:)]) [delegate cameraHasShutDown:sender];
  673.     }
  674.     if (central) {
  675.         [central cameraHasShutDown:self];
  676.     }
  677. }
  678.  
  679. - (void) cameraEventHappened:(id)sender event:(CameraEvent)evt {
  680.     if (delegate!=NULL) {
  681.         if ([delegate respondsToSelector:@selector(cameraEventHappened:event:)]) {
  682.             [delegate cameraEventHappened:sender event:evt];
  683.         }
  684.     }
  685. }
  686.  
  687. - (MyCameraInfo*) getCameraInfo {
  688.        return cameraInfo;
  689. }
  690.  
  691. - (void) setCameraInfo:(MyCameraInfo *)info {
  692.        cameraInfo = info;
  693. }
  694.  
  695. //USB Tool functions for subclasses
  696.  
  697. //Sends a generic command
  698. - (BOOL) usbCmdWithBRequestType:(UInt8)bReqType bRequest:(UInt8)bReq wValue:(UInt16)wVal wIndex:(UInt16)wIdx buf:(void*)buf len:(short)len {
  699.     IOReturn err;
  700.     IOUSBDevRequest req;
  701.     req.bmRequestType=bReqType;
  702.     req.bRequest=bReq;
  703.     req.wValue=wVal;
  704.     req.wIndex=wIdx;
  705.     req.wLength=len;
  706.     req.pData=buf;
  707.     if ((!isUSBOK)||(!intf)) return NO;
  708.     err=(*intf)->ControlRequest(intf,0,&req);
  709. #ifdef LOG_USB_CALLS
  710.     NSLog(@"usb command reqType:%i req:%i val:%i idx:%i len:%i ret:%i",bReqType,bReq,wVal,wIdx,len,err);
  711.     if (len>0) DumpMem(buf,len);
  712. #endif
  713.     CheckError(err,"usbCmdWithBRequestType");
  714.     if ((err==kIOUSBPipeStalled)&&(intf)) (*intf)->ClearPipeStall(intf,0);
  715.     return (!err);
  716. }
  717.  
  718. //sends a USB IN|VENDOR|DEVICE command
  719. - (BOOL) usbReadCmdWithBRequest:(short)bReq wValue:(short)wVal wIndex:(short)wIdx buf:(void*)buf len:(short)len {
  720.     return [self usbCmdWithBRequestType:USBmakebmRequestType(kUSBIn, kUSBVendor, kUSBDevice)
  721.                                bRequest:bReq
  722.                                  wValue:wVal
  723.                                  wIndex:wIdx
  724.                                     buf:buf
  725.                                     len:len];
  726. }
  727.  
  728. //sends a USB IN|VENDOR|INTERFACE command
  729. - (BOOL) usbReadVICmdWithBRequest:(short)bReq wValue:(short)wVal wIndex:(short)wIdx buf:(void*)buf len:(short)len {
  730.     return [self usbCmdWithBRequestType:USBmakebmRequestType(kUSBIn, kUSBVendor, kUSBInterface)
  731.                                bRequest:bReq
  732.                                  wValue:wVal
  733.                                  wIndex:wIdx
  734.                                     buf:buf
  735.                                     len:len];
  736. }
  737.  
  738. //sends a USB OUT|VENDOR|DEVICE command
  739. - (BOOL) usbWriteCmdWithBRequest:(short)bReq wValue:(short)wVal wIndex:(short)wIdx buf:(void*)buf len:(short)len {
  740.     return [self usbCmdWithBRequestType:USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBDevice)
  741.                                bRequest:bReq
  742.                                  wValue:wVal
  743.                                  wIndex:wIdx
  744.                                     buf:buf
  745.                                     len:len];
  746. }
  747.  
  748. //sends a USB OUT|VENDOR|INTERFACE command
  749. - (BOOL) usbWriteVICmdWithBRequest:(short)bReq wValue:(short)wVal wIndex:(short)wIdx buf:(void*)buf len:(short)len {
  750.     return [self usbCmdWithBRequestType:USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface)
  751.                                bRequest:bReq
  752.                                  wValue:wVal
  753.                                  wIndex:wIdx
  754.                                     buf:buf
  755.                                     len:len];
  756. }
  757.  
  758. - (BOOL) usbSetAltInterfaceTo:(short)alt testPipe:(short)pipe {
  759.     IOReturn err;
  760.     BOOL ok=YES;
  761.     if ((!isUSBOK)||(!intf)) ok=NO;
  762.     if (ok) {
  763.         err=(*intf)->SetAlternateInterface(intf,alt);            //set alternate interface
  764.         CheckError(err,"setAlternateInterface");
  765.         if (err) ok=NO;
  766.     }
  767.     if ((!isUSBOK)||(!intf)) ok=NO;
  768.     if (ok&&(alt!=0)&&(pipe!=0)) {
  769.         err=(*intf)->GetPipeStatus(intf,pipe);                //is the pipe ok?
  770.         CheckError(err,"getPipeStatus");
  771.         if (err) ok=NO;
  772.     }
  773. #ifdef LOG_USB_CALLS
  774.     if (ok) NSLog(@"alt interface switch to %i ok");
  775.     else NSLog(@"alt interface switch to %i failed");
  776. #endif
  777.     return ok;
  778. }
  779.  
  780. - (CameraError) usbConnectToCam:(UInt32)usbLocationId configIdx:(short)configIdx{
  781.     IOReturn                err;
  782.     IOCFPlugInInterface         **iodev;        // requires <IOKit/IOCFPlugIn.h>
  783.     SInt32                 score;
  784.     UInt8                numConf;
  785.     IOUSBConfigurationDescriptorPtr    confDesc;
  786.     IOUSBFindInterfaceRequest        interfaceRequest;
  787.     io_iterator_t            iterator;
  788.     io_service_t            usbInterfaceRef;
  789.     short                    retries;
  790.     kern_return_t            ret;
  791.     io_service_t            usbDeviceRef=IO_OBJECT_NULL;
  792.     mach_port_t                masterPort;
  793.     CFMutableDictionaryRef         matchingDict;
  794.     
  795. //Get a master port (we should release it later...) *******
  796.  
  797.     ret=IOMasterPort(MACH_PORT_NULL,&masterPort);
  798.     if (ret) {
  799. #ifdef VERBOSE
  800.         NSLog(@"usbConnectToCam: Could not get master port (err:%08x)",ret);
  801. #endif
  802.         return CameraErrorInternal;
  803.     }
  804.  
  805. //Search device with given location Id
  806.     matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
  807.     if (!matchingDict) {
  808. #ifdef VERBOSE
  809.             NSLog(@"usbConnectToCam: Could not build matching dict");
  810. #endif
  811.             return CameraErrorNoMem;
  812.     }
  813.     ret = IOServiceGetMatchingServices(masterPort,
  814.                                        matchingDict,
  815.                                        &iterator);
  816.     
  817.     if ((ret)||(!iterator)) {
  818. #ifdef VERBOSE
  819.         NSLog(@"usbConnectToCam: Could not build iterate services");
  820. #endif
  821.         return CameraErrorNoMem;
  822.     }
  823.  
  824.     //Go through results
  825.     
  826.     while (usbDeviceRef=IOIteratorNext(iterator)) {
  827.         UInt32 locId;
  828.         
  829.         err = IOCreatePlugInInterfaceForService(usbDeviceRef, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
  830.         CheckError(err,"usbConnectToCam-IOCreatePlugInInterfaceForService");
  831.         if ((!iodev)||(err)) return CameraErrorInternal;    //Bail - find better error code ***
  832.  
  833.         //ask plugin interface for device interface
  834.         err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID)&dev);
  835.         //IOPlugin interface is done
  836.         (*iodev)->Release(iodev);
  837.         if ((!dev)||(err)) return CameraErrorInternal;        //Bail - find better error code ***
  838.         CheckError(err,"usbConnectToCam-QueryInterface1");
  839.  
  840.         ret = (*dev)->GetLocationID(dev,&locId);
  841.         if (ret) {
  842. #ifdef VERBOSE
  843.             NSLog(@"could not get location id (err:%08x)",ret);
  844. #endif
  845.             (*dev)->Release(dev);
  846.             return CameraErrorUSBProblem;
  847.         }
  848.         if (usbLocationId==locId) break;    //We found our device
  849.         else {
  850.             (*dev)->Release(dev);
  851.             IOObjectRelease(usbDeviceRef);
  852.             dev=NULL;
  853.         }            
  854.     }
  855.  
  856.     IOObjectRelease(iterator); iterator=IO_OBJECT_NULL;
  857.     
  858.     if (!dev) return CameraErrorNoCam;
  859.     
  860.     //Now we should have the correct device interface.    
  861.  
  862.     //open device interface. Retry this to get it from Classic (see ClassicUSBDeviceArb.html - simplified mechanism)
  863.     for (retries=10;retries>0;retries--) {
  864.         err = (*dev)->USBDeviceOpen(dev);
  865.         CheckError(err,"usbConnectToCam-USBDeviceOpen");
  866.         if (err!=kIOReturnExclusiveAccess) break;    //Loop only if the device is busy
  867.         usleep(500000);
  868.     }
  869.     if (err) {            //If soneone else has our device, bail out as if nothing happened...
  870.         err = (*dev)->Release(dev);
  871.         CheckError(err,"usbConnectToCam-Release Device (exclusive access)");
  872.         dev=NULL;
  873.         return CameraErrorBusy;
  874.     }
  875.  
  876.     if (configIdx>=0) {    //Set configIdx to -1 if you don't want a config to be selected
  877.         //do a device reset. Shouldn't harm.
  878.         err = (*dev)->ResetDevice(dev);
  879.         CheckError(err,"usbConnectToCam-ResetDevice");
  880.         //Count configurations
  881.         err = (*dev)->GetNumberOfConfigurations(dev, &numConf);
  882.         CheckError(err,"usbConnectToCam-GetNumberOfConfigurations");
  883.         if (numConf<configIdx) {
  884.             NSLog(@"Invalid configuration index");
  885.             err = (*dev)->Release(dev);
  886.             dev=NULL;
  887.             return CameraErrorInternal;
  888.         }
  889.         err = (*dev)->GetConfigurationDescriptorPtr(dev, configIdx, &confDesc);                    CheckError(err,"usbConnectToCam-GetConfigurationDescriptorPtr");
  890.         retries=3;
  891.         do {
  892.             err = (*dev)->SetConfiguration(dev, confDesc->bConfigurationValue);
  893.             CheckError(err,"usbConnectToCam-SetConfiguration");
  894.             if (err==kIOUSBNotEnoughPowerErr) {        //no power?
  895.                 err = (*dev)->Release(dev);
  896.                 CheckError(err,"usbConnectToCam-Release Device (low power)");
  897.                 dev=NULL;
  898.                 return CameraErrorNoPower;
  899.             }
  900.         } while((err)&&((--retries)>0));
  901.         if (err) {                    //error opening interface?
  902.             err = (*dev)->Release(dev);
  903.             CheckError(err,"usbConnectToCam-Release Device (low power)");
  904.             dev=NULL;
  905.             return CameraErrorUSBProblem;
  906.         }
  907.     }
  908.  
  909.     interfaceRequest.bInterfaceClass = kIOUSBFindInterfaceDontCare;        // requested class
  910.     interfaceRequest.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;        // requested subclass
  911.     interfaceRequest.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;        // requested protocol
  912.     interfaceRequest.bAlternateSetting = kIOUSBFindInterfaceDontCare;        // requested alt setting
  913.     
  914. //take an iterator over the device interfaces...
  915.     err = (*dev)->CreateInterfaceIterator(dev, &interfaceRequest, &iterator);
  916.     CheckError(err,"usbConnectToCam-CreateInterfaceIterator");
  917.     
  918. //and take the first one
  919.     usbInterfaceRef = IOIteratorNext(iterator);
  920.     assert (usbInterfaceRef);
  921.  
  922.     //we don't need the iterator any more
  923.     IOObjectRelease(iterator);
  924.     iterator = 0;
  925.     
  926. //get a plugin interface for the interface interface
  927.     err = IOCreatePlugInInterfaceForService(usbInterfaceRef, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
  928.     CheckError(err,"usbConnectToCam-IOCreatePlugInInterfaceForService");
  929.     assert(iodev);
  930.     IOObjectRelease(usbInterfaceRef);
  931.     
  932. //get access to the interface interface
  933.     err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)&intf);
  934.     CheckError(err,"usbConnectToCam-QueryInterface2");
  935.     assert(intf);
  936.     (*iodev)->Release(iodev);                    // done with this
  937.     
  938. //open interface
  939.     err = (*intf)->USBInterfaceOpen(intf);
  940.     CheckError(err,"usbConnectToCam-USBInterfaceOpen");
  941.     
  942. //set alternate interface
  943.     err = (*intf)->SetAlternateInterface(intf,0);
  944.     CheckError(err,"usbConnectToCam-SetAlternateInterface");
  945.  
  946.     return CameraErrorOK;
  947. }
  948.  
  949. - (void) usbCloseConnection {
  950.     IOReturn err;
  951.     if (intf) {                            //close our interface interface
  952.         if (isUSBOK) {
  953.             err = (*intf)->USBInterfaceClose(intf);
  954.         }
  955.         err = (*intf)->Release(intf);
  956.         CheckError(err,"usbCloseConnection-Release Interface");
  957.         intf=NULL;
  958.     }
  959.     if (dev) {                            //close our device interface
  960.         if (isUSBOK) {
  961.             err = (*dev)->USBDeviceClose(dev);
  962.         }
  963.         err = (*dev)->Release(dev);
  964.         CheckError(err,"usbCloseConnection-Release Device");
  965.         dev=NULL;
  966.     }
  967. }
  968.  
  969. - (BOOL) usbGetSoon:(UInt64*)to {            //Get a bus frame number in the near future
  970.     AbsoluteTime at;
  971.     IOReturn err;
  972.     UInt64 frame;
  973.     
  974.     if ((!to)||(!intf)||(!isUSBOK)) return NO;
  975.     err=(*intf)->GetBusFrameNumber(intf, &frame, &at);
  976.     CheckError(err,"usbGetSoon");
  977.     if (err) return NO;
  978.     *to=frame+100;                    //give it a little time to start
  979.     return YES;
  980. }
  981.  
  982. //Other tool functions
  983. - (BOOL) makeErrorImage:(CameraError) err {
  984.     switch (err) {
  985.         case CameraErrorOK:        return [self makeOKImage]; break;
  986.         default:            return [self makeMessageImage:[central localizedCStrForError:err]]; break;
  987.     }
  988. }
  989.  
  990. - (BOOL) makeMessageImage:(char*) msg {
  991.     BOOL draw;
  992.     [imageBufferLock lock];
  993.     lastImageBuffer=nextImageBuffer;
  994.     lastImageBufferBPP=nextImageBufferBPP;
  995.     lastImageBufferRowBytes=nextImageBufferRowBytes;
  996.     draw=nextImageBufferSet;
  997.     nextImageBufferSet=NO;    
  998.     if (draw) {
  999.         if (lastImageBuffer) {
  1000.             memset(lastImageBuffer,0,lastImageBufferRowBytes*[self height]);
  1001.             MiniDrawString(lastImageBuffer,lastImageBufferBPP,lastImageBufferRowBytes,10,10,msg);
  1002.         }
  1003.         [imageBufferLock unlock];
  1004.         [self mergeImageReady];                //notify delegate about the image. perhaps get a new buffer
  1005.     } else {
  1006.         [imageBufferLock unlock];
  1007.     }
  1008.     return draw;
  1009. }    
  1010.  
  1011. - (BOOL) makeOKImage {
  1012.     BOOL draw;
  1013.     char cstr[20];
  1014.     short x,bar,y,width,height,barend;
  1015.     UInt8 r,g,b;
  1016.     UInt8* bufRun;
  1017.     BOOL alpha;
  1018.     CFTimeInterval time;
  1019.     short h,m,s,f;
  1020.     [imageBufferLock lock];
  1021.     lastImageBuffer=nextImageBuffer;
  1022.     lastImageBufferBPP=nextImageBufferBPP;
  1023.     lastImageBufferRowBytes=nextImageBufferRowBytes;
  1024.     draw=nextImageBufferSet;
  1025.     nextImageBufferSet=NO;
  1026.     [imageBufferLock unlock];
  1027.     if (draw) {
  1028.         if (lastImageBuffer) {
  1029. //Draw color stripes
  1030.             alpha=lastImageBufferBPP==4;
  1031.             width=[self width];
  1032.             height=[self height];
  1033.             bufRun=lastImageBuffer;
  1034.             for (y=0;y<height;y++) {
  1035.                 x=0;
  1036.                 for (bar=0;bar<8;bar++) {
  1037.                     switch (bar) {
  1038.                         case 0: r=255;g=255;b=255;break;
  1039.                         case 1: r=255;g=255;b=0  ;break;
  1040.                         case 2: r=255;g=0  ;b=255;break;
  1041.                         case 3: r=0  ;g=255;b=255;break;
  1042.                         case 4: r=255;g=0  ;b=0  ;break;
  1043.                         case 5: r=0  ;g=255;b=0  ;break;
  1044.                         case 6: r=0  ;g=0  ;b=255;break;
  1045.                         default:r=0  ;g=0  ;b=0  ;break;
  1046.                     }
  1047.                     barend=((bar+1)*width)/8;
  1048.                     while (x<barend) {
  1049.                         if (alpha) bufRun++;
  1050.                         *(bufRun++)=r;
  1051.                         *(bufRun++)=g;
  1052.                         *(bufRun++)=b;
  1053.                         x++;
  1054.                     }
  1055.                 }
  1056.                 bufRun+=lastImageBufferRowBytes-width*lastImageBufferBPP;
  1057.             }
  1058.             time=CFAbsoluteTimeGetCurrent();
  1059.             h=(((long long)time)/(60*60))%24;
  1060.             m=(((long long)time)/(60))%60;
  1061.             s=((long long)time)%60;
  1062.             time*=100.0;
  1063.             f=((long long)(time))%100;
  1064.             sprintf(cstr,"%02i:%02i:%02i:%02i",h,m,s,f);
  1065.             MiniDrawString(lastImageBuffer,lastImageBufferBPP,lastImageBufferRowBytes,10,10,cstr);
  1066.             MiniDrawString(lastImageBuffer,lastImageBufferBPP,lastImageBufferRowBytes,10,23,
  1067.                             (char*)[[[self getCameraInfo] cameraName] cString]);
  1068.         }
  1069.         [self mergeImageReady];                //notify delegate about the image. perhaps get a new buffer
  1070.     }
  1071.     return draw;
  1072. }
  1073.  
  1074.  
  1075. - (void) stopUsingUSB {
  1076.     isUSBOK=NO;
  1077. }
  1078.  
  1079. @end
  1080.