Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SIM: Add support Linux HCI Socket as BLE adaptor #1655

Merged
merged 1 commit into from
Aug 28, 2020

Conversation

btashton
Copy link
Contributor

Summary

There is also support on a Linux Host for attaching the Bluetooth hardware from the host to the NuttX Bluetoooth stack via the HCI Socket interface over the User Channel. This is enabled in the bthcisock configuration. In order to use this you must give the nuttx elf additional capabilities:
sudo setcap 'cap_net_raw,cap_net_admin=eip' ./nuttx
You can then monitor the HCI traffic on the host with wireshark or btmon:
sudo btmon

Impact

This enables much more powerful testing on the simulation target than we have with the null driver.

Testing

In the simulation:

❯  sudo setcap 'cap_net_raw,cap_net_admin=eip' ./nuttx 
❯ ./nuttx 
NuttShell (NSH) NuttX-9.1.0
nsh> bt bnep0 scan start -d
nsh> bt bnep0 scan stop
nsh> bt bnep0 scan get
Scan result:
 1.	addr:           4f:0f:8f:dd:3b:a3 type: 1
	rssi:            -74
	response type:   2
	advertiser data: 03 03 9f fe 17 16 9f fe 00 00 00 00 00 00 00 00
	                 00 00 00 00 00 00 00 00 00 00 00 00
 2.	addr:           4f:0f:8f:dd:3b:a3 type: 1
	rssi:            -74
	response type:   4
	advertiser data: 09 ff e0 00 56 f6 ca 68 26 96
 3.	addr:           71:ad:8c:45:b1:f7 type: 1
	rssi:            -62
	response type:   0
	advertiser data: 02 01 1a 0a ff 4c 00 10 05 03 1c 78 c4 7b
 4.	addr:           71:ad:8c:45:b1:f7 type: 1
	rssi:            -62
	response type:   4
	advertiser data: 5.	addr:           c8:ff:77:be:b8:a0 type: 0
	rssi:            -83
	response type:   0
	advertiser data: 02 01 06 11 06 a4 d0 87 a7 b4 d1 79 89 2d 45 37
	                 1c 10 00 d1 2d
nsh> 
❯ sudo btmon 
= Close Index: 60:57:18:EE:03:FD                                                                   [hci0] 4.204320
@ MGMT Event: Index Removed (0x0005) plen 0                                               {0x0002} [hci0] 4.204520
@ MGMT Event: Index Removed (0x0005) plen 0                                               {0x0001} [hci0] 4.204520
= Open Index: 60:57:18:EE:03:FD                                                                    [hci0] 4.204551
= Index Info: 60:57:18:EE:03:FD (Intel Corp.)                                                      [hci0] 4.204553
@ RAW Close: nuttx                                                                               {0x0003} 4.204557
@ USER Open: nuttx (privileged) version 2.22                                              {0x0003} [hci0] 4.204560
< HCI Command: Reset (0x03|0x0003) plen 0                                                       #5 [hci0] 4.204602
= bluetoothd: Endpoint unregistered: sender=:1.74 path=/MediaEndpoint/A2DPSink/sbc                        4.207973
= bluetoothd: Endpoint unregistered: sender=:1.74 path=/MediaEndpoint/A2DPSource/sbc                      4.208031
> HCI Event: Command Complete (0x0e) plen 4                                                     #6 [hci0] 4.218155
      Reset (0x03|0x0003) ncmd 2
        Status: Success (0x00)
< HCI Command: Read Local Supported Features (0x04|0x0003) plen 0                               #7 [hci0] 4.224783
> HCI Event: Command Complete (0x0e) plen 12                                                    #8 [hci0] 4.225184

...

> HCI Event: LE Meta Event (0x3e) plen 12                                                     #58 [hci0] 49.428408
      LE Advertising Report (0x02)
        Num reports: 1
        Event type: Scan response - SCAN_RSP (0x04)
        Address type: Random (0x01)
        Address: 71:AD:8C:45:B1:F7 (Resolvable)
        Data length: 0
        RSSI: -62 dBm (0xc2)
