[iOS] CoreBluetooth (2) 키워드, 코드 프로퍼티와 메서드 정리

Madeline👩🏻‍💻·2024년 5월 21일
1

iOS study

목록 보기
50/61
post-custom-banner

https://velog.io/@maddie/iOS-CoreBluetooth-1-%EA%B0%9C%EC%9A%94

저번엔 CoreBluetooth 이론적인 내용에 대해 다뤘다고 한다면, 오늘은 진짜 써야 되는 실무적인 내용과 알아야 할 키워드를 다뤄보려고 합니다!

🤖 RSSI

RSSI (Received Signal Strength Indicator)는 블루투스 통신에서 신호의 강도를 측정하는 값입니다. 일반적으로 데시벨 밀리와트(dBm) 단위로 측정되며, 음수 값으로 표시됩니다. RSSI 값은 블루투스 장치 간의 거리와 신호 품질을 추정하는 데 유용합니다. 값이 0에 가까울수록 신호가 강하고, 값이 더 작아질수록 신호가 약합니다.

앱 개발에서 RSSI 값을 활용할 수 있는 몇 가지 방법은 다음과 같습니다:

1. 거리 추정

RSSI 값을 이용하여 두 블루투스 장치 간의 거리를 추정할 수 있습니다. 이는 주로 실내 위치 추적 시스템에서 많이 사용됩니다. 다만, RSSI 값은 주변 환경(벽, 장애물 등)에 영향을 받기 때문에, 정확한 거리 측정을 위해 보정이 필요합니다.

2. 근접 감지

특정 범위 내에 있는 장치를 감지하고, 그에 따라 동작을 수행할 수 있습니다. 예를 들어, 특정 범위 내에 사용자가 들어오면 자동으로 문을 여는 스마트 도어락 같은 애플리케이션에서 사용할 수 있습니다.

3. 연결 품질 모니터링

블루투스 연결의 신호 강도를 모니터링하여 연결 품질이 나빠질 경우 사용자에게 경고를 보내거나, 연결을 유지하기 위한 조치를 취할 수 있습니다.

4. 신호 강도 기반 기능 조정

앱에서 장치 간의 거리나 신호 강도에 따라 기능을 조정할 수 있습니다. 예를 들어, 무선 오디오 장치는 신호 강도가 약해지면 자동으로 볼륨을 낮추거나, 데이터 전송 속도를 조절할 수 있습니다.

🤖 mtu

MTU (Maximum Transmission Unit)는 네트워크 통신에서 한 번에 전송할 수 있는 최대 패킷 크기를 나타내는 용어입니다. MTU는 바이트 단위로 측정되며, 전송되는 데이터의 최대 크기를 결정합니다. 블루투스에서도 MTU 설정이 중요한 역할을 합니다.

기본적으로 BLE에서 초기 MTU 값은 23 바이트로 설정되어 있습니다. 이는 프로토콜 오버헤드(ATT, L2CAP 헤더 등)를 제외한 20 바이트의 데이터 페이로드를 의미합니다.

func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
	peripheral.delegate = self
	peripheral.discoverServices(nil)
}
  • 블루투스에서 MTU의 역할 블루투스에서 MTU는 특히 BLE (Bluetooth Low Energy) 통신에서 중요한 요소입니다. BLE는 저전력 통신을 목표로 하며, 데이터 패킷 크기를 최적화하여 에너지 효율성을 높입니다.
    1. 데이터 전송 효율성 향상:
      MTU 크기를 최적화하면 데이터를 더 큰 청크로 전송할 수 있어, 전송 오버헤드가 줄어들고 전송 효율성이 향상됩니다.
    2. 애플리케이션 성능 개선:
      적절한 MTU 크기를 설정하면 데이터 전송 속도가 빨라지고, 응답 시간이 줄어들어 애플리케이션의 성능이 개선됩니다.
    3. 호환성 문제 해결:
      MTU 크기는 양쪽 장치에서 협상되어 설정되므로, 양쪽 장치가 지원하는 최대 MTU 크기를 고려해야 합니다. 서로 다른 MTU 크기를 지원하는 장치 간의 호환성 문제를 해결할 수 있습니다.

🍉 업데이트 내용 (샤라웃 투 머스크)
iOS에서는 MTU 크기를 직접 요청하거나 설정할 수 있는 공개 API가 없습니다. iOS는 자동으로 MTU 크기를 협상하며, 개발자가 이를 직접 제어할 수 없습니다.

iOS에서 MTU와 관련하여 할 수 있는 것은 다음과 같습니다:

  • 현재 MTU 크기 확인:
    maximumWriteValueLength(for:) 메서드를 사용하여 현재의 MTU 크기를 간접적으로 알 수 있습니다.
let withResponseMTU = peripheral.maximumWriteValueLength(for: .withResponse)
let withoutResponseMTU = peripheral.maximumWriteValueLength(for: .withoutResponse)

