//
//  VH7PC.m
//  VH7PC_Controller
//
//  Created by NYA on Wed Jul 09 2003.
//  Copyright (c) 2003 __MyCompanyName__. All rights reserved.
//

#import "VH7PC.h"
#import "Command.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> 

#include <mach/mach.h>
#import <mach/mach_interface.h>
#import <mach/mach_init.h>

#include <CoreFoundation/CFNumber.h>

#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/usb/IOUSBLib.h>
#include <IOKit/usb/USBSpec.h>
#include <IOKit/usb/IOUSBUserClient.h>
#include <IOKit/IOMessage.h>
#import <IOKit/pwr_mgt/IOPMLib.h>


#define MAX_ERROR 0x7FFF


VH7PC_cmd command;
int reqVal;
unsigned char iobuff[32];

mach_port_t masterPort = 0;				// requires <mach/mach.h>
IOUSBDeviceInterface187 **dev;

io_connect_t		root_port;
long global_messageArgument;

unsigned int cmdArray[51]={
    0xB8020681,
    0xB8020680,
    0xB8020091,
    0xB8020092,
    0xB80201D2,
    0xB8020095,
    0xB8020093,
    0xB8024D00,
    0xB802009C,
    0xB802014B,
    0xB80201C1,
    0xB80201C0,
    0xB80200CB,
    0xB80200C9,
    0xB80200CF,
    0xB80200CE,
    0xB8024400,
    0xB8020007,
    0xB8020006,
    0xB80200CC,
    0xB80201D4,
    0xB802018D,
    0xB802008F,
    0xB8020118,
    0xB8020107,
    0xB8020106,
    0xB8024C00,
    0xB80201D8,
    0xB80201D9,
    0xB80201DA,
    0xB80201DB,
    0xB8020040,
    0xB80201DD,
    0xB80201DC,
    0xB8024500,
    0xB80201DF,
    0xB80201DE,
    0xB80206D9,
    0xB80206DA,
    0xB80206DB,
    0xB80206DC,
    0xB80202CF,
    0xB8020342,
    0xB8020340,
    0xB80200D9,
    0xB80200D8,
    0xB80200DD,
    0xB80200DB,
    0xB80200DA,
    0xB80206DF,
    0xB80206DE
};

int waitArray[52]={
    0,0,				//Power on/off
    150,150,150,150,150,		//Select input mode
    0,				//Volume
    0,					//Mute
    0,					//N.B
    0,0,				//Input level up/down
    0,0,0,0,0,0,0,0,0,0,		//CD
    150,0,80,80,0,				//BAND
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	//MD
    0,0,0,0,0,0,			//TAPE
    0,					//SYS_REQ
    0					//GET_STATUS
};


typedef struct MyPrivateData {
    io_object_t			notification;
    IOUSBDeviceInterface *	*deviceInterface;
    CFStringRef			deviceName;
    UInt32			locationID;
} MyPrivateData;



static IONotificationPortRef gNotifyPort;
static io_iterator_t gAddedIter;
static CFRunLoopRef gRunLoop;

void allowPowerChange(){
    IOAllowPowerChange(root_port,global_messageArgument);
}

void sleepNotifire(void * x,io_service_t y,natural_t messageType,void * messageArgument){
    //printf("messageType %08lx, arg %08lx\n",(long unsigned int)messageType, (long unsigned int)messageArgument);
    
    switch ( messageType ) {
    case kIOMessageSystemWillSleep:
        {
            CFStringRef observedObject=CFSTR("CHVH7PCNotifire");
            CFNotificationCenterRef center=CFNotificationCenterGetDistributedCenter();
            
            CFNotificationCenterPostNotification(center,CFSTR("CHVH7PCSystemWillSleep"),observedObject,NULL,TRUE);
        }
        global_messageArgument=(long)messageArgument;
        //IOAllowPowerChange(root_port,(long)messageArgument);
        //printf("Going to sleep now\n");
        break;
    case kIOMessageCanSystemSleep:
        IOAllowPowerChange(root_port,(long)messageArgument);
        break;
    case kIOMessageSystemHasPoweredOn:
        {
            CFStringRef observedObject=CFSTR("CHVH7PCNotifire");
            CFNotificationCenterRef center=CFNotificationCenterGetDistributedCenter();
            
            CFNotificationCenterPostNotification(center,CFSTR("CHVH7PCSystemHasPoweredOn"),observedObject,NULL,TRUE);
        }
        //printf("Just had a nice snooze\n");
        break;
    }
    
}

