Brillo: brillo-m10-dev @ RPi 3B – Bluetooth模块

下面看一下RPi 3B的bluetooth模块

  • Raspbian系统

在Raspbian系统中,系统是通过ttyAMA0与bluetooth模块进行通信的,同时我们可以通过NOOBS_v1.9.0.zip/os/Raspbian/root.tar.xz/lib/systemd/system/hciuart.service文件知道Raspbian系统使用的BlueZ协议栈:

[Unit]
Description=Configure Bluetooth Modems connected by UART
ConditionPathIsDirectory=/proc/device-tree/soc/gpio@7e200000/bt_pins
Before=bluetooth.service
After=dev-ttyAMA0.device

[Service]
Type=forking
ExecStart=/usr/bin/hciattach /dev/ttyAMA0 bcm43xx 921600 noflow -

[Install]
WantedBy=multi-user.target

从这里我们可以知道当/proc/device-tree/soc/gpio@7e20000/bt_pins目录存在的时候会去执行/usr/bin/hciattach /dev/ttyAMA0 bcm43xx 921600 noflow -命令,执行这条命令时:

- 上传patch文件:NOOBS_v1.9.0.zip/os/Raspbian/root.tar.xz/lib/firmware/BCM43430A1.hcd

- 更改ttyAMA0的波特率为921600。

- 创建rfkill1(/sys/class/rfkill/rfkill1)

之后,我们就可以通过bluetoothctl命令对bluetooth进行操作了。

NOTE:在kernel中,会使用UART (H4) protocol (drivers/bluetooth/hci_h4.c)。

  • Brillo系统

在brillo-m10-dev系统中,与bluetooth相关的文件结构如下:

/local/brillo-m10-dev-rpi3b
+-- device
|   `-- hzak
|       `-- rpi3b
|           `-- bsp
|               `-- bluetooth
|                   +-- BCM43430A1.hcd
|                   +-- bt_rpi3b.rc
|                   +-- bt_vendor.conf
|                   `-- vnd_rpi.txt
+-- hardware
|   `-- broadcom
|       `--libbt
`-- system
    `-- bt

1. patch文件存放在device/hzak/rpi3b/bsp/bluetooth/BCM43430A1.hcd编译后会放在system/vendor/firmware/下。

2. 配置libbt-vendor的编译环境(device/hzak/rpi3b/bsp/bluetooth/vnd_rpi.txt):

BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyAMA0"
FW_PATCHFILE_LOCATION = "/vendor/firmware/"
BT_WAKE_VIA_PROC = FALSE
BT_WAKE_VIA_USERIAL_IOCTL = FALSE
LPM_IDLE_TIMEOUT_MULTIPLE = 5
BTVND_DBG = TRUE
BTHW_DBG = TRUE
VNDUSERIAL_DBG = TRUE
UPIO_DBG = TRUE
SCO_CFG_INCLUDED = FALSE
SCO_PCM_IF_CLOCK_RATE = 2
USE_CONTROLLER_BDADDR = FALSE
UART_TARGET_BAUD_RATE = 921600

- 使用串口:/dev/ttyAMA0

- patch文件放在/vendor/firmware即/system/vendor/firmware目录下

- 无唤醒控制

- 指定bluetooth初始化之后使用的串口波特率为921600

3. 修改system/bt/osi/src/alarm.c文件(再次强调):

hzak@B85RPI:/local/brillo-m10-dev-rpi3b/system/bt$ git diff
diff --git a/osi/src/alarm.c b/osi/src/alarm.c
index fa4f856..62d396c 100644
--- a/osi/src/alarm.c
+++ b/osi/src/alarm.c
@@ -96,11 +96,11 @@ struct alarm_t {
 int64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 3000;
 static const clockid_t CLOCK_ID = CLOCK_BOOTTIME;
 
-#if defined(KERNEL_MISSING_CLOCK_BOOTTIME_ALARM) && (KERNEL_MISSING_CLOCK_BOOTTIME_ALARM == TRUE)
+//#if defined(KERNEL_MISSING_CLOCK_BOOTTIME_ALARM) && (KERNEL_MISSING_CLOCK_BOOTTIME_ALARM == TRUE)
 static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME;
-#else
-static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME_ALARM;
-#endif
+//#else
+//static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME_ALARM;
+//#endif
 
 // This mutex ensures that the |alarm_set|, |alarm_cancel|, and alarm callback
 // functions execute serially and not concurrently. As a result, this mutex

4. 设置系统属性ro.rfkilldisabled=1,由于使用的是bluedroid(system/bt)协议栈,不再需要rfkill?

NOTE:

a. 由于bluetooth与WiFi模块在同一个芯片中,所以需要WiFi的固件要先加载

b. 当前bluetooth模块不支持multi-adversing,这就意味着无法将bluetooth role设为peripheral

[2016-04-06 21:46:09]

下面的代码片段使Android设备的Bluetooth模块工作在peripheral模式下:

public class BleActivity extends Activity {
    private final static String TAG = "BleActivity";

    private BluetoothGattServerCallback mCallback = new BluetoothGattServerCallback() {
        @Override
        public void onConnectionStateChange(BluetoothDevice device, int status,
                                        int newState) {
        }

        @Override
        public void onServiceAdded(int status, BluetoothGattService service) {
        }

        @Override
        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId,
                        int offset, BluetoothGattCharacteristic characteristic) {
        }

        @Override
        public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,
                                             BluetoothGattCharacteristic characteristic,
                                             boolean preparedWrite, boolean responseNeeded,
                                             int offset, byte[] value) {
        }

        @Override
        public void onDescriptorReadRequest(BluetoothDevice device, int requestId,
                                        int offset, BluetoothGattDescriptor descriptor) {
        }

        @Override
        public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
                                         BluetoothGattDescriptor descriptor,
                                         boolean preparedWrite, boolean responseNeeded,
                                         int offset,  byte[] value) {
        }

        @Override
        public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
        }
        @Override
        public void onNotificationSent(BluetoothDevice device, int status) {
        }
        @Override
        public void onMtuChanged(BluetoothDevice device, int mtu) {
        }
    };

    private BluetoothManager mBm;
    private BluetoothGattServer mServer;
    private BluetoothGattService mPrimaryService;
    private BluetoothGattCharacteristic mPrimaryChar;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBm = (BluetoothManager)getSystemService(BLUETOOTH_SERVICE);

        mPrimaryService = new BluetoothGattService(UUID.fromString(
            "0000180d-0000-1000-8000-00805f9b34fb"), BluetoothGattService.SERVICE_TYPE_PRIMARY);

        mPrimaryChar = new BluetoothGattCharacteristic(UUID.fromString(
            "00002a37-0000-1000-8000-00805f9b34fb"), BluetoothGattCharacteristic.PROPERTY_READ,
            BluetoothGattCharacteristic.PERMISSION_READ);
        mPrimaryService.addCharacteristic(mPrimaryChar);
    }

    @Override
    public void onResume() {
        super.onResume();

        mServer = mBm.openGattServer(getApplicationContext(), mCallback);
        mServer.addService(mPrimaryService);

        AdvertiseSettings.Builder builder = new AdvertiseSettings.Builder();
        builder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY);
        builder.setConnectable(true);
        builder.setTimeout(0);
        builder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);

        AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
        dataBuilder.addServiceUuid(ParcelUuid.fromString(
                "0000180d-0000-1000-8000-00805f9b34fb"));
        dataBuilder.setIncludeDeviceName(true);

        BluetoothAdapter adapter = mBm.getAdapter();
        BluetoothLeAdvertiser advertiser = adapter.getBluetoothLeAdvertiser();
        if (advertiser == null) {
            Toast.makeText(this, "Bluetooth LE advertising is not support!", Toast.LENGTH_SHORT).show();
            return;
        }

        advertiser.startAdvertising(builder.build(), dataBuilder.build(), new AdvertiseCallback() {
            @Override
            public void onStartFailure(int errCode) {
            }

            @Override
            public void onStartSuccess(AdvertiseSettings settingsInEffect) {
            }
        });
    }

    @Override
    public void onPause() {
        super.onPause();
        mServer.close();
    }
}

NOTE: 需要Android系统具有android.hardware.bluetooth_le这个feature。Nexus4 bluetooth模块不支持Bluetooth LE advertising, 执行BluetoothAdapter.getBluetoothLeAdvertiser()会返回null。

  • 相关的参考文档:
  1. https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothOverview/CoreBluetoothOverview.html#//apple_ref/doc/uid/TP40013257-CH2-SW1

《Brillo: brillo-m10-dev @ RPi 3B – Bluetooth模块》有6个想法

  1. 4. 设置系统属性ro.rfkilldisabled=1,由于使用的是bluedroid(system/bt)协议栈,不再需要rfkill?
    —>rfkill是用来控制蓝牙上下电的。
    a. 由于bluetooth与WiFi模块在同一个芯片中,所以需要WiFi的固件要先加载
    —>不需要先加载wifi固件。
    b. 当前bluetooth模块不支持multi-adverser,这就意味着无法将bluetooth role设为peripheral
    —>不支持multi-adverser也可以设为peripheral。

    1. 1. 目前来看由于RPi 3B使用的BCM43438模块,WiFi与Bluetooth模块共用RF, bluetooth的RF无法关闭?我对这一部分外行,也没有找到相关的文档。如果将不将ro.rfkilldisabled设为1, 在bluetooth-cli中执行enable时,bluetoothtbd service会挂掉,所以将ro.killdisabled设为了0。
      2. 是要先加载WiFi固件的,我猜想这个固件是对针对整个模块,不单单只是使WiFi模块进入工作状态。WiFi固件没有加载,无法通过bluetooth-cli中enable bluetooth。
      3. 我的表述有问题,由于当然Brillo系统只是让bluetooth模块工作在ble模式,而在ble模式下,当bluetooth role设为peripheral,需要max advertise instance >= 5, 由于RPi 3B max advertise instance=1达不到,无法进行advertising, 其他bluetooth设备无法搜索到该设备:
      在执行bluetooth-cli
      # enable
      # register-ble
      # start-adv -n -t -c
      后,logcat中会有如下log:
      04-02 11:09:58.539 391 397 E bt_btif : btgattc_handle_event invalid index in BTIF_GATTC_ENABLE_ADV
      04-02 11:09:58.539 391 405 W bt_btif : bta_gattc_multi_adv_cback Invalid p_ref received

发表评论

电子邮件地址不会被公开。 必填项已用*标注