print("MTU with response: \(withResponseMTU)")
print("MTU without response: \(withoutResponseMTU)")
  • MTU 변경 감지:
    MTU가 변경되면 peripheralDidUpdateMTU(_:) delegate 메서드가 호출됩니다.
    func peripheral(_ peripheral: CBPeripheral, didUpdateMTU mtu: Int, error: Error?) {
        if let error = error {
            print("MTU 업데이트 실패: \(error.localizedDescription)")
        } else {
            print("새로운 MTU 크기: \(mtu)")
        }
    }

iOS에서는 시스템이 자동으로 최적의 MTU 크기를 협상하므로, 대부분의 경우 개발자가 이를 직접 관리할 필요가 없습니다.

🤖 응답 없이 쓰기 (Write Without Response)

블루투스 저에너지(BLE)에서는 데이터를 쓰는 두 가지 주요 방법이 있습니다:

  1. Write with Response (응답 쓰기): 데이터가 수신되면 수신 장치가 송신 장치에 확인 응답을 보내는 방식입니다. 이 방법은 신뢰성이 높지만, 응답을 주고받는 데 시간이 더 소요됩니다.
  2. Write without Response (응답 없이 쓰기): 데이터가 수신되더라도 수신 장치가 송신 장치에 확인 응답을 보내지 않는 방식입니다. 이 방법은 응답을 기다릴 필요가 없어 더 빠르지만, 신뢰성이 떨어질 수 있습니다.

🤖 MAC 주소

MAC 주소(Media Access Control Address)는 네트워크 인터페이스 카드(NIC)에 할당된 고유 식별자입니다. 이 주소는 네트워크 장치 간의 통신을 가능하게 하며, 주로 로컬 네트워크 내에서 사용됩니다. MAC 주소는 48비트(6바이트) 길이의 식별자로, 일반적으로 16진수 형식으로 표기됩니다. 예를 들어, 00:1A:2B:3C:4D:5E와 같은 형태입니다.

let macAddress = peripheral.identifier.uuid
// (244, 101, 114, 136, 206, 144, 223, 15, 177, 162, 117, 116, 211, 116, 53, 99)
let macAddress = peripheral.identifier.uuidString // identifier와 동일

MAC 주소의 구조

MAC 주소는 두 부분으로 나뉩니다:

  1. OUI(Organizationally Unique Identifier): 첫 24비트(3바이트)는 제조업체를 식별합니다. IEEE가 제조업체에 할당합니다.
  2. NIC Specific: 나머지 24비트(3바이트)는 각 제조업체가 관리하는 고유 식별자입니다.

블루투스와 관련하여 iPhone의 MAC 주소는 다음과 같은 역할을 합니다:

  1. 블루투스 통신 식별자: iPhone의 블루투스 기능을 사용하여 다른 장치와 통신할 때, iPhone의 MAC 주소가 사용됩니다. 다른 장치는 iPhone을 식별하고 연결을 설정하기 위해 이 MAC 주소를 사용합니다.
  2. 주변 장치 인식: iPhone은 블루투스를 사용하여 다른 주변 장치를 감지할 수 있습니다. 이때 iPhone은 주변 장치의 MAC 주소를 스캔하여 인식합니다.
  3. 블루투스 연결: 다른 블루투스 장치와의 연결을 설정할 때, iPhone의 MAC 주소는 블루투스 통신에서 사용됩니다. 다른 장치와 iPhone을 식별하고 안전한 연결을 설정하는 데 사용됩니다.

블루투스 기능을 개발할 때는 iOS의 CoreBluetooth 프레임워크를 사용하여 블루투스 통신을 관리하게 됩니다. CoreBluetooth를 사용하면 iPhone의 블루투스 기능을 제어하고 다른 블루투스 장치와의 통신을 설정할 수 있습니다. iOS에서는 보안 및 개인 정보 보호를 고려하여 MAC 주소를 직접 공개하지 않으며, 대신 CoreBluetooth를 통해 블루투스 통신을 수행합니다.

identifier는 iOS 기기가 주변 장치를 식별하기 위해 사용하는 고유한 값이며, 로봇의 MAC 주소와 직접적으로 관련이 없습니다.

iOS 기기의 MAC 주소는 보안 및 개인 정보 보호를 고려하여 직접적으로 접근할 수 없습니다. iOS에서는 MAC 주소를 숨기고 대신 앱이 블루투스를 통해 주변 장치와 통신할 수 있도록 CBPeripheral 객체를 제공합니다. 따라서 iOS 앱에서는 자체적으로 iOS 기기의 MAC 주소를 가져올 수 없습니다.

대신 iOS 앱은 기기의 식별자인 UUID (Universally Unique Identifier)를 사용할 수 있습니다.

ex) iOS mac 주소: 22AB382D-...-...-BF28-D55C066FD854