void sleepNotifireInit(){
    IONotificationPortRef	notify;
    io_object_t 		anIterator;

    //fprintf(stderr, "\nAttempting to register for system power notifications\n");
    root_port = IORegisterForSystemPower (0,&notify,sleepNotifire,&anIterator);
    if ( !root_port ) {
            fprintf(stderr, "IORegisterForSystemPower failed\n");
            return;
    }
    //fprintf(stderr, "Registration successful\n");
    
    CFRunLoopAddSource(CFRunLoopGetCurrent(),
                        IONotificationPortGetRunLoopSource(notify),
                        kCFRunLoopDefaultMode);
                        
    //fprintf(stderr, "waiting...\n");
    //fprintf(stderr, "Look at the two IOKit header files for details\n");
    //fprintf(stderr, "#include <IOKit/pwr_mgt/IOPMLib.h>, #include <IOKit/IOMessage.h>\n");

    //return NSApplicationMain(argc, argv);
}


void DeviceNotification( void *		refCon,
                         io_service_t 	service,
                         natural_t 	messageType,
                         void *		messageArgument ){
    kern_return_t	kr;
    MyPrivateData	*privateDataRef = (MyPrivateData *) refCon;
    
    if (messageType == kIOMessageServiceIsTerminated){
        //NSLog(@"Device 0x%08x removed.¥n", service);
        CFRelease(privateDataRef->deviceName);
        if ( privateDataRef->deviceInterface )
            kr = (*privateDataRef->deviceInterface)->Release (privateDataRef->deviceInterface);
        
        kr = IOObjectRelease(privateDataRef->notification);
        free(privateDataRef);
        {
            CFStringRef observedObject=CFSTR("CHVH7PCNotifire");
            CFNotificationCenterRef center=CFNotificationCenterGetDistributedCenter();
            
            CFNotificationCenterPostNotification(center,CFSTR("CHVH7PCRemoved"),observedObject,NULL,TRUE);
        }
    }
}

