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