🤖 CBPeripheral 객체의 주요 속성 및 메서드

  1. name: 주변 장치의 이름을 나타냅니다. 이를 통해 특정 장치를 식별할 수 있습니다.
  2. identifier: 주변 장치의 UUID(고유 식별자)를 나타냅니다. 이 값은 iOS 기기마다 고유하며, 블루투스 장치마다 다릅니다.
  3. services: 주변 장치에서 제공하는 서비스 목록을 나타냅니다. 이를 통해 앱은 주변 장치에서 지원하는 기능을 확인할 수 있습니다.
  4. connect(_:options:): 주변 장치와 연결을 설정합니다.
  5. discoverServices(_:): 주변 장치의 서비스를 검색합니다.
  6. discoverCharacteristics(_:, for:): 주변 장치의 특성을 검색합니다.
  7. readValue(for:): 주변 장치의 특성 값을 읽습니다.
  8. writeValue(_:for: type:): 주변 장치의 특성에 값을 씁니다.
  9. setNotifyValue(_:for:): 주변 장치의 특성에 대한 알림을 활성화 또는 비활성화합니다.

Characteristics’ Property

Bluetooth Low Energy (BLE)에서 CBCharacteristicProperties는 특정 특성의 동작을 나타내는 속성들의 비트 마스크입니다. 여기에는 다양한 속성이 있으며, 각 속성은 특정 기능을 활성화하거나 제한합니다. 주요 속성들에 대해 설명하겠습니다:

  1. Broadcast (broadcast):
    • 특성이 연결된 모든 장치에 브로드캐스트될 수 있음을 나타냅니다.
  2. Read (read):
    • 특성의 값을 읽을 수 있음을 나타냅니다. 앱에서 이 속성이 설정된 특성에 대해 읽기 요청을 보낼 수 있습니다.
  3. Write Without Response (writeWithoutResponse):
    • 특성에 값을 쓸 수 있지만, 쓰기 작업에 대한 응답을 받지 않음을 나타냅니다. 빠른 데이터 전송에 유용합니다.
  4. Write (write):
    • 특성에 값을 쓸 수 있음을 나타냅니다. 쓰기 작업이 완료된 후 응답을 받습니다. 일반적으로 데이터의 무결성이 중요할 때 사용됩니다.
  5. Notify (notify):
    • 특성이 변경될 때 연결된 장치에 알림을 보낼 수 있음을 나타냅니다. 서버는 클라이언트에게 값이 변경될 때마다 알림을 보냅니다.
  6. Indicate (indicate):
    • 특성이 변경될 때 연결된 장치에 인디케이션을 보낼 수 있음을 나타냅니다. 알림과 비슷하지만, 클라이언트가 인디케이션을 수신했음을 확인해야 합니다.
  7. Authenticated Signed Writes (authenticatedSignedWrites):
    • 인증된 서명이 포함된 쓰기 작업을 지원합니다. 데이터 무결성을 보장하고 서명이 유효한지 확인합니다.
  8. Extended Properties (extendedProperties):
    • 특성이 추가적인 특성을 가지고 있음을 나타냅니다. 예를 들어, 특성의 신뢰성을 나타내는 속성 등이 포함될 수 있습니다.
  9. Notify Encryption Required (notifyEncryptionRequired):
    • 특성의 알림을 받기 위해 암호화된 연결이 필요함을 나타냅니다.
  10. Indicate Encryption Required (indicateEncryptionRequired):
  • 특성의 인디케이션을 받기 위해 암호화된 연결이 필요함을 나타냅니다.

이 속성들은 비트 마스크로 조합될 수 있습니다. 예를 들어, 특성이 읽기 및 알림 속성을 모두 가질 수 있습니다. 이러한 속성을 사용하여 특성과 상호작용할 수 있는 방법을 결정합니다.

사용 예시

특정 특성의 속성을 확인하고, 해당 속성에 따라 동작을 정의하는 코드 예시입니다:

func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
    guard let characteristics = service.characteristics else {
        return
    }

    for characteristic in characteristics {
        print("Discovered Characteristic: \\(characteristic)")

        if characteristic.properties.contains(.broadcast) {
            print("This characteristic supports broadcast")
        }
        if characteristic.properties.contains(.read) {
            print("This characteristic supports read")
            peripheral.readValue(for: characteristic)
        }
        if characteristic.properties.contains(.writeWithoutResponse) {
            print("This characteristic supports write without response")
        }
        if characteristic.properties.contains(.write) {
            print("This characteristic supports write")
        }
        if characteristic.properties.contains(.notify) {
            print("This characteristic supports notify")
            peripheral.setNotifyValue(true, for: characteristic)
        }
        if characteristic.properties.contains(.indicate) {
            print("This characteristic supports indicate")
        }
        if characteristic.properties.contains(.authenticatedSignedWrites) {
            print("This characteristic supports authenticated signed writes")
        }
        if characteristic.properties.contains(.extendedProperties) {
            print("This characteristic has extended properties")
        }
        if characteristic.properties.contains(.notifyEncryptionRequired) {
            print("This characteristic requires encryption for notify")
        }
        if characteristic.properties.contains(.indicateEncryptionRequired) {
            print("This characteristic requires encryption for indicate")
        }
    }
}

위의 코드는 특성의 속성을 검사하고, 각 속성에 대해 적절한 동작을 수행합니다. 예를 들어, 특성이 notify 속성을 가지고 있다면, setNotifyValue(true, for: characteristic)을 호출하여 알림을 활성화합니다.

profile
🍎 Apple Developer Academy@POSTECH 2기, 🍀 SeSAC iOS 4기
post-custom-banner

0개의 댓글