private void BulkReadingThread()
        {
            while (true)
            {
                //Read every bInterval
                Thread.Sleep(BulkInPipe.PipeEndpoint.bInterval);
                {
                    try
                    {
                        BulkInPipe.TransferData(BulkInBuffer, 0, BulkInBuffer.Length);
                        // uncomment for debugging
                        /*
                        int i = 0;
                        WriteSerial(
                            ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " +
                            ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " +
                            ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " +
                            ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " +
                            ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " +
                            ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " +
                            ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " +
                            ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " +
                            ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " +
                            ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " +
                            ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " +
                            ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " +
                            ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " +
                            ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " +
                            ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " +
                            ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++]) + " " + ByteToHex(BulkInBuffer[i++])
                            );
                        */
                        if (((BulkInBuffer[0] | (BulkInBuffer[1] << 8)) == (hci_handle | 0x2000)))//acl_handle_ok
                        {
                            if ((BulkInBuffer[6] | (BulkInBuffer[7] << 8)) == 0x0001)//l2cap_control - Channel ID for ACL-U
                            {
                                if (BulkInBuffer[8] != 0x00)
                                    Debug.Print("L2CAP Signaling Command - 0x" + ByteToHex(BulkInBuffer[8]));

                                if (BulkInBuffer[8] == L2CAP_CMD_COMMAND_REJECT)
                                    Debug.Print("L2CAP Command Reject - Reason: " + ByteToHex(BulkInBuffer[13]) + ByteToHex(BulkInBuffer[12]) + " Data: " + ByteToHex(BulkInBuffer[17]) + " " + ByteToHex(BulkInBuffer[16]) + " " + ByteToHex(BulkInBuffer[15]) + " " + ByteToHex(BulkInBuffer[14]));
                                else if (BulkInBuffer[8] == L2CAP_CMD_CONNECTION_REQUEST)
                                {
                                    //Debug.Print("Code: 0x" + ByteToHex(BulkInBuffer[8]) + " Identifier: 0x" + ByteToHex(BulkInBuffer[9]) + " Length: 0x" + ByteToHex(BulkInBuffer[11]) + ByteToHex(BulkInBuffer[10]) + " PSM: 0x" + ByteToHex(BulkInBuffer[13]) + ByteToHex(BulkInBuffer[12]) + " SCID: 0x" + ByteToHex(BulkInBuffer[15]) + ByteToHex(BulkInBuffer[14]));
                                    Debug.Print("L2CAP Connection Request - Source CID: 0x" + ByteToHex(BulkInBuffer[15]) + ByteToHex(BulkInBuffer[14]) + " PSM: 0x" + ByteToHex(BulkInBuffer[13]) + ByteToHex(BulkInBuffer[12]));
                                    if ((BulkInBuffer[13] | BulkInBuffer[12]) == L2CAP_PSM_HID_CTRL)
                                    {
                                        identifier = BulkInBuffer[9];
                                        control_scid[0] = BulkInBuffer[14];
                                        control_scid[1] = BulkInBuffer[15];
                                        l2cap_event_status |= l2cap_event.L2CAP_EV_CONTROL_CONNECTION_REQUEST;
                                    }
                                    else if ((BulkInBuffer[13] | BulkInBuffer[12]) == L2CAP_PSM_HID_INTR)
                                    {
                                        identifier = BulkInBuffer[9];
                                        interrupt_scid[0] = BulkInBuffer[14];
                                        interrupt_scid[1] = BulkInBuffer[15];
                                        l2cap_event_status |= l2cap_event.L2CAP_EV_INTERRUPT_CONNECTION_REQUEST;
                                    }
                                }
                                else if (BulkInBuffer[8] == L2CAP_CMD_CONFIG_RESPONSE)
                                {
                                    if (BulkInBuffer[12] == control_dcid[0] && BulkInBuffer[13] == control_dcid[1])
                                    {
                                        if ((BulkInBuffer[16] | (BulkInBuffer[17] << 8)) == 0x0000)//Success
                                        {
                                            Debug.Print("HID Control Configuration Complete");
                                            l2cap_event_status |= l2cap_event.L2CAP_EV_CONTROL_CONFIG_SUCCESS;
                                        }
                                    }
                                    else if (BulkInBuffer[12] == interrupt_dcid[0] && BulkInBuffer[13] == interrupt_dcid[1])
                                    {
                                        if ((BulkInBuffer[16] | (BulkInBuffer[17] << 8)) == 0x0000)//Success
                                        {
                                            Debug.Print("HID Interrupt Configuration Complete");
                                            l2cap_event_status |= l2cap_event.L2CAP_EV_INTERRUPT_CONFIG_SUCCESS;
                                        }
                                    }
                                }
                                else if (BulkInBuffer[8] == L2CAP_CMD_CONFIG_REQUEST)
                                {
                                    if (BulkInBuffer[12] == control_dcid[0] && BulkInBuffer[13] == control_dcid[1])
                                    {
                                        Debug.Print("HID Control Configuration Request");
                                        identifier = BulkInBuffer[9];
                                        l2cap_event_status |= l2cap_event.L2CAP_EV_CONTROL_CONFIG_REQUEST;
                                    }
                                    else if (BulkInBuffer[12] == interrupt_dcid[0] && BulkInBuffer[13] == interrupt_dcid[1])
                                    {
                                        Debug.Print("HID Interrupt Configuration Request");
                                        identifier = BulkInBuffer[9];
                                        l2cap_event_status |= l2cap_event.L2CAP_EV_INTERRUPT_CONFIG_REQUEST;
                                    }
                                }
                                else if (BulkInBuffer[8] == L2CAP_CMD_DISCONNECT_REQUEST)
                                {
                                    if (BulkInBuffer[12] == control_dcid[0] && BulkInBuffer[13] == control_dcid[1])
                                        Debug.Print("Disconnected Request: Disconnected Control");

                                    else if (BulkInBuffer[12] == interrupt_dcid[0] && BulkInBuffer[13] == interrupt_dcid[1])
                                        Debug.Print("Disconnected Request: Disconnected Interrupt");
                                }
                                else if (BulkInBuffer[8] == L2CAP_CMD_DISCONNECT_RESPONSE)
                                {
                                    if (BulkInBuffer[12] == control_scid[0] && BulkInBuffer[13] == control_scid[1])
                                    {
                                        Debug.Print("Disconnected Response: Disconnected Control");
                                        identifier = BulkInBuffer[9];
                                        l2cap_event_status |= l2cap_event.L2CAP_EV_CONTROL_DISCONNECT_RESPONSE;
                                    }

                                    else if (BulkInBuffer[12] == interrupt_scid[0] && BulkInBuffer[13] == interrupt_scid[1])
                                    {
                                        Debug.Print("Disconnected Response: Disconnected Interrupt");
                                        identifier = BulkInBuffer[9];
                                        l2cap_event_status |= l2cap_event.L2CAP_EV_INTERRUPT_DISCONNECT_RESPONSE;
                                    }
                                }
                            }
                            else if (BulkInBuffer[6] == interrupt_dcid[0] && BulkInBuffer[7] == interrupt_dcid[1])//l2cap_interrupt
                            {
                                //Debug.Print("L2CAP Interrupt");
                                //readReport();//Uncomment for debugging
                            }
                            L2CAP_task();
                        }

                    }
                    catch (Exception ex)
                    {
                        WriteSerial("Exception was thrown - try reconnecting the bluetooth dongle");
                        Debug.Print("==============================");
                        Debug.Print(DateTime.Now.ToString());
                        Debug.Print(ex.Message);
                        Debug.Print(ex.StackTrace);
                        if (ex.InnerException != null)
                        {
                            Debug.Print("Inner Exception: " + ex.InnerException.Message);
                        }
                    }
                }
            }
        }
        void HCI_task()
        {
            switch (hci_state)
            {
                case HCI_INIT_STATE:
                    hci_counter++;
                    if (hci_counter > 10)
                    {
                        // wait until we have looped 10 times to clear any old events
                        WriteSerial("Init State");
                        hci_reset();
                        hci_state = HCI_RESET_STATE;
                        hci_counter = 0;
                    }
                    break;

                case HCI_RESET_STATE:
                    hci_counter++;
                    if (hciflag(hci_event.HCI_FLAG_CMD_COMPLETE))
                    {
                        WriteSerial("HCI Reset Complete");
                        hci_state = HCI_BDADDR_STATE;
                        hci_read_bdaddr();
                        hci_counter = 0;
                    }
                    if (hci_counter > 100)
                    {
                        WriteSerial("No Response to HCI Reset - Try reconnecting the Bluetooth Dongle");
                        hci_state = HCI_INIT_STATE;
                        hci_counter = 0;
                    }
                    break;

                case HCI_BDADDR_STATE:
                    if (hciflag(hci_event.HCI_FLAG_CMD_COMPLETE))
                    {
                        WriteSerial("Local Bluetooth Address: " + ByteToHex(my_bdaddr[5]).ToString() + ":" + ByteToHex(my_bdaddr[4]).ToString() + ":" + ByteToHex(my_bdaddr[3]).ToString() + ":" + ByteToHex(my_bdaddr[2]).ToString() + ":" + ByteToHex(my_bdaddr[1]).ToString() + ":" + ByteToHex(my_bdaddr[0]).ToString());
                        BDaddr[0] = my_bdaddr[5];//The commands are sent as LSB
                        BDaddr[1] = my_bdaddr[4];
                        BDaddr[2] = my_bdaddr[3];
                        BDaddr[3] = my_bdaddr[2];
                        BDaddr[4] = my_bdaddr[1];
                        BDaddr[5] = my_bdaddr[0];

                        hci_state = HCI_SCANNING_STATE;
                    }
                    break;

                case HCI_SCANNING_STATE:
                    WriteSerial("Wait For Incoming Connection Request");
                    hci_write_scan_enable();
                    hci_state = HCI_CONNECT_IN_STATE;
                    break;

                case HCI_CONNECT_IN_STATE:
                    if (hciflag(hci_event.HCI_FLAG_INCOMING_REQUEST))
                    {
                        WriteSerial("Incoming Request");
                        hci_remote_name(0);
                        hci_state = HCI_REMOTE_NAME;
                    }
                    break;

                case HCI_REMOTE_NAME:
                    if (hciflag(hci_event.HCI_FLAG_REMOTE_NAME))
                    {
                        WriteSerial("Remote Name:");
                        byte i;
                        for (i = 0; i < 40; i++)
                        {
                            if (remote_name[i] == 0x00)
                                break;
                        }
                        remote_name[i] = 13;// Carriage Return
                        remote_name[i + 1] = 10;// Line Feed

                        UART.Write(remote_name, 0, i + 2);
                        hci_accept_connection();
                        hci_state = HCI_CONNECTED_STATE;
                    }
                    break;

                case HCI_CONNECTED_STATE:
                    if (hciflag(hci_event.HCI_FLAG_CONN_COMPLETE))
                    {
                        WriteSerial("Connected to Device: " + ByteToHex(disc_bdaddr[5]) + ":" + ByteToHex(disc_bdaddr[4]) + ":" + ByteToHex(disc_bdaddr[3]) + ":" + ByteToHex(disc_bdaddr[2]) + ":" + ByteToHex(disc_bdaddr[1]) + ":" + ByteToHex(disc_bdaddr[0]));
                        hci_write_scan_disable();//Only allow one controller
                        hci_state = HCI_DISABLE_SCAN;
                    }
                    break;

                case HCI_DISABLE_SCAN:
                    if (hciflag(hci_event.HCI_FLAG_CMD_COMPLETE))
                    {
                        WriteSerial("Scan Disabled");
                        l2cap_state = L2CAP_EV_CONTROL_SETUP;
                        hci_state = HCI_DONE_STATE;
                    }
                    break;

                case HCI_DONE_STATE:
                    if (hciflag(hci_event.HCI_FLAG_DISCONN_COMPLETE))
                        hci_state = HCI_DISCONNECT_STATE;
                    break;

                case HCI_DISCONNECT_STATE:
                    if (hciflag(hci_event.HCI_FLAG_DISCONN_COMPLETE))
                    {
                        WriteSerial("Disconnected from Device: " + ByteToHex(disc_bdaddr[5]) + ":" + ByteToHex(disc_bdaddr[4]) + ":" + ByteToHex(disc_bdaddr[3]) + ":" + ByteToHex(disc_bdaddr[2]) + ":" + ByteToHex(disc_bdaddr[1]) + ":" + ByteToHex(disc_bdaddr[0]));
                        l2cap_event_status = 0;//Clear all flags
                        hci_event_flag = 0;//Clear all flags

                        //Reset all buffers
                        for (byte i = 0; i < IntInBuffer.Length; i++)
                            IntInBuffer[i] = 0;
                        for (byte i = 0; i < HCIBuffer.Length; i++)
                            HCIBuffer[i] = 0;
                        for (byte i = 0; i < BulkInBuffer.Length; i++)
                            BulkInBuffer[i] = 0;
                        for (byte i = 0; i < L2CAPBuffer.Length; i++)
                            L2CAPBuffer[i] = 0;
                        for (int i = 0; i < PS3Controller.OUTPUT_REPORT_BUFFER.Length; i++)//First two bytes reserved for report type and ID
                            HIDBuffer[i + 2] = PS3Controller.OUTPUT_REPORT_BUFFER[i];
                        for (int i = 2; i < HIDMoveBuffer.Length; i++)//First two bytes reserved for DATA request and ID
                            HIDMoveBuffer[i] = 0;

                        l2cap_state = L2CAP_EV_WAIT;
                        hci_state = HCI_SCANNING_STATE;
                    }
                    break;
                default:
                    break;

            }
        }
 private bool l2capflag(l2cap_event flag)
 {
     if ((l2cap_event_status & flag) == flag)
         return true;
     else
         return false;
 }