void DeviceAdded(void *refCon, io_iterator_t iterator){
    kern_return_t		kr;
    io_service_t		usbDevice;
    IOCFPlugInInterface 	**plugInInterface=NULL;
    SInt32 			score;
    HRESULT 			res;

    while ( (usbDevice = IOIteratorNext(iterator)) ){
        
        io_name_t		deviceName;
        CFStringRef		deviceNameAsCFString;	
        MyPrivateData		*privateDataRef = NULL;
        UInt32			locationID;

        //NSLog(@"Device 0x%08x added.¥n", usbDevice);
        
        privateDataRef = malloc(sizeof(MyPrivateData));
        bzero( privateDataRef, sizeof(MyPrivateData));
        
        kr = IORegistryEntryGetName(usbDevice, deviceName);
	if (KERN_SUCCESS != kr){
            deviceName[0] = '\0';
        }
        
        deviceNameAsCFString = CFStringCreateWithCString(kCFAllocatorDefault, deviceName, kCFStringEncodingASCII);
        privateDataRef->deviceName = deviceNameAsCFString;
        kr = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score);

        if ((kIOReturnSuccess != kr) || !plugInInterface){
            printf("unable to create a plugin (%08x)¥n", kr);
            continue;
        }

        res=(*plugInInterface)->QueryInterface(plugInInterface,
            CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID)&privateDataRef->deviceInterface);
        (*plugInInterface)->Release(plugInInterface);			// done with this
        if (res || !privateDataRef->deviceInterface){
            printf("couldn't create a device interface (%08x)¥n", (int) res);
            continue;
        }

        kr = (*privateDataRef->deviceInterface)->GetLocationID(privateDataRef->deviceInterface, &locationID);
        if (KERN_SUCCESS != kr){
            printf("GetLocationID returned %08x¥n", kr);
            continue;
        }else{
            //printf("Location ID: 0x%lx¥n", locationID);
        }

        privateDataRef->locationID = locationID;

        kr = IOServiceAddInterestNotification(	gNotifyPort,			// notifyPort
                                               usbDevice,			// service
                                               kIOGeneralInterest,		// interestType
                                               DeviceNotification,		// callback
                                               privateDataRef,			// refCon
                                               &(privateDataRef->notification)	// notification
                                               );

        if (KERN_SUCCESS != kr){
            printf("IOServiceAddInterestNotification returned 0x%08x¥n", kr);
        }

        kr = IOObjectRelease(usbDevice);
        
        {
            CFStringRef observedObject=CFSTR("CHVH7PCNotifire");
            CFNotificationCenterRef center=CFNotificationCenterGetDistributedCenter();
            
            CFNotificationCenterPostNotification(center, CFSTR("CHVH7PCAdded"),observedObject,NULL,TRUE);
        }
    }
}

void notifireDealloc(){
    IONotificationPortDestroy(gNotifyPort);

    if (gAddedIter) {
        IOObjectRelease(gAddedIter);
        gAddedIter = 0;
    }
}

int notifireInit(){
    mach_port_t 		masterPort;
    CFMutableDictionaryRef 	matchingDict;
    CFRunLoopSourceRef		runLoopSource;
    CFNumberRef			numberRef;
    kern_return_t		kr;
    long			usbVendor = VENDER;
    long			usbProduct = PRODUCT;

    kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
    if (kr || !masterPort){
        printf("ERR: Couldn't create a master IOKit Port(%08x)¥n", kr);
        return -1;
    }

    matchingDict = IOServiceMatching(kIOUSBDeviceClassName);	// Interested in instances of class
                                                                // IOUSBDevice and its subclasses
    if (!matchingDict){
        printf("Can't create a USB matching dictionary¥n");
        mach_port_deallocate(mach_task_self(), masterPort);
        return -1;
    }
    
    numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbVendor);
    CFDictionarySetValue( 
            matchingDict, 
            CFSTR(kUSBVendorID), 
            numberRef);
    CFRelease(numberRef);
    
    numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbProduct);
    CFDictionarySetValue( 
            matchingDict, 
            CFSTR(kUSBProductID), 
            numberRef);
    CFRelease(numberRef);
    numberRef = 0;

    gNotifyPort = IONotificationPortCreate(masterPort);
    runLoopSource = IONotificationPortGetRunLoopSource(gNotifyPort);
    
    gRunLoop = CFRunLoopGetCurrent();
    CFRunLoopAddSource(gRunLoop, runLoopSource, kCFRunLoopDefaultMode);
    
    kr = IOServiceAddMatchingNotification(gNotifyPort,			// notifyPort
                                          kIOFirstMatchNotification,	// notificationType
                                          matchingDict,			// matching
                                          DeviceAdded,			// callback
                                          NULL,				// refCon
                                          &gAddedIter			// notification
                                          );		
    
    DeviceAdded(NULL, gAddedIter);

    mach_port_deallocate(mach_task_self(), masterPort);
    masterPort = 0;

    return 0;
}




