//
//  HA_USBDeviceObject.h
//  HA_server
//
//  Created by hark on 2013/07/10.
//  Copyright (c) 2013年 hark. All rights reserved.
//

#ifndef __HA_server__HA_USBDeviceObject__
#define __HA_server__HA_USBDeviceObject__

#ifdef __cplusplus

#include "HA_config.h"

#ifndef IS_APPLE_IOS

#include <linux/usbdevice_fs.h>
//// for struct usb_device_descriptor, etc...
#include <linux/version.h>
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
#include <linux/usb/ch9.h>
#else
#include <linux/usb_ch9.h>
#endif
////

#define NUM_URBS        10
#define NUM_PACKETS     10
#define MAX_PACKET_SIZE 1024//459//512//768 //1024 is max isochronous packet size on USB 3.1 specific by USB.org

#else // IS_APPLE_IOS

#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreAudio/CoreAudioTypes.h>
#import <AudioUnit/AudioUnitProperties.h>
#import <AudioToolbox/AudioSession.h>
#else // __OBJC__
typedef void *AudioUnit;
#endif // __OBJC__

#endif // IS_APPLE_IOS

#include <iostream>

#include "HA_Object.h"
#include "HA_buffer.h"
#include "HA_device.h"

namespace HARKAndroid {

#ifndef IS_APPLE_IOS
    
typedef struct _USB_DEVICE_
{
    int device_type;
    int fd; // if fd == -1 is set, invalid file descriptor.
    int channels;
    int bits;
    int interface_no;
    int address;
    int max_packet_size;

    char dev_name[64]; // current open device name.
    unsigned char desc[4096]; // current open device description.
    int desc_length; // current open device description length.
    int is_writeable; // fd is writeable.
} USB_DEVICE_t;

class USBDeviceObject : public DeviceObject {
private:
    pthread_t thread_id;
    ::pthread_mutex_t Being_Stopped_mutex;
    bool BeingStopped;
    
    USB_DEVICE_t usb_device_info;
    
    unsigned char iso_buffer[NUM_URBS][MAX_PACKET_SIZE * NUM_PACKETS];
    struct usbdevfs_urb *urbs[NUM_URBS];
    int urb_size;
    int urb_submit_count;

    char device_list[128][32]; // usb device list (include unsupported device)
    int device_count;
    int inf_ok, ep_ok;
public:
    USBDeviceObject(const USBDeviceObject&);
    USBDeviceObject();
    virtual ~USBDeviceObject();
    USBDeviceObject& operator = (const USBDeviceObject&);
    
    int open();
    int start(BufferObject&);
    int stop();
    int close();
    int allclose(){
        return close();
    }
    
    int SetBeingStopped();
    int ResetBeingStopped();
    bool isBeingStopped();
    
    BufferObject *buffer;
    
/*
enum {
    USB_VID_SIF   = 0x23a7, // System In Frontier, Inc.
    USB_VID_OVT   = 0x1415, // Nam Tai E&E Products Ltd. OmniVision Technologies, Inc.
    USB_VID_MS    = 0x045e, // Microsoft Corp.
    UBS_VID_DA    = 0x2212, // DevAudio.
    USB_VID_CIP   = 0x10c4, // Cygnal Integrated Products, Inc.
    USB_VID_TMP   = 0xf0f0, // Temporary USB VID (for under development)
    USB_VID_DUMMY = 0xffff  // dummy vid
}

enum {
    USB_PID_SIF_RASP_LC    = 0x0002, // RASP-LC
    USB_PID_SIF_RASP_ZX    = 0x0004, // RASP-ZX
    USB_PID_SIF_RASP_LC4   = 0x0005, // RASP-LC
    USB_PID_SIF_RASP_ZX8   = 0x0006, // RASP-ZX
    USB_PID_SIF_RASP_ZXV   = 0xf100, // New type RASP-ZX, Cascade microphone(s) are variable.
    USB_PID_OVT_PS_EYE     = 0x2000, // Sony PS-Eye for Play Station
    USB_PID_MS_KINECT_WIN  = 0x02be, // Kinect for Windows Microphone : [memo] 0x02bf is camera, 0x02c2 is motor?
    USB_PID_MS_KINECT_XBOX = 0x02ad, // Kinect for XBOX360 Microphone : [memo] 0x02ae is camera, 0x02b0 is motor
    USB_PID_DA_MICROCONE   = 0x0001, // Microcone
    USB_PID_CIP_HRI_KM     = 0xea60, // HRI Special Microphone type KM
    USB_PID_TMP_HRI_SHT    = 0x0000, // HRI Special Microphone type SHT
    USB_PID_DUMMY_DUMMY    = 0xffff  // dummy pid
}
*/