> HCI Event: LE Meta Event (0x3e) plen 33                                                     #59 [hci0] 51.635490
      LE Advertising Report (0x02)
        Num reports: 1
        Event type: Connectable undirected - ADV_IND (0x00)
        Address type: Public (0x00)
        Address: C8:FF:77:BE:B8:A0 (Dyson Limited)
        Data length: 21
        Flags: 0x06
          LE General Discoverable Mode
          BR/EDR Not Supported
        128-bit Service UUIDs (partial): 1 entry
          Vendor specific (2dd10010-1c37-452d-8979-d1b4a787d0a4)
        RSSI: -83 dBm (0xad)
> HCI Event: LE Meta Event (0x3e) plen 38                                                     #60 [hci0] 53.513519
      LE Advertising Report (0x02)
        Num reports: 1
        Event type: Scan response - SCAN_RSP (0x04)
        Address type: Public (0x00)
        Address: C8:FF:77:BE:B8:A0 (Dyson Limited)
        Data length: 26
        Name (complete): VV6-US-KFA1546A
        TX power: 0 dBm
        Slave Conn. Interval: 0x000c - 0x0018
        RSSI: -80 dBm (0xb0)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2                                        #61 [hci0] 59.354996
        Scanning: Disabled (0x00)
        Filter duplicates: Disabled (0x00)
> HCI Event: Command Complete (0x0e) plen 4                                                   #62 [hci0] 59.458558
      LE Set Scan Enable (0x08|0x000c) ncmd 2
        Status: Success (0x00)

@btashton btashton force-pushed the hci-socket branch 2 times, most recently from fead667 to ee643e1 Compare August 27, 2020 01:05
@protobits
Copy link
Contributor

Very nice addition!
Looked at the changes and have nothing to comment. Only a question: you receive HCI data in the IDLE loop. Does the HCI socket have an internal buffer which will accumulate pending packets? If not, packets could be lost. Or is this not a problem?

BTW, can we also expose L2CAP sockets? In that case we could fully use the simulator to test GATT for example.

@btashton
Copy link
Contributor Author

Very nice addition!
Looked at the changes and have nothing to comment. Only a question: you receive HCI data in the IDLE loop. Does the HCI socket have an internal buffer which will accumulate pending packets? If not, packets could be lost. Or is this not a problem?

Should not be a problem as the host side will queue based on the Linux network stack settings. I would do a select on the socket but there is not a real good way to handle this across the simulation boundary. This is basically the same thing we do for X11 and netdev.

BTW, can we also expose L2CAP sockets? In that case we could fully use the simulator to test GATT for example.

There is no need, this lets us hook in a the the controller level so the NuttX Bluetooth stack should be providing the L2CAP on top of this. I just added a little more to handle reading the ACL packets from the controller, it should already be handling sending them out.

@btashton
Copy link
Contributor Author

@v01d Just verified a GATT connection with this and was able to see the ACL send and recv through the the host and NuttX, so I think the L2CAP stuff should work fine on top of this.

@patacongo
Copy link
Contributor

Very nice, indeed. Could you also support a USB Bluetooth HCI dongle with libusb and feed that into the stack as well?

@patacongo
Copy link
Contributor

Should not be a problem as the host side will queue based on the Linux network stack settings. I would do a select on the socket but there is not a real good way to handle this across the simulation boundary. This is basically the same thing we do for X11 and netdev.

I would think that Sebastian Ene's pre-emption changes could support better realtime response.

@btashton
Copy link
Contributor Author

Should not be a problem as the host side will queue based on the Linux network stack settings. I would do a select on the socket but there is not a real good way to handle this across the simulation boundary. This is basically the same thing we do for X11 and netdev.

I would think that Sebastian Ene's pre-emption changes could support better realtime response.