/*
void dealWithDevice(io_service_t usbDeviceRef)
{
    IOReturn				err;
    IOCFPlugInInterface 		**iodev;		// requires <IOKit/IOCFPlugIn.h>
    IOUSBDeviceInterface 		**dev;
    SInt32 				score;
    IOUSBDevRequest req;
    int ErrNum=0;
    
    err = IOCreatePlugInInterfaceForService(usbDeviceRef, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
    if (err || !iodev){
	printf("dealWithDevice: unable to create plugin. ret = %08x, iodev = %p\n", err, iodev);
	return;
    }
    err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID187), (LPVOID)&dev);
    (*iodev)->Release(iodev);				// done with this
    if (err || !dev){
	printf("dealWithDevice: unable to create a device interface. ret = %08x, dev = %p\n", err, dev);
	return;
    }
    err = (*dev)->USBDeviceOpen(dev);
    if (err){
	printf("dealWithDevice: unable to open device. ret = %08x\n", err);
	return;
    }
    err = (*dev)->ResetDevice(dev);
    if(err) NSLog(@"ResetDeviceErr=%X",err);
    
    if(command!=GET_STATUS){
        int i;
        for(i=0;i<4;i++)
            iobuff[i]=(unsigned char)(0xFF&(cmdArray[command]>>((3-i)*8)));
    }
    if(command==VOLUME){
        int i;
        iobuff[3]=(unsigned char)reqVal;
        for(i=5;i<32;i++) iobuff[i]=(unsigned char)0x00;
    }
    iobuff[4] = (unsigned char)(0xFF00 ^ (iobuff[0]+iobuff[1]+iobuff[2]+iobuff[3])); // 下位1byteのChecksum 
    req.bmRequestType=USBmakebmRequestType((command==GET_STATUS)?kUSBIn:kUSBOut,kUSBVendor,kUSBInterface);
    req.bRequest=0;
    req.wValue = 0;	
    req.wIndex = 0;
    req.wLength = 32;
    req.wLenDone = (command==GET_STATUS)?32:5;
    req.pData = iobuff;

    //err = (*dev)->ResetDevice(dev);
    //if(err) NSLog(@"ResetDeviceErr=%X",err);
    err = (*dev)->DeviceRequest(dev,&req);
    if(err){
        NSLog(@"DeviceRequestErr=%X",err);
        while(err&&ErrNum<MAX_ERROR){
            ErrNum++;
            err = (*dev)->DeviceRequest(dev,&req);
        }
    	NSLog(@"ErrNum=%d",ErrNum);
    }
        
    err = (*dev)->USBDeviceClose(dev);
    if (err){
	printf("dealWithDevice: error closing device - %08x\n", err);
	(*dev)->Release(dev);
	return;
    }
    err = (*dev)->Release(dev);
    if (err){
	printf("dealWithDevice: error releasing device - %08x\n", err);
	return;
    }
}
*/

