Overview#
The EdgeFast Open Bluetooth Host stack software is built based on MCUXpresso SDK. The following chapter uses RT1170 as an example, other boards have similar folder structure and corresponding document.
Folder structure#
The following figure shows the EdgeFast Open examples folder structure.

The following figure shows the EdgeFast Open host stack folder structure.

The following table provides information regarding the structure and description.
Folder |
Description |
|---|---|
boards/ CMSIS/ devices/ docs/ middleware/ rtos/ tools/ |
MCUXpresso SDK directory. Refer to Chapter 5 Release contents of MCUXpresso SDK Release Notes at root/docs/ MCUXpresso SDK Release Notes for EVK-MIMXRT1170.pdf to know the details |
boards/<board>/wireless/edgefast_open_examples |
EdgeFast Open Bluetooth host stack example projects |
middleware/wireless/edgefast_open |
EdgeFast Open Bluetooth host stack source code |
The EdgeFast Open folder includes two subfolders:
include: This subfolder includes EdgeFast Open Bluetooth host stack headers.
source: This subfolder includes EdgeFast Open Bluetooth host stack source code ported from Zephyr Bluetooth Host stack.
Parent topic:Overview
Architecture#
The figure Architecture of EdgeFast Open demo in MCUXpresso SDK below shows that the EdgeFast Open Bluetooth host stack is integrated into the MCUXpresso SDK as a middleware component. It leverages the RTOS, the board support, the peripheral driver/component, and other components in the MCUXpresso SDK. The Bluetooth application is built on top of the EdgeFast Open Bluetooth host stack and supports different peripheral features, Bluetooth features, and different RTOSes required by the user.

MCUXpresso SDK has the dual-chip architecture defined by EdgeFast Open Bluetooth project, the Bluetooth application code, and the EdgeFast Open Bluetooth host stack running on the reference board. For example, MIMXRT1170-EVKB and the Linker Layer (LL) run on the Bluetooth modules like AW-AM457-USD, Murata Type 1XK, and Murata Type 1ZM and has single-chip architecture. Bluetooth Host stack and LL runs on the same chip, and communicate with Internal Communication Unit (IMU).
The communication between the host stack and the LL is implemented via the standard HCI UART interface and PCM interface for voice, or the IMU interface.
EdgeFast Open is an open-source Bluetooth Host protocol stack solution provided by NXP as part of the MCUXpresso SDK. It is derived from the Bluetooth Host Stack of Zephyr RTOS and has been ported, tailored, and enhanced by NXP. The stack runs on the MCU host processor, positioned below the application layer and above the HCI driver, and is responsible for the complete Bluetooth Classic and BLE host-side protocol functionality, including GAP, GATT, L2CAP, ATT, SM, RFCOMM, HFP, A2DP, AVRCP, etc.

Its architecture consists of two main parts:
The EdgeFast Open Host Stack itself, which contains the Bluetooth host protocol implementation ported from Zephyr, and a Porting Layer (abstraction layer) that maps Zephyr’s required kernel and system services—such as threads, mutexes, semaphores, queues, FIFOs, work queues, heaps, settings, shell, and logging—to the MCUXpresso SDK environment based on FreeRTOS and NXP platforms. Through this porting layer, the originally Zephyr-oriented Bluetooth stack can run seamlessly on FreeRTOS. EdgeFast Open communicates with the underlying Bluetooth Controller (Link Layer), typically an external BT/BLE module or wireless SoC, via a standard HCI interface (for example, UART, SPI, or PCM).
Note: The porting layer source code is located in the middleware/wireless/edgefast_open/source/porting directory,
which includes implementations for thread management, work queues, synchronization primitives, and other kernel services
required to adapt the Zephyr Bluetooth stack to FreeRTOS and MCUXpresso SDK platforms.
Note: The “ported” aspects of EdgeFast Open ensure compatibility with MCUXpresso SDK while maintaining the robustness and feature completeness of the original Zephyr Bluetooth Host Stack implementation. Therefore, the source code of Edgefast Open is consistent with the source code of the Zephyr Bluetooth protocol stack. This eliminates the need for any source code modifications to the core of the Zephyr Bluetooth protocol stack, thus facilitating maintenance and future updates.
For details about the different components in MCUXpresso SDK, see Getting Started with MCUXpresso SDK User’s Guide (document MCUXSDKGSUG) at root/docs/Getting Started with MCUXpresso SDK.pdf. For details on possible hardware rework requirements, see the hardware rework guide document of the relative board. Parent topic:Overview
Compare with EdgeFast Bluetooth PAL#
This document provides a detailed comparison between EdgeFast Open Bluetooth Host stack and EdgeFast Bluetooth PAL, highlighting the differences in features, examples, and APIs.
Features comparison#
The following table compares the features between EdgeFast Open Bluetooth Host stack and EdgeFast Bluetooth PAL.
Feature |
EdgeFast Open |
EdgeFast Bluetooth PAL |
|---|---|---|
Bluetooth Core Specification |
5.3 |
5.0 |
Bluetooth Host Stack |
Zephyr-based |
Proprietary with Zephyr API compatible |
Bluetooth Controller |
Supported (NXP controller) |
Supported (NXP controller) |
Mode |
LE and Classic |
LE and Classic |
Protocol Support |
L2CAP, GAP, GATT, RFCOMM, SDP, SM, SPP |
L2CAP, GAP, GATT, RFCOMM, SM, SPP |
Classic Profiles |
A2DP, HFP, AVRCP, AVRCP Cover Art, GOEP, BIP, MAP, PBAP |
A2DP, HFP, AVRCP, MAP, PBAP |
LE Profiles |
HTP, PXP, IPSP, HPS, GATT-based services |
HTP, PXP, IPSP, HPS |
Enhanced Attribute (EATT) |
Supported |
Supported |
LE Audio |
Supported |
Supported |
Examples comparison#
The following table compares the available examples between EdgeFast Open Bluetooth Host stack and EdgeFast Bluetooth PAL.
Example |
EdgeFast Open |
EdgeFast Bluetooth PAL |
|---|---|---|
a2dp_bridge |
Supported |
Not supported |
a2dp_sink |
Supported |
Supported |
a2dp_source |
Supported |
Supported |
bmr_4bis |
Supported |
Supported |
bms_4bis |
Supported |
Supported |
broadcast_media_receiver |
Supported |
Supported |
broadcast_media_sender |
Supported |
Supported |
call_gateway |
Supported |
Supported |
call_terminal |
Supported |
Supported |
central_fmp |
Supported |
Supported |
central_hpc |
Supported |
Supported |
central_ht |
Supported |
Supported |
central_ipsp |
Supported |
Supported |
central_pxm |
Supported |
Supported |
central_tip |
Supported |
Supported |
handsfree |
Supported |
Supported |
handsfree_ag |
Supported |
Supported |
map_mce |
Supported |
Supported |
map_mse |
Supported |
Supported |
pbap_pce |
Supported |
Supported |
pbap_pse |
Supported |
Supported |
peripheral_beacon |
Supported |
Supported |
peripheral_fmp |
Supported |
Supported |
peripheral_hps |
Supported |
Supported |
peripheral_ht |
Supported |
Supported |
peripheral_ipsp |
Supported |
Supported |
peripheral_pxr |
Supported |
Supported |
peripheral_tip |
Supported |
Supported |
sco_bridge |
Supported |
Not supported |
shell |
Supported |
Supported |
spp |
Supported |
Supported |
tmap_central |
Supported |
Supported |
tmap_peripheral |
Supported |
Supported |
umr2bms |
Supported |
Supported |
umr_4cis |
Supported |
Supported |
ums_4cis |
Supported |
Supported |
ums_microphone |
Supported |
Supported |
unicast_media_receiver |
Supported |
Supported |
unicast_media_sender |
Supported |
Supported |
wifi_cli_over_ble_wu |
Supported |
Supported |
wireless_uart |
Supported |
Supported |
APIs comparison#
Workflow#
The following workflow compares the key different of API between EdgeFast Open Bluetooth Host stack and EdgeFast Bluetooth PAL.
The following diagram is a typical Egdefast Open workflow:

The following diagram is a typical EdgeFast Bluetooth PAL workflow:

API Differences#
Core Protocols#
Core Protocols Comparison#
There are no differences in the following protocols, including GAP, SM, SPP, and L2CAP (CBFC).
L2CAP Classic Comparison#
The following table compares the L2CAP Classic differences between EdgeFast Open Bluetooth Host stack and EdgeFast Bluetooth PAL.
Feature |
EdgeFast Open |
EdgeFast Bluetooth PAL |
|---|---|---|
Connection-oriented channels in Basic Mode |
Supported |
Supported |
Connection-oriented channels in Retransmission Mode |
Supported |
Not supported |
Connection-oriented channels in Flow control Mode |
Supported |
Not supported |
Connection-oriented channels in Enhanced Retransmission Mode |
Supported |
Supported |
Connection-oriented channels in Streaming Mode |
Supported |
Supported |
Connectionless data channel in Basic L2CAP mode |
Supported |
Not supported |
Signaling packet ECHO |
Supported |
Not supported |
The following compares the L2CAP Classic differences between EdgeFast Open Bluetooth Host stack and EdgeFast Bluetooth PAL.
Aspect |
EdgeFast Open |
EdgeFast Bluetooth PAL |
|---|---|---|
L2CAP architecture |
Zephyr native L2CAP |
PAL adds explicit L2CAP config negotiation |
Channel config |
Static fields in chan.rx.* |
Callback‑based config exchange |
Mode negotiation |
Implicit |
Explicit (get_cfg / cfg_req / cfg_rsp) |
Who drives config |
Local side before connect |
Both sides during config phase |
L2CAP Classic in EdgeFast Open#
static int l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
{
}
static void l2cap_connected(struct bt_l2cap_chan *chan)
{
}
static void l2cap_disconnected(struct bt_l2cap_chan *chan)
{
}
static struct net_buf *l2cap_alloc_buf(struct bt_l2cap_chan *chan)
{
}
#if defined(CONFIG_BT_L2CAP_SEG_RECV)
static void seg_recv(struct bt_l2cap_chan *chan, size_t sdu_len, off_t seg_offset,
struct net_buf_simple *seg)
{
}
#endif /* CONFIG_BT_L2CAP_SEG_RECV */
static const struct bt_l2cap_chan_ops l2cap_ops = {
.alloc_buf = l2cap_alloc_buf,
.recv = l2cap_recv,
.connected = l2cap_connected,
.disconnected = l2cap_disconnected,
#if defined(CONFIG_BT_L2CAP_SEG_RECV)
.seg_recv = seg_recv,
#endif /* CONFIG_BT_L2CAP_SEG_RECV */
};
static struct bt_l2cap_br_chan chan = {
.chan.ops = &l2cap_ops,
.rx.mtu = DATA_BREDR_MTU,
},
chan.rx.mode = <Mode>;
chan.rx.max_transmit = <max_transmit>;
chan.rx.optional = <Mode optional settings>;
chan.rx.extended_control = <extended_control>;
chan.rx.max_window = <max_window>;
int err = bt_l2cap_chan_connect(default_conn, &chan.chan, psm);
if (err < 0) {
PRINTF("Unable to connect to psm %u (err %d)\n", psm, err);
} else {
PRINTF("L2CAP connection pending\n");
}
L2CAP Classic in EdgeFast Bluetooth PAL#
void l2cap_mode_get_cfg(struct bt_l2cap_chan *chan, struct bt_l2cap_cfg_options *cfg)
{
/* Channel configuration handler */
/* `cfg` argument needs to be filled with the configuration options */
}
void l2cap_mode_cfg_req(struct bt_l2cap_chan *chan, struct bt_l2cap_cfg_options *cfg, struct bt_l2cap_cfg_options *rsp)
{
/* Channel configuration response handler */
/* `rsp` argument needs to be filled with the response configuration options */
}
void l2cap_mode_cfg_rsp(struct bt_l2cap_chan *chan, struct bt_l2cap_cfg_options *rsp)
{
/* Channel configuration response handler */
}
static const struct bt_l2cap_chan_ops l2cap_mode_ops = {
.alloc_buf = l2cap_alloc_buf,
.recv = l2cap_recv,
.connected = l2cap_connected,
.disconnected = l2cap_disconnected,
.get_cfg = l2cap_mode_get_cfg,
.cfg_req = l2cap_mode_cfg_req,
.cfg_rsp = l2cap_mode_cfg_rsp
};
static struct bt_l2cap_br_chan chan = {
.chan.ops = &l2cap_mode_ops,
.rx.mtu = DATA_BREDR_MTU,
},
int err = bt_l2cap_chan_connect(default_conn, &chan.chan, psm);
if (err < 0) {
PRINTF("Unable to connect to psm %u (err %d)\n", psm, err);
} else {
PRINTF("L2CAP connection pending\n");
}
Parent topic:Core Protocols Comparison
SDP#
The following compares the SDP differences between EdgeFast Open Bluetooth Host stack and EdgeFast Bluetooth PAL.
Feature |
EdgeFast Open |
EdgeFast Bluetooth PAL |
|---|---|---|
SDP record discovery |
Support Attribute ID list and range settings |
Not supported |
SDP record parse |
bt_sdp_record_parse |
Not supported |
Check attribute |
bt_sdp_has_attr |
Not supported |
Parse attribute value |
bt_sdp_get_attr bt_sdp_attr_value_parse bt_sdp_attr_has_uuid bt_sdp_attr_read |
Not supported |
Parse Additional Protocol Descriptor List attribute |
bt_sdp_attr_addl_proto_parse bt_sdp_attr_addl_proto_count bt_sdp_attr_addl_proto_read |
Not supported |
Parent topic:Core Protocols Comparison
Parent topic:Compare with EdgeFast Bluetooth PAL
LE Profiles#
No differences between EdgeFast Open Bluetooth Host stack and EdgeFast Bluetooth PAL for LE profiles.
LE Audio Profiles#
No differences between EdgeFast Open Bluetooth Host stack and EdgeFast Bluetooth PAL for LE Audio profiles.
Classic Profiles#
The following compares the available Classic profiles between EdgeFast Open Bluetooth Host stack and EdgeFast Bluetooth PAL.
A2DP#
Edgefast Bluetooth vs Edgefast Open - A2DP API Differences#
Source:
middleware/edgefast_bluetooth/include/bluetooth/a2dp.h+bluetooth/a2dp_codec_sbc.hvsmiddleware/edgefast_open/include/zephyr/bluetooth/classic/a2dp.h+classic/a2dp_codec_sbc.h
Badge |
Stack |
|---|---|
edgefast_bluetooth |
NXP Ethermind stack |
edgefast_open |
Zephyr open-source stack |
Legend: 🟢 Only in edgefast_bluetooth | 🔴 Only in edgefast_open | 🟡 Equivalent concept, different API
Contents#
1. Architecture & Design Philosophy#
⚠️ Fundamental difference: edgefast_bluetooth uses a monolithic endpoint model -
struct bt_a2dp_endpointbundles codec capability, configuration, codec buffers, and all control/data callbacks into one object; AVDTP signalling is hidden behind high-level helpers (bt_a2dp_configure,bt_a2dp_start,bt_a2dp_stop). edgefast_open uses a split endpoint + stream model -struct bt_a2dp_epdescribes codec capability only whilestruct bt_a2dp_streamcarries per-connection state; every AVDTP signal has its own named function (bt_a2dp_stream_establish,bt_a2dp_stream_start,bt_a2dp_stream_suspend,bt_a2dp_stream_release,bt_a2dp_stream_abort).
ℹ️ Codec integration: edgefast_bluetooth integrates an optional internal SBC encoder/decoder (controlled by
A2DP_CODEC_EXTERNALandBT_A2DP_CODEC_CONTROL); the app can feed raw PCM viabt_a2dp_src_media_write. edgefast_open provides no built-in codec; the app is always responsible for encoding/decoding and usesbt_a2dp_stream_sendwith a pre-builtnet_buf.
Aspect |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
Primary endpoint object |
|
|
Per-connection stream state |
Embedded inside |
Separate |
AVDTP signal exposure |
Hidden; app calls |
Explicit per-signal: |
Callback registration |
Per-endpoint struct fields ( |
Global |
Media TX |
|
|
Media RX |
|
|
PDU buffer allocation |
Not exposed; internal to stack |
|
MTU query |
Not exposed |
|
Automatic endpoint selection |
|
App explicitly selects both local and remote EP in |
Peer endpoint discovery |
|
|
Codec buffers |
App allocates and provides |
Not needed; codec is external |
SBC channel mode spelling |
|
|
Error codes |
Not defined in |
|
2. Header File Layout & Constants#
Item |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
A2DP main header |
|
|
A2DP SBC codec header |
|
|
SBC IE length |
|
|
MPEG-1,2 IE length |
|
|
MPEG-2,4 IE length |
|
|
Max IE length |
- not present - |
|
Codec ID enum |
|
|
Media type enum |
|
Uses |
Role enum |
|
Uses |
Error codes |
- not present - |
|
SBC channel mode typo |
|
|
SBC bitpool min/max |
- not present in header - |
|
SBC media packet header struct |
|
- not present - (macros only) |
SBC config decode macros |
Parameterised as |
Parameterised as |
SBC helper functions return types |
|
|
Codec buffer size constants |
|
- not present - |
3. Endpoint / Stream Object Model#
ℹ️ This is the most structurally significant difference between the two stacks.
edgefast_bluetooth - single struct bt_a2dp_endpoint embeds everything:
struct bt_a2dp_endpoint {
uint8_t codec_id; /* codec type */
struct bt_a2dp_ep_info info; /* SEP info (media_type, tsep) */
struct bt_a2dp_codec_ie *capabilities;/* codec capability IE */
struct bt_a2dp_codec_ie *config; /* default config IE for SOURCE */
struct bt_a2dp_ep_cb control_cbs; /* configured/start_play/stop_play/sink_streamer_data */
uint8_t *codec_buffer; /* cached codec working buffer */
uint8_t *codec_buffer_nocached; /* non-cached codec working buffer */
/* optional service fields gated by Kconfig: */
/* cp_ie, recovery_ie, reporting_service_enable, */
/* delay_reporting_service_enable, header_compression_cap, multiplexing_service_enable */
};
edgefast_open - struct bt_a2dp_ep (capability descriptor) + struct bt_a2dp_stream (per-connection state):
struct bt_a2dp_ep {
uint8_t codec_type; /* codec type */
struct bt_avdtp_sep sep; /* SEP from AVDTP layer */
struct bt_a2dp_codec_ie *codec_cap; /* codec capability IE */
struct bt_a2dp_stream *stream; /* pointer to currently linked stream (NULL if idle) */
bool delay_report; /* delay report capability flag */
};
struct bt_a2dp_stream {
struct bt_a2dp_ep *local_ep; /* the registered local endpoint */
struct bt_a2dp_stream_ops *ops; /* stream event callbacks */
struct bt_a2dp *a2dp; /* back-reference to the A2DP connection */
struct bt_a2dp_codec_ie codec_config; /* negotiated configuration */
};
In edgefast_open the stream object is app-allocated and passed to
bt_a2dp_stream_config. The samebt_a2dp_epcan be reused across connections (a new stream object is passed each time), whereas in edgefast_bluetooth thebt_a2dp_endpointis bound to one active connection at a time.
4. Connection Management & Callback Registration#
ℹ️ Both stacks use
struct bt_conn *for the initial L2CAP connect and return astruct bt_a2dp *handle. The connect callback registration API differs.
edgefast_bluetooth
struct bt_a2dp *bt_a2dp_connect(struct bt_conn *conn);
int bt_a2dp_disconnect(struct bt_a2dp *a2dp);
int bt_a2dp_register_connect_callback(struct bt_a2dp_connect_cb *cb);
edgefast_open
struct bt_a2dp *bt_a2dp_connect(struct bt_conn *conn);
int bt_a2dp_disconnect(struct bt_a2dp *a2dp);
int bt_a2dp_register_cb(struct bt_a2dp_cb *cb);
bt_a2dp_connectandbt_a2dp_disconnectsignatures are identical in both stacks. The callback registration function is renamed (bt_a2dp_register_connect_callback→bt_a2dp_register_cb) and the callback struct type changes (struct bt_a2dp_connect_cb→struct bt_a2dp_cb).
Callback struct field |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
Connection established |
|
|
Connection released |
|
|
Remote endpoint discovered |
- (separate discovery callback type) |
|
5. Endpoint Registration & Discovery#
Endpoint Registration#
edgefast_bluetooth
int bt_a2dp_register_endpoint(struct bt_a2dp_endpoint *endpoint,
uint8_t media_type, uint8_t role);
Takes explicit
media_typeandroleparameters because the endpoint macro may embed them but the registration function re-declares them. The endpoint registered first has highest priority inbt_a2dp_configure.
edgefast_open
int bt_a2dp_register_ep(struct bt_a2dp_ep *ep, uint8_t media_type, uint8_t tsep);
Functionally equivalent - registers a local SEP with the AVDTP layer. Parameter names differ (
role→tsep). No priority concept; app always explicitly selects the EP inbt_a2dp_stream_config.
Peer Endpoint Discovery#
edgefast_bluetooth
/* callback type */
typedef uint8_t (*bt_a2dp_discover_peer_endpoint_cb_t)(
struct bt_a2dp *a2dp,
struct bt_a2dp_endpoint *endpoint,
struct bt_a2dp_endpoint *peer_endpoint);
int bt_a2dp_discover_peer_endpoints(struct bt_a2dp *a2dp,
bt_a2dp_discover_peer_endpoint_cb_t cb);
Callback returns
BT_A2DP_DISCOVER_ENDPOINT_STOPorBT_A2DP_DISCOVER_ENDPOINT_CONTINUEto control iteration. Both local matching endpoint and remote endpoint are passed together.
edgefast_open
int bt_a2dp_discover(struct bt_a2dp *a2dp, struct bt_a2dp_cb *cb);
/* result arrives in bt_a2dp_cb.discovery_result(a2dp, ep, err) */
Discovery result is delivered through the pre-registered
bt_a2dp_cbstruct rather than a dedicated function pointer. Only the remoteepis provided; the app matches it to a local EP manually.
Automatic vs Manual Configuration#
edgefast_bluetooth only 🟢
/* Automatically picks best local EP by priority and configures it */
int bt_a2dp_configure(struct bt_a2dp *a2dp, void (*result_cb)(int err));
/* Manual override: configure a specific local + remote EP pair */
int bt_a2dp_configure_endpoint(struct bt_a2dp *a2dp,
struct bt_a2dp_endpoint *endpoint,
struct bt_a2dp_endpoint *peer_endpoint,
struct bt_a2dp_endpoint_config *config);
edgefast_open has no automatic selection equivalent - the app always calls
bt_a2dp_stream_configwith explicit local and remote EP pointers.
6. AVDTP Stream Control Functions#
⚠️ This section shows the deepest API divergence. edgefast_bluetooth maps multiple AVDTP signals into fewer coarser functions; edgefast_open exposes each AVDTP signal as its own function.
AVDTP Signal |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
SET_CONFIGURATION |
Part of |
|
GET_CONFIGURATION |
- not exposed - |
|
OPEN (L2CAP media channel) |
Part of |
|
START |
|
|
SUSPEND |
|
|
CLOSE (release) |
|
|
RECONFIGURE |
|
|
ABORT |
- not exposed - |
|
edgefast_bluetooth
int bt_a2dp_start(struct bt_a2dp_endpoint *endpoint);
int bt_a2dp_stop(struct bt_a2dp_endpoint *endpoint);
int bt_a2dp_deconfigure(struct bt_a2dp_endpoint *endpoint);
int bt_a2dp_reconfigure(struct bt_a2dp_endpoint *endpoint,
struct bt_a2dp_endpoint_config *config);
edgefast_open
int bt_a2dp_stream_config(struct bt_a2dp *a2dp, struct bt_a2dp_stream *stream,
struct bt_a2dp_ep *local_ep, struct bt_a2dp_ep *remote_ep,
struct bt_a2dp_codec_cfg *config);
int bt_a2dp_stream_get_config(struct bt_a2dp_stream *stream);
int bt_a2dp_stream_establish(struct bt_a2dp_stream *stream);
int bt_a2dp_stream_start(struct bt_a2dp_stream *stream);
int bt_a2dp_stream_suspend(struct bt_a2dp_stream *stream);
int bt_a2dp_stream_release(struct bt_a2dp_stream *stream);
int bt_a2dp_stream_reconfig(struct bt_a2dp_stream *stream,
struct bt_a2dp_codec_cfg *config);
int bt_a2dp_stream_abort(struct bt_a2dp_stream *stream);
edgefast_open separates
establish(AVDTP OPEN + L2CAP media channel) fromconfig(AVDTP SET_CONFIGURATION), matching the AVDTP state machine precisely. edgefast_bluetooth merges both into thebt_a2dp_configure/bt_a2dp_configure_endpointpath.bt_a2dp_stream_abortandbt_a2dp_stream_get_confighave no equivalent in edgefast_bluetooth.
7. Media Data Transfer#
⚠️ The media I/O model is fundamentally different. edgefast_bluetooth optionally integrates an SBC encoder/decoder; edgefast_open is always codec-agnostic.
edgefast_bluetooth - Source TX
/* If CONFIG_A2DP_CODEC_EXTERNAL is NOT set and codec is SBC: pass raw PCM */
/* Otherwise: pass BT_AVDTP_MEDIA_HDR_SIZE + 1-byte SBC payload header + SBC frames */
int bt_a2dp_src_media_write(struct bt_a2dp_endpoint *endpoint,
uint8_t *data, uint16_t datalen);
/* Multi-endpoint write (SBC only, CONFIG_BT_A2DP_WRITE_EXT) */
int bt_a2dp_src_media_write_ext(struct bt_a2dp_endpoint *endpoints[],
uint8_t *data, uint16_t datalen);
edgefast_open - Source TX
/* Allocate net_buf with AVDTP/L2CAP headroom pre-reserved */
struct net_buf *bt_a2dp_stream_create_pdu(struct net_buf_pool *pool, k_timeout_t timeout);
/* Send the RTP payload (caller fills seq_num and ts) */
int bt_a2dp_stream_send(struct bt_a2dp_stream *stream, struct net_buf *buf,
uint16_t seq_num, uint32_t ts);
edgefast_open exposes RTP sequence number and timestamp explicitly so the application controls packetisation. edgefast_bluetooth manages the RTP header internally.
edgefast_bluetooth - Sink RX (callback field in endpoint struct)
/* Registered as endpoint->control_cbs.sink_streamer_data */
void sink_streamer_data(struct bt_a2dp_endpoint *endpoint,
struct bt_a2dp_streaming_ctx *ctx);
/* After processing, notify the stack the buffer was consumed */
int bt_a2dp_snk_media_sync(struct bt_a2dp_endpoint *endpoint,
uint8_t *data, uint16_t datalen);
edgefast_open - Sink RX (callback in bt_a2dp_stream_ops)
/* Delivered directly as a net_buf with seq_num and timestamp */
void recv(struct bt_a2dp_stream *stream, struct net_buf *buf,
uint16_t seq_num, uint32_t ts);
edgefast_bluetooth requires an explicit
bt_a2dp_snk_media_synccall after processing each received buffer. edgefast_open has no such acknowledgement - thenet_bufreference is managed by the stack.
7.1 SBC Codec Responsibility#
⚠️ Critical difference: edgefast_bluetooth contains a built-in SBC encoder (source) and SBC decoder (sink) inside the stack. edgefast_open has no built-in codec - the application must link and drive an external SBC library (
zephyr/bluetooth/sbc.h) for every encode/decode operation.
Aspect |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
SBC encoder location |
Internal to stack; app feeds raw PCM |
Application - app calls |
SBC decoder location |
Internal to stack; stack decodes before calling |
Application - app calls |
PCM input for source |
|
App encodes PCM → SBC frames → inserts into |
PCM output for sink |
Stack delivers decoded PCM in |
App decodes SBC frames from |
Encoder bit-rate tuning |
|
App passes |
SBC library |
Bundled and hidden |
Explicit |
edgefast_open Source - Application-driven SBC encoding (examples/a2dp_source/app_a2dp_source.c)#
#include <zephyr/bluetooth/sbc.h>
/* App owns the encoder state */
struct sbc_encoder encoder;
/* After stream is configured, app initialises the encoder from negotiated SBC params */
static void sbc_stream_configured(struct bt_a2dp_stream *stream)
{
struct sbc_encoder_init_param param;
struct bt_a2dp_codec_sbc_params *sbc_config =
(struct bt_a2dp_codec_sbc_params *)&sbc_cfg_default.codec_config->codec_ie[0];
a2dp_src_sf = bt_a2dp_sbc_get_sampling_frequency(sbc_config);
a2dp_src_nc = bt_a2dp_sbc_get_channel_num(sbc_config);
param.bit_rate = CONFIG_BT_A2DP_SOURCE_SBC_BIT_RATE_DEFAULT;
param.samp_freq = a2dp_src_sf;
param.blk_len = bt_a2dp_sbc_get_block_length(sbc_config);
param.subband = bt_a2dp_sbc_get_subband_num(sbc_config);
param.alloc_mthd = bt_a2dp_sbc_get_allocation_method(sbc_config);
param.ch_mode = bt_a2dp_sbc_get_channel_mode(sbc_config); /* typed enum */
param.ch_num = bt_a2dp_sbc_get_channel_num(sbc_config);
param.min_bitpool = sbc_config->min_bitpool;
param.max_bitpool = sbc_config->max_bitpool;
sbc_setup_encoder(&encoder, ¶m); /* app initialises encoder */
bt_a2dp_stream_establish(stream); /* then opens the media channel */
}
/* In the periodic send callback, app encodes PCM → SBC frames into a net_buf */
static void audio_work_handler(struct k_work *work)
{
struct net_buf *buf = bt_a2dp_stream_create_pdu(&a2dp_tx_pool, K_FOREVER);
uint8_t *sbc_hdr = net_buf_add(buf, 1u); /* reserve SBC media header byte */
for (uint8_t i = 0; i < frame_num; i++) {
/* App calls sbc_encode() - stack does NOT encode */
uint32_t out_size = sbc_encode(&encoder,
&pcm_data[i * pcm_frame_size],
net_buf_tail(buf));
net_buf_add(buf, out_size);
}
*sbc_hdr = BT_A2DP_SBC_MEDIA_HDR_ENCODE(frame_num, 0, 0, 0);
bt_a2dp_stream_send(&app_a2dps[0].sbc_stream, buf, send_count, send_samples_count);
}
edgefast_open Sink - Application-driven SBC decoding (examples/a2dp_sink/audio_buf.c)#
#include <zephyr/bluetooth/sbc.h>
/* App owns the decoder state */
static struct sbc_decoder decoder;
/* App resets/initialises the decoder when a stream starts */
void audio_buf_reset(uint32_t fs)
{
sbc_setup_decoder(&decoder); /* app initialises decoder - stack does NOT decode */
/* ... configure pcm ring-buffer size based on sample frequency ... */
}
/* In the recv callback, app iterates over SBC frames and calls sbc_decode() itself */
void audio_process_sbc_buf(uint8_t sbc_hdr, uint8_t *data, size_t len,
uint16_t seq_num, uint32_t ts, uint8_t channel_num)
{
uint8_t num_frames = BT_A2DP_SBC_MEDIA_HDR_NUM_FRAMES_GET(sbc_hdr);
for (uint8_t i = 0; i < num_frames; i++) {
uint32_t out_size = sizeof(pcm_frame_buffer);
/* App calls sbc_decode() - stack delivers raw SBC bytes, not PCM */
int err = sbc_decode(&decoder, &in_data, &len,
pcm_frame_buffer, &out_size);
if (err == 0) {
audio_add_pcm_data((uint8_t *)pcm_frame_buffer, out_size);
}
}
}
In contrast, edgefast_bluetooth handles encoding/decoding internally. When
A2DP_CODEC_EXTERNALis not set (default), the app simply callsbt_a2dp_src_media_write(endpoint, pcm_data, len)with raw PCM and the stack encodes it using its built-in SBC encoder. On the sink side, thesink_streamer_datacallback delivers already-decoded PCM data. The app only needs to allocatecodec_bufferandcodec_buffer_nocachedin the endpoint struct; it never calls any SBC function directly.
MTU query - edgefast_open only 🔴
uint32_t bt_a2dp_get_mtu(struct bt_a2dp_stream *stream);
No equivalent in edgefast_bluetooth.
8. Delay Reporting#
edgefast_bluetooth (gated by CONFIG_BT_A2DP_DR_SERVICE)
/* Set the initial delay before streaming starts */
int bt_a2dp_set_initial_delay_report(struct bt_a2dp_endpoint *endpoint, int16_t delay);
/* Send a delay report during streaming */
int bt_a2dp_send_delay_report(struct bt_a2dp_endpoint *endpoint, int16_t delay);
Uses
int16_t delaywith unspecified units (implementation-defined). Feature is optional viaBT_A2DP_DR_SERVICE.
edgefast_open (capability flag delay_report on struct bt_a2dp_ep)
/* Sink sends delay report to source (value in 1/10 ms) */
int bt_a2dp_stream_delay_report(struct bt_a2dp_stream *stream, uint16_t delay);
/* Source receives delay via bt_a2dp_stream_ops callback */
void delay_report(struct bt_a2dp_stream *stream, uint16_t value);
edgefast_open uses
uint16_tin units of 1/10 milliseconds (per A2DP spec). Delay reporting capability is advertised per-EP via thedelay_reportbool field instruct bt_a2dp_ep. No separate Kconfig symbol is needed - it is always compiled in.
Aspect |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
API name |
|
|
Units |
|
|
Initial setup |
|
Not needed; first call to |
RX on source side |
Not exposed |
|
Kconfig gate |
|
Always compiled in |
9. Optional / Extended Services#
🟢 The following services exist only in edgefast_bluetooth with no edgefast_open equivalent.
Service |
edgefast_bluetooth function |
Kconfig gate |
|---|---|---|
Content Protection header |
|
|
Internal codec enable/disable |
|
|
Multi-endpoint SBC write |
|
|
Recovery service (config only) |
Endpoint field |
|
Reporting service (config only) |
Endpoint field |
|
Header compression (config only) |
Endpoint field |
|
Multiplexing service (config only) |
Endpoint field |
|
10. Callback Structures Comparison#
Connection-level callbacks#
Event |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
Connected |
|
|
Disconnected |
|
|
Discovery result |
Separate callback type |
|
Endpoint / Stream-level callbacks#
edgefast_bluetooth - struct bt_a2dp_ep_cb (fields in struct bt_a2dp_endpoint)
struct bt_a2dp_ep_cb {
void (*configured)(struct bt_a2dp_endpoint *endpoint);
void (*start_play)(struct bt_a2dp_endpoint *endpoint,
struct bt_a2dp_streaming_ctx *ctx);
void (*stop_play)(struct bt_a2dp_endpoint *endpoint);
void (*sink_streamer_data)(struct bt_a2dp_endpoint *endpoint,
struct bt_a2dp_streaming_ctx *ctx);
/* Optional (Kconfig-gated): */
void (*sink_delay_report_cb)(struct bt_a2dp_endpoint *endpoint,
uint16_t delay); /* BT_A2DP_DR_SERVICE */
};
edgefast_open - struct bt_a2dp_stream_ops (registered per-stream)
struct bt_a2dp_stream_ops {
void (*configured)(struct bt_a2dp_stream *stream);
void (*established)(struct bt_a2dp_stream *stream); /* AVDTP OPEN complete */
void (*released)(struct bt_a2dp_stream *stream); /* AVDTP CLOSE/ABORT complete */
void (*started)(struct bt_a2dp_stream *stream);
void (*suspended)(struct bt_a2dp_stream *stream);
/* Sink only: */
void (*recv)(struct bt_a2dp_stream *stream, struct net_buf *buf,
uint16_t seq_num, uint32_t ts);
/* Source only: */
void (*sent)(struct bt_a2dp_stream *stream); /* TX SDU completed by controller */
void (*delay_report)(struct bt_a2dp_stream *stream, uint16_t value);
};
edgefast_open has separate
established(OPEN),released(CLOSE or ABORT),started, andsuspendedcallbacks for every AVDTP state transition. edgefast_bluetooth collapses start/stop intostart_play/stop_playand has noestablishedorreleasedcallbacks.
Callback correspondence table#
Event |
edgefast_bluetooth callback |
edgefast_open callback |
|---|---|---|
SET_CONFIGURATION accepted |
|
|
OPEN / media channel ready |
- not separate - |
|
START accepted |
|
|
SUSPEND accepted |
|
|
CLOSE / ABORT done |
- not exposed - |
|
Sink media data received |
|
|
Source TX completed |
- not exposed - |
|
Delay report received (source) |
|
|
11. Full Function Comparison Table#
Function |
edgefast_bluetooth |
edgefast_open |
Notes |
|---|---|---|---|
|
|
|
🟡 Identical |
|
|
|
🟡 Identical |
Register connect callback |
|
|
🟡 Renamed; struct type changed |
Register endpoint |
|
|
🟡 Renamed; struct type changed |
Discover peer endpoints |
|
|
🟡 Renamed; callback delivery differs |
Auto configure |
|
- not present - |
🟢 edgefast_bluetooth only |
Configure specific EP |
|
|
🟡 stream object added in edgefast_open |
Get configuration |
- not present - |
|
🔴 edgefast_open only |
Open / establish media channel |
Part of |
|
🔴 edgefast_open only |
Start streaming |
|
|
🟡 Renamed; argument type changed |
Stop / suspend |
|
|
🟡 Renamed; argument type changed |
Release / close |
|
|
🟡 Renamed; argument type changed |
Reconfigure |
|
|
🟡 Renamed; argument type changed |
Abort |
- not present - |
|
🔴 edgefast_open only |
Register stream callbacks |
Embedded in endpoint struct ( |
|
🟡 Per-stream in edgefast_open |
Source TX |
|
|
🟡 net_buf + explicit RTP fields in edgefast_open |
Source TX (multi-endpoint) |
|
- not present - |
🟢 edgefast_bluetooth only |
Allocate TX PDU buffer |
- not present - |
|
🔴 edgefast_open only |
Sink RX ack |
|
- not needed (net_buf managed by stack) - |
🟢 edgefast_bluetooth only |
Get MTU |
- not present - |
|
🔴 edgefast_open only |
Send delay report |
|
|
🟡 Renamed; units clarified |
Set initial delay report |
|
- not needed - |
🟢 edgefast_bluetooth only |
Content protection header |
|
- not present - |
🟢 edgefast_bluetooth only |
Internal codec control |
|
- not present - |
🟢 edgefast_bluetooth only |
SBC get channel mode |
|
|
🔴 |
SBC get allocation method |
returns |
returns |
🟡 Typed return in edgefast_open |
12. A2DP Kconfig Configuration Comparison#
⚠️ Source files: edgefast_bluetooth -
middleware/edgefast_bluetooth/include/Kconfig| edgefast_open -middleware/edgefast_open/source/bluetooth/host/classic/Kconfig
ℹ️ Key difference: edgefast_bluetooth exposes many optional service Kconfig symbols (content protection, recovery, reporting, delay report, header compression, multiplexing, task tuning, SBC codec buffers) that are absent from edgefast_open. edgefast_open is simpler - it only exposes core protocol enables plus two AVDTP transport tunables.
12.1 Core Protocol Enablement#
Symbol |
edgefast_bluetooth |
edgefast_open |
Notes |
|---|---|---|---|
|
bool, default 0 |
bool (no default) |
AVDTP layer. edgefast_bluetooth is explicit |
|
bool, default 0 |
bool (no default); |
A2DP master enable. edgefast_open auto-selects AVDTP and implies LIBSBC |
|
bool, default 0 |
bool (no default) |
Source role enable. Semantically identical |
|
bool, default 0 |
bool (no default) |
Sink role enable. Semantically identical |
12.2 AVDTP Transport Tunables#
Symbol |
edgefast_bluetooth |
edgefast_open |
Notes |
|---|---|---|---|
|
- not present - |
int, default 2 |
RTP protocol version. edgefast_open exposes this; edgefast_bluetooth hard-codes it |
|
- not present - |
int, default 512, range 48–65535 |
Max AVDTP signalling SDU size. Only in edgefast_open |
12.3 Connection & Endpoint Limits#
Symbol |
edgefast_bluetooth |
edgefast_open |
Notes |
|---|---|---|---|
|
int, default |
- not present - |
edgefast_bluetooth caps simultaneous A2DP connections; edgefast_open derives the limit from the underlying ACL pool |
|
int, default 2 |
- not present - |
edgefast_bluetooth limits registered SEPs; edgefast_open has no equivalent symbol |
12.4 Codec Integration (edgefast_bluetooth only) 🟢#
Symbol |
Type |
Default |
Notes |
|---|---|---|---|
|
bool |
0 |
When set, disables the internal SBC encoder/decoder; app provides pre-encoded frames |
|
bool |
0 |
Enables |
|
bool |
0 |
Enables |
|
int |
0 |
PCM input buffer size for internal SBC encoder (source) |
|
int |
328 |
Target SBC bit-rate for internal encoder (source) |
|
int |
0 |
PCM output buffer size for internal SBC decoder (sink) |
|
int |
328 |
Number of SBC data indications buffered (sink) |
|
int |
328 |
Samples per data indication (sink) |
None of these symbols exist in edgefast_open because edgefast_open never integrates a codec internally.
12.5 Task / Thread Tuning (edgefast_bluetooth only) 🟢#
Symbol |
Type |
Default |
Notes |
|---|---|---|---|
|
int |
4 |
A2DP task priority (processes streamer data and retries) |
|
int |
2048 |
A2DP task stack size in bytes |
edgefast_open uses the Zephyr workqueue/thread model and does not expose separate A2DP task configuration symbols.
12.6 Optional AVDTP Services (edgefast_bluetooth only) 🟢#
Symbol |
Type |
Default |
Notes |
|---|---|---|---|
|
bool |
0 |
Content Protection service (SCMS-T etc.) - config only |
|
bool |
0 |
Recovery service - config only (data transfer not supported) |
|
bool |
0 |
Reporting service - config only (data transfer not supported) |
|
bool |
0 |
Delay Reporting service - enables |
|
bool |
0 |
Header Compression service - config only (data transfer not supported) |
|
bool |
0 |
Multiplexing service - config only (data transfer not supported) |
edgefast_open has none of these optional service symbols. Delay reporting is always available via
bt_a2dp_stream_delay_reportwith no Kconfig gate.
12.7 Side-by-Side Symbol Summary#
Symbol |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
|
bool, default 0 |
bool |
|
- |
int, default 2 |
|
- |
int, default 512 |
|
bool, default 0 |
bool |
|
bool, default 0 |
bool |
|
bool, default 0 |
bool |
|
int, default BT_MAX_CONN |
- |
|
int, default 2 |
- |
|
bool, default 0 |
- |
|
bool, default 0 |
- |
|
bool, default 0 |
- |
|
int, default 0 |
- |
|
int, default 328 |
- |
|
int, default 0 |
- |
|
int, default 328 |
- |
|
int, default 328 |
- |
|
int, default 4 |
- |
|
int, default 2048 |
- |
|
bool, default 0 |
- |
|
bool, default 0 |
- |
|
bool, default 0 |
- |
|
bool, default 0 |
- |
|
bool, default 0 |
- |
|
bool, default 0 |
- |
AVRCP#
Edgefast Bluetooth vs Edgefast Open - AVRCP API Differences#
Source:
middleware/edgefast_bluetooth/include/bluetooth/avrcp.hvsmiddleware/edgefast_open/include/zephyr/bluetooth/classic/avrcp.h+avrcp_cover_art.h
Badge |
Stack |
|---|---|
edgefast_bluetooth |
NXP Ethermind stack |
edgefast_open |
Zephyr open-source stack |
Legend: 🟢 Only in edgefast_bluetooth | 🔴 Only in edgefast_open | 🟡 Equivalent concept, different API
Contents#
1. Architecture & Design Philosophy#
⚠️ Fundamental difference: edgefast_bluetooth uses a unified flat model - a single
struct bt_conn *handle covers all AVRCP operations and onestruct bt_avrcp_cbhandles all events edgefast_open uses a role-split object model - CT (Controller) and TG (Target) are distinct typed objects with separate callback structures and function namespaces.
ℹ️ Cover Art: edgefast_bluetooth integrates cover art in
avrcp.husing a numericuint8_t handleedgefast_open puts cover art in a separateavrcp_cover_art.husing typed objects that embed BIP (Basic Imaging Profile), with explicit separate L2CAP and OBEX connection steps.
Aspect |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
Connection handle |
|
|
Role separation |
Single unified API; send functions implicitly act as CT, responses handled in same callback |
Explicit CT namespace ( |
Callback registration |
Single |
Two separate: |
Transaction labels |
Implicit - library manages internally |
Explicit |
Command data passing |
Typed structs per command (e.g. |
Pre-serialized |
Fragmentation / continuation |
App calls |
Library reassembles internally; no continuation API exposed to application |
Passthrough vendor-unique |
Inline |
Separate |
Cover art handle |
Numeric |
Typed |
Cover art dependency |
Self-contained in |
Depends on |
2. Header File Layout & Constants#
Item |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
AVRCP main header |
|
|
Cover Art header |
Integrated in |
Separate |
Operation IDs |
|
|
Notification events |
|
|
AV/C response codes |
|
|
AV/C command types |
|
|
Error / status codes |
Two separate sets: |
Single unified |
Button state |
Raw |
|
Capability IDs |
|
|
Scopes |
|
Embedded as |
3. Connection Management#
ℹ️ The browsing connect/disconnect functions have identical signatures in both stacks Only the control-channel connect name differs (
bt_avrcp_control_connectvsbt_avrcp_connect).
Control & Browsing Channel Connect / Disconnect + Callback Registration#
edgefast_bluetooth
int bt_avrcp_control_connect(struct bt_conn *conn)
int bt_avrcp_control_disconnect(struct bt_conn *conn)
int bt_avrcp_browsing_connect(struct bt_conn *conn)
int bt_avrcp_browsing_disconnect(struct bt_conn *conn)
int bt_avrcp_register_callback(struct bt_avrcp_cb *cb)
edgefast_open
int bt_avrcp_connect(struct bt_conn *conn)
int bt_avrcp_disconnect(struct bt_conn *conn)
int bt_avrcp_browsing_connect(struct bt_conn *conn)
int bt_avrcp_browsing_disconnect(struct bt_conn *conn)
int bt_avrcp_ct_register_cb(const struct bt_avrcp_ct_cb *cb)
int bt_avrcp_tg_register_cb(const struct bt_avrcp_tg_cb *cb)
4. CT (Controller) Functions#
ℹ️ edgefast_bluetooth sends CT commands via
struct bt_conn *with implicit role edgefast_open uses explicitstruct bt_avrcp_ct *cttyped objects with an explicituint8_t tidon every call All TG response functions are in the separate Section 5.
Both take
struct bt_conn *. In edgefast_open the resulting typedstruct bt_avrcp_ct */struct bt_avrcp_tg *objects are delivered viaconnectedcallbacks. Callback registration is split into two role-specific calls in edgefast_open vs one combined call in edgefast_bluetooth.
edgefast_bluetooth
int bt_avrcp_send_unit_info(struct bt_conn *conn)
int bt_avrcp_send_subunit_info(struct bt_conn *conn)
int bt_avrcp_response_info(struct bt_conn *conn, uint8_t subunit, uint8_t subunit_type, uint8_t tl)
CT send + TG response on same handle/callback.
edgefast_open
int bt_avrcp_ct_get_unit_info(struct bt_avrcp_ct *ct, uint8_t tid)
int bt_avrcp_ct_get_subunit_info(struct bt_avrcp_ct *ct, uint8_t tid)
int bt_avrcp_tg_send_unit_info_rsp(struct bt_avrcp_tg *tg, uint8_t tid, struct bt_avrcp_unit_info_rsp *rsp)
int bt_avrcp_tg_send_subunit_info_rsp(struct bt_avrcp_tg *tg, uint8_t tid)
CT request and TG response on completely separate typed objects and callback structures.
Both take
struct bt_conn *. In edgefast_open the resulting typedstruct bt_avrcp_ct */struct bt_avrcp_tg *objects are delivered viaconnectedcallbacks. Callback registration is split into two role-specific calls in edgefast_open vs one combined call in edgefast_bluetooth.
Passthrough (CT send / TG respond)#
edgefast_bluetooth
int bt_avrcp_send_passthrough(struct bt_conn *conn, uint8_t op_id, uint8_t vendor_op_id, uint8_t state_flag)
int bt_avrcp_response_passthrough(struct bt_conn *conn, uint8_t rsp_type, struct bt_avrcp_control_msg *cmd)
Both CT send and TG response use same
struct bt_conn *. Vendor-unique op ID is a separate inline parameter.
edgefast_open
int bt_avrcp_ct_passthrough(struct bt_avrcp_ct *ct, uint8_t tid, uint8_t opid, uint8_t state, const uint8_t *payload, uint8_t len)
int bt_avrcp_tg_send_passthrough_rsp(struct bt_avrcp_tg *tg, uint8_t tid, bt_avrcp_rsp_t result, struct net_buf *buf)
CT and TG are fully separate. For standard operations pass
NULL/0forpayload/len; for vendor-unique ops, pre-serialize the vendor data into the payload bytes. TG response pre-serializes the passthrough response (opid + state + optional opvu data) into anet_bufallocated viabt_avrcp_create_pdu(), then passes it tobt_avrcp_tg_send_passthrough_rsp. Theresultparameter usesbt_avrcp_rsp_tenum for the AV/C response code.
Capabilities Query#
edgefast_bluetooth
int bt_avrcp_get_company_id_supported(struct bt_conn *conn)
int bt_avrcp_get_event_supported(struct bt_conn *conn)
Two separate functions for company IDs (cap_id=0x02) and events (cap_id=0x03).
edgefast_open
int bt_avrcp_ct_get_caps(struct bt_avrcp_ct *ct, uint8_t tid, uint8_t cap_id)
int bt_avrcp_tg_get_caps(struct bt_avrcp_tg *tg, uint8_t tid, uint8_t status, struct net_buf *buf)
Single CT function with
cap_idparameter. TG responds with pre-serializednet_buf.
Play Status, Notifications & Continuation#
edgefast_bluetooth
int bt_avrcp_get_play_status(struct bt_conn *conn)
int bt_avrcp_register_notification(struct bt_conn *conn, uint8_t event, uint32_t playback_interval)
int bt_avrcp_request_continuing_rsp(struct bt_conn *conn, uint8_t pdu_id)
int bt_avrcp_abort_continuing_rsp(struct bt_conn *conn, uint8_t pdu_id)
edgefast_open
int bt_avrcp_ct_get_play_status(struct bt_avrcp_ct *ct, uint8_t tid)
int bt_avrcp_ct_register_notification(struct bt_avrcp_ct *ct, uint8_t tid, uint8_t event_id, uint32_t interval, bt_avrcp_notify_changed_cb_t cb)
int bt_avrcp_tg_notification(struct bt_avrcp_tg *tg, uint8_t tid, uint8_t status, uint8_t event_id, struct bt_avrcp_event_data *data)
No continuation APIs - library handles fragmentation internally.
bt_avrcp_ct_register_notificationtakes an optional per-registrationbt_avrcp_notify_changed_cb_tcallback (can beNULLto use the global CT callback). TG sends notifications viabt_avrcp_tg_notification()with a typedstruct bt_avrcp_event_data *(not anet_buf); the library serializes it internally.
Vendor Dependent / Player App Settings / Element Attributes#
edgefast_bluetooth
int bt_avrcp_send_vendor_dependent(struct bt_conn *conn, uint8_t pdu_id, void *parameter)
struct bt_avrcp_vendor* bt_avrcp_vendor_rsp_parse(struct bt_avrcp_vendor_header *header, struct net_buf *buf, uint16_t buf_len)
Generic dispatcher: single function for all vendor-dependent PDUs (player app setting, element attrs, etc). Caller casts
parameterto the correct struct per PDU ID. A parse helper is provided for responses.
edgefast_open CT
bt_avrcp_ct_list_player_app_setting_attrs(ct, tid)bt_avrcp_ct_list_player_app_setting_vals(ct, tid, attr_id)bt_avrcp_ct_get_curr_player_app_setting_val(ct, tid, buf)bt_avrcp_ct_set_player_app_setting_val(ct, tid, buf)bt_avrcp_ct_get_player_app_setting_attr_text(ct, tid, buf)bt_avrcp_ct_get_player_app_setting_val_text(ct, tid, buf)bt_avrcp_ct_inform_displayable_char_set(ct, tid, buf)bt_avrcp_ct_inform_batt_status_of_ct(ct, tid, batt_status)bt_avrcp_ct_get_element_attrs(ct, tid, buf)bt_avrcp_ct_set_addressed_player(ct, tid, player_id)bt_avrcp_ct_set_absolute_volume(ct, tid, absolute_volume)bt_avrcp_ct_play_item(ct, tid, buf)bt_avrcp_ct_add_to_now_playing(ct, tid, buf)
edgefast_open explodes the generic vendor-dependent PDU into individual strongly-typed functions per PDU ID. No generic dispatcher; each command has its own function with typed parameters or
struct net_buf *.bt_avrcp_set_addressed_playerandbt_avrcp_set_volumefrom edgefast_bluetooth map tobt_avrcp_ct_set_addressed_playerandbt_avrcp_ct_set_absolute_volumerespectively.
5. TG (Target) Functions#
⚠️ edgefast_bluetooth has no explicit TG role The TG-side response functions (
bt_avrcp_response_info,bt_avrcp_response_passthrough,bt_avrcp_response_vendor_dependent) are present but share the samestruct bt_conn *and callback edgefast_open has a complete, separate TG API namespace.
TG Response Functions (target-side responses to CT requests)#
edgefast_bluetooth (TG-side functions)
int bt_avrcp_response_info(struct bt_conn *conn, uint8_t subunit, uint8_t subunit_type, uint8_t tl)
int bt_avrcp_response_passthrough(struct bt_conn *conn, uint8_t rsp_type, struct bt_avrcp_control_msg *cmd)
int bt_avrcp_response_vendor_dependent(struct bt_conn *conn, uint8_t pdu_id, uint8_t rsp_type, uint8_t packet_type, uint8_t tl, void *rsp_param, uint16_t param_len)
TG responses use same
struct bt_conn *as CT sends.response_vendor_dependentis a generic dispatcher covering all vendor-dependent response PDU IDs.
edgefast_open (bt_avrcp_tg_ functions)*
bt_avrcp_tg_send_unit_info_rsp(tg, tid, rsp)bt_avrcp_tg_send_subunit_info_rsp(tg, tid)bt_avrcp_tg_send_passthrough_rsp(tg, tid, result, buf)bt_avrcp_tg_get_caps(tg, tid, status, buf)bt_avrcp_tg_notification(tg, tid, status, event_id, data)bt_avrcp_tg_list_player_app_setting_attrs(tg, tid, status, buf)bt_avrcp_tg_list_player_app_setting_vals(tg, tid, status, buf)bt_avrcp_tg_get_curr_player_app_setting_val(tg, tid, status, buf)bt_avrcp_tg_set_player_app_setting_val(tg, tid, status)bt_avrcp_tg_get_player_app_setting_attr_text(tg, tid, status, buf)bt_avrcp_tg_get_player_app_setting_val_text(tg, tid, status, buf)bt_avrcp_tg_inform_displayable_char_set(tg, tid, status)bt_avrcp_tg_inform_batt_status_of_ct(tg, tid, status)bt_avrcp_tg_absolute_volume(tg, tid, status, absolute_volume)bt_avrcp_tg_get_element_attrs(tg, tid, status, buf)bt_avrcp_tg_get_play_status(tg, tid, status, buf)bt_avrcp_tg_set_addressed_player(tg, tid, status)bt_avrcp_tg_play_item(tg, tid, status)bt_avrcp_tg_add_to_now_playing(tg, tid, status)
Each TG response function corresponds 1:1 to a specific AVRCP PDU. The response uses the same
tidreceived in the request callback. Data is pre-serialized asstruct net_buf *bufwhere non-trivial, or a simple status code for acknowledgment-only responses.
6. Browsing Channel Functions#
ℹ️ Both stacks implement a full browsing channel API The fundamental design difference (typed CT/TG objects vs bt_conn, explicit tid) applies to browsing too edgefast_bluetooth uses typed structs for browsing commands; edgefast_open uses net_buf for complex browsing commands.
Browsing Channel Commands & Responses#
edgefast_bluetooth
int bt_avrcp_get_folder_items(struct bt_conn *conn, struct bt_avrcp_get_folder_items_cmd *param)
int bt_avrcp_change_path(struct bt_conn *conn, struct bt_avrcp_change_path_cmd *param)
int bt_avrcp_set_borwsed_player(struct bt_conn *conn, uint16_t player_id)
int bt_avrcp_get_items_attribute(struct bt_conn *conn, struct bt_avrcp_get_item_attrs_cmd *param)
int bt_avrcp_search(struct bt_conn *conn, struct bt_avrcp_search_cmd *param)
int bt_avrcp_get_total_num_of_items(struct bt_conn *conn, uint8_t scope)
int bt_avrcp_response_browsing(struct bt_conn *conn, uint8_t pdu_id, uint8_t tl, void *rsp_param, uint16_t param_len)
CT send functions use typed command structs. TG response is a single generic
bt_avrcp_response_browsing()dispatcher (void* parameter cast per PDU ID). Note:bt_avrcp_set_borwsed_playerhas a typo (“borwsed”) in the original header.
edgefast_open CT + TG browsing
int bt_avrcp_ct_set_browsed_player(struct bt_avrcp_ct *ct, uint8_t tid, uint16_t player_id)
int bt_avrcp_ct_get_folder_items(struct bt_avrcp_ct *ct, uint8_t tid, struct net_buf *buf)
int bt_avrcp_ct_change_path(struct bt_avrcp_ct *ct, uint8_t tid, struct net_buf *buf)
int bt_avrcp_ct_get_item_attrs(struct bt_avrcp_ct *ct, uint8_t tid, struct net_buf *buf)
int bt_avrcp_ct_get_total_number_of_items(struct bt_avrcp_ct *ct, uint8_t tid, uint8_t scope)
int bt_avrcp_ct_search(struct bt_avrcp_ct *ct, uint8_t tid, struct net_buf *buf)
int bt_avrcp_tg_set_browsed_player(struct bt_avrcp_tg *tg, uint8_t tid, struct net_buf *buf)
int bt_avrcp_tg_get_folder_items(struct bt_avrcp_tg *tg, uint8_t tid, struct net_buf *buf)
int bt_avrcp_tg_change_path(struct bt_avrcp_tg *tg, uint8_t tid, uint8_t status, uint32_t num_items)
int bt_avrcp_tg_get_item_attrs(struct bt_avrcp_tg *tg, uint8_t tid, struct net_buf *buf)
int bt_avrcp_tg_get_total_number_of_items(struct bt_avrcp_tg *tg, uint8_t tid, struct net_buf *buf)
int bt_avrcp_tg_search(struct bt_avrcp_tg *tg, uint8_t tid, struct net_buf *buf)
int bt_avrcp_tg_browsing_general_reject(struct bt_avrcp_tg *tg, uint8_t tid, uint8_t status)
edgefast_open fixes the typo:
bt_avrcp_ct_set_browsed_player(correct spelling). TG responses are per-PDU. A newbt_avrcp_tg_browsing_general_reject()API allows sending a GENERAL_REJECT browsing response.
Key Browsing API Design Differences#
Function |
edgefast_bluetooth signature |
edgefast_open equivalent |
Notes |
|---|---|---|---|
Set Browsed Player (CT) |
|
|
Typo fixed in edgefast_open. Explicit tid added. |
Get Folder Items (CT) |
|
|
Typed struct vs pre-serialized net_buf. |
Change Path (CT) |
|
|
Typed struct vs net_buf. |
Get Item Attrs (CT) |
|
|
Name simplified in edgefast_open. |
Search (CT) |
|
|
Typed struct vs net_buf. |
Get Total Num Items (CT) |
|
|
Name slightly different; tid added. |
Browsing response (TG) |
|
Per-PDU TG functions: |
edgefast_open splits into per-PDU TG calls. |
General Reject (TG) |
Not present |
|
New in edgefast_open. |
7. Cover Art Functions#
⚠️ Cover art is optional in both stacks edgefast_bluetooth guards cover art with Kconfig (
CONFIG_BT_AVRCP_COVER_ART_INITIATOR/_RESPONDER) edgefast_open uses a separate header file (avrcp_cover_art.h) that depends onclassic/bip.h.
Cover Art API Comparison
edgefast_bluetooth (in avrcp.h, handle-based)
int bt_avrcp_register_cover_art_cb(struct bt_avrcp_cover_art_cb *cb)
int bt_avrcp_cover_art_start_initiator(uint8_t *handle)
int bt_avrcp_cover_art_stop_initiator(uint8_t handle)
int bt_avrcp_cover_art_start_responder(uint8_t *handle)
int bt_avrcp_cover_art_stop_responder(uint8_t handle)
int bt_avrcp_cover_art_connect(uint8_t handle, struct bt_conn *conn, struct bt_avrcp_cover_art_connect *cmd)
int bt_avrcp_cover_art_disconnect(uint8_t handle)
int bt_avrcp_get_image_property(uint8_t handle, struct bt_avrcp_get_image_property *param)
int bt_avrcp_get_image(uint8_t handle, struct bt_avrcp_get_image *param)
int bt_avrcp_get_linked_thumbnail(uint8_t handle, struct bt_avrcp_get_linked_thumbnail *param)
int bt_avrcp_abort(uint8_t handle)
int bt_avrcp_send_request(uint8_t handle, uint8_t wait, struct bt_avrcp_cover_art_rsp *rsp)
int bt_avrcp_response_cover_art(uint8_t handle, uint8_t cmd, uint8_t response, void *rsp)
edgefast_open (in avrcp_cover_art.h, typed objects)
int bt_avrcp_cover_art_ct_cb_register(struct bt_avrcp_cover_art_ct_cb *cb)
int bt_avrcp_cover_art_tg_cb_register(struct bt_avrcp_cover_art_tg_cb *cb)
int bt_avrcp_cover_art_ct_l2cap_connect(struct bt_avrcp_ct *ct, struct bt_avrcp_cover_art_ct **cover_art_ct, uint16_t psm)
int bt_avrcp_cover_art_ct_l2cap_disconnect(struct bt_avrcp_cover_art_ct *ct)
int bt_avrcp_cover_art_tg_l2cap_disconnect(struct bt_avrcp_cover_art_tg *tg)
struct net_buf *bt_avrcp_cover_art_ct_create_pdu(struct bt_avrcp_cover_art_ct *ct, struct net_buf_pool *pool)
struct net_buf *bt_avrcp_cover_art_tg_create_pdu(struct bt_avrcp_cover_art_tg *tg, struct net_buf_pool *pool)
int bt_avrcp_cover_art_ct_connect(struct bt_avrcp_cover_art_ct *ct)
int bt_avrcp_cover_art_tg_connect(struct bt_avrcp_cover_art_tg *tg, uint8_t rsp_code)
int bt_avrcp_cover_art_ct_disconnect(struct bt_avrcp_cover_art_ct *ct)
int bt_avrcp_cover_art_tg_disconnect(struct bt_avrcp_cover_art_tg *tg, uint8_t rsp_code)
int bt_avrcp_cover_art_ct_abort(struct bt_avrcp_cover_art_ct *ct, struct net_buf *buf)
int bt_avrcp_cover_art_tg_abort(struct bt_avrcp_cover_art_tg *tg, uint8_t rsp_code, struct net_buf *buf)
int bt_avrcp_cover_art_ct_get_image_properties(struct bt_avrcp_cover_art_ct *ct, bool final, struct net_buf *buf)
int bt_avrcp_cover_art_tg_get_image_properties(struct bt_avrcp_cover_art_tg *tg, uint8_t rsp_code, struct net_buf *buf)
int bt_avrcp_cover_art_ct_get_image(struct bt_avrcp_cover_art_ct *ct, bool final, struct net_buf *buf)
int bt_avrcp_cover_art_tg_get_image(struct bt_avrcp_cover_art_tg *tg, uint8_t rsp_code, struct net_buf *buf)
int bt_avrcp_cover_art_ct_get_linked_thumbnail(struct bt_avrcp_cover_art_ct *ct, bool final, struct net_buf *buf)
int bt_avrcp_cover_art_tg_get_linked_thumbnail(struct bt_avrcp_cover_art_tg *tg, uint8_t rsp_code, struct net_buf *buf)
Every operation has a paired CT (initiator) and TG (responder) function. L2CAP transport connect/disconnect is explicit and separate from OBEX-layer connect/disconnect. PDU buffers are allocated via bt_avrcp_cover_art_ct/tg_create_pdu().
Cover Art Design Differences#
Aspect |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
Object type |
Numeric |
Typed struct pointers |
Role creation |
|
CT object delivered in |
L2CAP vs OBEX |
Single connect function combining L2CAP + OBEX |
Explicit separate steps: |
Callback structure |
Single |
Separate |
Get image property name |
|
|
Buffer model |
Typed parameter structs per command |
Pre-allocated |
PDU buffer allocation |
No explicit allocation API |
|
8. Callback Structures Comparison#
ℹ️ edgefast_bluetooth has one unified
struct bt_avrcp_cbcovering all events for both CT and TG roles edgefast_open has separatestruct bt_avrcp_ct_cbandstruct bt_avrcp_tg_cb, each with per-operation callback members matching the corresponding send function.
Event |
edgefast_bluetooth (bt_avrcp_cb) |
edgefast_open (bt_avrcp_ct_cb / bt_avrcp_tg_cb) |
|---|---|---|
Connected |
|
CT: |
Disconnected |
|
CT: |
Browsing connected |
|
CT: |
Browsing disconnected |
|
CT: |
Control received (TG) |
|
TG: per-command callbacks - |
Control rsp received (CT) |
|
CT: per-command response callbacks - |
Vendor dep. continue (CT) |
|
Not exposed - handled internally |
Browsing received (TG) |
|
TG: per-command callbacks - |
Browsing rsp received (CT) |
|
CT: per-command response callbacks - |
Cover art callbacks |
Single |
Separate |
9. Full Function Comparison Table#
ℹ️ Yellow = conceptually equivalent but different signature Green = only in edgefast_bluetooth Red = only in edgefast_open.
edgefast_bluetooth function |
edgefast_open equivalent |
Key difference |
|---|---|---|
bt_avrcp_register_callback |
bt_avrcp_ct_register_cb + bt_avrcp_tg_register_cb |
Split into two role-specific registrations |
bt_avrcp_control_connect(conn) |
bt_avrcp_connect(conn) |
Renamed only |
bt_avrcp_control_disconnect(conn) |
bt_avrcp_disconnect(conn) |
Renamed only |
bt_avrcp_browsing_connect(conn) |
bt_avrcp_browsing_connect(conn) |
Identical |
bt_avrcp_browsing_disconnect(conn) |
bt_avrcp_browsing_disconnect(conn) |
Identical |
bt_avrcp_send_unit_info(conn) |
bt_avrcp_ct_get_unit_info(ct, tid) |
Typed CT object + tid added |
bt_avrcp_send_subunit_info(conn) |
bt_avrcp_ct_get_subunit_info(ct, tid) |
Typed CT object + tid added |
bt_avrcp_response_info(conn, subunit, type, tl) |
bt_avrcp_tg_send_unit_info_rsp(tg, tid, rsp) |
Separate TG typed object; typed response struct |
bt_avrcp_send_passthrough(conn, op_id, vendor_op_id, state) |
bt_avrcp_ct_passthrough(ct, tid, opid, state, payload, len) |
Raw byte payload instead of typed struct ptr; tid; typed ct |
bt_avrcp_response_passthrough(conn, rsp_type, cmd*) |
bt_avrcp_tg_send_passthrough_rsp(tg, tid, result, buf) |
Pre-serialized net_buf instead of opid/state params; rsp_type is bt_avrcp_rsp_t enum |
bt_avrcp_get_company_id_supported(conn) |
bt_avrcp_ct_get_caps(ct, tid, BT_AVRCP_CAP_COMPANY_ID) |
Merged into single function with cap_id param |
bt_avrcp_get_event_supported(conn) |
bt_avrcp_ct_get_caps(ct, tid, BT_AVRCP_CAP_EVENTS_SUPPORTED) |
Merged into single function with cap_id param |
bt_avrcp_get_play_status(conn) |
bt_avrcp_ct_get_play_status(ct, tid) |
Typed CT object + tid |
bt_avrcp_register_notification(conn, event, interval) |
bt_avrcp_ct_register_notification(ct, tid, event_id, interval, cb) |
Typed CT object + tid + per-registration callback added |
bt_avrcp_request_continuing_rsp(conn, pdu_id) |
No equivalent - handled internally |
Library manages fragmentation in edgefast_open |
bt_avrcp_abort_continuing_rsp(conn, pdu_id) |
No equivalent - handled internally |
Library manages fragmentation in edgefast_open |
bt_avrcp_set_volume(conn, volume) |
bt_avrcp_ct_set_absolute_volume(ct, tid, absolute_volume) |
Renamed; typed CT object + tid |
bt_avrcp_set_addressed_player(conn, player_id) |
bt_avrcp_ct_set_addressed_player(ct, tid, player_id) |
Typed CT object + tid |
bt_avrcp_send_vendor_dependent(conn, pdu_id, void*) |
Individual per-PDU functions: bt_avrcp_ct_list_player_app_setting_attrs, bt_avrcp_ct_get_element_attrs, etc. |
Generic dispatcher replaced by per-PDU typed functions |
bt_avrcp_vendor_rsp_parse(header*, buf, len) |
No equivalent - responses delivered via per-PDU callbacks |
Not needed in edgefast_open due to per-operation callbacks |
bt_avrcp_response_vendor_dependent(conn, pdu_id, rsp_type, pkt_type, tl, param*, len) |
Individual per-PDU TG functions: bt_avrcp_tg_get_play_status, bt_avrcp_tg_get_element_attrs, etc. |
Generic dispatcher replaced by per-PDU TG functions |
bt_avrcp_set_borwsed_player(conn, player_id) [typo] |
bt_avrcp_ct_set_browsed_player(ct, tid, player_id) |
Typo fixed; typed CT object + tid |
bt_avrcp_get_folder_items(conn, cmd*) |
bt_avrcp_ct_get_folder_items(ct, tid, buf) |
Typed struct replaced by net_buf |
bt_avrcp_change_path(conn, cmd*) |
bt_avrcp_ct_change_path(ct, tid, buf) |
Typed struct replaced by net_buf |
bt_avrcp_get_items_attribute(conn, cmd*) |
bt_avrcp_ct_get_item_attrs(ct, tid, buf) |
Renamed + typed struct replaced by net_buf |
bt_avrcp_search(conn, cmd*) |
bt_avrcp_ct_search(ct, tid, buf) |
Typed struct replaced by net_buf |
bt_avrcp_get_total_num_of_items(conn, scope) |
bt_avrcp_ct_get_total_number_of_items(ct, tid, scope) |
Slightly renamed; typed CT + tid |
bt_avrcp_response_browsing(conn, pdu_id, tl, void*, len) |
Per-PDU: bt_avrcp_tg_get_folder_items, bt_avrcp_tg_change_path, bt_avrcp_tg_search, etc. |
Generic dispatcher split into per-PDU TG functions |
No equivalent |
bt_avrcp_tg_browsing_general_reject(tg, tid, status) |
New in edgefast_open |
bt_avrcp_register_cover_art_cb(cb) |
bt_avrcp_cover_art_ct_cb_register(cb) + bt_avrcp_cover_art_tg_cb_register(cb) |
Split into CT and TG |
bt_avrcp_cover_art_start_initiator(handle*) |
Implicit - ct object created on l2cap_connected callback |
Different lifecycle model |
bt_avrcp_cover_art_stop_initiator(handle) |
No direct equivalent |
Lifecycle managed by L2CAP disconnect |
bt_avrcp_cover_art_start_responder(handle*) |
Implicit - tg object created on l2cap_connected callback |
Different lifecycle model |
bt_avrcp_cover_art_stop_responder(handle) |
No direct equivalent |
Lifecycle managed by L2CAP disconnect |
bt_avrcp_cover_art_connect(handle, conn, cmd*) |
bt_avrcp_cover_art_ct_l2cap_connect(ct, cover_art_ct**, psm) then bt_avrcp_cover_art_ct_connect(ct) |
L2CAP and OBEX connect are separate steps |
bt_avrcp_cover_art_disconnect(handle) |
bt_avrcp_cover_art_ct_l2cap_disconnect(ct) |
Typed CT object |
bt_avrcp_get_image_property(handle, param*) |
bt_avrcp_cover_art_ct_get_image_properties(ct, final, buf) |
Typed CT; net_buf; bool final for fragmentation |
bt_avrcp_get_image(handle, param*) |
bt_avrcp_cover_art_ct_get_image(ct, final, buf) |
Typed CT; net_buf; bool final |
bt_avrcp_get_linked_thumbnail(handle, param*) |
bt_avrcp_cover_art_ct_get_linked_thumbnail(ct, final, buf) |
Typed CT; net_buf; bool final |
bt_avrcp_abort(handle) |
bt_avrcp_cover_art_ct_abort(ct, buf) |
Typed CT; optional net_buf for abort data |
bt_avrcp_send_request(handle, wait, rsp*) |
No equivalent - OBEX continuation handled via bool final parameter |
Different continuation model |
bt_avrcp_response_cover_art(handle, cmd, response, void*) |
bt_avrcp_cover_art_tg_get_image_properties / _get_image / _get_linked_thumbnail / _abort |
Generic response split into per-operation TG functions |
10. Architecture Summary#
ℹ️ Key architectural distinction: edgefast_bluetooth wraps the NXP Ethermind proprietary Bluetooth stack with a unified
struct bt_conn *-based API edgefast_open is the upstream Zephyr Bluetooth stack with a fully role-split, object-oriented API design where CT and TG are first-class typed objects throughout.
Dimension |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
Underlying stack |
NXP Ethermind (proprietary) |
Zephyr BT Host (open-source) |
Header location |
|
|
Connection object |
|
Typed |
Role model |
Unified flat namespace; implicit role by function chosen |
Explicit CT/TG namespaces; same operation has two typed functions |
Transaction IDs |
Library-managed, not exposed to application |
Explicit |
Callback model |
Single |
Separate |
Vendor-dependent PDUs |
Generic |
Individual per-PDU typed functions (13+ CT functions) |
Browsing TG responses |
Single |
Per-PDU TG response functions; new |
Fragmentation control |
App calls |
Internal; |
Data passing |
Typed structs per command (e.g. |
|
Cover art header |
Integrated in |
Separate |
Set browsed player typo |
|
|
Constants style |
|
|
Total AVRCP functions |
~30 control + browsing + cover art functions |
55+ CT and TG functions across control, browsing, and cover art |
11. edgefast_open API Usage Examples#
ℹ️ Each snippet below shows a minimal but complete usage pattern for edgefast_open AVRCP APIs that differ from edgefast_bluetooth All snippets assume Zephyr RTOS conventions (
struct net_buf,sys_put_be*, etc.).
bt_avrcp_ct_register_cb / bt_avrcp_tg_register_cb CT + TG
Register role-split callbacks before any connection. CT and TG callbacks are separate structures with per-operation function pointers.
/* ── Define CT callback structure ── */
static void avrcp_ct_connected(struct bt_avrcp_ct *ct) {
/* Save ct pointer for later sends */
my_ct = ct;
}
static void avrcp_ct_unit_info_rsp(struct bt_avrcp_ct *ct, uint8_t tid,
struct bt_avrcp_unit_info_rsp *rsp) {
printk("Unit type=0x%02x subunit_id=0x%02x\n", rsp->unit_type, rsp->subunit_id);
}
static const struct bt_avrcp_ct_cb ct_cb = {
.connected = avrcp_ct_connected,
.unit_info = avrcp_ct_unit_info_rsp,
/* ... fill remaining per-operation callbacks ... */
};
/* ── Define TG callback structure ── */
static void avrcp_tg_connected(struct bt_avrcp_tg *tg) { my_tg = tg; }
static const struct bt_avrcp_tg_cb tg_cb = {
.connected = avrcp_tg_connected,
/* ... fill remaining per-operation callbacks ... */
};
/* ── Register (call once at init, before bt_enable) ── */
bt_avrcp_ct_register_cb(&ct_cb);
bt_avrcp_tg_register_cb(&tg_cb);
bt_avrcp_connect / bt_avrcp_disconnect Control channel
Open and close the AVRCP control channel. Both take a plain struct bt_conn *. The resulting typed CT/TG objects are delivered in the connected callbacks.
/* In BR/EDR connection callback - initiate AVRCP after ACL is up */
static void br_connected(struct bt_conn *conn, uint8_t err) {
if (!err) {
bt_avrcp_connect(conn); /* triggers ct_cb.connected / tg_cb.connected */
}
}
/* Close control channel */
bt_avrcp_disconnect(conn);
/* Optional: open browsing channel after control is up */
bt_avrcp_browsing_connect(conn);
bt_avrcp_browsing_disconnect(conn);
bt_avrcp_ct_get_unit_info CT
Query the target’s unit info. tid is the transaction label (0-15); the same tid is echoed back in the unit_info response callback so requests and responses can be matched.
uint8_t tid = 0; /* application-chosen, 0-15 */
int err = bt_avrcp_ct_get_unit_info(my_ct, tid);
if (err) {
printk("Unit info request failed: %d\n", err);
}
/* Result arrives in ct_cb.unit_info(ct, tid, rsp) */
bt_avrcp_ct_passthrough CT
Send a passthrough command (e.g. PLAY, PAUSE). Pass NULL/0 for payload/len for standard operations. For vendor-unique operations, pre-serialize the struct bt_avrcp_passthrough_opvu_data fields into a byte buffer and pass it as payload with the appropriate len.
/* Send PLAY key press - no vendor-unique payload */
bt_avrcp_ct_passthrough(my_ct, tid,
BT_AVRCP_OPID_PLAY,
BT_AVRCP_BUTTON_PRESSED,
NULL, 0); /* no vendor-unique data */
/* Follow immediately with key release (per AVRCP spec) */
bt_avrcp_ct_passthrough(my_ct, tid + 1,
BT_AVRCP_OPID_PLAY,
BT_AVRCP_BUTTON_RELEASED,
NULL, 0);
/* Result arrives in ct_cb.passthrough(ct, tid, rsp) */
bt_avrcp_tg_send_passthrough_rsp TG
Respond to a passthrough command received in tg_cb.passthrough(tg, tid, buf). The response body (opid + state + optional vendor-unique data) must be pre-serialized into a net_buf allocated with bt_avrcp_create_pdu(). Use the BT_AVRCP_PASSTHROUGH_SET_STATE_OPID() macro to pack the state and opid fields.
/* Inside tg_cb.passthrough callback: */
static void tg_passthrough(struct bt_avrcp_tg *tg, uint8_t tid,
struct net_buf *cmd_buf) {
struct bt_avrcp_passthrough_cmd *cmd;
struct bt_avrcp_passthrough_rsp *rsp;
bt_avrcp_opid_t opid;
bt_avrcp_button_state_t state;
struct net_buf *buf;
int err;
cmd = net_buf_pull_mem(cmd_buf, sizeof(*cmd));
state = BT_AVRCP_PASSTHROUGH_GET_STATE(cmd);
opid = BT_AVRCP_PASSTHROUGH_GET_OPID(cmd);
buf = bt_avrcp_create_pdu(NULL);
if (!buf) { return; }
rsp = net_buf_add(buf, sizeof(*rsp));
BT_AVRCP_PASSTHROUGH_SET_STATE_OPID(rsp, state, opid);
rsp->data_len = 0;
/* Accept PLAY, reject everything else */
bt_avrcp_rsp_t result = (opid == BT_AVRCP_OPID_PLAY)
? BT_AVRCP_RSP_ACCEPTED
: BT_AVRCP_RSP_NOT_IMPLEMENTED;
err = bt_avrcp_tg_send_passthrough_rsp(tg, tid, result, buf);
if (err < 0) { net_buf_unref(buf); }
}
bt_avrcp_ct_get_caps CT
Single function replaces edgefast_bluetooth’s two separate functions. Use BT_AVRCP_CAP_COMPANY_ID or BT_AVRCP_CAP_EVENTS_SUPPORTED as the cap_id argument.
/* Query which events the TG supports */
bt_avrcp_ct_get_caps(my_ct, tid, BT_AVRCP_CAP_EVENTS_SUPPORTED);
/* Query company IDs */
bt_avrcp_ct_get_caps(my_ct, tid + 1, BT_AVRCP_CAP_COMPANY_ID);
/* Result arrives in ct_cb.get_caps(ct, tid, rsp) */
bt_avrcp_ct_get_play_status / bt_avrcp_tg_get_play_status CT + TG
CT queries current play status; TG responds with a pre-serialized net_buf containing song length, position, and play status.
/* CT side: send request */
bt_avrcp_ct_get_play_status(my_ct, tid);
/* Response in ct_cb.get_play_status(ct, tid, rsp) */
/* TG side: respond in tg_cb.get_play_status(tg, tid) callback */
static void tg_get_play_status_cb(struct bt_avrcp_tg *tg, uint8_t tid) {
struct bt_avrcp_get_play_status_rsp *rsp;
struct net_buf *buf;
buf = bt_avrcp_create_vendor_pdu(&avrcp_tx_pool);
if (buf == NULL) { return; }
rsp = net_buf_add(buf, sizeof(*rsp));
rsp->song_length = sys_cpu_to_be32(song_length_ms);
rsp->song_position = sys_cpu_to_be32(song_position_ms);
rsp->play_status = BT_AVRCP_PLAYBACK_STATUS_PLAYING;
bt_avrcp_tg_get_play_status(tg, tid, BT_AVRCP_STATUS_OK, buf);
net_buf_unref(buf);
}
bt_avrcp_ct_register_notification / bt_avrcp_tg_notification CT + TG
CT registers for a specific event notification. The fifth parameter is an optional per-registration bt_avrcp_notify_changed_cb_t callback (pass NULL to skip per-registration CHANGED delivery). TG calls bt_avrcp_tg_notification() with a typed struct bt_avrcp_event_data *; the library handles serialization internally. The first call with BT_AVRCP_STATUS_SUCCESS sends an INTERIM response (delivered to the CT notification callback); the next call for the same event sends a CHANGED response (delivered to bt_avrcp_notify_changed_cb_t). A non-SUCCESS status sends a REJECTED response (also delivered to the notification callback). No continuation API is needed.
/* Per-registration CHANGED callback for playback status events */
static void playback_status_changed(struct bt_avrcp_ct *ct, uint8_t event_id,
struct bt_avrcp_event_data *data)
{
printk("Playback status changed: %d\n", data->play_status);
}
/* CT: register for playback status change events */
bt_avrcp_ct_register_notification(my_ct, tid,
BT_AVRCP_EVT_PLAYBACK_STATUS_CHANGED,
0, /* playback_interval=0 (not used for this event) */
playback_status_changed); /* invoked on CHANGED notifications */
/* TG: send interim notification from tg_cb.register_notification callback */
static void tg_register_notif(struct bt_avrcp_tg *tg, uint8_t tid,
uint8_t event_id, uint32_t interval) {
struct bt_avrcp_event_data data;
memset(&data, 0, sizeof(data));
data.play_status = BT_AVRCP_PLAYBACK_STATUS_PLAYING;
/* BT_AVRCP_STATUS_SUCCESS causes library to send INTERIM first,
then CHANGED on subsequent calls */
bt_avrcp_tg_notification(tg, tid, BT_AVRCP_STATUS_SUCCESS,
event_id, &data);
}
/* TG: send volume-changed notification */
struct bt_avrcp_event_data vdata;
memset(&vdata, 0, sizeof(vdata));
vdata.absolute_volume = current_volume;
bt_avrcp_tg_notification(my_tg, saved_tid, BT_AVRCP_STATUS_SUCCESS,
BT_AVRCP_EVT_VOLUME_CHANGED, &vdata);
bt_avrcp_ct_set_absolute_volume / bt_avrcp_tg_absolute_volume CT + TG
CT sends a Set Absolute Volume command (renamed from bt_avrcp_set_volume in edgefast_bluetooth). TG confirms the accepted volume level.
/* CT: set absolute volume to 50% (0x3F out of 0x7F) */
bt_avrcp_ct_set_absolute_volume(my_ct, tid, 0x3F);
/* Response in ct_cb.set_absolute_volume(ct, tid, accepted_vol) */
/* TG: respond from tg_cb.set_absolute_volume(tg, tid, requested_vol) */
static void tg_set_volume(struct bt_avrcp_tg *tg, uint8_t tid,
uint8_t vol) {
uint8_t accepted = apply_volume(vol); /* clamp to hw range */
bt_avrcp_tg_absolute_volume(tg, tid, BT_AVRCP_STATUS_OK, accepted);
}
bt_avrcp_ct_set_addressed_player CT
Direct per-PDU function replacing the generic bt_avrcp_send_vendor_dependent(pdu_id, void*) dispatcher from edgefast_bluetooth.
/* Select player with ID 1 as the addressed player */
bt_avrcp_ct_set_addressed_player(my_ct, tid, 1);
/* Response in ct_cb.set_addressed_player(ct, tid, status) */
bt_avrcp_ct_get_element_attrs CT
Request track metadata (title, artist, album, etc.). The command payload is serialized into a net_buf using a typed struct bt_avrcp_get_element_attrs_cmd pointer, followed by optional per-attribute uint32_t IDs appended with net_buf_add_be32.
struct bt_avrcp_get_element_attrs_cmd *cmd;
struct net_buf *buf;
uint64_t identifier = 0; /* 0 = currently playing item */
buf = bt_avrcp_create_vendor_pdu(&avrcp_tx_pool);
if (buf == NULL) { return -ENOMEM; }
cmd = net_buf_add(buf, sizeof(*cmd));
memcpy(cmd->identifier, &identifier, sizeof(identifier));
cmd->num_attrs = 2; /* request Title + Artist */
net_buf_add_be32(buf, 0x01); /* TITLE */
net_buf_add_be32(buf, 0x02); /* ARTIST */
bt_avrcp_ct_get_element_attrs(my_ct, tid, buf);
/* Response in ct_cb.get_element_attrs(ct, tid, rsp) */
bt_avrcp_ct_list_player_app_setting_attrs CT
One of the per-PDU replacements for the generic bt_avrcp_send_vendor_dependent dispatcher. No payload required for listing attributes.
/* Step 1: list available player app setting attribute IDs */
bt_avrcp_ct_list_player_app_setting_attrs(my_ct, tid);
/* Response in ct_cb.list_player_app_setting_attrs(ct, tid, rsp) */
/* Step 2 (in callback): list values for attribute 0x01 (Equalizer) */
bt_avrcp_ct_list_player_app_setting_vals(my_ct, tid + 1, 0x01);
/* Response in ct_cb.list_player_app_setting_vals(ct, tid, rsp) */
bt_avrcp_ct_set_browsed_player CT (Browsing)
Fixes the bt_avrcp_set_borwsed_player typo from edgefast_bluetooth. Requires the browsing channel to be established first via bt_avrcp_browsing_connect.
/* Must have browsing channel open already */
bt_avrcp_ct_set_browsed_player(my_ct, tid, player_id);
/* Response in ct_cb.set_browsed_player(ct, tid, rsp) */
bt_avrcp_ct_get_folder_items / bt_avrcp_tg_get_folder_items CT + TG (Browsing)
Replaces the typed-struct approach of edgefast_bluetooth with a pre-serialized net_buf. Fields are written through a typed struct bt_avrcp_get_folder_items_cmd pointer cast from net_buf_add.
struct bt_avrcp_get_folder_items_cmd *cmd;
struct net_buf *buf;
buf = bt_avrcp_create_pdu(&avrcp_tx_pool);
if (buf == NULL) { return -ENOMEM; }
cmd = net_buf_add(buf, sizeof(*cmd));
cmd->scope = BT_AVRCP_SCOPE_VFS; /* Media Player Virtual File System */
cmd->start_item = sys_cpu_to_be32(0);
cmd->end_item = sys_cpu_to_be32(9);
cmd->attr_count = 0x00; /* 0 = return all attributes */
bt_avrcp_ct_get_folder_items(my_ct, tid, buf);
/* Response in ct_cb.get_folder_items(ct, tid, rsp) */
/* TG: respond from tg_cb.get_folder_items(tg, tid, cmd) callback */
static void tg_get_folder_items(struct bt_avrcp_tg *tg, uint8_t tid,
const struct bt_avrcp_get_folder_items_cmd *cmd) {
struct net_buf *rsp_buf = build_folder_items_response();
bt_avrcp_tg_get_folder_items(tg, tid, rsp_buf);
net_buf_unref(rsp_buf);
}
bt_avrcp_ct_change_path CT (Browsing)
Navigate into a folder on the browsed player. Fields are written through a typed struct bt_avrcp_change_path_cmd pointer cast from net_buf_add.
struct bt_avrcp_change_path_cmd *cmd;
struct net_buf *buf;
buf = bt_avrcp_create_pdu(&avrcp_tx_pool);
if (buf == NULL) { return -ENOMEM; }
cmd = net_buf_add(buf, sizeof(*cmd));
cmd->uid_counter = sys_cpu_to_be16(uid_counter); /* from set_browsed_player rsp */
cmd->direction = BT_AVRCP_CHANGE_PATH_CHILD; /* 0x01 = down into folder */
memcpy(cmd->folder_uid, &folder_uid, sizeof(cmd->folder_uid));
bt_avrcp_ct_change_path(my_ct, tid, buf);
/* Response in ct_cb.change_path(ct, tid, rsp) - rsp contains new item count */
bt_avrcp_ct_search CT (Browsing)
Search for items matching a string. The fixed header fields are written through a typed struct bt_avrcp_search_cmd pointer, then the search string bytes are appended with net_buf_add_mem.
struct bt_avrcp_search_cmd *cmd;
struct net_buf *buf;
const char *term = "Beatles";
uint16_t slen = (uint16_t)strlen(term);
buf = bt_avrcp_create_pdu(&avrcp_tx_pool);
if (buf == NULL) { return -ENOMEM; }
cmd = net_buf_add(buf, sizeof(*cmd));
cmd->charset_id = sys_cpu_to_be16(BT_AVRCP_CHARSET_UTF8);
cmd->search_str_len = sys_cpu_to_be16(slen);
net_buf_add_mem(buf, term, slen);
bt_avrcp_ct_search(my_ct, tid, buf);
/* Response in ct_cb.search(ct, tid, rsp) - rsp.num_items = match count */
bt_avrcp_tg_browsing_general_reject TG (Browsing) - new in edgefast_open
New API with no equivalent in edgefast_bluetooth. Sends a GENERAL_REJECT browsing response when the TG cannot handle the incoming browsing PDU at all.
/* Inside tg_cb.browsing_received - reject an unsupported PDU */
static void tg_browsing_received(struct bt_avrcp_tg *tg, uint8_t tid,
const struct bt_avrcp_browsing_cmd *cmd) {
if (cmd->pdu_id == UNSUPPORTED_PDU) {
/* BT_AVRCP_STATUS_INVALID_CMD = 0x20 */
bt_avrcp_tg_browsing_general_reject(tg, tid,
BT_AVRCP_STATUS_INVALID_CMD);
return;
}
/* ... handle other PDUs ... */
}
bt_avrcp_cover_art_ct_l2cap_connect - bt_avrcp_cover_art_ct_connect Cover Art CT
Two-step connection (vs edgefast_bluetooth’s single bt_avrcp_cover_art_connect). First establish L2CAP transport, then in the l2cap_connected callback establish the OBEX session.
/* Step 1: initiate L2CAP connection (call after AVRCP control is up) */
struct bt_avrcp_cover_art_ct *cover_art_ct;
bt_avrcp_cover_art_ct_l2cap_connect(my_ct, &cover_art_ct, psm);
/* Step 2: inside bt_avrcp_cover_art_ct_cb.l2cap_connected() callback */
static void ca_ct_l2cap_connected(struct bt_avrcp_cover_art_ct *ct) {
/* Now open the OBEX session over the L2CAP channel */
bt_avrcp_cover_art_ct_connect(ct);
}
/* Step 3: inside bt_avrcp_cover_art_ct_cb.connect() callback - ready */
static void ca_ct_connected(struct bt_avrcp_cover_art_ct *ct, uint8_t rsp_code) {
if (rsp_code == 0x20) { /* OBEX_RSP_SUCCESS */
g_cover_art_ct = ct; /* save for image requests */
}
}
bt_avrcp_cover_art_ct_get_image_properties Cover Art CT
Replaces bt_avrcp_get_image_property(handle, param*). The request body is serialized into a net_buf (OBEX GET request headers). bool final is true for single-packet requests, false when sending headers across multiple OBEX packets.
/* Allocate PDU buffer from the pool */
struct net_buf *buf = bt_avrcp_cover_art_ct_create_pdu(g_cover_art_ct,
&cover_art_pdu_pool);
if (!buf) { return -ENOMEM; }
/* Add OBEX headers - e.g. image handle header (0x30) */
net_buf_add_u8(buf, 0x30); /* ImgHandle header ID */
net_buf_add_be16(buf, 2 + img_handle_len * 2);
net_buf_add_mem(buf, img_handle_utf16, img_handle_len * 2);
/* final=true: this is the only (and last) OBEX packet */
bt_avrcp_cover_art_ct_get_image_properties(g_cover_art_ct, true, buf);
net_buf_unref(buf);
/* Response in bt_avrcp_cover_art_ct_cb.get_image_properties(ct, rsp_code, buf) */
bt_avrcp_cover_art_ct_get_image Cover Art CT
Replaces bt_avrcp_get_image(handle, param*). Similar pattern to get_image_properties but includes an image descriptor XML body in the OBEX GET request.
const char *img_desc =
""
""
"";
uint16_t desc_len = (uint16_t)strlen(img_desc);
struct net_buf *buf = bt_avrcp_cover_art_ct_create_pdu(g_cover_art_ct,
&cover_art_pdu_pool);
/* ImgHandle header */
net_buf_add_u8(buf, 0x30);
net_buf_add_be16(buf, 3 + img_handle_len * 2);
net_buf_add_mem(buf, img_handle_utf16, img_handle_len * 2);
net_buf_add_u8(buf, 0x00); /* NUL terminator */
/* ImgDescriptor header (0x71 = Type body, application/x-bt-coverart-imagedescriptor) */
net_buf_add_u8(buf, 0x48); /* Body header 0x48 (non-final) or 0x49 (final) */
net_buf_add_be16(buf, 3 + desc_len);
net_buf_add_mem(buf, img_desc, desc_len);
bt_avrcp_cover_art_ct_get_image(g_cover_art_ct, true, buf);
net_buf_unref(buf);
/* Image data arrives in bt_avrcp_cover_art_ct_cb.get_image(ct, rsp_code, buf) */
12. AVRCP Kconfig Configuration Comparison#
⚠️ Source files: edgefast_bluetooth -
middleware/edgefast_bluetooth/include/Kconfig| edgefast_open -middleware/edgefast_open/source/bluetooth/host/classic/Kconfig
ℹ️ Key naming difference: edgefast_bluetooth uses short abbreviations (
BT_AVRCP_CT,BT_AVRCP_TG) while edgefast_open uses full words (BT_AVRCP_CONTROLLER,BT_AVRCP_TARGET) edgefast_open also adds finer-grained cover art sub-operation symbols that are absent from edgefast_bluetooth.
12.1 Core Protocol Enablement#
Symbol |
edgefast_bluetooth |
edgefast_open |
Notes |
|---|---|---|---|
|
bool, default n |
bool (no default) |
Audio/Video Distribution Transport Protocol - prerequisite for A2DP and AVRCP in both stacks |
|
- not present - |
bool (no default) |
Audio/Video Control Transport Protocol layer. edgefast_open exposes this as a separate Kconfig knob; edgefast_bluetooth enables it implicitly when BT_AVRCP is set |
|
bool, default n |
bool (no default) |
Master AVRCP enable. Both stacks gate all AVRCP sub-features on this symbol. edgefast_bluetooth forces an explicit |
|
bool, default n |
bool (no default) |
Enables the AVRCP Browsing Channel (separate L2CAP PSM). Semantically identical in both stacks |
|
- not present - |
int, default 339 |
edgefast_open lets the application tune the Browsing Channel L2CAP MTU. edgefast_bluetooth fixes this at compile time in source code |
|
- not present - |
int, default 1024 |
Vendor-dependent data receive buffer size (bytes). edgefast_open exposes this tunable; edgefast_bluetooth uses a hard-coded internal value |
12.2 Role Enablement (Controller / Target)#
edgefast_bluetooth symbol |
edgefast_open equivalent |
Type |
Notes |
|---|---|---|---|
|
|
bool |
Enables the AVRCP Controller (CT) role. Symbol renamed: short form vs full word. No default in either |
|
|
bool |
Enables the AVRCP Target (TG) role. Same rename pattern. No default in either |
|
- not present - |
int, default BT_MAX_CONN |
edgefast_bluetooth caps simultaneous AVRCP connections. edgefast_open derives the limit from the underlying L2CAP/ACL connection pool instead |
12.3 Cover Art Kconfig Symbols#
⚠️ edgefast_open provides finer-grained cover art Kconfig symbols, splitting CT and TG cover art, and further breaking down CT cover art into individual operation enables edgefast_bluetooth provides a single shared symbol plus separate CT/TG gating symbols only.
edgefast_bluetooth symbol |
edgefast_open equivalent |
Type |
Notes |
|---|---|---|---|
|
- no direct equivalent - |
bool, default n |
edgefast_bluetooth top-level cover art gate. Selecting this enables the shared cover art OBEX/BIP transport. edgefast_open replaces this with per-role enables ( |
|
|
bool, default n |
Cover art initiator (CT side). edgefast_open renames to |
|
|
bool, default n |
Cover art responder (TG side). Renamed in edgefast_open |
- not present - |
|
bool |
edgefast_open only - enables the CT Get Image OBEX operation individually. edgefast_bluetooth bundles all cover art CT operations under |
- not present - |
|
bool |
edgefast_open only - enables the CT Get Image Properties OBEX operation individually |
- not present - |
|
bool |
edgefast_open only - enables the CT Get Linked Thumbnail OBEX operation individually |
12.4 Side-by-Side Symbol Summary#
Symbol |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
|
bool, default n |
bool |
|
- |
bool |
|
bool, default n |
bool |
|
bool, default n |
bool |
|
- |
int, default 339 |
|
- |
int, default 1024 |
|
bool, default n |
- BT_AVRCP_CONTROLLER |
|
bool, default n |
- BT_AVRCP_TARGET |
|
int, default BT_MAX_CONN |
- |
|
bool, default n |
- (split into CT/TG) |
|
bool, default n |
- BT_AVRCP_CT_COVER_ART |
|
bool, default n |
- BT_AVRCP_TG_COVER_ART |
|
- |
bool |
|
- |
bool |
|
- |
bool |
HFP#
Edgefast Bluetooth vs Edgefast Open - HFP API Differences#
Source:
middleware/edgefast_bluetooth/include/bluetooth/hfp_hf.h+hfp_ag.hvsmiddleware/edgefast_open/include/zephyr/bluetooth/classic/hfp_hf.h+hfp_ag.h
Badge |
Stack |
|---|---|
edgefast_bluetooth |
NXP Ethermind stack |
edgefast_open |
Zephyr open-source stack |
Legend: 🟢 Only in edgefast_bluetooth | 🔴 Only in edgefast_open | 🟡 Equivalent concept, different API
Contents#
1. Architecture & Design Philosophy#
⚠️ Fundamental difference: edgefast_bluetooth uses a mixed handle model -
struct bt_conn *is used for all HF operations, while AG uses a typedstruct bt_hfp_ag *object. Call operations (accept/reject/dial) are implicit, driven by AT commands sent through a single callback. edgefast_open uses a fully typed object model - both HF and AG have dedicated typed objects (struct bt_hfp_hf *,struct bt_hfp_ag *) and both introducestruct bt_hfp_hf_call */struct bt_hfp_ag_call *per-call objects for fine-grained call lifecycle management.
ℹ️ Call lifecycle: edgefast_bluetooth exposes broad AT command wrappers (e.g.,
bt_hfp_hf_send_cmd) withenum bt_hfp_hf_at_cmdfor ATA/CHUP, and explicit dial/multiparty APIs. edgefast_open models each call as a first-class object and provides dedicated typed functions per call state (bt_hfp_hf_accept,bt_hfp_hf_reject,bt_hfp_hf_terminate,bt_hfp_hf_hold_incoming), eliminating raw AT command strings.
ℹ️ Voice recognition text: edgefast_open adds enhanced voice recognition text support (
vre_state,vre_textual_representation,textual_representationcallback,ready_to_accept_audio) that has no equivalent in edgefast_bluetooth.
Aspect |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
HF connection handle |
|
|
AG connection handle |
|
|
Per-call handle |
None - call state tracked implicitly via AT indicators |
|
HF callback registration |
|
|
AG callback registration |
|
|
HF connect signature |
|
|
AG connect signature |
|
|
AG init/deinit |
|
No separate init/deinit - lifecycle managed via |
Call accept/reject (HF) |
|
|
Dialing (HF) |
|
|
CLIP / call waiting |
Separate enable/disable functions: |
Single boolean toggle: |
Volume control (HF) |
|
|
Volume control (AG) |
|
|
3-way call (HF) |
|
Individual functions: |
Codec handling |
|
|
ECNR |
None in HF header |
|
Indicator activation |
None |
|
HF indicators (battery/safety) |
Via |
|
Voice recognition text |
Not supported |
|
Subscriber number |
None (HF) / None (AG standalone query) |
|
Network operator |
None (HF) / |
|
AG incoming call notify |
|
|
DTMF |
None (HF) / |
|
2. Header File Layout & Constants#
Item |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
HF main header |
|
|
AG main header |
|
|
HF AT command enum |
|
No AT command enum - replaced by typed function calls |
Volume type |
|
No volume type enum - split into |
Multiparty call options |
|
No enum - individual named functions per CHLD value |
Call status (AG indicator) |
|
|
Call direction |
No enum |
|
Call mode |
No enum |
|
AG indicators enum |
None in header |
|
HF indicators enum |
None |
|
Codec IDs (AG) |
Not defined in header (passed via |
|
AG CIND struct |
|
No CIND struct - indicators set via individual functions ( |
HF config struct |
|
No config struct - initial values set via |
AG config struct |
|
No config struct - configuration via Kconfig and individual callbacks |
Current call info (HF) |
|
|
Ongoing call info (AG) |
None - AG uses raw |
|
Subscriber callback type |
None |
|
Waiting call struct |
|
Folded into |
Indicator status struct |
|
No struct - individual callbacks per indicator ( |
HF indicator IDs |
|
|
3. HF Connection Management#
ℹ️ Both stacks share the same function name
bt_hfp_hf_registerandbt_hfp_hf_connect/bt_hfp_hf_disconnect, but the handle type passed and returned changes fundamentally. edgefast_open’sconnectreturns a typedstruct bt_hfp_hf *object while edgefast_bluetooth uses the genericstruct bt_conn *throughout.
HF Register, Connect, and Disconnect#
edgefast_bluetooth
int bt_hfp_hf_register(struct bt_hfp_hf_cb *cb)
int bt_hfp_hf_connect(struct bt_conn *conn, uint8_t channel)
int bt_hfp_hf_disconnect(struct bt_conn *conn)
int bt_hfp_sco_disconnect(struct bt_conn *conn)
int bt_hfp_hf_discover(struct bt_conn *conn, bt_hfp_hf_discover_callback discoverCallback)
edgefast_open
int bt_hfp_hf_register(struct bt_hfp_hf_cb *cb)
int bt_hfp_hf_connect(struct bt_conn *conn, struct bt_hfp_hf **hf, uint8_t channel)
int bt_hfp_hf_disconnect(struct bt_hfp_hf *hf)
edgefast_bluetooth exposes a separate
bt_hfp_sco_disconnectand abt_hfp_hf_discoverfor manual SDP discovery. edgefast_open integrates SCO lifecycle entirely withinsco_connected/sco_disconnectedcallbacks and providesbt_hfp_hf_audio_connectinstead; no separate discover API is exposed.
4. HF Functions#
ℹ️ edgefast_open replaces edgefast_bluetooth’s raw AT command dispatch (
bt_hfp_hf_send_cmd) with per-operation typed functions. The call object (struct bt_hfp_hf_call *) replaces thestruct bt_conn *as the handle for call-level operations.
Audio Connection#
edgefast_bluetooth
int bt_hfp_hf_trigger_codec_connection(struct bt_conn *conn)
int bt_hfp_hf_open_audio(struct bt_conn *conn, uint8_t codec)
int bt_hfp_hf_close_audio(struct bt_conn *sco_conn)
edgefast_open
int bt_hfp_hf_audio_connect(struct bt_hfp_hf *hf)
int bt_hfp_hf_select_codec(struct bt_hfp_hf *hf, uint8_t codec_id)
int bt_hfp_hf_set_codecs(struct bt_hfp_hf *hf, uint8_t codec_ids)
edgefast_bluetooth provides
bt_hfp_hf_open_audio/bt_hfp_hf_close_audiofor direct SCO audio control (noted as PTS-only). edgefast_open usesbt_hfp_hf_audio_connectwhich handles codec negotiation (AT+BCC) internally when supported; codec IDs are set separately viabt_hfp_hf_set_codecs.
Call Accept / Reject / Terminate#
edgefast_bluetooth
int bt_hfp_hf_send_cmd(struct bt_conn *conn, enum bt_hfp_hf_at_cmd cmd)
/* cmd = BT_HFP_HF_ATA to accept, BT_HFP_HF_AT_CHUP to reject/terminate */
edgefast_open
int bt_hfp_hf_accept(struct bt_hfp_hf_call *call)
int bt_hfp_hf_reject(struct bt_hfp_hf_call *call)
int bt_hfp_hf_terminate(struct bt_hfp_hf_call *call)
int bt_hfp_hf_hold_incoming(struct bt_hfp_hf_call *call)
int bt_hfp_hf_query_respond_hold_status(struct bt_hfp_hf *hf)
edgefast_bluetooth uses a single
bt_hfp_hf_send_cmdwith an enum for ATA and AT+CHUP. edgefast_open models each call-state transition as a dedicated typed function operating on astruct bt_hfp_hf_call *, including the Response and Hold flow (bt_hfp_hf_hold_incoming,bt_hfp_hf_query_respond_hold_status).
Dialing#
edgefast_bluetooth
int bt_hfp_hf_dial(struct bt_conn *conn, const char *number)
int bt_hfp_hf_last_dial(struct bt_conn *conn)
int bt_hfp_hf_dial_memory(struct bt_conn *conn, int location)
edgefast_open
int bt_hfp_hf_number_call(struct bt_hfp_hf *hf, const char *number)
int bt_hfp_hf_redial(struct bt_hfp_hf *hf)
int bt_hfp_hf_memory_dial(struct bt_hfp_hf *hf, const char *location)
Functionally equivalent, but edgefast_bluetooth uses
int locationfor memory dial while edgefast_open usesconst char *location. Handle changes fromstruct bt_conn *tostruct bt_hfp_hf *. edgefast_open renamesbt_hfp_hf_dial-bt_hfp_hf_number_callandbt_hfp_hf_last_dial-bt_hfp_hf_redial.
Volume Control#
edgefast_bluetooth
int bt_hfp_hf_volume_update(struct bt_conn *conn, hf_volume_type_t type, int volume)
edgefast_open
int bt_hfp_hf_vgm(struct bt_hfp_hf *hf, uint8_t gain)
int bt_hfp_hf_vgs(struct bt_hfp_hf *hf, uint8_t gain)
edgefast_bluetooth uses a single
volume_updatewith a type enum. edgefast_open splits intovgm(microphone) andvgs(speaker) matching the AT+VGM / AT+VGS command names directly.
CLIP & Call Waiting Notifications#
edgefast_bluetooth
int bt_hfp_hf_enable_clip_notification(struct bt_conn *conn)
int bt_hfp_hf_disable_clip_notification(struct bt_conn *conn)
int bt_hfp_hf_enable_call_waiting_notification(struct bt_conn *conn)
int bt_hfp_hf_disable_call_waiting_notification(struct bt_conn *conn)
edgefast_open
int bt_hfp_hf_cli(struct bt_hfp_hf *hf, bool enable)
int bt_hfp_hf_call_waiting_notify(struct bt_hfp_hf *hf, bool enable)
edgefast_bluetooth uses separate enable/disable functions. edgefast_open merges each pair into a single boolean-toggled function.
3-Way Call (CHLD)#
edgefast_bluetooth
int bt_hfp_hf_multiparty_call_option(struct bt_conn *conn, hf_multiparty_call_option_t option)
/* option 1=Release+UDUB, 2=Release active+accept held/waiting,
3=Place active on hold+accept held/waiting, 4=Add to conference,
5=Connect two calls and disconnect subscriber */
edgefast_open
int bt_hfp_hf_release_all_held(struct bt_hfp_hf *hf) /* AT+CHLD=0 */
int bt_hfp_hf_set_udub(struct bt_hfp_hf *hf) /* AT+CHLD=0 */
int bt_hfp_hf_release_active_accept_other(struct bt_hfp_hf *hf) /* AT+CHLD=1 */
int bt_hfp_hf_hold_active_accept_other(struct bt_hfp_hf *hf) /* AT+CHLD=2 */
int bt_hfp_hf_join_conversation(struct bt_hfp_hf *hf) /* AT+CHLD=3 */
int bt_hfp_hf_explicit_call_transfer(struct bt_hfp_hf *hf) /* AT+CHLD=4 */
int bt_hfp_hf_release_specified_call(struct bt_hfp_hf_call *call) /* AT+CHLD=1<idx> */
int bt_hfp_hf_private_consultation_mode(struct bt_hfp_hf_call *call) /* AT+CHLD=2<idx> */
edgefast_bluetooth compresses all CHLD options into one enum-based function. edgefast_open exposes each CHLD variant as an individually named function, adds the ECC-specific per-call variants (
bt_hfp_hf_release_specified_call,bt_hfp_hf_private_consultation_mode) operating onstruct bt_hfp_hf_call *, and separatesrelease_all_heldfromset_udub(both map to AT+CHLD=0).
Voice Recognition#
edgefast_bluetooth
int bt_hfp_hf_start_voice_recognition(struct bt_conn *conn)
int bt_hfp_hf_stop_voice_recognition(struct bt_conn *conn)
edgefast_open
int bt_hfp_hf_voice_recognition(struct bt_hfp_hf *hf, bool activate)
int bt_hfp_hf_ready_to_accept_audio(struct bt_hfp_hf *hf)
edgefast_open merges start/stop into a single boolean-toggled function and adds
bt_hfp_hf_ready_to_accept_audiofor Enhanced Voice Recognition (AT+BVRA=2), which has no equivalent in edgefast_bluetooth.
Functions Only in edgefast_bluetooth (HF) 🟢#
int bt_hfp_hf_send_cmd(struct bt_conn *conn, enum bt_hfp_hf_at_cmd cmd)
int bt_hfp_hf_get_last_voice_tag_number(struct bt_conn *conn)
int bt_hfp_hf_get_peer_indicator_status(struct bt_conn *conn)
bt_hfp_hf_send_cmddispatches raw AT commands (ATA, AT+CHUP, AT+BAC); edgefast_open replaces this with typed functions.bt_hfp_hf_get_last_voice_tag_numberis replaced bybt_hfp_hf_request_phone_numberin edgefast_open.bt_hfp_hf_get_peer_indicator_status(sends AT+CIND? after SLC) has no direct equivalent.
Functions Only in edgefast_open (HF) 🔴#
int bt_hfp_hf_get_operator(struct bt_hfp_hf *hf)
int bt_hfp_hf_turn_off_ecnr(struct bt_hfp_hf *hf)
int bt_hfp_hf_indicator_status(struct bt_hfp_hf *hf, uint8_t status)
int bt_hfp_hf_enhanced_safety(struct bt_hfp_hf *hf, bool enable)
int bt_hfp_hf_battery(struct bt_hfp_hf *hf, uint8_t level)
int bt_hfp_hf_request_phone_number(struct bt_hfp_hf *hf)
int bt_hfp_hf_transmit_dtmf_code(struct bt_hfp_hf_call *call, char code)
int bt_hfp_hf_query_subscriber(struct bt_hfp_hf *hf)
int bt_hfp_hf_query_list_of_current_calls(struct bt_hfp_hf *hf)
💡 Reference code - edgefast_open HF-only APIs
/* bt_hfp_hf_get_operator - send AT+COPS? to read network operator name.
* Result delivered via .operator callback: (hf, mode, format, operator_str) */
int err = bt_hfp_hf_get_operator(hf);
if (err < 0) {
printk("bt_hfp_hf_get_operator failed: %d\n", err);
}
/* bt_hfp_hf_turn_off_ecnr - send AT+NREC=0 to disable AG echo-cancellation/noise-reduction.
* Result delivered via .ecnr_turn_off callback: (hf, err) */
int err = bt_hfp_hf_turn_off_ecnr(hf);
if (err < 0) {
printk("bt_hfp_hf_turn_off_ecnr failed: %d\n", err);
}
/* bt_hfp_hf_indicator_status - send AT+BIA to (de)activate AG indicators.
* 'status' is a bitmask: bit N = indicator index N. Example: deactivate index 3. */
uint8_t mask = 0xFF & ~(1U << 3); /* activate all except index 3 */
int err = bt_hfp_hf_indicator_status(hf, mask);
if (err < 0) {
printk("bt_hfp_hf_indicator_status failed: %d\n", err);
}
/* bt_hfp_hf_enhanced_safety - send AT+BIEV=1,<val> for Enhanced Driver Safety HF indicator */
int err = bt_hfp_hf_enhanced_safety(hf, true); /* true = enable */
if (err < 0) {
printk("bt_hfp_hf_enhanced_safety failed: %d\n", err);
}
/* bt_hfp_hf_battery - send AT+BIEV=2,<level> for Battery Level HF indicator (0-100) */
int err = bt_hfp_hf_battery(hf, 85); /* report 85% battery */
if (err < 0) {
printk("bt_hfp_hf_battery failed: %d\n", err);
}
/* bt_hfp_hf_request_phone_number - send AT+BINP=1 to request voice-tag phone number from AG.
* Result delivered via .request_phone_number callback: (hf, number) */
int err = bt_hfp_hf_request_phone_number(hf);
if (err < 0) {
printk("bt_hfp_hf_request_phone_number failed: %d\n", err);
}
/* bt_hfp_hf_transmit_dtmf_code - send AT+VTS=<code> on an active call.
* 'call' is the active call object; 'code' is a single DTMF char (0-9, *, #, A-D). */
int err = bt_hfp_hf_transmit_dtmf_code(call, '5');
if (err < 0) {
printk("bt_hfp_hf_transmit_dtmf_code failed: %d\n", err);
}
/* bt_hfp_hf_query_subscriber - send AT+CNUM to query subscriber numbers.
* Results delivered via .subscriber_number callback: (hf, number, type, service) */
int err = bt_hfp_hf_query_subscriber(hf);
if (err < 0) {
printk("bt_hfp_hf_query_subscriber failed: %d\n", err);
}
/* bt_hfp_hf_query_list_of_current_calls - send AT+CLCC to enumerate active calls.
* Each call delivered via .query_call callback: (hf, struct bt_hfp_hf_current_call *).
* Callback is invoked with NULL to signal end of list. */
int err = bt_hfp_hf_query_list_of_current_calls(hf);
if (err < 0) {
printk("bt_hfp_hf_query_list_of_current_calls failed: %d\n", err);
}
5. HF Callback Structures Comparison#
Callback |
edgefast_bluetooth |
edgefast_open |
Notes |
|---|---|---|---|
|
|
|
edgefast_open delivers the HF object here; no error code |
|
|
|
Handle type changes |
|
|
|
First param changes |
|
|
|
Identical |
|
|
|
Handle type changes |
|
|
Not present as raw indicator - replaced by |
edgefast_open lifts call state to typed per-call callbacks |
|
|
Not present - folded into |
- |
|
|
Not present as raw indicator - replaced by |
- |
|
|
|
Handle type changes |
|
|
|
Handle type changes |
|
|
|
Handle type changes |
|
|
|
Renamed; edgefast_open uses |
|
|
|
Renamed; |
|
|
Not present |
No equivalent in edgefast_open |
|
|
|
Struct replaced by inline params |
|
|
|
Param changes to call object |
|
|
|
Split by direction; type enum removed |
|
|
Not present as batch struct - each indicator has its own callback |
Decomposed into individual callbacks |
|
|
|
Narrowed to dial result; general AT cmd completion removed |
|
|
|
Renamed; |
|
|
Not present |
Config eliminated; use |
|
|
|
Renamed; pointer - value |
|
|
Not present |
No direct equivalent |
|
|
|
Renamed; struct now uses typed enums |
|
Not present |
|
New in edgefast_open |
|
Not present |
|
New in edgefast_open |
|
Not present |
|
New in edgefast_open |
|
Not present |
|
New in edgefast_open |
|
Not present |
|
New in edgefast_open |
|
Not present |
|
New in edgefast_open |
|
Not present |
|
New in edgefast_open |
|
Not present |
|
New in edgefast_open |
|
Not present |
|
New in edgefast_open |
|
Not present |
|
New in edgefast_open |
|
Not present |
|
New in edgefast_open |
|
Not present |
|
New in edgefast_open |
|
Not present |
|
New in edgefast_open - Enhanced VR engine state |
|
Not present |
|
New in edgefast_open - VR text |
|
Not present |
|
New in edgefast_open |
6. AG Connection Management#
ℹ️ edgefast_bluetooth’s
bt_hfp_ag_connecttakes a fullhfp_ag_get_configstruct with 10+ fields at connect time and also embeds the callback. edgefast_open’sbt_hfp_ag_connectonly needs thestruct bt_conn *and RFCOMMchannel; configuration is distributed into callbacks (get_indicator_value,get_ongoing_call) and Kconfig settings. edgefast_bluetooth also requires explicitbt_hfp_ag_init()/bt_hfp_ag_deinit()lifecycle calls.
AG Register, Connect, and Disconnect#
edgefast_bluetooth
int bt_hfp_ag_init(void)
int bt_hfp_ag_deinit(void)
int bt_hfp_ag_register_cb(struct bt_hfp_ag_cb *cb)
int bt_hfp_ag_connect(struct bt_conn *conn, hfp_ag_get_config *config,
struct bt_hfp_ag_cb *cb, struct bt_hfp_ag **phfp_ag)
int bt_hfp_ag_disconnect(struct bt_hfp_ag *hfp_ag)
struct bt_conn *bt_hfp_ag_get_conn(struct bt_hfp_ag *hfp_ag)
int bt_hfp_ag_discover(struct bt_conn *conn, bt_hfp_ag_discover_callback discoverCallback)
edgefast_open
int bt_hfp_ag_register(struct bt_hfp_ag_cb *cb)
int bt_hfp_ag_connect(struct bt_conn *conn, struct bt_hfp_ag **ag, uint8_t channel)
int bt_hfp_ag_disconnect(struct bt_hfp_ag *ag)
edgefast_bluetooth provides
bt_hfp_ag_get_connto retrieve the underlying ACL connection from an AG object. edgefast_open does not expose this. edgefast_bluetooth includes abt_hfp_ag_discoverfor manual SDP discovery; edgefast_open has no equivalent.
7. AG Functions#
ℹ️ edgefast_open refactors the AG notification model: instead of single flat status-setter functions (e.g.,
bt_hfp_ag_call_status_pl), it provides role-named event functions (bt_hfp_ag_remote_incoming,bt_hfp_ag_remote_ringing,bt_hfp_ag_remote_accept,bt_hfp_ag_remote_reject,bt_hfp_ag_remote_terminate) plus per-call control functions operating onstruct bt_hfp_ag_call *.
Audio Connection (AG)#
edgefast_bluetooth
void bt_hfp_ag_open_audio(struct bt_hfp_ag *hfp_ag, uint8_t codec)
void bt_hfp_ag_close_audio(struct bt_hfp_ag *hfp_ag)
int bt_hfp_ag_codec_selector(struct bt_hfp_ag *hfp_ag, uint8_t value)
edgefast_open
int bt_hfp_ag_audio_connect(struct bt_hfp_ag *ag, uint8_t id)
edgefast_bluetooth’s
open_audio/close_audioarevoidreturn. edgefast_open merges codec selection intobt_hfp_ag_audio_connectand returnsint. Separatebt_hfp_ag_codec_selectordoes not exist in edgefast_open; codec is passed directly toaudio_connect.
AG Call Lifecycle#
edgefast_bluetooth
void bt_hfp_ag_call_status_pl(struct bt_hfp_ag *hfp_ag, hfp_ag_call_status_t status)
void bt_hfp_ag_send_callring(struct bt_hfp_ag *hfp_ag)
int bt_hfp_ag_send_ccwa_indicator(struct bt_hfp_ag *hfp_ag, char *number)
edgefast_open
int bt_hfp_ag_remote_incoming(struct bt_hfp_ag *ag, const char *number)
int bt_hfp_ag_remote_ringing(struct bt_hfp_ag_call *call)
int bt_hfp_ag_remote_accept(struct bt_hfp_ag_call *call)
int bt_hfp_ag_remote_reject(struct bt_hfp_ag_call *call)
int bt_hfp_ag_remote_terminate(struct bt_hfp_ag_call *call)
int bt_hfp_ag_hold_incoming(struct bt_hfp_ag_call *call)
int bt_hfp_ag_reject(struct bt_hfp_ag_call *call)
int bt_hfp_ag_accept(struct bt_hfp_ag_call *call)
int bt_hfp_ag_terminate(struct bt_hfp_ag_call *call)
int bt_hfp_ag_retrieve(struct bt_hfp_ag_call *call)
int bt_hfp_ag_hold(struct bt_hfp_ag_call *call)
int bt_hfp_ag_outgoing(struct bt_hfp_ag *ag, const char *number)
edgefast_bluetooth uses a single
bt_hfp_ag_call_status_plwith an enum to drive the entire call lifecycle. edgefast_open introduces per-event functions and separates HF-initiated events (remote_*) from AG-initiated events (e.g.,bt_hfp_ag_hold,bt_hfp_ag_outgoing).
AG Indicator Notifications#
edgefast_bluetooth
int bt_hfp_ag_send_call_indicator(struct bt_hfp_ag *hfp_ag, uint8_t value)
int bt_hfp_ag_send_callsetup_indicator(struct bt_hfp_ag *hfp_ag, uint8_t value)
int bt_hfp_ag_send_callheld_indicator(struct bt_hfp_ag *hfp_ag, uint8_t value)
int bt_hfp_ag_send_service_indicator(struct bt_hfp_ag *hfp_ag, uint8_t value)
int bt_hfp_ag_send_signal_indicator(struct bt_hfp_ag *hfp_ag, uint8_t value)
int bt_hfp_ag_send_roaming_indicator(struct bt_hfp_ag *hfp_ag, uint8_t value)
int bt_hfp_ag_send_battery_indicator(struct bt_hfp_ag *hfp_ag, uint8_t value)
int bt_hfp_ag_get_cind_setting(struct bt_hfp_ag *hfp_ag, hfp_ag_cind_t *cind_setting)
int bt_hfp_ag_set_cind_setting(struct bt_hfp_ag *hfp_ag, hfp_ag_cind_t *cind_setting)
edgefast_open
int bt_hfp_ag_service_availability(struct bt_hfp_ag *ag, bool available)
int bt_hfp_ag_signal_strength(struct bt_hfp_ag *ag, uint8_t strength)
int bt_hfp_ag_roaming_status(struct bt_hfp_ag *ag, uint8_t status)
int bt_hfp_ag_battery_level(struct bt_hfp_ag *ag, uint8_t level)
edgefast_bluetooth explicitly sends
call,callsetup, andcallheldindicators via dedicated functions and also provides a bulk CIND get/set viahfp_ag_cind_t. In edgefast_open, call/callsetup/callheld indicators are managed internally by the stack as part of the call object lifecycle - no explicit indicator send functions for these are exposed. Only network-related indicators (service, signal, roam, battery) require application notification.
AG Voice Recognition#
edgefast_bluetooth
int bt_hfp_ag_send_enable_voice_recognition(struct bt_hfp_ag *hfp_ag)
int bt_hfp_ag_send_disable_voice_recognition(struct bt_hfp_ag *hfp_ag)
edgefast_open
int bt_hfp_ag_voice_recognition(struct bt_hfp_ag *ag, bool activate)
int bt_hfp_ag_vre_state(struct bt_hfp_ag *ag, uint8_t state)
int bt_hfp_ag_vre_textual_representation(struct bt_hfp_ag *ag, uint8_t state, const char *id,
uint8_t type, uint8_t operation, const char *text)
edgefast_bluetooth uses separate enable/disable functions. edgefast_open merges into a boolean toggle and adds
bt_hfp_ag_vre_stateandbt_hfp_ag_vre_textual_representationfor Enhanced Voice Recognition, which are absent in edgefast_bluetooth.
AG Volume, Network Operator, Inband Ring#
edgefast_bluetooth
int bt_hfp_ag_set_volume_control(struct bt_hfp_ag *hfp_ag, hf_ag_volume_type_t type, int value)
int bt_hfp_ag_set_cops(struct bt_hfp_ag *hfp_ag, char *name)
int bt_hfp_ag_set_inband_ring_tone(struct bt_hfp_ag *hfp_ag, int value)
edgefast_open
int bt_hfp_ag_vgm(struct bt_hfp_ag *ag, uint8_t vgm)
int bt_hfp_ag_vgs(struct bt_hfp_ag *ag, uint8_t vgs)
int bt_hfp_ag_set_operator(struct bt_hfp_ag *ag, uint8_t mode, char *name)
int bt_hfp_ag_inband_ringtone(struct bt_hfp_ag *ag, bool inband)
Volume control split from one type-enum function into two named functions.
set_copsrenamed toset_operatorand gains amodeparameter. Inband ring tone changes fromint valuetobool inband.
Functions Only in edgefast_bluetooth (AG) 🟢#
int bt_hfp_ag_init(void)
int bt_hfp_ag_deinit(void)
struct bt_conn *bt_hfp_ag_get_conn(struct bt_hfp_ag *hfp_ag)
int bt_hfp_ag_discover(struct bt_conn *conn, bt_hfp_ag_discover_callback discoverCallback)
int bt_hfp_ag_register_supp_features(struct bt_hfp_ag *hfp_ag, uint32_t supported_features)
uint32_t bt_hfp_ag_get_peer_supp_features(struct bt_hfp_ag *hfp_ag)
int bt_hfp_ag_register_cind_features(struct bt_hfp_ag *hfp_ag, char *cind)
int bt_hfp_ag_send_enable_voice_ecnr(struct bt_hfp_ag *hfp_ag)
int bt_hfp_ag_send_disable_voice_ecnr(struct bt_hfp_ag *hfp_ag)
int bt_hfp_ag_set_phnum_tag(struct bt_hfp_ag *hfp_ag, char *name)
int bt_hfp_ag_handle_btrh(struct bt_hfp_ag *hfp_ag, uint8_t option)
int bt_hfp_ag_handle_indicator_enable(struct bt_hfp_ag *hfp_ag, uint8_t index, uint8_t enable)
void bt_hfp_ag_send_callring(struct bt_hfp_ag *hfp_ag)
int bt_hfp_ag_send_clip(struct bt_hfp_ag *hfp_ag, uint8_t *clip_result)
int bt_hfp_ag_set_clcc(struct bt_hfp_ag *hfp_ag, char *call_list)
int bt_hfp_ag_unknown_at_response(struct bt_hfp_ag *hfp_ag, uint8_t *unknow_at_rsp, uint16_t unknow_at_rsplen)
int bt_hfp_ag_set_hf_indicator(struct bt_hfp_ag *hfp_ag, uint16_t hf_indicator, uint8_t enable)
Functions Only in edgefast_open (AG) 🔴#
int bt_hfp_ag_remote_incoming(struct bt_hfp_ag *ag, const char *number)
int bt_hfp_ag_remote_ringing(struct bt_hfp_ag_call *call)
int bt_hfp_ag_remote_accept(struct bt_hfp_ag_call *call)
int bt_hfp_ag_remote_reject(struct bt_hfp_ag_call *call)
int bt_hfp_ag_remote_terminate(struct bt_hfp_ag_call *call)
int bt_hfp_ag_hold_incoming(struct bt_hfp_ag_call *call)
int bt_hfp_ag_reject(struct bt_hfp_ag_call *call)
int bt_hfp_ag_accept(struct bt_hfp_ag_call *call)
int bt_hfp_ag_terminate(struct bt_hfp_ag_call *call)
int bt_hfp_ag_retrieve(struct bt_hfp_ag_call *call)
int bt_hfp_ag_hold(struct bt_hfp_ag_call *call)
int bt_hfp_ag_outgoing(struct bt_hfp_ag *ag, const char *number)
int bt_hfp_ag_explicit_call_transfer(struct bt_hfp_ag *ag)
int bt_hfp_ag_vre_state(struct bt_hfp_ag *ag, uint8_t state)
int bt_hfp_ag_vre_textual_representation(struct bt_hfp_ag *ag, uint8_t state, const char *id,
uint8_t type, uint8_t operation, const char *text)
int bt_hfp_ag_ongoing_calls(struct bt_hfp_ag *ag, struct bt_hfp_ag_ongoing_call *calls, size_t count)
int bt_hfp_ag_hf_indicator(struct bt_hfp_ag *ag, enum hfp_ag_hf_indicators indicator, bool enable)
💡 Reference code - edgefast_open AG-only APIs
/* bt_hfp_ag_remote_incoming - notify HF that a remote party is calling (AG-originated).
* Creates a new struct bt_hfp_ag_call * object delivered via .incoming callback.
* Use for a phone call arriving at the AG from the cellular network. */
int err = bt_hfp_ag_remote_incoming(ag, "123456789");
if (err) {
printk("bt_hfp_ag_remote_incoming failed: %d\n", err);
}
/* bt_hfp_ag_remote_ringing - notify HF that remote party is now ringing (outgoing call).
* Call object obtained from the .outgoing callback. Transitions call to ALERTING. */
int err = bt_hfp_ag_remote_ringing(call);
if (err) {
printk("bt_hfp_ag_remote_ringing failed: %d\n", err);
}
/* bt_hfp_ag_remote_accept - notify HF that remote party accepted (outgoing call - ACTIVE). */
int err = bt_hfp_ag_remote_accept(call);
if (err) {
printk("bt_hfp_ag_remote_accept failed: %d\n", err);
}
/* bt_hfp_ag_remote_reject - notify HF that remote party rejected the outgoing call. */
int err = bt_hfp_ag_remote_reject(call);
if (err) {
printk("bt_hfp_ag_remote_reject failed: %d\n", err);
}
/* bt_hfp_ag_remote_terminate - notify HF that remote party hung up. */
int err = bt_hfp_ag_remote_terminate(call);
if (err) {
printk("bt_hfp_ag_remote_terminate failed: %d\n", err);
}
/* bt_hfp_ag_accept - accept an incoming call on behalf of the AG (response to AT+ATA from HF).
* Called from .accept callback to confirm the HF-initiated accept. */
int err = bt_hfp_ag_accept(call);
if (err) {
printk("bt_hfp_ag_accept failed: %d\n", err);
}
/* bt_hfp_ag_reject - reject a call not yet active (AT+CHUP, call in INCOMING state).
* bt_hfp_ag_terminate - terminate an active/held call (AT+CHUP, call was ACTIVE).
* Choose based on current call state (from app_handsfree_ag.c pattern): */
int err;
if (hfp_in_calling) {
err = bt_hfp_ag_terminate(call);
} else {
err = bt_hfp_ag_reject(call);
}
if (err) {
printk("ag stop call failed: %d\n", err);
}
/* bt_hfp_ag_hold - place active call on hold (AT+CHLD=2 from HF).
* bt_hfp_ag_retrieve - retrieve a held call (AT+CHLD=2, swap). */
int err = bt_hfp_ag_hold(call); /* or bt_hfp_ag_retrieve(call) */
if (err) {
printk("ag hold/retrieve failed: %d\n", err);
}
/* bt_hfp_ag_outgoing - initiate an outgoing call from the AG side.
* Creates a new struct bt_hfp_ag_call * delivered via .outgoing callback. */
int err = bt_hfp_ag_outgoing(ag, "987654321");
if (err) {
printk("bt_hfp_ag_outgoing failed: %d\n", err);
}
/* bt_hfp_ag_explicit_call_transfer - perform AT+CHLD=4 (connect two calls, disconnect AG).
* Typically called from .explicit_call_transfer callback. */
int err = bt_hfp_ag_explicit_call_transfer(ag);
if (err) {
printk("bt_hfp_ag_explicit_call_transfer failed: %d\n", err);
}
/* bt_hfp_ag_audio_connect - open SCO audio connection with the specified codec.
* codec: BT_HFP_AG_CODEC_CVSD(1), BT_HFP_AG_CODEC_MSBC(2), BT_HFP_AG_CODEC_LC3_SWB(3) */
int err = bt_hfp_ag_audio_connect(ag, BT_HFP_AG_CODEC_MSBC);
if (err) {
printk("bt_hfp_ag_audio_connect failed: %d\n", err);
}
/* bt_hfp_ag_vre_state - send +BVRA:<state> Enhanced VR engine state update to HF.
* state: 0=deactivated, 1=activated, 2=ready_to_accept_audio */
int err = bt_hfp_ag_vre_state(ag, 1); /* VR engine activated */
if (err) {
printk("bt_hfp_ag_vre_state failed: %d\n", err);
}
/* bt_hfp_ag_vre_textual_representation - send +BVRA textual representation to HF.
* Used for Enhanced VR to display recognized text on HF. */
int err = bt_hfp_ag_vre_textual_representation(ag,
1, /* state: activated */
"msg-1", /* text ID */
0, /* type: speech */
0, /* operation: add */
"Call John");
if (err) {
printk("bt_hfp_ag_vre_textual_representation failed: %d\n", err);
}
/* bt_hfp_ag_hf_indicator - enable or disable a specific HF indicator reported by the HF.
* indicator: HFP_AG_ENHANCED_SAFETY_IND (1) or HFP_AG_BATTERY_LEVEL_IND (2).
* Returns -EOPNOTSUPP if the HF did not register support for this indicator. */
int err = bt_hfp_ag_hf_indicator(ag, HFP_AG_BATTERY_LEVEL_IND, true);
if (err == -EOPNOTSUPP) {
printk("HF does not support battery indicator\n");
} else if (err) {
printk("bt_hfp_ag_hf_indicator failed: %d\n", err);
}
8. AG Callback Structures Comparison#
Callback |
edgefast_bluetooth |
edgefast_open |
Notes |
|---|---|---|---|
|
|
|
edgefast_open also delivers the ACL conn; no error code |
|
|
|
Equivalent; parameter renamed |
|
|
|
Identical |
|
|
|
edgefast_open passes SCO conn + reason code; edgefast_bluetooth passes AG object |
|
|
Not present - replaced by |
Config struct eliminated |
|
Not present |
|
New in edgefast_open - initial indicator values at SLC |
|
Not present |
|
New in edgefast_open - replaces |
|
|
|
Split by direction |
|
|
Not present |
Remote HF feature bits not surfaced as callback in edgefast_open |
|
|
|
Renamed; param changes to call object |
|
|
|
Decomposed by call state |
|
|
|
Renamed; |
|
|
|
edgefast_open passes location as string + requests number back |
|
|
|
edgefast_open expects app to fill in the last number |
|
Not present |
|
New - call object created here |
|
Not present |
|
New - incoming call object |
|
Not present |
|
New |
|
Not present |
|
New - replaces |
|
Not present |
|
New |
|
Not present |
|
New |
|
Not present |
|
New |
|
Not present |
|
New |
|
|
|
Renamed; |
|
|
|
Renamed; value removed (always turn-off) |
|
|
|
param changes from codec ID to result code |
|
|
|
Renamed |
|
|
|
Identical |
|
|
|
edgefast_open handles most CHLD operations without app callback |
|
|
|
Renamed; edgefast_open uses |
|
|
|
Renamed |
|
|
Not present |
No unknown AT passthrough in edgefast_open |
|
|
|
Renamed; index to enum |
|
Not present |
|
New - AT+BINP=1 handler |
|
Not present |
|
New - AT+CNUM handler |
|
Not present |
|
New - Enhanced VR |
|
Not present |
|
New - replaces brva |
|
Not present |
|
New - AT+CHLD=4 |
|
Not present |
|
New |
|
Not present |
|
New |
|
Not present |
|
New |
|
Not present |
|
New |
|
Not present |
|
New |
9. Full Function Comparison Table#
HF Functions#
Function |
edgefast_bluetooth |
edgefast_open |
Status |
|---|---|---|---|
Register HF callbacks |
|
|
Same name, different struct |
Connect |
|
|
Returns HF object |
Disconnect |
|
|
Handle type changes |
SCO disconnect |
|
- (managed via callbacks) |
Only in edgefast_bluetooth |
SDP discover |
|
- |
Only in edgefast_bluetooth |
Accept call |
|
|
Renamed + typed |
Reject call |
|
|
Renamed + typed |
Terminate call |
|
|
Renamed + typed |
Hold incoming |
- |
|
Only in edgefast_open |
Query R&H status |
- |
|
Only in edgefast_open |
Dial number |
|
|
Renamed |
Redial |
|
|
Renamed |
Memory dial |
|
|
Location type changes |
Volume update |
|
|
Split by direction |
CLIP enable |
|
|
Merged with bool |
CLIP disable |
|
|
Merged with bool |
Call waiting enable |
|
|
Merged with bool |
Call waiting disable |
|
|
Merged with bool |
3-way call |
|
8 individual functions |
Decomposed |
Start voice recognition |
|
|
Merged with bool |
Stop voice recognition |
|
|
Merged with bool |
Ready to accept audio |
- |
|
Only in edgefast_open |
Codec connection |
|
|
Renamed |
Open audio |
|
- (merged into audio_connect) |
Only in edgefast_bluetooth (PTS) |
Close audio |
|
- |
Only in edgefast_bluetooth (PTS) |
Select codec |
- |
|
Only in edgefast_open |
Set codecs |
- |
|
Only in edgefast_open |
Turn off ECNR |
- |
|
Only in edgefast_open |
Indicator status |
- |
|
Only in edgefast_open |
Enhanced safety |
- |
|
Only in edgefast_open |
Battery level |
- |
|
Only in edgefast_open |
Get operator |
- |
|
Only in edgefast_open |
Voice tag number |
|
|
Renamed |
DTMF |
- |
|
Only in edgefast_open |
Query subscriber |
- |
|
Only in edgefast_open |
Peer indicator status |
|
- |
Only in edgefast_bluetooth |
Send raw AT cmd |
|
- (replaced by typed functions) |
Only in edgefast_bluetooth |
Query current calls |
|
|
Renamed |
AG Functions#
Function |
edgefast_bluetooth |
edgefast_open |
Status |
|---|---|---|---|
Init |
|
- |
Only in edgefast_bluetooth |
Deinit |
|
- |
Only in edgefast_bluetooth |
Register callbacks |
|
|
Renamed |
Connect |
|
|
Simplified |
Disconnect |
|
|
Equivalent |
Get ACL conn |
|
- |
Only in edgefast_bluetooth |
SDP discover |
|
- |
Only in edgefast_bluetooth |
Open audio |
|
|
Renamed; returns int |
Close audio |
|
- (managed via SCO callbacks) |
Only in edgefast_bluetooth |
Codec select |
|
- (merged into audio_connect) |
Only in edgefast_bluetooth |
Call status |
|
- (replaced by per-event functions) |
Only in edgefast_bluetooth |
Notify incoming |
- |
|
Only in edgefast_open |
Notify ringing |
|
|
Renamed + typed |
Notify remote accept |
- |
|
Only in edgefast_open |
Notify remote reject |
- |
|
Only in edgefast_open |
Notify remote terminate |
- |
|
Only in edgefast_open |
Hold incoming |
- |
|
Only in edgefast_open |
Reject call |
- |
|
Only in edgefast_open |
Accept call |
- |
|
Only in edgefast_open |
Terminate call |
- |
|
Only in edgefast_open |
Retrieve call |
- |
|
Only in edgefast_open |
Hold call |
- |
|
Only in edgefast_open |
Outgoing call |
- |
|
Only in edgefast_open |
Explicit call transfer |
- |
|
Only in edgefast_open |
CCWA indicator |
|
- (managed internally by stack) |
Only in edgefast_bluetooth |
Send call indicator |
|
- (managed internally) |
Only in edgefast_bluetooth |
Send callsetup indicator |
|
- (managed internally) |
Only in edgefast_bluetooth |
Send callheld indicator |
|
- (managed internally) |
Only in edgefast_bluetooth |
Send service indicator |
|
|
Renamed; uint8 to bool |
Send signal indicator |
|
|
Renamed |
Send roam indicator |
|
|
Renamed |
Send battery indicator |
|
|
Renamed |
Get CIND setting |
|
- |
Only in edgefast_bluetooth |
Set CIND setting |
|
- |
Only in edgefast_bluetooth |
Set ongoing calls |
|
|
Renamed; typed struct |
Volume control |
|
|
Split by direction |
Set operator |
|
|
Renamed; mode added |
Inband ring |
|
|
Renamed; int to bool |
Set CLIP |
|
- (managed internally) |
Only in edgefast_bluetooth |
Enable VR |
|
|
Merged with bool |
Disable VR |
|
|
Merged with bool |
VR engine state |
- |
|
Only in edgefast_open |
VR text |
- |
|
Only in edgefast_open |
Enable ECNR |
|
- |
Only in edgefast_bluetooth |
Disable ECNR |
|
- |
Only in edgefast_bluetooth |
Supp features register |
|
- |
Only in edgefast_bluetooth |
Get peer features |
|
- |
Only in edgefast_bluetooth |
CIND string register |
|
- |
Only in edgefast_bluetooth |
Phone number tag |
|
- (handled via request_phone_number callback) |
Only in edgefast_bluetooth |
BTRH handler |
|
- |
Only in edgefast_bluetooth |
HF indicator enable |
|
|
Renamed; index to enum |
HF indicator set |
|
|
Merged |
Unknown AT response |
|
- |
Only in edgefast_bluetooth |
10. Architecture Summary#
Topic |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
HF handle |
|
|
AG handle |
|
|
Call handle |
No per-call object |
|
Call indicator management |
App explicitly sends |
Stack manages |
AT command exposure |
Raw AT commands dispatched via |
No raw AT exposure - all operations via typed functions |
Config at connect |
AG: full |
AG: only |
Lifecycle management |
AG requires |
No separate init/deinit |
Codec IDs |
Numeric |
Named macros |
Enhanced VR |
Not supported |
Full support: |
3-way call (HF) |
One function with enum (5 options) |
8 individually named functions per CHLD value |
Volume |
Single function with type enum for both HF and AG |
|
CLIP/CCWA toggle |
Separate enable/disable functions |
Single |
SDP discover |
Manual: |
Not exposed - caller passes |
Unknown AT handling |
|
Not exposed in edgefast_open |
CLIP sending (AG) |
|
Managed internally by stack |
11. HFP Kconfig Configuration Comparison#
Feature |
edgefast_bluetooth Kconfig |
edgefast_open Kconfig |
|---|---|---|
HF enable |
|
|
AG enable |
|
|
HF indicators |
|
|
Codec negotiation (HF) |
|
|
CLI notification (HF) |
No dedicated Kconfig - controlled via |
|
Volume (HF) |
No dedicated Kconfig - always available |
|
3-way call (HF) |
No dedicated Kconfig |
|
ECC (HF) |
No dedicated Kconfig |
|
ECNR (HF) |
No dedicated Kconfig in HF header |
|
Voice recognition (HF) |
No dedicated Kconfig in HF header |
|
Enhanced VR (HF) |
Not supported |
|
VR text (HF) |
Not supported |
|
ECS (current calls, HF) |
No dedicated Kconfig |
|
3-way call (AG) |
No dedicated Kconfig |
|
ECNR (AG) |
No dedicated Kconfig |
|
Voice recognition (AG) |
No dedicated Kconfig |
|
Enhanced VR (AG) |
Not supported |
|
VR text (AG) |
Not supported |
|
Voice tag (AG) |
No dedicated Kconfig |
|
HF indicators (AG) |
|
|
Phone number max len |
Not configurable (hardcoded |
|
Ongoing call timeout |
Not configurable |
|
MAP#
Edgefast Bluetooth vs Edgefast Open — MAP API Differences#
Source:
middleware/edgefast_bluetooth/include/bluetooth/map_mce.h+map_mse.hvsmiddleware/edgefast_open/include/zephyr/bluetooth/classic/map.h
Badge |
Stack |
|---|---|
edgefast_bluetooth |
NXP Ethermind stack |
edgefast_open |
Zephyr open-source stack |
Legend: 🟢 Only in edgefast_bluetooth | 🔴 Only in edgefast_open | 🟡 Equivalent concept, different API
Contents#
1. Architecture & Design Philosophy #
⚠️ Fundamental difference: edgefast_bluetooth uses a stack-managed opaque object model — the stack allocates
struct bt_map_mce_mas */struct bt_map_mse_mas *on connection and returns it via callback; a single globalregister(cb)call covers all instances. edgefast_open uses an application-owned instance model — the app pre-allocates the instance struct, registers callbacks per-instance, then explicitly performs transport connect and OBEX connect as two separate steps.
ℹ️ Transport abstraction: edgefast_bluetooth hides the RFCOMM/L2CAP transport difference behind a single
connected/disconnectedcallback pair. edgefast_open exposes four separate transport callbacks (rfcomm_connected,rfcomm_disconnected,l2cap_connected,l2cap_disconnected) plus additional OBEX-levelconnect/disconnectcallbacks, giving the application full visibility of each connection phase.
Aspect |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
Object lifecycle |
Stack allocates instance on connect; app receives pointer via callback |
App pre-allocates |
Callback registration |
Single global call: |
Per-instance: |
Transport connection (MCE) |
Single step: |
Two steps: |
Transport events (MCE) |
Single |
Split: |
Server registration |
Single global call: |
Per-server call: |
MAP header encoding |
Stack adds OBEX Connection ID, SRM, SRMP, Name and Type headers automatically based on input parameters and provides dedicated helper macros ( |
App calls OBEX APIs directly ( |
Fragmentation control |
|
|
SRM state management |
Stack adds SRM header and maintains SRM state internally |
App calls |
Callback behaviour when SRM enabled |
Stack generates a synthetic callback immediately after app sends a request (client side) or response (server side) to prompt the next transfer, even without an actual response from the peer |
No synthetic request/response callback — callback fires only when a real packet is received; app must schedule the next outgoing request or response by itself rather than waiting for a callback |
Buffer reservation macros |
|
Not present — replaced by |
Max packet length query |
|
Not present — maximum packet length returned via |
Abort |
|
|
MSE disconnect |
|
|
2. Header File Layout & Constants #
Item |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
MCE header |
|
Unified |
MSE header |
|
Same unified |
Shared types header |
|
All types defined inline in |
OBEX dependency |
|
|
RSV_LEN macros |
|
Not present |
Type headers |
|
|
Supported features |
|
|
Application param tag IDs |
|
|
Add application parameter helper |
|
Not present as named macro — app calls OBEX layer directly: |
Add body helper |
|
Not present as named macro — app calls OBEX layer directly: |
Parse application parameter helper |
|
Not present as named macro — app calls OBEX layer directly: |
Get body helper |
|
Not present as named macro — app calls OBEX layer directly: |
3. MCE MAS — Connection Management #
ℹ️ The most significant architectural change: edgefast_bluetooth uses a one-step opaque connect where the stack allocates the MAS object and delivers it via
connectedcallback. edgefast_open requires the app to allocate the instance, register callbacks, initiate transport connection, then separately initiate the OBEX session.
MCE MAS Connect / Disconnect#
edgefast_bluetooth
/* Register global callbacks (once, before any connection) */
int bt_map_mce_mas_register(struct bt_map_mce_mas_cb *cb);
int bt_map_mce_mas_unregister(void);
/* Initiate L2CAP connection — stack allocates *mce_mas */
int bt_map_mce_psm_connect(struct bt_conn *conn, uint16_t psm,
uint32_t supported_features,
struct bt_map_mce_mas **mce_mas);
/* Initiate RFCOMM connection — stack allocates *mce_mas */
int bt_map_mce_scn_connect(struct bt_conn *conn, uint8_t scn,
uint32_t supported_features,
struct bt_map_mce_mas **mce_mas);
/* Disconnect (OBEX + transport combined) */
int bt_map_mce_disconnect(struct bt_map_mce_mas *mce_mas);
/* Abort current operation */
int bt_map_mce_abort(struct bt_map_mce_mas *mce_mas);
/* Query maximum OBEX packet length */
int bt_map_mce_get_max_pkt_len(struct bt_map_mce_mas *mce_mas, uint16_t *max_pkt_len);
edgefast_open
/* Per-instance callback registration */
int bt_map_mce_mas_cb_register(struct bt_map_mce_mas *mce_mas,
const struct bt_map_mce_mas_cb *cb);
/* Step 1a: initiate RFCOMM transport connection (app owns mce_mas) */
int bt_map_mce_mas_rfcomm_connect(struct bt_conn *conn,
struct bt_map_mce_mas *mce_mas,
uint8_t channel);
/* Step 1b: initiate L2CAP transport connection */
int bt_map_mce_mas_l2cap_connect(struct bt_conn *conn,
struct bt_map_mce_mas *mce_mas,
uint16_t psm);
/* Step 2: send OBEX CONNECT (call from rfcomm_connected / l2cap_connected cb) */
int bt_map_mce_mas_connect(struct bt_map_mce_mas *mce_mas, struct net_buf *buf);
/* OBEX disconnect */
int bt_map_mce_mas_disconnect(struct bt_map_mce_mas *mce_mas, struct net_buf *buf);
/* Transport disconnect */
int bt_map_mce_mas_rfcomm_disconnect(struct bt_map_mce_mas *mce_mas);
int bt_map_mce_mas_l2cap_disconnect(struct bt_map_mce_mas *mce_mas);
/* Abort current operation (takes optional extra-header buf) */
int bt_map_mce_mas_abort(struct bt_map_mce_mas *mce_mas, struct net_buf *buf);
/* OBEX connect callback returns maximum OBEX packet length */
void (*connect)(struct bt_map_mce_mas *mce_mas, uint8_t rsp_code, uint8_t version,
uint16_t mopl, struct net_buf *buf);
edgefast_open has no
bt_map_mce_mas_unregister(), nosupported_featuresparameter on transport connect (passed separately in OBEX CONNECT headers viabuf), and noget_max_pkt_len— themoplvalue is delivered in theconnectcallback.
4. MCE MAS — MAP Operations #
ℹ️ MAP header encoding: edgefast_bluetooth adds OBEX Connection ID, SRM, SRMP, Name and Type headers based on input parameters and provides dedicated helper macros (
BT_MAP_ADD_*,BT_MAP_ADD_BODY, etc.) to add OBEX body and application parameter headers. edgefast_open requires direct OBEX API calls (bt_obex_add_header_conn_id,bt_obex_add_header_srm,bt_obex_add_header_srm_param,bt_obex_add_header_name,bt_obex_add_header_type,bt_obex_add_header_app_param,bt_obex_add_header_body, etc.), giving the app full control over header construction and placement within thestruct net_buf.
ℹ️ Fragmentation control model: For multi-packet operations, the fragmentation control mechanism has been redesigned. In edgefast_bluetooth, segmentation is controlled through
enum bt_obex_req_flags flags(e.g.,BT_OBEX_REQ_START/BT_OBEX_REQ_END) together with abool waitflag for SRMP handling. In edgefast_open, this is simplified to a singlebool final(true = last packet, false = more packets to follow). SRMP handling is no longer part of the API in edgefast_open — app must explicitly add the SRMP header tobufwhen required.
ℹ️ SRM state management: In edgefast_bluetooth, SRM is automatically handled by the stack: it adds the SRM header based on the transport type (L2CAP or RFCOMM) and maintains SRM state internally. In edgefast_open, full responsibility is shifted to the app — all headers, including SRM, must be explicitly added to
buf, and SRM state must be tracked and managed by the app.
ℹ️ Callback behavior differences with SRM enabled: On the client side, edgefast_bluetooth generates a synthetic response callback after sending a request to prompt the app to send the next request, even if no actual response has been received from the peer; edgefast_open does not generate a response callback unless an actual response is received, requiring the app to schedule the next request. On the server side, edgefast_bluetooth immediately generates a synthetic request callback after sending a response to prompt the app to send the next response, even without an actual request from the peer; edgefast_open only generates a request callback when an actual request is received, and the app must explicitly send subsequent responses.
edgefast_bluetooth
int bt_map_mce_set_folder(struct bt_map_mce_mas *mce_mas, char *name);
int bt_map_mce_get_folder_listing(struct bt_map_mce_mas *mce_mas,
struct net_buf *buf, bool wait,
enum bt_obex_req_flags flags);
int bt_map_mce_get_msg_listing(struct bt_map_mce_mas *mce_mas,
struct net_buf *buf, char *name,
bool wait, enum bt_obex_req_flags flags);
int bt_map_mce_get_msg(struct bt_map_mce_mas *mce_mas,
struct net_buf *buf, char *name,
bool wait, enum bt_obex_req_flags flags);
int bt_map_mce_set_msg_status(struct bt_map_mce_mas *mce_mas,
struct net_buf *buf, char *name,
enum bt_obex_req_flags flags);
int bt_map_mce_push_msg(struct bt_map_mce_mas *mce_mas,
struct net_buf *buf, char *name,
enum bt_obex_req_flags flags);
int bt_map_mce_set_ntf_reg(struct bt_map_mce_mas *mce_mas, struct net_buf *buf);
int bt_map_mce_update_inbox(struct bt_map_mce_mas *mce_mas);
int bt_map_mce_get_mas_inst_info(struct bt_map_mce_mas *mce_mas,
struct net_buf *buf, bool wait,
enum bt_obex_req_flags flags);
int bt_map_mce_set_owner_status(struct bt_map_mce_mas *mce_mas,
struct net_buf *buf,
enum bt_obex_req_flags flags);
int bt_map_mce_get_owner_status(struct bt_map_mce_mas *mce_mas,
struct net_buf *buf, bool wait,
enum bt_obex_req_flags flags);
int bt_map_mce_get_convo_listing(struct bt_map_mce_mas *mce_mas,
struct net_buf *buf, bool wait,
enum bt_obex_req_flags flags);
int bt_map_mce_set_ntf_filter(struct bt_map_mce_mas *mce_mas, struct net_buf *buf);
edgefast_open
int bt_map_mce_mas_set_folder(struct bt_map_mce_mas *mce_mas, uint8_t flags,
struct net_buf *buf);
int bt_map_mce_mas_get_folder_listing(struct bt_map_mce_mas *mce_mas, bool final,
struct net_buf *buf);
int bt_map_mce_mas_get_msg_listing(struct bt_map_mce_mas *mce_mas, bool final,
struct net_buf *buf);
int bt_map_mce_mas_get_msg(struct bt_map_mce_mas *mce_mas, bool final,
struct net_buf *buf);
int bt_map_mce_mas_set_msg_status(struct bt_map_mce_mas *mce_mas, bool final,
struct net_buf *buf);
int bt_map_mce_mas_push_msg(struct bt_map_mce_mas *mce_mas, bool final,
struct net_buf *buf);
int bt_map_mce_mas_set_ntf_reg(struct bt_map_mce_mas *mce_mas, bool final,
struct net_buf *buf);
int bt_map_mce_mas_update_inbox(struct bt_map_mce_mas *mce_mas, bool final,
struct net_buf *buf);
int bt_map_mce_mas_get_mas_inst_info(struct bt_map_mce_mas *mce_mas, bool final,
struct net_buf *buf);
int bt_map_mce_mas_set_owner_status(struct bt_map_mce_mas *mce_mas, bool final,
struct net_buf *buf);
int bt_map_mce_mas_get_owner_status(struct bt_map_mce_mas *mce_mas, bool final,
struct net_buf *buf);
int bt_map_mce_mas_get_convo_listing(struct bt_map_mce_mas *mce_mas, bool final,
struct net_buf *buf);
int bt_map_mce_mas_set_ntf_filter(struct bt_map_mce_mas *mce_mas, bool final,
struct net_buf *buf);
5. MCE MNS — Notification Server #
ℹ️ Summary of changes: In edgefast_bluetooth, all MCE MNS servers are registered by a single call
bt_map_mce_mns_register(cb)and it only receivesconnected/disconnectedandsend_eventcallbacks. In edgefast_open, the MCE MNS server must explicitly register typed server structs (one for RFCOMM, one for L2CAP), accept incoming connections in anacceptcallback, register per-instance callbacks, and respond to OBEX CONNECT / DISCONNECT / ABORT requests.
ℹ️ SRM state management: Same as MCE MAS — MAP Operations
ℹ️ Callback behavior differences with SRM enabled: Same as MCE MAS — MAP Operations
edgefast_bluetooth
/* Register global callbacks and all MCE MNS servers */
int bt_map_mce_mns_register(struct bt_map_mce_mns_cb *cb);
int bt_map_mce_mns_unregister(void);
/* Disconnect incoming MNS */
int bt_map_mce_mns_disconnect(struct bt_map_mce_mns *mce_mns);
/* Respond to SendEvent from MSE */
int bt_map_mce_send_event_response(struct bt_map_mce_mns *mce_mns,
uint8_t result, bool wait);
edgefast_open
/* Per-server registration */
int bt_map_mce_mns_rfcomm_register(struct bt_map_mce_mns_rfcomm_server *server);
int bt_map_mce_mns_l2cap_register(struct bt_map_mce_mns_l2cap_server *server);
/* Per-instance callback registration */
int bt_map_mce_mns_cb_register(struct bt_map_mce_mns *mce_mns,
const struct bt_map_mce_mns_cb *cb);
/* Respond to OBEX CONNECT request */
int bt_map_mce_mns_connect(struct bt_map_mce_mns *mce_mns,
uint8_t rsp_code, struct net_buf *buf);
/* Respond to OBEX DISCONNECT request */
int bt_map_mce_mns_disconnect(struct bt_map_mce_mns *mce_mns,
uint8_t rsp_code, struct net_buf *buf);
/* Respond to OBEX ABORT request */
int bt_map_mce_mns_abort(struct bt_map_mce_mns *mce_mns,
uint8_t rsp_code, struct net_buf *buf);
/* Respond to SendEvent from MSE */
int bt_map_mce_mns_send_event(struct bt_map_mce_mns *mce_mns,
uint8_t rsp_code, struct net_buf *buf);
/* Transport disconnect */
int bt_map_mce_mns_rfcomm_disconnect(struct bt_map_mce_mns *mce_mns);
int bt_map_mce_mns_l2cap_disconnect(struct bt_map_mce_mns *mce_mns);
/* Allocate PDU buffer */
struct net_buf *bt_map_mce_mns_create_pdu(struct bt_map_mce_mns *mce_mns,
struct net_buf_pool *pool);
Function renamed
bt_map_mce_send_event_response→bt_map_mce_mns_send_event.bool waitremoved;bufadded for SRMP headers. edgefast_open requires explicit OBEX handshake responses (CONNECT / DISCONNECT / ABORT) that edgefast_bluetooth handled internally.
6. MSE MAS — Server Registration & Responses #
ℹ️ Connection management: In edgefast_bluetooth, MSE MAS is registered with a single global callback and the stack delivers
mse_masobject viaconnectedcallback. In edgefast_open, the app registers typed RFCOMM/L2CAP server structs with anacceptcallback that allocates the instance and registers per-instance callbacks.
ℹ️ MAP header encoding: Same as MCE MAS — MAP Operations
ℹ️ SRM state management: Same as MCE MAS — MAP Operations
ℹ️ Callback behavior differences with SRM enabled: Same as MCE MAS — MAP Operations
edgefast_bluetooth
/* Single global registration */
int bt_map_mse_mas_register(struct bt_map_mse_mas_cb *cb);
int bt_map_mse_mas_unregister(void);
/* Disconnect (combined) */
int bt_map_mse_disconnect(struct bt_map_mse_mas *mse_mas);
/* Query maximum OBEX packet length */
int bt_map_mse_get_max_pkt_len(struct bt_map_mse_mas *mse_mas, uint16_t *max_pkt_len);
/* Response functions */
int bt_map_mse_set_folder_response(struct bt_map_mse_mas *mse_mas, uint8_t result);
int bt_map_mse_get_folder_listing_response(struct bt_map_mse_mas *mse_mas,
uint8_t result, struct net_buf *buf, bool wait);
int bt_map_mse_get_msg_listing_response(struct bt_map_mse_mas *mse_mas,
uint8_t result, struct net_buf *buf, bool wait);
int bt_map_mse_get_msg_response(struct bt_map_mse_mas *mse_mas,
uint8_t result, struct net_buf *buf, bool wait);
int bt_map_mse_set_msg_status_response(struct bt_map_mse_mas *mse_mas, uint8_t result);
int bt_map_mse_push_msg_response(struct bt_map_mse_mas *mse_mas,
uint8_t result, char *name, bool wait);
int bt_map_mse_set_ntf_reg_response(struct bt_map_mse_mas *mse_mas, uint8_t result);
int bt_map_mse_update_inbox_response(struct bt_map_mse_mas *mse_mas, uint8_t result);
int bt_map_mse_get_mas_inst_info_response(struct bt_map_mse_mas *mse_mas,
uint8_t result, struct net_buf *buf, bool wait);
int bt_map_mse_set_owner_status_response(struct bt_map_mse_mas *mse_mas, uint8_t result);
int bt_map_mse_get_owner_status_response(struct bt_map_mse_mas *mse_mas,
uint8_t result, struct net_buf *buf, bool wait);
int bt_map_mse_get_convo_listing_response(struct bt_map_mse_mas *mse_mas,
uint8_t result, struct net_buf *buf, bool wait);
int bt_map_mse_set_ntf_filter_response(struct bt_map_mse_mas *mse_mas, uint8_t result);
edgefast_open
/* Per-server registration */
int bt_map_mse_mas_rfcomm_register(struct bt_map_mse_mas_rfcomm_server *server);
int bt_map_mse_mas_l2cap_register(struct bt_map_mse_mas_l2cap_server *server);
/* Per-instance callback registration */
int bt_map_mse_mas_cb_register(struct bt_map_mse_mas *mse_mas,
const struct bt_map_mse_mas_cb *cb);
/* Explicit OBEX handshake responses */
int bt_map_mse_mas_connect(struct bt_map_mse_mas *mse_mas,
uint8_t rsp_code, struct net_buf *buf);
int bt_map_mse_mas_disconnect(struct bt_map_mse_mas *mse_mas,
uint8_t rsp_code, struct net_buf *buf);
int bt_map_mse_mas_abort(struct bt_map_mse_mas *mse_mas,
uint8_t rsp_code, struct net_buf *buf);
/* Transport disconnect */
int bt_map_mse_mas_rfcomm_disconnect(struct bt_map_mse_mas *mse_mas);
int bt_map_mse_mas_l2cap_disconnect(struct bt_map_mse_mas *mse_mas);
/* Response functions */
int bt_map_mse_mas_set_folder(struct bt_map_mse_mas *mse_mas,
uint8_t rsp_code, struct net_buf *buf);
int bt_map_mse_mas_get_folder_listing(struct bt_map_mse_mas *mse_mas,
uint8_t rsp_code, struct net_buf *buf);
int bt_map_mse_mas_get_msg_listing(struct bt_map_mse_mas *mse_mas,
uint8_t rsp_code, struct net_buf *buf);
int bt_map_mse_mas_get_msg(struct bt_map_mse_mas *mse_mas,
uint8_t rsp_code, struct net_buf *buf);
int bt_map_mse_mas_set_msg_status(struct bt_map_mse_mas *mse_mas,
uint8_t rsp_code, struct net_buf *buf);
int bt_map_mse_mas_push_msg(struct bt_map_mse_mas *mse_mas,
uint8_t rsp_code, struct net_buf *buf);
int bt_map_mse_mas_set_ntf_reg(struct bt_map_mse_mas *mse_mas,
uint8_t rsp_code, struct net_buf *buf);
int bt_map_mse_mas_update_inbox(struct bt_map_mse_mas *mse_mas,
uint8_t rsp_code, struct net_buf *buf);
int bt_map_mse_mas_get_mas_inst_info(struct bt_map_mse_mas *mse_mas,
uint8_t rsp_code, struct net_buf *buf);
int bt_map_mse_mas_set_owner_status(struct bt_map_mse_mas *mse_mas,
uint8_t rsp_code, struct net_buf *buf);
int bt_map_mse_mas_get_owner_status(struct bt_map_mse_mas *mse_mas,
uint8_t rsp_code, struct net_buf *buf);
int bt_map_mse_mas_get_convo_listing(struct bt_map_mse_mas *mse_mas,
uint8_t rsp_code, struct net_buf *buf);
int bt_map_mse_mas_set_ntf_filter(struct bt_map_mse_mas *mse_mas,
uint8_t rsp_code, struct net_buf *buf);
/* Allocate PDU buffer */
struct net_buf *bt_map_mse_mas_create_pdu(struct bt_map_mse_mas *mse_mas,
struct net_buf_pool *pool);
All response functions renamed from
bt_map_mse_*_response()→bt_map_mse_mas_*().bool waitremoved.bufalways present.char *nameremoved — name encoded inbuf.
7. MSE MNS — Notification Client #
ℹ️ MAP header encoding: Same as MCE MAS — MAP Operations
ℹ️ SRM state management: Same as MCE MAS — MAP Operations
ℹ️ Callback behavior differences with SRM enabled: Same as MCE MAS — MAP Operations
edgefast_bluetooth
/* Register global callbacks */
int bt_map_mse_mns_register(struct bt_map_mse_mns_cb *cb);
int bt_map_mse_mns_unregister(void);
/* Initiate L2CAP connection to MCE MNS */
int bt_map_mse_mns_psm_connect(struct bt_conn *conn, uint16_t psm,
uint32_t supported_features,
struct bt_map_mse_mns **mse_mns);
/* Initiate RFCOMM connection to MCE MNS */
int bt_map_mse_mns_scn_connect(struct bt_conn *conn, uint8_t scn,
uint32_t supported_features,
struct bt_map_mse_mns **mse_mns);
/* Disconnect */
int bt_map_mse_mns_disconnect(struct bt_map_mse_mns *mse_mns);
/* Send event to MCE (fragmented with flags) */
int bt_map_mse_send_event(struct bt_map_mse_mns *mse_mns,
struct net_buf *buf,
enum bt_obex_req_flags flags);
/* Query negotiated MTU */
int bt_map_mse_mns_get_max_pkt_len(struct bt_map_mse_mns *mse_mns,
uint16_t *max_pkt_len);
/* Reserve space: BT_MAP_MSE_RSV_LEN_SEND_EVENT(mse_mns, flags) */
edgefast_open
/* Per-instance callback registration */
int bt_map_mse_mns_cb_register(struct bt_map_mse_mns *mse_mns,
const struct bt_map_mse_mns_cb *cb);
/* Step 1a: initiate RFCOMM transport connection (app owns mse_mns) */
int bt_map_mse_mns_rfcomm_connect(struct bt_conn *conn,
struct bt_map_mse_mns *mse_mns,
uint8_t channel);
/* Step 1b: initiate L2CAP transport connection */
int bt_map_mse_mns_l2cap_connect(struct bt_conn *conn,
struct bt_map_mse_mns *mse_mns,
uint16_t psm);
/* Step 2: send OBEX CONNECT */
int bt_map_mse_mns_connect(struct bt_map_mse_mns *mse_mns, struct net_buf *buf);
/* OBEX disconnect */
int bt_map_mse_mns_disconnect(struct bt_map_mse_mns *mse_mns, struct net_buf *buf);
/* Transport disconnect */
int bt_map_mse_mns_rfcomm_disconnect(struct bt_map_mse_mns *mse_mns);
int bt_map_mse_mns_l2cap_disconnect(struct bt_map_mse_mns *mse_mns);
/* OBEX abort */
int bt_map_mse_mns_abort(struct bt_map_mse_mns *mse_mns, struct net_buf *buf);
/* Send event to MCE (fragmented with bool final) */
int bt_map_mse_mns_send_event(struct bt_map_mse_mns *mse_mns, bool final,
struct net_buf *buf);
/* Allocate PDU buffer */
struct net_buf *bt_map_mse_mns_create_pdu(struct bt_map_mse_mns *mse_mns,
struct net_buf_pool *pool);
Function renamed
bt_map_mse_send_event→bt_map_mse_mns_send_event.enum bt_obex_req_flags flags→bool final. Two-step transport + OBEX connect replaces one-steppsm_connect/scn_connect. MSE MNS callbacksconnected(mse_mns)/disconnected(mse_mns, result)/send_event(mse_mns, result)in edgefast_bluetooth become split transport + OBEX callbacks in edgefast_open.
8. Callback Structures Comparison #
8.1 MCE MAS Callbacks#
Callback |
edgefast_bluetooth |
edgefast_open |
Notes |
|---|---|---|---|
Transport connected |
|
|
🟡 edgefast_open exposes |
Transport disconnected |
|
|
🟡 No result code in edgefast_open transport disconnect |
OBEX connect |
— (implicit in |
|
🟡 edgefast_open explicit OBEX connect response with OBEX version + MOPL |
OBEX disconnect |
— (implicit in |
|
🟡 edgefast_open explicit OBEX disconnect response |
OBEX abort response |
|
|
🟡 edgefast_open adds |
get_folder_listing |
|
|
🟡 Identical semantics; parameter renamed |
set_folder |
|
|
🟡 edgefast_open adds |
get_msg_listing |
|
|
🟡 Identical |
get_msg |
|
|
🟡 Identical |
set_msg_status |
|
|
🟡 edgefast_open adds |
push_msg |
|
|
🟡 |
set_ntf_reg |
|
|
🟡 edgefast_open adds |
update_inbox |
|
|
🟡 edgefast_open adds |
get_mas_inst_info |
|
|
🟡 Identical |
set_owner_status |
|
|
🟡 edgefast_open adds |
get_owner_status |
|
|
🟡 Identical |
get_convo_listing |
|
|
🟡 Identical |
set_ntf_filter |
|
|
🟡 edgefast_open adds |
8.2 MCE MNS Callbacks#
Callback |
edgefast_bluetooth |
edgefast_open |
Notes |
|---|---|---|---|
Transport connected |
|
|
🟡 edgefast_open exposes |
Transport disconnected |
|
|
🟡 No result code in edgefast_open transport disconnect |
OBEX connect request |
— (implicit in |
|
🟡 edgefast_open receives explicit CONNECT request and must respond |
OBEX disconnect request |
— (implicit in |
|
🟡 edgefast_open receives explicit DISCONNECT request and must respond |
OBEX abort request |
— |
|
🔴 edgefast_open only |
send_event |
|
|
🟡 edgefast_bluetooth uses |
8.3 MSE MAS Callbacks#
Callback |
edgefast_bluetooth |
edgefast_open |
Notes |
|---|---|---|---|
Transport connected |
|
|
🟡 edgefast_bluetooth delivers assigned PSM/SCN in callback; edgefast_open exposes |
Transport disconnected |
|
|
🟡 No result code in edgefast_open transport disconnect |
OBEX connect request |
— (implicit in |
|
🟡 edgefast_open requires explicit CONNECT handshake response |
OBEX disconnect request |
— (implicit in |
|
🟡 edgefast_open requires explicit DISCONNECT handshake response |
OBEX abort request |
|
|
🟡 edgefast_bluetooth handles abort response internally; edgefast_open requires explicit response |
get_folder_listing |
|
|
🟡 edgefast_open uses |
set_folder |
|
|
🟡 edgefast_bluetooth delivers name string; edgefast_open delivers flags + raw buf with name encoded in |
get_msg_listing |
|
|
🟡 |
get_msg |
|
|
🟡 |
set_msg_status |
|
|
🟡 |
push_msg |
|
|
🟡 |
set_ntf_reg |
|
|
🟡 Identical |
update_inbox |
|
|
🟡 edgefast_open passes |
get_mas_inst_info |
|
|
🟡 Identical |
set_owner_status |
|
|
🟡 Identical |
get_owner_status |
|
|
🟡 Identical |
get_convo_listing |
|
|
🟡 Identical |
set_ntf_filter |
|
|
🟡 Identical |
8.4 MSE MNS Callbacks#
Callback |
edgefast_bluetooth |
edgefast_open |
Notes |
|---|---|---|---|
Transport connected |
|
|
🟡 edgefast_open exposes |
Transport disconnected |
|
|
🟡 No result code in edgefast_open transport disconnect |
OBEX connect response |
— (implicit in |
|
🟡 edgefast_open explicit OBEX connect response with OBEX version + MOPL |
OBEX disconnect response |
— (implicit in |
|
🟡 edgefast_open explicit OBEX disconnect response |
OBEX abort response |
— |
|
🔴 edgefast_open only |
send_event response |
|
|
🟡 edgefast_open adds |
9. Full Function Comparison Table #
9.1 MCE MAS Functions#
edgefast_bluetooth |
edgefast_open |
Notes |
|---|---|---|
|
|
🟡 Global register replaced by per-instance |
|
— |
🟢 |
|
|
🟡 Stack allocates vs app allocates; no |
|
|
🟡 |
— |
|
🔴 Explicit OBEX CONNECT request |
|
|
🟡 edgefast_open takes |
— |
|
🔴 |
— |
|
🔴 |
|
|
🟡 edgefast_open takes |
|
— |
🟢 MOPL delivered in OBEX |
|
|
🟡 PDU buffer helper |
|
|
🟡 Name string → OBEX Name header in buf; explicit |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 edgefast_open adds |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 |
9.2 MCE MNS Functions#
edgefast_bluetooth |
edgefast_open |
Notes |
|---|---|---|
|
|
🟡 edgefast_open registers individual servers and per-instance callbacks; edgefast_bluetooth resgiter global callbacks and all servers |
|
— |
🟢 |
|
|
🟡 Split by transport |
— |
|
🔴 Explicit OBEX CONNECT response |
— |
|
🔴 Explicit OBEX DISCONNECT response |
— |
|
🔴 Abort response was internal in edgefast_bluetooth |
|
|
🟡 Renamed; |
|
— |
🟢 MOPL delivered in OBEX |
|
|
🟡 PDU buffer helper |
9.3 MSE MAS Functions#
edgefast_bluetooth |
edgefast_open |
Notes |
|---|---|---|
|
|
🟡 edgefast_open registers individual servers and per-instance callbacks; edgefast_bluetooth resgiters global callbacks and all servers |
|
— |
🟢 |
|
|
🟡 Split by transport |
— |
|
🔴 Explicit OBEX CONNECT response |
— |
|
🔴 Explicit OBEX DISCONNECT response |
— |
|
🔴 Abort response was internal in edgefast_bluetooth |
|
— |
🟢 MOPL delivered in OBEX |
|
|
🟡 PDU buffer helper |
|
|
🟡 edgefast_open adds |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 edgefast_open adds |
|
|
🟡 |
|
|
🟡 edgefast_open adds |
|
|
🟡 edgefast_open adds |
|
|
🟡 |
|
|
🟡 edgefast_open adds |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 edgefast_open adds |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 |
|
|
🟡 |
9.4 MSE MNS Functions#
edgefast_bluetooth |
edgefast_open |
Notes |
|---|---|---|
|
|
🟡 Global register replaced by per-instance |
|
— |
🟢 |
|
|
🟡 Stack allocates vs app allocates; |
|
|
🟡 |
— |
|
🔴 Explicit OBEX CONNECT request |
|
|
🟡 edgefast_open OBEX disconnect takes |
— |
|
🔴 |
— |
|
🔴 |
— |
|
🔴 Explicit OBEX ABORT |
|
|
🟡 Renamed; |
|
— |
🟢 MOPL delivered in OBEX |
|
|
🟡 PDU buffer helper |
10. Architecture Summary #
ℹ️ A quick reference comparing the two stacks across every dimension of MAP API design.
Dimension |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
Object model |
Stack-managed opaque pointers; app receives |
App-owned structs embedded in app context |
Instance allocation |
Stack allocates on incoming connection or |
App pre-allocates array; instance pointer passed at |
Callback registration |
One |
Per-instance |
Transport layer |
Transparent; single |
Explicit: |
OBEX layer |
Implicit within |
Explicit: |
OBEX DISCONNECT/ABORT |
Handled internally by stack |
App must explicitly call |
Server registration |
Single |
Typed server structs ( |
SRM management |
Automatic: stack adds SRM header and manages SRM state |
Manual: app adds |
SRMP (wait) |
|
Manual: app adds |
Fragmentation |
|
|
Max packet length |
|
Delivered in OBEX |
Buffer allocation |
App pre-allocates with |
App calls |
Name / handle passing |
Dedicated |
Encoded as OBEX Name header inside |
App parameter helpers |
|
|
Body helpers |
|
|
App param parsing |
|
|
SDP registration |
Managed by stack |
App calls |
Migration Checklist (edgefast_bluetooth → edgefast_open)#
☐ Replace single
bt_map_mce_mas_register(cb)with per-instancebt_map_mce_mas_cb_register(mce_mas, cb)called before transport connect☐ Split
bt_map_mce_psm_connect()intobt_map_mce_mas_l2cap_connect()(transport) +bt_map_mce_mas_connect(buf)(OBEX)☐ Add Target UUID and supported-features app param TLV to OBEX CONNECT
buf☐ Add Connection ID, SRM(if required), SRMP(if required) and Type headers to OBEX PUT/GET/SETPATH
bufusingbt_obex_add_header_*☐ Store
moplfromconnect(rsp_code, version, mopl, buf)callback; replaceget_max_pkt_len()with this value☐ Replace
BT_MAP_MCE_RSV_LEN_*+net_buf_reservewithbt_map_mce_mas_create_pdu(mce_mas, pool)☐ Replace
BT_MAP_ADD_*TLV macros withstruct bt_obex_tlv[]+bt_obex_add_header_app_param()☐ Replace
BT_MAP_ADD_BODY/BT_MAP_ADD_END_OF_BODYmacros withbt_obex_add_header_body/bt_obex_add_header_end_body/bt_obex_add_header_body_or_end_body☐ Replace
char *nameparameters withbt_obex_add_header_name(buf, unicode_len, unicode_name)(name must be UTF-16BE encoded)☐ Replace
flags/waitparameters withbool final; manage SRM/SRMP headers manually☐ Replace
bt_map_mce_mns_register(cb)with typed server registration:bt_map_mce_mns_rfcomm_register(server)+bt_map_mce_mns_l2cap_register(server)withacceptcallback☐ Add explicit
bt_map_mce_mns_connect(mce_mns, rsp_code, buf)inconnectcallback; adddisconnectandabortresponse calls☐ Replace
bt_map_mce_send_event_response(mce_mns, result, wait)withbt_map_mce_mns_send_event(mce_mns, rsp_code, buf)☐ On MSE side: replace
bt_map_mse_mas_register(cb)with typedbt_map_mse_mas_rfcomm_register(server)/bt_map_mse_mas_l2cap_register(server)+acceptcallback☐ Add explicit
bt_map_mse_mas_connect(rsp_code, buf)/disconnect(rsp_code, buf)/abort(rsp_code, buf)response calls☐ Rename all
bt_map_mse_*_response(result, buf, wait)→bt_map_mse_mas_*(rsp_code, buf)removingwait☐ Register SDP records with
bt_sdp_register_service()after server registration
11. edgefast_open API Usage Examples (Code Snapshots) #
⚠️ Source files:
middleware/edgefast_open/source/bluetooth/host/classic/shell/map.c
ℹ️ All examples use
NET_BUF_POOL_FIXED_DEFINEpools andbt_map_*_create_pdu()for buffer allocation. Theconn_idis stored from the OBEXconnectcallback and inserted in every subsequent request. SRM/SRMP headers are managed manually by tracking auint8_t srmbitmask.
11.1 MCE MAS — Connection Setup (RFCOMM)#
Two-step connection: first establish RFCOMM transport, then in the transport callback send OBEX CONNECT with Target UUID and supported features.
/* Step 1: allocate app-owned instance, register callbacks, initiate transport */
struct mce_mas_instance {
struct bt_map_mce_mas mce_mas; /* must be first — embedded MAP object */
struct bt_conn *conn;
uint32_t conn_id;
uint16_t mopl;
uint8_t srm;
};
static struct mce_mas_instance g_inst;
static struct bt_map_mce_mas_cb mce_mas_cb = {
.rfcomm_connected = mce_mas_rfcomm_connected,
.rfcomm_disconnected = mce_mas_rfcomm_disconnected,
.l2cap_connected = mce_mas_l2cap_connected,
.l2cap_disconnected = mce_mas_l2cap_disconnected,
.connect = mce_mas_connect,
.disconnect = mce_mas_disconnect,
.abort = mce_mas_abort,
/* ... MAP operation callbacks ... */
};
/* Register per-instance callbacks and start RFCOMM transport */
bt_map_mce_mas_cb_register(&g_inst.mce_mas, &mce_mas_cb);
bt_map_mce_mas_rfcomm_connect(default_conn, &g_inst.mce_mas, channel);
/* Step 2: in rfcomm_connected callback — send OBEX CONNECT */
static void mce_mas_rfcomm_connected(struct bt_conn *conn,
struct bt_map_mce_mas *mce_mas)
{
struct net_buf *buf = bt_map_mce_mas_create_pdu(mce_mas, &mas_tx_pool);
const struct bt_uuid_128 *uuid = BT_MAP_UUID_MAS;
uint8_t val[BT_UUID_SIZE_128];
/* Add Target header: MAP MAS UUID (byte-swapped) */
sys_memcpy_swap(val, uuid->val, sizeof(val));
bt_obex_add_header_target(buf, sizeof(val), val);
/* Add MAP supported features as application parameter TLV */
uint32_t features = sys_cpu_to_be32(0x0077FFFF);
struct bt_obex_tlv appl_params[] = {
{ BT_MAP_APPL_PARAM_TAG_ID_MAP_SUPPORTED_FEATURES,
sizeof(features), (const uint8_t *)&features },
};
bt_obex_add_header_app_param(buf, ARRAY_SIZE(appl_params), appl_params);
bt_map_mce_mas_connect(mce_mas, buf); /* buf ownership transferred */
}
/* Step 3: in connect callback — store mopl and conn_id */
static void mce_mas_connect(struct bt_map_mce_mas *mce_mas, uint8_t rsp_code,
uint8_t version, uint16_t mopl, struct net_buf *buf)
{
struct mce_mas_instance *inst =
CONTAINER_OF(mce_mas, struct mce_mas_instance, mce_mas);
inst->mopl = mopl;
bt_obex_get_header_conn_id(buf, &inst->conn_id);
}
11.2 MCE MAS — SetFolder#
Navigate the remote folder tree. Path logic determines flags; name is UTF-16BE encoded into buf.
static void do_set_folder(struct bt_map_mce_mas *mce_mas, const char *path)
{
struct mce_mas_instance *inst =
CONTAINER_OF(mce_mas, struct mce_mas_instance, mce_mas);
uint8_t flags;
const char *name;
/* Determine flags and name from path string */
if (strcmp(path, "/") == 0) {
flags = BT_MAP_SET_FOLDER_FLAGS_ROOT;
name = NULL;
} else if (strncmp(path, "..", 2) == 0) {
flags = BT_MAP_SET_FOLDER_FLAGS_UP;
name = (path[2] == '/') ? &path[3] : NULL; /* "../child" or ".." */
} else {
flags = BT_MAP_SET_FOLDER_FLAGS_DOWN;
name = path; /* "telecom" or "msg" */
}
struct net_buf *buf = bt_map_mce_mas_create_pdu(mce_mas, &mas_tx_pool);
bt_obex_add_header_conn_id(buf, inst->conn_id);
/* Encode name as UTF-16BE in OBEX Name header */
if (name && strlen(name) > 0) {
char unicode[64];
uint16_t name_len = strlen(name);
memset(unicode, 0, sizeof(unicode));
for (int i = 0; i < name_len; i++) {
unicode[i * 2 + 1] = name[i]; /* ASCII → UTF-16BE */
}
bt_obex_add_header_name(buf, name_len * 2 + 2, unicode);
} else {
bt_obex_add_header_name(buf, 0, NULL);
}
bt_map_mce_mas_set_folder(mce_mas, flags, buf);
/* Response in mce_mas_cb.set_folder(mce_mas, rsp_code, buf) */
}
11.3 MCE MAS — SetNotificationRegistration#
Enable/disable MSE notifications. Requires Type header, NtfStatus TLV, and a 1-byte filler body.
static void do_set_ntf_reg(struct bt_map_mce_mas *mce_mas, uint8_t ntf_status)
{
struct mce_mas_instance *inst =
CONTAINER_OF(mce_mas, struct mce_mas_instance, mce_mas);
struct net_buf *buf = bt_map_mce_mas_create_pdu(mce_mas, &mas_tx_pool);
uint16_t len = 0;
bt_obex_add_header_conn_id(buf, inst->conn_id);
/* Type header: x-bt/MAP-NotificationRegistration */
bt_obex_add_header_type(buf, sizeof(BT_MAP_HDR_TYPE_SET_NTF_REG),
BT_MAP_HDR_TYPE_SET_NTF_REG);
/* Application parameter: NtfStatus (0x01 = ON, 0x00 = OFF) */
struct bt_obex_tlv appl_params[] = {
{ BT_MAP_APPL_PARAM_TAG_ID_NTF_STATUS, sizeof(ntf_status),
(const uint8_t *)&ntf_status },
};
bt_obex_add_header_app_param(buf, ARRAY_SIZE(appl_params), appl_params);
/* Filler body (MAP spec requires a body for PUT operations) */
bt_obex_add_header_body_or_end_body(buf, inst->mopl, 1,
BT_MAP_FILLER_BYTE, &len);
bt_map_mce_mas_set_ntf_reg(mce_mas, true /* final */, buf);
/* Response in mce_mas_cb.set_ntf_reg(mce_mas, rsp_code, buf) */
}
11.4 MCE MAS — GetFolderListing (with SRM)#
GET operation with optional SRM acceleration. SRM header added on first request; subsequent continuation handled by checking rsp_code.
static void do_get_folder_listing(struct bt_map_mce_mas *mce_mas)
{
struct mce_mas_instance *inst =
CONTAINER_OF(mce_mas, struct mce_mas_instance, mce_mas);
struct net_buf *buf = bt_map_mce_mas_create_pdu(mce_mas, &mas_tx_pool);
if (inst->rsp_code == BT_OBEX_RSP_CODE_CONTINUE) {
/* Continuation packet — SRM enabled, no need to resend headers */
if (is_srm_no_wait_enabled(inst->srm)) {
net_buf_unref(buf);
return; /* SRM in no-wait mode — server sends without MCE re-request */
}
/* SRM disabled or waiting: resend without initial headers */
bt_map_mce_mas_get_folder_listing(mce_mas, true, buf);
return;
}
/* First request: add all headers */
bt_obex_add_header_conn_id(buf, inst->conn_id);
/* Request SRM if using L2CAP (GOEP v2) */
if (inst->goep_v2) {
bt_obex_add_header_srm(buf, BT_OBEX_SRM_ENABLE);
inst->srm |= LOCAL_SRM_ENABLED;
}
bt_obex_add_header_type(buf, sizeof(BT_MAP_HDR_TYPE_GET_FOLDER_LISTING),
BT_MAP_HDR_TYPE_GET_FOLDER_LISTING);
/* Optional: add MaxListCount / ListStartOffset as app params */
uint16_t max_list_count = sys_cpu_to_be16(1024);
struct bt_obex_tlv appl_params[] = {
{ BT_MAP_APPL_PARAM_TAG_ID_MAX_LIST_CNT, sizeof(max_list_count),
(const uint8_t *)&max_list_count },
};
bt_obex_add_header_app_param(buf, ARRAY_SIZE(appl_params), appl_params);
bt_map_mce_mas_get_folder_listing(mce_mas, true /* final */, buf);
}
/* In get_folder_listing response callback */
static void mce_mas_get_folder_listing(struct bt_map_mce_mas *mce_mas,
uint8_t rsp_code, struct net_buf *buf)
{
struct mce_mas_instance *inst =
CONTAINER_OF(mce_mas, struct mce_mas_instance, mce_mas);
/* Parse folder-listing XML body from buf here */
inst->rsp_code = rsp_code;
if (rsp_code == BT_OBEX_RSP_CODE_CONTINUE) {
/* Check if remote accepted SRM */
parse_header_srm_rsp(buf, &inst->srm);
parse_header_srm_param_rsp(buf, &inst->srm);
/* If SRM no-wait not enabled, app must call do_get_folder_listing again */
} else {
inst->srm = 0; /* Reset SRM state at end of operation */
}
}
11.5 MCE MAS — GetMessageListing#
Similar to GetFolderListing but with a subfolder Name header and message-listing-specific app params.
static void do_get_msg_listing(struct bt_map_mce_mas *mce_mas, const char *folder_name)
{
struct mce_mas_instance *inst =
CONTAINER_OF(mce_mas, struct mce_mas_instance, mce_mas);
struct net_buf *buf = bt_map_mce_mas_create_pdu(mce_mas, &mas_tx_pool);
bt_obex_add_header_conn_id(buf, inst->conn_id);
if (inst->goep_v2) {
bt_obex_add_header_srm(buf, BT_OBEX_SRM_ENABLE);
inst->srm |= LOCAL_SRM_ENABLED;
}
bt_obex_add_header_type(buf, sizeof(BT_MAP_HDR_TYPE_GET_MSG_LISTING),
BT_MAP_HDR_TYPE_GET_MSG_LISTING);
/* Encode subfolder name as UTF-16BE (NULL name = current folder) */
if (folder_name && strlen(folder_name) > 0) {
uint16_t name_len = strlen(folder_name);
char unicode[64] = {0};
for (int i = 0; i < name_len; i++) {
unicode[i * 2 + 1] = folder_name[i];
}
bt_obex_add_header_name(buf, name_len * 2 + 2, unicode);
} else {
bt_obex_add_header_name(buf, 0, NULL);
}
/* App params: MaxListCount=100, FilterMessageType=0 (all types) */
uint16_t max_cnt = sys_cpu_to_be16(100);
uint8_t filter_type = 0x00;
struct bt_obex_tlv appl_params[] = {
{ BT_MAP_APPL_PARAM_TAG_ID_MAX_LIST_CNT, sizeof(max_cnt),
(const uint8_t *)&max_cnt },
{ BT_MAP_APPL_PARAM_TAG_ID_FILTER_MSG_TYPE, sizeof(filter_type),
(const uint8_t *)&filter_type },
};
bt_obex_add_header_app_param(buf, ARRAY_SIZE(appl_params), appl_params);
bt_map_mce_mas_get_msg_listing(mce_mas, true /* final */, buf);
/* Response in mce_mas_cb.get_msg_listing(mce_mas, rsp_code, buf) */
}
11.6 MCE MAS — GetMessage#
Retrieve a specific message by handle (encoded as Name header). Charset and Attachment app params control the response format.
static void do_get_msg(struct bt_map_mce_mas *mce_mas, const char *msg_handle)
{
struct mce_mas_instance *inst =
CONTAINER_OF(mce_mas, struct mce_mas_instance, mce_mas);
struct net_buf *buf = bt_map_mce_mas_create_pdu(mce_mas, &mas_tx_pool);
bt_obex_add_header_conn_id(buf, inst->conn_id);
if (inst->goep_v2) {
bt_obex_add_header_srm(buf, BT_OBEX_SRM_ENABLE);
inst->srm |= LOCAL_SRM_ENABLED;
}
bt_obex_add_header_type(buf, sizeof(BT_MAP_HDR_TYPE_GET_MSG),
BT_MAP_HDR_TYPE_GET_MSG);
/* Message handle as UTF-16BE Name header */
uint16_t handle_len = strlen(msg_handle);
char unicode[32] = {0};
for (int i = 0; i < handle_len; i++) {
unicode[i * 2 + 1] = msg_handle[i];
}
bt_obex_add_header_name(buf, handle_len * 2 + 2, unicode);
/* App params: Charset=UTF-8, Attachment=1 */
uint8_t charset = BT_MAP_CHARSET_UTF8;
uint8_t attachment = BT_MAP_ATTACHMENT_ON;
struct bt_obex_tlv appl_params[] = {
{ BT_MAP_APPL_PARAM_TAG_ID_CHARSET, sizeof(charset),
(const uint8_t *)&charset },
{ BT_MAP_APPL_PARAM_TAG_ID_ATTACHMENT, sizeof(attachment),
(const uint8_t *)&attachment },
};
bt_obex_add_header_app_param(buf, ARRAY_SIZE(appl_params), appl_params);
bt_map_mce_mas_get_msg(mce_mas, true /* final */, buf);
/* Message body arrives in mce_mas_cb.get_msg(mce_mas, rsp_code, buf) */
}
11.7 MCE MAS — SetMessageStatus#
Mark a message as read. StatusIndicator and StatusValue TLVs control which attribute to change.
static void do_set_msg_status(struct bt_map_mce_mas *mce_mas,
const char *msg_handle)
{
struct mce_mas_instance *inst =
CONTAINER_OF(mce_mas, struct mce_mas_instance, mce_mas);
struct net_buf *buf = bt_map_mce_mas_create_pdu(mce_mas, &mas_tx_pool);
uint16_t len = 0;
bt_obex_add_header_conn_id(buf, inst->conn_id);
/* Encode message handle as UTF-16BE Name header */
uint16_t handle_len = strlen(msg_handle);
char unicode[32] = {0};
for (int i = 0; i < handle_len; i++) {
unicode[i * 2 + 1] = msg_handle[i];
}
bt_obex_add_header_name(buf, handle_len * 2 + 2, unicode);
bt_obex_add_header_type(buf, sizeof(BT_MAP_HDR_TYPE_SET_MSG_STATUS),
BT_MAP_HDR_TYPE_SET_MSG_STATUS);
/* StatusIndicator=READ (0), StatusValue=YES (1) → mark as read */
uint8_t status_ind = BT_MAP_STATUS_IND_READ;
uint8_t status_val = BT_MAP_STATUS_VAL_YES;
struct bt_obex_tlv appl_params[] = {
{ BT_MAP_APPL_PARAM_TAG_ID_STATUS_IND, sizeof(status_ind),
(const uint8_t *)&status_ind },
{ BT_MAP_APPL_PARAM_TAG_ID_STATUS_VAL, sizeof(status_val),
(const uint8_t *)&status_val },
};
bt_obex_add_header_app_param(buf, ARRAY_SIZE(appl_params), appl_params);
/* Filler body required for PUT operations */
bt_obex_add_header_body_or_end_body(buf, inst->mopl, 1, BT_MAP_FILLER_BYTE, &len);
bt_map_mce_mas_set_msg_status(mce_mas, true /* final */, buf);
/* Response in mce_mas_cb.set_msg_status(mce_mas, rsp_code, buf) */
}
11.8 MCE MAS — PushMessage (fragmented body)#
Large message bodies are split across multiple OBEX PUT packets. The bool final is determined by whether bt_obex_add_header_body_or_end_body placed an end-of-body header.
static const char *MSG_BODY =
"BEGIN:BMSG\r\n"
"VERSION:1.0\r\nSTATUS:UNREAD\r\nTYPE:SMS_GSM\r\nFOLDER:\r\n"
"BEGIN:VCARD\r\nVERSION:2.1\r\nN;CHARSET=UTF-8:\r\nTEL;CHARSET=UTF-8:\r\n"
"END:VCARD\r\n"
"BEGIN:BENV\r\nBEGIN:VCARD\r\nVERSION:2.1\r\nFN;CHARSET=UTF-8:+0123456789\r\n"
"TEL:+0123456789\r\nEND:VCARD\r\n"
"BEGIN:BBODY\r\nCHARSET:UTF-8\r\nLENGTH:50\r\n"
"BEGIN:MSG\r\nHello from edgefast_open MAP!\r\nEND:MSG\r\n"
"END:BBODY\r\nEND:BENV\r\nEND:BMSG";
static uint16_t g_tx_cnt = 0; /* bytes already sent */
static void do_push_msg(struct bt_map_mce_mas *mce_mas, const char *folder)
{
struct mce_mas_instance *inst =
CONTAINER_OF(mce_mas, struct mce_mas_instance, mce_mas);
struct net_buf *buf = bt_map_mce_mas_create_pdu(mce_mas, &mas_tx_pool);
uint16_t len = 0;
bool final;
if (g_tx_cnt > 0) {
/* Continuation: only body data needed */
goto continue_req;
}
/* First packet: headers + first body chunk */
bt_obex_add_header_conn_id(buf, inst->conn_id);
if (inst->goep_v2) {
bt_obex_add_header_srm(buf, BT_OBEX_SRM_ENABLE);
inst->srm |= LOCAL_SRM_ENABLED;
}
bt_obex_add_header_type(buf, sizeof(BT_MAP_HDR_TYPE_PUSH_MSG),
BT_MAP_HDR_TYPE_PUSH_MSG);
/* Target folder as UTF-16BE Name header */
if (folder && strlen(folder) > 0) {
uint16_t flen = strlen(folder);
char unicode[64] = {0};
for (int i = 0; i < flen; i++) {
unicode[i * 2 + 1] = folder[i];
}
bt_obex_add_header_name(buf, flen * 2 + 2, unicode);
} else {
bt_obex_add_header_name(buf, 0, NULL);
}
/* App params: Charset=UTF-8 */
uint8_t charset = BT_MAP_CHARSET_UTF8;
struct bt_obex_tlv appl_params[] = {
{ BT_MAP_APPL_PARAM_TAG_ID_CHARSET, sizeof(charset),
(const uint8_t *)&charset },
};
bt_obex_add_header_app_param(buf, ARRAY_SIZE(appl_params), appl_params);
continue_req:
/* Add as much body as fits; function places Body or End-Body header */
bt_obex_add_header_body_or_end_body(
buf, inst->mopl,
strlen(MSG_BODY) - g_tx_cnt,
MSG_BODY + g_tx_cnt,
&len);
/* final=true when End-Body header was placed */
final = bt_obex_has_header(buf, BT_OBEX_HEADER_ID_END_BODY);
if (bt_map_mce_mas_push_msg(mce_mas, final, buf) == 0) {
if (!final) {
g_tx_cnt += len;
} else {
g_tx_cnt = 0; /* reset for next push */
}
}
/* Response in mce_mas_cb.push_msg(mce_mas, rsp_code, buf) */
}
11.9 MCE MAS — UpdateInbox#
Single-packet PUT with Type header and filler body.
static void do_update_inbox(struct bt_map_mce_mas *mce_mas)
{
struct mce_mas_instance *inst =
CONTAINER_OF(mce_mas, struct mce_mas_instance, mce_mas);
struct net_buf *buf = bt_map_mce_mas_create_pdu(mce_mas, &mas_tx_pool);
uint16_t len = 0;
bt_obex_add_header_conn_id(buf, inst->conn_id);
bt_obex_add_header_type(buf, sizeof(BT_MAP_HDR_TYPE_UPDATE_INBOX),
BT_MAP_HDR_TYPE_UPDATE_INBOX);
/* Filler body */
bt_obex_add_header_body_or_end_body(buf, inst->mopl, 1, BT_MAP_FILLER_BYTE, &len);
bt_map_mce_mas_update_inbox(mce_mas, true /* final */, buf);
/* Response in mce_mas_cb.update_inbox(mce_mas, rsp_code, buf) */
}
11.10 MCE MNS — Server Registration & Responding to SendEvent#
MCE registers a typed server struct with an accept callback. In accept, the app allocates the instance and registers per-instance callbacks. In the send_event callback, MCE responds with success or continue.
static struct bt_map_mce_mns_l2cap_server mce_l2cap_server;
static struct mce_mns_instance g_mns_inst;
/* accept callback: allocate instance and register per-instance callbacks */
static int mce_mns_l2cap_accept(struct bt_conn *conn,
struct bt_map_mce_mns_l2cap_server *server,
struct bt_map_mce_mns **mce_mns)
{
g_mns_inst.conn = bt_conn_ref(conn);
bt_map_mce_mns_cb_register(&g_mns_inst.mce_mns, &mce_mns_cb);
*mce_mns = &g_mns_inst.mce_mns;
return 0;
}
/* Register L2CAP server (call once at startup) */
static void register_mce_mns(void)
{
mce_l2cap_server.accept = mce_mns_l2cap_accept;
bt_map_mce_mns_l2cap_register(&mce_l2cap_server);
bt_sdp_register_service(&mce_mns_sdp_rec);
}
/* OBEX CONNECT request arrived — respond with SUCCESS */
static void mce_mns_connect(struct bt_map_mce_mns *mce_mns,
uint8_t version, uint16_t mopl, struct net_buf *buf)
{
bt_map_mce_mns_connect(mce_mns, BT_OBEX_RSP_CODE_SUCCESS, NULL);
}
/* OBEX DISCONNECT request arrived — respond and clean up */
static void mce_mns_disconnect(struct bt_map_mce_mns *mce_mns, struct net_buf *buf)
{
bt_map_mce_mns_disconnect(mce_mns, BT_OBEX_RSP_CODE_SUCCESS, NULL);
}
/* MSE sent an event — respond with SUCCESS (or CONTINUE for multi-packet) */
static void mce_mns_send_event(struct bt_map_mce_mns *mce_mns,
bool final, struct net_buf *buf)
{
struct mce_mns_instance *inst =
CONTAINER_OF(mce_mns, struct mce_mns_instance, mce_mns);
/* Parse event-report XML body from buf here */
uint8_t rsp_code = final ? BT_OBEX_RSP_CODE_SUCCESS
: BT_OBEX_RSP_CODE_CONTINUE;
struct net_buf *rsp_buf = bt_map_mce_mns_create_pdu(mce_mns, &mns_tx_pool);
/* Add SRM header in response if remote requested it */
if (is_remote_srm_enabled(inst->srm) && !is_srm_enabled(inst->srm)) {
bt_obex_add_header_srm(rsp_buf, BT_OBEX_SRM_ENABLE);
inst->srm |= LOCAL_SRM_ENABLED;
}
bt_map_mce_mns_send_event(mce_mns, rsp_code, rsp_buf);
}
11.11 MSE MAS — Server Registration & Responding to Requests#
MSE registers typed server structs. In the connect callback, MSE responds to OBEX CONNECT. For each MAP operation callback, MSE builds a response buf and calls the corresponding response function.
static struct bt_map_mse_mas_rfcomm_server mse_rfcomm_server;
static struct bt_map_mse_mas_l2cap_server mse_l2cap_server;
static struct mse_mas_instance g_mse_inst;
/* accept callback for RFCOMM */
static int mse_mas_rfcomm_accept(struct bt_conn *conn,
struct bt_map_mse_mas_rfcomm_server *server,
struct bt_map_mse_mas **mse_mas)
{
g_mse_inst.conn = bt_conn_ref(conn);
bt_map_mse_mas_cb_register(&g_mse_inst.mse_mas, &mse_mas_cb);
*mse_mas = &g_mse_inst.mse_mas;
return 0;
}
/* Register servers at startup */
static void register_mse_mas(void)
{
mse_rfcomm_server.accept = mse_mas_rfcomm_accept;
mse_l2cap_server.accept = mse_mas_l2cap_accept;
bt_map_mse_mas_rfcomm_register(&mse_rfcomm_server);
bt_map_mse_mas_l2cap_register(&mse_l2cap_server);
bt_sdp_register_service(&mse_mas_sdp_rec);
}
/* Respond to OBEX CONNECT */
static void mse_mas_connect(struct bt_map_mse_mas *mse_mas,
uint8_t version, uint16_t mopl, struct net_buf *buf)
{
struct mse_mas_instance *inst =
CONTAINER_OF(mse_mas, struct mse_mas_instance, mse_mas);
inst->mopl = mopl;
bt_map_mse_mas_connect(mse_mas, BT_OBEX_RSP_CODE_SUCCESS, NULL);
}
/* Respond to GetFolderListing — send folder XML */
static void mse_mas_get_folder_listing(struct bt_map_mse_mas *mse_mas,
bool final, struct net_buf *buf)
{
struct mse_mas_instance *inst =
CONTAINER_OF(mse_mas, struct mse_mas_instance, mse_mas);
struct net_buf *rsp_buf = bt_map_mse_mas_create_pdu(mse_mas, &mas_tx_pool);
/* Optionally accept SRM from client request */
parse_header_srm_req(buf, &inst->srm);
if (is_remote_srm_enabled(inst->srm) && !is_srm_enabled(inst->srm)) {
bt_obex_add_header_srm(rsp_buf, BT_OBEX_SRM_ENABLE);
inst->srm |= LOCAL_SRM_ENABLED;
}
/* App params: FolderListingSize */
uint16_t listing_size = sys_cpu_to_be16(5);
struct bt_obex_tlv appl_params[] = {
{ BT_MAP_APPL_PARAM_TAG_ID_FOLDER_LISTING_SIZE, sizeof(listing_size),
(const uint8_t *)&listing_size },
};
bt_obex_add_header_app_param(rsp_buf, ARRAY_SIZE(appl_params), appl_params);
/* Add folder-listing XML as body */
const char *xml = "<folder-listing version=\"1.0\"></folder-listing>";
uint16_t len = 0;
bt_obex_add_header_body_or_end_body(rsp_buf, inst->mopl, strlen(xml), xml, &len);
bt_map_mse_mas_get_folder_listing(mse_mas, BT_OBEX_RSP_CODE_SUCCESS, rsp_buf);
}
/* Respond to SetNotificationRegistration */
static void mse_mas_set_ntf_reg(struct bt_map_mse_mas *mse_mas,
bool final, struct net_buf *buf)
{
/* Parse NtfStatus TLV from application parameters */
bt_obex_tlv_parse(/* len */, /* data */, parse_ntf_status_cb, NULL);
/* Respond SUCCESS — if ntf_status == 1, initiate MNS connection */
bt_map_mse_mas_set_ntf_reg(mse_mas, BT_OBEX_RSP_CODE_SUCCESS, NULL);
}
11.12 MSE MNS — Connecting to MCE and Sending Events#
After receiving SetNotificationRegistration ON, MSE initiates MNS connection to MCE. Once OBEX is established, MSE sends event-report XML via bt_map_mse_mns_send_event.
static struct mse_mns_instance g_mse_mns_inst;
/* Initiate MNS connection to MCE after SetNotificationRegistration ON */
static void initiate_mns_connection(struct bt_conn *conn,
uint16_t psm_from_sdp)
{
bt_map_mse_mns_cb_register(&g_mse_mns_inst.mse_mns, &mse_mns_cb);
/* Step 1: L2CAP transport connect */
bt_map_mse_mns_l2cap_connect(conn, &g_mse_mns_inst.mse_mns, psm_from_sdp);
}
/* Step 2: in l2cap_connected callback — send OBEX CONNECT */
static void mse_mns_l2cap_connected(struct bt_conn *conn,
struct bt_map_mse_mns *mse_mns)
{
struct net_buf *buf = bt_map_mse_mns_create_pdu(mse_mns, &mns_tx_pool);
/* Target: MAP MNS UUID */
const struct bt_uuid_128 *uuid = BT_MAP_UUID_MNS;
uint8_t val[BT_UUID_SIZE_128];
sys_memcpy_swap(val, uuid->val, sizeof(val));
bt_obex_add_header_target(buf, sizeof(val), val);
bt_map_mse_mns_connect(mse_mns, buf);
}
/* Step 3: in connect callback — store mopl, start sending events */
static void mse_mns_connect(struct bt_map_mse_mns *mse_mns, uint8_t rsp_code,
uint8_t version, uint16_t mopl, struct net_buf *buf)
{
struct mse_mns_instance *inst =
CONTAINER_OF(mse_mns, struct mse_mns_instance, mse_mns);
if (rsp_code == BT_OBEX_RSP_CODE_SUCCESS) {
inst->mopl = mopl;
/* Now ready to send events */
}
}
/* Send a new-message event notification */
static void send_new_message_event(struct bt_map_mse_mns *mse_mns)
{
struct mse_mns_instance *inst =
CONTAINER_OF(mse_mns, struct mse_mns_instance, mse_mns);
struct net_buf *buf = bt_map_mse_mns_create_pdu(mse_mns, &mns_tx_pool);
bt_obex_add_header_conn_id(buf, inst->conn_id);
/* Type header */
bt_obex_add_header_type(buf, sizeof(BT_MAP_HDR_TYPE_SEND_EVENT),
BT_MAP_HDR_TYPE_SEND_EVENT);
/* App params: MasInstanceId */
uint8_t mas_id = 0;
struct bt_obex_tlv appl_params[] = {
{ BT_MAP_APPL_PARAM_TAG_ID_MAS_INST_ID, sizeof(mas_id),
(const uint8_t *)&mas_id },
};
bt_obex_add_header_app_param(buf, ARRAY_SIZE(appl_params), appl_params);
/* Event-report XML as body */
const char *event_xml =
"<MAP-event-report version=\"1.0\">"
"<event type=\"NewMessage\" handle=\"0001\" folder=\"INBOX\""
" msg_type=\"SMS_GSM\"/>"
"</MAP-event-report>";
uint16_t len = 0;
bt_obex_add_header_body_or_end_body(buf, inst->mopl,
strlen(event_xml), event_xml, &len);
bt_map_mse_mns_send_event(mse_mns, true /* final */, buf);
/* Response in mse_mns_cb.send_event(mse_mns, rsp_code, buf) */
}
12. MAP Kconfig Configuration Comparison #
⚠️ Source files: edgefast_bluetooth —
middleware/edgefast_bluetooth/include/Kconfig| edgefast_open —middleware/edgefast_open/source/bluetooth/host/classic/Kconfig
ℹ️ Key differences: edgefast_bluetooth provides fine-grained instance/MTU/supported-features tunables per role. edgefast_open has minimal Kconfig symbols — instance limits are controlled by application-level array sizes, and MTU is governed by the shared
BT_GOEP_RFCOMM_MTU/BT_GOEP_L2CAP_MTUsymbols.
12.1 Core Protocol Enablement#
Symbol |
edgefast_bluetooth |
edgefast_open |
Notes |
|---|---|---|---|
|
— (implicit) |
bool, no default |
edgefast_open exposes GOEP as a separate Kconfig knob; edgefast_bluetooth enables it implicitly |
|
— (hard-coded per role) |
int, default 255 |
edgefast_open shared RFCOMM MTU for all GOEP profiles; replaces per-role |
|
— (hard-coded per role) |
int, default 255 |
edgefast_open shared L2CAP MTU for all GOEP profiles |
|
bool, default 0 |
bool (no default; select |
Master MAP enable. Both stacks gate all MAP sub-features on this symbol |
|
bool, default 0 |
bool (no default; select |
Enables MCE (client) role |
|
bool, default 0 |
bool (no default; select |
Enables MSE (server) role |
12.2 Instance and MTU Tunables#
edgefast_bluetooth symbol |
edgefast_open equivalent |
Type |
Notes |
|---|---|---|---|
|
— |
int, default 2 |
edgefast_bluetooth limits the number of concurrent MCE MAS connections. edgefast_open manages this in app-level |
|
— |
int, default 1 |
edgefast_bluetooth MCE MNS instance limit. edgefast_open manages this in app-level |
|
|
int, default 512 (EB) / 255 (EO) |
edgefast_bluetooth per-connection MTU for MCE MAS. edgefast_open uses shared GOEP MTU |
|
|
int, default 1790 (EB) / 255 (EO) |
edgefast_bluetooth per-connection MTU for MCE MNS. edgefast_open uses shared GOEP MTU |
|
— |
int, default 2 |
edgefast_bluetooth MSE MAS instance limit. edgefast_open manages this in app-level |
|
— |
int, default 1 |
edgefast_bluetooth MSE MNS instance limit. edgefast_open manages this in app-level |
|
|
int, default 1790 (EB) / 255 (EO) |
edgefast_bluetooth per-connection MTU for MSE MAS. edgefast_open uses shared GOEP MTU |
|
|
int, default 512 (EB) / 255 (EO) |
edgefast_bluetooth per-connection MTU for MSE MNS. edgefast_open uses shared GOEP MTU |
12.3 Supported Features Defaults#
edgefast_bluetooth symbol |
edgefast_open equivalent |
Type |
Notes |
|---|---|---|---|
|
— |
hex, default |
edgefast_bluetooth bakes default supported features into Kconfig. edgefast_open defines this in app-level |
|
— |
hex, default |
Same pattern for MSE role |
12.4 Side-by-Side Symbol Summary#
Symbol |
edgefast_bluetooth |
edgefast_open |
|---|---|---|
|
— (implicit) |
bool |
|
— |
int, default 255 |
|
— |
int, default 255 |
|
bool, default 0 |
bool |
|
bool, default 0 |
bool |
|
bool, default 0 |
bool |
|
int, default 2 |
— |
|
int, default 1 |
— |
|
int, default 512 |
→ |
|
int, default 1790 |
→ |
|
hex, default |
defined in app-level |
|
int, default 2 |
— |
|
int, default 1 |
— |
|
int, default 1790 |
→ |
|
int, default 512 |
→ |
|
hex, default |
defined in app-level |
PBAP#
PBAP Comparison#
The following compares the PBAP differences between EdgeFast Open Bluetooth Host stack and EdgeFast Bluetooth PAL.
1. Architectural Differences (Core Changes)#
Dimension |
EdgeFast Open |
EdgeFast Bluetooth PAL |
Migration impact |
|---|---|---|---|
API abstraction |
PDU-/protocol-driven: most APIs take only |
Parameter-driven: function parameters directly carry |
Old: “pass parameters”; New: “build PDUs + add headers + parse buffers”. |
Header construction |
Application builds 100% of headers (Name/Type/AppParams/SRMP/Body/EndBody/auth, etc.) |
OBEX/PBAP headers are built internally based on API parameters; application mainly reserves headroom |
Main migration task: map old API parameters into a sequence of |
Connection responsibility |
Clearly split: transport bearer (RFCOMM/L2CAP) + OBEX CONNECT/DISCONNECT/ABORT PDU handling |
Connect APIs often bundle object creation, authentication, feature info, and transport setup |
Connection procedure becomes longer (one or two extra steps). |
Segmentation/chunking |
Final-bit / End-of-Body and segmentation are decided by the application’s PDU construction; PBAP APIs only transmit |
Driven by |
Requires redesign of “first packet / subsequent packet / last packet” strategy. |
SRMP (“wait”) |
Not a parameter anymore; application adds SRMP header |
|
|
Name/path |
Not a function parameter; carried in the OBEX Name header inside |
|
|
Authentication |
New provides nonce/digest/verify helpers; auth headers are added by the application |
Old callback includes |
Auth shifts from “configuration/struct callback” to “parse challenge + compute + add headers”. |
2. PCE (Client) API Alignment Differences (Function Level)#
Function |
EdgeFast Open API ( |
EdgeFast Bluetooth PAL API ( |
Key differences (incl. migration notes) |
|---|---|---|---|
Callback registration / init |
(No equivalent global |
|
Old: global callback registration; New: more instance-oriented, |
RFCOMM connect (SCN/channel) |
|
|
Old creates/returns the PCE object and takes |
L2CAP connect (PSM) |
|
|
Same pattern as RFCOMM connect. |
Disconnect (high-level) |
|
|
New requires application-provided |
Disconnect (transport bearer) |
|
(No dedicated API) |
New separates bearer teardown from OBEX DISCONNECT PDU. |
OBEX CONNECT (PBAP session) |
|
(Typically implicit in old connect flow) |
Application must construct the OBEX CONNECT PDU and headers via |
ABORT |
|
|
Application constructs ABORT PDU headers. |
Pull Phonebook |
|
|
|
SetPath |
|
|
Old passes |
Pull vCard Listing |
|
|
Same as Pull Phonebook: parameters → headers. |
Pull vCard Entry |
|
|
Same as above. |
Get max packet length |
(No same-name API found) |
|
Old provides direct query; New may obtain it via OBEX CONNECT negotiation (e.g., MOPl) or OBEX layer APIs. |
Helper: parse App Params |
(No same-name macro in |
|
New encourages direct OBEX/AppParams header manipulation/parsing by the application. |
Helper: get Body |
(No same-name macro in |
|
New callbacks deliver |
3. PSE (Server) API Alignment Differences (Function Level)#
Function |
EdgeFast Open API ( |
EdgeFast Bluetooth PAL API ( |
Key differences (incl. migration notes) |
|---|---|---|---|
Callback registration / init |
|
|
New requires a PSE instance, i.e., a more instance-based server model. |
Server bearer registration |
|
(Not provided in old header) |
New adds explicit RFCOMM/L2CAP server registration and accept model. |
Disconnect |
|
|
New is response/PDU oriented; application builds the response PDU and headers. |
CONNECT/ABORT response |
|
(More abstracted in old version) |
New requires explicit response PDU construction and transmission. |
Pull phonebook response |
|
|
|
SetPath response |
|
|
New requires a response |
Pull vCard listing response |
|
|
|
Pull vCard entry response |
|
|
Same as above. |
Get max packet length |
(No same-name API found) |
|
New may rely on OBEX/GOEP layer APIs. |
Get peer supported features |
(No same-name API found) |
|
New may expose this via negotiation/callback/buffer parsing or internal state. |
5. Callback Model Differences: From “High-level Events” to “Protocol Events + Buffer-driven”#
5.1 PCE callbacks#
Aspect |
EdgeFast Open |
EdgeFast Bluetooth PAL |
Migration impact |
|---|---|---|---|
Bearer connected |
|
|
New distinguishes bearer type and provides |
Bearer disconnected |
|
|
The disconnect reason/result is more reflected in protocol |
OBEX CONNECT result |
|
(Not typically exposed explicitly) |
New exposes negotiated parameters and delivers the raw buffer. |
pull/set/abort callbacks |
uniformly |
result + buf (some callbacks without buf) |
Application must parse OBEX headers/body from |
Auth info retrieval |
(Not present) |
|
New expects application-driven OBEX auth header handling (parse challenge, compute, add response). |
5.2 PSE callbacks#
Aspect |
EdgeFast Open |
EdgeFast Bluetooth PAL |
Migration impact |
|---|---|---|---|
Pull request callback params |
|
|
New requires parsing Name/Type/AppParams/SRMP/segmentation from |
SetPath request |
|
|
Flags are standardized; folder name is parsed from Name header in |
connect/disconnect/abort |
New provides buffer-level callbacks and explicit response APIs |
More abstracted |
New behaves like an OBEX server role: app participates in handshake and PDU construction. |
6. Migration Mapping: “Old parameters” → “New headers (obex_add_header_xxx)”#
Old parameter/concept |
EdgeFast Open |
EdgeFast Bluetooth PAL |
Application action (conceptual) |
|---|---|---|---|
|
Not a function parameter anymore |
API parameter |
Add/parse OBEX Name header in request/response PDUs. |
|
|
Often internal in old stack |
Add OBEX Type header ( |
App Parameters (filter/format/order/search, etc.) |
enums in |
via |
Encode/decode PBAP AppParams TLVs inside the OBEX App Parameters header. |
|
Not present as parameter |
|
Add/parse SRMP header to control Server Response Mode Parameter. |
|
Not present as parameter |
|
Express segmentation via PDU construction (Final-bit, Body vs End-of-Body, multi-PDU flow). |
|
unified |
|
Choose OBEX response code based on whether more PDUs follow; build Body/End-of-Body accordingly. |
|
nonce/digest/verify helpers |
connect parameter or |
Build OBEX auth headers in PDUs; compute/verify using provided helpers. |
|
not in prototypes |
connect parameter or explicit getter |
Likely obtained via negotiation/SDP/buffer parsing/internal state; avoid injecting via connect signature. |
7. Newly Added / Enhanced APIs & Capabilities in EdgeFast Open#
Item |
EdgeFast Open API/structure |
Value |
|---|---|---|
PDU allocation helper |
|
Provides a PDU container to be populated by the application via |
PSE bearer server registration |
|
More complete server integration model (multi-connection / custom accept). |
OBEX-level response APIs (PSE) |
|
Application can explicitly control OBEX response codes and attached headers. |
Authentication utilities |
|
Facilitates application-implemented OBEX/PBAP authentication headers and validation. |
8. Migration Recommendations (High-level)#
Refactor connection sequencing (PCE):
Establish bearer first:
bt_pbap_pce_rfcomm_connectorbt_pbap_pce_l2cap_connectThen build the OBEX CONNECT PDU (application uses
obex_add_header_xxx()) and callbt_pbap_pce_connect
Change request transmission to “build PDU first, then call PBAP API”:
bt_pbap_pce_create_pdu()→obex_add_header_xxx()(Name/Type/AppParams/SRMP/Body…) →bt_pbap_pce_pull_*()
Change response sending (PSE) to “application fully owns headers/body/end-of-body”:
Request callbacks deliver only
buf; parse Name/Type/AppParamsBuild response
buf: add Body/End-of-Body and required headers viaobex_add_header_xxx()→ callbt_pbap_pse_*_rsp()
Segmentation/CONTINUE strategy migration:
Old:
flag + wait + resultNew: application decides whether to include End-of-Body, whether more PDUs follow, and selects
rsp_code(CONTINUE/SUCCESS)
Authentication migration:
Old:
get_auth_info+struct bt_pbap_authNew: application parses OBEX auth challenge headers, computes digests via
bt_pbap_calculate_*, and adds auth response/challenge headers viaobex_add_header_xxx()
Parent topic:Compare with EdgeFast Bluetooth PAL
Parent topic:Overview
Features#
This section provides an overview of Bluetooth features, toolchain support, and RTOS support.
Bluetooth features#
Bluetooth 5.3 compliant
Protocol support
L2CAP, GAP, GATT, RFCOMM, SDP, SM, and SPP
Classic profile
A2DP, HFP, AVRCP, AVRCP Cover Art, GOEP, BIP, MAP, PBAP
LE profile
HTP, PXP, IPSP, HPS
LE audio
Digital Audio Interface including PCM interface for HFP
Parent topic:Features
Toolchain support#
IAR Embedded Workbench for ARM®
MCUXpresso IDE
Keil® MDK/μVision
Makefiles support with GCC from Arm Embedded
Note: For details on IDE Development tools version details, see Section 3, Development tools in MCUXpresso SDK Release Notes (document MCUXSDKMIMXRT117XRN). The Release Notes document is available at root/docs/ MCUXpresso SDK Release Notes for EVK-MIMXRT1170.pdf.
Parent topic:Features
RTOS support#
FreeRTOSTMOS
Note: The FreeRTOS static allocation feature is required by Edgefast Open. The macro configSUPPORT_STATIC_ALLOCATION needs to be set to enable this feature.
Parent topic:Features
Parent topic:Overview
Examples list#
The following examples are provided. Not all the examples are implemented on all the boards. See the board package for a list of the implemented examples.
central_hpc (central http proxy service client): Demonstrates a basic Bluetooth Low Energy Central role functionality. The application scans for other Bluetooth Low Energy devices and establishes a connection to the peripheral with the strongest signal. The application specifically looks for HPS Server and programs a set of characteristics that configures a Hyper Text Transfer Protocol (HTTP) request, initiates request, and reads the response once connected.
central_ht (central health thermometer): Demonstrates a basic Bluetooth Low Energy Central role functionality. The application scans for other Bluetooth Low Energy devices and establishes a connection to the peripheral with the strongest signal. The application specifically looks for health thermometer sensor and reports the die temperature readings once connected.
central_ipsp (central Internet protocol support profile): Demonstrates a basic Bluetooth Low Energy Central role functionality. The application scans for other Bluetooth Low Energy devices and establishes connection to the peripheral with the strongest signal. The application specifically looks for IPSP Service and communicates between the devices that support IPSP. Once connected, the communication is done using IPv6 packets over the Bluetooth Low Energy transport.
central_pxm (central proximity monitor): Demonstrates a basic Bluetooth Low Energy Central role functionality. The application scans for other Bluetooth Low Energy devices and establishes a connection to the peripheral with the strongest signal. The application specifically looks for Proximity Reporter.
peripheral beacon: Demonstrates the Bluetooth Low Energy Peripheral role, This application implements types of beacon applications.
beacon: Demonstrates the Bluetooth Low Energy Broadcaster role functionality by advertising Company Identifier, Beacon Identifier, UUID, A, B, C, RSSI.
Eddystone: The Eddystone Configuration Service runs as a GATT service on the beacon while it is connectable and allows configuration of the advertised data, the broadcast power levels, and the advertising intervals.
iBeacon: Demonstrates the Bluetooth Low Energy Broadcaster role functionality by advertising an Apple iBeacon.
peripheral_hps (peripheral http proxy service): Demonstrates the Bluetooth Low Energy Peripheral role. The application specifically exposes the HTTP Proxy GATT Service.
peripheral_ht (peripheral health thermometer): Demonstrates the Bluetooth Low Energy Peripheral role. The application specifically exposes the HT (Health Thermometer) GATT Service. Once a device connects, it generates dummy temperature values.
peripheral_ipsp (peripheral Internet protocol support profile): Demonstrates the Bluetooth Low Energy Peripheral role. The application specifically exposes the Internet Protocol Support GATT Service.
peripheral_pxr (peripheral proximity reporter): Demonstrates the Bluetooth Low Energy Peripheral role. The application specifically exposes the Proximity Reporter (including LLS, IAS, and TPS) GATT Service.
wireless uart: The application automatically starts advertising the wireless uart service and connects to the wireless uart service after the role switch. The wireless UART service is a custom service that implements a custom writable ASCII Char characteristic (UUID: 01ff0101-ba5e-f4ee-5ca1-eb1e5e4b1ce0) that holds the character written by the peer device.
spp (serial prot profile): Application demonstrates the use of the SPP feature.
handsfree: Application demonstrating usage of the Hands-free Profile (HFP) feature.
handsfree_ag: Application demonstrating usage of the Hands-free Profile Audio Gateway (HFP-AG) feature.
a2dp_sink: Application demonstrating how to use the a2dp sink feature.
a2dp_source: Application demonstrating how to use the a2dp source feature.
shell: Shell application demonstrating the shell mode of the simplified Adapter APIs.
Parent topic:Overview