Note: GATT service with Bluetooth Low Energy

傳統的Bluetooth Device 透過 SDP service 使用Profile UUID 去讓兩者相連, 但是BLE則擴充了這個方法, 透過提供 GATT (Generic Attributes) Profile 去取代 SDP的功能,使用GATT Service 內的 Service/Characteristics 功能可以更方便跟分類各種服務跟屬性值, 並且透過GATT 可以自我宣告特定應用的Service與Characteristics 去創建自己的特殊應用 常見有iBeacon/Eddystone Beacon 或是 像是 TI SensorTags 可以參考這個 Andorid Source 去使用Ti 自定義的Barometers service

官方說法 from https://www.bluetooth.com/specifications/profiles-overview
For two Bluetooth devices to be compatible, they must support the same profiles. And while profiles generally describe the same use case behaviors, they are different for Bluetooth BR/EDR and Bluetooth Low Energy (LE) implementations. Compatibility between Bluetooth BR/EDR and Bluetooth LE implementations requires a dual-mode controller on at least one. For BR/EDR, a wide range of adopted Bluetooth profiles describe many different, commonly used types of applications or use cases for devices. For Bluetooth LE, developers can use a comprehensive set of adopted profiles, or they can use Generic Attribute Profile (GATT) to create new profiles. This flexibility helps support innovative new applications that maintain interoperability with other Bluetooth devices.

廣告

Get Bluetooth Dongle Address for WINCE 5.0/WM5/WM6

Just need 2 step.

  1. Get “BTD0:" handle
  2. Call DeviceIOControl, ReadLocalAddr (14)
BOOL GetBTH_ADDR(BT_ADDR *btaddr)
{
	HANDLE hDev = INVALID_HANDLE_VALUE;

	unsigned buff[8];

	memset(buff, 0, sizeof(buff));

	*btaddr = 0;

	hDev = CreateFile(L"BTD0:", GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_READ | FILE_SHARE_WRITE,
		NULL,
		OPEN_EXISTING,
		0,
		NULL);

	if (hDev == INVALID_HANDLE_VALUE)
	{
		return FALSE;
	}

#define BT_IOCTL_ReadLocalAddr 14

	int iErr = DeviceIoControl(hDev, BT_IOCTL_ReadLocalAddr, &buff, sizeof(buff), NULL, NULL, NULL, NULL);
	CloseHandle(hDev);
	hDev = INVALID_HANDLE_VALUE;

	if (iErr)
	{
		*btaddr = *((BT_ADDR*)buff);
		return TRUE;
	}

	return FALSE;
}

static WCHAR NUM2HEX(UINT i)
{
	const WCHAR idx[] = { L'0', L'1', L'2', L'3',
			L'4', L'5', L'6', L'7',
			L'8', L'9', L'A', L'B',
			L'C', L'D', L'E', L'F' };
	i &= 0xF;
	return idx[i];
/*
	if (i < 10)
	 return i + L'0';

	i -= 10;
	return i + L'A';
*/
}

static WCHAR LOBYTE2WC(const UCHAR x)
{
	return NUM2HEX(x & 0x0F);
}

static WCHAR HIBYTE2WC(const UCHAR x)
{
	return NUM2HEX(x>>4);
}

void BTADDR2WC(WCHAR* buff, BT_ADDR _btAddr, UINT sz)
{
	BYTE *pB = (BYTE*)&_btAddr+5;
	UINT i = 0;

	if (sz < (6*3 + 1))
		return;

	do
	{
		buff[i*3]=HIBYTE2WC(*(pB-i));
		buff[i*3+1]=LOBYTE2WC(*(pB-i));
		buff[i*3+2]=L':';
	} while (++i < 6);
	buff[i*3-1] = L'/0';
}

Bluetooth Service UUID List

今天找了一下 關於 Bluetooth 的標準 Service/Profile 的 UUID ,但是看了一下 Specification Doucments 都只有 16bits 長,這是所謂的UUID16格式

後來才了解,原來Bluetooth 將UUID 的部份固定,只取16bits 作為各種 Service 的區分,這樣可以節省分析 SDP Record and 與程式空間,避免增加 Bluetooth Device 的成本。