void sendCommand(){
    IOReturn err;
    IOUSBDevRequestTO req;
    //IOCFPlugInInterface 		**iodev;		// requires <IOKit/IOCFPlugIn.h>
    //IOUSBInterfaceInterface 		**intf;
    //SInt32 				score;
    UInt8				numConf;
    IOUSBConfigurationDescriptorPtr	confDesc;
    //IOUSBFindInterfaceRequest		interfaceRequest;
    //io_iterator_t			iterator;
    //io_service_t			usbInterfaceRef;
    int ErrNum=0;

    err = (*dev)->GetNumberOfConfigurations(dev, &numConf);
    if (err || !numConf){
	printf("dealWithDevice: unable to obtain the number of configurations. ret = %08x\n", err);
        (*dev)->USBDeviceClose(dev);
        (*dev)->Release(dev);
	return;
    }
    err = (*dev)->GetConfigurationDescriptorPtr(dev, 0, &confDesc);			// get the first config desc (index 0)
    if (err){
	printf("dealWithDevice:unable to get config descriptor for index 0\n");
        (*dev)->USBDeviceClose(dev);
        (*dev)->Release(dev);
	return;
    }
    err = (*dev)->SetConfiguration(dev, confDesc->bConfigurationValue);
    if (err){
	printf("dealWithDevice: unable to set the configuration\n");
        (*dev)->USBDeviceClose(dev);
        (*dev)->Release(dev);
	return;
    }
    /*
    interfaceRequest.bInterfaceClass = kIOUSBFindInterfaceDontCare;		// requested class
    interfaceRequest.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;		// requested subclass
    interfaceRequest.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;		// requested protocol
    interfaceRequest.bAlternateSetting = kIOUSBFindInterfaceDontCare;		// requested alt setting
    err = (*dev)->CreateInterfaceIterator(dev, &interfaceRequest, &iterator);
    if (err){
	printf("dealWithDevice: unable to create interface iterator\n");
        (*dev)->USBDeviceClose(dev);
        (*dev)->Release(dev);
	return;
    }
    usbInterfaceRef = IOIteratorNext(iterator);
    err = IOCreatePlugInInterfaceForService(usbInterfaceRef, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
    if (err || !iodev){
	printf("dealWithInterface: unable to create plugin. ret = %08x, iodev = %p\n", err, iodev);
	return;
    }
    err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)&intf);
    (*iodev)->Release(iodev);				// done with this
    if (err || !intf){
	printf("dealWithInterface: unable to create a device interface. ret = %08x, intf = %p\n", err, intf);
	return;
    }
    err = (*intf)->USBInterfaceOpen(intf);
    */

    if(command!=GET_STATUS){
        int i;
        for(i=0;i<4;i++)
            iobuff[i]=(unsigned char)(0xFF&(cmdArray[command]>>((3-i)*8)));
    }
    if(command==VOLUME){
        int i;
        iobuff[3]=(unsigned char)reqVal;
        for(i=5;i<32;i++) iobuff[i]=(unsigned char)0x00;
    }
    if(command==PH_SEARCH){
        int i;
        iobuff[3]=(unsigned char)reqVal;
        for(i=5;i<32;i++) iobuff[i]=(unsigned char)0x00;
    }
    iobuff[4] = (unsigned char)(0xFF00 ^ (iobuff[0]+iobuff[1]+iobuff[2]+iobuff[3])); // 下位1byteのChecksum 
    req.bmRequestType=USBmakebmRequestType((command==GET_STATUS)?kUSBIn:kUSBOut,kUSBVendor,kUSBInterface);
    req.bRequest=0;
    req.wValue = 0;	
    req.wIndex = 0;
    req.wLength = 32;
    req.wLenDone = (command==GET_STATUS)?32:5;
    req.pData = iobuff;
    req.noDataTimeout=kUSBDefaultControlNoDataTimeoutMS;
    req.completionTimeout=kUSBDefaultControlCompletionTimeoutMS;

    //err = (*dev)->ResetDevice(dev);
    //if(err) NSLog(@"ResetDeviceErr=%X",err);
    //err = (*intf)->ControlRequest(intf,0,&req);
    err = (*dev)->DeviceRequestTO(dev,&req);
    if(err==kIOUSBPipeStalled){
        IOReturn er = (*dev)->USBDeviceAbortPipeZero(dev);
    	if(er) NSLog(@"USBDeviceAbortPipeZeroErr = %d",er);
        while(err&&ErrNum<MAX_ERROR){
            ErrNum++;
            //err = (*intf)->ControlRequest(intf,0,&req);
            err = (*dev)->DeviceRequestTO(dev,&req);
        }
    	//if(ErrNum) NSLog(@"kIOUSBPipeStalled %d",ErrNum);
    }else if(err){
        NSLog(@"DeviceRequestError=%08x",err);
    }
    
    /*
    IOObjectRelease(iterator);
    iterator = 0;

    err = (*intf)->USBInterfaceClose(intf);
    if (err){
	printf("dealWithInterface: unable to close interface. ret = %08x\n", err);
	return;
    }
    err = (*intf)->Release(intf);
    if (err){
	printf("dealWithInterface: unable to release interface. ret = %08x\n", err);
	return;
    }
    */
}