    int InitDevice(void);
    int InitDevice(int vid, int pid, int pid_mask);
    int ReleaseDevice(void);
    int CreateUSBDeviceList(void);
    int FindUSBDeviceAndSet(unsigned int vid, unsigned int pid, unsigned int pid_mask, int create_list);
    int USBDeviceOpen(const char *dev_name);
    int USBDeviceClose(void);
    int USBDeviceNew(const char *dev_name);
    int TryEnableWriteMode(void);
    int GetFD(void);
    const char* GetDeviceName(void);
    int GetUniqueID(const char *dev_name);
    int GetDeviceNameFromUniqueID(int id, char *dev_name);
    unsigned int GetVendorID(void);
    unsigned int GetProductID(void);
    int GetString(int index, char *ret_string);
    int GetManufacturerName(int index, char *ret_string);
    int GetProductName(int index, char *ret_string);
    int GetSerialNumber(int index, char *ret_string);
    int USBClaimInterface(unsigned int interface, int force);
    int ReleaseInterface(unsigned int interface);
    int ConnectKernelDriver(unsigned int interface, int connect);
    int SetConfiguration(unsigned int configuration);
    int SetInterface(unsigned int interface, unsigned int altsetting);
    
    void FreeUrbs(void);
    int SubmitUrb(int index);
    int RecStart();
    int RecStop();
    int ReadData(unsigned char *data, int buf_size);
    
    int SetDeviceType(int device_type){
        usb_device_info.device_type = device_type;
        return 0;
    }
    int SetDevice(int channels, int bits){
        usb_device_info.channels    = channels;
        usb_device_info.bits        = bits;
        return 0;
    }
    int GetChannels(){
        return usb_device_info.channels;
    }
    int GetBits(){
        return usb_device_info.bits;
    }
    int SetInterface(int interface_no, int address, int max_packet_size){
        usb_device_info.interface_no    = interface_no;
        usb_device_info.address         = address;
        usb_device_info.max_packet_size = max_packet_size;
        return 0;
    }
    int GetMaxPacketSize(){
    	return usb_device_info.max_packet_size;
    }
    int SetFd(int fd){
        usb_device_info.fd = fd;
        return 0;
    }
};

#else // IS_APPLE_IOS
    
class USBDeviceObject : public DeviceObject {
private:
    
public:
    enum AudioUnitElement {
        kOutputElement = 0,
        kInputElement = 1
    };

    int num_channels;
    int nbits_per_Channel;
    int samplerate;
    
    USBDeviceObject(const USBDeviceObject&);
    USBDeviceObject();
    virtual ~USBDeviceObject();
    USBDeviceObject& operator = (const USBDeviceObject&);
    
    int open();
    int start(BufferObject&);
    int stop();
    int close();
    
    int setBitsPerChannel(const int bits_per_channel){
        nbits_per_Channel = bits_per_channel;
        return(0);
    }
    int setSampleRate(const int rate){
        samplerate = rate;
        return(0);
    }
    AudioUnit outputUnit;
    BufferObject *buffer;
};

#endif // IS_APPLE_IOS

} // end of namespace
#endif // __cpusplus

#endif /* defined(__HA_server__HA_USBDeviceObject__) */
