5 // Created by Nathan Oates on Sun Aug 01 2004.
6 // Copyright (c) 2004-7 Nathan Oates nathan@noates.com All rights reserved.
9 /* This file was modified by Kalle Olavi Niemitalo on 2007-10-18. */
11 // includes code based on uproar, license noted below:
13 // Copyright (c) 2001 Kasima Tharnpipitchai <me@kasima.org>
14 #import "TFUSBController.h"
15 #import "UIElements.h"
17 @interface TFUSBController (PrivateMethods)
18 - (UInt32) checkCommunicationBlock:(NSData*)block;
19 - (UInt32) cmdFromCommunicationBlock:(NSData*)block;
20 - (BOOL) appendToData:(NSMutableData*)data sizeAndFname:(NSString*)fname;
21 - (NSData*) prepareFailWithECode:(UInt32)eCode;
22 - (NSData*) prepareSuccess;
23 - (NSData*) prepareCancel;
24 - (NSData*) prepareCmdHddDirWithPath:(NSString*)path;
25 - (NSData*) prepareCmdHddFileSendWithDirection:(UInt8)direction
26 fname:(NSString*)fname offset:(UInt64)offset;
27 - (NSData*) prepareDataHddFileEnd;
28 - (NSData*) prepareCmdTurboWithMode:(SInt32)mode;
29 - (NSData*) prepareCmdHddDelWithFname:(NSString*)fname;
30 - (UIElements*) uiElements;
33 @implementation TFUSBController
38 * This source code is free software; you can redistribute it and/or
39 * modify it under the terms of the GNU Public License as published
40 * by the Free Software Foundation; either version 2 of the License,
41 * or (at your option) any later version.
43 * This source code is distributed in the hope that it will be useful,
44 * but WITHOUT ANY WARRANTY; without even the implied warranty of
45 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
46 * Please refer to the GNU Public License for more details.
48 * You should have received a copy of the GNU Public License along with
49 * this source code; if not, write to:
50 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
55 /* Much of the code that initializes and closes the device is from Apple
56 * and is released under the license below.
60 * © Copyright 2001 Apple Computer, Inc. All rights reserved.
62 * IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. (“Apple”) in
63 * consideration of your agreement to the following terms, and your use, installation,
64 * modification or redistribution of this Apple software constitutes acceptance of these
65 * terms. If you do not agree with these terms, please do not use, install, modify or
66 * redistribute this Apple software.
68 * In consideration of your agreement to abide by the following terms, and subject to these
69 * terms, Apple grants you a personal, non exclusive license, under Apple’s copyrights in this
70 * original Apple software (the “Apple Software”), to use, reproduce, modify and redistribute
71 * the Apple Software, with or without modifications, in source and/or binary forms; provided
72 * that if you redistribute the Apple Software in its entirety and without modifications, you
73 * must retain this notice and the following text and disclaimers in all such redistributions
74 * of the Apple Software. Neither the name, trademarks, service marks or logos of Apple
75 * Computer, Inc. may be used to endorse or promote products derived from the Apple Software
76 * without specific prior written permission from Apple. Except as expressly stated in this
77 * notice, no other rights or licenses, express or implied, are granted by Apple herein,
78 * including but not limited to any patent rights that may be infringed by your derivative
79 * works or by other works in which the Apple Software may be incorporated.
81 * The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES,
82 * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-
83 * INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE
84 * SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
86 * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL
87 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
88 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE,
89 * REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND
90 * WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
91 * OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
95 #define TopfieldVendorID 4571
99 #define TF5kProdID 4096
104 // ---------------------------------------------------------------------------
106 // ---------------------------------------------------------------------------
108 int doSend(IOUSBDeviceInterface197 **dev, IOUSBInterfaceInterface197 **intf,
109 UInt8 *outBuf, UInt32 len, int type)
115 printf(("sending:\n"));
116 hexDump(outBuf, len);
118 sendLen = ((len/kBlockSize))*kBlockSize;
119 if (len % kBlockSize)
120 sendLen += kBlockSize;
121 if ((sendLen % 0x200) == 0)
122 sendLen += kBlockSize;
124 err = (*intf)->WritePipeTO(intf, 1, outBuf, sendLen, 1000, 20000);
126 printf("write err: %08x\n", err);
132 int doRecv(IOUSBDeviceInterface197 **dev, IOUSBInterfaceInterface197 **intf,
133 UInt8 *inBuf, UInt32 dataLen, int type) {
137 if (dataLen > kMaxXferSize) return 1;
139 len = (dataLen/kBlockSize) * kBlockSize;
140 if (dataLen % kBlockSize)
143 err = (*intf)->ReadPipeTO(intf, 2, (void *)inBuf, &len, 1000, 20000);
145 printf("read err 2: %08x\n", err);
146 printf("resetting\n");
147 err = (*intf)->ClearPipeStallBothEnds(intf, 2);
152 printf(("receiving: \n"));
158 int dealWithInterface(io_service_t usbInterfaceRef, USBDeviceContext *device)
161 IOCFPlugInInterface **iodev; // requires <IOKit/IOCFPlugIn.h>
162 IOUSBInterfaceInterface197 **intf;
163 IOUSBDeviceInterface197 **dev;
165 UInt8 numPipes, confNum, dSpeed;
168 err = IOCreatePlugInInterfaceForService(usbInterfaceRef, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
171 printf("dealWithInterface: unable to create plugin. ret = %08x, iodev = %p\n", err, iodev);
172 return kUproarDeviceErr;
174 err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)&(device->intf));
175 (*iodev)->Release(iodev); // done with this
179 printf("dealWithInterface: unable to create a device interface. ret = %08x, intf = %p\n", err, intf);
180 return kUproarDeviceErr;
184 err = (*intf)->USBInterfaceOpen(intf);
187 printf("dealWithInterface: unable to open interface. ret = %08x\n", err);
188 return kUproarDeviceErr;
190 err = (*intf)->GetNumEndpoints(intf, &numPipes);
193 printf("dealWithInterface: unable to get number of endpoints. ret = %08x\n", err);
194 return kUproarDeviceErr;
197 printf("dealWithInterface: found %d pipes\n", numPipes);
199 err = (*intf)->GetConfigurationValue(intf, &confNum);
200 err = (*dev)->GetDeviceSpeed(dev, &dSpeed);
206 printf("confnum: %08x, dspeed: %08x, blockS:%i\n", confNum, dSpeed, kBlockSize);
207 connectedSpeed = dSpeed;
208 return kUproarSuccess;
212 int dealWithDevice(io_service_t usbDeviceRef, USBDeviceContext *device)
215 IOCFPlugInInterface **iodev; // requires <IOKit/IOCFPlugIn.h>
216 IOUSBDeviceInterface197 **dev;
219 IOUSBConfigurationDescriptorPtr confDesc;
220 IOUSBFindInterfaceRequest interfaceRequest;
221 io_iterator_t iterator;
222 io_service_t usbInterfaceRef;
226 err = IOCreatePlugInInterfaceForService(usbDeviceRef, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
229 printf("dealWithDevice: unable to create plugin. ret = %08x, iodev = %p\n", err, iodev);
230 return kUproarDeviceErr;
232 err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID)&(device->dev));
233 (*iodev)->Release(iodev);
238 printf("dealWithDevice: unable to create a device interface. ret = %08x, dev = %p\n", err, dev);
239 return kUproarDeviceErr;
241 err = (*dev)->USBDeviceOpen(dev);
244 printf("dealWithDevice: unable to open device. ret = %08x\n", err);
245 return kUproarDeviceErr;
247 err = (*dev)->GetNumberOfConfigurations(dev, &numConf);
250 printf("dealWithDevice: unable to obtain the number of configurations. ret = %08x\n", err);
251 return kUproarDeviceErr;
253 printf("dealWithDevice: found %d configurations\n", numConf);
254 err = (*dev)->GetConfigurationDescriptorPtr(dev, 0, &confDesc); // get the first config desc (index 0)
257 printf("dealWithDevice:unable to get config descriptor for index 0\n");
258 return kUproarDeviceErr;
260 err = (*dev)->SetConfiguration(dev, confDesc->bConfigurationValue);
263 printf("dealWithDevice: unable to set the configuration\n");
264 return kUproarDeviceErr;
267 interfaceRequest.bInterfaceClass = kIOUSBFindInterfaceDontCare; // requested class
268 interfaceRequest.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; // requested subclass
269 interfaceRequest.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; // requested protocol
270 interfaceRequest.bAlternateSetting = kIOUSBFindInterfaceDontCare; // requested alt setting
272 err = (*dev)->CreateInterfaceIterator(dev, &interfaceRequest, &iterator);
275 printf("dealWithDevice: unable to create interface iterator\n");
276 return kUproarDeviceErr;
279 while (usbInterfaceRef = IOIteratorNext(iterator))
281 printf("found interface: %p\n", (void*)usbInterfaceRef);
282 err = dealWithInterface(usbInterfaceRef, device);
283 IOObjectRelease(usbInterfaceRef); // no longer need this reference
287 IOObjectRelease(iterator);
289 if ((!found) || (err))
290 return kUproarDeviceErr;
292 return kUproarSuccess;
296 int initDevice(USBDeviceContext *device){
297 mach_port_t masterPort = 0;
299 CFMutableDictionaryRef matchingDictionary = 0; // requires <IOKit/IOKitLib.h>
300 short idVendor = TopfieldVendorID;
301 short idProduct = TF5kProdID;
302 CFNumberRef numberRef;
303 io_iterator_t iterator = 0;
304 io_service_t usbDeviceRef;
307 err = IOMasterPort(bootstrap_port, &masterPort);
311 printf("Anchortest: could not create master port, err = %08x\n", err);
314 matchingDictionary = IOServiceMatching(kIOUSBDeviceClassName); // requires <IOKit/usb/IOUSBLib.h>
315 if (!matchingDictionary)
317 printf("Anchortest: could not create matching dictionary\n");
320 numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &idVendor);
323 printf("Anchortest: could not create CFNumberRef for vendor\n");
326 CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBVendorName), numberRef);
327 CFRelease(numberRef);
329 numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &idProduct);
332 printf("Anchortest: could not create CFNumberRef for product\n");
335 CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBProductName), numberRef);
336 CFRelease(numberRef);
339 err = IOServiceGetMatchingServices(masterPort, matchingDictionary, &iterator);
340 matchingDictionary = 0; // this was consumed by the above call
342 while (usbDeviceRef = IOIteratorNext(iterator))
344 printf("Found device %p\n", (void*)usbDeviceRef);
345 err = dealWithDevice(usbDeviceRef, device);
346 IOObjectRelease(usbDeviceRef); // no longer need this reference
351 IOObjectRelease(iterator);
353 mach_port_deallocate(mach_task_self(), masterPort);
354 if ((!found) || (err))
355 return kUproarDeviceErr;
357 return kUproarSuccess;
361 - (void) closeDevice:(USBDeviceContext *) device
363 IOUSBInterfaceInterface197 **intf;
364 IOUSBDeviceInterface197 **dev;
370 err = (*intf)->USBInterfaceClose(intf);
373 printf("dealWithInterface: unable to close interface. ret = %08x\n", err);
375 err = (*intf)->Release(intf);
378 printf("dealWithInterface: unable to release interface. ret = %08x\n", err);
381 err = (*dev)->USBDeviceClose(dev);
384 printf("dealWithDevice: error closing device - %08x\n", err);
385 (*dev)->Release(dev);
387 err = (*dev)->Release(dev);
390 printf("dealWithDevice: error releasing device - %08x\n", err);
394 - (USBDeviceContext*) initializeUSB {
395 USBDeviceContext *device;
398 device = malloc(sizeof(USBDeviceContext));
399 err = initDevice(device);
401 printf("Could not connect to Topfield\n");
405 printf("Connected to Topfield\n\n");
410 - (NSData*) sendCommand:(NSData*) fullyPackagedCommand
411 toDevice:(USBDeviceContext*)device expectResponse:(BOOL) getResponse
412 careForReturn:(BOOL) careFactor{
414 int cmdLength = [fullyPackagedCommand length];
415 unsigned char outBuffer[cmdLength];
416 memset(outBuffer, 0, cmdLength);
417 // NSLog(@"send: %@", [fullyPackagedCommand description]);
418 [fullyPackagedCommand getBytes:outBuffer];
420 err = doSend(device->dev, device->intf, outBuffer, cmdLength, 2);
422 NSLog(@"sendError: %08x\n");
424 if (! getResponse) return nil;
426 int inLen = 0xFFFF; // i think this is biggest needed?
427 unsigned char inBuf[inLen];
428 memset(inBuf, 0, inLen);
429 err = doRecv(device->dev, device->intf, inBuf, inLen, 2);
431 NSLog(@"inError: %08x\n", err);
433 if (! careFactor) return nil;
434 NSMutableData* data = [NSMutableData dataWithBytes:inBuf length:inLen];
435 data = [self swap:data];
436 inLen = inBuf[1]*256 + inBuf[0]; // work out how long the response really is. NB data is flipped, but inBuf still isn't
437 return [data subdataWithRange:(NSRange) {0,inLen}];
440 // ---------------------------------------------------------------------------
441 // Framing of communication blocks
442 // ---------------------------------------------------------------------------
444 -(UInt16) findCRC:(const UInt8*)p length:(size_t) n
446 UInt16 m_crc16 = 0x0000;
447 static const UInt16 crc16Tbl[256] = {
448 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
449 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
450 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
451 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
452 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
453 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
454 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
455 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
456 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
457 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
458 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
459 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
460 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
461 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
462 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
463 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
464 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
465 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
466 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
467 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
468 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
469 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
470 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
471 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
472 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
473 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
474 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
475 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
476 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
477 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
478 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
479 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
482 for(i = 0; i < n; i++)
483 m_crc16 = (m_crc16 >> 8) ^ crc16Tbl[*p++ ^ (m_crc16 & 0xFF)];
487 -(NSMutableData*) swap: (NSData*) inData {
488 int len = [inData length];
491 uneven = 1; // prepare space for padding
495 if ((array = calloc((len + uneven), sizeof(char))) == NULL) {
496 NSLog(@"ERROR: Malloc failed");
497 return [NSMutableData dataWithData:inData];
499 if ((outarray = calloc((len + uneven), sizeof(char))) == NULL) {
500 NSLog(@"ERROR: Malloc failed");
501 return [NSMutableData dataWithData:inData];
503 [inData getBytes:array length:len];
504 swab(array, outarray, len+uneven);
505 NSMutableData* ret = [NSMutableData dataWithCapacity:len+uneven];
506 [ret setData:[NSData dataWithBytes:outarray length:len+uneven]];
512 - (NSData*) prepareCommand:(UInt32)cmd withData:(NSData*) inData {
513 NSMutableData* block = [NSMutableData dataWithLength:8];
515 [block appendData:inData];
516 size_t blockLength = [block length];
517 if (blockLength > 0xFFFF)
518 return nil; // wouldn't fit in UInt16
520 UInt32 cmd_bigendian = EndianU32_NtoB(cmd);
521 [block replaceBytesInRange:(NSRange){4,4} withBytes:&cmd_bigendian];
523 UInt16 crc = [self findCRC:(const UInt8*)[block bytes]+4 length:blockLength-4];
524 UInt16 crc_bigendian = EndianU16_NtoB(crc);
525 [block replaceBytesInRange:(NSRange){2,2} withBytes:&crc_bigendian];
527 UInt16 blockLength_bigendian = EndianU16_NtoB(blockLength);
528 [block replaceBytesInRange:(NSRange){0,2} withBytes:&blockLength_bigendian];
530 return [self swap:block];
533 // Check the size and CRC of a received communication block.
534 // Return an ECODE to be sent back, or USB_OK.
535 - (UInt32) checkCommunicationBlock:(NSData*)block {
536 if (block == nil) return USB_Err_RunFail;
537 size_t length = [block length];
538 if (length < 8) return USB_Err_Size;
539 UInt16 crc16_bigendian;
540 [block getBytes:&crc16_bigendian range:(NSRange){2,2}];
541 UInt16 crc = EndianU16_BtoN(crc16_bigendian);
542 UInt16 calcCrc = [self findCRC:(const UInt8*)[block bytes]+4 length:length-4];
543 if (crc != calcCrc) return USB_Err_Crc;
547 - (UInt32) cmdFromCommunicationBlock:(NSData*)block {
548 UInt32 cmd_bigendian;
549 [block getBytes:&cmd_bigendian range:(NSRange){4,4}];
550 return EndianU32_BtoN(cmd_bigendian);
553 - (BOOL) appendToData:(NSMutableData*)data sizeAndFname:(NSString*)fname {
554 NSData* fnameData = [fname dataUsingEncoding:NSISOLatin1StringEncoding];
555 if (fnameData == nil) // fname contains characters unsupported by encoding
557 const size_t terminatorSize = 1;
558 const size_t nameSize = [fnameData length] + terminatorSize;
559 if (nameSize > 0xFFFF) // size would not fit in UInt16
561 const UInt16 nameSize_bigendian = EndianU16_NtoB(nameSize);
562 [data appendBytes:&nameSize_bigendian length:2];
563 [data appendData:fnameData];
564 [data increaseLengthBy:terminatorSize]; // fills with 0x00
568 // ---------------------------------------------------------------------------
569 // Preparing communication blocks for various commands
570 // ---------------------------------------------------------------------------
572 - (NSData*) prepareFailWithECode:(UInt32)eCode {
573 const UInt32 eCode_bigendian = EndianU32_NtoB(eCode);
574 NSData* data = [NSData dataWithBytes:&eCode_bigendian length:4];
575 if (data == nil) // out of memory presumably
577 return [self prepareCommand:USB_Fail withData:data];
580 - (NSData*) prepareSuccess {
581 return [self prepareCommand:USB_Success withData:nil];
584 - (NSData*) prepareCancel {
585 return [self prepareCommand:USB_Cancel withData:nil];
588 // Prepare a communication block that asks the Toppy to list the files
589 // in a directory. Return the communication block, or nil on error.
590 - (NSData*) prepareCmdHddDirWithPath:(NSString*)path {
591 NSData *pathData = [path dataUsingEncoding:NSISOLatin1StringEncoding];
592 if (pathData == nil) // path contains characters unsupported by encoding
594 NSMutableData *cmdData = [NSMutableData dataWithData:pathData];
595 [cmdData increaseLengthBy:1]; // not sure if need to pad here?
596 return [self prepareCommand:USB_CmdHddDir withData:cmdData];
599 - (NSData*) prepareCmdHddFileSendWithDirection:(UInt8)direction
600 fname:(NSString*)fname offset:(UInt64)offset
602 NSMutableData *cmdData = [NSMutableData dataWithBytes:&direction length:1];
603 if (cmdData == nil) // out of memory presumably
605 if (![self appendToData:cmdData sizeAndFname:fname])
607 const UInt64 offset_bigendian = EndianU64_NtoB(offset);
608 [cmdData appendBytes:&offset_bigendian length:8];
609 return [self prepareCommand:USB_CmdHddFileSend withData:cmdData];
612 - (NSData*) prepareDataHddFileEnd {
613 return [self prepareCommand:USB_DataHddFileEnd withData:nil];
616 - (NSData*) prepareCmdTurboWithMode:(SInt32)mode {
617 const SInt32 mode_bigendian = EndianS32_NtoB(mode);
618 NSData* cmdData = [NSData dataWithBytes:&mode_bigendian length:4];
619 if (cmdData == nil) // out of memory presumably
621 return [self prepareCommand:USB_CmdTurbo withData:cmdData];
624 - (NSData*) prepareCmdHddDelWithFname:(NSString*)fname {
625 NSData* fnameData = [fname dataUsingEncoding:NSISOLatin1StringEncoding];
626 if (fnameData == nil) // fname contains characters unsupported by encoding
628 NSMutableData *cmdData = [NSMutableData dataWithData:fnameData];
629 if (cmdData == nil) // out of memory presumably
631 [cmdData increaseLengthBy:1];
632 return [self prepareCommand:USB_CmdHddDel withData:cmdData];
635 // ---------------------------------------------------------------------------
636 // Protocol message sequences
637 // ---------------------------------------------------------------------------
639 - (id) getFileListForPath:(NSString*) path {
640 if (myContext == nil)
643 NSData* hddListCmd = [self prepareCmdHddDirWithPath:path];
644 if (hddListCmd == nil)
647 [self checkUSB:myContext]; // sends cancel and waits for response
648 int contiguousErrors = 0;
649 [[dh fileList] removeAllObjects];
650 NSData* response = [self sendCommand:hddListCmd toDevice:myContext
651 expectResponse:YES careForReturn:YES];
652 while (response != nil && contiguousErrors++ < 5) {
653 const UInt32 eCode = [self checkCommunicationBlock:response];
654 if (eCode != USB_OK) {
655 response = [self sendCommand:[self prepareFailWithECode:eCode]
656 toDevice:myContext expectResponse:YES careForReturn:YES];
657 } else switch ([self cmdFromCommunicationBlock:response]) {
659 // [statusField setStringValue:NSLocalizedString(@"LAST_ERROR", @"Error on last command.")];
660 [[dh fileList] removeAllObjects];
661 response = [self sendCommand:hddListCmd toDevice:myContext
662 expectResponse:YES careForReturn:YES];
665 contiguousErrors = 0;
667 // Swapping sometimes adds a byte of padding. The following uses
668 // only complete 144-byte structures and so ignores such padding.
669 for (i=0; 8+(i+1)*114 <= [response length]; i++) {
670 NSData* typeFile = [response subdataWithRange:(NSRange) {8+i*114,114}];
671 NSMutableDictionary* tfFile = [dh getTFFileFromSwappedHexData:typeFile];
672 if (![[tfFile objectForKey:@"name"] isEqualToString:@".."]) {
673 [dh convertRawDataToUseful:tfFile];
674 [[dh fileList] addObject:tfFile];
677 response = [self sendCommand:[self prepareSuccess]
678 toDevice:myContext expectResponse:YES careForReturn:YES];
680 case USB_DataHddDirEnd:
681 contiguousErrors = 0;
685 [self checkUSB:myContext]; // cancel whatever is going on
686 [[dh fileList] removeAllObjects];
687 response = [self sendCommand:hddListCmd toDevice:myContext
688 expectResponse:YES careForReturn:YES];
693 [tableView reloadData];
694 [[self uiElements] tableView:tableView didClickTableColumn:[[self uiElements]selectedColumn]];
695 [[self uiElements] tableView:tableView didClickTableColumn:[[self uiElements]selectedColumn]]; //twice so get the same sort as before
699 - (int) getFile:(NSDictionary*)fileInfo forPath:(NSString*)currentPath
700 toSaveTo:(NSString*)savePath beginAtOffset:(unsigned long long) offset
701 withLooping:(BOOL)looping existingTime:(NSTimeInterval)existingTime {
702 // [progressBar setDoubleValue:0];
703 // [progressTime setDoubleValue:0];
704 NSString* nameOnToppy = [fileInfo objectForKey:@"name"];
705 [[[self uiElements] currentlyField] setStringValue:
706 [NSLocalizedString(@"DOWNLOADING", @"Downloading: ") stringByAppendingString:nameOnToppy]];
707 [[[self uiElements] connectLight] setImage:[NSImage imageNamed:@"blink.tiff"]];
708 [[[self uiElements] currentlyField] displayIfNeeded];
709 //construct file send request
710 NSNumber* fileSize = [fileInfo objectForKey:@"fileSize"];
712 //prepackage commands to send
713 NSData* fileSendCmd = [self prepareCmdHddFileSendWithDirection:USB_FileToHost
714 fname:[NSString stringWithFormat:@"%@\\%@", currentPath, nameOnToppy]
716 NSData* usbSuccess = [self prepareSuccess];
717 NSData* usbCancel = [self prepareCancel];
722 [self turnTurboOn:YES];
724 [self checkUSB:myContext]; //turbo has a check itself
725 [self sendCommand:fileSendCmd toDevice:myContext expectResponse:YES careForReturn:NO];
727 NSDate* startTime = [NSDate date];
728 startTime = [startTime addTimeInterval:(0-existingTime)];
729 // send start request and get response
730 NSData *data = [self sendCommand:usbSuccess toDevice:myContext expectResponse:YES careForReturn:YES];
731 const UInt32 rW_bigendian = EndianU32_NtoB(USB_DataHddFileData);
732 NSData *responseWanted = [NSData dataWithBytes:&rW_bigendian length:4];
733 if ([data length] < 16) {
734 NSLog(@"Incorrect Data length");
737 NSData *responseToCheck = [data subdataWithRange:(NSRange) {4,4}];
738 if (![responseWanted isEqualToData:responseToCheck]) {
739 NSLog(@"Unexpected response from Toppy during download");
743 // clean up data and prepare path to save it
744 NSData* header = [data subdataWithRange:(NSRange) {4,4}]; //cmd data
745 NSData* finalData = [data subdataWithRange:(NSRange) {16,[data length]-16}];
747 // first initialize a file of the right name, as NSFileHandle requires an existing file to work on
749 [[NSData dataWithBytes:"\0" length:1] writeToFile:savePath atomically:NO]; // write 0x00 to initialize (overwritten later)
750 NSFileHandle* outFile = [NSFileHandle fileHandleForWritingAtPath:savePath];
751 [outFile seekToFileOffset:offset];
752 [outFile writeData:finalData];
753 if (looping) { // loop for multiple data sends (ie files > 64k)
755 if ([fileSize isGreaterThan:[NSNumber numberWithDouble:1048576]]) {
757 NSLog(@"large file detected - low GUI update rate");
760 const UInt32 test_bigendian = EndianU32_NtoB(USB_DataHddFileData);
761 double amountReceived = 0xfe00 + offset;
762 NSData* testData = [NSData dataWithBytes:&test_bigendian length:4];
763 while ([header isEqualToData:testData] && [[[self uiElements] isConnected] intValue]) {
764 if ([priorityTransferQueue count] != 0) {
765 [self addTransfer:[NSDictionary dictionaryWithObjectsAndKeys:
766 fileInfo,@"filename", currentPath,@"path", savePath,@"savePath",
767 [NSNumber numberWithUnsignedLongLong:amountReceived],@"offset",
768 @"download",@"transferType", [NSNumber numberWithBool:YES],@"looping",
769 [NSNumber numberWithInt:[[NSDate date] timeIntervalSinceDate:startTime]],@"existingTime",
771 atIndex:1]; // nb adding to index 1 as the current transfer lies at 0 and will be deleted soon
772 // send reset again just to make sure!
773 [self sendCommand:usbCancel toDevice:myContext expectResponse:YES careForReturn:NO];
775 //now add the right modification date to the file
776 [[NSFileManager defaultManager]
777 changeFileAttributes:[NSDictionary
778 dictionaryWithObject:[fileInfo objectForKey:@"date"]
779 forKey:@"NSFileModificationDate"]
781 [self turnTurboOn:NO];
785 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
786 data = [self sendCommand:usbSuccess toDevice:myContext expectResponse:YES careForReturn:YES];
787 amountReceived += 0xfe00;
788 if (timesAround < 8 || timesAround % updateRate == 0) {
789 [NSThread detachNewThreadSelector:@selector(updateProgress:) toTarget:self
790 withObject:[NSDictionary dictionaryWithObjectsAndKeys:
791 [NSNumber numberWithDouble:(double)amountReceived], @"offset",
792 fileSize, @"size", startTime, @"startTime", nil]];
794 if ([data length] > 16){ //there is something to read
795 header = [[data subdataWithRange:(NSRange) {4,4}] retain]; //cmd data
796 NSData* finalData = [data subdataWithRange:(NSRange) {16,[data length]-16}];
797 [outFile writeData:finalData];
798 [outFile synchronizeFile];
804 [self sendCommand:usbCancel toDevice:myContext expectResponse:YES careForReturn:NO]; // send reset again just to make sure!
806 //now add the right modification date to the file
807 [[NSFileManager defaultManager]
808 changeFileAttributes:[NSDictionary
809 dictionaryWithObject:[fileInfo objectForKey:@"date"]
810 forKey:@"NSFileModificationDate"]
812 [self turnTurboOn:NO];
813 if (looping) [[self uiElements] finishTransfer];
817 - (void) uploadFile:(NSString*) fileToUpload ofSize:(long long) size
818 fromPath:(NSString*)curPath withAttributes:(NSData*) typeFile
819 atOffset:(unsigned long long)offset existingTime:(NSTimeInterval)existingTime {
820 NSLog(@"upload: %@,%@,%qu", fileToUpload, curPath, offset);
821 USBDeviceContext* dev = myContext;
822 // prepare Send command
823 NSMutableArray* array = [NSMutableArray arrayWithArray:[fileToUpload componentsSeparatedByString:@"/"]];
824 NSMutableString* fname = [NSMutableString stringWithString:[array lastObject]];
825 char dir = USB_FileToDevice;
826 NSMutableData* build = [NSMutableData dataWithBytes:&dir length:1];
827 short int nsize = [fname length]+[curPath length]+2;// one for slash, one for padding 0x00
828 const UInt16 nsize_bigendian = EndianU16_NtoB(nsize);
829 [build appendData:[NSData dataWithBytes:&nsize_bigendian length:2]];
830 NSData* d = [curPath dataUsingEncoding:NSISOLatin1StringEncoding];
831 [build appendData:d];
832 dir = 0x5c; // 0x5c = "/"
833 [build appendData:[NSData dataWithBytes:&dir length:1]];
834 [build appendData:[fname dataUsingEncoding:NSISOLatin1StringEncoding]];// may need to pad to 95...
835 if ([fname length] < 95)
836 [build increaseLengthBy:95-[fname length]];
838 [build appendData:[NSData dataWithBytes:&dir length:1]];
839 UInt64 offset_bigendian = EndianU64_NtoB(offset);
840 [build appendData:[NSData dataWithBytes:&offset_bigendian length:8]];
842 // prepackage commands to send
843 NSData* fileSendCmd = [self prepareCommand:USB_CmdHddFileSend withData:build];
844 NSData* fileStartCmd = [self prepareCommand:USB_DataHddFileStart withData:typeFile];
845 NSData* fileEndCmd = [self prepareDataHddFileEnd];
848 NSDate* startTime = [NSDate date];
849 startTime = [startTime addTimeInterval:(0-existingTime)];
852 [self turnTurboOn:YES];
855 // now the proper commands
856 NSData *data = [self sendCommand:fileSendCmd toDevice:dev expectResponse:YES careForReturn:YES];
857 data = [self sendCommand:fileStartCmd toDevice:dev expectResponse:YES careForReturn:YES];
858 const UInt32 rW_bigendian = EndianU32_NtoB(USB_Success);
859 NSData* responseWanted = [NSData dataWithBytes:&rW_bigendian length:4];
860 NSData* responseToCheck = nil;
862 NSFileHandle* fileHandle = [NSFileHandle fileHandleForReadingAtPath:fileToUpload];
863 [fileHandle seekToFileOffset:offset];
865 if ([priorityTransferQueue count] != 0) {
866 //break out and create a new transfer to continue it
867 NSLog(@"pausing upload");
868 [self addTransfer:[NSDictionary dictionaryWithObjectsAndKeys:
869 fileToUpload,@"filename",
870 [NSNumber numberWithUnsignedLongLong:size],@"fileSize",
871 curPath,@"path",typeFile,@"attributes",@"upload",@"transferType",
872 [NSNumber numberWithUnsignedLongLong:offset],@"offset",
873 [NSNumber numberWithInt:[[NSDate date] timeIntervalSinceDate:startTime]],@"existingTime",
875 atIndex:1]; //nb use index 1 as current transfer is at 0 and will be deleted
876 [self turnTurboOn:NO];
879 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
880 offset_bigendian = EndianU64_NtoB(offset);
881 NSMutableData* fileData = [NSMutableData dataWithBytes:&offset_bigendian length:8];
882 [fileData appendData:[fileHandle readDataOfLength:rate]];
884 NSData* fileDataCmd = [self prepareCommand:USB_DataHddFileData withData:fileData];
885 data = [self sendCommand:fileDataCmd toDevice:dev expectResponse:YES careForReturn:YES];
886 if ([data length] >= 8)
887 responseToCheck = [data subdataWithRange:(NSRange) {4,4}];
888 else responseToCheck = nil;
889 if (responseToCheck == nil || ![responseWanted isEqualToData:responseToCheck])
891 [NSThread detachNewThreadSelector:@selector(updateProgress:) toTarget:self
892 withObject:[NSDictionary dictionaryWithObjectsAndKeys:
893 [NSNumber numberWithDouble:(double)offset], @"offset",
894 [NSNumber numberWithDouble:(double)size], @"size",
895 startTime, @"startTime", nil]];
898 } while (offset < size && [[[self uiElements] isConnected] intValue]);
899 if ([[[self uiElements] isConnected] intValue])
900 data = [self sendCommand:fileEndCmd toDevice:dev expectResponse:YES careForReturn:YES];
901 [fileHandle closeFile];
902 [[self uiElements] goToPath:[[self uiElements]currentPath]];
903 [[self uiElements] tableView:tableView didClickTableColumn:[[self uiElements]selectedColumn]];
904 [[self uiElements] tableView:tableView didClickTableColumn:[[self uiElements]selectedColumn]]; //twice so get the same sort as before
905 [self turnTurboOn:NO];
906 [[self uiElements] finishTransfer];
909 - (void) turnTurboOn:(BOOL) turnOn {
910 if (![[[self uiElements] isConnected] intValue]) return;
911 [self checkUSB:myContext];
912 NSData* turboCommand = [self prepareCmdTurboWithMode:(turnOn ? 1 : 0)];
913 [self sendCommand:turboCommand toDevice:myContext expectResponse:YES careForReturn:NO];
916 - (void) deleteFile:(NSDictionary*)fileInfo fromPath:(NSString*)currentPath {
917 [self checkUSB:myContext];
918 NSString* fname = [NSString stringWithFormat:@"%@\\%@",
919 currentPath, [fileInfo objectForKey:@"name"]];
920 NSData* fileDelCmd = [self prepareCmdHddDelWithFname:fname];
921 [self sendCommand:fileDelCmd toDevice:myContext expectResponse:YES careForReturn:NO];
924 - (void) renameFile:(NSString*) oldName withName:(NSString*)newName atPath:(NSString*)currentPath {
925 NSLog(@"%@,%@,%@", oldName, newName, currentPath);
926 [self checkUSB:myContext];
927 unsigned short int i = [oldName length]+[currentPath length]+2;
928 UInt16 i_bigendian = EndianU16_NtoB(i);
929 NSMutableData* build = [NSMutableData dataWithBytes:&i_bigendian length:2];
930 [build appendData:[currentPath dataUsingEncoding:NSISOLatin1StringEncoding]];
932 [build appendData:[NSData dataWithBytes:&dir length:1]];
933 [build appendData:[oldName dataUsingEncoding:NSISOLatin1StringEncoding]];
935 [build appendData:[NSData dataWithBytes:&dir length:1]];
936 i = [newName length]+[currentPath length]+2;
937 i_bigendian = EndianU16_NtoB(i);
938 [build appendData:[NSData dataWithBytes:&i_bigendian length:2]];
939 [build appendData:[currentPath dataUsingEncoding:NSISOLatin1StringEncoding]];
941 [build appendData:[NSData dataWithBytes:&dir length:1]];
942 [build appendData:[newName dataUsingEncoding:NSISOLatin1StringEncoding]];
944 [build appendData:[NSData dataWithBytes:&dir length:1]];
945 NSData* fileRenCmd = [self prepareCommand:USB_CmdHddRename withData:build];
946 [self sendCommand:fileRenCmd toDevice:myContext expectResponse:YES careForReturn:NO];
949 - (void) makeFolder:(NSString*)newName atPath:(NSString*)currentPath {
950 [self checkUSB:myContext];
951 unsigned short int i = [newName length]+[currentPath length]+2;
952 const UInt16 i_bigendian = EndianU16_NtoB(i);
953 NSMutableData* build = [NSMutableData dataWithBytes:&i_bigendian length:2];
954 [build appendData:[currentPath dataUsingEncoding:NSISOLatin1StringEncoding]];
956 [build appendData:[NSData dataWithBytes:&dir length:1]];
957 [build appendData:[newName dataUsingEncoding:NSISOLatin1StringEncoding]];
959 [build appendData:[NSData dataWithBytes:&dir length:1]];
960 NSData* newFoldCmd = [self prepareCommand:USB_CmdHddCreateDir withData:build];
961 NSData* usbCancel = [self prepareCancel];
962 [self sendCommand:usbCancel toDevice:myContext expectResponse:YES careForReturn:NO];
963 [self sendCommand:newFoldCmd toDevice:myContext expectResponse:YES careForReturn:NO];
966 - (void) checkUSB:(USBDeviceContext*)device {
967 NSData* usbCancel = [self prepareCancel];
968 NSData* data = [self sendCommand:usbCancel toDevice:device expectResponse:YES careForReturn:YES];
969 const UInt32 rW_bigendian = EndianU32_NtoB(USB_Success);
971 NSData* responseWanted = [NSData dataWithBytes:&rW_bigendian length:4];
972 while ((data == nil || [data length] < 8) && i < 8) {
973 NSLog (@"incorrect response");
975 data = [self sendCommand:usbCancel toDevice:device expectResponse:YES careForReturn:YES];
978 // tell someone that no longer connected here??
981 NSData* responseToCheck = [data subdataWithRange:(NSRange) {4,4}];
982 if (![responseWanted isEqualToData:responseToCheck]) {
983 [self sendCommand:usbCancel toDevice:device expectResponse:YES careForReturn:NO]; // send reset again
987 // ---------------------------------------------------------------------------
989 // ---------------------------------------------------------------------------
991 - (void) addPriorityTransfer:(id)newTransfer {
992 [priorityTransferQueue addObject:newTransfer];
993 NSLog(@"%i,p:%i-%@",[transferQueue count],[priorityTransferQueue count],[newTransfer objectForKey:@"transferType"]);
996 - (void) addTransfer:(id)newTransfer atIndex:(int)front { //-1 for at end
997 if (front>=0) [transferQueue insertObject:newTransfer atIndex:front];
998 else [transferQueue addObject:newTransfer];
999 NSLog(@"%i,p:%i",[transferQueue count],[priorityTransferQueue count]);
1002 - (void) clearQueues {
1003 [priorityTransferQueue removeAllObjects];
1004 [transferQueue removeAllObjects];
1005 [pausedQueue removeAllObjects];
1008 - (id) transferQueue {
1009 return transferQueue;
1012 - (id) pausedQueue {
1016 - (void) transfer:(id)sender {
1017 while ([[[self uiElements] isConnected] intValue]) {
1018 NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
1019 if ([priorityTransferQueue count] != 0 ) {
1020 id currentTransfer = [priorityTransferQueue objectAtIndex:0];
1021 if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"fileList"]) {
1022 [self getFileListForPath:[currentTransfer objectForKey:@"path"]];
1023 [priorityTransferQueue removeObjectAtIndex:0];
1024 // NSLog(@"fL fin %i,p:%i",[transferQueue count],[priorityTransferQueue count]);
1026 else if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"turbo"]) {
1027 // [self turnTurboOn:[[currentTransfer objectForKey:@"turboOn"] boolValue]];
1028 [priorityTransferQueue removeObjectAtIndex:0];
1030 else if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"rename"]) {
1031 [self renameFile:[currentTransfer objectForKey:@"oldName"]
1032 withName:[currentTransfer objectForKey:@"newName"]
1033 atPath:[currentTransfer objectForKey:@"path"]];
1034 [priorityTransferQueue removeObjectAtIndex:0];
1036 else if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"newFolder"]) {
1037 [self makeFolder:[currentTransfer objectForKey:@"newName"] atPath:[currentTransfer objectForKey:@"path"]];
1038 [priorityTransferQueue removeObjectAtIndex:0];
1040 if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"delete"]) {
1041 [self deleteFile:[currentTransfer objectForKey:@"file"] fromPath:[currentTransfer objectForKey:@"path"]];
1042 [priorityTransferQueue removeObjectAtIndex:0];
1044 if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"pause"]) {
1045 if ([transferQueue count] != 0) {
1046 NSArray* toPause = [transferQueue filteredArrayUsingPredicate:
1047 [NSPredicate predicateWithFormat:@"(filename = %@)",
1048 [currentTransfer objectForKey:@"filename"]]];
1049 if ([toPause count] > 1) NSLog(@"multiple pauses?");
1051 [pausedQueue addObjectsFromArray:toPause];
1052 [transferQueue removeObjectsInArray:toPause];
1055 [priorityTransferQueue removeObjectAtIndex:0];
1057 if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"resume"]) {
1058 if ([pausedQueue count] != 0) {
1059 NSArray* toResume = [pausedQueue filteredArrayUsingPredicate:
1060 [NSPredicate predicateWithFormat:@"(filename = %@)",
1061 [currentTransfer objectForKey:@"filename"]]];
1062 if ([toResume count] > 1) NSLog(@"multiple resumes?");
1064 [transferQueue addObjectsFromArray:toResume];
1065 [pausedQueue removeObjectsInArray:toResume];
1068 [priorityTransferQueue removeObjectAtIndex:0];
1071 else if ([transferQueue count] != 0) {
1072 id currentTransfer = [transferQueue objectAtIndex:0];
1073 if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"download"]) {
1074 [self getFile:[currentTransfer objectForKey:@"filename"]
1075 forPath:[currentTransfer objectForKey:@"path"]
1076 toSaveTo:[currentTransfer objectForKey:@"savePath"]
1077 beginAtOffset:[[currentTransfer objectForKey:@"offset"] unsignedLongLongValue]
1078 withLooping:[[currentTransfer objectForKey:@"looping"] boolValue]
1079 existingTime:[[currentTransfer objectForKey:@"existingTime"] intValue]];
1080 [transferQueue removeObjectAtIndex:0];
1081 // NSLog(@"dl fin %i,p:%i",[transferQueue count],[priorityTransferQueue count]);
1083 else if ([[currentTransfer objectForKey:@"transferType"] isEqualToString:@"upload"]) {
1084 // NSLog(@"ul start %i,p:%i",[transferQueue count],[priorityTransferQueue count]);
1085 [self uploadFile:[currentTransfer objectForKey:@"filename"]
1086 ofSize:[[currentTransfer objectForKey:@"fileSize"] unsignedLongLongValue]
1087 fromPath:[currentTransfer objectForKey:@"path"]
1088 withAttributes:[currentTransfer objectForKey:@"attributes"]
1089 atOffset:[[currentTransfer objectForKey:@"offset"] unsignedLongLongValue]
1090 existingTime:[[currentTransfer objectForKey:@"existingTime"] intValue]];
1091 [transferQueue removeObjectAtIndex:0];
1092 // NSLog(@"ul fin %i,p:%i",[transferQueue count],[priorityTransferQueue count]);
1100 // ---------------------------------------------------------------------------
1102 // ---------------------------------------------------------------------------
1104 - (UIElements*) uiElements {
1105 return [NSApp delegate];
1108 -(void) setProgressBar:(NSProgressIndicator*)bar time:(NSTextField*)timeField turbo:(NSButton*)turbo{
1110 progressTime = timeField;
1114 -(void) updateProgress:(NSDictionary*) inDict {
1115 NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
1116 double offset = [[inDict objectForKey:@"offset"] doubleValue];
1117 double size = [[inDict objectForKey:@"size"] doubleValue];
1118 NSDate* startTime = [inDict objectForKey:@"startTime"];
1119 [progressBar setDoubleValue:((double)offset/size*100)];
1120 [progressBar displayIfNeeded];
1121 [progressTime setStringValue:[self elapsedTime:[[NSDate date] timeIntervalSinceDate:startTime]]];
1122 [progressTime displayIfNeeded];
1126 - (NSString*) elapsedTime:(NSTimeInterval) totalSeconds {
1129 char sp = 20; //padding
1130 int hours = (totalSeconds / 3600); // returns number of whole hours fitted in totalSecs
1133 int minutes = ((totalSeconds / 60) - hours*60); // Whole minutes
1136 int seconds = ((long) totalSeconds % 60); // Here we can use modulo to get num secs NOT fitting in whole minutes (60 secs)
1139 return [NSString stringWithFormat:@"%c%i:%c%i:%c%i", hp, hours, mp, minutes, sp, seconds];
1142 - (void) setDH:(id)newDH tableView:(id)tv {
1147 // ---------------------------------------------------------------------------
1149 // ---------------------------------------------------------------------------
1152 if (self = [super init]) {
1155 transferQueue = [[NSMutableArray arrayWithCapacity:1] retain];
1156 pausedQueue = [[NSMutableArray arrayWithCapacity:1] retain];
1157 priorityTransferQueue = [[NSMutableArray arrayWithCapacity:1] retain];
1162 void hexDump(UInt8 *buf, int len) {
1163 int row, col, maxrows;
1166 if (len % 16) maxrows++;
1167 for (row=0; row< maxrows; row++) {
1168 for (col=0; col<16; col++) {
1169 if (!(col%2)) printf(" ");
1170 printf("%02x", buf[row*16 + col] & 0xff);
1173 for (col=0; col<16; col++) {
1174 if ((buf[row*16 + col]>32) && (buf[row*16 + col]<126)) {
1175 printf("%c", buf[row*16 + col]);
1177 else { printf("."); }
1184 return connectedSpeed;
1187 -(void) setDebug:(int)mode {
1189 NSLog(@"Debug level: %i", debug);
1192 -(void) setRate:(int) newRate {
1194 NSLog(@"New rate set: %i", rate);