bluez-rs icon indicating copy to clipboard operation
bluez-rs copied to clipboard

Cannot set device class

Open schell opened this issue 4 years ago • 3 comments

Thank you for this nice crate. When trying to set up my rpi as a bluetooth keyboard I run into the following error, specifically while setting the device class:

Error: Xfer { source: Bluez { source: CommandError { opcode: SetDeviceClass, status: InvalidParams } } }

Where Xfer is my own Error enum.

This is roughly my program:

pub async fn run() -> Result<(), Error> {
    let mut client = BlueZClient::new().unwrap();

    let version = client.get_mgmt_version().await?;
    trace!(
        "management version: {}.{}",
        version.version,
        version.revision
    );

    let controllers = client.get_ext_controller_list().await?;
    let (controller, type_is, bus) = controllers.first().with_context(|| NoControllers)?;
    trace!(
        "got controller:\n{:?} ({:?}, {:?})",
        controller,
        type_is,
        bus
    );
    trace!(
        "info:\n{:#?}",
        client.get_controller_info(*controller).await?
    );

    let ctrl_settings = client
        .set_powered(
            *controller,
            true
        )
        .await?;
    trace!("controller settings after power on: {:?}", ctrl_settings);

    let ctrl_settings = client
        .set_connectable(
            *controller,
            true
        )
        .await?;
    trace!("controller settings after connectable: {:?}", ctrl_settings);

    let ctrl_settings = client
        .set_discoverable(
            *controller,
            DiscoverableMode::Limited,
            Some(60)
        )
        .await?;
    trace!("controller settings after discoverable: {:?}", ctrl_settings);

    let return_classes = client
        .set_device_class(
            *controller,
            DeviceClass::Peripheral {
                keyboard: true,
                pointer: false,
                class: PeripheralDeviceClass::Uncategorized,
            },
        )
        .await?;

    trace!("set device class, got: {:?}", return_classes);
    Ok(())
}

It's notable however, that using the command line to set the device class is working:

sudo hciconfig hci0 class 0x002540

After running the cli above, the settings have properly updated:

ControllerInfo {
    address: Address {
        bytes: [
            248,
            250,
            50,
            235,
            39,
            184,
        ],
    },
    bluetooth_version: 7,
    manufacturer: 15,
    supported_settings: BitFlags<ControllerSetting> {
        bits: 0b11011111111111111,
        flags: Powered | Connectable | FastConnectable | Discoverable | Pairable | LinkLevelSecurity | SecureSimplePairing | BREDR | HighSpeed | LE | Advertising | SecureConnection | DebugKeys | Privacy | StaticAddress | PhyConfiguration,
    },
    current_settings: BitFlags<ControllerSetting> {
        bits: 0b101011010011,
        flags: Powered | Connectable | Pairable | SecureSimplePairing | BREDR | LE | SecureConnection,
    },
    class_of_device: (
        Peripheral {
            keyboard: true,
            pointer: false,
            class: Uncategorized,
        },
        BitFlags<ServiceClass> {
            bits: 0b0,
        },
    ),
    name: "raspberrypi",
    short_name: "",
}

I'm new to working with bluetooth so I'm not sure what the problem is, but I thought it might be that the DeviceClass wasn't being converted into the correct u16 - indeed my device class seems to convert to 0x540, but making exec_command public and calling it with an explicit class of 0x2540 encounters the same error.

schell avatar Nov 16 '20 00:11 schell

It is unclear why this is not working. The BlueZ documentation doesn't give any information about why 0x540 might be an invalid device class, and neither does the Bluetooth website.

laptou avatar Nov 21 '20 05:11 laptou

Yes, it seems weird. In the meantime I'm using the cli as a backup.

schell avatar Nov 21 '20 17:11 schell

I think it's notable that the 0x2000 part of 0x2540 sets the device in limited discovery mode. I thought maybe the problem was that setting 0x540 when the device is not already in limited discover would result in an invalid param error, so I set the device explicitly in limited discovery by first using set_discoverable. This doesn't seem to remedy the situation, though.

schell avatar Nov 23 '20 16:11 schell