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

#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"

#ifdef _WIN64
#pragma comment(lib, "wclCommon.a")
#pragma comment(lib, "wclCommunication.a")
#pragma comment(lib, "wclBluetoothFrameworkR.a")
#else
#pragma comment(lib, "wclCommon.lib")
#pragma comment(lib, "wclCommunication.lib")
#pragma comment(lib, "wclBluetoothFrameworkR.lib")
#endif

TfmMain *fmMain;
//---------------------------------------------------------------------------

__fastcall TfmMain::TfmMain(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::FormDestroy(TObject *Sender)
{
  wclBluetoothManager->Close();
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::btOpenClick(TObject *Sender)
{
  int Res = wclBluetoothManager->Open();
  if (Res != WCL_E_SUCCESS)
    MessageDlg("Error: 0x" + IntToHex(Res, 8), mtError, TMsgDlgButtons() << mbOK, 0);
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::btCloseClick(TObject *Sender)
{
  int Res = wclBluetoothManager->Close();
  if (Res != WCL_E_SUCCESS)
    MessageDlg("Error: 0x" + IntToHex(Res, 8), mtError, TMsgDlgButtons() << mbOK, 0);
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::btStartClick(TObject *Sender)
{
  TwclBluetoothRadio* Radio = GetRadio();
  if (Radio != NULL)
  {
    TwclBluetoothLeScanningMode Mode;
    if (cbMode->Checked)
      Mode = smActive;
    else
      Mode = smPassive;
    int Res = wclBluetoothLeBeaconWatcher->Start(Radio, Mode,
      StrToInt(edScanInterval->Text), StrToInt(edScanWindow->Text));
    if (Res != WCL_E_SUCCESS)
      MessageDlg("Error: 0x" + IntToHex(Res, 8), mtError, TMsgDlgButtons() << mbOK, 0);
  }
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::btStopClick(TObject *Sender)
{
  if (!wclBluetoothManager->Active)
    MessageDlg("Bluetooth Manager was not opened", mtWarning, TMsgDlgButtons() << mbOK, 0);
  else
  {
    int Res = wclBluetoothLeBeaconWatcher->Stop();
    if (Res != WCL_E_SUCCESS)
      MessageDlg("Error: 0x" + IntToHex(Res, 8), mtError, TMsgDlgButtons() << mbOK, 0);
  }
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothManagerAfterOpen(TObject *Sender)
{
  ListBox->Items->Add("Bluetooth Manager Opened");
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothManagerBeforeClose(TObject *Sender)
{
  ListBox->Items->Add("Bluetooth Manager Closed");
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothManagerStatusChanged(TObject *Sender,
      const TwclBluetoothRadio *Radio)
{
  String Str;
  if (((TwclBluetoothRadio*)Radio)->Available)
   Str = "AVAILABLE";
  else
   Str = "UNAVAILABLE";
  ListBox->Items->Add("Radio " + ((TwclBluetoothRadio*)Radio)->ApiName + " status changed: " + Str);
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::btClearClick(TObject *Sender)
{
  lbFrames->Clear();
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::btClearLogsClick(TObject *Sender)
{
  ListBox->Clear();
}
//---------------------------------------------------------------------------

TDateTime __fastcall TfmMain::ConvertTime(__int64 Timestamp)
{
  ULARGE_INTEGER li;
  FILETIME ft;
  SYSTEMTIME st;
  // Conver timestamp.
  li.QuadPart = Timestamp;
  ft.dwLowDateTime = li.LowPart;
  ft.dwHighDateTime = li.HighPart;
  FileTimeToLocalFileTime(&ft, &ft);
  FileTimeToSystemTime(&ft, &st);
  return SystemTimeToDateTime(st);
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherStarted(
      TObject *Sender)
{
  ListBox->Items->Add("Beacons Monitoring Started");
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherStopped(
      TObject *Sender)
{
  ListBox->Items->Add("Beacons Monitoring Stopped");
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::btStopAdvertisingClick(TObject *Sender)
{
  int Res = wclBluetoothLeAdvertiser->Stop();
  if (Res != WCL_E_SUCCESS)
    ListBox->Items->Add("Stop advertiser failed: 0x" + IntToHex(Res, 8));
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::btStartAdvertisingClick(TObject *Sender)
{
  static const GUID BEACON_UUID = { 0x09039835, 0x4A80, 0x443B, { 0x87, 0xAA, 0xDC, 0x56, 0x5D, 0x09, 0xEA, 0x61 } };

  TwclBluetoothRadio* Radio = GetRadio();
  if (Radio != NULL)
  {
    TwclBluetoothLeAdvertisement* Adv;
    // Create and add iBeacon advdertisement.
    if (cbIBeacon->Checked)
    {
      Adv = new TwclBluetoothLeiBeaconAdvertisement(-5, 0x0101, 0x0202,
        BEACON_UUID);
      AddAdvertisement(Adv);
    }

    // Create and add Proximity Beacon advertisement.
    if (cbProximityBeacon->Checked)
    {
      Adv = new TwclBluetoothLeProximityBeaconAdvertisement(-5, 0x0101, 0x0202,
        BEACON_UUID, 0xFFFE);
      AddAdvertisement(Adv);
    }

    // Create and add Alt Beacon advertisement.
    if (cbAltBeacon->Checked)
    {
      Adv = new TwclBluetoothLeAltBeaconAdvertisement(-5, 0x0101, 0x0202,
        BEACON_UUID, 0xFFFE, 0x11);
      AddAdvertisement(Adv);
    }

    // Create and add Eddystone UID advertisement.
    if (cbEddystoneUid->Checked)
    {
      Adv = new TwclBluetoothLeEddystoneUidBeaconAdvertisement(-5, BEACON_UUID);
      AddAdvertisement(Adv);
    }

    // Create and add Eddystone URL.
    if (cbEddystoneUrl->Checked)
    {
      Adv = new TwclBluetoothLeEddystoneUrlBeaconAdvertisement(-5,
        "https://www.btframework.com");
      AddAdvertisement(Adv);
    }

    // Create and add custom advertisement.
    if (cb128SolUuid->Checked)
    {
      TwclBluetoothLeAdvertisementFrameRawData Data;
      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);
    }

    // Create and add manufacturer specific advertisement.
    if (cbManufacturer->Checked)
    {
      TwclBluetoothLeAdvertisementFrameRawData Data;
      Data.Length = 2;
      Data[0] = 0x12;
      Data[1] = 0x34;
      Adv = new TwclBluetoothLeManufacturerAdvertisement(0x010E, Data);
      AddAdvertisement(Adv);
    }

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

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

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

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

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

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

    if (cbCustomRaw->Checked)
    {
      TwclBluetoothLeAdvertisementFrameRawData Data;
      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 (wclBluetoothLeAdvertiser->Count == 0)
      ShowMessage("Select at least one advertisement type.");
    else
    {
      wclBluetoothLeAdvertiser->UseExtendedAdvertisement = cbUseExtended->Checked;
      wclBluetoothLeAdvertiser->Anonymous = cbAnonymous->Checked;
      wclBluetoothLeAdvertiser->IncludeTxRssi = cbIncludeTxRssi->Checked;
      wclBluetoothLeAdvertiser->PreferredTxRssi = 10;
      int Res = wclBluetoothLeAdvertiser->Start(Radio,
        StrToInt(edAdvInterval->Text));
      if (Res != WCL_E_SUCCESS)
      {
        ListBox->Items->Add("Start advertiser failed: 0x" + IntToHex(Res, 8));
        wclBluetoothLeAdvertiser->Clear();
      }
    }
  }
}
//---------------------------------------------------------------------------

void TfmMain::AddAdvertisement(TwclBluetoothLeAdvertisement* Adv)
{
  int Res = wclBluetoothLeAdvertiser->Add(Adv);
  if (Res != WCL_E_SUCCESS)
  {
    ListBox->Items->Add("Add advertisement failed: 0x" + IntToHex(Res, 8));
    delete Adv;
  }
}
//---------------------------------------------------------------------------

TwclBluetoothRadio* TfmMain::GetRadio()
{
  TwclBluetoothRadio* Radio;
  int Res = wclBluetoothManager->GetLeRadio(Radio);
  if (Res != WCL_E_SUCCESS)
  {
    MessageDlg("Get working radio failed: 0x" + IntToHex(Res, 8), mtError,
      TMsgDlgButtons() << mbOK, 0);
    return NULL;
  }
  return Radio;
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeAdvertiserStarted(TObject *Sender)
{
  ListBox->Items->Add("Bluetooth LE Advertising Started");

  EnableAdvertisements(false);
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeAdvertiserStopped(TObject *Sender)
{
  ListBox->Items->Add("Bluetooth LE Advertising Stopped");
  wclBluetoothLeAdvertiser->Clear();

  EnableAdvertisements(true);
}
//---------------------------------------------------------------------------

void TfmMain::EnableAdvertisements(bool Enable)
{
  cbIBeacon->Enabled = Enable;
  cbProximityBeacon->Enabled = Enable;
  cbAltBeacon->Enabled = Enable;
  cbEddystoneUid->Enabled = Enable;
  cbEddystoneUrl->Enabled = Enable;
  cb128SolUuid->Enabled = Enable;
  cbManufacturer->Enabled = Enable;
  cb16UuidService->Enabled = Enable;
  cb32UuidService->Enabled = Enable;
  cb128UuidService->Enabled = Enable;
  cb16UuidData->Enabled = Enable;
  cb32UuidData->Enabled = Enable;
  cb128UuidData->Enabled = Enable;
  cbCustomRaw->Enabled = Enable;
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::FormCreate(TObject *Sender)
{
  edAdvInterval->Text = IntToStr(WCL_BLE_DEFAULT_ADVERTISING_INTERVAL);

  DefaultScanParams();
}
//---------------------------------------------------------------------------

void TfmMain::DumpData(const TwclBluetoothLeAdvertisementFrameRawData Data)
{
  if (Data.Length > 0)
  {
    String Str = "";
    unsigned char c = 0;
    for (int i = 0; i < Data.Length; i++)
    {
      Str = Str + IntToHex(Data[i], 2);
      if (c == 15)
      {
        lbFrames->Items->Add("    " + Str);
        Str = "";
        c = 0;
      }
      else
        c++;
    }
    if (Str != "")
      lbFrames->Items->Add("    " + Str);
  }
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::btDefaultScanParamsClick(TObject *Sender)
{
  DefaultScanParams();
}
//---------------------------------------------------------------------------

void TfmMain::DefaultScanParams()
{
  cbMode->Checked = true;
  edScanInterval->Text = IntToStr(WCL_BLE_DEFAULT_SCAN_INTERVAL);
  edScanWindow->Text = IntToStr(WCL_BLE_DEFAULT_SCAN_WINDOW);
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::btDefIntervalClick(TObject *Sender)
{
  edAdvInterval->Text = IntToStr(WCL_BLE_DEFAULT_ADVERTISING_INTERVAL);
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherAdvertisementExtFrameInformation(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const TwclBluetoothAddressType AddressType,
      const SByte TxPower, const TwclBluetoothLeExtendedFrameFlags Flags)
{
  lbFrames->Items->Add("EXTENDED FRAME INFORMATION");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));

  String Str;
  switch (AddressType)
  {
    case atPublic:
      Str = "Public";
      break;
    case atRandom:
      Str = "Random";
      break;
    case atUnspecified:
      Str = "Unspecified";
      break;
    default:
      Str = "Unknown";
      break;
  }
  lbFrames->Items->Add("  Address type: " + Str);

  lbFrames->Items->Add("  TX Power: " + IntToStr(TxPower));

  Str = "[";
  if (Flags.Contains(efAnonymous))
    Str = Str + " efAnonymous";
  if (Flags.Contains(efConnectable))
    Str = Str + " efConnectable";
  if (Flags.Contains(efDirected))
    Str = Str + " efDirected";
  if (Flags.Contains(efScannable))
    Str = Str + " efScannable";
  if (Flags.Contains(efScanResponse))
    Str = Str + " efScanResponse";
  Str = Str + " ]";
  lbFrames->Items->Add("  Flags: " + Str);

  lbFrames->Items->Add("-----------------------------------------------------");
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherAdvertisementFrameInformation(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
	  const SByte Rssi, const String Name,
	  const TwclBluetoothLeAdvertisementType PacketType,
      const TwclBluetoothLeAdvertisementFlags Flags)
{
  lbFrames->Items->Add("FRAME INFORMATION");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));
  lbFrames->Items->Add("  Name: " + Name);

  String Str;
  switch (PacketType)
  {
    case atConnectableUndirected:
      Str = "Connectable Undirected";
      break;
    case atConnectableDirected:
      Str = "Connectable Directed";
      break;
    case atScannableUndirected:
      Str = "Scannable Undirecte";
      break;
    case atNonConnectableUndirected:
      Str = "Non Connectable Undirected";
      break;
    case atScanResponse:
      Str = "Scan Response";
      break;
    default:
      Str = "Unknown";
      break;
  }
  lbFrames->Items->Add("  Frame type: " + Str);

  Str = "[";
  if (Flags.Contains(afLimitedDiscoverableMode))
    Str = Str + " afLimitedDiscoverableMode";
  if (Flags.Contains(afGeneralDiscoverableMode))
    Str = Str + " afGeneralDiscoverableMode";
  if (Flags.Contains(afClassicNotSupported))
    Str = Str + " afClassicNotSupported";
  if (Flags.Contains(afDualModeControllerCapable))
    Str = Str + " afDualModeControllerCapable";
  if (Flags.Contains(afDualModeHostCapable))
    Str = Str + " afDualModeHostCapable";
  Str = Str + " ]";
  lbFrames->Items->Add("  Flags: " + Str);

  lbFrames->Items->Add("-----------------------------------------------------");        
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherAdvertisementRawFrame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const BYTE DataType,
      const TwclBluetoothLeAdvertisementFrameRawData Data)
{
  lbFrames->Items->Add("UNKNOWN RAW FRAME");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));

  lbFrames->Items->Add("  Data type: " + IntToHex(DataType, 2));

  DumpData(Data);

  lbFrames->Items->Add("-----------------------------------------------------");        
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherAdvertisementReceived(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi,
      const TwclBluetoothLeAdvertisementFrameRawData Data)
{
  lbFrames->Items->Add("RAW ADVERTISEMENT FRAME");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));

  DumpData(Data);

  lbFrames->Items->Add("-----------------------------------------------------");        
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherAdvertisementService128DataFrame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const TGUID &Uuid,
      const TwclBluetoothLeAdvertisementFrameRawData Data)
{
  lbFrames->Items->Add("128 UUID SERVICE DATA");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));
  #if __BORLANDC__ >= 0x0570
  lbFrames->Items->Add("  UUID: " + Sysutils::GUIDToString(Uuid));
  #else
  lbFrames->Items->Add("  UUID: " + GUIDToString(Uuid));
  #endif

  DumpData(Data);

  lbFrames->Items->Add("-----------------------------------------------------");        
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherAdvertisementService16DataFrame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const WORD Uuid,
      const TwclBluetoothLeAdvertisementFrameRawData Data)
{
  lbFrames->Items->Add("16 UUID SERVICE DATA");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));
  lbFrames->Items->Add("  UUID: " + IntToHex(Uuid, 4));

  DumpData(Data);

  lbFrames->Items->Add("-----------------------------------------------------");        
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherAdvertisementService32DataFrame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const DWORD Uuid,
      const TwclBluetoothLeAdvertisementFrameRawData Data)
{
  lbFrames->Items->Add("32 UUID SERVICE DATA");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));
  lbFrames->Items->Add("  UUID: " + IntToHex((int)Uuid, 8));

  DumpData(Data);

  lbFrames->Items->Add("-----------------------------------------------------");        
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherAdvertisementServiceSol128Frame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const TGUID &Uuid)
{
  lbFrames->Items->Add("128 UUID SOL SERVICE");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));
  #if __BORLANDC__ >= 0x0570
  lbFrames->Items->Add("  UUID: " + Sysutils::GUIDToString(Uuid));
  #else
  lbFrames->Items->Add("  UUID: " + GUIDToString(Uuid));
  #endif

  lbFrames->Items->Add("-----------------------------------------------------");        
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherAdvertisementServiceSol16Frame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const WORD Uuid)
{
  lbFrames->Items->Add("16 UUID SOL SERVICE");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));
  lbFrames->Items->Add("  UUID: " + IntToHex(Uuid, 4));

  lbFrames->Items->Add("-----------------------------------------------------");        
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherAdvertisementServiceSol32Frame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const DWORD Uuid)
{
  lbFrames->Items->Add("32 UUID SOL SERVICE");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));
  lbFrames->Items->Add("  UUID: " + IntToHex((int)Uuid, 8));

  lbFrames->Items->Add("-----------------------------------------------------");        
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherAdvertisementUuidFrame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const TGUID &Uuid)
{
  lbFrames->Items->Add("UUID FRAME");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));
  #if __BORLANDC__ >= 0x0570
  lbFrames->Items->Add("  UUID: " + Sysutils::GUIDToString(Uuid));
  #else
  lbFrames->Items->Add("  UUID: " + GUIDToString(Uuid));
  #endif

  lbFrames->Items->Add("-----------------------------------------------------");        
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherAltBeaconFrame(
      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)
{
  // Calculate distance.
  double Dist = pow(10.0, (double)(TxRssi - Rssi) / 20.0);

  lbFrames->Items->Add("ALT BEACON FRAME");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Company ID: " + IntToHex(CompanyId, 4));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));

  #if __BORLANDC__ >= 0x0570
  lbFrames->Items->Add("  UUID: " + Sysutils::GUIDToString(Uuid));
  #else
  lbFrames->Items->Add("  UUID: " + GUIDToString(Uuid));
  #endif
  lbFrames->Items->Add("  Major: " + IntToHex(Major, 4));
  lbFrames->Items->Add("  Minor: " + IntToHex(Minor, 4));
  lbFrames->Items->Add("  Reserved: " + IntToHex(Reserved, 2));
  lbFrames->Items->Add("  TX RSSI: " + IntToStr(TxRssi));
  lbFrames->Items->Add("  Distance: " + FloatToStr(Dist));

  DumpData(Data);

  lbFrames->Items->Add("-----------------------------------------------------");        
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherEddystoneTlmFrame(
      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)
{
  lbFrames->Items->Add("EDDYSTONE TLM FRAME");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));

  lbFrames->Items->Add("  Advertisements counter: " + IntToStr((int)AdvCnt));
  lbFrames->Items->Add("  Battery (mv): " + IntToStr(Batt));
  lbFrames->Items->Add("  Seconds running: " + FloatToStr(SecCnt / 10));
  lbFrames->Items->Add("  Temperature: " + FloatToStr(Temp));

  DumpData(Data);

  lbFrames->Items->Add("-----------------------------------------------------");        
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherEddystoneUidFrame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const SByte TxRssi, const TGUID &Uuid,
      const TwclBluetoothLeAdvertisementFrameRawData Data)
{
  // Calculate distance.
  double Dist = pow(10.0, (double)(TxRssi - 41 - Rssi) / 20.0);

  lbFrames->Items->Add("EDDYSTONE UID FRAME");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));

  #if __BORLANDC__ >= 0x0570
  lbFrames->Items->Add("  UUID: " + Sysutils::GUIDToString(Uuid));
  #else
  lbFrames->Items->Add("  UUID: " + GUIDToString(Uuid));
  #endif
  lbFrames->Items->Add("  TX RSSI: " + IntToStr(TxRssi));
  lbFrames->Items->Add("  Distance: " + FloatToStr(Dist));

  DumpData(Data);

  lbFrames->Items->Add("-----------------------------------------------------");        
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherEddystoneUrlFrame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const SByte TxRssi, const String Url)
{
  // Calculate distance.
  double Dist = pow(10.0, (double)(TxRssi - 41 - Rssi) / 20.0);

  lbFrames->Items->Add("EDDYSTONE URL FRAME");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));

  lbFrames->Items->Add("  URL: " + Url);

  lbFrames->Items->Add("  TX RSSI: " + IntToStr(TxRssi));
  lbFrames->Items->Add("  Distance: " + FloatToStr(Dist));

  lbFrames->Items->Add("-----------------------------------------------------");        
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherManufacturerRawFrame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const WORD CompanyId,
      const TwclBluetoothLeAdvertisementFrameRawData Data)
{
  lbFrames->Items->Add("UNKNOWN MANUFACTURER RAW FRAME");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Company ID: " + IntToHex(CompanyId, 4));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));

  DumpData(Data);

  lbFrames->Items->Add("-----------------------------------------------------");        
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherProximityBeaconFrame(
      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 TwclBluetoothLeAdvertisementFrameRawData Data)
{
  // Calculate distance.
  double Dist = pow(10.0, (double)(TxRssi - Rssi) / 20.0);

  lbFrames->Items->Add("PROXIMITY BEACON FRAME");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Company ID: " + IntToHex(CompanyId, 4));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));


  #if __BORLANDC__ >= 0x0570
  lbFrames->Items->Add("  UUID: " + Sysutils::GUIDToString(Uuid));
  #else
  lbFrames->Items->Add("  UUID: " + GUIDToString(Uuid));
  #endif
  lbFrames->Items->Add("  Major: " + IntToHex(Major, 4));
  lbFrames->Items->Add("  Minor: " + IntToHex(Minor, 4));
  lbFrames->Items->Add("  TX RSSI: " + IntToStr(TxRssi));
  lbFrames->Items->Add("  Distance: " + FloatToStr(Dist));

  DumpData(Data);

  lbFrames->Items->Add("-----------------------------------------------------");
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherAdvertisementTxPowerLevelFrame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const SByte TxPower)
{
  lbFrames->Items->Add("TX POWER FRAME");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));

  lbFrames->Items->Add("  TX Power: " + IntToStr(TxPower));

  lbFrames->Items->Add("-----------------------------------------------------");
}
//---------------------------------------------------------------------------

void __fastcall TfmMain::wclBluetoothLeBeaconWatcherAdvertisementAppearanceFrame(
      TObject *Sender, const __int64 Address, const __int64 Timestamp,
      const SByte Rssi, const WORD Appearance)
{
  lbFrames->Items->Add("APPEARANCE FRAME");

  lbFrames->Items->Add("  Address: " + IntToHex(Address, 12));
  lbFrames->Items->Add("  Timestamp: " + DateTimeToStr(ConvertTime(Timestamp)));
  lbFrames->Items->Add("  RSSI: " + IntToStr(Rssi));

  lbFrames->Items->Add("  Appearance: " + IntToHex(Appearance, 4));

  lbFrames->Items->Add("-------------------------------------------------------");
}
//---------------------------------------------------------------------------