int gravIterator=0;

int grabDevice(){
    kern_return_t		err;
    CFMutableDictionaryRef 	matchingDictionary = 0;		// requires <IOKit/IOKitLib.h>
    SInt32			idVendor = VENDER;
    SInt32			idProduct = PRODUCT;
    CFNumberRef			numberRef;
    io_iterator_t 		iterator = 0;
    io_service_t		usbDeviceRef;
    //BOOL flag=NO;
    IOReturn				ierr;
    IOCFPlugInInterface 		**iodev;		// requires <IOKit/IOCFPlugIn.h>
    //IOUSBDeviceInterface 		**dev;
    SInt32 	score;
    
    err=IOMasterPort(MACH_PORT_NULL, &masterPort);				
    if (err){
        printf("VH7PC Controller: could not create master port, err = %08x\n", err);
        return err;
    }
    matchingDictionary = IOServiceMatching(kIOUSBDeviceClassName);	// requires <IOKit/usb/IOUSBLib.h>
    if (!matchingDictionary){
        printf("VH7PC Controller: could not create matching dictionary\n");
        return -1;
    }
    numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &idVendor);
    if (!numberRef){
        printf("VH7PC Controller: could not create CFNumberRef for vendor\n");
        return -1;
    }
    CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBVendorID), numberRef);
    CFRelease(numberRef);
    numberRef = 0;
    numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &idProduct);
    if (!numberRef){
        printf("VH7PC Controller: could not create CFNumberRef for product\n");
        return -1;
    }
    CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBProductID), numberRef);
    CFRelease(numberRef);
    numberRef = 0;
    
    err = IOServiceGetMatchingServices(masterPort, matchingDictionary, &iterator);
    matchingDictionary = 0;			// this was consumed by the above call
    
    usbDeviceRef = IOIteratorNext(iterator);
    
    ierr = IOCreatePlugInInterfaceForService(usbDeviceRef, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
    if (ierr || !iodev){
	printf("dealWithDevice: unable to create plugin. ret = %08x, iodev = %p\n", err, iodev);
	return ierr;
    }
    ierr = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID187), (LPVOID)&dev);
    (*iodev)->Release(iodev);				// done with this
    if (ierr || !dev){
	printf("dealWithDevice: unable to create a device interface. ret = %08x, dev = %p\n", err, dev);
	return ierr;
    }
    //ierr = (*dev)->USBDeviceOpen(dev);
    ierr = (*dev)->USBDeviceOpenSeize(dev);
    if (ierr){
	printf("dealWithDevice: unable to open device. ret = %08x\n", ierr);
	if(gravIterator) return ierr;
        ierr = (*dev)->Release(dev);
        if(ierr){
            NSLog(@"releaseDeviceErr=%X",ierr);
            return ierr;
        }
        gravIterator=1;
        ierr = grabDevice();
        if(ierr){
            NSLog(@"USBDeviceOpenErr=%X",ierr);
            return ierr;
        }
    }
    ierr = (*dev)->ResetDevice(dev);
    if(ierr) NSLog(@"ResetDeviceErr=%X",ierr);
    
    IOObjectRelease(usbDeviceRef);
    IOObjectRelease(iterator);
    
    return 0;
}

