//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "main.h"
#include "math.h"
#include "wclErrors.hpp"
#include "wclUUIDs.hpp"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "wclBluetooth"
#pragma resource "*.dfm"
//---------------------------------------------------------------------------
__fastcall TFrameStorage::TFrameStorage(const TAdvertisementFrame Frame,
		const __int64 Address, const __int64 Timestamp, const SByte Rssi)
{
		FAddress = Address;
		FFrame = Frame;
		FTimestamp = Timestamp;
		FRssi = Rssi;
}
//---------------------------------------------------------------------------
TFrameStorage::~TFrameStorage()
{
}
//---------------------------------------------------------------------------
__fastcall TGuidFrameStorage::TGuidFrameStorage(const TAdvertisementFrame Frame,
        const __int64 Address, const __int64 Timestamp, const SByte Rssi,
        const TGUID& Uuid)
        : TFrameStorage(Frame, Address, Timestamp, Rssi)
{
        FUuid = Uuid;
}
//---------------------------------------------------------------------------
__fastcall TDataFrameStorage::TDataFrameStorage(const TAdvertisementFrame Frame,
        const __int64 Address, const __int64 Timestamp, const SByte Rssi,
        const TwclBluetoothLeAdvertisementFrameRawData& Data)
        : TFrameStorage(Frame, Address, Timestamp, Rssi)
{
        FData = Data;
}
//---------------------------------------------------------------------------
__fastcall TGuidDataFrameStorage::TGuidDataFrameStorage(const TAdvertisementFrame Frame,
        const __int64 Address, const __int64 Timestamp, const SByte Rssi,
        const TGUID& Uuid, const TwclBluetoothLeAdvertisementFrameRawData& Data)
        : TDataFrameStorage(Frame, Address, Timestamp, Rssi, Data)
{
        FUuid = Uuid;
}
//---------------------------------------------------------------------------
__fastcall TAppearanceFrame::TAppearanceFrame(const __int64 Address,
        const __int64 Timestamp, const SByte Rssi, const Word Appearance)
        : TFrameStorage(afAppearance, Address, Timestamp, Rssi)
{
        FAppearance = Appearance;
}
//---------------------------------------------------------------------------
__fastcall TExtInformationFrame::TExtInformationFrame(const __int64 Address,
        const __int64 Timestamp, const SByte Rssi,
        const TwclBluetoothAddressType AddressType,
        const TwclBluetoothLeExtendedFrameFlags& Flags, const SByte TxPower)
        : TFrameStorage(afExtInformation, Address, Timestamp, Rssi)
{
        FAddressType = AddressType;
        FFlags = Flags;
        FTxPower = TxPower;
}
//---------------------------------------------------------------------------
__fastcall TInformationFrame::TInformationFrame(const __int64 Address,
        const __int64 Timestamp, const SByte Rssi,
        const TwclBluetoothLeAdvertisementFlags& Flags, const String& Name,
        const TwclBluetoothLeAdvertisementType PacketType)
        : TFrameStorage(afInformation, Address, Timestamp, Rssi)
{
        FFlags = Flags;
        FName = Name;
        FPacketType = PacketType;
}
//---------------------------------------------------------------------------
__fastcall TRawFrame::TRawFrame(const __int64 Address, const __int64 Timestamp,
        const SByte Rssi, const TwclBluetoothLeAdvertisementFrameRawData& Data,
        const Byte DataType)
        : TDataFrameStorage(afRaw, Address, Timestamp, Rssi, Data)
{
        FDataType = DataType;
}
//---------------------------------------------------------------------------
__fastcall TDetailsFrame::TDetailsFrame(const __int64 Address, const __int64 Timestamp,
        const SByte Rssi, const TwclBluetoothLeAdvertisementFrameRawData& Data)
        : TDataFrameStorage(afDetails, Address, Timestamp, Rssi, Data)
{
}
//---------------------------------------------------------------------------
__fastcall TService16DataFrame::TService16DataFrame(const __int64 Address,
        const __int64 Timestamp, const SByte Rssi,
        const TwclBluetoothLeAdvertisementFrameRawData& Data, const Word Uuid)
        : TDataFrameStorage(afService16Data, Address, Timestamp, Rssi, Data)
{
        FUuid = Uuid;
}
//---------------------------------------------------------------------------
__fastcall TService32DataFrame::TService32DataFrame(const __int64 Address,
        const __int64 Timestamp, const SByte Rssi,
        const TwclBluetoothLeAdvertisementFrameRawData& Data, const Cardinal Uuid)
        : TDataFrameStorage(afService32Data, Address, Timestamp, Rssi, Data)
{
        FUuid = Uuid;
}
//---------------------------------------------------------------------------
__fastcall TService128DataFrame::TService128DataFrame(const __int64 Address,
        const __int64 Timestamp, const SByte Rssi, const TGUID& Uuid,
        const TwclBluetoothLeAdvertisementFrameRawData& Data)
        : TGuidDataFrameStorage(afService128Data, Address, Timestamp, Rssi, Uuid, Data)
{
}
//---------------------------------------------------------------------------
__fastcall TSol16Frame::TSol16Frame(const __int64 Address, const __int64 Timestamp,
        const SByte Rssi, const Word Uuid)
        : TFrameStorage(afSol16, Address, Timestamp, Rssi)
{
        FUuid = Uuid;
}
//---------------------------------------------------------------------------
__fastcall TSol32Frame::TSol32Frame(const __int64 Address, const __int64 Timestamp,
        const SByte Rssi, const Cardinal Uuid)
        : TFrameStorage(afSol32, Address, Timestamp, Rssi)
{
        FUuid = Uuid;
}
//---------------------------------------------------------------------------
__fastcall TSol128Frame::TSol128Frame(const __int64 Address, const __int64 Timestamp,
        const SByte Rssi, const TGUID& Uuid)
        : TGuidFrameStorage(afSol128, Address, Timestamp, Rssi, Uuid)
{
}
//---------------------------------------------------------------------------
__fastcall TTxPowerFrame::TTxPowerFrame(const __int64 Address, const __int64 Timestamp,
        const SByte Rssi, const SByte TxPower)
        : TFrameStorage(afTxPower, Address, Timestamp, Rssi)
{
        FTxPower = TxPower;
}
//---------------------------------------------------------------------------
__fastcall TUuidFrame::TUuidFrame(const __int64 Address, const __int64 Timestamp,
        const SByte Rssi, const TGUID& Uuid)
        : TGuidFrameStorage(afUuid, Address, Timestamp, Rssi, Uuid)
{
}
//---------------------------------------------------------------------------
__fastcall TBeaconFrame::TBeaconFrame(const TAdvertisementFrame Frame,
        const __int64 Address, const __int64 Timestamp, const SByte Rssi,
        const TwclBluetoothLeAdvertisementFrameRawData& Data, const TGUID& Uuid,
        const Word CompanyId, const Word Major, const Word Minor, const SByte TxRssi)
        : TGuidDataFrameStorage(Frame, Address, Timestamp, Rssi, Uuid, Data)
{
        FCompanyId = CompanyId;
        FMajor = Major;
        FMinor = Minor;
        FTxRssi = TxRssi;
}
//---------------------------------------------------------------------------
__fastcall TAltBeaconFrame::TAltBeaconFrame(const __int64 Address, const __int64 Timestamp,
        const SByte Rssi, const TwclBluetoothLeAdvertisementFrameRawData& Data,
        const TGUID& Uuid, const Word CompanyId, const Word Major, const Word Minor,
        const SByte TxRssi, const Byte Reserved)
        : TBeaconFrame(afAltBeacon, Address, Timestamp, Rssi, Data, Uuid,
                CompanyId, Major, Minor, TxRssi)
{
        FReserved = Reserved;
}
//---------------------------------------------------------------------------
__fastcall TMicrosoftCdpBeaconFrame::TMicrosoftCdpBeaconFrame(
        const __int64 Address, const __int64 Timestamp, const SByte Rssi,
        const bool AddressAsDeviceId, const TwclBluetoothLeCdpBeaconDeviceType DeviceType,
        const TwclBluetoothLeCdpBeaconExtendedDeviceStatuses ExtendedDeviceStatus,
        const TwclBluetoothLeCdpBeaconHash& Hash, const TwclBluetoothLeCdpBeaconSalt& Salt,
        const TwclBluetoothLeCdpBeaconScenarioType ScenarioType,
        const bool ShareNearBy, const Byte SubVersion, const Byte Version)
        : TFrameStorage(afMicrosoftCdpBeacon, Address, Timestamp, Rssi)
{
        FAddressAsDeviceId = AddressAsDeviceId;
        FDeviceType = DeviceType;
        FExtendedDeviceStatus = ExtendedDeviceStatus;
        FHash = Hash;
        FSalt = Salt;
        FScenarioType = ScenarioType;
        FShareNearBy = ShareNearBy;
        FSubVersion  = SubVersion;
        FVersion = Version;
}
//---------------------------------------------------------------------------
__fastcall TAppleFrame::TAppleFrame(const TAdvertisementFrame Frame,
        const TwclBluetoothLeAdvertisementInfo& Info)
        : TFrameStorage(Frame, Info.Address, Info.Timestamp, Info.Rssi)
{
}
//---------------------------------------------------------------------------
__fastcall TAppleAirdropFrame::TAppleAirdropFrame(
        const TwclBluetoothLeAdvertisementInfo& Info,
        const TwclBluetoothLeAppleAirdropFrameData& Data)
        : TAppleFrame(afAppleAirdrop, Info)
{
        FData = Data;
}
//---------------------------------------------------------------------------
__fastcall TAppleAirplaySourceFrame::TAppleAirplaySourceFrame(
        const TwclBluetoothLeAdvertisementInfo& Info,
        const TwclBluetoothLeAppleAirplaySourceFrameData& Data)
        : TAppleFrame(afAppleAirplaySource, Info)
{
        FData = Data;
}
//---------------------------------------------------------------------------
__fastcall TAppleAirplayTargetFrame::TAppleAirplayTargetFrame(
        const TwclBluetoothLeAdvertisementInfo& Info,
        const TwclBluetoothLeAppleAirplayTargetFrameData& Data)
        : TAppleFrame(afAppleAirplayTarget, Info)
{
        FData = Data;
}
//---------------------------------------------------------------------------
__fastcall TAppleAirprintFrame::TAppleAirprintFrame(
        const TwclBluetoothLeAdvertisementInfo& Info,
        const TwclBluetoothLeAppleAirprintFrameData& Data)
        : TAppleFrame(afAppleAirprint, Info)
{
        FData = Data;
}
//---------------------------------------------------------------------------
__fastcall TAppleHomeKitFrame::TAppleHomeKitFrame(
        const TwclBluetoothLeAdvertisementInfo& Info,
        const TwclBluetoothLeAppleHomeKitFrameData& Data)
        : TAppleFrame(afAppleHomeKit, Info)
{
        FData = Data;
}
//---------------------------------------------------------------------------
__fastcall TAppleiBeaconFrame::TAppleiBeaconFrame(
        const TwclBluetoothLeAdvertisementInfo& Info,
        const TwclBluetoothLeAppleiBeaconFrameData& Data)
        : TAppleFrame(afAppleiBeacon, Info)
{
        FData = Data;
}
//---------------------------------------------------------------------------
__fastcall TAppleNearbyActionFrame::TAppleNearbyActionFrame(
        const TwclBluetoothLeAdvertisementInfo& Info,
        const TwclBluetoothLeAppleNearbyActionFrameData& Data)
        : TAppleFrame(afAppleNearbyAction, Info)
{
        FData = Data;
}
//---------------------------------------------------------------------------
__fastcall TAppleNearbyInfoFrame::TAppleNearbyInfoFrame(
        const TwclBluetoothLeAdvertisementInfo& Info,
        const TwclBluetoothLeAppleNearbyInfoFrameData& Data)
        : TAppleFrame(afAppleNearbyInfo, Info)
{
        FData = Data;
}
//---------------------------------------------------------------------------
__fastcall TAppleProximityPairingFrame::TAppleProximityPairingFrame(
        const TwclBluetoothLeAdvertisementInfo& Info,
        const TwclBluetoothLeAppleProximityPairingFrameData& Data)\
        : TAppleFrame(afAppleProximityPairing, Info)
{
        FData = Data;
}
//---------------------------------------------------------------------------
__fastcall TAppleUnknownFrame::TAppleUnknownFrame(
        const TwclBluetoothLeAdvertisementInfo& Info,
        const TwclBluetoothLeAppleUnknownFrameData& Data)
        : TAppleFrame(afAppleUnknown, Info)
{
        FData = Data;
}
//---------------------------------------------------------------------------
__fastcall TAppleFindMyFrame::TAppleFindMyFrame(
        const TwclBluetoothLeAdvertisementInfo& Info,
        const TwclBluetoothLeAppleFindMyFrameData& Data)
        : TAppleFrame(afAppleFindMy, Info)
{
        FData = Data;
}
//---------------------------------------------------------------------------
__fastcall TAppleHandoffFrame::TAppleHandoffFrame(
        const TwclBluetoothLeAdvertisementInfo& Info,
        const TwclBluetoothLeAppleHandoffFrameData& Data)
        : TAppleFrame(afAppleHandoff, Info)
{
        FData = Data;
}
//---------------------------------------------------------------------------
__fastcall TAppleHeySiriFrame::TAppleHeySiriFrame(
        const TwclBluetoothLeAdvertisementInfo& Info,
        const TwclBluetoothLeAppleHeySiriFrameData& Data)
        : TAppleFrame(afAppleHeySiri, Info)
{
        FData = Data;
}
//---------------------------------------------------------------------------
__fastcall TAppleMagicSwitchFrame::TAppleMagicSwitchFrame(
        const TwclBluetoothLeAdvertisementInfo& Info,
        const TwclBluetoothLeAppleMagicSwitchFrameData& Data)
        : TAppleFrame(afAppleMagicSwitch, Info)
{
        FData = Data;
}
//---------------------------------------------------------------------------
__fastcall TAppleTetheringSourceFrame::TAppleTetheringSourceFrame(
        const TwclBluetoothLeAdvertisementInfo& Info,
        const TwclBluetoothLeAppleTetheringSourceFrameData& Data)
        : TAppleFrame(afAppleTetheringSource, Info)
{
        FData = Data;
}
//---------------------------------------------------------------------------
__fastcall TAppleTetheringTargetFrame::TAppleTetheringTargetFrame(
        const TwclBluetoothLeAdvertisementInfo& Info,
        const TwclBluetoothLeAppleTetheringTargetFrameData& Data)
        : TAppleFrame(afAppleTetheringTarget, Info)
{
        FData = Data;
}
//---------------------------------------------------------------------------
__fastcall TEddystoneTlmFrame::TEddystoneTlmFrame(const __int64 Address,
        const __int64 Timestamp, const SByte Rssi,
        const TwclBluetoothLeAdvertisementFrameRawData& Data, const Cardinal AdvCnt,
        const Word Batt, const Cardinal SecCnt, const Double Temp)
        : TDataFrameStorage(afEddystoneTlm, Address, Timestamp, Rssi, Data)
{
        FAdvCnt = AdvCnt;
        FBatt = Batt;
        FSecCnt = SecCnt;
        FTemp = Temp;
}
//---------------------------------------------------------------------------
__fastcall TEddystoneUidFrame::TEddystoneUidFrame(const __int64 Address,
        const __int64 Timestamp, const SByte Rssi,
        const TwclBluetoothLeAdvertisementFrameRawData& Data, const TGUID& Uuid,
        const SByte TxRssi)
        : TGuidDataFrameStorage(afEddystoneUid, Address, Timestamp, Rssi, Uuid, Data)
{
        FTxRssi = TxRssi;
}
//---------------------------------------------------------------------------
__fastcall TEddystoneUrlFrame::TEddystoneUrlFrame(const __int64 Address,
        const __int64 Timestamp, const SByte Rssi, const SByte TxRssi,
        const String& Url)
        : TFrameStorage(afEddystoneUrl, Address, Timestamp, Rssi)
{
        FTxRssi = TxRssi;
        FUrl = Url;
}
//---------------------------------------------------------------------------
__fastcall TManufacturerFrame::TManufacturerFrame(const __int64 Address,
        const __int64 Timestamp, const SByte Rssi, const Word CompanyId,
        const TwclBluetoothLeAdvertisementFrameRawData& Data)
        : TDataFrameStorage(afManufacturerRaw, Address, Timestamp, Rssi, Data)
{
        FCompanyId = CompanyId;
}
//---------------------------------------------------------------------------
__fastcall TDriAsdFrame::TDriAsdFrame(const __int64 Address,
        const __int64 Timestamp, const SByte Rssi, const TwclDriRawData& Raw)
        : TFrameStorage(afDriAsd, Address, Timestamp, Rssi)
{
        FRaw = Raw;
}
//---------------------------------------------------------------------------
TfmMain *fmMain;
//---------------------------------------------------------------------------
__fastcall TfmMain::TfmMain(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::AdvertiserDefaults()
{
        LeAdvertiser->RestoreDefaults();
        edAdvertiserInterval->Text = IntToStr(LeAdvertiser->Interval);

        cbAdvertiserBeacon->Checked = true;
        cbAdvertiserProximityBeacon->Checked = false;
        cbAdvertiserAltBeacon->Checked = false;
        cbAdvertiserEddystoneUid->Checked = false;
        cbAdvertiserEddystoneUrl->Checked = false;
        cbAdvertiser128SolUuid->Checked = false;
        cbAdvertiserManufacturer->Checked = false;
        cbAdvertiser16Uuid->Checked = false;
        cbAdvertiser32Uuid->Checked = false;
        cbAdvertiser128Uuid->Checked = false;
        cbAdvertiser16UuidData->Checked = false;
        cbAdvertiser32UuidData->Checked = false;
        cbAdvertiser128UuidData->Checked = false;
        cbAdvertiserCustom->Checked = false;

        cbAdvertiserExtended->Checked = false;
        cbAdvertiserAnonymous->Checked = false;
        cbAdvertiserTxRssi->Checked = false;

        cbAdvertiserAnonymous->Enabled = false;
        cbAdvertiserTxRssi->Enabled = false;
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::WatcherDefaults()
{
        BeaconWatcher->RestoreDefaults();
        if (BeaconWatcher->ScanningMode == smActive)
                cbWatcherScanMode->ItemIndex = 0;
        else
                cbWatcherScanMode->ItemIndex = 1;
        edWatcherScanInterval->Text = IntToStr(BeaconWatcher->ScanInterval);
        edWatcherScanWindow->Text = IntToStr(BeaconWatcher->ScanWindow);
        cbWatcherEnableExtended->Checked = BeaconWatcher->AllowExtendedAdvertisements;
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::AdvertiserEnableControls(const bool Stopped)
{
        btAdvertiserStart->Enabled = Stopped;
        btAdvertiserStop->Enabled = (!Stopped);
        btAdvertiserDefault->Enabled = Stopped;

        edAdvertiserInterval->Enabled = Stopped;

        cbAdvertiserBeacon->Enabled = Stopped;
        cbAdvertiserProximityBeacon->Enabled = Stopped;
        cbAdvertiserAltBeacon->Enabled = Stopped;
        cbAdvertiserEddystoneUid->Enabled = Stopped;
        cbAdvertiserEddystoneUrl->Enabled = Stopped;
        cbAdvertiser128SolUuid->Enabled = Stopped;
        cbAdvertiserManufacturer->Enabled = Stopped;
        cbAdvertiser16Uuid->Enabled = Stopped;
        cbAdvertiser32Uuid->Enabled = Stopped;
        cbAdvertiser128Uuid->Enabled = Stopped;
        cbAdvertiser16UuidData->Enabled = Stopped;
        cbAdvertiser32UuidData->Enabled = Stopped;
        cbAdvertiser128UuidData->Enabled = Stopped;
        cbAdvertiserCustom->Enabled = Stopped;

        cbAdvertiserExtended->Enabled = Stopped;
        cbAdvertiserAnonymous->Enabled = (Stopped && cbAdvertiserExtended->Checked);
        cbAdvertiserTxRssi->Enabled = (Stopped && cbAdvertiserExtended->Checked);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::WatcherEnableControls(const bool Stopped)
{
        cbWatcherScanMode->Enabled = Stopped;
        edWatcherScanInterval->Enabled = Stopped;
        edWatcherScanWindow->Enabled = Stopped;
        cbWatcherEnableExtended->Enabled = Stopped;

        btWatcherDefault->Enabled = Stopped;

        btWatcherStart->Enabled = Stopped;
        btWatcherStop->Enabled = (!Stopped);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::Trace(const String& Msg)
{
        lbLog->Items->Add(Msg);
        if (cbAutoScroll->Checked)
                lbLog->TopIndex = lbLog->Items->Count - 1;
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::Trace(const String& Msg, const int Res)
{
        Trace(Msg + " failed: 0x" + IntToHex(Res, 8));
}
//---------------------------------------------------------------------------
TwclBluetoothRadio* __fastcall TfmMain::GetRadio()
{
        int Res = WCL_E_SUCCESS;
        if (!BluetoothManager->Active)
                Res = BluetoothManager->Open();

        if (Res != WCL_E_SUCCESS)
        {
                Trace("Bluetooth Manager open", Res);
                return NULL;
        }

        TwclBluetoothRadio* Radio;
        Res = BluetoothManager->GetLeRadio(Radio);
        if (Res != WCL_E_SUCCESS)
        {
                Trace("Get working radio", Res);
                return NULL;
        }

        Trace("Use " + Radio->ApiName + " radio");
        return Radio;
}
//---------------------------------------------------------------------------
TListItem* __fastcall TfmMain::AddDevice(const __int64 Address)
{
        String AddrStr = IntToHex(Address, 12);

        if (lvDevices->Items->Count > 0)
        {
                for (int i = 0; i < lvDevices->Items->Count; i++)
                {
                        if (AddrStr == lvDevices->Items->Item[i]->Caption)
                                return lvDevices->Items->Item[i];
                }
        }

        TListItem* Item = lvDevices->Items->Add();
        Item->Caption = AddrStr;
        Item->Data = NULL;
        Item->SubItems->Add("");
        return Item;
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::AddFrame(TFrameStorage* const Frame)
{
        TListItem* FrameItem = NULL;
        TListItem* Device = AddDevice(Frame->Address);
        if (Device->Index < lvDevices->Items->Count - 1)
        {
                for (int i = Device->Index + 1; i < lvDevices->Items->Count; i++)
                {
                        if (lvDevices->Items->Item[i]->Data == NULL)
                                break;

                        if (((TFrameStorage*)lvDevices->Items->Item[i]->Data)->Frame == Frame->Frame)
                        {
                                FrameItem = lvDevices->Items->Item[i];
                                break;
                        }
                }
        }

        if (FrameItem == NULL)
        {
                FrameItem = lvDevices->Items->Insert(Device->Index + 1);
                FrameItem->Caption = "";
                FrameItem->Data = NULL;

                switch (Frame->Frame)
                {
                        case afAppearance:
                                FrameItem->SubItems->Add("Appearance");
                                break;
                        case afExtInformation:
                                FrameItem->SubItems->Add("Ext Information");
                                break;
                        case afInformation:
                                FrameItem->SubItems->Add("Information");
                                break;
                        case afRaw:
                                FrameItem->SubItems->Add("Raw");
                                break;
                        case afDetails:
                                FrameItem->SubItems->Add("Details");
                                break;
                        case afService16Data:
                                FrameItem->SubItems->Add("Service 16");
                                break;
                        case afService32Data:
                                FrameItem->SubItems->Add("Service 32");
                                break;
                        case afService128Data:
                                FrameItem->SubItems->Add("Service 128");
                                break;
                        case afSol16:
                                FrameItem->SubItems->Add("16 SOL");
                                break;
                        case afSol32:
                                FrameItem->SubItems->Add("32 SOL");
                                break;
                        case afSol128:
                                FrameItem->SubItems->Add("128 SOL");
                                break;
                        case afTxPower:
                                FrameItem->SubItems->Add("Tx Power");
                                break;
                        case afUuid:
                                FrameItem->SubItems->Add("UUID");
                                break;
                        case afAltBeacon:
                                FrameItem->SubItems->Add("Alt Beacon");
                                break;
                        case afEddystoneTlm:
                                FrameItem->SubItems->Add("Eddystone TLM");
                                break;
                        case afEddystoneUid:
                                FrameItem->SubItems->Add("Eddystone UID");
                                break;
                        case afEddystoneUrl:
                                FrameItem->SubItems->Add("Eddystone URL");
                                break;
                        case afManufacturerRaw:
                                FrameItem->SubItems->Add("Manufacturer");
                                break;
                        case afMicrosoftCdpBeacon:
                                FrameItem->SubItems->Add("Microsoft CDP");
                                break;
                        case afAppleAirdrop:
                                FrameItem->SubItems->Add("Apple AirDrop");
                                break;
                        case afAppleAirplaySource:
                                FrameItem->SubItems->Add("Apple Airplay Source");
                                break;
                        case afAppleAirplayTarget:
                                FrameItem->SubItems->Add("Apple Airplay Target");
                                break;
                        case afAppleAirprint:
                                FrameItem->SubItems->Add("Apple AirPrint");
                                break;
                        case afAppleHomeKit:
                                FrameItem->SubItems->Add("Apple Home Kit");
                                break;
                        case afAppleiBeacon:
                                FrameItem->SubItems->Add("Apple iBeacon");
                                break;
                        case afAppleNearbyAction:
                                FrameItem->SubItems->Add("Apple Nearby Action");
                                break;
                        case afAppleNearbyInfo:
                                FrameItem->SubItems->Add("Apple Nearby Info");
                                break;
                        case afAppleProximityPairing:
                                FrameItem->SubItems->Add("Apple Proximity Pairing");
                                break;
                        case afAppleUnknown:
                                FrameItem->SubItems->Add("Apple Unknown");
                                break;
                        case afAppleFindMy:
                                FrameItem->SubItems->Add("Apple Find My");
                                break;
                        case afAppleHandoff:
                                FrameItem->SubItems->Add("Apple Handoff");
                                break;
                        case afAppleHeySiri:
                                FrameItem->SubItems->Add("Apple Hey Siri");
                                break;
                        case afAppleMagicSwitch:
                                FrameItem->SubItems->Add("Apple Magic Switch");
                                break;
                        case afAppleTetheringSource:
                                FrameItem->SubItems->Add("Apple Tethering Source");
                                break;
                        case afAppleTetheringTarget:
                                FrameItem->SubItems->Add("Apple Tethering Target");
                                break;
                        case afDriAsd:
                                FrameItem->SubItems->Add("DRI ASD");
                                break;
                        default:
                                FrameItem->SubItems->Add("Unknown");
                                break;
                }
        }

        if (FrameItem->Data != NULL)
                delete (TFrameStorage*)FrameItem->Data;
        FrameItem->Data = Frame;

        if (Frame->Frame == afInformation)
        {
                if (((TInformationFrame*)Frame)->Name != "")
                        Device->SubItems->Strings[0] = ((TInformationFrame*)Frame)->Name;
        }

        if (FrameItem->Selected)
                ShowFrameData(Frame);
}
//---------------------------------------------------------------------------
TDateTime __fastcall TfmMain::ConvertTime(const __int64 Timestamp)
{
        ULARGE_INTEGER li;
        li.QuadPart = Timestamp;
        FILETIME ft;
        ft.dwLowDateTime = li.LowPart;
        ft.dwHighDateTime = li.HighPart;
        FileTimeToLocalFileTime(&ft, &ft);
        SYSTEMTIME st;
        FileTimeToSystemTime(&ft, &st);
        return SystemTimeToDateTime(st);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowData(const String& Name, const String& Value)
{
        TListItem* Item = lvFrameDetails->Items->Add();
        Item->Caption = Name;
        Item->SubItems->Add(Value);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowFrameBaseData(TFrameStorage* const Frame)
{
        ShowData("Address", IntToHex(Frame->Address, 12));
        ShowData("Timestamp", DateTimeToStr(ConvertTime(Frame->Timestamp)));
        ShowData("RSSI", IntToStr(Frame->Rssi));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowFrameRawData(
        const TwclBluetoothLeAdvertisementFrameRawData& Data)
{
        String First = "Data";

        if (Data.Length > 0)
        {
                String Str = "";
                Byte c = 0;
                for (int i = 0; i < Data.Length; i++)
                {
                        Str = Str + IntToHex(Data[i], 2) + " ";
                        if (c == 15)
                        {
                                ShowData(First, Str);

                                First = "";
                                Str = "";
                                c = 0;
                        }
                        else
                                c++;
                }

                if (Str != "")
                        ShowData(First, Str);
        }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowDriFrameRawData(const TwclDriRawData& Raw)
{
        int Len = Raw.Length;
        if (Len > 0)
        {
                TwclBluetoothLeAdvertisementFrameRawData Data;
                Data.Length = Len;
                for (int i = 0; i < Len; i++)
                        Data[i] = Raw[i];
                ShowFrameRawData(Data);
        }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowAppearanceFrame(TAppearanceFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("Appearance", IntToHex(Frame->Appearance, 4));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowExtInformationFrame(TExtInformationFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        String Str;
        switch (Frame->AddressType)
        {
                case atClassic:
                        Str = "Classic";
                        break;
                case atPublic:
                        Str = "Public";
                        break;
                case atRandom:
                        Str = "Random";
                        break;
                case atUnspecified:
                        Str = "Unpecified";
                        break;
                default:
                        Str = "Unknonw";
                        break;
        }
        ShowData("Address type", Str);

        Str = "";
        if (Frame->Flags.Contains(efAnonymous))
                Str = Str + " [Anonymous]";
        if (Frame->Flags.Contains(efConnectable))
                Str = Str + " [Connectable]";
        if (Frame->Flags.Contains(efDirected))
                Str = Str + " [Directed]";
        if (Frame->Flags.Contains(efScannable))
                Str = Str + " [Scannable]";
        if (Frame->Flags.Contains(efScanResponse))
                Str = Str + " [Scan Response]";
        Str = Str + " ";
        ShowData("Flags", Str);

        ShowData("TX Power", IntToStr(Frame->TxPower));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowInformationFrame(TInformationFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        String Str = "";
        if (Frame->Flags.Contains(afLimitedDiscoverableMode))
                Str = Str + " [General Discoverable Mode]";
        if (Frame->Flags.Contains(afClassicNotSupported))
                Str = Str + " [Classic Not Supported]";
        if (Frame->Flags.Contains(afDualModeControllerCapable))
                Str = Str + " [Dual Mode Controller Capable]";
        if (Frame->Flags.Contains(afDualModeHostCapable))
                Str = Str + " [Dual Mode Host Capable]";
        Str = Str + " ";
        ShowData("Flags", Str);

        ShowData("Name", Frame->Name);

        switch (Frame->PacketType)
        {
                case atConnectableUndirected:
                        Str = "Connectable Undirected";
                        break;
                case atConnectableDirected:
                        Str = "Connectable Directed";
                        break;
                case atScannableUndirected:
                        Str = "Scannable Undirected";
                        break;
                case atNonConnectableUndirected:
                        Str = "Non Connectable Undirected";
                        break;
                case atScanResponse:
                        Str = "Scan Response";
                        break;
                case atExtended:
                        Str = "Extended";
                        break;
                default:
                        Str = "Unknown";
                        break;
        }
        ShowData("Packet Type", Str);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowRawFrame(TRawFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("Data Type", IntToHex(Frame->DataType, 2));

        ShowFrameRawData(Frame->Data);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowDetailsFrame(TDetailsFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowFrameRawData(Frame->Data);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowService16DataFrame(TService16DataFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("UUID", IntToHex(Frame->Uuid, 4));

        ShowFrameRawData(Frame->Data);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowService32DataFrame(TService32DataFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("UUID", IntToHex((int)Frame->Uuid, 8));

        ShowFrameRawData(Frame->Data);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowService128DataFrame(TService128DataFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("UUID", Sysutils::GUIDToString(Frame->Uuid));

        ShowFrameRawData(Frame->Data);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowSol16Frame(TSol16Frame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("UUID", IntToHex(Frame->Uuid, 4));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowSol32Frame(TSol32Frame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("UUID", IntToHex((int)Frame->Uuid, 8));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowSol128Frame(TSol128Frame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("UUID", Sysutils::GUIDToString(Frame->Uuid));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowTxPowerFrame(TTxPowerFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("TX Power", IntToStr(Frame->TxPower));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowUuidFrame(TUuidFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("UUID", Sysutils::GUIDToString(Frame->Uuid));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowAltBeaconFrame(TAltBeaconFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("UUID", Sysutils::GUIDToString(Frame->Uuid));
        ShowData("CompanyId", IntToHex(Frame->CompanyId, 4));
        ShowData("Major", IntToHex(Frame->Major, 4));
        ShowData("Minor", IntToHex(Frame->Minor, 4));
        ShowData("TX RSSI", IntToStr(Frame->TxRssi));
        ShowData("Reserved", IntToHex(Frame->Reserved, 2));

        ShowFrameRawData(Frame->Data);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowEddystoneTlmFrame(TEddystoneTlmFrame* const Frame)
{
        ShowFrameBaseData(Frame);

		ShowData("Advertisements Counter", IntToStr((int)Frame->AdvCnt));
        ShowData("Battery status", IntToStr(Frame->Batt));
		ShowData("Seconds", IntToStr((int)Frame->SecCnt));
        ShowData("Temperature", FloatToStr(Frame->Temp));

        ShowFrameRawData(Frame->Data);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowEddystoneUidFrame(TEddystoneUidFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("UUID", Sysutils::GUIDToString(Frame->Uuid));
        ShowData("TX RSSI", IntToStr(Frame->TxRssi));

        ShowFrameRawData(Frame->Data);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowEddystoneUrlFrame(TEddystoneUrlFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("TX RSSI", IntToStr(Frame->TxRssi));
        ShowData("URL", Frame->Url);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowManufacturerFrame(TManufacturerFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("Company ID", IntToHex(Frame->CompanyId, 4));

        ShowFrameRawData(Frame->Data);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowMicrosoftCdpBeaconFrame(
        TMicrosoftCdpBeaconFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("Address As Device ID", BoolToStr(Frame->AddressAsDeviceId, true));
        switch (Frame->DeviceType)
        {
                case dtXboxOne:
                        ShowData("Device Type", "Xbox one");
                        break;
                case dtiPhone:
                        ShowData("Device Type", "iPhone");
                        break;
                case dtiPad:
                        ShowData("Device Type", "iPad");
                        break;
                case dtAndroid:
                        ShowData("Device Type", "Android");
                        break;
                case dtWindowsDesktop:
                        ShowData("Device Type", "Windows Desktop");
                        break;
                case dtWindowsPhone:
                        ShowData("Device Type", "Windows Phone");
                        break;
                case dtLinux:
                        ShowData("Device Type", "Linux");
                        break;
                case dtWindowsIoT:
                        ShowData("Device Type", "Windows IoT");
                        break;
                case dtSurfaceHub:
                        ShowData("Device Type", "Surface Hub");
                        break;
                case dtWindowsLaptop:
                        ShowData("Device Type", "Windows Laptop");
                        break;
                case dtWindowsTablet:
                        ShowData("Device Type", "Windows Tablet");
                        break;
                default:
                        ShowData("Device Type", IntToHex((int)Frame->DeviceType, 2));
                        break;
        }

        String Str = "";
        if (Frame->ExtendedDeviceStatus.Contains(edsRemoteSessionsHosted))
                Str = Str + " [Remote Sessions Hosted]";
        if (Frame->ExtendedDeviceStatus.Contains(edsRemoteSessionsNotHosted))
                Str = Str + " [Remote Sessions Not Hosted]";
        if (Frame->ExtendedDeviceStatus.Contains(edsNearShareAuthPolicySameUser))
                Str = Str + " [Near Share Auth Policy Same User]";
        if (Frame->ExtendedDeviceStatus.Contains(edsNearShareAuthPolicyPermissive))
                Str = Str + " [Near Share Auth Policy Permissive]";
        Str = Str + " ";
        ShowData("Extended Device Status", Str);

        Str = "";
        if (Frame->Hash.Length > 0)
        {
                for (Byte i = 0; i < Frame->Hash.Length; i++)
                        Str = Str + IntToHex(Frame->Hash[i], 2) + " ";
        }
        ShowData("Hash", Str);

        Str = "";
        if (Frame->Salt.Length > 0)
        {
                for (Byte i = 0; i < Frame->Salt.Length; i++)
                        Str = Str + IntToHex(Frame->Salt[i], 2) + " ";
        }
        ShowData("Salt", Str);

        switch (Frame->ScenarioType)
        {
                case stBluetooth:
                        ShowData("Scenario Type", "Bluetooth");
                        break;
                default:
                        ShowData("Scenario Type", IntToHex((int)Frame->ScenarioType, 2));
                        break;
        }

        ShowData("Share Near By", BoolToStr(Frame->ShareNearBy, true));
        ShowData("Subversion", IntToHex(Frame->SubVersion, 2));
        ShowData("Version", IntToHex(Frame->Version, 2));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowAppleiBeaconFrame(TAppleiBeaconFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("UUID", Sysutils::GUIDToString(Frame->Data.Uuid));
        ShowData("Major", IntToHex(Frame->Data.Major, 4));
        ShowData("Minor", IntToHex(Frame->Data.Minor, 4));
        ShowData("TX RSSI", IntToStr(Frame->Data.TxRssi));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowAppleNearbyActionFrame(
        TAppleNearbyActionFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("Flags", IntToHex(Frame->Data.Flags, 2));

        switch (Frame->Data.Action)
        {
                case 0x01:
                        ShowData("Action", "Apple TV Setup");
                        break;
                case 0x04:
                        ShowData("Action", "Mobile Backup");
                        break;
                case 0x05:
                        ShowData("Action", "Watch Setup");
                        break;
                case 0x06:
                        ShowData("Action", "Apple TV Pair");
                        break;
                case 0x07:
                        ShowData("Action", "Internet Relay");
                        break;
                case 0x08:
                        ShowData("Action", "WiFi Password");
                        break;
                case 0x09:
                        ShowData("Action", "iOS Setup");
                        break;
                case 0x0A:
                        ShowData("Action", "Repair");
                        break;
                case 0x0B:
                        ShowData("Action", "Speaker Setupd");
                        break;
                case 0x0C:
                        ShowData("Action", "Apple Pay");
                        break;
                case 0x0D:
                        ShowData("Action", "Whole Home Audio Setup");
                        break;
                case 0x0E:
                        ShowData("Action", "Developer Tools Pairing Request");
                        break;
                case 0x0F:
                        ShowData("Action", "Answered Call");
                        break;
                case 0x10:
                        ShowData("Action", "Ended Call");
                        break;
                case 0x11:
                        ShowData("Action", "DD Ping");
                        break;
                case 0x12:
                        ShowData("Action", "DD Pong");
                        break;
                case 0x13:
                        ShowData("Action", "Remote Auto Fill");
                        break;
                case 0x14:
                        ShowData("Action", "Companion Link Proximity");
                        break;
                case 0x15:
                        ShowData("Action", "Remote Management");
                        break;
                case 0x16:
                        ShowData("Action", "Remote Auto Fill Pong");
                        break;
                case 0x17:
                        ShowData("Action", "Remote Display");
                        break;
                default:
                        ShowData("Action", "Unknown: 0x" + IntToHex(Frame->Data.Action, 2));
                        break;
        }

        ShowData("Tag", IntToHex((int)Frame->Data.Tag, 6));

        switch (Frame->Data.Device)
        {
                case 0x02:
                        ShowData("Device", "iPhone");
                        break;
                case 0x04:
                        ShowData("Device", "iPod");
                        break;
                case 0x06:
                        ShowData("Device", "iPad");
                        break;
                case 0x08:
                        ShowData("Device", "Audio accessory (HomePod)");
                        break;
                case 0x0A:
                        ShowData("Device", "Mac");
                        break;
                case 0x0C:
                        ShowData("Device", "AppleTV");
                        break;
                case 0x0E:
                        ShowData("Device", "Watch");
                        break;
                default:
                        ShowData("Device", "Unknown: 0x" + IntToHex(Frame->Data.Device, 2));
                        break;
        }

        if (Frame->Data.Params.Length > 0)
        {
                String Str = "";
                for (int i = 0; i < Frame->Data.Params.Length; i++)
                        Str = Str + IntToHex(Frame->Data.Params[i], 2);
                ShowData("Params", Str);
        }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowAppleNearbyInfoFrame(TAppleNearbyInfoFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        if ((Frame->Data.Status & 0x01) != 0)
                ShowData("Primary device", "YES");
        else
                ShowData("Primary device", "NO");
        if ((Frame->Data.Status & 0x04) != 0)
                ShowData("AirDrop", "RECEIVING");
        else
                ShowData("AirDrop", "NOT ACTIVE");

        switch (Frame->Data.Action)
        {
                case 0x00:
                        ShowData("Action", "None");
                        break;
                case 0x01:
                        ShowData("Action", "Activity reporting disabled");
                        break;
                case 0x03:
                        ShowData("Action", "Idle user");
                        break;
                case 0x05:
                        ShowData("Action", "Audio playing while screen locked");
                        break;
                case 0x07:
                        ShowData("Action", "Active user (screen on)");
                        break;
                case 0x09:
                        ShowData("Action", "Screen on with video playing");
                        break;
                case 0x0A:
                        ShowData("Action", "Watch on wrist and unlocked");
                        break;
                case 0x0B:
                        ShowData("Action", "Recent user interaction");
                        break;
                case 0x0D:
                        ShowData("Action", "User is driving a vehicle");
                        break;
                case 0x0E:
                        ShowData("Action", "Phone or Facetime Call");
                        break;
                default:
                        ShowData("Action", "Unknown: 0x" + IntToHex(Frame->Data.Action, 2));
                        break;
        }

        if ((Frame->Data.Flags & 0x01) != 0)
                ShowData("AirDrop state", "Connected and Screen ON");
        else
                ShowData("AirDrop state", "Disconnected");

        if ((Frame->Data.Flags & 0x02) != 0)
                ShowData("Auth tag length", "4 bytes");
        else
                ShowData("Auth tag length", "3 bytes");

        if ((Frame->Data.Flags & 0x04) != 0)
                ShowData("WiFi", "ON");
        else
                ShowData("WiFi", "OFF");

        if ((Frame->Data.Flags & 0x10) != 0)
                ShowData("Auth Tag Present", "YES");
        else
                ShowData("Auth Tag Present", "NO");

        if ((Frame->Data.Flags & 0x20) != 0)
                ShowData("Apple Watch", "LOCKED");
        else
                ShowData("Apple Watch", "UNLOCKED");

        if ((Frame->Data.Flags & 0x40) != 0)
                ShowData("Apple Watch AutoLock", "ENABLED");
        else
                ShowData("Apple Watch AutoLock", "DISABLED");

        if ((Frame->Data.Flags & 0x80) != 0)
                ShowData("AutoLock", "ENABLED");
        else
                ShowData("AutoLock", "DISABLED");

        if ((Frame->Data.Flags & 0x10) != 0)
        {
                if ((Frame->Data.Flags & 0x02) != 0)
                        ShowData("Auth Tag", IntToHex((int)Frame->Data.Tag, 8));
                else
                        ShowData("Auth Tag", IntToHex((int)Frame->Data.Tag, 6));
        }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowAppleProximityPairingFrame(
        TAppleProximityPairingFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("Prefix", IntToHex(Frame->Data.Prefix, 2));

        switch (Frame->Data.DeviceModel)
        {
                case 0x2002:
                        ShowData("Device mode", "AirPods");
                        break;
                case 0x2003:
                        ShowData("Device mode", "Powerbeats 3");
                        break;
                case 0x2005:
                        ShowData("Device mode", "BeatsX");
                        break;
                case 0x2006:
                        ShowData("Device mode", "Beats Solo 3");
                        break;
                case 0x2007:
                        ShowData("Device mode", "Beats Studio 3");
                        break;
                case 0x2009:
                        ShowData("Device mode", "Beats Studio 3");
                        break;
                case 0x200A:
                        ShowData("Device mode", "AirPods Max");
                        break;
                case 0x200B:
                        ShowData("Device mode", "Powerbeats Pro");
                        break;
                case 0x200C:
                        ShowData("Device mode", "Beats Solo Pro");
                        break;
                case 0x200D:
                        ShowData("Device mode", "Powerbeats 4");
                        break;
                case 0x200E:
                        ShowData("Device mode", "AirPods Pro");
                        break;
                case 0x200F:
                        ShowData("Device mode", "AirPods 2");
                        break;
                case 0x2010:
                        ShowData("Device mode", "Beats Flex");
                        break;
                case 0x2011:
                        ShowData("Device mode", "Beats Studio Buds");
                        break;
                case 0x2012:
                        ShowData("Device mode", "Beats Fit Pro");
                        break;
                case 0x2013:
                        ShowData("Device mode", "AirPods 3");
                        break;
                case 0x2014:
                        ShowData("Device mode", "AirPods Pro 2");
                        break;
                default:
                        ShowData("Device mode", "Unknown: 0x" + IntToHex(Frame->Data.DeviceModel, 4));
                        break;
        }

        switch (Frame->Data.Status)
        {
                case 0x01:
                        ShowData("Status", "AirPods: Both out of case, not in ear");
                        break;
                case 0x02:
                        ShowData("Status", "Right in ear, Left in case");
                        break;
                case 0x03:
                        ShowData("Status", "AirPods: Right in ear, Left out of case");
                        break;
                case 0x0B:
                        ShowData("Status", "Both AirPods in ear");
                        break;
                case 0x11:
                        ShowData("Status", "AirPods: Right out of case, Left in case");
                        break;
                case 0x13:
                        ShowData("Status", "AirPods: Right in ear, Left in case");
                        break;
                case 0x21:
                        ShowData("Status", "Both taken out of ears, Pause Audio");
                        break;
                case 0x22:
                        ShowData("Status", "Left in ear, Right in case");
                        break;
                case 0x23:
                        ShowData("Status", "AirPods: Left in ear, Right out of case");
                        break;
                case 0x2B:
                        ShowData("Status", "Both AirPods in ear");
                        break;
                case 0x31:
                        ShowData("Status", "AirPods: Left out of case, Right in case");
                        break;
                case 0x33:
                        ShowData("Status", "AirPods: Left in ear, Right in case");
                        break;
                case 0x51:
                        ShowData("Status", "Case: Left out of case, Right in case");
                        break;
                case 0x53:
                        ShowData("Status", "Case: Left in ear, Right in case");
                        break;
                case 0x55:
                        ShowData("Status", "Case: Both AirPods in case");
                        break;
                case 0x71:
                        ShowData("Status", "Case: Right out of case, Left in case");
                        break;
                case 0x73:
                        ShowData("Status", "Case: Right in ear, Left in case");
                        break;
                case 0x75:
                        ShowData("Status", "Case: Both AirPods in case");
                        break;
                default:
                        ShowData("Status", "Unknown: 0x" + IntToHex(Frame->Data.Status, 2));
                        break;
        }

        ShowData("Left Battery", IntToStr(Frame->Data.LeftBattery));
        ShowData("Right Battery", IntToStr(Frame->Data.RightBattery));

        if (Frame->Data.CaseCharging)
                ShowData("Case charging", "Yes");
        else
                ShowData("Case charging", "No");
        if (Frame->Data.RightCharging)
                ShowData("Right charging", "Yes");
        else
                ShowData("Right charging", "No");
        if (Frame->Data.LeftCharging)
                ShowData("Left charging", "Yes");
        else
                ShowData("Left charging", "No");

        ShowData("Case Battery", IntToStr(Frame->Data.CaseBattery));
        ShowData("Lid open counter", IntToStr(Frame->Data.Counter));

        switch (Frame->Data.Color)
        {
                case 0x00:
                        ShowData("Color", "White");
                        break;
                case 0x01:
                        ShowData("Color", "Black");
                        break;
                case 0x02:
                        ShowData("Color", "Red");
                        break;
                case 0x03:
                        ShowData("Color", "Blue");
                        break;
                case 0x04:
                        ShowData("Color", "Pink");
                        break;
                case 0x05:
                        ShowData("Color", "Gray");
                        break;
                case 0x06:
                        ShowData("Color", "Silver");
                        break;
                case 0x07:
                        ShowData("Color", "Gold");
                        break;
                case 0x08:
                        ShowData("Color", "Rose Gold");
                        break;
                case 0x09:
                        ShowData("Color", "Space Gray");
                        break;
                case 0x0A:
                        ShowData("Color", "Dark Blue");
                        break;
                case 0x0B:
                        ShowData("Color", "Light Blue");
                        break;
                case 0x0C:
                        ShowData("Color", "Yellow");
                        break;
                default:
                        ShowData("Color", "Unknown: 0x" + IntToHex(Frame->Data.Color, 2));
                        break;
        }

        ShowData("Suffix", IntToHex(Frame->Data.Suffix, 2));

        String Str = "";
        for (unsigned char i = 0; i < 16; i++)
                Str += IntToHex(Frame->Data.Data[i], 2);
        ShowData("Encrypted", Str);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowDriAsdFrame(TDriAsdFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowDriFrameRawData(Frame->Raw);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowFrameData(TFrameStorage* const Frame)
{
        lvFrameDetails->Items->Clear();

        switch (Frame->Frame)
        {
                case afAppearance:
                        ShowAppearanceFrame((TAppearanceFrame*)Frame);
                        break;
                case afExtInformation:
                        ShowExtInformationFrame((TExtInformationFrame*)Frame);
                        break;
                case afInformation:
                        ShowInformationFrame((TInformationFrame*)Frame);
                        break;
                case afRaw:
                        ShowRawFrame((TRawFrame*)Frame);
                        break;
                case afDetails:
                        ShowDetailsFrame((TDetailsFrame*)Frame);
                        break;
                case afService16Data:
                        ShowService16DataFrame((TService16DataFrame*)Frame);
                        break;
                case afService32Data:
                        ShowService32DataFrame((TService32DataFrame*)Frame);
                        break;
                case afService128Data:
                        ShowService128DataFrame((TService128DataFrame*)Frame);
                        break;
                case afSol16:
                        ShowSol16Frame((TSol16Frame*)Frame);
                        break;
                case afSol32:
                        ShowSol32Frame((TSol32Frame*)Frame);
                        break;
                case afSol128:
                        ShowSol128Frame((TSol128Frame*)Frame);
                        break;
                case afTxPower:
                        ShowTxPowerFrame((TTxPowerFrame*)Frame);
                        break;
                case afUuid:
                        ShowUuidFrame((TUuidFrame*)Frame);
                        break;
                case afAltBeacon:
                        ShowAltBeaconFrame((TAltBeaconFrame*)Frame);
                        break;
                case afEddystoneTlm:
                        ShowEddystoneTlmFrame((TEddystoneTlmFrame*)Frame);
                        break;
                case afEddystoneUid:
                        ShowEddystoneUidFrame((TEddystoneUidFrame*)Frame);
                        break;
                case afEddystoneUrl:
                        ShowEddystoneUrlFrame((TEddystoneUrlFrame*)Frame);
                        break;
                case afManufacturerRaw:
                        ShowManufacturerFrame((TManufacturerFrame*)Frame);
                        break;
                case afMicrosoftCdpBeacon:
                        ShowMicrosoftCdpBeaconFrame((TMicrosoftCdpBeaconFrame*)Frame);
                        break;
                case afAppleAirdrop:
                        ShowAppleAirdropFrame((TAppleAirdropFrame*)Frame);
                        break;
                case afAppleAirplaySource:
                        ShowAppleAirplaySourceFrame((TAppleAirplaySourceFrame*)Frame);
                        break;
                case afAppleAirplayTarget:
                        ShowAppleAirplayTargetFrame((TAppleAirplayTargetFrame*)Frame);
                        break;
                case afAppleAirprint:
                        ShowAppleAirprintFrame((TAppleAirprintFrame*)Frame);
                        break;
                case afAppleHomeKit:
                        ShowAppleHomeKitFrame((TAppleHomeKitFrame*)Frame);
                        break;
                case afAppleiBeacon:
                        ShowAppleiBeaconFrame((TAppleiBeaconFrame*)Frame);
                        break;
                case afAppleNearbyAction:
                        ShowAppleNearbyActionFrame((TAppleNearbyActionFrame*)Frame);
                        break;
                case afAppleNearbyInfo:
                        ShowAppleNearbyInfoFrame((TAppleNearbyInfoFrame*)Frame);
                        break;
                case afAppleProximityPairing:
                        ShowAppleProximityPairingFrame((TAppleProximityPairingFrame*)Frame);
                        break;
                case afDriAsd:
                        ShowDriAsdFrame((TDriAsdFrame*)Frame);
                        break;
                case afAppleUnknown:
                        ShowAppleUnknownFrame((TAppleUnknownFrame*)Frame);
                        break;
                case afAppleFindMy:
                        ShowAppleFindMyFrame((TAppleFindMyFrame*)Frame);
                        break;
                case afAppleHandoff:
                        ShowAppleHandoffFrame((TAppleHandoffFrame*)Frame);
                        break;
                case afAppleHeySiri:
                        ShowAppleHeySiriFrame((TAppleHeySiriFrame*)Frame);
                        break;
                case afAppleMagicSwitch:
                        ShowAppleMagicSwitchFrame((TAppleMagicSwitchFrame*)Frame);
                        break;
                case afAppleTetheringSource:
                        ShowAppleTetheringSourceFrame((TAppleTetheringSourceFrame*)Frame);
                        break;
                case afAppleTetheringTarget:
                        ShowAppleTetheringTargetFrame((TAppleTetheringTargetFrame*)Frame);
                        break;
                case afUnknown:
                        // Makes compiler happy.
                        break;
        }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::AddAdvertisement(TwclBluetoothLeAdvertisement* const Adv)
{
        int Res = LeAdvertiser->Add(Adv);
        if (Res != WCL_E_SUCCESS)
        {
                Trace("Add advertisement", Res);
                Adv->Free();
        }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::lvDevicesSelectItem(TObject *Sender,
      TListItem *Item, bool Selected)
{
        if (lvDevices->Selected != NULL && lvDevices->Selected->Data != NULL)
                ShowFrameData((TFrameStorage*)lvDevices->Selected->Data);
        else
                lvFrameDetails->Items->Clear();
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::FormCreate(TObject *Sender)
{
        AdvertiserDefaults();
        WatcherDefaults();

        btAdvertiserStop->Enabled = false;
        btWatcherStop->Enabled = false;

        cbAutoScroll->Checked = true;
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::FormDestroy(TObject *Sender)
{
        BluetoothManager->Close();
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::btClearLogClick(TObject *Sender)
{
        lbLog->Items->Clear();
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::btWatcherDefaultClick(TObject *Sender)
{
        WatcherDefaults();
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::btAdvertiserDefaultClick(TObject *Sender)
{
        AdvertiserDefaults();
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::cbAdvertiserExtendedClick(TObject *Sender)
{
        cbAdvertiserAnonymous->Enabled = cbAdvertiserExtended->Checked;
        cbAdvertiserTxRssi->Enabled = cbAdvertiserExtended->Checked;
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::EditKeyPress(TObject *Sender, char &Key)
{
        if ((Key >= '0' && Key <= '9') || Key == 8)
                return;
        Key = 0;
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BluetoothManagerAfterOpen(TObject *Sender)
{
        Trace("Bluetooth Manager opened");
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BluetoothManagerBeforeClose(TObject *Sender)
{
        Trace("Bluetooth Manager is closing");

        LeAdvertiser->Stop();
        BeaconWatcher->Stop();
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BluetoothManagerClosed(TObject *Sender)
{
        Trace("Bluetooth Manager closed");
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::btWatcherStartClick(TObject *Sender)
{
        TwclBluetoothRadio* Radio = GetRadio();
        if (Radio != NULL)
        {
                BeaconWatcher->AllowExtendedAdvertisements =
                        cbWatcherEnableExtended->Checked;
                if (cbWatcherScanMode->ItemIndex == 0)
                        BeaconWatcher->ScanningMode = smActive;
                else
                        BeaconWatcher->ScanningMode = smPassive;
                BeaconWatcher->ScanInterval = StrToInt(edWatcherScanInterval->Text);
                BeaconWatcher->ScanWindow = StrToInt(edWatcherScanWindow->Text);

                int Res = BeaconWatcher->Start(Radio);
                if (Res != WCL_E_SUCCESS)
                Trace("Start Watched", Res);
        }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::btWatcherStopClick(TObject *Sender)
{
        int Res = BeaconWatcher->Stop();
        if (Res != WCL_E_SUCCESS)
                Trace("Beacon Watcher stop", Res);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherStarted(TObject *Sender)
{
        Trace("Beacon Watcher started");

        WatcherEnableControls(false);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherStopped(TObject *Sender)
{
        Trace("Beacon Watcher stopped");

        WatcherEnableControls(true);

        lvFrameDetails->Items->Clear();

        if (lvDevices->Items->Count > 0)
        {
                for (int i = 0; i < lvDevices->Items->Count; i++)
                {
                        if (lvDevices->Items->Item[i]->Data != NULL)
                                delete (TFrameStorage*)lvDevices->Items->Item[i]->Data;
                }

                lvDevices->Items->Clear();
        }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAdvertisementAppearanceFrame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const WORD Appearance)
{
        TFrameStorage* Frame = new TAppearanceFrame(Address, Timestamp, Rssi,
                Appearance);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAdvertisementExtFrameInformation(
	  TObject *Sender, const __int64 Address, const __int64 Timestamp,
	  const SByte Rssi, const TwclBluetoothAddressType AddressType,
	  const SByte TxPower, const TwclBluetoothLeExtendedFrameFlags Flags)
{
        TFrameStorage* Frame = new TExtInformationFrame(Address, Timestamp,
                Rssi, AddressType, Flags, TxPower);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAdvertisementFrameInformation(
	  TObject *Sender, const __int64 Address, const __int64 Timestamp,
	  const SByte Rssi, const String Name,
	  const TwclBluetoothLeAdvertisementType PacketType,
	  const TwclBluetoothLeAdvertisementFlags Flags)
{
        TFrameStorage* Frame = new TInformationFrame(Address, Timestamp, Rssi,
                Flags, Name, PacketType);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAdvertisementRawFrame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const BYTE DataType,
      const TwclBluetoothLeAdvertisementFrameRawData Data)
{
        TFrameStorage* Frame = new TRawFrame(Address, Timestamp, Rssi, Data,
                DataType);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAdvertisementReceived(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi,
      const TwclBluetoothLeAdvertisementFrameRawData Data)
{
        TFrameStorage* Frame = new TDetailsFrame(Address, Timestamp, Rssi, Data);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAdvertisementService128DataFrame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const TGUID &Uuid,
      const TwclBluetoothLeAdvertisementFrameRawData Data)
{
        TFrameStorage* Frame = new TService128DataFrame(Address, Timestamp, Rssi,
                Uuid, Data);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAdvertisementService16DataFrame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const WORD Uuid,
      const TwclBluetoothLeAdvertisementFrameRawData Data)
{
        TFrameStorage* Frame = new TService16DataFrame(Address, Timestamp, Rssi,
                Data, Uuid);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAdvertisementService32DataFrame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const DWORD Uuid,
      const TwclBluetoothLeAdvertisementFrameRawData Data)
{
        TFrameStorage* Frame = new TService32DataFrame(Address, Timestamp, Rssi,
                Data, Uuid);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAdvertisementServiceSol128Frame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const TGUID &Uuid)
{
        TFrameStorage* Frame = new TSol128Frame(Address, Timestamp, Rssi, Uuid);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAdvertisementServiceSol16Frame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const WORD Uuid)
{
        TFrameStorage* Frame = new TSol16Frame(Address, Timestamp, Rssi, Uuid);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAdvertisementServiceSol32Frame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const DWORD Uuid)
{
        TFrameStorage* Frame = new TSol32Frame(Address, Timestamp, Rssi, Uuid);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAdvertisementTxPowerLevelFrame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const SByte TxPower)
{
        TFrameStorage* Frame = new TTxPowerFrame(Address, Timestamp, Rssi, TxPower);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAdvertisementUuidFrame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const TGUID &Uuid)
{
        TFrameStorage* Frame = new TUuidFrame(Address, Timestamp, Rssi, Uuid);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAltBeaconFrame(TObject *Sender,
      const __int64 Address, const __int64 Timestamp, const SByte Rssi,
      const WORD CompanyId, const WORD Major, const WORD Minor,
      const TGUID &Uuid, const SByte TxRssi, const BYTE Reserved,
      const TwclBluetoothLeAdvertisementFrameRawData Data)
{
        TFrameStorage* Frame = new TAltBeaconFrame(Address, Timestamp, Rssi,
                Data, Uuid, CompanyId, Major, Minor, TxRssi, Reserved);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherEddystoneTlmFrame(TObject *Sender,
      const __int64 Address, const __int64 Timestamp, const SByte Rssi,
      const DWORD AdvCnt, const WORD Batt, const DWORD SecCnt,
      const double Temp,
      const TwclBluetoothLeAdvertisementFrameRawData Data)
{
        TFrameStorage* Frame = new TEddystoneTlmFrame(Address, Timestamp, Rssi,
                Data, AdvCnt, Batt, SecCnt, Temp);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherEddystoneUidFrame(TObject *Sender,
      const __int64 Address, const __int64 Timestamp, const SByte Rssi,
      const SByte TxRssi, const TGUID &Uuid,
      const TwclBluetoothLeAdvertisementFrameRawData Data)
{
        TFrameStorage* Frame = new TEddystoneUidFrame(Address, Timestamp, Rssi,
                Data, Uuid, TxRssi);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherEddystoneUrlFrame(TObject *Sender,
      const __int64 Address, const __int64 Timestamp, const SByte Rssi,
      const SByte TxRssi, const String Url)
{
        TFrameStorage* Frame = new TEddystoneUrlFrame(Address, Timestamp, Rssi,
                TxRssi, Url);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherManufacturerRawFrame(TObject *Sender,
      const __int64 Address, const __int64 Timestamp, const SByte Rssi,
      const WORD CompanyId,
      const TwclBluetoothLeAdvertisementFrameRawData Data)
{
        TFrameStorage* Frame = new TManufacturerFrame(Address, Timestamp, Rssi,
                CompanyId, Data);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherMicrosoftCdpBeaconFrame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi,
      const TwclBluetoothLeCdpBeaconScenarioType ScenarioType,
      const BYTE Version,
      const TwclBluetoothLeCdpBeaconDeviceType DeviceType,
      const BYTE SubVersion, const bool ShareNearBy,
      const bool AddressAsDeviceId,
      const TwclBluetoothLeCdpBeaconExtendedDeviceStatuses ExtendedDeviceStatus,
      const TwclBluetoothLeCdpBeaconSalt Salt,
      const TwclBluetoothLeCdpBeaconHash Hash)
{
        TFrameStorage* Frame = new TMicrosoftCdpBeaconFrame(Address, Timestamp,
                Rssi, AddressAsDeviceId, DeviceType, ExtendedDeviceStatus, Hash,
                Salt, ScenarioType, ShareNearBy, SubVersion, Version);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherDriAsdMessage(TObject *Sender,
      const __int64 Address, const __int64 Timestamp, const SByte Rssi,
      const TwclDriRawData Raw)
{
        TDriAsdFrame* Frame = new TDriAsdFrame(Address, Timestamp, Rssi, Raw);
        AddFrame(Frame);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::btAdvertiserStartClick(TObject *Sender)
{
        static const GUID BEACON_UUID = { 0x09039835, 0x4A80, 0x443B, { 0x87, 0xAA, 0xDC, 0x56, 0x5D, 0x09, 0xEA, 0x61 } };

        TwclBluetoothRadio* Radio = GetRadio();
        if (Radio != NULL)
        {
                LeAdvertiser->Clear();

                TwclBluetoothLeAdvertisement* Adv;
                if (cbAdvertiserBeacon->Checked)
                {
                        Adv = new TwclBluetoothLeiBeaconAdvertisement(-5,
                                0x0101, 0x0202, BEACON_UUID);
                        AddAdvertisement(Adv);
                }

                if (cbAdvertiserProximityBeacon->Checked)
                {
                        Adv = new TwclBluetoothLeProximityBeaconAdvertisement(-5,
                                0x0101, 0x0202, BEACON_UUID, 0xFFFE);
                        AddAdvertisement(Adv);
                }

                if (cbAdvertiserAltBeacon->Checked)
                {
                        Adv = new TwclBluetoothLeAltBeaconAdvertisement(-5,
                                0x0101, 0x0202, BEACON_UUID, 0xFFFE, 0x11);
                        AddAdvertisement(Adv);
                }

                if (cbAdvertiserEddystoneUid->Checked)
                {
                        Adv = new TwclBluetoothLeEddystoneUidBeaconAdvertisement(
                                -5, BEACON_UUID);
                        AddAdvertisement(Adv);
                }

                if (cbAdvertiserEddystoneUrl->Checked)
                {
                        Adv = new TwclBluetoothLeEddystoneUrlBeaconAdvertisement(
                                -5, "https://www.btframework.com");
                        AddAdvertisement(Adv);
                }

                TwclBluetoothLeAdvertisementFrameRawData Data;
                if (cbAdvertiser128SolUuid->Checked)
                {
                        Data.Length = 16;
                        Data[0] = 0xD0;
                        Data[1] = 0x00;
                        Data[2] = 0x2D;
                        Data[3] = 0x12;
                        Data[4] = 0x1E;
                        Data[5] = 0x4B;
                        Data[6] = 0x0F;
                        Data[7] = 0xA4;
                        Data[8] = 0x99;
                        Data[9] = 0x4E;
                        Data[10] = 0xCE;
                        Data[11] = 0xB5;
                        Data[12] = 0x31;
                        Data[13] = 0xF4;
                        Data[14] = 0x05;
                        Data[15] = 0x79;
                        Adv = new TwclBluetoothLeCustomAdvertisement(
                                LE_GAP_AD_TYPE_SERVICE_SOL_UUIDS_128, Data);
                        AddAdvertisement(Adv);
                }

                if (cbAdvertiserManufacturer->Checked)
                {
                        Data.Length = 2;
                        Data[0] = 0x12;
                        Data[1] = 0x34;
                        Adv = new TwclBluetoothLeManufacturerAdvertisement(0x010E, Data);
                        AddAdvertisement(Adv);
                }

                if (cbAdvertiser16Uuid->Checked)
                {
                        Adv = new TwclBluetoothLe16ServiceAdvertisement(0x9835);
                        AddAdvertisement(Adv);
                }

                if (cbAdvertiser32Uuid->Checked)
                {
                        Adv = new TwclBluetoothLe32ServiceAdvertisement(0x09039835);
                        AddAdvertisement(Adv);
                }

                if (cbAdvertiser128Uuid->Checked)
                {
                        Adv = new TwclBluetoothLe128ServiceAdvertisement(BEACON_UUID);
                        AddAdvertisement(Adv);
                }

                if (cbAdvertiser16UuidData->Checked)
                {
                        Data.Length = 2;
                        Data[0] = 0x12;
                        Data[1] = 0x34;
                        Adv = new TwclBluetoothLe16ServiceDataAdvertisement(0x9835, Data);
                        AddAdvertisement(Adv);
                }

                if (cbAdvertiser32UuidData->Checked)
                {
                        Data.Length = 2;
                        Data[0] = 0x12;
                        Data[1] = 0x34;
                        Adv = new TwclBluetoothLe32ServiceDataAdvertisement(0x09039835, Data);
                        AddAdvertisement(Adv);
                }

                if (cbAdvertiser128UuidData->Checked)
                {
                        Data.Length = 2;
                        Data[0] = 0x12;
                        Data[1] = 0x34;
                        Adv = new TwclBluetoothLe128ServiceDataAdvertisement(BEACON_UUID,
                                Data);
                        AddAdvertisement(Adv);
                }

                if (cbAdvertiserCustom->Checked)
                {
                        Data.Length = 20;

                        // 16 bit Service Data
                        Data[0] = 0x09; // Length.
                        Data[1] = LE_GAP_AD_TYPE_SERVICE_DATA_16; // Data type.
                        Data[2] = 0x12; // 16 UUID LO BYTE
                        Data[3] = 0x34; // 16 UUID HI BYTE
                        Data[4] = 0xFF; // Data 1st byte
                        Data[5] = 0xFE; // Data 2st byte
                        Data[6] = 0xFD; // Data 3st byte
                        Data[7] = 0xFC; // Data 4st byte
                        Data[8] = 0xFB; // Data 5st byte
                        Data[9] = 0xFA; // Data 6st byte
                        // Manufacturer specific data.
                        Data[10] = 0x09; // Length.
                        Data[11] = LE_GAP_AD_TYPE_MANUFACTURER; // Data type.
                        Data[12] = 0x10; // Company ID.
                        Data[13] = 0x12; // Company ID.
                        Data[14] = 0x01; // Data 1st byte
                        Data[15] = 0x02; // Data 2st byte
                        Data[16] = 0x03; // Data 3st byte
                        Data[17] = 0x04; // Data 4st byte
                        Data[18] = 0x05; // Data 5st byte
                        Data[19] = 0x06; // Data 6st byte

                        Adv = new TwclBluetoothLeRawAdvertisement(Data);
                        AddAdvertisement(Adv);
                }

                if (LeAdvertiser->Count == 0)
                        ShowMessage("Select at least one advertisement type.");
                else
                {
                        LeAdvertiser->Interval = StrToInt(edAdvertiserInterval->Text);

                        LeAdvertiser->UseExtendedAdvertisement = cbAdvertiserExtended->Checked;
                        LeAdvertiser->Anonymous = cbAdvertiserAnonymous->Checked;
                        LeAdvertiser->IncludeTxRssi = cbAdvertiserTxRssi->Checked;
                        LeAdvertiser->PreferredTxRssi = 10;

                        int Res = LeAdvertiser->Start(Radio);
                        if (Res != WCL_E_SUCCESS)
                                Trace("Start advertiser", Res);
                }
        }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::btAdvertiserStopClick(TObject *Sender)
{
        int Res = LeAdvertiser->Stop();
        if (Res != WCL_E_SUCCESS)
                Trace("Advertiser stop", Res);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::LeAdvertiserStarted(TObject *Sender)
{
        Trace("LE Advertiser started");

        AdvertiserEnableControls(false);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::LeAdvertiserStopped(TObject *Sender)
{
        Trace("LE Advertiser stopped");

        AdvertiserEnableControls(true);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAppleiBeaconFrame(TObject *Sender,
      const TwclBluetoothLeAdvertisementInfo &Info,
      const TwclBluetoothLeAppleiBeaconFrameData &Data)
{
        AddFrame(new TAppleiBeaconFrame(Info, Data));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAppleNearbyInfoFrame(TObject *Sender,
      const TwclBluetoothLeAdvertisementInfo &Info,
      const TwclBluetoothLeAppleNearbyInfoFrameData &Data)
{
        AddFrame(new TAppleNearbyInfoFrame(Info, Data));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAppleNearbyActionFrame(
      TObject *Sender, const TwclBluetoothLeAdvertisementInfo &Info,
      const TwclBluetoothLeAppleNearbyActionFrameData &Data)
{
        AddFrame(new TAppleNearbyActionFrame(Info, Data));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAppleHomeKitFrame(TObject *Sender,
      const TwclBluetoothLeAdvertisementInfo &Info,
      const TwclBluetoothLeAppleHomeKitFrameData &Data)
{
        AddFrame(new TAppleHomeKitFrame(Info, Data));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowAppleAirplaySourceFrame(
        TAppleAirplaySourceFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("Data byte", IntToHex(Frame->Data.Data, 2));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowAppleAirplayTargetFrame(
        TAppleAirplayTargetFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("Flags", IntToHex(Frame->Data.Flags, 2));
        ShowData("Seed", IntToHex(Frame->Data.Seed, 2));

		String Str = IntToStr((int)(Frame->Data.Address >> 24)) + ".";
		Str += IntToStr((int)((Frame->Data.Address & 0x00FF0000) >> 16)) + ".";
		Str += IntToStr((int)((Frame->Data.Address & 0x0000FF00) >> 8)) + ".";
        Str += IntToStr((int)(Frame->Data.Address & 0x000000FF));
        ShowData("IPv4 address", Str);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowAppleHomeKitFrame(TAppleHomeKitFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("Status", IntToHex(Frame->Data.Status, 2));

        String Str = "";
        for (unsigned char i = 0; i < 6; i++)
                Str = Str + IntToHex(Frame->Data.DeviceId[i], 2);
        ShowData("Device ID", Str);

        switch (Frame->Data.Category)
        {
                case 0x0000:
                        ShowData("Category", "Unknown");
                        break;
                case 0x0001:
                        ShowData("Category", "Other");
                        break;
                case 0x0002:
                        ShowData("Category", "Bridge");
                        break;
                case 0x0003:
                        ShowData("Category", "Fan");
                        break;
                case 0x0004:
                        ShowData("Category", "Garage Door Opener");
                        break;
                case 0x0005:
                        ShowData("Category", "Lightbulb");
                        break;
                case 0x0006:
                        ShowData("Category", "Door Lock");
                        break;
                case 0x0007:
                        ShowData("Category", "Outlet");
                        break;
                case 0x0008:
                        ShowData("Category", "Switch");
                        break;
                case 0x0009:
                        ShowData("Category", "Thermostat");
                        break;
                case 0x000A:
                        ShowData("Category", "Sensor");
                        break;
                case 0x000B:
                        ShowData("Category", "Security System");
                        break;
                case 0x000C:
                        ShowData("Category", "Door");
                        break;
                case 0x000D:
                        ShowData("Category", "Window");
                        break;
                case 0x000E:
                        ShowData("Category", "Window Covering");
                        break;
                case 0x000F:
                        ShowData("Category", "Programmable Switch");
                        break;
                case 0x0010:
                        ShowData("Category", "Range Extender");
                        break;
                case 0x0011:
                        ShowData("Category", "IP Camera");
                        break;
                case 0x0012:
                        ShowData("Category", "Video Doorbell");
                        break;
                case 0x0013:
                        ShowData("Category", "Air Purifier");
                        break;
                case 0x0014:
                        ShowData("Category", "Heater");
                        break;
                case 0x0015:
                        ShowData("Category", "Air Conditioner");
                        break;
                case 0x0016:
                        ShowData("Category", "Humidifier");
                        break;
                case 0x0017:
                        ShowData("Category", "Dehumidifier");
                        break;
                case 0x001C:
                        ShowData("Category", "Sprinklers");
                        break;
                case 0x001D:
                        ShowData("Category", "Faucets");
                        break;
                case 0x001E:
                        ShowData("Category", "Shower Systems");
                        break;
                default:
                        ShowData("Category", "Unknown: 0x" + IntToHex(Frame->Data.Category, 4));
                        break;
        }

        ShowData("State Number", IntToHex(Frame->Data.StateNumber, 4));
        ShowData("Config Number", IntToHex(Frame->Data.ConfigNumber, 2));
        ShowData("Version", IntToHex(Frame->Data.Version, 2));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowAppleUnknownFrame(TAppleUnknownFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("Message ID", IntToHex(Frame->Data.Id, 2));

        if (Frame->Data.Payload.Length > 0)
        {
                String Str = "";
                for (int i = 0; i < Frame->Data.Payload.Length; i++)
                        Str = Str + IntToHex(Frame->Data.Payload[i], 2);
                ShowData("Payload", Str);
        }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAppleUnknownFrame(TObject *Sender,
      const TwclBluetoothLeAdvertisementInfo &Info,
      const TwclBluetoothLeAppleUnknownFrameData &Data)
{
        AddFrame(new TAppleUnknownFrame(Info, Data));        
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAppleAirplaySourceFrame(
      TObject *Sender, const TwclBluetoothLeAdvertisementInfo &Info,
      const TwclBluetoothLeAppleAirplaySourceFrameData Data)
{
        AddFrame(new TAppleAirplaySourceFrame(Info, Data));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAppleAirplayTargetFrame(
      TObject *Sender, const TwclBluetoothLeAdvertisementInfo &Info,
      const TwclBluetoothLeAppleAirplayTargetFrameData &Data)
{
        AddFrame(new TAppleAirplayTargetFrame(Info, Data));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowAppleAirdropFrame(TAppleAirdropFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        String Str = "";
        for (unsigned char i = 0; i < 8; i++)
                Str += IntToHex(Frame->Data.Prefix[i], 2);
        ShowData("Prefix", Str);

        ShowData("Version", IntToHex(Frame->Data.Version, 2));
        ShowData("Apple ID", IntToHex(Frame->Data.AppleId, 4));
        ShowData("Phone", IntToHex(Frame->Data.PhoneNumber, 4));
        ShowData("E-Mail", IntToHex(Frame->Data.Email, 4));
        ShowData("E-Mail 2", IntToHex(Frame->Data.Email2, 4));
        ShowData("Suffix", IntToHex(Frame->Data.Suffix, 2));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowAppleAirprintFrame(TAppleAirprintFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("Address type", IntToHex(Frame->Data.AddressType, 2));
        ShowData("Resource type", IntToHex(Frame->Data.ResourceType, 2));
        ShowData("Security type", IntToHex(Frame->Data.SecurityType, 2));
        ShowData("Port", IntToStr(Frame->Data.Port));

        String Str = "";
        for (unsigned char i = 0; i < 15; i++)
                Str += IntToStr(Frame->Data.Address[i]) + ".";
        Str += IntToStr(Frame->Data.Address[15]);
        ShowData("Address", Str);

        ShowData("Power", IntToStr(Frame->Data.Power));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAppleAirdropFrame(TObject *Sender,
      const TwclBluetoothLeAdvertisementInfo &Info,
      const TwclBluetoothLeAppleAirdropFrameData &Data)
{
        AddFrame(new TAppleAirdropFrame(Info, Data));        
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAppleAirprintFrame(TObject *Sender,
      const TwclBluetoothLeAdvertisementInfo &Info,
      const TwclBluetoothLeAppleAirprintFrameData &Data)
{
        AddFrame(new TAppleAirprintFrame(Info, Data));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAppleProximityPairingFrame(
      TObject *Sender, const TwclBluetoothLeAdvertisementInfo &Info,
      const TwclBluetoothLeAppleProximityPairingFrameData &Data)
{
        AddFrame(new TAppleProximityPairingFrame(Info, Data));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAppleFindMyFrame(TObject *Sender,
      const TwclBluetoothLeAdvertisementInfo &Info,
      const TwclBluetoothLeAppleFindMyFrameData &Data)
{
        AddFrame(new TAppleFindMyFrame(Info, Data));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowAppleFindMyFrame(TAppleFindMyFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        switch (Frame->Data.Status)
        {
                case 0x00:
                        ShowData("Status", "Owner did not connect within key rotation period (15 min.)");
                        break;
                case 0x24:
                        ShowData("Status", "Owner connected with key roation period, Battery Full");
                        break;
                case 0x64:
                        ShowData("Status", "Owner connected with key roation period, Battery Medium");
                        break;
                case 0xA4:
                        ShowData("Status", "Owner connected with key roation period, Battery Low");
                        break;
                case 0xE4:
                        ShowData("Status", "Owner connected with key roation period, Battery Critically Low");
                        break;
                default:
                        ShowData("Status", IntToHex(Frame->Data.Status, 2));
                        break;
        }

        String Str = "";
        for (int i = 0; i < 22; i++)
                Str += IntToHex(Frame->Data.Key[i], 2);
        ShowData("Key", Str);

        switch (Frame->Data.KeyBits)
        {
                case 0x00:
                        ShowData("Key bits", "bits 6 and 7 not set in public key");
                        break;
                case 0x01:
                        ShowData("Key bits", "bit 6 set in public key");
                        break;
                case 0x02:
                        ShowData("Key bits", "bit 7 set in public key");
                        break;
                case 0x03:
                        ShowData("Key bits", "bits 6 and 7 set in public key");
                        break;
                default:
                        ShowData("Key bits", IntToHex(Frame->Data.KeyBits, 2));
                        break;
        }

        ShowData("Hint", IntToHex(Frame->Data.Hint, 2));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowAppleHandoffFrame(TAppleHandoffFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        if (Frame->Data.Clipboard)
                ShowData("Clipboard", "Yes");
        else
                ShowData("Clipboard", "No");

        ShowData("Sequence", IntToStr(Frame->Data.Sequence));
        ShowData("Auth tag", IntToHex(Frame->Data.AuthTag, 2));

        String Str = "";
        for (int i = 0; i < 10; i++)
                Str += IntToHex(Frame->Data.Data[i], 2);
        ShowData("Data", Str);
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAppleHandoffFrame(TObject *Sender,
      const TwclBluetoothLeAdvertisementInfo &Info,
      const TwclBluetoothLeAppleHandoffFrameData &Data)
{
        AddFrame(new TAppleHandoffFrame(Info, Data));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowAppleHeySiriFrame(TAppleHeySiriFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("Hash", IntToHex(Frame->Data.Hash, 4));
        ShowData("Snr", IntToStr(Frame->Data.Snr));

        switch (Frame->Data.Confidence)
        {
                case 0x03:
                        ShowData("Confidence", "Not on Wrist");
                        break;
                case 0x1F:
                        ShowData("Confidence", "Wrist detection disabled");
                        break;
                case 0x3F:
                        ShowData("Confidence", "On Wrist");
                        break;
                default:
                        ShowData("Confidence", IntToHex(Frame->Data.Confidence, 2));
                        break;
        }

        switch (Frame->Data.DeviceClass)
        {
                case 0x0002:
                        ShowData("Device class", "iPhone");
                        break;
                case 0x0003:
                        ShowData("Device class", "iPad");
                        break;
                case 0x0007:
                        ShowData("Device class", "HomePod");
                        break;
                case 0x0009:
                        ShowData("Device class", "MacBook");
                        break;
                case 0x000A:
                        ShowData("Device class", "Watch");
                        break;
                default:
                        ShowData("Device class", IntToHex(Frame->Data.DeviceClass, 4));
                        break;
        }

        ShowData("Rand", IntToHex(Frame->Data.Rand, 2));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAppleHeySiriFrame(TObject *Sender,
      const TwclBluetoothLeAdvertisementInfo &Info,
      const TwclBluetoothLeAppleHeySiriFrameData &Data)
{
        AddFrame(new TAppleHeySiriFrame(Info, Data));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowAppleMagicSwitchFrame(TAppleMagicSwitchFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("Data", IntToHex(Frame->Data.Data, 4));

        switch (Frame->Data.Confidence)
        {
                case 0x03:
                        ShowData("Confidence", "Not on Wrist");
                        break;
                case 0x1F:
                        ShowData("Confidence", "Wrist detection disabled");
                        break;
                case 0x3F:
                        ShowData("Confidence", "On Wrist");
                        break;
                default:
                        ShowData("Confidence", IntToHex(Frame->Data.Confidence, 2));
                        break;
        }
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAppleMagicSwitchFrame(
      TObject *Sender, const TwclBluetoothLeAdvertisementInfo &Info,
      const TwclBluetoothLeAppleMagicSwitchFrameData Data)
{
        AddFrame(new TAppleMagicSwitchFrame(Info, Data));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowAppleTetheringSourceFrame(
        TAppleTetheringSourceFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("Version", IntToHex(Frame->Data.Version, 2));
        ShowData("Flags", IntToHex(Frame->Data.Flags, 2));
        ShowData("Battery", IntToStr(Frame->Data.Battery));

        switch (Frame->Data.CellType)
        {
                case 0x0000:
                        ShowData("Cell type", "4G (GSM)");
                        break;
                case 0x0001:
                        ShowData("Cell type", "1xRTT");
                        break;
                case 0x0002:
                        ShowData("Cell type", "GPRS");
                        break;
                case 0x0003:
                        ShowData("Cell type", "EDGE");
                        break;
                case 0x0004:
                        ShowData("Cell type", "3G (EV-DO)");
                        break;
                case 0x0005:
                        ShowData("Cell type", "3G");
                        break;
                case 0x0006:
                        ShowData("Cell type", "4G");
                        break;
                case 0x0007:
                        ShowData("Cell type", "LTE");
                        break;
                default:
                        ShowData("Cell type", IntToHex(Frame->Data.CellType, 4));
        }

        ShowData("Bars", IntToStr(Frame->Data.Bars));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAppleTetheringSourceFrame(
      TObject *Sender, const TwclBluetoothLeAdvertisementInfo &Info,
      const TwclBluetoothLeAppleTetheringSourceFrameData &Data)
{
        AddFrame(new TAppleTetheringSourceFrame(Info, Data));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::ShowAppleTetheringTargetFrame(
        TAppleTetheringTargetFrame* const Frame)
{
        ShowFrameBaseData(Frame);

        ShowData("Id", IntToHex((int)Frame->Data.Id, 8));
}
//---------------------------------------------------------------------------
void __fastcall TfmMain::BeaconWatcherAppleTetheringTargetFrame(
      TObject *Sender, const TwclBluetoothLeAdvertisementInfo &Info,
      const TwclBluetoothLeAppleTetheringTargetFrameData Data)
{
        AddFrame(new TAppleTetheringTargetFrame(Info, Data));        
}
//---------------------------------------------------------------------------

