Skip to content

Latest commit

 

History

History
249 lines (162 loc) · 6.79 KB

File metadata and controls

249 lines (162 loc) · 6.79 KB

Lecture 5 — How BLE becomes hci0 and how to validate the full path

Course: Jetson ESP-Hosted Host Code guide · Phase 2 — Embedded Linux

Previous: Lecture 04


1. The Bluetooth side is a separate Linux subsystem

Wi-Fi and Bluetooth ride over the same host transport, but Linux does not treat them as the same thing.

For BLE, the important file is:

  • esp_hosted_ng/host/esp_bt.c

This file integrates with the Linux HCI subsystem instead of cfg80211.

That is the key Embedded Linux lesson:

  • one transport
  • multiple Linux subsystem personalities

Related Linux kernel concepts

This lecture connects most directly to:

Lecture 1 is useful here because HCI is another example of the kernel exposing a standard abstraction over unusual hardware. The ESP is still remote and still behind SPI, but once hci_register_dev() succeeds Linux Bluetooth tools can treat it like a normal controller.

Lecture 17 matters because the Bluetooth side also follows the same object-registration pattern as the Wi-Fi side, just in a different subsystem. The important shift is from “a transport packet arrived” to “the kernel accepted that packet as HCI traffic and handed it to the Bluetooth stack.”

The HCI abstraction matters because Bluetooth in Linux is built around a host/controller split. The controller may be on USB, UART, SDIO, or in this case SPI, but once the driver feeds packets into the HCI layer, BlueZ can manage discovery and connections without caring about the underlying bus details.

That is why BLE validation cannot stop at “hci0 exists.” A visible controller only proves registration; scanning successfully proves that HCI commands, events, and data packets are flowing correctly across the transport and back into the Linux Bluetooth stack.

The kernel interfaces to focus on are:

  • hci_alloc_dev()
  • hci_register_dev()
  • hci_recv_frame(...)
  • HCI bus typing with HCI_SPI

2. The exact code path for hci0

Read these functions:

  • esp_init_bt(...)
  • esp_deinit_bt(...)
  • esp_bt_send_frame(...)

In esp_init_bt(...), the driver:

  • allocates an HCI device
  • associates it with the adapter
  • sets the HCI bus type
  • registers the HCI device

On the SPI path, the bus becomes:

  • HCI_SPI

That is why the validated Jetson logs and tools showed:

  • hci0
  • Bus: SPI

This is not cosmetic. It means Linux Bluetooth tooling now sees a standard controller interface.

The key block in esp_bt.c is short and very literal:

int esp_init_bt(struct esp_adapter *adapter)
{
	...
	hdev = hci_alloc_dev();
	...
	adapter->hcidev = hdev;
	hci_set_drvdata(hdev, adapter);

	hdev->bus = INVALID_HDEV_BUS;
	...
	else if (adapter->if_type == ESP_IF_TYPE_SPI)
		hdev->bus = HCI_SPI;

	hdev->open  = esp_bt_open;
	hdev->close = esp_bt_close;
	hdev->flush = esp_bt_flush;
	hdev->send  = esp_bt_send_frame;
	...
	ret = hci_register_dev(hdev);
	...
}

That is the precise moment when “Bluetooth packets from a remote ESP” become “a normal Linux HCI controller.”


3. How incoming BLE data reaches Linux

Now return to main.c and re-read part of process_rx_packet(...).

That function checks the incoming payload type.

When the packet is for Bluetooth:

  • payload_header->if_type == ESP_HCI_IF

the code forwards the data to the HCI stack using:

  • hci_recv_frame(...)

This is the crucial handoff:

  • transport packet from ESP
  • becomes HCI traffic in Linux

That is exactly how a custom hardware path gets translated into a standard subsystem view.

The handoff in main.c is direct:

} else if (payload_header->if_type == ESP_HCI_IF) {
	if (hdev) {
		type = skb->data;
		hci_skb_pkt_type(skb) = *type;
		skb_pull(skb, 1);

		if (hci_recv_frame(hdev, skb)) {
			hdev->stat.err_rx++;
		} else {
			esp_hci_update_rx_counter(hdev, *type, skb->len);
		}
	}
}

The transport does not expose a custom user API for BLE. It converts remote packets into the standard HCI receive path that BlueZ already understands.


4. What the capability logs are telling you

In main.c, the capability printout tells you what the ESP claims to support.

On the validated Jetson path, the logs showed:

  • BT/BLE
  • HCI over SPI
  • BLE only

That last point matters for ESP32-C6:

  • this path is BLE-only
  • do not expect classic Bluetooth audio profiles from this configuration

That is a practical product constraint, not just a code detail.

The capability reporting comes from main.c and is worth scanning once in real code:

if (cap & ESP_BT_SPI_SUPPORT)
	esp_info("\t   - HCI over SPI\n");

if ((cap & ESP_BLE_ONLY_SUPPORT) && (cap & ESP_BR_EDR_ONLY_SUPPORT))
	esp_info("\t   - BT/BLE dual mode\n");
else if (cap & ESP_BLE_ONLY_SUPPORT)
	esp_info("\t   - BLE only\n");
else if (cap & ESP_BR_EDR_ONLY_SUPPORT)
	esp_info("\t   - BR EDR only\n");

Those log lines are not decoration. They are the driver telling you how the remote firmware wants Linux to treat the radio.


5. The validated Linux-side BLE proof

On real hardware, the validation path was:

  • hciconfig -a
  • bluetoothctl list
  • bluetoothctl
  • scan on

And the proof points were:

  • hci0 existed
  • BlueZ recognized the controller
  • the controller bus reported SPI
  • BLE scan discovered nearby devices

That means the BLE path was not just registered. It was functional.

This is important:

  • hci0 appearing is good
  • scan on finding devices is much better

That is the same lesson you saw with Wi-Fi:

  • appearance is not the same as validated behavior

6. End-to-end success criteria for this codebase

For this Jetson case study, full success means:

  • transport up
  • boot-up event received
  • chipset validated
  • wlan0 created
  • Wi-Fi scan works
  • hci0 created
  • BLE scan works

That is the right Embedded Linux mindset:

  • validate at the subsystem level the operating system actually cares about
  • not just at the signal or module-insert level

Final lab

Answer these:

  1. Where is the HCI device allocated?
  2. Where is the HCI bus type set to SPI?
  3. Where do incoming Bluetooth packets get handed to Linux?
  4. Why is scan on stronger evidence than bluetoothctl list alone?
  5. Why does this repo make a good Embedded Linux case study for subsystem integration?

Optional extension:

  • write a short comparison of:
    • cfg80211 integration for Wi-Fi
    • HCI integration for BLE
  • identify what is shared between them and what is subsystem-specific

Previous: Lecture 04 · Back to: Course hub