bjoernQ / bleps

A toy-level BLE peripheral stack
MIT License
55 stars 18 forks source link

It's very hard to write a gatt service using `gatt!` macro #40

Closed HaoboGu closed 6 months ago

HaoboGu commented 6 months ago

Hello, I'm trying to make a keyboard using esp32 + bleps. I found that it is quite hard to create a gatt service using bleps.

What I'm trying to create is like https://github.com/embassy-rs/nrf-softdevice/blob/master/examples/src/bin/ble_keyboard_peripheral_builder.rs#L289

The following is my code:

    let mut hid_info_fn = |_offset: usize, data: &mut [u8]| {
        data[0..4].copy_from_slice(&[0x1u8, 0x1u8, 0x00u8, 0x03u8]);
        4
    };
    let mut hid_desc_fn = |_offset: usize, data: &mut [u8]| {
        data[0..HID_REPORT_DESCRIPTOR.len()].copy_from_slice(HID_REPORT_DESCRIPTOR);
        HID_REPORT_DESCRIPTOR.len()
    };

    let mut hid_report_fn = |_offset: usize, data: &mut [u8]| {
        data[0..8].copy_from_slice(&[0, 0, 0x04, 0,0,0,0,0]);
        8
    };

    let keyboard_desc_value = [1,1u8];
    let mut kb_report = [0; 8];

    gatt!([service {
        uuid: "1812",
        characteristics: [
            characteristic {
                uuid: "2A4A",
                read: hid_info_fn,
            },
            characteristic {
                uuid: "2A4B",
                read: hid_desc_fn,
            },
            characteristic {
                uuid: "2A4D",
                notify: true,
                read: hid_report_fn,
                descriptors: [
                    descriptor {
                        uuid: "2908",
                        value: keyboard_desc_value,
                    },
                ],
            },
        ],
    },]);

I think I write the arguments right but the macro just doesn't compile. There is not any info from Rust compiler, even using RUSTFLAGS="-Zmacro-backtrace":

$ RUSTFLAGS="-Zmacro-backtrace" cargo build
error: Unexpected
   --> src\lib.rs:593:5
    |