底下的值可以從 windows XP or Server 2003 SDK 的 bt_sdp.h or BlueZ 的 sdp.h(UUID16) 中找到定義,可以觀察出 下列的固定序列除了替換 XXXX部份

‘{0000xxxx-0000-1000-8000-00805F9B34FB}’,而XXXX 部份就是 所謂的 UUID16 定義。

Protocols UUID http://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm
BASE UUID 00000000-0000-1000-8000-00805F9B34FB
SDP_PROTOCOL_UUID         = '{00000001-0000-1000-8000-00805F9B34FB}';
UDP_PROTOCOL_UUID         = '{00000002-0000-1000-8000-00805F9B34FB}';
RFCOMM_PROTOCOL_UUID      = '{00000003-0000-1000-8000-00805F9B34FB}';
TCP_PROTOCOL_UUID         = '{00000004-0000-1000-8000-00805F9B34FB}';
TCSBIN_PROTOCOL_UUID      = '{00000005-0000-1000-8000-00805F9B34FB}';
TCSAT_PROTOCOL_UUID       = '{00000006-0000-1000-8000-00805F9B34FB}';
OBEX_PROTOCOL_UUID        = '{00000008-0000-1000-8000-00805F9B34FB}';
IP_PROTOCOL_UUID          = '{00000009-0000-1000-8000-00805F9B34FB}';
FTP_PROTOCOL_UUID         = '{0000000A-0000-1000-8000-00805F9B34FB}';
HTTP_PROTOCOL_UUID        = '{0000000C-0000-1000-8000-00805F9B34FB}';
WSP_PROTOCOL_UUID         = '{0000000E-0000-1000-8000-00805F9B34FB}';
BNEP_PROTOCOL_UUID        = '{0000000F-0000-1000-8000-00805F9B34FB}';
UPNP_PROTOCOL_UUID        = '{00000010-0000-1000-8000-00805F9B34FB}';
HID_PROTOCOL_UUID         = '{00000011-0000-1000-8000-00805F9B34FB}';
HCCC_PROTOCOL_UUID        = '{00000012-0000-1000-8000-00805F9B34FB}';
HCDC_PROTOCOL_UUID        = '{00000014-0000-1000-8000-00805F9B34FB}';
HN_PROTOCOL_UUID          = '{00000016-0000-1000-8000-00805F9B34FB}';
AVCTP_PROTOCOL_UUID       = '{00000017-0000-1000-8000-00805F9B34FB}';
AVDTP_PROTOCOL_UUID       = '{00000019-0000-1000-8000-00805F9B34FB}';
CMPT_PROTOCOL_UUID        = '{0000001B-0000-1000-8000-00805F9B34FB}';
UDI_C_PLANE_PROTOCOL_UUID = '{0000001D-0000-1000-8000-00805F9B34FB}';
L2CAP_PROTOCOL_UUID       = '{00000100-0000-1000-8000-00805F9B34FB}';
Ref. Service class IDs http://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm
ServiceDiscoveryServerServiceClassID_UUID       = '{00001000-0000-1000-8000-00805F9B34FB}';
BrowseGroupDescriptorServiceClassID_UUID        = '{00001001-0000-1000-8000-00805F9B34FB}';
PublicBrowseGroupServiceClass_UUID              = '{00001002-0000-1000-8000-00805F9B34FB}';
SerialPortServiceClass_UUID                     = '{00001101-0000-1000-8000-00805F9B34FB}';
LANAccessUsingPPPServiceClass_UUID              = '{00001102-0000-1000-8000-00805F9B34FB}';
DialupNetworkingServiceClass_UUID               = '{00001103-0000-1000-8000-00805F9B34FB}';
IrMCSyncServiceClass_UUID                       = '{00001104-0000-1000-8000-00805F9B34FB}';
OBEXObjectPushServiceClass_UUID                 = '{00001105-0000-1000-8000-00805F9B34FB}';
OBEXFileTransferServiceClass_UUID               = '{00001106-0000-1000-8000-00805F9B34FB}';
IrMCSyncCommandServiceClass_UUID                = '{00001107-0000-1000-8000-00805F9B34FB}';
HeadsetServiceClass_UUID                        = '{00001108-0000-1000-8000-00805F9B34FB}';
CordlessTelephonyServiceClass_UUID              = '{00001109-0000-1000-8000-00805F9B34FB}';
AudioSourceServiceClass_UUID                    = '{0000110A-0000-1000-8000-00805F9B34FB}';
AudioSinkServiceClass_UUID                      = '{0000110B-0000-1000-8000-00805F9B34FB}';
AVRemoteControlTargetServiceClass_UUID          = '{0000110C-0000-1000-8000-00805F9B34FB}';
AdvancedAudioDistributionServiceClass_UUID      = '{0000110D-0000-1000-8000-00805F9B34FB}';
AVRemoteControlServiceClass_UUID                = '{0000110E-0000-1000-8000-00805F9B34FB}';
VideoConferencingServiceClass_UUID              = '{0000110F-0000-1000-8000-00805F9B34FB}';
IntercomServiceClass_UUID                       = '{00001110-0000-1000-8000-00805F9B34FB}';
FaxServiceClass_UUID                            = '{00001111-0000-1000-8000-00805F9B34FB}';
HeadsetAudioGatewayServiceClass_UUID            = '{00001112-0000-1000-8000-00805F9B34FB}';
WAPServiceClass_UUID                            = '{00001113-0000-1000-8000-00805F9B34FB}';
WAPClientServiceClass_UUID                      = '{00001114-0000-1000-8000-00805F9B34FB}';
PANUServiceClass_UUID                           = '{00001115-0000-1000-8000-00805F9B34FB}';
NAPServiceClass_UUID                            = '{00001116-0000-1000-8000-00805F9B34FB}';
GNServiceClass_UUID                             = '{00001117-0000-1000-8000-00805F9B34FB}';
DirectPrintingServiceClass_UUID                 = '{00001118-0000-1000-8000-00805F9B34FB}';
ReferencePrintingServiceClass_UUID              = '{00001119-0000-1000-8000-00805F9B34FB}';
ImagingServiceClass_UUID                        = '{0000111A-0000-1000-8000-00805F9B34FB}';
ImagingResponderServiceClass_UUID               = '{0000111B-0000-1000-8000-00805F9B34FB}';
ImagingAutomaticArchiveServiceClass_UUID        = '{0000111C-0000-1000-8000-00805F9B34FB}';
ImagingReferenceObjectsServiceClass_UUID        = '{0000111D-0000-1000-8000-00805F9B34FB}';
HandsfreeServiceClass_UUID                      = '{0000111E-0000-1000-8000-00805F9B34FB}';
HandsfreeAudioGatewayServiceClass_UUID          = '{0000111F-0000-1000-8000-00805F9B34FB}';
DirectPrintingReferenceObjectsServiceClass_UUID = '{00001120-0000-1000-8000-00805F9B34FB}';
ReflectedUIServiceClass_UUID                    = '{00001121-0000-1000-8000-00805F9B34FB}';
BasicPringingServiceClass_UUID                  = '{00001122-0000-1000-8000-00805F9B34FB}';
PrintingStatusServiceClass_UUID                 = '{00001123-0000-1000-8000-00805F9B34FB}';
HumanInterfaceDeviceServiceClass_UUID           = '{00001124-0000-1000-8000-00805F9B34FB}';
HardcopyCableReplacementServiceClass_UUID       = '{00001125-0000-1000-8000-00805F9B34FB}';
HCRPrintServiceClass_UUID                       = '{00001126-0000-1000-8000-00805F9B34FB}';
HCRScanServiceClass_UUID                        = '{00001127-0000-1000-8000-00805F9B34FB}';
CommonISDNAccessServiceClass_UUID               = '{00001128-0000-1000-8000-00805F9B34FB}';
VideoConferencingGWServiceClass_UUID            = '{00001129-0000-1000-8000-00805F9B34FB}';
UDIMTServiceClass_UUID                          = '{0000112A-0000-1000-8000-00805F9B34FB}';
UDITAServiceClass_UUID                          = '{0000112B-0000-1000-8000-00805F9B34FB}';
AudioVideoServiceClass_UUID                     = '{0000112C-0000-1000-8000-00805F9B34FB}';
PnPInformationServiceClass_UUID                 = '{00001200-0000-1000-8000-00805F9B34FB}';
GenericNetworkingServiceClass_UUID              = '{00001201-0000-1000-8000-00805F9B34FB}';
GenericFileTransferServiceClass_UUID            = '{00001202-0000-1000-8000-00805F9B34FB}';
GenericAudioServiceClass_UUID                   = '{00001203-0000-1000-8000-00805F9B34FB}';
GenericAudioServiceClass_UUID                   = '{00001203-0000-1000-8000-00805F9B34FB}';
GenericTelephonyServiceClass_UUID               = '{00001204-0000-1000-8000-00805F9B34FB}';
UPnPServiceClass_UUID                           = '{00001205-0000-1000-8000-00805F9B34FB}';
UPnPIpServiceClass_UUID                         = '{00001206-0000-1000-8000-00805F9B34FB}';
ESdpUPnPIpPanServiceClass_UUID                  = '{00001300-0000-1000-8000-00805F9B34FB}';
ESdpUPnPIpLapServiceClass_UUID                  = '{00001301-0000-1000-8000-00805F9B34FB}';
EdpUPnpIpL2CAPServiceClass_UUID                 = '{00001302-0000-1000-8000-00805F9B34FB}';
Technorati tags: , , , , 

