Bluetooth Low Energy(BLE)デバイスには、ネットワーク内で個体を一意に識別するためのMACアドレスが割り当てられています。Nordic SemiconductorのSoCでは、製造時にFICR(Factory Information Configuration Registers)領域に初期MACアドレスが書き込まれており、デフォルトではこの値がプロトコルスタックによって利用されます。本記事では、nRF52 SDKおよびNCS(Nordic Connect SDK)環境におけるMACアドレスの読み出し、上書き設定、およびBluetooth仕様上のアドレスビット調整方法について解説します。
nRF52 SDK 環境での操作
Nordic SoftDevice APIを介してMACアドレスを操作する場合、GAPレイヤーのソFTDevice API関数を利用します。
現在のアドレス取得
void retrieve_device_mac(void)
{
ble_gap_addr_t gap_addr;
uint32_t status = sd_ble_gap_addr_get(&gap_addr);
if (status != NRF_SUCCESS) {
NRF_LOG_ERROR("アドレス取得失敗 (code: 0x%x)", status);
return;
}
char buffer[18];
snprintf(buffer, sizeof(buffer), "%02X:%02X:%02X:%02X:%02X:%02X",
gap_addr.addr[5], gap_addr.addr[4], gap_addr.addr[3],
gap_addr.addr[2], gap_addr.addr[1], gap_addr.addr[0]);
NRF_LOG_INFO("現在のBLEアドレス: %s", buffer);
}
カスタムアドレス設定
void configure_custom_mac(void)
{
ble_gap_addr_t custom_addr = {
.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC,
.addr = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}
};
uint32_t status = sd_ble_gap_addr_set(&custom_addr);
if (status != NRF_SUCCESS) {
NRF_LOG_ERROR("アドレス設定失敗 (code: 0x%x)", status);
} else {
NRF_LOG_INFO("カスタムMACアドレスが反映されました");
}
}
NCS(Zephyrベース)環境での操作
NCS 2.9.0以降の環境では、Zephyr Bluetooth APIとハードウェアレジスタ直接アクセスを組み合わせる方法が一般的です。ここではnRF54L15 DKを前提とした実装を示します。
FICRからのアドレス読み出し
static void read_ficr_mac(uint8_t *out_mac)
{
uint32_t val_lo = NRF_FICR->DEVICEADDR[0];
uint32_t val_hi = NRF_FICR->DEVICEADDR[1];
const uint8_t *lo_bytes = (const uint8_t *)&val_lo;
const uint8_t *hi_bytes = (const uint8_t *)&val_hi;
out_mac[0] = hi_bytes[1];
out_mac[1] = hi_bytes[0];
out_mac[2] = lo_bytes[3];
out_mac[3] = lo_bytes[2];
out_mac[4] = lo_bytes[1];
out_mac[5] = lo_bytes[0];
}
// bt_enable() 完了後の呼び出し例
uint8_t device_mac[6];
read_ficr_mac(device_mac);
LOG_INF("FICRから読み取ったMAC: %02X:%02X:%02X:%02X:%02X:%02X",
device_mac[0], device_mac[1], device_mac[2],
device_mac[3], device_mac[4], device_mac[5]);
Zephyr APIによるアドレス上書き
static int apply_dynamic_identity(void)
{
bt_addr_le_t target_addr;
int rc = bt_addr_le_from_str("11:22:33:44:55:66", "random", &target_addr);
if (rc != 0) {
LOG_ERR("文字列変換エラー (err: %d)", rc);
return rc;
}
rc = bt_id_create(&target_addr, NULL);
if (rc < 0) {
LOG_ERR("アイデンティティ作成失敗 (err: %d)", rc);
return rc;
}
LOG_INF("新しいBLE IDが登録されました");
return 0;
}
// bt_enable() コールバック完了後に実行してください
Bluetooth仕様におけるアドレスビットの調整
レジスタから直接取得した生データ(例:4C:BD:FF:FC:79:1B)と実際に空中でブロードキャストされるアドレス(例:CC:BD:FF:FC:79:1B)が異なる場合があります。これはBluetooth Core Specification Vol 6 Part B §1.3.2.1で規定されている通り、デバイスアドレスの最上位2ビット(MSB)は常に1(0b11)に設定される必要があるためです。プロトコルスタックは自動的に0x4C(01001100)を0xCC(11001100)へビットマスク処理し、仕様準拠のアドレスへ変換して送信します。
プライバシー保護のための動的MACアドレス
特定の端末に対してアドレスを常時公開したくない場合、Dynamic Resolvable Private Address機能の活用が有効です。この方式では、Identity Resolving Key(IRK)と乱数を用いて定期的にMACアドレスを算出します。解析側は同じIRKを保持している必要があります。
NCS/Zephyr環境でこの機能を有効化するには、prj.confへ以下の設定を追記するだけで有効になります。
CONFIG_BT_PRIVACY=y
上記を有効にしbt_id_createを呼び出すと、スタックが自動でIRKに基づいた動的アドレス生成を開始します。実際のペアリングデバイスにおけるアドレス解決処理については、プロファイル実装に応じて追加設定が必要となります。