Prominent notice in TFUSBController.m.
[MacTF.git] / USBFunctions.m
bloba584832800c604b54377e1599ddaa8182df308ad
1 //
2 //  USBFunctions.m
3 //  MacTF
4 //
5 //  Created by Nathan Oates on Sun Aug 01 2004.
6 //  Copyright (c) 2004 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 "USBFunctions.h"
14 @implementation USBFunctions
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         kCmd                    0
76 #define         kFin                    1
77 #define         kDat                    2
79 #define         kTopfieldVendorID       4571
80    //1317 for HC
81    //0x138c for humax
82    //4571 for toppy
83 #define         kTF5kProdID     4096
84 //42514 for HC
85 //0x02ad for humax
86 //4096 for toppy
87 -(id) init {
88         id ret = [super init];
89         debug = 0;
90         rate = 0xfe00;
91         return ret;
95 void hexDump(UInt8 *buf, int len) {
96         int row, col, maxrows;
97         
98         maxrows = len/16;
99         if (len % 16) maxrows++;
100         for (row=0; row< maxrows; row++) {
101                 for (col=0; col<16; col++) {
102                         if (!(col%2)) printf(" ");
103                         printf("%02x", buf[row*16 + col] & 0xff);
104                 }
105                 printf("\t");   
106                 for (col=0; col<16; col++) {
107                         if ((buf[row*16 + col]>32) && (buf[row*16 + col]<126)) {
108                                 printf("%c", buf[row*16 + col]);
109                         }
110                         else { printf("."); }
111                 }
112                 printf("\n");
113         }
118 int doSend(IOUSBDeviceInterface197 **dev, IOUSBInterfaceInterface197 **intf,
119                 char *outBuf, UInt32 len, int type) 
121         IOReturn        err;
122         UInt32          sendLen;
123         
124         
125                 if (debug == 1){
126                         printf(("sending:\n"));
127             hexDump(outBuf, len);
128                 }
129                 sendLen = ((len/kBlockSize))*kBlockSize;
130         if (len % kBlockSize)
131             sendLen += kBlockSize;
132         if ((sendLen % 0x200) == 0)  
133                 sendLen += kBlockSize;
134   //      if (type == kFin) //          err = beginInitiateRequest(dev); //  else  //    err = beginCmdSendRequest(dev);
135         err = (*intf)->WritePipeTO(intf, 1, outBuf, sendLen, 1000, 20000);
136         if (err) {
137                 printf("write err: %08x\n", err);
138                 return err;
139         }
140 //      err = endRequest(dev);
141         return err;
145 int doRecv(IOUSBDeviceInterface197 **dev, IOUSBInterfaceInterface197 **intf,
146             UInt8 *inBuf, UInt32 dataLen, int type) {
147         IOReturn        err;
148         UInt32          len;
149         
150         if (dataLen > kMaxXferSize) return 1;
151         
152         len = (dataLen/kBlockSize) * kBlockSize;
153         if (dataLen % kBlockSize)
154                 len += kBlockSize;
156                 err = (*intf)->ReadPipeTO(intf, 2, (void *)inBuf, &len,  1000, 20000);
157                 if (err) {
158                 printf("read err 2: %08x\n", err);
159                                 printf("resetting\n");
160                                 err = (*intf)->ClearPipeStallBothEnds(intf, 2); 
161                         return err;
162         }
164                 
165         if (debug == 1) {
166           printf(("receiving: \n")); 
167                         hexDump(inBuf, len);
168                 }
169         return err;
176 int dealWithInterface(io_service_t usbInterfaceRef, USBDeviceContext *device)
178     IOReturn                            err;
179     IOCFPlugInInterface                 **iodev;                // requires <IOKit/IOCFPlugIn.h>
180     IOUSBInterfaceInterface197          **intf;
181     IOUSBDeviceInterface197             **dev;
182     SInt32                              score;
183         UInt8                           numPipes, confNum, dSpeed;
186     err = IOCreatePlugInInterfaceForService(usbInterfaceRef, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
187     if (err || !iodev)
188     {
189         printf("dealWithInterface: unable to create plugin. ret = %08x, iodev = %p\n", err, iodev);
190         return kUproarDeviceErr;
191     }
192     err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)&(device->intf));
193     (*iodev)->Release(iodev);                           // done with this
194     if (err || !intf)
195     {
196         printf("dealWithInterface: unable to create a device interface. ret = %08x, intf = %p\n", err, intf);
197         return kUproarDeviceErr;
198     }
199     
200     intf = device->intf;
201     dev = device->dev;
202     err = (*intf)->USBInterfaceOpen(intf);
203     if (err)
204     {
205         printf("dealWithInterface: unable to open interface. ret = %08x\n", err);
206         return kUproarDeviceErr;
207     }
208     err = (*intf)->GetNumEndpoints(intf, &numPipes);
209     if (err)
210     {
211         printf("dealWithInterface: unable to get number of endpoints. ret = %08x\n", err);
212         return kUproarDeviceErr;
213     }
214     
215     printf("dealWithInterface: found %d pipes\n", numPipes);
217     err = (*intf)->GetConfigurationValue(intf, &confNum);
218     err = (*dev)->GetDeviceSpeed(dev, &dSpeed);
219         if (dSpeed == 2) {
220                 kBlockSize = 0x40;
221         } else {
222                 kBlockSize = 0x4;
223         }
224     printf("confnum: %08x, dspeed: %08x, blockS:%i\n", confNum, dSpeed, kBlockSize);
225     connectedSpeed = dSpeed;
226     return kUproarSuccess;
230 int dealWithDevice(io_service_t usbDeviceRef, USBDeviceContext *device)
232     IOReturn                            err;
233     IOCFPlugInInterface                 **iodev;                // requires <IOKit/IOCFPlugIn.h>
234     IOUSBDeviceInterface197             **dev;
235     SInt32                              score;
236     UInt8                               numConf;
237     IOUSBConfigurationDescriptorPtr     confDesc;
238     IOUSBFindInterfaceRequest           interfaceRequest;
239     io_iterator_t                       iterator;
240     io_service_t                        usbInterfaceRef;
241     int                                 found=0;
242     
243     
244     err = IOCreatePlugInInterfaceForService(usbDeviceRef, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
245     if (err || !iodev)
246     {
247         printf("dealWithDevice: unable to create plugin. ret = %08x, iodev = %p\n", err, iodev);
248         return kUproarDeviceErr;
249     }
250     err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID)&(device->dev));
251     (*iodev)->Release(iodev);                           
252     
253     dev = device->dev;
254     if (err || !dev)
255     {
256         printf("dealWithDevice: unable to create a device interface. ret = %08x, dev = %p\n", err, dev);
257         return kUproarDeviceErr;
258     }
259     err = (*dev)->USBDeviceOpen(dev);
260     if (err)
261     {
262         printf("dealWithDevice: unable to open device. ret = %08x\n", err);
263         return kUproarDeviceErr;
264     }
265     err = (*dev)->GetNumberOfConfigurations(dev, &numConf);
266     if (err || !numConf)
267     {
268         printf("dealWithDevice: unable to obtain the number of configurations. ret = %08x\n", err);
269         return kUproarDeviceErr;
270     }
271     printf("dealWithDevice: found %d configurations\n", numConf);
272     err = (*dev)->GetConfigurationDescriptorPtr(dev, 0, &confDesc);     // get the first config desc (index 0)
273     if (err)
274     {
275         printf("dealWithDevice:unable to get config descriptor for index 0\n");
276         return kUproarDeviceErr;
277     }
278     err = (*dev)->SetConfiguration(dev, confDesc->bConfigurationValue);
279     if (err)
280     {
281         printf("dealWithDevice: unable to set the configuration\n");
282         return kUproarDeviceErr;
283     }
285     interfaceRequest.bInterfaceClass = kIOUSBFindInterfaceDontCare;             // requested class
286     interfaceRequest.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;          // requested subclass
287     interfaceRequest.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;          // requested protocol
288     interfaceRequest.bAlternateSetting = kIOUSBFindInterfaceDontCare;           // requested alt setting
289     
290     err = (*dev)->CreateInterfaceIterator(dev, &interfaceRequest, &iterator);
291     if (err)
292     {
293         printf("dealWithDevice: unable to create interface iterator\n");
294         return kUproarDeviceErr;
295     }
296     
297     while (usbInterfaceRef = IOIteratorNext(iterator))
298     {
299         printf("found interface: %p\n", (void*)usbInterfaceRef);
300         err = dealWithInterface(usbInterfaceRef, device);
301         IOObjectRelease(usbInterfaceRef);       // no longer need this reference
302         found = 1;
303     }
304     
305     IOObjectRelease(iterator);
306     iterator = 0;
307     if ((!found) || (err))
308         return kUproarDeviceErr;
309     else
310         return kUproarSuccess;
314 int initDevice(USBDeviceContext *device){
315     mach_port_t         masterPort = 0;
316     kern_return_t               err;
317     CFMutableDictionaryRef      matchingDictionary = 0;         // requires <IOKit/IOKitLib.h>
318     short                       idVendor = kTopfieldVendorID;
319     short                       idProduct = kTF5kProdID;
320     CFNumberRef                 numberRef;
321     io_iterator_t               iterator = 0;
322     io_service_t                usbDeviceRef;
323     int                         found =0;
324     
325     err = IOMasterPort(bootstrap_port, &masterPort);                    
326     
327     if (err)
328     {
329         printf("Anchortest: could not create master port, err = %08x\n", err);
330         return err;
331     }
332     matchingDictionary = IOServiceMatching(kIOUSBDeviceClassName);      // requires <IOKit/usb/IOUSBLib.h>
333     if (!matchingDictionary)
334     {
335         printf("Anchortest: could not create matching dictionary\n");
336         return -1;
337     }
338     numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &idVendor);
339     if (!numberRef)
340     {
341         printf("Anchortest: could not create CFNumberRef for vendor\n");
342         return -1;
343     }
344     CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBVendorName), numberRef);
345     CFRelease(numberRef);
346     numberRef = 0;
347     numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &idProduct);
348     if (!numberRef)
349     {
350         printf("Anchortest: could not create CFNumberRef for product\n");
351         return -1;
352     }
353     CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBProductName), numberRef);
354     CFRelease(numberRef);
355     numberRef = 0;
356     
357     err = IOServiceGetMatchingServices(masterPort, matchingDictionary, &iterator);
358     matchingDictionary = 0;                     // this was consumed by the above call
359     
360     while (usbDeviceRef = IOIteratorNext(iterator))
361     {
362         printf("Found device %p\n", (void*)usbDeviceRef);
363         err = dealWithDevice(usbDeviceRef, device);
364         IOObjectRelease(usbDeviceRef);                  // no longer need this reference
365         found = 1;
366     }
367     
368     
369     IOObjectRelease(iterator);
370     iterator = 0;
371     mach_port_deallocate(mach_task_self(), masterPort);
372     if ((!found) || (err))
373         return kUproarDeviceErr;
374     else
375         return kUproarSuccess;
379 - (void) closeDevice:(USBDeviceContext *) device
381     IOUSBInterfaceInterface197  **intf;
382     IOUSBDeviceInterface197     **dev;
383     IOReturn                    err;
384     
385     intf = device->intf;
386     dev = device->dev;
387     
388     err = (*intf)->USBInterfaceClose(intf);
389     if (err)
390     {
391         printf("dealWithInterface: unable to close interface. ret = %08x\n", err);
392     }
393     err = (*intf)->Release(intf);
394     if (err)
395     {
396         printf("dealWithInterface: unable to release interface. ret = %08x\n", err);
397     }
398     
399     err = (*dev)->USBDeviceClose(dev);
400     if (err)
401     {
402         printf("dealWithDevice: error closing device - %08x\n", err);
403         (*dev)->Release(dev);
404     }
405     err = (*dev)->Release(dev);
406     if (err)
407     {
408         printf("dealWithDevice: error releasing device - %08x\n", err);
409     }
412 - (USBDeviceContext*) initializeUSB {
413                                 USBDeviceContext        *device;
414                                 int                     err;
415         kBlockSize = 0x08;
416         device = malloc(sizeof(USBDeviceContext));
417         err = initDevice(device);
418         if (err) {
419                 printf("Could not connect to Topfield\n");
420                 return nil;
421         }
422         printf("\n\n");
423         printf("Connected to Topfield\n\n");
424         myContext = device;
425         return device;
428 - (NSData*) getHDDSize:(USBDeviceContext*)device  {
429         IOReturn        err;
430         UInt8           outBuf[8], inBuf[64];
431         UInt32          len;
432         [self checkUSB:device];
433         memset(outBuf, 0, 8);
434         memset(inBuf, 0, 64);
435         outBuf[0] = 0x08; //08000dc000000010 = request for HDD size info
436         outBuf[1] = 0x00;
437         outBuf[2] = 0x0d;
438         outBuf[3] = 0xc0;
439         outBuf[6] = 0x00;
440         outBuf[7] = 0x10;
441         
442         err = doSend(device->dev, device->intf, outBuf, 8, kDat);
443         len = 64;
444         err = doRecv(device->dev, device->intf, inBuf, len, kDat);
445                          
446         NSData* data = [NSData dataWithBytes:inBuf length:16];
447         data = [self swap:data];
448         return data;
452 - (NSData*) getFileList:(USBDeviceContext*)device forPath:(NSString*) path {    
453         if (device == nil)
454                 return nil;
455         
456         // turn path into data
457         NSMutableData *pathData = [NSMutableData dataWithData:[path dataUsingEncoding:NSISOLatin1StringEncoding]];
458         unsigned int padding = 0x00;  // not sure if need to pad here?
459         [pathData appendData:[NSData dataWithBytes:&padding length:1]];
460         
461         //prepackage any commands needed
462         NSData* hddListCmd = [self prepareCommand:USB_CmdHddDir withData:pathData];
463 //      NSData* usbCancel = [self prepareCommand:USB_Cancel withData:nil];
464         [self checkUSB:device];
465         //send commands
466         //reset first of all to make sure all is fine
467 /*      NSData* data = [self sendCommand:usbCancel toDevice:device expectResponse:YES careForReturn:YES];
468         unsigned int rW = 0x00000002;
469         NSData* responseWanted = [NSData dataWithBytes:&rW length:4];
470         while (data == nil || [data length] < 8) {
471                 NSLog (@"incorrect response");
472                 data = [self sendCommand:usbCancel toDevice:device expectResponse:YES careForReturn:YES];
473         }
474         NSData* responseToCheck = [data subdataWithRange:(NSRange) {4,4}];
475         if (![responseWanted isEqualToData:responseToCheck]) {
476                 [self sendCommand:usbCancel toDevice:device expectResponse:YES careForReturn:NO]; // send reset again   
477         }
478 */      //now real one
479         NSData* data = [self sendCommand:hddListCmd toDevice:device expectResponse:YES careForReturn:YES];      
480         // deal with data recieved - in this case pass it back up for parsing
481         return data;
484 -(word) findCRC:(byte*)p length:(dword) n
486         word m_crc16 = 0x0000;
487         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, };
488         unsigned long i;        
489         for(i = 0; i < n; i++)
490                         m_crc16 = (m_crc16 >> 8) ^ crc16Tbl[*p++ ^ (m_crc16 & 0xFF)];
491         return m_crc16;
494 - (NSData*) prepareCommand:(unsigned int)cmd withData:(NSData*) inData {        
495                 // work out length
496                 unsigned short int length = 0;
497                 if (inData == nil)
498                         length = 8;
499                 else {
500                         unsigned short int l = [inData length];
501                         length = l + 8;
502                 }
503                 NSMutableData* toSend = [NSMutableData dataWithBytes:&length length:2];
504                 NSMutableData* build = [NSMutableData dataWithBytes:&cmd length:4];
505                 if (inData != nil)
506                         [build appendData:inData];
507                 // work out crc
508                 byte test[length];
509                 memset(test, 0, length);
510                 [build getBytes:test length:[build length]];
511                 unsigned short int crc = [self findCRC:test length:[build length]];
512                 [toSend appendData:[NSMutableData dataWithBytes:&crc length:2]];
513                 [toSend appendData:build];
514                 // reverse and send
515                 toSend = [self swap:toSend];
516                 return toSend;
519 - (int) getFile:(NSDictionary*)fileInfo forPath:(NSString*) currentPath toSaveTo:(NSString*) savePath withLoop:(BOOL)looping {  
520         //construct file send request
521         NSMutableString* fname = [NSMutableString stringWithString:[fileInfo objectForKey:@"name"]];
522         NSNumber* fileSize = [fileInfo objectForKey:@"fileSize"];
523         char dir = USB_FileToHost;
524         NSMutableData* build = [NSMutableData dataWithBytes:&dir length:1];
525         short int nsize = [fname length]+[currentPath length]+2;// one for slash, one for padding 0x00
526         [build appendData:[NSData dataWithBytes:&nsize length:2]];
527         NSData* d = [currentPath dataUsingEncoding:NSISOLatin1StringEncoding];
528         [build appendData:d];
529         dir = 0x5c; // 0x5c = "/"
530         [build appendData:[NSData dataWithBytes:&dir length:1]];
531         [build appendData:[fname dataUsingEncoding:NSISOLatin1StringEncoding]];
532         dir = 0x00;
533         [build appendData:[NSData dataWithBytes:&dir length:1]];
534         
535         //prepackage commands to send
536         NSData* fileSendCmd = [self prepareCommand:USB_CmdHddFileSend withData:build];
537         NSData* usbSuccess = [self prepareCommand:USB_Success withData:nil];
538         NSData* usbCancel = [self prepareCommand:USB_Cancel withData:nil];
539         
540         // send commands
541         [self checkUSB:myContext];
542         [self sendCommand:fileSendCmd toDevice:myContext expectResponse:YES careForReturn:NO];
543         //start timer
544         NSDate* startTime = [NSDate date];
545         // send start request and get response
546         NSData *data = [self sendCommand:usbSuccess toDevice:myContext expectResponse:YES careForReturn:YES];
547         unsigned int rW = 0x0000100a;
548         NSData *responseWanted = [NSData dataWithBytes:&rW length:4];
549         if ([data length] < 16) {
550                 NSLog(@"Incorrect Data length");
551                 return 1;
552         }
553         NSData *responseToCheck = [data subdataWithRange:(NSRange) {4,4}];
554         if (![responseWanted isEqualToData:responseToCheck]) {
555                 NSLog(@"Unexpected response from Toppy during download");
556                 return 1;
557         }
558         
559         // clean up data and prepare path to save it
560         NSData* header = [data subdataWithRange:(NSRange) {4,4}]; //cmd data
561         NSData* finalData = [data subdataWithRange:(NSRange) {16,[data length]-16}];
562         
563         // first initialize a file of the right name, as NSFileHandle requires an existing file to work on
564         [[NSData dataWithBytes:&dir length:1] writeToFile:savePath atomically:NO]; // write 0x00 to initialize (overwritten later)
565         NSFileHandle* outFile = [NSFileHandle fileHandleForWritingAtPath:savePath];
566         [outFile writeData:finalData];
567         if (looping) {  // loop for multiple data sends (ie files > 64k)
568                 int updateRate = 8; 
569                 if ([fileSize isGreaterThan:[NSNumber numberWithDouble:1048576]]) {
570                         updateRate = 24;
571                         NSLog(@"large file detected - low GUI update rate");
572                 }
573                 int timesAround = 0;
574                 int test = USB_DataHddFileData; 
575                 double amountReceived = 0xfe00;
576                 NSData* testData = [NSData dataWithBytes:&test length:4];
577                 while ([header isEqualToData:testData] && [[[NSApp delegate] isConnected] intValue]) {
578                         timesAround ++;
579                         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];                             
580                         data = [self sendCommand:usbSuccess toDevice:myContext expectResponse:YES careForReturn:YES];
581                         amountReceived += 0xfe00;
582                         if (timesAround < 8 || timesAround % updateRate == 0) {
583                                         [NSThread detachNewThreadSelector:@selector(updateProgress:) toTarget:self withObject:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithDouble:(double)amountReceived], @"offset", fileSize, @"size", startTime, @"startTime", nil]];
584                         }
585                         if ([data length] > 16){ //there is something to read 
586                                 header = [[data subdataWithRange:(NSRange) {4,4}] retain]; //cmd data
587                                 NSData* finalData = [data subdataWithRange:(NSRange) {16,[data length]-16}];
588                                 [outFile writeData:finalData];
589                                 [outFile synchronizeFile];
590                         } 
591                         else break;
592                         [pool release];
593                 }
594         }
595         [self sendCommand:usbCancel toDevice:myContext expectResponse:YES careForReturn:NO]; // send reset again        just to make sure!
596         [outFile closeFile];
597     //now add the right modification date to the file
598         [[NSFileManager defaultManager] changeFileAttributes:[NSDictionary dictionaryWithObject:[fileInfo objectForKey:@"date"] forKey:@"NSFileModificationDate"] atPath:savePath];
599         return 0;
602 - (int) getFile:(NSDictionary*)fileInfo forPath:(NSString*) currentPath toSaveTo:(NSString*) savePath atOffset:(unsigned long long) offset withLoop:(BOOL)looping {     
603         //construct file send request
604         NSMutableString* fname = [NSMutableString stringWithString:[fileInfo objectForKey:@"name"]];
605         NSNumber* fileSize = [fileInfo objectForKey:@"fileSize"];
606         char dir = USB_FileToHost;
607         NSMutableData* build = [NSMutableData dataWithBytes:&dir length:1];
608         short int nsize = [fname length]+[currentPath length]+2;// one for slash, one for padding 0x00
609         [build appendData:[NSData dataWithBytes:&nsize length:2]];
610         NSData* d = [currentPath dataUsingEncoding:NSISOLatin1StringEncoding];
611         [build appendData:d];   
612         dir = 0x5c; // 0x5c = "/"
613         [build appendData:[NSData dataWithBytes:&dir length:1]];
614         [build appendData:[fname dataUsingEncoding:NSISOLatin1StringEncoding]];
615         dir = 0x00;
616         [build appendData:[NSData dataWithBytes:&dir length:1]];
617         //add 8 byte offset here
618         NSLog(@"%qu", offset);
619         [build appendData:[NSData dataWithBytes:&offset length:8]];
620         NSLog([build description]);
621         
622         //prepackage commands to send
623         NSData* fileSendCmd = [self prepareCommand:USB_CmdHddFileSend withData:build];
624         NSData* usbSuccess = [self prepareCommand:USB_Success withData:nil];
625         NSData* usbCancel = [self prepareCommand:USB_Cancel withData:nil];
626         
627         // send commands
628         [self checkUSB:myContext];
629         [self sendCommand:fileSendCmd toDevice:myContext expectResponse:YES careForReturn:NO];
630         //start timer
631         NSDate* startTime = [NSDate date];
632         // send start request and get response
633         NSData *data = [self sendCommand:usbSuccess toDevice:myContext expectResponse:YES careForReturn:YES];
634         unsigned int rW = 0x0000100a;
635         NSData *responseWanted = [NSData dataWithBytes:&rW length:4];
636         if ([data length] < 16) {
637                 NSLog(@"Incorrect Data length");
638                 return 1;
639         }
640         NSData *responseToCheck = [data subdataWithRange:(NSRange) {4,4}];
641         if (![responseWanted isEqualToData:responseToCheck]) {
642                 NSLog(@"Unexpected response from Toppy during download");
643                 return 1;
644         }
645         
646         // clean up data and prepare path to save it
647         NSData* header = [data subdataWithRange:(NSRange) {4,4}]; //cmd data
648         NSData* finalData = [data subdataWithRange:(NSRange) {16,[data length]-16}];
649         
650         // first initialize a file of the right name, as NSFileHandle requires an existing file to work on
651 //      [[NSData dataWithBytes:&dir length:1] writeToFile:savePath atomically:NO]; // write 0x00 to initialize (overwritten later)
652         NSFileHandle* outFile = [NSFileHandle fileHandleForWritingAtPath:savePath];
653         [outFile seekToFileOffset:offset];
654         [outFile writeData:finalData];
655         if (looping) {  // loop for multiple data sends (ie files > 64k)
656                 int updateRate = 8; 
657                 if ([fileSize isGreaterThan:[NSNumber numberWithDouble:1048576]]) {
658                         updateRate = 24;
659                         NSLog(@"large file detected - low GUI update rate");
660                 }
661                 int timesAround = 0;
662                 int test = USB_DataHddFileData; 
663                 double amountReceived = 0xfe00;
664                 NSData* testData = [NSData dataWithBytes:&test length:4];
665                 while ([header isEqualToData:testData] && [[[NSApp delegate] isConnected] intValue]) {
666                         timesAround ++;
667                         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];                             
668                         data = [self sendCommand:usbSuccess toDevice:myContext expectResponse:YES careForReturn:YES];
669                         amountReceived += 0xfe00;
670                         if (timesAround < 8 || timesAround % updateRate == 0) {
671                                         [NSThread detachNewThreadSelector:@selector(updateProgress:) toTarget:self withObject:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithDouble:(double)amountReceived], @"offset", fileSize, @"size", startTime, @"startTime", nil]];
672                         }
673                         if ([data length] > 16){ //there is something to read 
674                                 header = [[data subdataWithRange:(NSRange) {4,4}] retain]; //cmd data
675                                 NSData* finalData = [data subdataWithRange:(NSRange) {16,[data length]-16}];
676                                 [outFile writeData:finalData];
677                                 [outFile synchronizeFile];
678                         } 
679                         else break;
680                         [pool release];
681                 }
682         }
683         [self sendCommand:usbCancel toDevice:myContext expectResponse:YES careForReturn:NO]; // send reset again        just to make sure!
684         [outFile closeFile];
685     //now add the right modification date to the file
686         [[NSFileManager defaultManager] changeFileAttributes:[NSDictionary dictionaryWithObject:[fileInfo objectForKey:@"date"] forKey:@"NSFileModificationDate"] atPath:savePath];
687         return 0;
690 - (NSData*) sendCommand:(NSData*) fullyPackagedCommand toDevice:(USBDeviceContext*)device expectResponse:(BOOL) getResponse careForReturn:(BOOL) careFactor{
691         IOReturn        err;
692         int cmdLength = [fullyPackagedCommand length];
693         unsigned char outBuffer[cmdLength];
694         memset(outBuffer, 0, cmdLength);
695 //      NSLog(@"send: %@", [fullyPackagedCommand description]);
696         [fullyPackagedCommand getBytes:outBuffer];
697         
698         err = doSend(device->dev, device->intf, outBuffer, cmdLength, kDat);
699         if (err)
700                 NSLog(@"sendError: %08x\n");
701         
702         if (! getResponse) return nil;
703         
704         int inLen = 0xFFFF; // i think this is biggest needed?
705         unsigned char inBuf[inLen];
706         memset(inBuf, 0, inLen);
707         err = doRecv(device->dev, device->intf, inBuf, inLen, kDat);
708         if (err)
709                 NSLog(@"inError: %08x\n", err);
710         
711         if (! careFactor) return nil;
712         NSMutableData* data = [NSMutableData dataWithBytes:inBuf length:inLen];
713         data = [self swap:data];
714         inLen = inBuf[1]*256 + inBuf[0]; // work out how long the response really is. NB data is flipped, but inBuf still isn't
715         return [data subdataWithRange:(NSRange) {0,inLen}];
718 -(NSMutableData*) swap: (NSData*) inData {
719 //      NSLog(@"Entering swap");
720 //      if ([inData length] > 500)
721 //              NSLog(@"cut:%@",[[inData subdataWithRange:(NSRange){0,500}] description]);
722 //      else 
723 //              NSLog([inData description]);
724         int len = [inData length];
725         int uneven = 0;
726         if (len % 2 != 0) {
727                 uneven = 1; // prepare space for padding
728         }
729 //      NSLog(@"Uneven: %i", uneven);
730 //      char array[len + uneven];
731 //      char outarray[len + uneven];
732 //      memset(array, 0 , len+uneven);
733 //      memset(outarray, 0 , len+uneven);
734         char *array;
735         char *outarray;
736         if ((array = calloc((len + uneven), sizeof(char))) == NULL) {
737                 NSLog(@"ERROR: Malloc failed");
738                 return [NSMutableData dataWithData:inData];
739         }
740         if ((outarray = calloc((len + uneven), sizeof(char))) == NULL) {
741                 NSLog(@"ERROR: Malloc failed");
742                 return [NSMutableData dataWithData:inData];
743         }
744 //      NSLog(@"memset complete");
745         [inData getBytes:array length:len];
746         swab(array, outarray, len+uneven);
747 //      NSLog(@"swab over");
748         NSMutableData* ret = [NSMutableData dataWithCapacity:len+uneven];
749         [ret setData:[NSData dataWithBytes:outarray length:len+uneven]];
750 //      NSLog(@"outdata prepared");
751         free(array);
752         free(outarray);
753         return ret; 
756 - (void) uploadFile:(NSString*) fileToUpload ofSize:(long long) size fromPath:(NSString*)curPath withAttributes:(NSData*) typeFile toDevice:(USBDeviceContext*)dev {
757         // prepare Send command
758         NSMutableArray* array = [NSMutableArray arrayWithArray:[fileToUpload componentsSeparatedByString:@"/"]];
759         NSMutableString* fname = [NSMutableString stringWithString:[array lastObject]];
760         char dir = USB_FileToDevice;
761         NSMutableData* build = [NSMutableData dataWithBytes:&dir length:1];
762         short int nsize = [fname length]+[curPath length]+2;// one for slash, one for padding 0x00
763         [build appendData:[NSData dataWithBytes:&nsize length:2]];
764         NSData* d = [curPath dataUsingEncoding:NSISOLatin1StringEncoding];
765         [build appendData:d];
766         dir = 0x5c; // 0x5c = "/"
767         [build appendData:[NSData dataWithBytes:&dir length:1]];
768         [build appendData:[fname dataUsingEncoding:NSISOLatin1StringEncoding]];// may need to pad to 95...
769                 int f = 0x0000000000;
770                 int i = 0;
771                 while (i < 95 -[fname length]){
772                         [build appendData:[NSData dataWithBytes:&f length:1]];
773                         i++;
774                 }
775         dir = 0x00;
776         [build appendData:[NSData dataWithBytes:&dir length:1]];
777         
778         // prepackage commands to send
779         NSData* fileSendCmd = [self prepareCommand:USB_CmdHddFileSend withData:build];
780 //      NSData* usbSuccess = [self prepareCommand:USB_Success withData:nil];
781 //      NSData* usbCancel = [self prepareCommand:USB_Cancel withData:nil];
782         NSData* fileStartCmd = [self prepareCommand:USB_DataHddFileStart withData:typeFile];
783         NSData* fileEndCmd = [self prepareCommand:USB_DataHddFileEnd withData:nil];
785         //start timer
786         NSDate* startTime = [NSDate date];
787         
788         //send commands
789         [self checkUSB:dev];
790         // now the proper commands
791         NSData *data = [self sendCommand:fileSendCmd toDevice:dev expectResponse:YES careForReturn:YES];
792         data = [self sendCommand:fileStartCmd toDevice:dev expectResponse:YES careForReturn:YES];
793         unsigned int rW = 0x00000002;
794         NSData* responseWanted = [NSData dataWithBytes:&rW length:4];
795         NSData* responseToCheck = nil;
797         unsigned long long offset = 0x0000000000000000;
798         NSFileHandle* fileHandle = [NSFileHandle fileHandleForReadingAtPath:fileToUpload];
799         do {
800                 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
801                 NSMutableData* fileData = [NSMutableData dataWithBytes:&offset length:8];
802                 [fileData appendData:[fileHandle readDataOfLength:rate]];
803                 offset += rate;
804                 NSData* fileDataCmd = [self prepareCommand:USB_DataHddFileData withData:fileData];
805                 data = [self sendCommand:fileDataCmd toDevice:dev expectResponse:YES careForReturn:YES];
806                 if ([data length] >= 8) 
807                         responseToCheck = [data subdataWithRange:(NSRange) {4,4}];
808                 else responseToCheck = nil;
809                 if (responseToCheck == nil || ![responseWanted isEqualToData:responseToCheck]) 
810                         break;
811                 [NSThread detachNewThreadSelector:@selector(updateProgress:) toTarget:self withObject:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithDouble:(double)offset], @"offset", [NSNumber numberWithDouble:(double)size], @"size", startTime, @"startTime", nil]];
812                 [pool release];
813         } while (offset < size && [[[NSApp delegate] isConnected] intValue]);
814         if ([[[NSApp delegate] isConnected] intValue])
815                 data = [self sendCommand:fileEndCmd toDevice:dev expectResponse:YES careForReturn:YES];
816         [fileHandle closeFile];         
820 - (void) turnTurboOn:(BOOL) turnOn forDevice:(USBDeviceContext*)device withReset:(BOOL)reset {
821         if (![[[NSApp delegate] isConnected] intValue]) return;
822         if (reset) [self checkUSB:device];
823         int mode = 0;
824         if (turnOn) 
825                 mode = 1;
826         NSData* modeData = [NSData dataWithBytes:&mode length:4];
827         NSLog([modeData description]); //debugging
828         NSData* turboCommand  = [self prepareCommand:USB_CmdTurbo withData:modeData];
829         [self sendCommand:turboCommand toDevice:device expectResponse:YES careForReturn:NO];
832 - (int) getSpeed {
833         return connectedSpeed;
836 -(void) setDebug:(int)mode {
837         debug = mode;
838         NSLog(@"Debug level: %i", debug);
841 -(void) setRate:(int) newRate {
842         rate = newRate;
843         NSLog(@"New rate set: %i", rate);
846 -(void) setProgressBar:(NSProgressIndicator*)bar time:(NSTextField*)timeField {
847         progressBar = bar;
848         progressTime = timeField;
851 -(void) updateProgress:(NSDictionary*) inDict {
852         NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
853         double offset = [[inDict objectForKey:@"offset"] doubleValue];
854         double size = [[inDict objectForKey:@"size"] doubleValue];
855         NSDate* startTime = [inDict objectForKey:@"startTime"];         
856         [progressBar setDoubleValue:((double)offset/size*100)];
857         [progressBar displayIfNeeded];
858         [progressTime setStringValue:[self elapsedTime:[[NSDate date] timeIntervalSinceDate:startTime]]];
859         [progressTime displayIfNeeded];
860         [pool release];
864 - (NSString*) elapsedTime:(NSTimeInterval) totalSeconds {
865         char hp = 20;
866         char mp = 20;
867         char sp = 20; //padding
868         int hours = (totalSeconds / 3600);  // returns number of whole hours fitted in totalSecs
869         if (hours < 10)
870                 hp = 48;
871         int minutes = ((totalSeconds / 60) - hours*60);  // Whole minutes
872         if (minutes < 10)
873                 mp = 48;
874         int seconds = ((long) totalSeconds % 60);       // Here we can use modulo to get num secs NOT fitting in whole minutes (60 secs)
875         if (seconds < 10)
876                 sp = 48;
877         return [NSString stringWithFormat:@"%c%i:%c%i:%c%i", hp, hours, mp, minutes, sp, seconds];
880 - (void) deleteFile:(NSDictionary*)fileInfo fromPath:(NSString*)currentPath onDevice:(USBDeviceContext*)device {
881         [self checkUSB:device];
882         NSMutableString* fname = [NSMutableString stringWithString:[fileInfo objectForKey:@"name"]];
883         NSMutableData* build = [NSMutableData dataWithData:[currentPath dataUsingEncoding:NSISOLatin1StringEncoding]];
884         char dir = 0x5c; // 0x5c = "\"
885         [build appendData:[NSData dataWithBytes:&dir length:1]];
886         [build appendData:[fname dataUsingEncoding:NSISOLatin1StringEncoding]];
887         dir = 0x00;
888         [build appendData:[NSData dataWithBytes:&dir length:1]];
889         NSData* fileDelCmd = [self prepareCommand:USB_CmdHddDel withData:build];
890         [self sendCommand:fileDelCmd toDevice:device expectResponse:YES careForReturn:NO];
893 - (void) renameFile:(NSString*) oldName withName:(NSString*)newName atPath:(NSString*)currentPath onDevice:(USBDeviceContext*)device {
894         [self checkUSB:device];
895         unsigned short int i = [oldName length]+[currentPath length]+2;
896         NSMutableData* build = [NSMutableData dataWithBytes:&i length:2];
897         [build appendData:[currentPath dataUsingEncoding:NSISOLatin1StringEncoding]];
898         char dir = 0x5c;
899         [build appendData:[NSData dataWithBytes:&dir length:1]];
900         [build appendData:[oldName dataUsingEncoding:NSISOLatin1StringEncoding]];
901         dir = 0x00;
902         [build appendData:[NSData dataWithBytes:&dir length:1]];
903         i = [newName length]+[currentPath length]+2;
904         [build appendData:[NSData dataWithBytes:&i length:2]];
905         [build appendData:[currentPath dataUsingEncoding:NSISOLatin1StringEncoding]];
906         dir = 0x5c;
907         [build appendData:[NSData dataWithBytes:&dir length:1]];
908         [build appendData:[newName dataUsingEncoding:NSISOLatin1StringEncoding]];
909         dir = 0x00;
910         [build appendData:[NSData dataWithBytes:&dir length:1]];
911         NSData* fileRenCmd = [self prepareCommand:USB_CmdHddRename withData:build];
912         [self sendCommand:fileRenCmd toDevice:device expectResponse:YES careForReturn:NO];
915 - (void) makeFolder:(NSString*)newName atPath:(NSString*)currentPath onDevice:(USBDeviceContext*)device {
916         [self checkUSB:device];
917         unsigned short int i = [newName length]+[currentPath length]+2;
918         NSMutableData* build = [NSMutableData dataWithBytes:&i length:2];
919         [build appendData:[currentPath dataUsingEncoding:NSISOLatin1StringEncoding]];
920         char dir = 0x5c;
921         [build appendData:[NSData dataWithBytes:&dir length:1]];
922         [build appendData:[newName dataUsingEncoding:NSISOLatin1StringEncoding]];
923         dir = 0x00;
924         [build appendData:[NSData dataWithBytes:&dir length:1]];
925         NSData* newFoldCmd = [self prepareCommand:USB_CmdHddCreateDir withData:build];
926         NSData* usbCancel = [self prepareCommand:USB_Cancel withData:nil];
927         [self sendCommand:usbCancel toDevice:device expectResponse:YES careForReturn:NO];
928         [self sendCommand:newFoldCmd toDevice:device expectResponse:YES careForReturn:NO];
931 - (void) checkUSB:(USBDeviceContext*)device {
932         NSData* usbCancel = [self prepareCommand:USB_Cancel withData:nil];
933         NSData* data = [self sendCommand:usbCancel toDevice:device expectResponse:YES careForReturn:YES];
934         unsigned int rW = 0x00000002;
935         int i = 0;
936         NSData* responseWanted = [NSData dataWithBytes:&rW length:4];
937         while ((data == nil || [data length] < 8) && i < 8) {
938                 NSLog (@"incorrect response");
939                 i++;
940                 data = [self sendCommand:usbCancel toDevice:device expectResponse:YES careForReturn:YES];
941         }
942         if (!i<=8) {
943                 // tell someone that no longer connected here??
944                 return;
945                 }
946         NSData* responseToCheck = [data subdataWithRange:(NSRange) {4,4}];
947         if (![responseWanted isEqualToData:responseToCheck]) {
948                 [self sendCommand:usbCancel toDevice:device expectResponse:YES careForReturn:NO]; // send reset again   
949         }
952 @end