int releaseDevice(){
    kern_return_t		err;
    //CFMutableDictionaryRef 	matchingDictionary = 0;		// requires <IOKit/IOKitLib.h>
    //SInt32			idVendor = VENDER;
    //SInt32			idProduct = PRODUCT;
    //CFNumberRef			numberRef;
    //io_iterator_t 		iterator = 0;
    //io_service_t		usbDeviceRef;
    //BOOL flag=NO;

    
    err = (*dev)->USBDeviceClose(dev);
    if (err){
	printf("dealWithDevice: error closing device - %08x\n", err);
	(*dev)->Release(dev);
	return err;
    }
    
    err = (*dev)->Release(dev);
    if (err){
	printf("dealWithDevice: error releasing device - %08x\n", err);
	return err;
    }
        
	//IOObjectRelease(usbDeviceRef);			// no longer need this reference
    //}
    
    //IOObjectRelease(iterator);
    //iterator = 0;
    
    mach_port_deallocate(mach_task_self(), masterPort);
    return 0;
}

int hex2int(unsigned char c){
    return (int)(10*(c/16)+c%16);
}

@implementation VH7PC

-(id)init{
    [super init];
    
    NSDistributedNotificationCenter *nc;
    nc=[NSDistributedNotificationCenter notificationCenterForType:NSLocalNotificationCenterType];
    [nc addObserver:self selector:@selector(sendCommandByNotification:) name:@"CHSendCommand2VH7PC" object:nil];

    _commandQueue=[[NSMutableArray alloc] initWithCapacity:0];
    _periodTimer=nil;
    sleepNotifireInit();
    
    return self;
}

-(void)awakeFromNib{
    //notifireInit();
}

-(void)sendCommandByNotification:(NSNotification *)nc{
    int com=[[[nc userInfo] objectForKey:@"Command"] intValue];
    int val=[[[nc userInfo] objectForKey:@"Value"] intValue];
    
    if(com==GET_STATUS){
        [self getStatus];

        NSDistributedNotificationCenter* nc;
        nc=[NSDistributedNotificationCenter notificationCenterForType:NSLocalNotificationCenterType];
        [nc postNotificationName:@"CHGetStatusFromVH7PC" object:nil userInfo:
            [self statusDictionary]
        deliverImmediately:YES];
    }else [self sendCommand:com andValue:val];
}

-(BOOL)getStatus{
    int err;
    
    err=[self sendCommand:GET_STATUS andValue:0];
    if(err!=0) return YES;
    [self setStatus];
    return NO;
}

-(void)sendCommand:(VH7PC_cmd)cmd{
    [self sendCommand:cmd andValue:0];
}

-(void)changeVol:(int)val{
    [self sendCommand:VOLUME andValue:val];
}