ref. An Introduction to Bluetooth programming in GNU/Linux – Chapter 4. Bluetooth programming in C with BlueZ
4.4. Service Discovery Protocol

CSR HCI Extension Packet

CSR使用一個 HCI Extension 包裹 其 BCCMD 命令
基本的結構就是 OGF: 0x03F, OCF:0x00 => OpCode:0xFC00
BYTE cmdArray[] = { 0x00, 0x0FC, parameters total length, payload description, payload };
其 HCI_EVENT 則為下列結構

BYTE eventArray[] = {0xFF, parameters total length, payload decription, payload };


Payload Description
MSB
  • bit 7, Last Fragment
  • bit 6, First Fragment
  • bit 5~0, Channel ID
LSB
refer CSR HCI Extensions, July 2004.

 


而BCCMD 使用 Channel 2,BCCMD 基本結構是 是被 CSR 稱為 Message,由 5 個 UINT 16bits 的Head 開始

  • Type
    • GETREQ, 0x0000
    • GETRESP, 0x0001
    • SETREQ, 0x0002
  • Length, 整個 Message 的長度
  • Seq. No
  • Varid, 用來識別 CSR 內部獨特的資料庫 像是 PS Key 等, 0x0000 代表沒有使用
  • Status, 在 GETREQ 與 SETREQ 永遠是 0x0000(0K)
    • OK, 0x0000
    • NO_SUCH_VARID, 0x0001
    • TO_BIG, 0x0002
    • NO_VALUE, 0x0003
    • BAD_REG, 0x0004
    • NO_ACCESS, 0x0005
    • READ_ONLY, 0x0006
    • WRITE_ONLY, 0x0007
    • ERROR, 0x0008
    • PERMISSION_DENIED, 0x0009

