Support multi-block directory listings.
[MacTF.git] / TFUSBController.m
blobda052376bc8824bf9173ce738c47947132418204
1 //
2 //  TFUSBController.m
3 //  MacTF
4 //
5 //  Created by Nathan Oates on Sun Aug 01 2004.
6 //  Copyright (c) 2004-7 Nathan Oates nathan@noates.com All rights reserved.
7 //
9 /* This file was modified by Kalle Olavi Niemitalo on 2007-10-18.  */
11 // includes code based on uproar, license noted below:
12 //  uproar 0.1
13 //  Copyright (c) 2001 Kasima Tharnpipitchai <me@kasima.org>
14 #import "TFUSBController.h"
15 #import "UIElements.h"
17 @implementation TFUSBController
19 /* 
20  *
21  * This source code is free software; you can redistribute it and/or
22  * modify it under the terms of the GNU Public License as published
23  * by the Free Software Foundation; either version 2 of the License,
24  * or (at your option) any later version.
25  *
26  * This source code is distributed in the hope that it will be useful,
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
29  * Please refer to the GNU Public License for more details.
30  *
31  * You should have received a copy of the GNU Public License along with
32  * this source code; if not, write to:
33  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34  */
38 /* Much of the code that initializes and closes the device is from Apple
39  * and is released under the license below.
40  */
43  * © Copyright 2001 Apple Computer, Inc. All rights reserved.
44  *
45  * IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc. (“Apple”) in 
46  * consideration of your agreement to the following terms, and your use, installation, 
47  * modification or redistribution of this Apple software constitutes acceptance of these
48  * terms.  If you do not agree with these terms, please do not use, install, modify or 
49  * redistribute this Apple software.
50  *
51  * In consideration of your agreement to abide by the following terms, and subject to these 
52  * terms, Apple grants you a personal, non exclusive license, under Apple’s copyrights in this 
53  * original Apple software (the “Apple Software”), to use, reproduce, modify and redistribute 
54  * the Apple Software, with or without modifications, in source and/or binary forms; provided 
55  * that if you redistribute the Apple Software in its entirety and without modifications, you 
56  * must retain this notice and the following text and disclaimers in all such redistributions 
57  * of the Apple Software.  Neither the name, trademarks, service marks or logos of Apple 
58  * Computer, Inc. may be used to endorse or promote products derived from the Apple Software 
59  * without specific prior written permission from Apple. Except as expressly stated in this 
60  * notice, no other rights or licenses, express or implied, are granted by Apple herein, 
61  * including but not limited to any patent rights that may be infringed by your derivative 
62  * works or by other works in which the Apple Software may be incorporated.
63  * 
64  * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO WARRANTIES, 
65  * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-
66  * INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE 
67  * SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 
68  *
69  * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL 
70  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 
71  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, 
72  * REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND 
73  * WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR 
74  * OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
75  */                     
78 #define         TopfieldVendorID        4571
79    //1317 for HC
80    //0x138c for humax
81    //4571 for toppy
82 #define         TF5kProdID      4096
83 //42514 for HC
84 //0x02ad for humax
85 //4096 for toppy
87 -(id) init {
88         if (self = [super init]) {
89                 debug = 0;
90                 rate = 0xfe00;
91                 transferQueue = [[NSMutableArray arrayWithCapacity:1] retain];
92                 pausedQueue = [[NSMutableArray arrayWithCapacity:1] retain];
93                 priorityTransferQueue = [[NSMutableArray arrayWithCapacity:1] retain];
94         }
95         return self;
98 void hexDump(UInt8 *buf, int len) {
99         int row, col, maxrows;
100         
101         maxrows = len/16;
102         if (len % 16) maxrows++;
103         for (row=0; row< maxrows; row++) {
104                 for (col=0; col<16; col++) {
105                         if (!(col%2)) printf(" ");
106                         printf("%02x", buf[row*16 + col] & 0xff);
107                 }
108                 printf("\t");   
109                 for (col=0; col<16; col++) {
110                         if ((buf[row*16 + col]>32) && (buf[row*16 + col]<126)) {
111                                 printf("%c", buf[row*16 + col]);
112                         }
113                         else { printf("."); }
114                 }
115                 printf("\n");
116         }
121 int doSend(IOUSBDeviceInterface197 **dev, IOUSBInterfaceInterface197 **intf,
122                 UInt8 *outBuf, UInt32 len, int type) 
124         IOReturn        err;
125         UInt32          sendLen;        
126         
127                 if (debug == 1){
128                         printf(("sending:\n"));
129             hexDump(outBuf, len);
130                 }
131                 sendLen = ((len/kBlockSize))*kBlockSize;
132         if (len % kBlockSize)
133             sendLen += kBlockSize;
134         if ((sendLen % 0x200) == 0)  
135                 sendLen += kBlockSize;
137         err = (*intf)->WritePipeTO(intf, 1, outBuf, sendLen, 1000, 20000);
138         if (err) {
139                 printf("write err: %08x\n", err);
140                 return err;
141         }
142         return err;
146 int doRecv(IOUSBDeviceInterface197 **dev, IOUSBInterfaceInterface197 **intf,
147             UInt8 *inBuf, UInt32 dataLen, int type) {
148         IOReturn        err;
149         UInt32          len;
150         
151         if (dataLen > kMaxXferSize) return 1;
152         
153         len = (dataLen/kBlockSize) * kBlockSize;
154         if (dataLen % kBlockSize)
155                 len += kBlockSize;
157                 err = (*intf)->ReadPipeTO(intf, 2, (void *)inBuf, &len,  1000, 20000);
158                 if (err) {
159                 printf("read err 2: %08x\n", err);
160                                 printf("resetting\n");
161                                 err = (*intf)->ClearPipeStallBothEnds(intf, 2); 
162                         return err;
163         }
164                 
165         if (debug == 1) {
166           printf(("receiving: \n")); 
167                         hexDump(inBuf, len);
168                 }
169         return err;
176 int dealWithInterface(io_service_t usbInterfaceRef, USBDeviceContext *device)
178     IOReturn                            err;
179     IOCFPlugInInterface                 **iodev;                // requires <IOKit/IOCFPlugIn.h>
180     IOUSBInterfaceInterface197          **intf;
181     IOUSBDeviceInterface197             **dev;
182     SInt32                              score;
183         UInt8                           numPipes, confNum, dSpeed;
186     err = IOCreatePlugInInterfaceForService(usbInterfaceRef, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
187     if (err || !iodev)
188     {
189         printf("dealWithInterface: unable to create plugin. ret = %08x, iodev = %p\n", err, iodev);
190         return kUproarDeviceErr;
191     }
192     err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)&(device->intf));
193     (*iodev)->Release(iodev);                           // done with this
194     intf = device->intf;
195     if (err || !intf)
196     {
197         printf("dealWithInterface: unable to create a device interface. ret = %08x, intf = %p\n", err, intf);
198         return kUproarDeviceErr;
199     }
200     
201     dev = device->dev;
202     err = (*intf)->USBInterfaceOpen(intf);
203     if (err)
204     {
205         printf("dealWithInterface: unable to open interface. ret = %08x\n", err);
206         return kUproarDeviceErr;
207     }
208     err = (*intf)->GetNumEndpoints(intf, &numPipes);
209     if (err)
210     {
211         printf("dealWithInterface: unable to get number of endpoints. ret = %08x\n", err);
212         return kUproarDeviceErr;
213     }
214     
215     printf("dealWithInterface: found %d pipes\n", numPipes);
217     err = (*intf)->GetConfigurationValue(intf, &confNum);
218     err = (*dev)->GetDeviceSpeed(dev, &dSpeed);
219         if (dSpeed == 2) {
220                 kBlockSize = 0x40;
221         } else {
222                 kBlockSize = 0x4;
223         }
224     printf("confnum: %08x, dspeed: %08x, blockS:%i\n", confNum, dSpeed, kBlockSize);
225     connectedSpeed = dSpeed;
226     return kUproarSuccess;
230 int dealWithDevice(io_service_t usbDeviceRef, USBDeviceContext *device)
232     IOReturn                            err;
233     IOCFPlugInInterface                 **iodev;                // requires <IOKit/IOCFPlugIn.h>
234     IOUSBDeviceInterface197             **dev;
235     SInt32                              score;
236     UInt8                               numConf;
237     IOUSBConfigurationDescriptorPtr     confDesc;
238     IOUSBFindInterfaceRequest           interfaceRequest;
239     io_iterator_t                       iterator;
240     io_service_t                        usbInterfaceRef;
241     int                                 found=0;
242     
243     
244     err = IOCreatePlugInInterfaceForService(usbDeviceRef, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
245     if (err || !iodev)
246     {
247         printf("dealWithDevice: unable to create plugin. ret = %08x, iodev = %p\n", err, iodev);
248         return kUproarDeviceErr;
249     }
250     err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID)&(device->dev));
251     (*iodev)->Release(iodev);                           
252     
253     dev = device->dev;
254     if (err || !dev)
255     {
256         printf("dealWithDevice: unable to create a device interface. ret = %08x, dev = %p\n", err, dev);
257         return kUproarDeviceErr;
258     }
259     err = (*dev)->USBDeviceOpen(dev);
260     if (err)
261     {
262         printf("dealWithDevice: unable to open device. ret = %08x\n", err);
263         return kUproarDeviceErr;
264     }
265     err = (*dev)->GetNumberOfConfigurations(dev, &numConf);
266     if (err || !numConf)
267     {
268         printf("dealWithDevice: unable to obtain the number of configurations. ret = %08x\n", err);
269         return kUproarDeviceErr;
270     }
271     printf("dealWithDevice: found %d configurations\n", numConf);
272     err = (*dev)->GetConfigurationDescriptorPtr(dev, 0, &confDesc);     // get the first config desc (index 0)
273     if (err)
274     {
275         printf("dealWithDevice:unable to get config descriptor for index 0\n");
276         return kUproarDeviceErr;
277     }
278     err = (*dev)->SetConfiguration(dev, confDesc->bConfigurationValue);
279     if (err)
280     {
281         printf("dealWithDevice: unable to set the configuration\n");
282         return kUproarDeviceErr;
283     }
285     interfaceRequest.bInterfaceClass = kIOUSBFindInterfaceDontCare;             // requested class
286     interfaceRequest.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;          // requested subclass
287     interfaceRequest.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;          // requested protocol
288     interfaceRequest.bAlternateSetting = kIOUSBFindInterfaceDontCare;           // requested alt setting
289     
290     err = (*dev)->CreateInterfaceIterator(dev, &interfaceRequest, &iterator);
291     if (err)
292     {
293         printf("dealWithDevice: unable to create interface iterator\n");
294         return kUproarDeviceErr;
295     }
296     
297     while (usbInterfaceRef = IOIteratorNext(iterator))
298     {
299         printf("found interface: %p\n", (void*)usbInterfaceRef);
300         err = dealWithInterface(usbInterfaceRef, device);
301         IOObjectRelease(usbInterfaceRef);       // no longer need this reference
302         found = 1;
303     }
304     
305     IOObjectRelease(iterator);
306     iterator = 0;
307     if ((!found) || (err))
308         return kUproarDeviceErr;
309     else
310         return kUproarSuccess;
314 int initDevice(USBDeviceContext *device){
315     mach_port_t         masterPort = 0;
316     kern_return_t               err;
317     CFMutableDictionaryRef      matchingDictionary = 0;         // requires <IOKit/IOKitLib.h>
318     short                       idVendor = TopfieldVendorID;
319     short                       idProduct = TF5kProdID;
320     CFNumberRef                 numberRef;
321     io_iterator_t               iterator = 0;
322     io_service_t                usbDeviceRef;
323     int                         found =0;
324     
325     err = IOMasterPort(bootstrap_port, &masterPort);                    
326     
327     if (err)
328     {
329         printf("Anchortest: could not create master port, err = %08x\n", err);
330         return err;
331     }
332     matchingDictionary = IOServiceMatching(kIOUSBDeviceClassName);      // requires <IOKit/usb/IOUSBLib.h>
333     if (!matchingDictionary)
334     {
335         printf("Anchortest: could not create matching dictionary\n");
336         return -1;
337     }
338     numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &idVendor);
339     if (!numberRef)
340     {
341         printf("Anchortest: could not create CFNumberRef for vendor\n");
342         return -1;
343     }
344     CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBVendorName), numberRef);
345     CFRelease(numberRef);
346     numberRef = 0;
347     numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &idProduct);
348     if (!numberRef)
349     {
350         printf("Anchortest: could not create CFNumberRef for product\n");
351         return -1;
352     }
353     CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBProductName), numberRef);
354     CFRelease(numberRef);
355     numberRef = 0;
356     
357     err = IOServiceGetMatchingServices(masterPort, matchingDictionary, &iterator);
358     matchingDictionary = 0;                     // this was consumed by the above call
359     
360     while (usbDeviceRef = IOIteratorNext(iterator))
361     {
362         printf("Found device %p\n", (void*)usbDeviceRef);
363         err = dealWithDevice(usbDeviceRef, device);
364         IOObjectRelease(usbDeviceRef);                  // no longer need this reference
365         found = 1;
366     }
367     
368     
369     IOObjectRelease(iterator);
370     iterator = 0;
371     mach_port_deallocate(mach_task_self(), masterPort);
372     if ((!found) || (err))
373         return kUproarDeviceErr;
374     else
375         return kUproarSuccess;
379 - (void) closeDevice:(USBDeviceContext *) device
381     IOUSBInterfaceInterface197  **intf;
382     IOUSBDeviceInterface197     **dev;
383     IOReturn                    err;
384     
385     intf = device->intf;
386     dev = device->dev;
387     
388     err = (*intf)->USBInterfaceClose(intf);
389     if (err)
390     {
391         printf("dealWithInterface: unable to close interface. ret = %08x\n", err);
392     }
393     err = (*intf)->Release(intf);
394     if (err)
395     {
396         printf("dealWithInterface: unable to release interface. ret = %08x\n", err);
397     }
398     
399     err = (*dev)->USBDeviceClose(dev);
400     if (err)
401     {
402         printf("dealWithDevice: error closing device - %08x\n", err);
403         (*dev)->Release(dev);
404     }
405     err = (*dev)->Release(dev);
406     if (err)
407     {
408         printf("dealWithDevice: error releasing device - %08x\n", err);
409     }
412 - (USBDeviceContext*) initializeUSB {
413         USBDeviceContext        *device;
414         int                     err;
415         kBlockSize = 0x08;
416         device = malloc(sizeof(USBDeviceContext));
417         err = initDevice(device);
418         if (err) {
419                 printf("Could not connect to Topfield\n");
420                 return nil;
421         }
422         printf("\n\n");
423         printf("Connected to Topfield\n\n");
424         myContext = device;
425         return device;
428 - (UIElements*) uiElements {
429         return [NSApp delegate];
432 - (NSData*) prepareFailWithECode:(UInt32)eCode {
433         const UInt32 eCode_bigendian = EndianU32_NtoB(eCode);
434         NSData* data = [NSData dataWithBytes:&eCode_bigendian length:4];
435         if (data == nil) // out of memory presumably
436                 return nil;
437         return [self prepareCommand:USB_Fail withData:data];
440 // Prepare a communication block that asks the Toppy to list the files
441 // in a directory.  Return the communication block, or nil on error.
442 - (NSData*) prepareCmdHddDirWithPath:(NSString*)path {
443         NSData *pathData = [path dataUsingEncoding:NSISOLatin1StringEncoding];
444         if (pathData == nil) // path contains characters unsupported by encoding
445                 return nil;
446         NSMutableData *cmdData = [NSMutableData dataWithData:pathData];
447         [cmdData increaseLengthBy:1]; // not sure if need to pad here?
448         return [self prepareCommand:USB_CmdHddDir withData:cmdData];
451 // Check the size and CRC of a received communication block.
452 // Return an ECODE to be sent back, or USB_OK.
453 - (UInt32) checkCommunicationBlock:(NSData*)block {
454         if (block == nil) return USB_Err_RunFail;
455         size_t length = [block length];
456         if (length < 8) return USB_Err_Size;
457         UInt16 crc16_bigendian;
458         [block getBytes:&crc16_bigendian range:(NSRange){2,2}];
459         UInt16 crc = EndianU16_BtoN(crc16_bigendian);
460         UInt16 calcCrc = [self findCRC:(const UInt8*)[block bytes]+4 length:length-4];
461         if (crc != calcCrc) return USB_Err_Crc;
462         return USB_OK;
465 - (UInt32) cmdFromCommunicationBlock:(NSData*)block {
466         UInt32 cmd_bigendian;
467         [block getBytes:&cmd_bigendian range:(NSRange){4,4}];
468         return EndianU32_BtoN(cmd_bigendian);
471 - (id) getFileListForPath:(NSString*) path {    
472         if (myContext == nil)
473                 return nil;
475         NSData* hddListCmd = [self prepareCmdHddDirWithPath:path];
476         if (hddListCmd == nil)
477                 return nil;
479         [self checkUSB:myContext]; // sends cancel and waits for response
480         int contiguousErrors = 0;
481         [[dh fileList] removeAllObjects];
482         NSData* response = [self sendCommand:hddListCmd toDevice:myContext
483                 expectResponse:YES careForReturn:YES];
484         while (response != nil && contiguousErrors++ < 5) {
485                 const UInt32 eCode = [self checkCommunicationBlock:response];
486                 if (eCode != USB_OK) {
487                         response = [self sendCommand:[self prepareFailWithECode:eCode]
488                                 toDevice:myContext expectResponse:YES careForReturn:YES];
489                 } else switch ([self cmdFromCommunicationBlock:response]) {
490                 case USB_Fail:
491 //                      [statusField setStringValue:NSLocalizedString(@"LAST_ERROR", @"Error on last command.")];
492                         [[dh fileList] removeAllObjects];
493                         response = [self sendCommand:hddListCmd toDevice:myContext
494                                 expectResponse:YES careForReturn:YES];
495                         break;
496                 case USB_DataHddDir:
497                         contiguousErrors = 0;
498                         size_t i;
499                         // Swapping sometimes adds a byte of padding.  The following uses
500                         // only complete 144-byte structures and so ignores such padding.
501                         for (i=0; 8+(i+1)*114 <= [response length]; i++) {
502                                 NSData* typeFile = [response subdataWithRange:(NSRange) {8+i*114,114}];
503                                 NSMutableDictionary* tfFile = [dh getTFFileFromSwappedHexData:typeFile];
504                                 if (![[tfFile objectForKey:@"name"] isEqualToString:@".."]) {
505                                         [dh convertRawDataToUseful:tfFile];
506                                         [[dh fileList] addObject:tfFile];
507                                 }
508                         }
509                         response = [self sendCommand:[self prepareCommand:USB_Success withData:nil]
510                                 toDevice:myContext expectResponse:YES careForReturn:YES];
511                         break;
512                 case USB_DataHddDirEnd:
513                         contiguousErrors = 0;
514                         response = nil;
515                         break;
516                 default:
517                         [self checkUSB:myContext]; // cancel whatever is going on
518                         [[dh fileList] removeAllObjects];
519                         response = [self sendCommand:hddListCmd toDevice:myContext
520                                 expectResponse:YES careForReturn:YES];
521                         break;
522                 }
523         }
525         [tableView reloadData];
526         [[self uiElements] tableView:tableView didClickTableColumn:[[self uiElements]selectedColumn]];
527         [[self uiElements] tableView:tableView didClickTableColumn:[[self uiElements]selectedColumn]]; //twice so get the same sort as before
528         return nil;
531 -(UInt16) findCRC:(const UInt8*)p length:(size_t) n
533         UInt16 m_crc16 = 0x0000;
534         static const UInt16 crc16Tbl[256] = {
535                 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
536                 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
537                 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
538                 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
539                 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
540                 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
541                 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
542                 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
543                 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
544                 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
545                 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
546                 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
547                 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
548                 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
549                 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
550                 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
551                 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
552                 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
553                 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
554                 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
555                 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
556                 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
557                 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
558                 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
559                 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
560                 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
561                 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
562                 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
563                 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
564                 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
565                 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
566                 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
567         };
568         size_t i;       
569         for(i = 0; i < n; i++)
570                         m_crc16 = (m_crc16 >> 8) ^ crc16Tbl[*p++ ^ (m_crc16 & 0xFF)];
571         return m_crc16;
574 - (NSData*) prepareCommand:(unsigned int)cmd withData:(NSData*) inData {        
575                 // work out length
576                 unsigned short int length = 0;
577                 if (inData == nil)
578                         length = 8;
579                 else {
580                         unsigned short int l = [inData length];
581                         length = l + 8;
582                 }
583                 const UInt16 length_bigendian = EndianU16_NtoB(length);
584                 NSMutableData* toSend = [NSMutableData dataWithBytes:&length_bigendian length:2];
585                 const UInt32 cmd_bigendian = EndianU32_NtoB(cmd);
586                 NSMutableData* build = [NSMutableData dataWithBytes:&cmd_bigendian length:4];
587                 if (inData != nil)
588                         [build appendData:inData];
589                 // work out crc
590                 UInt8 test[length];
591                 memset(test, 0, length);
592                 [build getBytes:test length:[build length]];
593                 unsigned short int crc = [self findCRC:test length:[build length]];
594                 const UInt16 crc_bigendian = EndianU16_NtoB(crc);
595                 [toSend appendData:[NSMutableData dataWithBytes:&crc_bigendian length:2]];
596                 [toSend appendData:build];
597                 // reverse and send
598                 toSend = [self swap:toSend];
599                 return toSend;
602 - (int) getFile:(NSDictionary*)fileInfo forPath:(NSString*)currentPath
603                 toSaveTo:(NSString*)savePath beginAtOffset:(unsigned long long) offset
604                 withLooping:(BOOL)looping existingTime:(NSTimeInterval)existingTime {   
605 //      [progressBar setDoubleValue:0];
606 //      [progressTime setDoubleValue:0];
607         NSString* nameOnToppy = [fileInfo objectForKey:@"name"];
608         [[[self uiElements] currentlyField] setStringValue:
609                 [NSLocalizedString(@"DOWNLOADING", @"Downloading: ") stringByAppendingString:nameOnToppy]];
610         [[[self uiElements] connectLight] setImage:[NSImage imageNamed:@"blink.tiff"]];
611         [[[self uiElements] currentlyField] displayIfNeeded];
612         //construct file send request
613         NSMutableString* fname = [NSMutableString stringWithString:[fileInfo objectForKey:@"name"]];
614         NSNumber* fileSize = [fileInfo objectForKey:@"fileSize"];
615         char dir = USB_FileToHost;
616         NSMutableData* build = [NSMutableData dataWithBytes:&dir length:1];
617         short int nsize = [fname length]+[currentPath length]+2;// one for slash, one for padding 0x00
618         const SInt16 nsize_bigendian = EndianS16_NtoB(nsize);
619         [build appendData:[NSData dataWithBytes:&nsize_bigendian length:2]];
620         NSData* d = [currentPath dataUsingEncoding:NSISOLatin1StringEncoding];
621         [build appendData:d];   
622         dir = 0x5c; // 0x5c = "/"
623         [build appendData:[NSData dataWithBytes:&dir length:1]];
624         [build appendData:[fname dataUsingEncoding:NSISOLatin1StringEncoding]];
625         dir = 0x00;
626         [build appendData:[NSData dataWithBytes:&dir length:1]];
627         //add 8 byte offset here
628         const UInt64 offset_bigendian = EndianU64_NtoB(offset);
629         [build appendData:[NSData dataWithBytes:&offset_bigendian length:8]];
630         
631         //prepackage commands to send
632         NSData* fileSendCmd = [self prepareCommand:USB_CmdHddFileSend withData:build];
633         NSData* usbSuccess = [self prepareCommand:USB_Success withData:nil];
634         NSData* usbCancel = [self prepareCommand:USB_Cancel withData:nil];
635         
636         // send commands
637         
638         if ([turboCB state]) 
639                 [self turnTurboOn:YES];
640         else
641                 [self checkUSB:myContext]; //turbo has a check itself
642         [self sendCommand:fileSendCmd toDevice:myContext expectResponse:YES careForReturn:NO];
643         //start timer
644         NSDate* startTime = [NSDate date];
645         startTime = [startTime addTimeInterval:(0-existingTime)];
646         // send start request and get response
647         NSData *data = [self sendCommand:usbSuccess toDevice:myContext expectResponse:YES careForReturn:YES];
648         const UInt32 rW_bigendian = EndianU32_NtoB(USB_DataHddFileData);
649         NSData *responseWanted = [NSData dataWithBytes:&rW_bigendian length:4];
650         if ([data length] < 16) {
651                 NSLog(@"Incorrect Data length");
652                 return 1;
653         }
654         NSData *responseToCheck = [data subdataWithRange:(NSRange) {4,4}];
655         if (![responseWanted isEqualToData:responseToCheck]) {
656                 NSLog(@"Unexpected response from Toppy during download");
657                 return 1;
658         }
659         
660         // clean up data and prepare path to save it
661         NSData* header = [data subdataWithRange:(NSRange) {4,4}]; //cmd data
662         NSData* finalData = [data subdataWithRange:(NSRange) {16,[data length]-16}];
663         
664         // first initialize a file of the right name, as NSFileHandle requires an existing file to work on
665         if (offset == 0)
666                 [[NSData dataWithBytes:&dir length:1] writeToFile:savePath atomically:NO]; // write 0x00 to initialize (overwritten later)
667         NSFileHandle* outFile = [NSFileHandle fileHandleForWritingAtPath:savePath];
668         [outFile seekToFileOffset:offset];
669         [outFile writeData:finalData];
670         if (looping) {  // loop for multiple data sends (ie files > 64k)
671                 int updateRate = 8; 
672                 if ([fileSize isGreaterThan:[NSNumber numberWithDouble:1048576]]) {
673                         updateRate = 24;
674                         NSLog(@"large file detected - low GUI update rate");
675                 }
676                 int timesAround = 0;
677                 const UInt32 test_bigendian = EndianU32_NtoB(USB_DataHddFileData);
678                 double amountReceived = 0xfe00 + offset;
679                 NSData* testData = [NSData dataWithBytes:&test_bigendian length:4];
680                 while ([header isEqualToData:testData] && [[[self uiElements] isConnected] intValue]) {
681                         if ([priorityTransferQueue count] != 0) {
682                                 [self addTransfer:[NSDictionary dictionaryWithObjectsAndKeys:
683                                                 fileInfo,@"filename", currentPath,@"path", savePath,@"savePath",
684                                                 [NSNumber numberWithUnsignedLongLong:amountReceived],@"offset",
685                                                 @"download",@"transferType", [NSNumber numberWithBool:YES],@"looping",
686                                                 [NSNumber numberWithInt:[[NSDate date] timeIntervalSinceDate:startTime]],@"existingTime",
687                                                 nil]
688                                         atIndex:1]; // nb adding to index 1 as the current transfer lies at 0 and will be deleted soon
689                                 // send reset again     just to make sure!
690                                 [self sendCommand:usbCancel toDevice:myContext expectResponse:YES careForReturn:NO];
691                                 [outFile closeFile];
692                                 //now add the right modification date to the file
693                                 [[NSFileManager defaultManager]
694                                         changeFileAttributes:[NSDictionary
695                                                 dictionaryWithObject:[fileInfo objectForKey:@"date"]
696                                                 forKey:@"NSFileModificationDate"]
697                                         atPath:savePath];
698                                 [self turnTurboOn:NO];
699                                 return 0;
700                         }
701                         timesAround ++;
702                         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];                             
703                         data = [self sendCommand:usbSuccess toDevice:myContext expectResponse:YES careForReturn:YES];
704                         amountReceived += 0xfe00;
705                         if (timesAround < 8 || timesAround % updateRate == 0) {
706                                 [NSThread detachNewThreadSelector:@selector(updateProgress:) toTarget:self
707                                         withObject:[NSDictionary dictionaryWithObjectsAndKeys:
708                                                 [NSNumber numberWithDouble:(double)amountReceived], @"offset",
709                                                 fileSize, @"size", startTime, @"startTime", nil]];
710                         }
711                         if ([data length] > 16){ //there is something to read 
712                                 header = [[data subdataWithRange:(NSRange) {4,4}] retain]; //cmd data
713                                 NSData* finalData = [data subdataWithRange:(NSRange) {16,[data length]-16}];
714                                 [outFile writeData:finalData];
715                                 [outFile synchronizeFile];
716                         } 
717                         else break;
718                         [pool release];
719                 }
720         }
721         [self sendCommand:usbCancel toDevice:myContext expectResponse:YES careForReturn:NO]; // send reset again        just to make sure!
722         [outFile closeFile];
723     //now add the right modification date to the file
724         [[NSFileManager defaultManager]
725                 changeFileAttributes:[NSDictionary
726                         dictionaryWithObject:[fileInfo objectForKey:@"date"]
727                         forKey:@"NSFileModificationDate"]
728                 atPath:savePath];
729         [self turnTurboOn:NO];
730         if (looping) [[self uiElements] finishTransfer];
731         return 0;
734 - (NSData*) sendCommand:(NSData*) fullyPackagedCommand
735                 toDevice:(USBDeviceContext*)device expectResponse:(BOOL) getResponse
736                 careForReturn:(BOOL) careFactor{
737         IOReturn        err;
738         int cmdLength = [fullyPackagedCommand length];
739         unsigned char outBuffer[cmdLength];
740         memset(outBuffer, 0, cmdLength);
741 //      NSLog(@"send: %@", [fullyPackagedCommand description]);
742         [fullyPackagedCommand getBytes:outBuffer];
743         
744         err = doSend(device->dev, device->intf, outBuffer, cmdLength, 2);
745         if (err)
746                 NSLog(@"sendError: %08x\n");
747         
748         if (! getResponse) return nil;
749         
750         int inLen = 0xFFFF; // i think this is biggest needed?
751         unsigned char inBuf[inLen];
752         memset(inBuf, 0, inLen);
753         err = doRecv(device->dev, device->intf, inBuf, inLen, 2);
754         if (err)
755                 NSLog(@"inError: %08x\n", err);
756         
757         if (! careFactor) return nil;
758         NSMutableData* data = [NSMutableData dataWithBytes:inBuf length:inLen];
759         data = [self swap:data];
760         inLen = inBuf[1]*256 + inBuf[0]; // work out how long the response really is. NB data is flipped, but inBuf still isn't
761         return [data subdataWithRange:(NSRange) {0,inLen}];
764 -(NSMutableData*) swap: (NSData*) inData {
765         int len = [inData length];
766         int uneven = 0;
767         if (len % 2 != 0) {
768                 uneven = 1; // prepare space for padding
769         }
770         char *array;
771         char *outarray;
772         if ((array = calloc((len + uneven), sizeof(char))) == NULL) {
773                 NSLog(@"ERROR: Malloc failed");
774                 return [NSMutableData dataWithData:inData];
775         }
776         if ((outarray = calloc((len + uneven), sizeof(char))) == NULL) {
777                 NSLog(@"ERROR: Malloc failed");
778                 return [NSMutableData dataWithData:inData];
779         }
780         [inData getBytes:array length:len];
781         swab(array, outarray, len+uneven);
782         NSMutableData* ret = [NSMutableData dataWithCapacity:len+uneven];
783         [ret setData:[NSData dataWithBytes:outarray length:len+uneven]];
784         free(array);
785         free(outarray);
786         return ret; 
789 - (void) uploadFile:(NSString*) fileToUpload ofSize:(long long) size
790                 fromPath:(NSString*)curPath withAttributes:(NSData*) typeFile
791                 atOffset:(unsigned long long)offset existingTime:(NSTimeInterval)existingTime {
792         NSLog(@"upload: %@,%@,%qu", fileToUpload, curPath, offset);
793         USBDeviceContext* dev = myContext;
794         // prepare Send command
795         NSMutableArray* array = [NSMutableArray arrayWithArray:[fileToUpload componentsSeparatedByString:@"/"]];
796         NSMutableString* fname = [NSMutableString stringWithString:[array lastObject]];
797         char dir = USB_FileToDevice;
798         NSMutableData* build = [NSMutableData dataWithBytes:&dir length:1];
799         short int nsize = [fname length]+[curPath length]+2;// one for slash, one for padding 0x00
800         const UInt16 nsize_bigendian = EndianU16_NtoB(nsize);
801         [build appendData:[NSData dataWithBytes:&nsize_bigendian length:2]];
802         NSData* d = [curPath dataUsingEncoding:NSISOLatin1StringEncoding];
803         [build appendData:d];
804         dir = 0x5c; // 0x5c = "/"
805         [build appendData:[NSData dataWithBytes:&dir length:1]];
806         [build appendData:[fname dataUsingEncoding:NSISOLatin1StringEncoding]];// may need to pad to 95...
807         if ([fname length] < 95)
808                 [build increaseLengthBy:95-[fname length]];
809         dir = 0x00;
810         [build appendData:[NSData dataWithBytes:&dir length:1]];
811         UInt64 offset_bigendian = EndianU64_NtoB(offset);
812         [build appendData:[NSData dataWithBytes:&offset_bigendian length:8]];
813         
814         // prepackage commands to send
815         NSData* fileSendCmd = [self prepareCommand:USB_CmdHddFileSend withData:build];
816         NSData* fileStartCmd = [self prepareCommand:USB_DataHddFileStart withData:typeFile];
817         NSData* fileEndCmd = [self prepareCommand:USB_DataHddFileEnd withData:nil];
819         //start timer
820         NSDate* startTime = [NSDate date];
821         startTime = [startTime addTimeInterval:(0-existingTime)];
822         //send commands
823         if ([turboCB state]) 
824                 [self turnTurboOn:YES];
825         else
826                 [self checkUSB:dev];
827         // now the proper commands
828         NSData *data = [self sendCommand:fileSendCmd toDevice:dev expectResponse:YES careForReturn:YES];
829         data = [self sendCommand:fileStartCmd toDevice:dev expectResponse:YES careForReturn:YES];
830         const UInt32 rW_bigendian = EndianU32_NtoB(USB_Success);
831         NSData* responseWanted = [NSData dataWithBytes:&rW_bigendian length:4];
832         NSData* responseToCheck = nil;
834         NSFileHandle* fileHandle = [NSFileHandle fileHandleForReadingAtPath:fileToUpload];
835         [fileHandle seekToFileOffset:offset];
836         do {
837                 if ([priorityTransferQueue count] != 0) {
838                         //break out and create a new transfer to continue it
839                         NSLog(@"pausing upload");
840                         [self addTransfer:[NSDictionary dictionaryWithObjectsAndKeys:
841                                         fileToUpload,@"filename",
842                                         [NSNumber numberWithUnsignedLongLong:size],@"fileSize",
843                                         curPath,@"path",typeFile,@"attributes",@"upload",@"transferType",
844                                         [NSNumber numberWithUnsignedLongLong:offset],@"offset",
845                                         [NSNumber numberWithInt:[[NSDate date] timeIntervalSinceDate:startTime]],@"existingTime",
846                                         nil]
847                                 atIndex:1]; //nb use index 1 as current transfer is at 0 and will be deleted
848                         [self turnTurboOn:NO];
849                         break;
850                 } else {
851                 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
852                 offset_bigendian = EndianU64_NtoB(offset);
853                 NSMutableData* fileData = [NSMutableData dataWithBytes:&offset_bigendian length:8];
854                 [fileData appendData:[fileHandle readDataOfLength:rate]];
855                 offset += rate;
856                 NSData* fileDataCmd = [self prepareCommand:USB_DataHddFileData withData:fileData];
857                 data = [self sendCommand:fileDataCmd toDevice:dev expectResponse:YES careForReturn:YES];
858                 if ([data length] >= 8) 
859                         responseToCheck = [data subdataWithRange:(NSRange) {4,4}];
860                 else responseToCheck = nil;
861                 if (responseToCheck == nil || ![responseWanted isEqualToData:responseToCheck]) 
862                         break;
863                 [NSThread detachNewThreadSelector:@selector(updateProgress:) toTarget:self
864                         withObject:[NSDictionary dictionaryWithObjectsAndKeys:
865                                 [NSNumber numberWithDouble:(double)offset], @"offset",
866                                 [NSNumber numberWithDouble:(double)size], @"size",
867                                 startTime, @"startTime", nil]];
868                 [pool release];
869                 }
870         } while (offset < size && [[[self uiElements] isConnected] intValue]);
871         if ([[[self uiElements] isConnected] intValue])
872                 data = [self sendCommand:fileEndCmd toDevice:dev expectResponse:YES careForReturn:YES];
873         [fileHandle closeFile]; 
874         [[self uiElements] goToPath:[[self uiElements]currentPath]];
875         [[self uiElements] tableView:tableView didClickTableColumn:[[self uiElements]selectedColumn]];
876         [[self uiElements] tableView:tableView didClickTableColumn:[[self uiElements]selectedColumn]]; //twice so get the same sort as before
877         [self turnTurboOn:NO];
878         [[self uiElements] finishTransfer];
882 - (void) turnTurboOn:(BOOL) turnOn {
883         if (![[[self uiElements] isConnected] intValue]) return;
884         [self checkUSB:myContext];
885         int mode = 0;
886         if (turnOn) 
887                 mode = 1;
888         const SInt32 mode_bigendian = EndianS32_NtoB(mode);
889         NSData* modeData = [NSData dataWithBytes:&mode_bigendian length:4];
890         NSLog([modeData description]); //debugging
891         NSData* turboCommand  = [self prepareCommand:USB_CmdTurbo withData:modeData];
892         [self sendCommand:turboCommand toDevice:myContext expectResponse:YES careForReturn:NO];
895 - (int) getSpeed {
896         return connectedSpeed;
899 -(void) setDebug:(int)mode {
900         debug = mode;
901         NSLog(@"Debug level: %i", debug);
904 -(void) setRate:(int) newRate {
905         rate = newRate;
906         NSLog(@"New rate set: %i", rate);
909 -(void) setProgressBar:(NSProgressIndicator*)bar time:(NSTextField*)timeField turbo:(NSButton*)turbo{
910         progressBar = bar;
911         progressTime = timeField;
912         turboCB = turbo;
915 -(void) updateProgress:(NSDictionary*) inDict {
916         NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
917         double offset = [[inDict objectForKey:@"offset"] doubleValue];
918         double size = [[inDict objectForKey:@"size"] doubleValue];
919         NSDate* startTime = [inDict objectForKey:@"startTime"];         
920         [progressBar setDoubleValue:((double)offset/size*100)];
921         [progressBar displayIfNeeded];
922         [progressTime setStringValue:[self elapsedTime:[[NSDate date] timeIntervalSinceDate:startTime]]];
923         [progressTime displayIfNeeded];
924         [pool release];
928 - (NSString*) elapsedTime:(NSTimeInterval) totalSeconds {
929         char hp = 20;
930         char mp = 20;
931         char sp = 20; //padding
932         int hours = (totalSeconds / 3600);  // returns number of whole hours fitted in totalSecs
933         if (hours < 10)
934                 hp = 48;
935         int minutes = ((totalSeconds / 60) - hours*60);  // Whole minutes
936         if (minutes < 10)
937                 mp = 48;
938         int seconds = ((long) totalSeconds % 60);       // Here we can use modulo to get num secs NOT fitting in whole minutes (60 secs)
939         if (seconds < 10)
940                 sp = 48;
941         return [NSString stringWithFormat:@"%c%i:%c%i:%c%i", hp, hours, mp, minutes, sp, seconds];
944 - (void) deleteFile:(NSDictionary*)fileInfo fromPath:(NSString*)currentPath {
945         [self checkUSB:myContext];
946         NSMutableString* fname = [NSMutableString stringWithString:[fileInfo objectForKey:@"name"]];
947         NSMutableData* build = [NSMutableData dataWithData:[currentPath dataUsingEncoding:NSISOLatin1StringEncoding]];
948         char dir = 0x5c; // 0x5c = "\"
949         [build appendData:[NSData dataWithBytes:&dir length:1]];
950         [build appendData:[fname dataUsingEncoding:NSISOLatin1StringEncoding]];
951         dir = 0x00;
952         [build appendData:[NSData dataWithBytes:&dir length:1]];
953         NSData* fileDelCmd = [self prepareCommand:USB_CmdHddDel withData:build];
954         [self sendCommand:fileDelCmd toDevice:myContext expectResponse:YES careForReturn:NO];
957 - (void) renameFile:(NSString*) oldName withName:(NSString*)newName atPath:(NSString*)currentPath {
958         NSLog(@"%@,%@,%@", oldName, newName, currentPath);
959         [self checkUSB:myContext];
960         unsigned short int i = [oldName length]+[currentPath length]+2;
961         UInt16 i_bigendian = EndianU16_NtoB(i);
962         NSMutableData* build = [NSMutableData dataWithBytes:&i_bigendian length:2];
963         [build appendData:[currentPath dataUsingEncoding:NSISOLatin1StringEncoding]];
964         char dir = 0x5c;
965         [build appendData:[NSData dataWithBytes:&dir length:1]];
966         [build appendData:[oldName dataUsingEncoding:NSISOLatin1StringEncoding]];
967         dir = 0x00;
968         [build appendData:[NSData dataWithBytes:&dir length:1]];
969         i = [newName length]+[currentPath length]+2;
970         i_bigendian = EndianU16_NtoB(i);
971         [build appendData:[NSData dataWithBytes:&i_bigendian length:2]];
972         [build appendData:[currentPath dataUsingEncoding:NSISOLatin1StringEncoding]];
973         dir = 0x5c;
974         [build appendData:[NSData dataWithBytes:&dir length:1]];
975         [build appendData:[newName dataUsingEncoding:NSISOLatin1StringEncoding]];
976         dir = 0x00;
977         [build appendData:[NSData dataWithBytes:&dir length:1]];
978         NSData* fileRenCmd = [self prepareCommand:USB_CmdHddRename withData:build];
979         [self sendCommand:fileRenCmd toDevice:myContext expectResponse:YES careForReturn:NO];
982 - (void) makeFolder:(NSString*)newName atPath:(NSString*)currentPath {
983         [self checkUSB:myContext];
984         unsigned short int i = [newName length]+[currentPath length]+2;
985         const UInt64 i_bigendian = EndianU16_NtoB(i);
986         NSMutableData* build = [NSMutableData dataWithBytes:&i_bigendian length:2];
987         [build appendData:[currentPath dataUsingEncoding:NSISOLatin1StringEncoding]];
988         char dir = 0x5c;
989         [build appendData:[NSData dataWithBytes:&dir length:1]];
990         [build appendData:[newName dataUsingEncoding:NSISOLatin1StringEncoding]];
991         dir = 0x00;
992         [build appendData:[NSData dataWithBytes:&dir length:1]];
993         NSData* newFoldCmd = [self prepareCommand:USB_CmdHddCreateDir withData:build];
994         NSData* usbCancel = [self prepareCommand:USB_Cancel withData:nil];
995         [self sendCommand:usbCancel toDevice:myContext expectResponse:YES careForReturn:NO];
996         [self sendCommand:newFoldCmd toDevice:myContext expectResponse:YES careForReturn:NO];
999 - (void) checkUSB:(USBDeviceContext*)device {
1000         NSData* usbCancel = [self prepareCommand:USB_Cancel withData:nil];
1001         NSData* data = [self sendCommand:usbCancel toDevice:device expectResponse:YES careForReturn:YES];
1002         const UInt32 rW_bigendian = EndianU32_NtoB(USB_Success);
1003         int i = 0;
1004         NSData* responseWanted = [NSData dataWithBytes:&rW_bigendian length:4];
1005         while ((data == nil || [data length] < 8) && i < 8) {
1006                 NSLog (@"incorrect response");
1007                 i++;
1008                 data = [self sendCommand:usbCancel toDevice:device expectResponse:YES careForReturn:YES];
1009         }
1010         if (!i<=8) {
1011                 // tell someone that no longer connected here??
1012                 return;
1013                 }
1014         NSData* responseToCheck = [data subdataWithRange:(NSRange) {4,4}];
1015         if (![responseWanted isEqualToData:responseToCheck]) {
1016                 [self sendCommand:usbCancel toDevice:device expectResponse:YES careForReturn:NO]; // send reset again   
1017         }
1020 - (void) transfer:(id)sender {
1021         while ([[[self uiElements] isConnected] intValue]) {
1022                 NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
1023                 if ([priorityTransferQueue count] != 0 ) {
1024                         id currentTransfer = [priorityTransferQueue objectAtIndex:0];
1025                         if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"fileList"]) {
1026                                 [self getFileListForPath:[currentTransfer objectForKey:@"path"]];
1027                                 [priorityTransferQueue removeObjectAtIndex:0];
1028 //                              NSLog(@"fL fin %i,p:%i",[transferQueue count],[priorityTransferQueue count]);
1029                         }
1030                         else if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"turbo"]) {
1031                 //              [self turnTurboOn:[[currentTransfer objectForKey:@"turboOn"] boolValue]];
1032                                 [priorityTransferQueue removeObjectAtIndex:0];
1033                         }
1034                         else if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"rename"]) {
1035                                 [self renameFile:[currentTransfer objectForKey:@"oldName"]
1036                                         withName:[currentTransfer objectForKey:@"newName"]
1037                                         atPath:[currentTransfer objectForKey:@"path"]];
1038                                 [priorityTransferQueue removeObjectAtIndex:0];
1039                         }
1040                         else if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"newFolder"]) {
1041                                 [self makeFolder:[currentTransfer objectForKey:@"newName"] atPath:[currentTransfer objectForKey:@"path"]];
1042                                 [priorityTransferQueue removeObjectAtIndex:0];
1043                         }
1044                         if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"delete"]) {
1045                                 [self deleteFile:[currentTransfer objectForKey:@"file"] fromPath:[currentTransfer objectForKey:@"path"]];
1046                                 [priorityTransferQueue removeObjectAtIndex:0];
1047                         }
1048                         if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"pause"]) {
1049                                 if ([transferQueue count] != 0) {
1050                                         NSArray* toPause = [transferQueue filteredArrayUsingPredicate:
1051                                                 [NSPredicate predicateWithFormat:@"(filename = %@)",
1052                                                         [currentTransfer objectForKey:@"filename"]]];
1053                                         if ([toPause count] > 1) NSLog(@"multiple pauses?");
1054                                         else {
1055                                                 [pausedQueue addObjectsFromArray:toPause];
1056                                                 [transferQueue removeObjectsInArray:toPause];
1057                                         }
1058                                 }
1059                                 [priorityTransferQueue removeObjectAtIndex:0];
1060                         }
1061                         if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"resume"]) {
1062                                 if ([pausedQueue count] != 0) {
1063                                         NSArray* toResume = [pausedQueue filteredArrayUsingPredicate:
1064                                                 [NSPredicate predicateWithFormat:@"(filename = %@)",
1065                                                         [currentTransfer objectForKey:@"filename"]]];
1066                                         if ([toResume count] > 1) NSLog(@"multiple resumes?");
1067                                         else {
1068                                                 [transferQueue addObjectsFromArray:toResume];
1069                                                 [pausedQueue removeObjectsInArray:toResume];
1070                                         }
1071                                 }
1072                                 [priorityTransferQueue removeObjectAtIndex:0];
1073                         }
1074                 }
1075                 else if ([transferQueue count] != 0) {
1076                         id currentTransfer = [transferQueue objectAtIndex:0];
1077                         if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"download"]) {
1078                                 [self getFile:[currentTransfer objectForKey:@"filename"]
1079                                         forPath:[currentTransfer objectForKey:@"path"]
1080                                         toSaveTo:[currentTransfer objectForKey:@"savePath"]
1081                                         beginAtOffset:[[currentTransfer objectForKey:@"offset"] unsignedLongLongValue]
1082                                         withLooping:[[currentTransfer objectForKey:@"looping"] boolValue]
1083                                         existingTime:[[currentTransfer objectForKey:@"existingTime"] intValue]];
1084                                 [transferQueue removeObjectAtIndex:0];
1085 //                              NSLog(@"dl fin %i,p:%i",[transferQueue count],[priorityTransferQueue count]);
1086                         }
1087                         else if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"upload"]) {
1088 //                              NSLog(@"ul start %i,p:%i",[transferQueue count],[priorityTransferQueue count]);
1089                                 [self uploadFile:[currentTransfer objectForKey:@"filename"]
1090                                         ofSize:[[currentTransfer objectForKey:@"fileSize"] unsignedLongLongValue]
1091                                         fromPath:[currentTransfer objectForKey:@"path"]
1092                                         withAttributes:[currentTransfer objectForKey:@"attributes"]
1093                                         atOffset:[[currentTransfer objectForKey:@"offset"] unsignedLongLongValue]
1094                                         existingTime:[[currentTransfer objectForKey:@"existingTime"] intValue]];
1095                                 [transferQueue removeObjectAtIndex:0];
1096 //                              NSLog(@"ul fin %i,p:%i",[transferQueue count],[priorityTransferQueue count]);
1097                         }
1098                 }
1099                 else usleep(100);
1100                 [pool release];
1101         }
1104 - (void) addPriorityTransfer:(id)newTransfer {
1105         [priorityTransferQueue addObject:newTransfer];
1106         NSLog(@"%i,p:%i-%@",[transferQueue count],[priorityTransferQueue count],[newTransfer objectForKey:@"transferType"]);
1109 - (void) addTransfer:(id)newTransfer atIndex:(int)front { //-1 for at end
1110         if (front>=0) [transferQueue insertObject:newTransfer atIndex:front];
1111         else [transferQueue addObject:newTransfer];
1112         NSLog(@"%i,p:%i",[transferQueue count],[priorityTransferQueue count]);
1115 - (void) setDH:(id)newDH tableView:(id)tv {
1116         dh = newDH;
1117         tableView = tv;
1120 - (void) clearQueues {
1121         [priorityTransferQueue removeAllObjects];
1122         [transferQueue removeAllObjects];
1123         [pausedQueue removeAllObjects];
1126 - (id) transferQueue {
1127         return transferQueue;
1130 - (id) pausedQueue {
1131         return pausedQueue;
1134 @end