-(int)sendCommand:(VH7PC_cmd)cmd andValue:(int)val{
    command=cmd;
    reqVal=val;
    if(_connected) sendCommand();
    usleep(1000*waitArray[command]);
    return 0;
/*
    [_commandQueue addObject:[Command commandWithCommand:cmd andValue:val]];
    if(_periodTimer==nil){
        id tmp=[_commandQueue objectAtIndex:0];
        [_commandQueue removeObjectAtIndex:0];
        
        command=[tmp command];
        reqVal=[tmp reqVal];
        if(_connected) sendCommand();
        if([_commandQueue count]!=0)
            _periodTimer=[NSTimer scheduledTimerWithTimeInterval 
                :0.2 
                target:self 
                selector:@selector(stopTimer) 
                userInfo:nil
                repeats:YES];
    }
    
    return 0;
*/
}
/*
-(void)stopTimer{
    id tmp=[_commandQueue objectAtIndex:0];
    
    [_commandQueue removeObjectAtIndex:0];
    command=[tmp command];
    reqVal=[tmp reqVal];
    if(_connected) sendCommand();
    
    if([_commandQueue count]==0){
        [_periodTimer invalidate];
        _periodTimer=nil;
    }
}
*/
-(void)setStatus{
    switch(iobuff[5]%0x10){
        case 1:		_status.powerOn=YES;	_status.mute=NO;	break;
        case 2:		_status.powerOn=NO;	_status.mute=NO;	break;
        case 3:		_status.powerOn=YES;	_status.mute=YES;	break;
        default:	_status.powerOn=NO;	_status.mute=YES;	break;
    }
    switch((iobuff[5]/0x10)%0x08){
        case 0x01:		_status.tone=NB1;	break;
        case 0x02:		_status.tone=NB2;	break;
        case 0x03:		_status.tone=TONE;	break;
        default:	_status.tone=NONE;	break;
    }
    //NSLog(@"%X",(iobuff[5]/0x10)%0x08);
    switch(iobuff[3]%0x10){
        case 0:
            _status.inputMode=FM;
            if(iobuff[14]==0x01){
                _status.inputMode=AM;
                _status.rStationNum_U=hex2int(iobuff[12]);//radio station number
                _status.rStationNum_D=hex2int(iobuff[13]);//radio station number
                _status.rPresetNum=hex2int(iobuff[9]);//PRESET NUMBER
            }else{
                _status.rPresetNum=hex2int(iobuff[9]);//PRESET NUMBER
                _status.rStationNum_U=hex2int(iobuff[12]);//radio station number
                _status.rStationNum_D=hex2int(iobuff[13]);//radio station number
            }
            break;
        case 1:
            _status.inputMode=CD;
            _status.cdTracknum=hex2int(iobuff[9]);//track No.
            _status.cdMin=hex2int(iobuff[10]);//Min;
            _status.cdSec=hex2int(iobuff[11]);//Sec;
            _status.cdMaxTrack=hex2int(iobuff[13]);//全track数
            switch(iobuff[14]){
                case 0x02:	_status.repInfo=RAND;		break;
                case 0x04:	_status.repInfo=REP;		break;
                case 0x08:	_status.repInfo=RAll;		break;
                case 0x0A:	_status.repInfo=REPRAND;	break;
                default:	_status.repInfo=PLAIN;
            }
            //NSLog(@"%X",iobuff[14]);
            break;
        case 2:	_status.inputMode=MD;		break;
        case 3:	_status.inputMode=TAPE;		break;
        case 4: _status.inputMode=PC_USB;	break;
    }
    _status.atAuto=iobuff[15]?NO:YES;
    _status.volume=hex2int(iobuff[4]);
}

-(void)setConnedted:(BOOL)b{
    _connected=b;
}

-(VH7PC_stat *)statusRef{
    return &_status;
}

-(NSDictionary*)statusDictionary{
    return [NSDictionary dictionaryWithObjectsAndKeys:
        [NSNumber numberWithBool:_status.powerOn],@"PowerOn",
        [NSNumber numberWithBool:_status.mute],@"Mute",
        [NSNumber numberWithInt:_status.tone],@"Tone",
        [NSNumber numberWithInt:_status.inputMode],@"InputMode",
        [NSNumber numberWithInt:_status.rPresetNum],@"RadioPresetNumber",
        [NSNumber numberWithInt:_status.rStationNum_U],@"RadioStationNumberUpper",
        [NSNumber numberWithInt:_status.rStationNum_D],@"RadioStationNumberLower",
        [NSNumber numberWithInt:_status.cdTracknum],@"CDTrackNumber",
        [NSNumber numberWithInt:_status.cdMin],@"CDMinute",
        [NSNumber numberWithInt:_status.cdSec],@"CDSecond",
        [NSNumber numberWithInt:_status.cdMaxTrack],@"CDMaxTrack",
        [NSNumber numberWithInt:_status.repInfo],@"RepeatInfo",
        [NSNumber numberWithInt:_status.volume],@"Volume",
        [NSNumber numberWithBool:_status.atAuto],@"AutoMono",
    nil];
}

-(BOOL)connected{
    return _connected;
}


-(void)dealloc{
    NSDistributedNotificationCenter *nc;
    nc=[NSDistributedNotificationCenter notificationCenterForType:NSLocalNotificationCenterType];
    [nc removeObserver:self];

    notifireDealloc();
    if(_connected) releaseDevice();
    [_commandQueue release];
    [super dealloc];
}

@end
