4.Rust嵌入式入门——蓝牙服务

1,497 阅读3分钟

4.Rust嵌入式入门——蓝牙服务

这一节将利用BLE蓝牙技术来提供一项服务,使得我们能够通过应用程序来控制灯光的开启与关闭。

前置知识

不了解蓝牙的同学可以先了解一点蓝牙知识。

Bluetooth 技术概述

BLE低功耗蓝牙技术详解

sdk配置

在项目目录下的sdkconfig.defaults文件中添加下面配置

CONFIG_BT_ENABLED=y
CONFIG_BT_BLE_ENABLED=y
CONFIG_BT_BLUEDROID_ENABLED=n
CONFIG_BT_NIMBLE_ENABLED=y

安装依赖

cargo add esp32-nimble

蓝牙服务

新建bin/ble_server.rs

use std::sync::{ Arc, Mutex };
use esp_idf_svc::hal::delay::FreeRtos;
use rgb::RGB8;
use rust_embedded_study::{ init, led::WS2812RMT };
use esp32_nimble::{ utilities::BleUuid, BLEAdvertisementData, BLEDevice, NimbleProperties };

fn main() -> anyhow::Result<()> {
    // 初始化系统、外设和NVS flash。
    let (_sys, peripherals, _nvs) = init()?;

    // 获取BLE设备实例
    let device = BLEDevice::take();

    // 初始化LED灯
    let led = Arc::new(
        Mutex::new(WS2812RMT::new(peripherals.pins.gpio8, peripherals.rmt.channel0)?)
    );

    // 获取并配置BLE的广告实例
    let advertising = device.get_advertising();

    // 获取并配置BLE的服务实例。
    let server = device.get_server();

    // 配置BLE连接时的回调函数
    server.on_connect(|server, desc| {
        log::info!("on_connect: {:#?}", desc);
        server.update_conn_params(desc.conn_handle(), 24, 48, 0, 60).unwrap();
        if server.connected_count() < (esp_idf_svc::sys::CONFIG_BT_NIMBLE_MAX_CONNECTIONS as _) {
            advertising.lock().start().unwrap();
        }
    });

    // 配置BLE断开连接时的回调函数
    server.on_disconnect(|desc, reason| {
        log::warn!("on_disconnect: {:#?}, reason: {:#?}", desc, reason)
    });

    // 创建BLE服务,使用UUID 0x8848
    let service = server.create_service(BleUuid::from_uuid16(0x8848));

    // 在服务中创建一个特性,用于设置LED颜色,使用UUID 0xffa1
    let set_color_characteristic = service
        .lock()
        .create_characteristic(
            BleUuid::from_uuid16(0xffa1),
            NimbleProperties::WRITE | NimbleProperties::READ
        );

    // 在服务中创建一个特性,用于关闭LED,使用UUID 0xffa2
    let close_characteristic = service
        .lock()
        .create_characteristic(BleUuid::from_uuid16(0xffa2), NimbleProperties::WRITE);

    // 当设置颜色特性被写入时,更新LED的颜色。
    let write_led = led.clone();
    set_color_characteristic
        .lock()
        .on_write(move |args| {
            let data = args.recv_data();
            match write_led.lock().unwrap().set_pixel(RGB8::new(data[0], data[1], data[2])) {
                Ok(_) => {
                    log::warn!("Set LED color to {:?}", RGB8::new(data[0], data[1], data[2]))
                }
                Err(e) => log::error!("Error: {}", e),
            }
        })
        .on_read(|value, desc| {
            log::warn!("Read from descriptor {:?}", desc);
            value.set_value(b"hello world")
        });

    // 当关闭特性被写入时,关闭LED。
    close_characteristic.lock().on_write(move |args| {
        let data = args.recv_data();
        if data[0] == 1 {
            match led.lock().unwrap().shutdown() {
                Ok(_) => { log::warn!("Close LED {:?}", data) }
                Err(e) => log::error!("Error: {}", e),
            }
        }
    });

    // 配置广告数据并启动广告
    advertising
        .lock()
        .set_data(
            BLEAdvertisementData::new().name("ESP32").add_service_uuid(BleUuid::from_uuid16(0x8848))
        )?;
    advertising.lock().start()?;
    // 打印蓝牙服务相关日志
    server.ble_gatts_show_local();

    loop {
        FreeRtos::delay_ms(10000);
    }
}

  1. 程序首先进行系统、外设和NVS flash的初始化。
  2. 获取BLE设备实例,并初始化LED灯。
  3. 获取并配置BLE的广告实例和服务实例。
  4. 配置BLE连接和断开连接时的回调函数。
  5. 创建BLE服务,并在服务中创建两个特性:一个用于设置LED颜色,一个用于关闭LED。
  6. 当设置颜色特性被写入时,更新LED的颜色;当关闭特性被写入时,关闭LED。
  7. 配置广告数据并启动广告。
  8. 程序进入循环等待状态。

然后写入开发板

cargo run --bin ble_server

蓝牙调试工具的相关信息可以参考以下文章:

然后只需按照规定向这些服务和特性写入相应的值即可。

最后

🎉恭喜您成功实现了蓝牙服务功能。您所探索的代码可以在GitHub仓库yexiyue/rust-embedded-study中找到。

如果您觉得不错,请点个关注或者收藏,感谢您的支持。