I was worried about issuing a blocking read on the host socket inside a NuttX thread. If you have any thoughts on that the logic is rather isolated, I just was not sure how to do this.

@btashton
Copy link
Contributor Author

Very nice, indeed. Could you also support a USB Bluetooth HCI dongle with libusb and feed that into the stack as well?

So right now the physical transport is agnostic since Linux takes care of that exposing a generic HCI interface, on my machine I have a fairly standard PCIe form factor dual Bluetooth Wifi chip and the Bluetooth half of it is USB. The downside of this is it is Linux specific, but I also get to put Wireshark in the middle at the controller level which means it gets to snoop on the encryption.

If you want something more cross platform then yeah libusb is probably the way to go, the Xiaomi patch actually implemented a libusb interface for I think a standard CSR dongle. Instead of adding the tty interface on top it could be wired into the stack as a normal device.

I do all my development on Linux and my interest is a little further up the stack so I probably would not implement this myself, but I would review it.

@patacongo
Copy link
Contributor

I would think that Sebastian Ene's pre-emption changes could support better realtime response.

I was worried about issuing a blocking read on the host socket inside a NuttX thread. If you have any thoughts on that the logic is rather isolated, I just was not sure how to do this.

Yeah, you are right. There is probably more involved.

I did experiment with a configuration where I implemented simulated serial device drivers on a pthread which avoided the blocking issue in the simulation main thread. But I never worked through all of the issues. I bet Sebastien Ene could make that kind of device driver model work.

@protobits
Copy link
Contributor

@v01d Just verified a GATT connection with this and was able to see the ACL send and recv through the the host and NuttX, so I think the L2CAP stuff should work fine on top of this.

Great!

@protobits
Copy link
Contributor

LGTM

arch/sim/src/sim/up_idle.c Outdated Show resolved Hide resolved
* Public Function Prototypes
****************************************************************************/

int bthcisock_host_send(int fd, uint8_t pkt_type, uint8_t *data, size_t len);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we merge into up_internal.h? since all other drivers put the function prototype there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are functions that cross the Host NuttX boundary, I don't really want to expose these interfaces to other drivers. VPN kit for instance also carries its own header file in the vpnkit folder.

arch/sim/src/sim/up_hcisocket_host.c Outdated Show resolved Hide resolved
arch/sim/src/sim/up_idle.c Outdated Show resolved Hide resolved
@acassis
Copy link
Contributor

acassis commented Aug 27, 2020

Hi Brennan, this is a great addition! Kudos!!!
Could we include into Documentation this "Testing" procedure? It is very useful. And keeping it here will be difficult for other people to find it.

@btashton
Copy link
Contributor Author

@acassis I would like to leave this in the board readme for now and write a more cohesive document on the Bluetooth stack and testing once we get more of it solidified.

Copy link
Contributor

@acassis acassis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@acassis I would like to leave this in the board readme for now and write a more cohesive document on the Bluetooth stack and testing once we get more of it solidified.

@btashton I agree. I tried to include the Testing example in mode details inside the README.txt but I think it got messy.

boards/sim/sim/sim/README.txt Show resolved Hide resolved
boards/sim/sim/sim/README.txt Show resolved Hide resolved
@btashton
Copy link
Contributor Author

@xiaoxiang781216 I think I have addressed all of your comments. With the readv change I also allowed for keeping the allocated buffer around if the buffer was not used so we do not have to go through the allocate and free every loop, only if there is data.

@xiaoxiang781216
Copy link
Contributor

LGTM.

@jerpelea
Copy link
Contributor

LGTM

@xiaoxiang781216 xiaoxiang781216 merged commit 8934f2e into apache:master Aug 28, 2020
@xiaoxiang781216
Copy link
Contributor

@btashton The HCISOCKET(BTPROTO_HCI) work very well for BT and BLE, but it seem that the socket with BTPROTO_SCO can't work as expected. Do you have any idea to simulate the SCO capability?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants