[BLE] GATT란? - Services & Characteristics
GATT(Generic Attribute Profile)란?
GATT(Generic Attribute Profile)
는 BLE 연결을 통해 프로필 및 데이터를 주고받기 위한 방법을 정의합니다. 로우 레벨의 상호작용을 정의하는 GAP와는 달리 GATT는 실제 데이터 전송 절차 및 데이터 형식만을 다룹니다. 또한, 다른 업체에서 제작한 서로 다른 디바이스 간의 상호 운용성을 보장하는 SIG defined GATT-based profiles을 제공합니다. 올바르게 작동하려면 모든 표준 BLE Profile은 GATT을 기반으로 해야 하며 GATT를 준수해야 합니다. 따라서, 어플리케이션과 사용자는 데이터를 전송하기 위해 데이터의 타입을 정할 때 GATT 규칙에 따라 전송해야 합니다. GATT는 ATT(Attribute Protocol)를 전송 프로토콜로 사용하여 디바이스 간에 데이터를 교환합니다. 데이터는 Service라는 섹션으로 계층적으로 구성되며, 하위 섹션에는 사용자 데이터와 관련된 Characteristic로 구성되어 있습니다.
Roles
Bluetooth 사양의 다른 프로토콜 또는 프로필과 마찬가지로 GATT는 디바이스가 상호작용할 때의 역할(Role)
을 정의하는 것으로 시작합니다. GATT의 Role은 GAP의 Role과는 완전히 독립적이지만 서로 상호 호환됩니다. 즉, GAP Central과 GAP Peripheral이 모두 GATT Client 또는 GATT Server 중 하나의 역할을 하거나 두 역할 모두를 할 수도 있습니다.
GATT Client
GATT Client
는 ATT(Attribute Protocol)의 클라이언트에 해당하며 서버에 요청을 보내고 서버로부터 응답을 받습니다. GATT Client는 서버의 특성에 대해 미리 알지 못하므로 먼저 Service 검색을 수행하여 해당 특성의 존재 여부를 조회해야 합니다. 서비스 검색을 완료한 후에는 서버에서 데이터를 받아 올 수 있을 뿐만 아니라 서버에 있는 특성에 대해 Read/Write를 할 수 있습니다.
GATT Server
GATT Server
는 ATT(Attribute Protocol)의 서버에 해당하며 클라이언트로부터 요청을 수신하고 응답을 보냅니다. 모든 BLE 디바이스는 오류를 응답하더라도 클라이언트의 요청에 응답할 수 있는 최소한의 기본 GATT 서버가 존재해야 합니다.
UUIDs
UUID(Universally Unique Identifier)
는 유니크함을 보장해주는 128-bit(16-byte) 숫자입니다. UUID는 Bluetooth 이외의 많은 프로토콜 혹은 어플리케이션에서 사용되며 형식 및 생성에 대한 내용은 ITU-T Rec. X.667(ISO/IEC 9834-8:2005)에 명시되어 있습니다. UUID는 효율성을 위해 추가하는 링크 레이어의 Data Payload는 27-byte를 차지하기 때문에 BLE 사양에서는 16-bit와 32-bit 두 가지 형식의 UUID를 사용합니다. 이러한 단축된(shortened) 형식은 Bluetooth 사양에 정의되어 있는 Bluetooth SIG에서 정의한 표준 Bluetooth UUID에서만 사용할 수 있습니다.
전체 128-bit의 UUID를 단축된 버전으로 재구성하려면 맨 앞에 0으로 시작하는 16-bit 혹은 32-bit의 짧은 값을 Bluetooth 기본 UUID에 추가합니다. (e.g. xxxxxxxx-0000-1000-8000-00805F9B34FB)
Bluetooth SIG는 정의한 모든 Types, Services, Profiles에 대해 shortened UUID를 제공합니다. 하지만, Bluetooth SIG가 제공하는 기능만으로는 어플리케이션이 요구 사항을 충족하지 못하거나 프로필 사양에서 고려하지 않은 새로운 기능을 구현하려는 경우 ITU의 UUID 생성 페이지에서 새롭게 생성할 수 있습니다.
http://www.itu.int/en/ITU-T/asn1/Pages/UUID/uuids.aspx
Bluetooth의 기본 UUID에서 파생되지 않은 UUID에는 단축하여 사용할 수 없습니다. 이러한 경우에는 항상 전체 128-bit의 UUID 값을 사용해야 합니다.
Attribute
특성(Attribute)
은 GATT에서 정의한 가장 작은 데이터 Entity입니다. 개념적으로 특성은 항상 서버에 있으며 클라이언트가 액세스 합니다. 서버 내에 포함된 다양한 특성은 사용자 데이터를 포함하는 주소 지정 가능한(addressable) 정보입니다. 이 사양은 개념적으로만 속성을 정의하며 속성에는 시간이 지남에도 변하지 않는 속성도 존재하지만 시간에 따라 변경되는 데이터도 존재하기 때문에 ATT 및 GATT의 구현이 저장 형식이나 특정 메커니즘을 사용하도록 강제하지는 않습니다.
Attribute의 구조는 아래와 같습니다.
예를 들어 Heart Rate Profile이라는 주제로 어플리케이션을 만든다고 하면, 아래와 같은 Attribute들을 만들 수 있습니다.
Attribute Handle
Attribute Handle
은 특정 GATT 서버의 각 속성에 대한 변하지 않는 16-bit identifier입니다. Attribute는 각 주소를 지정할 수 있으며(Addressable) 트랜잭션 혹은 장치 연결 이후에도 변경되지 않도록 보장합니다. GATT 서버에서 사용할 수 있는 Handle의 양은 0x0000부터 0xFFFF까지 65535개이지만 실제로는 서버에 존재하는 Attribute의 숫자는 수십 개에 불과합니다.
GATT 서버 내에서 핸들 값이 증가함에 따라 클라이언트가 액세스 할 수 있는 Attribute 시퀀스가 결정됩니다. Handle은 서버에서 순서대로 증가하지만 연속적으로 존재하는 것이 아니라 간격이 허용되므로 클라이언트는 다음 Attribute의 위치를 추측하기 위해 연속 시퀀스에만 의존할 수 없습니다. 그러므로, 클라이언트는 Service and Characteristics Discovery 기능을 사용하여 Attribute의 핸들을 가져와야 합니다.
Attribute Type
Attribute Type
은 Attribute의 유형을 나타내는 UUID이며 16, 32, 128-bit일 수 있습니다. Attribute Type은 Attribute의 데이터 타입을 결정하고 결정된 타입을 이용해서 해당 Type의 Attribute만 검색할 수도 있습니다. Attibute Type은 모두 UUID이긴 해도 여러 타입의 UUID가 존재합니다. UUID는 Service 혹은 Characteristics UUID와 같은 GATT 서버의 특성 계층 구조의 레이아웃을 결정하는 표준 UUID일 수도 있고, 심박수 측정 또는 온도와 같이 속성에 포함된 데이터의 종류를 지정하는 Profile UUID, 공급업체에서 할당하고 구현에 따라 달라지는 Vendor-Specified UUID일 수도 있습니다.
정리하자면 아래와 같은 UUID가 존재할 수 있습니다.
- Service UUID
- Characteristic UUID
- Profile UUID
- Vendor-Specified UUID
Attribute Value
Attribute Value
는 Attribute의 실제 데이터 내용을 말합니다. 데이터 형식에는 제한이 없지만 최대 길이는 사양에 따라 512 bytes로 제한됩니다. Attribute Type에 따라서 Attribute Value는 특성 자체만 있을 수도 있고 사용자가 정의한 추가 정보를 보유할 수도 있습니다. 아주 일부분만 클라이언트가 Read와 Write 모두 액세스 할 수 있는 Attribute이고 나머지 대부분은 클라이언트가 직접 수정하거나 액세스 할 수 없습니다.
예를 들면, 가상의 GATT 서버에 포함된 Attribute 속성은 아래와 같습니다.
Handle | Type | Permissions | Value | Value length |
0x0201 | UUID(16-bit) | Read only, no security | 0x180A | 2 |
0x0202 | UUID(16-bit) | Read only, no security | 0x2A29 | 2 |
0x0215 | UUID(16-bit) | Read/write, authorization required | a readable UTF-8 string | 23 |
0x030C | UUID(128-bit) | Write only, no security | {0xFF, 0xFF, 0x00, 0x00} | 4 |
0x030D | UUID(128-bit) | Read/write, authenticated encryption required | 36, 43 | 8 |
0x031A | UUID(128-bit) | Read only, no security | 0x1801 | 2 |
위의 가상의 GATT 서버에 포함된 속성은 실제 GATT 서버와는 다른 6개의 속성만 호스팅 하고 있고 위에서 언급했듯이 Attribute Handle이 연속될 필요는 없지만 점점 증가하는 구조를 가지고 있습니다.
0x201, 0x0202, 0x031A의 Attribute Value는 16-bit 정수가 포함되어 있고, 0x0215의 Attribute Value는 UTF-8 문자열이 포함되어 있으며, 0x030C는 4바이트 버퍼가 포함되어 있고, 0x030D는 IEEE-754 64비트 부동 소수점 숫자가 포함되어 있습니다.
Attribute Permission
Attribute Permission
은 각 특성에서 실행할 수 있는 속성 권한과 보안 요구 사항을 포함하는 메타데이터입니다.
GATT(ATT) Access Permissions
GATT Access Permissions
는 클라이언트가 특성에 읽거나 쓸 수 있는지 여부를 결정합니다.
아래의 액세스 권한 중 하나가 있을 수 있습니다.
None
-> 이 속성은 클라이언트에게 읽기, 쓰기 권한이 주어지지 않습니다.
Readable
-> 이 속성은 클라이언트가 읽을 수 있는 권한이 주어집니다.
Writable
-> 이 속성은 클라이언트가 쓸 수 있는 권한이 주어집니다.
Readable and writeable
-> 이 속성은 클라이언트가 읽고 쓸 수 있는 권한이 주어집니다.
Encryption
Encryption
은 클라이언트에서 Attribute에 액세스 할 때 특정 level의 암호화가 필요한지 여부를 결정합니다.
No Encryption required(Security Mode 1, Level 1)
-> 이 속성은 암호화되지 않은 일반 텍스트 연결에서 액세스 할 수 있습니다.
Unauthenticated encryption required(Security Mode 1, Level 2)
-> 이 속성은 Attribute에 액세스 할 때 연결을 암호화해야 하지만 암호화 키를 인증할 필요는 없습니다.
Authenticated encryption required(Security Mode 1, Level 3)
-> 이 속성은 Attribute에 액세스 할 때 인증된 키로 연결을 암호화해야 합니다.
Authorization
Authorization
은 클라이언트가 Attribute에 액세스 할 때 사용자 권한이 필요한지 여부를 결정합니다.
No authorization required
-> 이 속성은 Attribute에 액세스할 때 authorization이 필요하지 않습니다.
Authorization required
-> 이 속성은 Attribute에 액세스할 때 authorization이 필요합니다.
Attribute and Data Hierarchy
GATT는 재사용 가능하고 실용적인 방식으로 속성을 만들기 위해 계층 구조로 구성하였습니다. 이것을 GATT Server Profile
이라고 합니다.
GATT 서버의 속성은 Service로 그룹화되어있고, 각 Service는 0개 이상의 Characteristics를 포함할 수 있습니다. 그리고 각 Characteristics는 0개 이상의 Descriptor를 포함할 수 있습니다. 이 계층 구조는 GATT 호환성을 가지는 모든 디바이스에 대해 엄격하게 적용되며 모든 특성이 이 세 가지 중 하나에 포함됨을 의미합니다. GATT 계층 구조에 있는 대부분의 타입의 경우 정의(definition)와 선언(declaration)을 구분해야 합니다. 선언은 정의 내에서 항상 첫 번째(handle 순서가 증가)에 배치되고 뒤에 있는 데이터는 단일 특성을 가지는 메타데이터입니다.
Service
GATT Service
는 GATT 서버에서 설정된 속성 정보 집합을 말하며 하나의 공통 섹션에서 개념적으로 관련된 속성을 그룹화시키는 역할을 합니다. 특정 기능을 수행하기 위한 데이터 및 관련 동작의 모음을 서비스 정의(Service Definition)라고 하며 각 속성은 서비스의 시작을 나타내는 서비스 선언(Service declaration이며 단일 속성을 뜻함)으로 시작합니다.
서비스는 Public 혹은 Private으로 분류됩니다.
Public
-> Bluetooth SIG(16비트 UUID)에 의해 정의된 서비스. (16-bit UUID)
Private
-> 공급 업체에 의해 정의된 서비스. (128-bit UUID)
Service Declaration Attribute
서비스에 대한 Attribute를 예로 들면 아래 표와 같이 정의할 수 있습니다.
Handle | Type | Permissions | Value | Value length |
0xNNNN | UUID primary service (0x2800) or UUID secondary service (0x2801) |
Read Only | Service UUID | 2, 4, or 16 bytes |
UUID primary service
와 UUID secondary service
는 UUID가 16비트 이므로 블루투스 사양에 정의되어 있는 Bluetooth SIG에서 할당한 UUID라는 것을 알 수 있습니다. 여기서 primary service와 secondary service의 차이점은 primary service는 GATT 서버에서 노출하는 표준 기능을 포함하는 서비스입니다. 반면에, secondary service는 다른 기본 서비스에만 포함되어 있으며 해당 서비스 자체로는 의미가 없는 수식어로만 의미가 있으며 실제로 secondary service는 거의 사용되지 않습니다.
서비스의 Attribute에는 UUID가 포함되며 이 서비스 선언이 실제 서비스의 UUID에 해당합니다. 이렇게 항상 서비스의 첫 번째 Attribue가 서비스 선언 되어야만 뒤의 서비스 선언인 characteristics 혹은 descriptor 등이 정의될 있습니다.
Include Declaration attribute
개념적으로 GATT 서비스는 GATT 서버 내에서 여러 번 인스턴스화될 수 있기 때문에 객체 지향 언어에서의 클래스로 생각할 수 있습니다. 또한, 서비스 정의 내에서(즉, 서비스 내부에서) include 정의를 사용해서 다른 서비스에 대한 참조를 추가할 수 있습니다. 이렇게 다른 서비스에서 참조하는 경우 GATT 서버에서 데이터의 중복을 방지하며 메모리를 절약할 수 있습니다.
예를 들면, 아래의 표는 Include 선언 특성과 필드들을 나타냅니다.
Handle | Type | Permissions | Value | Value length |
0xNNNN | UUID include (0x2802) |
Read only | Included service handle, end group handle, Included Service UUID | 6, 8, or 20 bytes |
여기서, UUID include 0x2802는 Include 선언에서만 사용되는 특수 SIG 할당 UUID이며, 이 경우 value 필드에는 Include 서비스의 시작 및 종료 handle과 해당 서비스의 UUID가 포함됩니다.
Characteristic
Charactristic은 Service에 포함되는 필드로 실제 사용자 데이터를 말합니다. 여기에는 두 가지 특성이 포함됩니다.
Characteristic Declaration Attribute
-> 값 속성의 메타데이터.
Characteristic Value Attribute
-> 값 필드의 사용자 데이터를 포함하는 전체 특성.
예를 들면, 아래의 표는 Characteristic의 두 가지 특성의 구조를 보여줍니다.
모든 GATT Characteristic은 항상 서비스의 일부 이므로 항상 하나로 묶여 있습니다.
Attribute Handle | Attribute Type | Attribute Permissions | Attribute Value | Value length |
0xNNNN | UUID characteristic (0x2803) |
Read only | Properties, value handle (0xMMMM), characteristic UUID | 5, 7, or 19 bytes |
0xMMMM | Characteristic UUID | Any | Actual value | Variable |
Characteristics Declaration Attribute
Characteristic Declaration Attribute
의 Attribute Type UUID 0x2803는 characteristic의 시작을 나타내는 사용되는 표준화된 UUID입니다. 다른 모든 선언(service 및 include)과 마찬가지로 이 특성은 읽을 수만 있고(Read-only) 수정은 불가능하기 때문에 Permission은 읽기 전용 권한이 존재합니다.
Characteristic Value Attribute
Characteristic Value Attribute
는 Properties, Value handle, UUID로 항목이 나누어집니다.
아래의 표는 characteristic Declartion Attriubte의 값의 항목들입니다.
Name | Length in bytes | Description |
Characteristic Properties | 1 | A bitfield listing the permitted operations on this characteristic |
Characteristic Value | 2 | The handle of the attribute containing the characteristic value |
Characteristic UUID | 2, 4, or 16 | The UUID for this particular characteristic |
위의 3가지 항목들을 하나씩 정리하겠습니다.
Characteristic Properties -> Characteristic Properties
는 8-bit field로 구성되어 있습니다.
클라이언트는 위 속성을 읽어 수행할 수 있는 작업을 찾을 수 있습니다. 이 중에서, Notify/Indicate는 GATT server가 먼저 Characterisctic의 변화를 알려주는 기능이며 server-initiated updates라고 부릅니다. 클라이언트가 Characteristic의 설정 값을 가지고 있는 Descriptor를 조작해서 기능을 Notify/Indicate 기능을 On 시킬 수 있으며, 해당 Descriptor를 CCCD(Client Characteristic Configuration Descriptor)라고 부릅니다.
Characteristic Value Handle
-> 핸들의 2 바이트에는 characteristic의 실제 값을 포함하는 attirubte handle 값이 포함되어 있습니다. 이 핸들은 마찬가지로 연속적이지 않습니다.(ex. 0xNNNN +1)
Characteristic UUID
-> Characteristic의 UUID는 표준 Profile에 포함된 SIG-apporved GATT UUID와 128-bit의 공급업체별 UUID일 수 있습니다.
Characteristic Descriptor
GATT Characterstic Descriptor
는 클라이언트에게 메타데이터(characteristic 및 해당 값에 대한 추가정보)를 제공하는 데 사용됩니다. Descriptor는 Characteristic 정의 내부에 characteristic value attirbute 뒤에 배치되어 항상 단일 속성으로 구성되어 있습니다.
GATT에서 정의한 일반적인 Descriptor Attribute 유형은 아래와 같습니다.
Extended Properties Descriptor
-> Characteristics Properties 표의 맨 마지막에 존재하는 2-bit의 추가적인 property bits를 포함하고 있는 Descriptor입니다.
Characteristic User Description Descriptor
-> 이름에서 알 수 있듯이 이 Descriptor가 배치되어 있는 characteristic에 대한 사용자가 읽을 수 있는 설명이 포함되어 있는 UTF-8 문자열을 포함하고 있는 Descriptor입니다.(ex. 거실의 온도)
Client Characteristic Configuration Descriptor (CCCD)
-> 가장 중요하며 일반적으로 사용되는 Descriptor입니다. Descriptor를 포함하고 있는 Characteristic의 server-initiated updates에 대한 enabling/disabling하는 switch 역할을 하는 Descrptior입니다. CCCD는 2-bit 필드에 불과하며 한 비트는 Notification, 나머지 한 비트는 Indication에 해당합니다. 클라이언트는 Notification/Indication을 활성화시키고 싶으면 ATT 패킷을 이용하여 해당 비트를 1로 설정하기만 하면 됩니다.
Notification과 Indication의 차이점은 아래와 같습니다.
Notification
: 데이터를 수신하면 Client는 Server에 수신에 대한 ACK를 전송합니다.Indication
: 데이터를 수신해도 Client는 Server에 수신에 대한 ACK 신호를 전송하지 않습니다.
GATT 프로필 예시
아래 다이어그램은 GATT Heart Profile Service를 보여줍니다.
References
Kevin Townsend, Carles Cufi, "Getting Started with Bluetooth Low Energy: Tools and Techniques for Low-Power Networking", O'REILLY MEDIA (2014)