Inheritance: System.ComponentModel.INotifyPropertyChanged
        protected override void Dispose(bool disposing)
        {
            if (null != device_info)
            {
                device_info.PropertyChanged -= prop_changed_handler;
                device_info = null;
            }

            base.Dispose(disposing);
        }
 protected override void Dispose(bool disposing)
 {
     if (null != device_info)
     {
         device_info.PropertyChanged -= prop_changed_handler;
         device_info = null;
     }
     
     base.Dispose(disposing);
 }
        public void SetDeviceInfo(BTDeviceInfo dinfo)
        {
            if (dinfo == device_info) return;

            if (null != device_info)
            {
                device_info.PropertyChanged -= prop_changed_handler;
                device_info = null;
            }

            device_info = dinfo;
            if (null != device_info)
            {
                device_info.PropertyChanged += prop_changed_handler;
                initView();
            }
        }
        public void SetDeviceInfo(BTDeviceInfo dinfo)
        {
            if (dinfo == device_info)
            {
                return;
            }

            if (null != device_info)
            {
                device_info.PropertyChanged -= prop_changed_handler;
                device_info = null;
            }

            device_info = dinfo;
            if (null != device_info)
            {
                device_info.PropertyChanged += prop_changed_handler;
                initView();
            }
        }
        static void packet_handler(byte packet_type, UInt16 channel, IntPtr packet_ptr, UInt16 size)
        {
            Byte[] packet = new Byte[size];
            Marshal.Copy(packet_ptr, packet, (int)0, (int)size);

            int numResponses = 0;

            Byte[] addr;

            BTDeviceInfo info;

            switch (packet_type)
            {
            case HCICommands.HCI_EVENT_PACKET:
                switch (packet[0])
                {
                case HCICommands.BTSTACK_EVENT_STATE:
                    // bt stack activated, get started - set local name
                    if (packet[2] == (byte)HCICommands.HCI_STATE.HCI_STATE_WORKING)
                    {
                        BTStackWrapper.bt_send_cmd(ref HCICommands.hci_write_inquiry_mode, (byte)0x01);         // with RSSI
                        next();
                    }
                    break;

                case HCICommands.HCI_EVENT_COMMAND_COMPLETE:
                    if (BTStackWrapper.IsCommandCompleteEvent(packet, HCICommands.hci_write_inquiry_mode))
                    {
                        next();
                    }
                    break;

                case HCICommands.HCI_EVENT_INQUIRY_RESULT:
                    numResponses = packet[2];
                    for (int i = 0; i < numResponses && device_list.Count < MAX_DEVICES; i++)
                    {
                        // get address
                        addr = new byte[6];
                        Array.Copy(packet, 3 + i * 6, addr, 0, addr.Length);
                        Array.Reverse(addr);

                        info = getDeviceInfoForAddress(addr);
                        if (null != info)
                        {
                            continue;
                        }

                        info = new BTDeviceInfo(addr)
                        {
                            PageScanRepetitionMode = packet[3 + 6 * numResponses + i * 1],
                            ClassOfDevice          = BTStackWrapper.readBt24(packet, 3 + (6 + 1 + 1 + 1) * numResponses + i * 3),
                            ClockOffset            = (UInt16)(BTStackWrapper.readBt16(packet, 3 + (6 + 1 + 1 + 1 + 3) * numResponses + i * 2) & 0x7fff),
                            Rssi  = 0,
                            State = BTDeviceInfo.Status.Found
                        };
                        device_list.Add(info);
                        invokeDeviceListChangedEvent();
                        Debug.WriteLine(String.Format("Device found: {0} with COD: 0x{1:6X}, pageScan:{2} clock offset {3}.", info.GetBtAddress(), info.ClassOfDevice, info.PageScanRepetitionMode, info.ClockOffset));
                    }
                    break;

                case HCICommands.HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:
                    numResponses = packet[2];
                    for (int i = 0; i < numResponses && device_list.Count < MAX_DEVICES; i++)
                    {
                        // get address
                        addr = new byte[6];
                        Array.Copy(packet, 3 + i * 6, addr, 0, addr.Length);
                        Array.Reverse(addr);

                        info = getDeviceInfoForAddress(addr);
                        if (null != info)
                        {
                            continue;
                        }

                        info = new BTDeviceInfo(addr)
                        {
                            PageScanRepetitionMode = packet[3 + 6 * numResponses + i * 1],
                            ClassOfDevice          = BTStackWrapper.readBt24(packet, 3 + (6 + 1 + 1 + 1) * numResponses + i * 3),
                            ClockOffset            = (UInt16)(BTStackWrapper.readBt16(packet, 3 + (6 + 1 + 1 + 1 + 3) * numResponses + i * 2) & 0x7fff),
                            Rssi  = packet[3 + numResponses * (6 + 1 + 1 + 3 + 2) + i * 1],
                            State = BTDeviceInfo.Status.Found
                        };
                        device_list.Add(info);
                        invokeDeviceListChangedEvent();
                        Debug.WriteLine(String.Format("Device found: {0} with COD: 0x{1:6X}, pageScan:{2} clock offset {3}.", info.GetBtAddress(), info.ClassOfDevice, info.PageScanRepetitionMode, info.ClockOffset));
                    }
                    break;

                case HCICommands.HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
                    // get address
                    addr = new byte[6];
                    Array.Copy(packet, 3, addr, 0, addr.Length);
                    Array.Reverse(addr);
                    info = getDeviceInfoForAddress(addr);
                    if (null != info)
                    {
                        if (packet[2] == 0)
                        {
                            var name = System.Text.Encoding.ASCII.GetString(packet, 9, packet.Length - 9);
                            Debug.WriteLine(String.Format("Name: {0}", name));
                            info.DeviceName = name;
                            info.State      = BTDeviceInfo.Status.RemoteNameFound;
                        }
                        else
                        {
                            Debug.WriteLine("Failed to get name: page timeout.");
                        }
                    }
                    next();
                    break;

                case HCICommands.HCI_EVENT_INQUIRY_COMPLETE:
                    Debug.WriteLine("Inquiry scan done.");
                    foreach (var device in device_list)
                    {
                        if (device.State == BTDeviceInfo.Status.RemoteNameTried)
                        {
                            device.State = BTDeviceInfo.Status.Found;
                        }
                    }
                    next();
                    break;

                default:
                    break;
                }
                break;

            default:
                break;
            }
        }
        static void packet_handler(byte packet_type,  UInt16 channel, IntPtr packet_ptr, UInt16 size) 
        {
            Byte[] packet = new Byte[size];
            Marshal.Copy(packet_ptr, packet, (int)0, (int)size);

            int numResponses = 0;
            Byte[] addr;

            BTDeviceInfo info;
            switch (packet_type)
            {
                case HCICommands.HCI_EVENT_PACKET:
                    switch (packet[0])
                    {
                        case HCICommands.BTSTACK_EVENT_STATE:
                            // bt stack activated, get started - set local name                                            
                            if (packet[2] == (byte)HCICommands.HCI_STATE.HCI_STATE_WORKING)
                            {
                                BTStackWrapper.bt_send_cmd(ref HCICommands.hci_write_inquiry_mode, (byte)0x01); // with RSSI
                                next();
                            }
                            break;
                        case HCICommands.HCI_EVENT_COMMAND_COMPLETE:
                            if (BTStackWrapper.IsCommandCompleteEvent(packet, HCICommands.hci_write_inquiry_mode))
                            {
                                next();
                            }
                            break;
                        case HCICommands.HCI_EVENT_INQUIRY_RESULT:
                            numResponses = packet[2];
                            for (int i = 0; i < numResponses && device_list.Count < MAX_DEVICES; i++)
                            {
                                // get address
                                addr = new byte[6];
                                Array.Copy(packet, 3 + i * 6, addr, 0, addr.Length);
                                Array.Reverse(addr);

                                info = getDeviceInfoForAddress(addr);
                                if (null != info) continue;

                                info = new BTDeviceInfo(addr)
                                {                                    
                                    PageScanRepetitionMode = packet[3 + 6 * numResponses + i * 1],
                                    ClassOfDevice = BTStackWrapper.readBt24(packet, 3 + (6 + 1 + 1 + 1) * numResponses + i * 3),
                                    ClockOffset = (UInt16)(BTStackWrapper.readBt16(packet, 3 + (6 + 1 + 1 + 1 + 3) * numResponses + i * 2) & 0x7fff),
                                    Rssi = 0,
                                    State = BTDeviceInfo.Status.Found
                                };
                                device_list.Add(info);
                                invokeDeviceListChangedEvent();
                                Debug.WriteLine(String.Format("Device found: {0} with COD: 0x{1:6X}, pageScan:{2} clock offset {3}.", info.GetBtAddress(), info.ClassOfDevice, info.PageScanRepetitionMode, info.ClockOffset));
                            }
                            break;
                        case HCICommands.HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:
                            numResponses = packet[2];
                            for (int i = 0; i < numResponses && device_list.Count < MAX_DEVICES; i++)
                            {
                                // get address
                                addr = new byte[6];
                                Array.Copy(packet, 3 + i * 6, addr, 0, addr.Length);
                                Array.Reverse(addr);

                                info = getDeviceInfoForAddress(addr);
                                if (null != info) continue;

                                info = new BTDeviceInfo(addr)
                                {                                
                                    PageScanRepetitionMode = packet[3 + 6 * numResponses + i * 1],
                                    ClassOfDevice = BTStackWrapper.readBt24(packet, 3 + (6 + 1 + 1 + 1) * numResponses + i * 3),
                                    ClockOffset = (UInt16)(BTStackWrapper.readBt16(packet, 3 + (6 + 1 + 1 + 1 + 3) * numResponses + i * 2) & 0x7fff),
                                    Rssi = packet[3 + numResponses * (6 + 1 + 1 + 3 + 2) + i * 1],
                                    State = BTDeviceInfo.Status.Found
                                };
                                device_list.Add(info);
                                invokeDeviceListChangedEvent();
                                Debug.WriteLine(String.Format("Device found: {0} with COD: 0x{1:6X}, pageScan:{2} clock offset {3}.", info.GetBtAddress(), info.ClassOfDevice, info.PageScanRepetitionMode, info.ClockOffset));
                            }
                            break;
                        case HCICommands.HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
                            // get address
                            addr = new byte[6];
                            Array.Copy(packet, 3, addr, 0, addr.Length);
                            Array.Reverse(addr);
                            info = getDeviceInfoForAddress(addr);
                            if (null != info)
                            {
                                if (packet[2] == 0)
                                {
                                    var name = System.Text.Encoding.ASCII.GetString(packet, 9, packet.Length - 9);
                                    Debug.WriteLine(String.Format("Name: {0}", name));
                                    info.DeviceName = name;
                                    info.State = BTDeviceInfo.Status.RemoteNameFound;
                                }
                                else
                                {
                                    Debug.WriteLine("Failed to get name: page timeout.");
                                }
                            }
                            next();
                            break;

                        case HCICommands.HCI_EVENT_INQUIRY_COMPLETE:
                            Debug.WriteLine("Inquiry scan done.");
                            foreach (var device in device_list)
                            {
                                if (device.State == BTDeviceInfo.Status.RemoteNameTried)
                                    device.State = BTDeviceInfo.Status.Found;
                            }
                            next();
                            break;

                        default:
                            break;
                    }
                    break;

                default:
                    break;             
            }

        }