一個設定Radio TX testing 範例就是如下

Host –> BlueCore(SETREQ)

    1. BCCMD. TYPE:  SETREQ(0x0002)
    2. BCCMD. LENGTH:  0x0009
    3. BCCMD. SEQ_NO:  ANY from HOST
    4. BCCMD. VARID:  RADIO_TEST(0x5004 or 20484)
    5. BCCMD. STATUS: OK(0x0000)
    6. BCCMD. RADIO_TEST.TYPE: TX_START (0x0001)
    7. BCCMD. RADIO_TEST.TX_START.FREQUENCY(2402 ~ 2495) (Mhz)
    8. BCCMD. RADIO_TEST.TX AMP. default (0xff32)
    9. BCCMD. RADIO_TEST.MODULATION: default (0x0000)

BYTE bccmd[18] = { 0x02, 0x00, 0x09, 0x00, 0x01, 0x00, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x62, 0x09, 0x32, 0xFF, 0x00, 0x00};

BYTE hci_cmd[] = { 0x00, 0xFC, 19, 0x02, include bccmd};

BlueCore –> Host (GETRESP)

    1. BCCMD. TYPE:  GETRESP(0x0001)
    2. BCCMD. LENGTH:  0x0009
    3. BCCMD. SEQ_NO:  same SETREQ
    4. BCCMD. VARID:  RADIO_TEST(0x5004 or 20484)
    5. BCCMD. STATUS: OK(0x0000)
    6. BCCMD. RADIO_TEST.TYPE: TX_START (0x0001)
    7. BCCMD. RADIO_TEST.TX_START.FREQUENCY(2402 ~ 2495) (Mhz)
    8. BCCMD. RADIO_TEST.TX AMP. default (0xff32)
    9. BCCMD. RADIO_TEST.MODULATION: default (0x0000)

BYTE hci_event[] = { 0xFF, 19, 0x02, 0x01, 0x00, 0x09, 0x01, 0x00, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x62, 0x09, 0x32, 0xff, 0x00, 0x00 };


Bluetooth HCI Data format

HCI (Host Control Interface) 是 Bluetooth SIG 設計用來提供Host 與 Bluetooth Module 連接的軟體介面(Software Inferface),在實際連結的硬體上目前制定了Transport 可以使HOST 與BT Module 實際連結有所依據,目前已經制定的Transport 有

  • UART
  • USB
  • SD
  • 3-Wire UART
HCI 有四種基本型態的封包,在不同的傳輸層透過不同的方式區別,
  • Commands, 用於Host 對 BT Module的控制
    • 在UART  Transport 使用 0x01 放在packet的開頭作識別
    • USB Transport  是 control endpoint(endpoint 0)
  • ACL, 用於傳輸一般性資料具有基本的資料可靠性保證
    • UART transport 使用 0x02
    • USB transport用Bulk endpoint 傳輸
  • SCO, 用於語音資料的傳遞
    • UART transport 使用 0x03
    • USB transport用Isochronous endpoint 傳輸
  • Event, 用於BT Module 回應 Host 的控制
    • UART transport 使用 0x04
    • USB transport 則用 Interrupt endpoint
typedef  enum _HCI_PACKET_TYPE_ {
HCI_COMMAND = 0x01,
HCI_ACL = 0x02,
HCI_SCL = 0x03,
HCI_EVENT = 0x04
} HCI_PACKET_TYPE;
HCI 是採用 Little Endian, signal 採用2’s 補數表示(Refer Section 5.2, Part E, Volume 2, Core Spec.)
HCI 命令封包(Command Packet) 是由一個16bits 唯一操作碼(Opcode)開始, 操作碼由兩部份組成 分別是 OGF(OpCode Group Field, Lenght: 6bits) 與 OCF (OpCode Command Field, 10bits) OGF:0x3F (111111B)是保留給Vendor-Specific 測試使用, OGF:0x3E(111110B)則是保留給 Bluetooth Logo Test。
當OGF與OCF 都為0 時則是一個 NOP 命令,在流量控制中可能會需要使用到。
接在Opcode 後的就是命令參數總長度具有 8bits 長,每個參數有多長則依據不同的命令有所不同

HCI Command Packet Format
用C Strruce 可以這樣表示
_HCI_PACKET_ {
union
{
UINT16 code;
struct {
unsigned int ocf :10;
unsigned int ogf : 6;
} op;
}
unsigned char Size;     // parameter total length
unsgined char* body; // context of parameters
} HCI_PACKET;

OGF 目前定義了 6 個 Group

  1. 連結控制命令(Link Control Command), OGF: 0x01
  2. 連結方式命令(Link Policy Command), OGF: 0x02
  3. 控制器與基頻命令(Controller & Baseband Command), OGF: 0x03
  4. 資訊參數(Informational Parameters), OGF: 0x04
  5. 狀態參數(Status Parameters), OGF: 0x05
  6. 測試命令(Testing Command), OGF: 0x06
因此要對一個BT Module 下達進入測試模式(Enable Device Under Test Mode)的話透過 HCI 需要使用 OGF:0x06, 而OCF:0x03(Refer Section 7.6.3 Part E, Volume 2, Core Spec.)。而要離開的話則是使用 HCI_Reset (OGF:0x03, OCF:0x03, Refer Section 7.3.2 Part E, Volume 2, Core Spec. ) 。每當一個Command 下達給BT Module內的Control 後,會回應一個HCI Command Complete Event 給Host端表示完成命令,除了HCI_RESET 命令外。因為HCI_RESET是使得Controller進入重置狀態,因此當收到HCI_RESET 的 Command Complete Event 是表示Controller 正準備執行HCI_RESET 而已。
HCI Event 是BT Module 用來回應 HCI Command 的封包,基本結構如下

HCI Event Packet Format