593 | /     gatt!([service {
594 | |         uuid: "1812",
595 | |         characteristics: [
596 | |             characteristic {
...   |
615 | |         ],
616 | |     },]);
    | |        ^ in this macro invocation
    | |________|
    | 
    |
   ::: C:\Users\haobo\.cargo\git\checkouts\bleps-c5f04b27afb89012\9371d7d\bleps-macros\src\lib.rs:31:1
    |
31  |   pub fn gatt(input: TokenStream) -> TokenStream {
    |   ---------------------------------------------- in this expansion of `gatt!`

There is only an Unexpected error, I cannot get any info about what's unexpected and how to fix it. Any ideas? Thanks!

bjoernQ commented 6 months ago

I agree the error messages from the macro should get improved - then I think the macro approach is generally nicer than doing all the things manually (which is also possible - the macro is just for convenience).

btw. I was also trying to implement a BLE-HID device and my services/characteristics looks like this: https://github.com/bjoernQ/esp32c3-ble-hid/blob/main/src/main.rs#L229-L284

That works and I can use it with Android. It doesn't yet work with Windows (haven tried anything else). Would be great if you get your implementation to work with more OSes

HaoboGu commented 6 months ago

Thanks for reply! Yeah macros makes it much simpler to build a gatt service, that's true. I got my service worked eventually, by reading a lot of macro code..

If the error messages got improved, telling users why the way you use the macro is wrong, it would be great.

HaoboGu commented 6 months ago

https://github.com/bjoernQ/esp32c3-ble-hid/blob/main/src/main.rs#L229-L284

I cannot get this work on macos nor iphone. The device is discoverable and connectable, but after connected, nothing can be read from host.

The following is the log, but I cannot find anything valuable:

[INFO] - Hello ESP BLE!
[INFO] - esp-wifi configuration Config { rx_queue_size: 5, tx_queue_size: 3, static_rx_buf_num: 10, dynamic_rx_buf_num: 32, static_tx_buf_num: 0, dynamic_tx_buf_num: 32, ampdu_rx_enable: 0, ampdu_tx_enable: 0, amsdu_tx_enable: 0, rx_ba_win: 6, max_burst_size: 1, country_code: "CN", country_code_operating_class: 0, mtu: 1492, heap_size: 65536, tick_rate_hz: 100, listen_interval: 3, beacon_timeout: 6, ap_beacon_timeout: 300, failure_retry_cnt: 1, scan_method: 0 }
[DEBUG] - ble init
[DEBUG] - BT controller compile version b877d66
[DEBUG] - btdm_rom_table_ready_wrapper not implemented
[DEBUG] - spawning task btController: 0x40381764 param 0x0 prio 200
0x40381764 - btdm_rw_run
    at ??:??
[DEBUG] - task started: 0x40381764 0x0
0x40381764 - btdm_rw_run
    at ??:??
[DEBUG] - !!!! unimplemented srand 603
[DEBUG] - The btdm_controller_init was initialized
Connector created
[DEBUG] - coex_schm_status_bit_clear 1 -1
[DEBUG] - ignored coex_wifi_sleep_set 0 - because original implementation does the same
[DEBUG] - coex_schm_status_bit_clear 1 -1
[DEBUG] - ignored coex_wifi_sleep_set 0 - because original implementation does the same
[DEBUG] - ignored coex_wifi_sleep_set 0 - because original implementation does the same
[DEBUG] - ignored coex_wifi_sleep_set 0 - because original implementation does the same
[DEBUG] - coex_schm_status_bit_set 1 1
[DEBUG] - ignored coex_wifi_sleep_set 0 - because original implementation does the same
[INFO] - Start advertising
notify hid report
notify hid report
[DEBUG] - coex_schm_status_bit_clear 1 1
[DEBUG] - ignored coex_wifi_sleep_set 0 - because original implementation does the same
[DEBUG] - coex_schm_status_bit_set 1 4
[DEBUG] - ignored coex_wifi_sleep_set 1 - because original implementation does the same
[DEBUG] - ignored coex_wifi_sleep_set 0 - because original implementation does the same
notify hid report
notify hid report
notify hid report
notify hid report
notify hid report
bjoernQ commented 6 months ago

Another way to debug it might be to use https://github.com/esp-rs/esp-wifi/tree/main/extras/esp-wifishark

HaoboGu commented 6 months ago

Another way to debug it might be to use https://github.com/esp-rs/esp-wifi/tree/main/extras/esp-wifishark

I got the following error:

     Running `espflash flash --monitor --log-format defmt target/riscv32imc-unknown-none-elf/release/rmk-esp32c3`
[2024-03-27T08:16:18Z INFO ] Detected 2 serial ports
[2024-03-27T08:16:18Z INFO ] Ports which match a known common dev board are highlighted
[2024-03-27T08:16:18Z INFO ] Please select a port
[2024-03-27T08:16:19Z INFO ] Serial port: '/dev/tty.usbmodem211301'
[2024-03-27T08:16:19Z INFO ] Connecting...
Error: espflash::serial_error

  × Failed to open serial port /dev/tty.usbmodem211301
  ├─▶ Error while connecting to device
  ├─▶ IO error while using serial port: Device or resource busy
  ╰─▶ Device or resource busy

If I start esp32's program before open wireshark, the wireshark would report similar Device or resource busy error when I start esp-wifi HCI capture: bt

HaoboGu commented 6 months ago

Another thing that I can report is, according to the readme of esp-wifishark:

By default it tries to identify exactly one serialport. If that doesn't work for you, you can configure the serialport via the Wireshark UI.

But I cannot find serial port configurations in wireshark. I have to edit the esp-wifishark's source code. It would be better if there's a screenshot about this.

bjoernQ commented 6 months ago

image

You can click the gear icon left to the esp-wifi HCI capture extcap to open the settings

HaoboGu commented 6 months ago

@bjoernQ yeah, just found it.. I set it to /dev/tty.usbmodem211301

image

But still got the error:

Error: espflash::serial_error

  × Failed to open serial port /dev/tty.usbmodem211301
  ├─▶ Error while connecting to device
  ├─▶ IO error while using serial port: Device or resource busy
  ╰─▶ Device or resource busy
HaoboGu commented 6 months ago

If I start esp32 first then watch, I got this:

image
bjoernQ commented 6 months ago

Is the device still monitored by espflash maybe? That would explain why the port is currently in use

HaoboGu commented 6 months ago

yeah, I think so.

I removed --monitor argument in espflash, but got nothing in wireshark. It seems without --monitor, esp wouldn't send logs to serial port (or the host wouldn't read from serial port? idk).

I also tried to remove defmt, enabled log feature for esp-println, but still not work.

HaoboGu commented 6 months ago

Printed HCI logs, but I have no idea about those data...

[INFO] - Hello ESP BLE!
[INFO] - esp-wifi configuration Config { rx_queue_size: 5, tx_queue_size: 3, static_rx_buf_num: 10, dynamic_rx_buf_num: 32, static_tx_buf_num: 0, dynamic_tx_buf_num: 32, ampdu_rx_enable: 0, ampdu_tx_enable: 0, amsdu_tx_enable: 0, rx_ba_win: 6, max_burst_size: 1, country_code: "CN", country_code_operating_class: 0, mtu: 1492, heap_size: 65536, tick_rate_hz: 100, listen_interval: 3, beacon_timeout: 6, ap_beacon_timeout: 300, failure_retry_cnt: 1, scan_method: 0 }
[DEBUG] - ble init
[DEBUG] - BT controller compile version b877d66
[DEBUG] - btdm_rom_table_ready_wrapper not implemented
[DEBUG] - spawning task btController: 0x40381764 param 0x0 prio 200
0x40381764 - btdm_rw_run
    at ??:??
[DEBUG] - task started: 0x40381764 0x0
0x40381764 - btdm_rw_run
    at ??:??
[DEBUG] - !!!! unimplemented srand 566
[DEBUG] - The btdm_controller_init was initialized
[DEBUG] - Connector created
[INFO] - @HCIFRAME [1, 3, 12, 0]
[DEBUG] - coex_schm_status_bit_clear 1 -1
[DEBUG] - ignored coex_wifi_sleep_set 0 - because original implementation does the same
[DEBUG] - coex_schm_status_bit_clear 1 -1
[DEBUG] - ignored coex_wifi_sleep_set 0 - because original implementation does the same
[INFO] - @HCIFRAME [4, 14, 4, 5, 3, 12, 0]
[INFO] - @HCIFRAME [1, 1, 12, 8, 255, 255, 255, 255, 255, 255, 255, 255]
[INFO] - @HCIFRAME [4, 14, 4, 5, 1, 12, 0]
[INFO] - @HCIFRAME [1, 6, 32, 15, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0]
[DEBUG] - ignored coex_wifi_sleep_set 0 - because original implementation does the same
[DEBUG] - ignored coex_wifi_sleep_set 0 - because original implementation does the same
[INFO] - @HCIFRAME [4, 14, 4, 5, 6, 32, 0]
[INFO] - @HCIFRAME [1, 8, 32, 32, 29, 2, 1, 6, 3, 3, 18, 24, 17, 9, 69, 83, 80, 32, 82, 77, 75, 32, 75, 101, 121, 98, 111, 97, 114, 100, 3, 25, 193, 3, 0, 0]
[INFO] - @HCIFRAME [4, 14, 4, 5, 8, 32, 0]
[INFO] - @HCIFRAME [1, 10, 32, 1, 1]
[DEBUG] - coex_schm_status_bit_set 1 1
[DEBUG] - ignored coex_wifi_sleep_set 0 - because original implementation does the same
[INFO] - @HCIFRAME [4, 14, 4, 5, 10, 32, 0]
[INFO] - Start advertising
[INFO] - @HCIFRAME [1, 9, 16, 0]
[INFO] - @HCIFRAME [4, 14, 10, 5, 9, 16, 0, 197, 135, 209, 59, 218, 238]
notify hid report
[DEBUG] - coex_schm_status_bit_clear 1 1
[DEBUG] - ignored coex_wifi_sleep_set 0 - because original implementation does the same
[DEBUG] - coex_schm_status_bit_set 1 4
[DEBUG] - ignored coex_wifi_sleep_set 1 - because original implementation does the same
[DEBUG] - ignored coex_wifi_sleep_set 0 - because original implementation does the same
[INFO] - @HCIFRAME [4, 62, 19, 1, 0, 1, 0, 1, 0, 35, 236, 216, 103, 126, 108, 24, 0, 0, 0, 72, 0, 1]
[INFO] - @HCIFRAME [2, 1, 32, 7, 0, 3, 0, 4, 0, 2, 15, 2]
[INFO] - @HCIFRAME [2, 1, 32, 7, 0, 3, 0, 4, 0, 3, 23, 0]
[INFO] - @HCIFRAME [4, 19, 5, 1, 1, 0, 1, 0]
[INFO] - @HCIFRAME [2, 1, 32, 7, 0, 3, 0, 4, 0, 10, 15, 0]
[INFO] - @HCIFRAME [2, 1, 32, 12, 0, 8, 0, 4, 0, 11, 2, 76, 75, 70, 67, 0, 0]
[INFO] - @HCIFRAME [4, 19, 5, 1, 1, 0, 1, 0]
[INFO] - @HCIFRAME [2, 1, 32, 7, 0, 3, 0, 4, 0, 10, 3, 0]
[INFO] - @HCIFRAME [2, 1, 32, 9, 0, 5, 0, 4, 0, 11, 1, 1, 0, 3]
[INFO] - @HCIFRAME [4, 19, 5, 1, 1, 0, 1, 0]
[INFO] - @HCIFRAME [2, 1, 32, 7, 0, 3, 0, 4, 0, 10, 5, 0]
[INFO] - @HCIFRAME [2, 1, 32, 27, 0, 23, 0, 4, 0, 11, 5, 1, 9, 6, 161, 1, 133, 1, 5, 7, 25, 1, 41, 127, 21, 0, 37, 1, 117, 1, 149, 8]
[INFO] - @HCIFRAME [4, 19, 5, 1, 1, 0, 1, 0]
[INFO] - @HCIFRAME [2, 1, 32, 9, 0, 5, 0, 4, 0, 12, 5, 0, 22, 0]
[INFO] - @HCIFRAME [2, 1, 32, 27, 0, 23, 0, 4, 0, 13, 129, 2, 149, 1, 117, 8, 129, 1, 149, 5, 117, 1, 5, 8, 25, 1, 41, 5, 145, 2, 149, 1]
[INFO] - @HCIFRAME [4, 19, 5, 1, 1, 0, 1, 0]
[INFO] - @HCIFRAME [2, 1, 32, 9, 0, 5, 0, 4, 0, 12, 5, 0, 44, 0]
[INFO] - @HCIFRAME [2, 1, 32, 26, 0, 22, 0, 4, 0, 13, 117, 3, 145, 1, 149, 6, 117, 8, 21, 0, 37, 101, 5, 7, 25, 0, 41, 101, 129, 0, 192]
[INFO] - @HCIFRAME [4, 19, 5, 1, 1, 0, 1, 0]
notify hid report
notify hid report
notify hid report

edit: I tried to dump the pcap file from logs directly, here is the result. pcap.txt. You can load in in wireshark

I'm not that familiar with HCI protocol, so still have no idea about what's the problem 😭

bjoernQ commented 6 months ago

Here are two HCI captures - one with Android (where it's working) and one with Windows 11 (it's not working there)

hid-pairing.zip

Would be good to see how a working HID device works

HaoboGu commented 6 months ago

thank you very much! I'll have a look!

it seems that we are off-topic a little bit. I'm closing this issue now.

bjoernQ commented 6 months ago

Yes, we are off-topic. If you find out anything regarding the HID example I'd be happy to hear about that in the https://github.com/bjoernQ/esp32c3-ble-hid repository

Thanks!