MCUXpresso SDK Documentation

Compare with EdgeFast Bluetooth PAL

Contents

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.h vs middleware/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_endpoint bundles 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_ep describes codec capability only while struct bt_a2dp_stream carries 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_EXTERNAL and BT_A2DP_CODEC_CONTROL); the app can feed raw PCM via bt_a2dp_src_media_write. edgefast_open provides no built-in codec; the app is always responsible for encoding/decoding and uses bt_a2dp_stream_send with a pre-built net_buf.

Aspect

edgefast_bluetooth

edgefast_open

Primary endpoint object

struct bt_a2dp_endpoint (codec + config + buffers + cbs in one)

struct bt_a2dp_ep (codec capability only)

Per-connection stream state

Embedded inside struct bt_a2dp_endpoint

Separate struct bt_a2dp_stream linked to an ep at configuration time

AVDTP signal exposure

Hidden; app calls bt_a2dp_configure / bt_a2dp_start / bt_a2dp_stop / bt_a2dp_deconfigure

Explicit per-signal: bt_a2dp_stream_config, bt_a2dp_stream_establish, bt_a2dp_stream_start, bt_a2dp_stream_suspend, bt_a2dp_stream_release, bt_a2dp_stream_abort

Callback registration

Per-endpoint struct fields (control_cbs.configured, control_cbs.start_play, etc.)

Global bt_a2dp_stream_ops registered per-stream via bt_a2dp_stream_cb_register

Media TX

bt_a2dp_src_media_write(endpoint, data, len) - raw byte buffer; optional internal SBC encoder

bt_a2dp_stream_send(stream, net_buf, seq_num, ts) - caller provides fully-formed RTP payload

Media RX

sink_streamer_data callback field in endpoint struct

recv(stream, net_buf, seq_num, ts) callback in bt_a2dp_stream_ops

PDU buffer allocation

Not exposed; internal to stack

bt_a2dp_stream_create_pdu(pool, timeout) - allocates net_buf with correct headroom

MTU query

Not exposed

bt_a2dp_get_mtu(stream)

Automatic endpoint selection

bt_a2dp_configure picks best local EP by priority

App explicitly selects both local and remote EP in bt_a2dp_stream_config

Peer endpoint discovery

bt_a2dp_discover_peer_endpoints(a2dp, cb) with continue/stop return from callback

bt_a2dp_discover(a2dp, cb) - cb delivers each remote EP

Codec buffers

App allocates and provides codec_buffer + codec_buffer_nocached in endpoint struct

Not needed; codec is external

SBC channel mode spelling

A2DP_SBC_CH_MODE_STREO (typo in macro name)

A2DP_SBC_CH_MODE_STEREO (corrected)

Error codes

Not defined in a2dp.h

enum bt_a2dp_err_code with ~30 named AVDTP/A2DP error values

2. Header File Layout & Constants#

Item

edgefast_bluetooth

edgefast_open

A2DP main header

include/bluetooth/a2dp.h

include/zephyr/bluetooth/classic/a2dp.h

A2DP SBC codec header

include/bluetooth/a2dp_codec_sbc.h

include/zephyr/bluetooth/classic/a2dp_codec_sbc.h

SBC IE length

#define BT_A2DP_SBC_IE_LENGTH (4u)

#define BT_A2DP_SBC_IE_LENGTH (4U) (identical value)

MPEG-1,2 IE length

#define BT_A2DP_MPEG_1_2_IE_LENGTH (4u)

#define BT_A2DP_MPEG_1_2_IE_LENGTH (4U)

MPEG-2,4 IE length

#define BT_A2DP_MPEG_2_4_IE_LENGTH (6u)

#define BT_A2DP_MPEG_2_4_IE_LENGTH (6U)

Max IE length

- not present -

#define BT_A2DP_MAX_IE_LENGTH (8U)

Codec ID enum

enum bt_a2dp_codec_id { BT_A2DP_SBC=0x00, BT_A2DP_MPEG1=0x01, BT_A2DP_MPEG2=0x02, BT_A2DP_ATRAC=0x04, BT_A2DP_VENDOR=0xff }

enum bt_a2dp_codec_id { BT_A2DP_SBC=0x00, BT_A2DP_MPEG1=0x01, BT_A2DP_MPEG2=0x02, BT_A2DP_ATRAC=0x04, BT_A2DP_VENDOR=0xff } (identical)

Media type enum

enum MEDIA_TYPE { BT_A2DP_AUDIO=0x00, BT_A2DP_VIDEO=0x01, BT_A2DP_MULTIMEDIA=0x02 }

Uses BT_AVDTP_AUDIO etc. from classic/avdtp.h; no separate MEDIA_TYPE enum in a2dp.h

Role enum

enum ROLE_TYPE { BT_A2DP_SOURCE=0, BT_A2DP_SINK=1 }

Uses BT_AVDTP_SOURCE / BT_AVDTP_SINK from classic/avdtp.h

Error codes

- not present -

enum bt_a2dp_err_code with ~30 entries (BT_A2DP_INVALID_CODEC_TYPE, BT_A2DP_NOT_SUPPORTED_CODEC_TYPE, etc.)

SBC channel mode typo

A2DP_SBC_CH_MODE_STREO

A2DP_SBC_CH_MODE_STEREO (fixed)

SBC bitpool min/max

- not present in header -

BT_A2DP_SBC_MIN_BITPOOL_VALUE 2, BT_A2DP_SBC_MAX_BITPOOL_VALUE 250

SBC media packet header struct

struct bt_a2dp_codec_sbc_media_packet_hdr (bit-field struct)

- not present - (macros only)

SBC config decode macros

Parameterised as preset (BT_A2DP_SBC_SAMP_FREQ(preset))

Parameterised as cap (BT_A2DP_SBC_SAMP_FREQ(cap))

SBC helper functions return types

uint8_t bt_a2dp_sbc_get_allocation_method(...) returns uint8_t

enum sbc_alloc_mthd bt_a2dp_sbc_get_allocation_method(...) returns typed enum; enum sbc_ch_mode bt_a2dp_sbc_get_channel_mode(...) added

Codec buffer size constants

BT_A2DP_SOURCE_SBC_CODEC_BUFFER_SIZE, BT_A2DP_SINK_SBC_CODEC_BUFFER_SIZE, etc. (used in endpoint init macros)

- 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 same bt_a2dp_ep can be reused across connections (a new stream object is passed each time), whereas in edgefast_bluetooth the bt_a2dp_endpoint is 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 a struct 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_connect and bt_a2dp_disconnect signatures are identical in both stacks. The callback registration function is renamed (bt_a2dp_register_connect_callbackbt_a2dp_register_cb) and the callback struct type changes (struct bt_a2dp_connect_cbstruct bt_a2dp_cb).

Callback struct field

edgefast_bluetooth bt_a2dp_connect_cb

edgefast_open bt_a2dp_cb

Connection established

connected(struct bt_a2dp *a2dp, int err)

connected(struct bt_a2dp *a2dp, int err) (identical)

Connection released

disconnected(struct bt_a2dp *a2dp)

disconnected(struct bt_a2dp *a2dp) (identical)

Remote endpoint discovered

- (separate discovery callback type)

discovery_result(struct bt_a2dp *a2dp, struct bt_a2dp_ep *ep, uint8_t err)

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_type and role parameters because the endpoint macro may embed them but the registration function re-declares them. The endpoint registered first has highest priority in bt_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 (roletsep). No priority concept; app always explicitly selects the EP in bt_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_STOP or BT_A2DP_DISCOVER_ENDPOINT_CONTINUE to 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_cb struct rather than a dedicated function pointer. Only the remote ep is 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_config with 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 bt_a2dp_configure / bt_a2dp_configure_endpoint

bt_a2dp_stream_config(a2dp, stream, local_ep, remote_ep, config)

GET_CONFIGURATION

- not exposed -

bt_a2dp_stream_get_config(stream) 🔴

OPEN (L2CAP media channel)

Part of bt_a2dp_configure flow (automatic)

bt_a2dp_stream_establish(stream) 🔴

START

bt_a2dp_start(endpoint)

bt_a2dp_stream_start(stream)

SUSPEND

bt_a2dp_stop(endpoint)

bt_a2dp_stream_suspend(stream)

CLOSE (release)

bt_a2dp_deconfigure(endpoint)

bt_a2dp_stream_release(stream)

RECONFIGURE

bt_a2dp_reconfigure(endpoint, config)

bt_a2dp_stream_reconfig(stream, config)

ABORT

- not exposed -

bt_a2dp_stream_abort(stream) 🔴

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) from config (AVDTP SET_CONFIGURATION), matching the AVDTP state machine precisely. edgefast_bluetooth merges both into the bt_a2dp_configure / bt_a2dp_configure_endpoint path. bt_a2dp_stream_abort and bt_a2dp_stream_get_config have 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_sync call after processing each received buffer. edgefast_open has no such acknowledgement - the net_buf reference 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_setup_encoder() and sbc_encode() directly

SBC decoder location

Internal to stack; stack decodes before calling sink_streamer_data

Application - app calls sbc_setup_decoder() and sbc_decode() directly

PCM input for source

bt_a2dp_src_media_write(endpoint, pcm_data, len) when A2DP_CODEC_EXTERNAL=0

App encodes PCM → SBC frames → inserts into net_buf before calling bt_a2dp_stream_send

PCM output for sink

Stack delivers decoded PCM in sink_streamer_data callback

App decodes SBC frames from net_buf in the recv callback using sbc_decode()

Encoder bit-rate tuning

BT_A2DP_SBC_ENCODER_BIT_RATE Kconfig

App passes bit_rate in struct sbc_encoder_init_param to sbc_setup_encoder()

SBC library

Bundled and hidden

Explicit #include <zephyr/bluetooth/sbc.h>; struct sbc_encoder and struct sbc_decoder objects owned by app

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, &param);   /* 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_EXTERNAL is not set (default), the app simply calls bt_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, the sink_streamer_data callback delivers already-decoded PCM data. The app only needs to allocate codec_buffer and codec_buffer_nocached in 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 delay with unspecified units (implementation-defined). Feature is optional via BT_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_t in units of 1/10 milliseconds (per A2DP spec). Delay reporting capability is advertised per-EP via the delay_report bool field in struct bt_a2dp_ep. No separate Kconfig symbol is needed - it is always compiled in.

Aspect

edgefast_bluetooth

edgefast_open

API name

bt_a2dp_send_delay_report

bt_a2dp_stream_delay_report

Units

int16_t (unspecified)

uint16_t in 1/10 ms

Initial setup

bt_a2dp_set_initial_delay_report

Not needed; first call to bt_a2dp_stream_delay_report suffices

RX on source side

Not exposed

delay_report callback in bt_a2dp_stream_ops

Kconfig gate

BT_A2DP_DR_SERVICE

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

bt_a2dp_set_cp_header(endpoint, header, header_len)

BT_A2DP_CP_SERVICE

Internal codec enable/disable

bt_a2dp_set_ep_codec_enable(endpoint, bool enable)

BT_A2DP_CODEC_CONTROL

Multi-endpoint SBC write

bt_a2dp_src_media_write_ext(endpoints[], data, datalen)

BT_A2DP_WRITE_EXT

Recovery service (config only)

Endpoint field recovery_ie / recovery_config

BT_A2DP_RECOVERY_SERVICE

Reporting service (config only)

Endpoint field reporting_service_enable

BT_A2DP_REPORTING_SERVICE

Header compression (config only)

Endpoint field header_compression_cap / header_compression_config

BT_A2DP_HC_SERVICE

Multiplexing service (config only)

Endpoint field multiplexing_service_enable

BT_A2DP_MULTIPLEXING_SERVICE

10. Callback Structures Comparison#

Connection-level callbacks#

Event

edgefast_bluetooth bt_a2dp_connect_cb

edgefast_open bt_a2dp_cb

Connected

connected(struct bt_a2dp *a2dp, int err)

connected(struct bt_a2dp *a2dp, int err)

Disconnected

disconnected(struct bt_a2dp *a2dp)

disconnected(struct bt_a2dp *a2dp)

Discovery result

Separate callback type bt_a2dp_discover_peer_endpoint_cb_t

discovery_result(struct bt_a2dp *a2dp, struct bt_a2dp_ep *ep, uint8_t err)

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, and suspended callbacks for every AVDTP state transition. edgefast_bluetooth collapses start/stop into start_play / stop_play and has no established or released callbacks.

Callback correspondence table#

Event

edgefast_bluetooth callback

edgefast_open callback

SET_CONFIGURATION accepted

control_cbs.configured(endpoint)

bt_a2dp_stream_ops.configured(stream)

OPEN / media channel ready

- not separate -

bt_a2dp_stream_ops.established(stream) 🔴

START accepted

control_cbs.start_play(endpoint, ctx)

bt_a2dp_stream_ops.started(stream)

SUSPEND accepted

control_cbs.stop_play(endpoint)

bt_a2dp_stream_ops.suspended(stream)

CLOSE / ABORT done

- not exposed -

bt_a2dp_stream_ops.released(stream) 🔴

Sink media data received

control_cbs.sink_streamer_data(endpoint, ctx)

bt_a2dp_stream_ops.recv(stream, buf, seq, ts)

Source TX completed

- not exposed -

bt_a2dp_stream_ops.sent(stream) 🔴

Delay report received (source)

control_cbs.sink_delay_report_cb(endpoint, delay)

bt_a2dp_stream_ops.delay_report(stream, value)

11. Full Function Comparison Table#

Function

edgefast_bluetooth

edgefast_open

Notes

bt_a2dp_connect

struct bt_a2dp *bt_a2dp_connect(struct bt_conn *conn)

struct bt_a2dp *bt_a2dp_connect(struct bt_conn *conn)

🟡 Identical

bt_a2dp_disconnect

int bt_a2dp_disconnect(struct bt_a2dp *a2dp)

int bt_a2dp_disconnect(struct bt_a2dp *a2dp)

🟡 Identical

Register connect callback

bt_a2dp_register_connect_callback(struct bt_a2dp_connect_cb *cb)

bt_a2dp_register_cb(struct bt_a2dp_cb *cb)

🟡 Renamed; struct type changed

Register endpoint

bt_a2dp_register_endpoint(endpoint, media_type, role)

bt_a2dp_register_ep(ep, media_type, tsep)

🟡 Renamed; struct type changed

Discover peer endpoints

bt_a2dp_discover_peer_endpoints(a2dp, cb)

bt_a2dp_discover(a2dp, cb)

🟡 Renamed; callback delivery differs

Auto configure

bt_a2dp_configure(a2dp, result_cb)

- not present -

🟢 edgefast_bluetooth only

Configure specific EP

bt_a2dp_configure_endpoint(a2dp, ep, peer_ep, config)

bt_a2dp_stream_config(a2dp, stream, local_ep, remote_ep, config)

🟡 stream object added in edgefast_open

Get configuration

- not present -

bt_a2dp_stream_get_config(stream)

🔴 edgefast_open only

Open / establish media channel

Part of bt_a2dp_configure flow

bt_a2dp_stream_establish(stream)

🔴 edgefast_open only

Start streaming

bt_a2dp_start(endpoint)

bt_a2dp_stream_start(stream)

🟡 Renamed; argument type changed

Stop / suspend

bt_a2dp_stop(endpoint)

bt_a2dp_stream_suspend(stream)

🟡 Renamed; argument type changed

Release / close

bt_a2dp_deconfigure(endpoint)

bt_a2dp_stream_release(stream)

🟡 Renamed; argument type changed

Reconfigure

bt_a2dp_reconfigure(endpoint, config)

bt_a2dp_stream_reconfig(stream, config)

🟡 Renamed; argument type changed

Abort

- not present -

bt_a2dp_stream_abort(stream)

🔴 edgefast_open only

Register stream callbacks

Embedded in endpoint struct (control_cbs.*)

bt_a2dp_stream_cb_register(stream, ops)

🟡 Per-stream in edgefast_open

Source TX

bt_a2dp_src_media_write(endpoint, data, datalen)

bt_a2dp_stream_send(stream, buf, seq_num, ts)

🟡 net_buf + explicit RTP fields in edgefast_open

Source TX (multi-endpoint)

bt_a2dp_src_media_write_ext(endpoints[], data, datalen)

- not present -

🟢 edgefast_bluetooth only

Allocate TX PDU buffer

- not present -

bt_a2dp_stream_create_pdu(pool, timeout)

🔴 edgefast_open only

Sink RX ack

bt_a2dp_snk_media_sync(endpoint, data, datalen)

- not needed (net_buf managed by stack) -

🟢 edgefast_bluetooth only

Get MTU

- not present -

bt_a2dp_get_mtu(stream)

🔴 edgefast_open only

Send delay report

bt_a2dp_send_delay_report(endpoint, delay)

bt_a2dp_stream_delay_report(stream, delay)

🟡 Renamed; units clarified

Set initial delay report

bt_a2dp_set_initial_delay_report(endpoint, delay)

- not needed -

🟢 edgefast_bluetooth only

Content protection header

bt_a2dp_set_cp_header(endpoint, header, len)

- not present -

🟢 edgefast_bluetooth only

Internal codec control

bt_a2dp_set_ep_codec_enable(endpoint, enable)

- not present -

🟢 edgefast_bluetooth only

SBC get channel mode

bt_a2dp_sbc_get_channel_num(...) (returns count)

bt_a2dp_sbc_get_channel_mode(...) + bt_a2dp_sbc_get_channel_num(...)

🔴 get_channel_mode added in edgefast_open

SBC get allocation method

returns uint8_t

returns enum sbc_alloc_mthd

🟡 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

BT_AVDTP

bool, default 0

bool (no default)

AVDTP layer. edgefast_bluetooth is explicit default 0; edgefast_open relies on Kconfig default (disabled)

BT_A2DP

bool, default 0

bool (no default); select BT_AVDTP, imply LIBSBC

A2DP master enable. edgefast_open auto-selects AVDTP and implies LIBSBC

BT_A2DP_SOURCE

bool, default 0

bool (no default)

Source role enable. Semantically identical

BT_A2DP_SINK

bool, default 0

bool (no default)

Sink role enable. Semantically identical

12.2 AVDTP Transport Tunables#

Symbol

edgefast_bluetooth

edgefast_open

Notes

BT_AVDTP_RTP_VERSION

- not present -

int, default 2

RTP protocol version. edgefast_open exposes this; edgefast_bluetooth hard-codes it

BT_AVDTP_SIGNAL_SDU_MAX

- 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

BT_A2DP_MAX_CONN

int, default BT_MAX_CONN

- not present -

edgefast_bluetooth caps simultaneous A2DP connections; edgefast_open derives the limit from the underlying ACL pool

BT_A2DP_MAX_ENDPOINT_COUNT

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

A2DP_CODEC_EXTERNAL

bool

0

When set, disables the internal SBC encoder/decoder; app provides pre-encoded frames

BT_A2DP_CODEC_CONTROL

bool

0

Enables bt_a2dp_set_ep_codec_enable to pause/resume the internal codec

BT_A2DP_WRITE_EXT

bool

0

Enables bt_a2dp_src_media_write_ext for multi-endpoint SBC broadcast

BT_A2DP_SBC_ENCODER_PCM_BUFFER_SIZE

int

0

PCM input buffer size for internal SBC encoder (source)

BT_A2DP_SBC_ENCODER_BIT_RATE

int

328

Target SBC bit-rate for internal encoder (source)

BT_A2DP_SBC_DECODER_PCM_BUFFER_SIZE

int

0

PCM output buffer size for internal SBC decoder (sink)

BT_A2DP_SBC_DATA_IND_COUNT

int

328

Number of SBC data indications buffered (sink)

BT_A2DP_SBC_DATA_IND_SAMPLES_COUNT

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

BT_A2DP_TASK_PRIORITY

int

4

A2DP task priority (processes streamer data and retries)

BT_A2DP_TASK_STACK_SIZE

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

BT_A2DP_CP_SERVICE

bool

0

Content Protection service (SCMS-T etc.) - config only

BT_A2DP_RECOVERY_SERVICE

bool

0

Recovery service - config only (data transfer not supported)

BT_A2DP_REPORTING_SERVICE

bool

0

Reporting service - config only (data transfer not supported)

BT_A2DP_DR_SERVICE

bool

0

Delay Reporting service - enables bt_a2dp_send_delay_report

BT_A2DP_HC_SERVICE

bool

0

Header Compression service - config only (data transfer not supported)

BT_A2DP_MULTIPLEXING_SERVICE

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_report with no Kconfig gate.

12.7 Side-by-Side Symbol Summary#

Symbol

edgefast_bluetooth

edgefast_open

BT_AVDTP

bool, default 0

bool

BT_AVDTP_RTP_VERSION

-

int, default 2

BT_AVDTP_SIGNAL_SDU_MAX

-

int, default 512

BT_A2DP

bool, default 0

bool

BT_A2DP_SOURCE

bool, default 0

bool

BT_A2DP_SINK

bool, default 0

bool

BT_A2DP_MAX_CONN

int, default BT_MAX_CONN

-

BT_A2DP_MAX_ENDPOINT_COUNT

int, default 2

-

A2DP_CODEC_EXTERNAL

bool, default 0

-

BT_A2DP_CODEC_CONTROL

bool, default 0

-

BT_A2DP_WRITE_EXT

bool, default 0

-

BT_A2DP_SBC_ENCODER_PCM_BUFFER_SIZE

int, default 0

-

BT_A2DP_SBC_ENCODER_BIT_RATE

int, default 328

-

BT_A2DP_SBC_DECODER_PCM_BUFFER_SIZE

int, default 0

-

BT_A2DP_SBC_DATA_IND_COUNT

int, default 328

-

BT_A2DP_SBC_DATA_IND_SAMPLES_COUNT

int, default 328

-

BT_A2DP_TASK_PRIORITY

int, default 4

-

BT_A2DP_TASK_STACK_SIZE

int, default 2048

-

BT_A2DP_CP_SERVICE

bool, default 0

-

BT_A2DP_RECOVERY_SERVICE

bool, default 0

-

BT_A2DP_REPORTING_SERVICE

bool, default 0

-

BT_A2DP_DR_SERVICE

bool, default 0

-

BT_A2DP_HC_SERVICE

bool, default 0

-

BT_A2DP_MULTIPLEXING_SERVICE

bool, default 0

-

AVRCP#

Edgefast Bluetooth vs Edgefast Open - AVRCP API Differences#

Source: middleware/edgefast_bluetooth/include/bluetooth/avrcp.h vs middleware/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 one struct bt_avrcp_cb handles 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.h using a numeric uint8_t handle edgefast_open puts cover art in a separate avrcp_cover_art.h using typed objects that embed BIP (Basic Imaging Profile), with explicit separate L2CAP and OBEX connection steps.

Aspect

edgefast_bluetooth

edgefast_open

Connection handle

struct bt_conn *conn (generic BT conn)

struct bt_avrcp_ct *ct / struct bt_avrcp_tg *tg (AVRCP-typed role objects)

Role separation

Single unified API; send functions implicitly act as CT, responses handled in same callback

Explicit CT namespace (bt_avrcp_ct_*) and TG namespace (bt_avrcp_tg_*)

Callback registration

Single bt_avrcp_register_callback(struct bt_avrcp_cb *cb)

Two separate: bt_avrcp_ct_register_cb() and bt_avrcp_tg_register_cb()

Transaction labels

Implicit - library manages internally

Explicit uint8_t tid (0-15) on every CT send and TG response call

Command data passing

Typed structs per command (e.g. struct bt_avrcp_get_folder_items_cmd *)

Pre-serialized struct net_buf *buf for complex cmds; typed structs for simple ones

Fragmentation / continuation

App calls bt_avrcp_request_continuing_rsp() / bt_avrcp_abort_continuing_rsp() explicitly

Library reassembles internally; no continuation API exposed to application

Passthrough vendor-unique

Inline uint8_t vendor_op_id alongside op_id

Separate struct bt_avrcp_passthrough_opvu_data *opvu_data pointer (NULL for standard ops)

Cover art handle

Numeric uint8_t handle; allocated by bt_avrcp_cover_art_start_initiator()

Typed struct bt_avrcp_cover_art_ct/tg; L2CAP connect is separate step from OBEX connect

Cover art dependency

Self-contained in avrcp.h with custom OBEX structs

Depends on classic/bip.h (Basic Imaging Profile)

2. Header File Layout & Constants#

Item

edgefast_bluetooth

edgefast_open

AVRCP main header

include/bluetooth/avrcp.h (~54 KB)

include/zephyr/bluetooth/classic/avrcp.h (~2440 lines)

Cover Art header

Integrated in avrcp.h (guarded by CONFIG_BT_AVRCP_COVER_ART_INITIATOR / _RESPONDER)

Separate classic/avrcp_cover_art.h; depends on classic/bip.h

Operation IDs

#define BT_AVRCP_OP_ID_SELECT 0x00 (plain macros, prefix BT_AVRCP_OP_ID_)

typedef enum __packed { BT_AVRCP_OPID_SELECT=0x00, ... } bt_avrcp_opid_t (prefix BT_AVRCP_OPID_)

Notification events

#define BT_AVRCP_EVENT_PLAYBACK_STATUS_CHANGED 0x01 (prefix BT_AVRCP_EVENT_)

typedef enum __packed { BT_AVRCP_EVT_PLAYBACK_STATUS_CHANGED=0x01, ... } bt_avrcp_evt_t (prefix BT_AVRCP_EVT_)

AV/C response codes

#define BT_AVRCP_RESPONSE_TYPE_NOT_IMPLEMENTED 0x08

typedef enum __packed { BT_AVRCP_RSP_NOT_IMPLEMENTED=0x8, ... } bt_avrcp_rsp_t

AV/C command types

#define BT_AVRCP_COMMAND_TYPE_CONTROL 0x00

typedef enum __packed { BT_AVRCP_CTYPE_CONTROL=0x0, ... } bt_avrcp_ctype_t

Error / status codes

Two separate sets: #define BT_AVRCP_METADATA_ERROR_* and #define BT_AVRCP_BOW_ERROR_*

Single unified typedef enum __packed { ... } bt_avrcp_status_t covering both metadata and browsing errors

Button state

Raw uint8_t state_flag (0=pressed, 1=released)

typedef enum __packed { BT_AVRCP_BUTTON_PRESSED=0, BT_AVRCP_BUTTON_RELEASED=1 } bt_avrcp_button_state_t

Capability IDs

#define BT_AVRCP_CAP_ID_COMPANY_ID 0x02, #define BT_AVRCP_CAP_ID_EVENTS_SUPPORTED 0x03

typedef enum __packed { BT_AVRCP_CAP_COMPANY_ID=0x2, BT_AVRCP_CAP_EVENTS_SUPPORTED=0x3 } bt_avrcp_cap_t

Scopes

#define BT_AVRCP_SCOPE_MEDIA_PLAYER_LIST 0x00BT_AVRCP_SCOPE_NOW_PLAYING 0x03

Embedded as uint8_t scope field values in command structs; no named enum

3. Connection Management#

ℹ️ The browsing connect/disconnect functions have identical signatures in both stacks Only the control-channel connect name differs (bt_avrcp_control_connect vs bt_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 explicit struct bt_avrcp_ct *ct typed objects with an explicit uint8_t tid on every call All TG response functions are in the separate Section 5.

Both take struct bt_conn *. In edgefast_open the resulting typed struct bt_avrcp_ct * / struct bt_avrcp_tg * objects are delivered via connected callbacks. 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 typed struct bt_avrcp_ct * / struct bt_avrcp_tg * objects are delivered via connected callbacks. 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/0 for payload/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 a net_buf allocated via bt_avrcp_create_pdu(), then passes it to bt_avrcp_tg_send_passthrough_rsp. The result parameter uses bt_avrcp_rsp_t enum 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_id parameter. TG responds with pre-serialized net_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_notification takes an optional per-registration bt_avrcp_notify_changed_cb_t callback (can be NULL to use the global CT callback). TG sends notifications via bt_avrcp_tg_notification() with a typed struct bt_avrcp_event_data * (not a net_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 parameter to 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_player and bt_avrcp_set_volume from edgefast_bluetooth map to bt_avrcp_ct_set_addressed_player and bt_avrcp_ct_set_absolute_volume respectively.

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 same struct 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_dependent is 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 tid received in the request callback. Data is pre-serialized as struct net_buf *buf where 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_player has 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 new bt_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)

bt_avrcp_set_borwsed_player(conn, player_id)

bt_avrcp_ct_set_browsed_player(ct, tid, player_id)

Typo fixed in edgefast_open. Explicit tid added.

Get Folder Items (CT)

bt_avrcp_get_folder_items(conn, struct bt_avrcp_get_folder_items_cmd *)

bt_avrcp_ct_get_folder_items(ct, tid, struct net_buf *)

Typed struct vs pre-serialized net_buf.

Change Path (CT)

bt_avrcp_change_path(conn, struct bt_avrcp_change_path_cmd *)

bt_avrcp_ct_change_path(ct, tid, struct net_buf *)

Typed struct vs net_buf.

Get Item Attrs (CT)

bt_avrcp_get_items_attribute(conn, struct bt_avrcp_get_item_attrs_cmd *)

bt_avrcp_ct_get_item_attrs(ct, tid, struct net_buf *)

Name simplified in edgefast_open.

Search (CT)

bt_avrcp_search(conn, struct bt_avrcp_search_cmd *)

bt_avrcp_ct_search(ct, tid, struct net_buf *)

Typed struct vs net_buf.

Get Total Num Items (CT)

bt_avrcp_get_total_num_of_items(conn, scope)

bt_avrcp_ct_get_total_number_of_items(ct, tid, scope)

Name slightly different; tid added.

Browsing response (TG)

bt_avrcp_response_browsing(conn, pdu_id, tl, void*, len) - one generic function

Per-PDU TG functions: bt_avrcp_tg_get_folder_items, bt_avrcp_tg_change_path, etc.

edgefast_open splits into per-PDU TG calls.

General Reject (TG)

Not present

bt_avrcp_tg_browsing_general_reject(tg, tid, status)

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 on classic/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 uint8_t handle allocated by start_initiator/responder

Typed struct pointers struct bt_avrcp_cover_art_ct * / struct bt_avrcp_cover_art_tg *

Role creation

bt_avrcp_cover_art_start_initiator(handle*) / bt_avrcp_cover_art_start_responder(handle*)

CT object delivered in l2cap_connected callback after bt_avrcp_cover_art_ct_l2cap_connect()

L2CAP vs OBEX

Single connect function combining L2CAP + OBEX

Explicit separate steps: ct_l2cap_connect() then ct_connect() (OBEX layer)

Callback structure

Single struct bt_avrcp_cover_art_cb with cmd_received and rsp_received (guarded by role macros)

Separate struct bt_avrcp_cover_art_ct_cb and struct bt_avrcp_cover_art_tg_cb, each with per-operation callbacks

Get image property name

bt_avrcp_get_image_property()

bt_avrcp_cover_art_ct_get_image_properties() (plural, explicit CT prefix)

Buffer model

Typed parameter structs per command

Pre-allocated net_buf via create_pdu(); bool final for OBEX packet fragmentation

PDU buffer allocation

No explicit allocation API

bt_avrcp_cover_art_ct_create_pdu(ct, pool) / _tg_create_pdu(tg, pool)

8. Callback Structures Comparison#

ℹ️ edgefast_bluetooth has one unified struct bt_avrcp_cb covering all events for both CT and TG roles edgefast_open has separate struct bt_avrcp_ct_cb and struct 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

connected(conn, err)

CT: connected(ct)   TG: connected(tg)

Disconnected

disconnected(conn, err)

CT: disconnected(ct)   TG: disconnected(tg)

Browsing connected

browsing_connected(conn, err)

CT: browsing_connected(ct)   TG: browsing_connected(tg)

Browsing disconnected

browsing_disconnected(conn, err)

CT: browsing_disconnected(ct)   TG: browsing_disconnected(tg)

Control received (TG)

control_received(conn, bt_avrcp_control_msg*, err) - all command types

TG: per-command callbacks - unit_info(tg,tid), subunit_info(tg,tid), passthrough(tg,tid,cmd), etc.

Control rsp received (CT)

control_rsp_received(conn, bt_avrcp_control_msg*, err) - all response types

CT: per-command response callbacks - unit_info(ct,tid,rsp), passthrough(ct,tid,rsp), get_caps(ct,tid,rsp), etc.

Vendor dep. continue (CT)

vendor_dependent_continue_rsp(conn, header*, net_buf*)

Not exposed - handled internally

Browsing received (TG)

browsing_received(conn, bt_avrcp_browsing_cmd*, err) - all browsing command types in one callback

TG: per-command callbacks - get_folder_items(tg,tid,cmd), change_path(tg,tid,cmd), search(tg,tid,cmd), etc.

Browsing rsp received (CT)

browsing_rsp_received(conn, bt_avrcp_browsing_rsp*, err) - all browsing responses

CT: per-command response callbacks - get_folder_items(ct,tid,rsp), change_path(ct,tid,rsp), etc.

Cover art callbacks

Single struct bt_avrcp_cover_art_cb with connected, disconnected, cmd_received, rsp_received

Separate struct bt_avrcp_cover_art_ct_cb and struct bt_avrcp_cover_art_tg_cb, each with l2cap_connected, l2cap_disconnected, connect, disconnect, abort, get_image_properties, get_image, get_linked_thumbnail

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

include/bluetooth/avrcp.h (flat)

include/zephyr/bluetooth/classic/avrcp.h + classic/avrcp_cover_art.h

Connection object

struct bt_conn *conn for all operations

Typed struct bt_avrcp_ct *ct / struct bt_avrcp_tg *tg

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 uint8_t tid on every call - app controls matching of request and response

Callback model

Single struct bt_avrcp_cb for all events

Separate struct bt_avrcp_ct_cb and struct bt_avrcp_tg_cb, each with per-operation members

Vendor-dependent PDUs

Generic bt_avrcp_send_vendor_dependent(pdu_id, void*) dispatcher

Individual per-PDU typed functions (13+ CT functions)

Browsing TG responses

Single bt_avrcp_response_browsing(pdu_id, void*) dispatcher

Per-PDU TG response functions; new bt_avrcp_tg_browsing_general_reject()

Fragmentation control

App calls bt_avrcp_request_continuing_rsp() / bt_avrcp_abort_continuing_rsp()

Internal; bool final parameter on cover art operations only

Data passing

Typed structs per command (e.g. struct bt_avrcp_get_folder_items_cmd)

struct net_buf *buf for complex commands; app pre-serializes in big-endian per spec

Cover art header

Integrated in avrcp.h, handle-based (uint8_t)

Separate avrcp_cover_art.h; typed CT/TG objects embedding BIP; explicit L2CAP + OBEX steps

Set browsed player typo

bt_avrcp_set_borwsed_player (typo in header)

bt_avrcp_ct_set_browsed_player (typo fixed)

Constants style

#define macros for op IDs, events, errors, response types

typedef enum __packed for all constant sets; unified bt_avrcp_status_t for errors

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

BT_AVDTP

bool, default n

bool (no default)

Audio/Video Distribution Transport Protocol - prerequisite for A2DP and AVRCP in both stacks

BT_AVCTP

- 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

BT_AVRCP

bool, default n

bool (no default)

Master AVRCP enable. Both stacks gate all AVRCP sub-features on this symbol. edgefast_bluetooth forces an explicit default n; edgefast_open relies on Kconfig default (also disabled)

BT_AVRCP_BROWSING

bool, default n

bool (no default)

Enables the AVRCP Browsing Channel (separate L2CAP PSM). Semantically identical in both stacks

BT_AVRCP_BROWSING_L2CAP_MTU

- 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

BT_AVRCP_VD_RX_SIZE

- 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

BT_AVRCP_CT

BT_AVRCP_CONTROLLER

bool

Enables the AVRCP Controller (CT) role. Symbol renamed: short form vs full word. No default in either

BT_AVRCP_TG

BT_AVRCP_TARGET

bool

Enables the AVRCP Target (TG) role. Same rename pattern. No default in either

BT_AVRCP_MAX_CONN

- 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

BT_AVRCP_COVER_ART

- 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 (BT_AVRCP_CT_COVER_ART / BT_AVRCP_TG_COVER_ART)

BT_AVRCP_COVER_ART_INITIATOR

BT_AVRCP_CT_COVER_ART

bool, default n

Cover art initiator (CT side). edgefast_open renames to CT_COVER_ART and additionally gates the fine-grained operation symbols below

BT_AVRCP_COVER_ART_RESPONDER

BT_AVRCP_TG_COVER_ART

bool, default n

Cover art responder (TG side). Renamed in edgefast_open

- not present -

BT_AVRCP_CT_COVER_ART_GET_IMAGE

bool

edgefast_open only - enables the CT Get Image OBEX operation individually. edgefast_bluetooth bundles all cover art CT operations under BT_AVRCP_COVER_ART_INITIATOR

- not present -

BT_AVRCP_CT_COVER_ART_GET_IMAGE_PROPERTIES

bool

edgefast_open only - enables the CT Get Image Properties OBEX operation individually

- not present -

BT_AVRCP_CT_COVER_ART_GET_LINKED_THUMBNAIL

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

BT_AVDTP

bool, default n

bool

BT_AVCTP

-

bool

BT_AVRCP

bool, default n

bool

BT_AVRCP_BROWSING

bool, default n

bool

BT_AVRCP_BROWSING_L2CAP_MTU

-

int, default 339

BT_AVRCP_VD_RX_SIZE

-

int, default 1024

BT_AVRCP_CT

bool, default n

- BT_AVRCP_CONTROLLER

BT_AVRCP_TG

bool, default n

- BT_AVRCP_TARGET

BT_AVRCP_MAX_CONN

int, default BT_MAX_CONN

-

BT_AVRCP_COVER_ART

bool, default n

- (split into CT/TG)

BT_AVRCP_COVER_ART_INITIATOR

bool, default n

- BT_AVRCP_CT_COVER_ART

BT_AVRCP_COVER_ART_RESPONDER

bool, default n

- BT_AVRCP_TG_COVER_ART

BT_AVRCP_CT_COVER_ART_GET_IMAGE

-

bool

BT_AVRCP_CT_COVER_ART_GET_IMAGE_PROPERTIES

-

bool

BT_AVRCP_CT_COVER_ART_GET_LINKED_THUMBNAIL

-

bool

HFP#

Edgefast Bluetooth vs Edgefast Open - HFP API Differences#

Source: middleware/edgefast_bluetooth/include/bluetooth/hfp_hf.h + hfp_ag.h vs middleware/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 typed struct 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 introduce struct 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) with enum bt_hfp_hf_at_cmd for 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_representation callback, ready_to_accept_audio) that has no equivalent in edgefast_bluetooth.

Aspect

edgefast_bluetooth

edgefast_open

HF connection handle

struct bt_conn *conn (generic BT conn)

struct bt_hfp_hf *hf (HFP-typed object delivered in connected callback)

AG connection handle

struct bt_hfp_ag *hfp_ag (typed AG object from bt_hfp_ag_connect)

struct bt_hfp_ag *ag (typed AG object - same concept, cleaner lifecycle)

Per-call handle

None - call state tracked implicitly via AT indicators

struct bt_hfp_hf_call *call / struct bt_hfp_ag_call *call per active call

HF callback registration

bt_hfp_hf_register(struct bt_hfp_hf_cb *cb)

bt_hfp_hf_register(struct bt_hfp_hf_cb *cb) - same name, different callback struct

AG callback registration

bt_hfp_ag_register_cb(struct bt_hfp_ag_cb *cb)

bt_hfp_ag_register(struct bt_hfp_ag_cb *cb) - renamed

HF connect signature

bt_hfp_hf_connect(conn, channel)

bt_hfp_hf_connect(conn, **hf, channel) - returns HF object

AG connect signature

bt_hfp_ag_connect(conn, config, cb, **phfp_ag)

bt_hfp_ag_connect(conn, **ag, channel) - config moved to callback

AG init/deinit

bt_hfp_ag_init() / bt_hfp_ag_deinit() explicit

No separate init/deinit - lifecycle managed via bt_hfp_ag_register

Call accept/reject (HF)

bt_hfp_hf_send_cmd(conn, BT_HFP_HF_ATA) / bt_hfp_hf_send_cmd(conn, BT_HFP_HF_AT_CHUP)

bt_hfp_hf_accept(call) / bt_hfp_hf_reject(call) / bt_hfp_hf_terminate(call)

Dialing (HF)

bt_hfp_hf_dial(conn, number) / bt_hfp_hf_last_dial(conn) / bt_hfp_hf_dial_memory(conn, location)

bt_hfp_hf_number_call(hf, number) / bt_hfp_hf_redial(hf) / bt_hfp_hf_memory_dial(hf, location)

CLIP / call waiting

Separate enable/disable functions: bt_hfp_hf_enable_clip_notification / bt_hfp_hf_disable_clip_notification

Single boolean toggle: bt_hfp_hf_cli(hf, enable) / bt_hfp_hf_call_waiting_notify(hf, enable)

Volume control (HF)

bt_hfp_hf_volume_update(conn, hf_volume_type_t, volume) using custom enum

bt_hfp_hf_vgm(hf, gain) / bt_hfp_hf_vgs(hf, gain) - split by direction

Volume control (AG)

bt_hfp_ag_set_volume_control(hfp_ag, hf_ag_volume_type_t, value)

bt_hfp_ag_vgm(ag, vgm) / bt_hfp_ag_vgs(ag, vgs) - split by direction

3-way call (HF)

bt_hfp_hf_multiparty_call_option(conn, hf_multiparty_call_option_t) with enum options 1�?

Individual functions: bt_hfp_hf_release_all_held, bt_hfp_hf_set_udub, bt_hfp_hf_release_active_accept_other, bt_hfp_hf_hold_active_accept_other, bt_hfp_hf_join_conversation, bt_hfp_hf_explicit_call_transfer, bt_hfp_hf_release_specified_call, bt_hfp_hf_private_consultation_mode

Codec handling

bt_hfp_hf_trigger_codec_connection(conn) / bt_hfp_hf_open_audio(conn, codec) / bt_hfp_hf_close_audio(sco_conn)

bt_hfp_hf_audio_connect(hf) / bt_hfp_hf_select_codec(hf, codec_id) / bt_hfp_hf_set_codecs(hf, codec_ids)

ECNR

None in HF header

bt_hfp_hf_turn_off_ecnr(hf)

Indicator activation

None

bt_hfp_hf_indicator_status(hf, status) with bitmap

HF indicators (battery/safety)

Via bt_hfp_ag_handle_indicator_enable and bt_hfp_ag_set_hf_indicator

bt_hfp_hf_enhanced_safety(hf, enable) / bt_hfp_hf_battery(hf, level)

Voice recognition text

Not supported

bt_hfp_hf_ready_to_accept_audio(hf) + vre_state / textual_representation callbacks

Subscriber number

None (HF) / None (AG standalone query)

bt_hfp_hf_query_subscriber(hf) / bt_hfp_ag_ongoing_calls + subscriber_number callback

Network operator

None (HF) / bt_hfp_ag_set_cops(hfp_ag, name) (AG)

bt_hfp_hf_get_operator(hf) (HF) / bt_hfp_ag_set_operator(ag, mode, name) (AG)

AG incoming call notify

bt_hfp_ag_call_status_pl(hfp_ag, hfp_ag_call_status_t)

bt_hfp_ag_remote_incoming(ag, number) + bt_hfp_ag_remote_ringing/accept/reject/terminate

DTMF

None (HF) / recv_dtmf_codes callback (AG)

bt_hfp_hf_transmit_dtmf_code(call, code) (HF) / transmit_dtmf_code callback (AG)

2. Header File Layout & Constants#

Item

edgefast_bluetooth

edgefast_open

HF main header

include/bluetooth/hfp_hf.h

include/zephyr/bluetooth/classic/hfp_hf.h

AG main header

include/bluetooth/hfp_ag.h

include/zephyr/bluetooth/classic/hfp_ag.h

HF AT command enum

enum bt_hfp_hf_at_cmd { BT_HFP_HF_ATA, BT_HFP_HF_AT_CHUP, BT_HFP_HF_AT_BAC } - raw AT commands exposed to app

No AT command enum - replaced by typed function calls

Volume type

typedef enum _hf_volume_type_t { hf_volume_type_speaker, hf_volume_type_mic } (HF) and typedef enum _hf_ag_volume_type_t (AG)

No volume type enum - split into vgm/vgs functions

Multiparty call options

typedef enum _hf_multiparty_call_option_t with options 1–5

No enum - individual named functions per CHLD value

Call status (AG indicator)

typedef enum hfp_ag_call_status_t { call_end, call_active, call_incoming, call_outgoing }

enum __packed bt_hfp_ag_call_status with 7 values (ACTIVE, HELD, DIALING, ALERTING, INCOMING, WAITING, INCOMING_HELD)

Call direction

No enum

enum __packed bt_hfp_hf_call_dir / enum __packed bt_hfp_ag_call_dir

Call mode

No enum

enum __packed bt_hfp_hf_call_mode { VOICE, DATA, FAX }

AG indicators enum

None in header

enum bt_hfp_ag_indicator with 7 named values (BT_HFP_AG_SERVICE_IND - BT_HFP_AG_BATTERY_IND)

HF indicators enum

None

enum hfp_hf_ag_indicators and enum hfp_ag_hf_indicators

Codec IDs (AG)

Not defined in header (passed via uint8_t codec or config struct bt_hfp_ag_codec)

#define BT_HFP_AG_CODEC_CVSD 0x01, BT_HFP_AG_CODEC_MSBC 0x02, BT_HFP_AG_CODEC_LC3_SWB 0x03

AG CIND struct

typedef struct _hfp_ag_cind_t with flat uint8 fields

No CIND struct - indicators set via individual functions (bt_hfp_ag_service_availability, bt_hfp_ag_signal_strength, etc.)

HF config struct

typedef struct _hfp_hf_get_config { vgs, vgm } obtained in get_config callback

No config struct - initial values set via bt_hfp_hf_vgm/vgs in connected callback

AG config struct

typedef struct _hfp_ag_get_config with 10+ fields passed to bt_hfp_ag_connect

No config struct - configuration via Kconfig and individual callbacks

Current call info (HF)

typedef struct bt_hfp_hf_current_calls_state_t with raw char number[] and uint8_t alpha[] arrays

struct bt_hfp_hf_current_call with typed enums for dir, status, mode and bool multiparty

Ongoing call info (AG)

None - AG uses raw char *call_list string in bt_hfp_ag_set_clcc

struct bt_hfp_ag_ongoing_call with typed enums for dir, status

Subscriber callback type

None

typedef int (*bt_hfp_ag_query_subscriber_func_t)(ag, number, type, service)

Waiting call struct

typedef struct _hf_waiting_call_state_t { number, type, voice_class, alpha } in callback

Folded into call_waiting callback with direct number + type parameters

Indicator status struct

typedef struct _hf_indicator_status_t with 7 uint8 fields

No struct - individual callbacks per indicator (service, signal, roam, battery)

HF indicator IDs

#define HF_INDICATOR_ENHANCED_DRIVER_SAFETY 0x0001 / HF_INDICATOR_BATTERY_LEVEL 0x0002 in hfp_ag.h

enum hfp_ag_hf_indicators { HFP_AG_ENHANCED_SAFETY_IND=1, HFP_AG_BATTERY_LEVEL_IND=2 }

3. HF Connection Management#

ℹ️ Both stacks share the same function name bt_hfp_hf_register and bt_hfp_hf_connect / bt_hfp_hf_disconnect, but the handle type passed and returned changes fundamentally. edgefast_open’s connect returns a typed struct bt_hfp_hf * object while edgefast_bluetooth uses the generic struct 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_disconnect and a bt_hfp_hf_discover for manual SDP discovery. edgefast_open integrates SCO lifecycle entirely within sco_connected / sco_disconnected callbacks and provides bt_hfp_hf_audio_connect instead; 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 the struct 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_audio for direct SCO audio control (noted as PTS-only). edgefast_open uses bt_hfp_hf_audio_connect which handles codec negotiation (AT+BCC) internally when supported; codec IDs are set separately via bt_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_cmd with an enum for ATA and AT+CHUP. edgefast_open models each call-state transition as a dedicated typed function operating on a struct 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 location for memory dial while edgefast_open uses const char *location. Handle changes from struct bt_conn * to struct bt_hfp_hf *. edgefast_open renames bt_hfp_hf_dial - bt_hfp_hf_number_call and bt_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_update with a type enum. edgefast_open splits into vgm (microphone) and vgs (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 on struct bt_hfp_hf_call *, and separates release_all_held from set_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_audio for 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_cmd dispatches raw AT commands (ATA, AT+CHUP, AT+BAC); edgefast_open replaces this with typed functions. bt_hfp_hf_get_last_voice_tag_number is replaced by bt_hfp_hf_request_phone_number in 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 bt_hfp_hf_cb

edgefast_open bt_hfp_hf_cb

Notes

connected

(struct bt_conn *conn, int err)

(struct bt_conn *conn, struct bt_hfp_hf *hf)

edgefast_open delivers the HF object here; no error code

disconnected

(struct bt_conn *conn)

(struct bt_hfp_hf *hf)

Handle type changes

sco_connected

(struct bt_conn *conn, struct bt_conn *sco_conn)

(struct bt_hfp_hf *hf, struct bt_conn *sco_conn)

First param changes

sco_disconnected

(struct bt_conn *sco_conn, uint8_t reason)

(struct bt_conn *sco_conn, uint8_t reason)

Identical

service

(struct bt_conn *conn, uint32_t value)

(struct bt_hfp_hf *hf, uint32_t value)

Handle type changes

call

(struct bt_conn *conn, uint32_t value)

Not present as raw indicator - replaced by outgoing, incoming, accept, reject, terminate callbacks on struct bt_hfp_hf_call *

edgefast_open lifts call state to typed per-call callbacks

call_setup

(struct bt_conn *conn, uint32_t value)

Not present - folded into outgoing / remote_ringing / incoming / dialing callbacks

-

call_held

(struct bt_conn *conn, uint32_t value)

Not present as raw indicator - replaced by held / retrieve callbacks on call object

-

signal

(struct bt_conn *conn, uint32_t value)

(struct bt_hfp_hf *hf, uint32_t value)

Handle type changes

roam

(struct bt_conn *conn, uint32_t value)

(struct bt_hfp_hf *hf, uint32_t value)

Handle type changes

battery

(struct bt_conn *conn, uint32_t value)

(struct bt_hfp_hf *hf, uint32_t value)

Handle type changes

voicetag_phnum

(struct bt_conn *conn, char *number)

request_phone_number(struct bt_hfp_hf *hf, const char *number)

Renamed; edgefast_open uses const char *

call_phnum

(struct bt_conn *conn, char *number)

clip(struct bt_hfp_hf_call *call, const char *number, uint8_t type)

Renamed; type field added

call_phname

(struct bt_conn *conn, char *name)

Not present

No equivalent in edgefast_open

waiting_call

(struct bt_conn *conn, hf_waiting_call_state_t *wcs)

call_waiting(struct bt_hfp_hf_call *call, const char *number, uint8_t type)

Struct replaced by inline params

ring_indication

(struct bt_conn *conn)

ring_indication(struct bt_hfp_hf_call *call)

Param changes to call object

volume_update

(struct bt_conn *conn, hf_volume_type_t type, int volume)

vgm(struct bt_hfp_hf *hf, uint8_t gain) + vgs(struct bt_hfp_hf *hf, uint8_t gain)

Split by direction; type enum removed

indicator_status

(struct bt_conn *conn, hf_indicator_status_t *status)

Not present as batch struct - each indicator has its own callback

Decomposed into individual callbacks

cmd_complete_cb

(struct bt_conn *conn, struct bt_hfp_hf_cmd_complete *cmd)

dialing(struct bt_hfp_hf *hf, int err)

Narrowed to dial result; general AT cmd completion removed

ringtone_inband_set

(struct bt_conn *conn, uint8_t set)

inband_ring(struct bt_hfp_hf *hf, bool inband)

Renamed; uint8_t - bool

get_config

(hfp_hf_get_config **config)

Not present

Config eliminated; use vgm/vgs in connected callback

codec_selection_cb

(struct bt_conn *conn, uint8_t *codec)

codec_negotiate(struct bt_hfp_hf *hf, uint8_t id)

Renamed; pointer - value

get_peer_supported_features_ext

(uint32_t bt_hfp_hf_peer_supported_features_ext)

Not present

No direct equivalent

list_current_calls

(struct bt_conn *conn, bt_hfp_hf_current_calls_state_t *calls_state)

query_call(struct bt_hfp_hf *hf, struct bt_hfp_hf_current_call *call)

Renamed; struct now uses typed enums

outgoing

Not present

outgoing(struct bt_hfp_hf *hf, struct bt_hfp_hf_call *call) 🔴

New in edgefast_open

remote_ringing

Not present

remote_ringing(struct bt_hfp_hf_call *call) 🔴

New in edgefast_open

incoming

Not present

incoming(struct bt_hfp_hf *hf, struct bt_hfp_hf_call *call) 🔴

New in edgefast_open

incoming_held

Not present

incoming_held(struct bt_hfp_hf_call *call) 🔴

New in edgefast_open

accept

Not present

accept(struct bt_hfp_hf_call *call) 🔴

New in edgefast_open

reject

Not present

reject(struct bt_hfp_hf_call *call) 🔴

New in edgefast_open

terminate

Not present

terminate(struct bt_hfp_hf_call *call) 🔴

New in edgefast_open

held

Not present

held(struct bt_hfp_hf_call *call) 🔴

New in edgefast_open

retrieve

Not present

retrieve(struct bt_hfp_hf_call *call) 🔴

New in edgefast_open

operator

Not present

operator(struct bt_hfp_hf *hf, uint8_t mode, uint8_t format, const char *operator) 🔴

New in edgefast_open

ecnr_turn_off

Not present

ecnr_turn_off(struct bt_hfp_hf *hf, int err) 🔴

New in edgefast_open

voice_recognition

Not present

voice_recognition(struct bt_hfp_hf *hf, bool activate) 🔴

New in edgefast_open

vre_state

Not present

vre_state(struct bt_hfp_hf *hf, uint8_t state) 🔴

New in edgefast_open - Enhanced VR engine state

textual_representation

Not present

textual_representation(struct bt_hfp_hf *hf, char *id, uint8_t type, uint8_t operation, const char *text) 🔴

New in edgefast_open - VR text

subscriber_number

Not present

subscriber_number(struct bt_hfp_hf *hf, const char *number, uint8_t type, uint8_t service) 🔴

New in edgefast_open

6. AG Connection Management#

ℹ️ edgefast_bluetooth’s bt_hfp_ag_connect takes a full hfp_ag_get_config struct with 10+ fields at connect time and also embeds the callback. edgefast_open’s bt_hfp_ag_connect only needs the struct bt_conn * and RFCOMM channel; configuration is distributed into callbacks (get_indicator_value, get_ongoing_call) and Kconfig settings. edgefast_bluetooth also requires explicit bt_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_conn to retrieve the underlying ACL connection from an AG object. edgefast_open does not expose this. edgefast_bluetooth includes a bt_hfp_ag_discover for 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 on struct 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_audio are void return. edgefast_open merges codec selection into bt_hfp_ag_audio_connect and returns int. Separate bt_hfp_ag_codec_selector does not exist in edgefast_open; codec is passed directly to audio_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_pl with 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, and callheld indicators via dedicated functions and also provides a bulk CIND get/set via hfp_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_state and bt_hfp_ag_vre_textual_representation for 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_cops renamed to set_operator and gains a mode parameter. Inband ring tone changes from int value to bool 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 bt_hfp_ag_cb

edgefast_open bt_hfp_ag_cb

Notes

connected

(struct bt_hfp_ag *hfp_ag, int err)

(struct bt_conn *conn, struct bt_hfp_ag *ag)

edgefast_open also delivers the ACL conn; no error code

disconnected

(struct bt_hfp_ag *hfp_ag)

(struct bt_hfp_ag *ag)

Equivalent; parameter renamed

sco_connected

(struct bt_hfp_ag *ag, struct bt_conn *sco_conn)

(struct bt_hfp_ag *ag, struct bt_conn *sco_conn)

Identical

sco_disconnected

(struct bt_hfp_ag *ag)

(struct bt_conn *sco_conn, uint8_t reason)

edgefast_open passes SCO conn + reason code; edgefast_bluetooth passes AG object

get_config

(struct bt_hfp_ag *hfp_ag, hfp_ag_get_config **config)

Not present - replaced by get_indicator_value + get_ongoing_call

Config struct eliminated

get_indicator_value

Not present

(struct bt_hfp_ag *ag, uint8_t *service, uint8_t *strength, uint8_t *roam, uint8_t *battery) 🔴

New in edgefast_open - initial indicator values at SLC

get_ongoing_call

Not present

(struct bt_hfp_ag *ag) 🔴

New in edgefast_open - replaces bt_hfp_ag_set_clcc call pattern

volume_control

(struct bt_hfp_ag *hfp_ag, hf_ag_volume_type_t type, int value)

vgm(struct bt_hfp_ag *ag, uint8_t gain) + vgs(struct bt_hfp_ag *ag, uint8_t gain)

Split by direction

hfu_brsf

(struct bt_hfp_ag *hfp_ag, uint32_t value)

Not present

Remote HF feature bits not surfaced as callback in edgefast_open

ata_response

(struct bt_hfp_ag *hfp_ag)

accept(struct bt_hfp_ag_call *call)

Renamed; param changes to call object

chup_response

(struct bt_hfp_ag *hfp_ag)

reject(struct bt_hfp_ag_call *call) + terminate(struct bt_hfp_ag_call *call)

Decomposed by call state

dial

(struct bt_hfp_ag *hfp_ag, char *number)

number_call(struct bt_hfp_ag *ag, const char *number)

Renamed; const added

memory_dial

(struct bt_hfp_ag *ag, uint32_t location)

memory_dial(struct bt_hfp_ag *ag, const char *location, char **number)

edgefast_open passes location as string + requests number back

last_dial

(struct bt_hfp_ag *ag)

redial(struct bt_hfp_ag *ag, char number[...])

edgefast_open expects app to fill in the last number

outgoing

Not present

outgoing(struct bt_hfp_ag *ag, struct bt_hfp_ag_call *call, const char *number) 🔴

New - call object created here

incoming

Not present

incoming(struct bt_hfp_ag *ag, struct bt_hfp_ag_call *call, const char *number) 🔴

New - incoming call object

incoming_held

Not present

incoming_held(struct bt_hfp_ag_call *call) 🔴

New

ringing

Not present

ringing(struct bt_hfp_ag_call *call, bool in_band) 🔴

New - replaces bt_hfp_ag_send_callring

held

Not present

held(struct bt_hfp_ag_call *call) 🔴

New

retrieve

Not present

retrieve(struct bt_hfp_ag_call *call) 🔴

New

reject

Not present

reject(struct bt_hfp_ag_call *call) 🔴

New

terminate

Not present

terminate(struct bt_hfp_ag_call *call) 🔴

New

brva

(struct bt_hfp_ag *hfp_ag, uint32_t value)

voice_recognition(struct bt_hfp_ag *ag, bool activate)

Renamed; uint32_t - bool

nrec

(struct bt_hfp_ag *hfp_ag, uint32_t value)

ecnr_turn_off(struct bt_hfp_ag *ag)

Renamed; value removed (always turn-off)

codec_negotiate

(struct bt_hfp_ag *hfp_ag, uint32_t value)

codec_negotiate(struct bt_hfp_ag *ag, int err)

param changes from codec ID to result code

codec_connect_req

(struct bt_hfp_ag *hfp_ag)

audio_connect_req(struct bt_hfp_ag *ag)

Renamed

codec

(struct bt_hfp_ag *ag, uint32_t ids)

codec(struct bt_hfp_ag *ag, uint32_t ids)

Identical

chld

(struct bt_hfp_ag *hfp_ag, uint8_t option, uint8_t index)

explicit_call_transfer(struct bt_hfp_ag *ag) - only for CHLD=4; CHLD=0/1/2/3 handled internally

edgefast_open handles most CHLD operations without app callback

clcc

(struct bt_hfp_ag *ag)

get_ongoing_call(struct bt_hfp_ag *ag)

Renamed; edgefast_open uses bt_hfp_ag_ongoing_calls() to respond

recv_dtmf_codes

(struct bt_hfp_ag *ag, char dtmf_code)

transmit_dtmf_code(struct bt_hfp_ag *ag, char code)

Renamed

unkown_at

(struct bt_hfp_ag *hfp_ag, char *value, uint32_t length)

Not present

No unknown AT passthrough in edgefast_open

hf_indicator

(struct bt_hfp_ag *hfp_ag, uint16_t indicator, uint32_t value)

hf_indicator_value(struct bt_hfp_ag *ag, enum hfp_ag_hf_indicators indicator, uint32_t value)

Renamed; index to enum

request_phone_number

Not present

request_phone_number(struct bt_hfp_ag *ag, char **number)

New - AT+BINP=1 handler

subscriber_number

Not present

subscriber_number(struct bt_hfp_ag *ag, bt_hfp_ag_query_subscriber_func_t func)

New - AT+CNUM handler

ready_to_accept_audio

Not present

ready_to_accept_audio(struct bt_hfp_ag *ag)

New - Enhanced VR

voice_recognition

Not present

voice_recognition(struct bt_hfp_ag *ag, bool activate)

New - replaces brva

explicit_call_transfer

Not present

explicit_call_transfer(struct bt_hfp_ag *ag)

New - AT+CHLD=4

accept

Not present

accept(struct bt_hfp_ag_call *call)

New

held

Not present

held(struct bt_hfp_ag_call *call)

New

retrieve

Not present

retrieve(struct bt_hfp_ag_call *call)

New

reject

Not present

reject(struct bt_hfp_ag_call *call)

New

terminate

Not present

terminate(struct bt_hfp_ag_call *call)

New

9. Full Function Comparison Table#

HF Functions#

Function

edgefast_bluetooth

edgefast_open

Status

Register HF callbacks

bt_hfp_hf_register(cb)

bt_hfp_hf_register(cb)

Same name, different struct

Connect

bt_hfp_hf_connect(conn, channel)

bt_hfp_hf_connect(conn, **hf, channel)

Returns HF object

Disconnect

bt_hfp_hf_disconnect(conn)

bt_hfp_hf_disconnect(hf)

Handle type changes

SCO disconnect

bt_hfp_sco_disconnect(conn)

- (managed via callbacks)

Only in edgefast_bluetooth

SDP discover

bt_hfp_hf_discover(conn, cb)

-

Only in edgefast_bluetooth

Accept call

bt_hfp_hf_send_cmd(conn, BT_HFP_HF_ATA)

bt_hfp_hf_accept(call)

Renamed + typed

Reject call

bt_hfp_hf_send_cmd(conn, BT_HFP_HF_AT_CHUP)

bt_hfp_hf_reject(call)

Renamed + typed

Terminate call

bt_hfp_hf_send_cmd(conn, BT_HFP_HF_AT_CHUP)

bt_hfp_hf_terminate(call)

Renamed + typed

Hold incoming

-

bt_hfp_hf_hold_incoming(call)

Only in edgefast_open

Query R&H status

-

bt_hfp_hf_query_respond_hold_status(hf)

Only in edgefast_open

Dial number

bt_hfp_hf_dial(conn, number)

bt_hfp_hf_number_call(hf, number)

Renamed

Redial

bt_hfp_hf_last_dial(conn)

bt_hfp_hf_redial(hf)

Renamed

Memory dial

bt_hfp_hf_dial_memory(conn, int location)

bt_hfp_hf_memory_dial(hf, const char *location)

Location type changes

Volume update

bt_hfp_hf_volume_update(conn, type, volume)

bt_hfp_hf_vgm(hf, gain) + bt_hfp_hf_vgs(hf, gain)

Split by direction

CLIP enable

bt_hfp_hf_enable_clip_notification(conn)

bt_hfp_hf_cli(hf, true)

Merged with bool

CLIP disable

bt_hfp_hf_disable_clip_notification(conn)

bt_hfp_hf_cli(hf, false)

Merged with bool

Call waiting enable

bt_hfp_hf_enable_call_waiting_notification(conn)

bt_hfp_hf_call_waiting_notify(hf, true)

Merged with bool

Call waiting disable

bt_hfp_hf_disable_call_waiting_notification(conn)

bt_hfp_hf_call_waiting_notify(hf, false)

Merged with bool

3-way call

bt_hfp_hf_multiparty_call_option(conn, option)

8 individual functions

Decomposed

Start voice recognition

bt_hfp_hf_start_voice_recognition(conn)

bt_hfp_hf_voice_recognition(hf, true)

Merged with bool

Stop voice recognition

bt_hfp_hf_stop_voice_recognition(conn)

bt_hfp_hf_voice_recognition(hf, false)

Merged with bool

Ready to accept audio

-

bt_hfp_hf_ready_to_accept_audio(hf)

Only in edgefast_open

Codec connection

bt_hfp_hf_trigger_codec_connection(conn)

bt_hfp_hf_audio_connect(hf)

Renamed

Open audio

bt_hfp_hf_open_audio(conn, codec)

- (merged into audio_connect)

Only in edgefast_bluetooth (PTS)

Close audio

bt_hfp_hf_close_audio(sco_conn)

-

Only in edgefast_bluetooth (PTS)

Select codec

-

bt_hfp_hf_select_codec(hf, codec_id)

Only in edgefast_open

Set codecs

-

bt_hfp_hf_set_codecs(hf, codec_ids)

Only in edgefast_open

Turn off ECNR

-

bt_hfp_hf_turn_off_ecnr(hf)

Only in edgefast_open

Indicator status

-

bt_hfp_hf_indicator_status(hf, status)

Only in edgefast_open

Enhanced safety

-

bt_hfp_hf_enhanced_safety(hf, enable)

Only in edgefast_open

Battery level

-

bt_hfp_hf_battery(hf, level)

Only in edgefast_open

Get operator

-

bt_hfp_hf_get_operator(hf)

Only in edgefast_open

Voice tag number

bt_hfp_hf_get_last_voice_tag_number(conn)

bt_hfp_hf_request_phone_number(hf)

Renamed

DTMF

-

bt_hfp_hf_transmit_dtmf_code(call, code)

Only in edgefast_open

Query subscriber

-

bt_hfp_hf_query_subscriber(hf)

Only in edgefast_open

Peer indicator status

bt_hfp_hf_get_peer_indicator_status(conn)

-

Only in edgefast_bluetooth

Send raw AT cmd

bt_hfp_hf_send_cmd(conn, cmd)

- (replaced by typed functions)

Only in edgefast_bluetooth

Query current calls

bt_hfp_hf_query_list_current_calls(conn)

bt_hfp_hf_query_list_of_current_calls(hf)

Renamed

AG Functions#

Function

edgefast_bluetooth

edgefast_open

Status

Init

bt_hfp_ag_init()

-

Only in edgefast_bluetooth

Deinit

bt_hfp_ag_deinit()

-

Only in edgefast_bluetooth

Register callbacks

bt_hfp_ag_register_cb(cb)

bt_hfp_ag_register(cb)

Renamed

Connect

bt_hfp_ag_connect(conn, config, cb, **ag)

bt_hfp_ag_connect(conn, **ag, channel)

Simplified

Disconnect

bt_hfp_ag_disconnect(hfp_ag)

bt_hfp_ag_disconnect(ag)

Equivalent

Get ACL conn

bt_hfp_ag_get_conn(hfp_ag)

-

Only in edgefast_bluetooth

SDP discover

bt_hfp_ag_discover(conn, cb)

-

Only in edgefast_bluetooth

Open audio

bt_hfp_ag_open_audio(hfp_ag, codec)

bt_hfp_ag_audio_connect(ag, id)

Renamed; returns int

Close audio

bt_hfp_ag_close_audio(hfp_ag)

- (managed via SCO callbacks)

Only in edgefast_bluetooth

Codec select

bt_hfp_ag_codec_selector(hfp_ag, value)

- (merged into audio_connect)

Only in edgefast_bluetooth

Call status

bt_hfp_ag_call_status_pl(hfp_ag, status)

- (replaced by per-event functions)

Only in edgefast_bluetooth

Notify incoming

-

bt_hfp_ag_remote_incoming(ag, number)

Only in edgefast_open

Notify ringing

bt_hfp_ag_send_callring(hfp_ag)

bt_hfp_ag_remote_ringing(call)

Renamed + typed

Notify remote accept

-

bt_hfp_ag_remote_accept(call)

Only in edgefast_open

Notify remote reject

-

bt_hfp_ag_remote_reject(call)

Only in edgefast_open

Notify remote terminate

-

bt_hfp_ag_remote_terminate(call)

Only in edgefast_open

Hold incoming

-

bt_hfp_ag_hold_incoming(call)

Only in edgefast_open

Reject call

-

bt_hfp_ag_reject(call)

Only in edgefast_open

Accept call

-

bt_hfp_ag_accept(call)

Only in edgefast_open

Terminate call

-

bt_hfp_ag_terminate(call)

Only in edgefast_open

Retrieve call

-

bt_hfp_ag_retrieve(call)

Only in edgefast_open

Hold call

-

bt_hfp_ag_hold(call)

Only in edgefast_open

Outgoing call

-

bt_hfp_ag_outgoing(ag, number)

Only in edgefast_open

Explicit call transfer

-

bt_hfp_ag_explicit_call_transfer(ag)

Only in edgefast_open

CCWA indicator

bt_hfp_ag_send_ccwa_indicator(hfp_ag, number)

- (managed internally by stack)

Only in edgefast_bluetooth

Send call indicator

bt_hfp_ag_send_call_indicator(hfp_ag, value)

- (managed internally)

Only in edgefast_bluetooth

Send callsetup indicator

bt_hfp_ag_send_callsetup_indicator(hfp_ag, value)

- (managed internally)

Only in edgefast_bluetooth

Send callheld indicator

bt_hfp_ag_send_callheld_indicator(hfp_ag, value)

- (managed internally)

Only in edgefast_bluetooth

Send service indicator

bt_hfp_ag_send_service_indicator(hfp_ag, value)

bt_hfp_ag_service_availability(ag, available)

Renamed; uint8 to bool

Send signal indicator

bt_hfp_ag_send_signal_indicator(hfp_ag, value)

bt_hfp_ag_signal_strength(ag, strength)

Renamed

Send roam indicator

bt_hfp_ag_send_roaming_indicator(hfp_ag, value)

bt_hfp_ag_roaming_status(ag, status)

Renamed

Send battery indicator

bt_hfp_ag_send_battery_indicator(hfp_ag, value)

bt_hfp_ag_battery_level(ag, level)

Renamed

Get CIND setting

bt_hfp_ag_get_cind_setting(hfp_ag, cind)

-

Only in edgefast_bluetooth

Set CIND setting

bt_hfp_ag_set_cind_setting(hfp_ag, cind)

-

Only in edgefast_bluetooth

Set ongoing calls

bt_hfp_ag_set_clcc(hfp_ag, call_list)

bt_hfp_ag_ongoing_calls(ag, calls, count)

Renamed; typed struct

Volume control

bt_hfp_ag_set_volume_control(hfp_ag, type, value)

bt_hfp_ag_vgm(ag, vgm) + bt_hfp_ag_vgs(ag, vgs)

Split by direction

Set operator

bt_hfp_ag_set_cops(hfp_ag, name)

bt_hfp_ag_set_operator(ag, mode, name)

Renamed; mode added

Inband ring

bt_hfp_ag_set_inband_ring_tone(hfp_ag, value)

bt_hfp_ag_inband_ringtone(ag, inband)

Renamed; int to bool

Set CLIP

bt_hfp_ag_send_clip(hfp_ag, clip_result)

- (managed internally)

Only in edgefast_bluetooth

Enable VR

bt_hfp_ag_send_enable_voice_recognition(hfp_ag)

bt_hfp_ag_voice_recognition(ag, true)

Merged with bool

Disable VR

bt_hfp_ag_send_disable_voice_recognition(hfp_ag)

bt_hfp_ag_voice_recognition(ag, false)

Merged with bool

VR engine state

-

bt_hfp_ag_vre_state(ag, state)

Only in edgefast_open

VR text

-

bt_hfp_ag_vre_textual_representation(...)

Only in edgefast_open

Enable ECNR

bt_hfp_ag_send_enable_voice_ecnr(hfp_ag)

-

Only in edgefast_bluetooth

Disable ECNR

bt_hfp_ag_send_disable_voice_ecnr(hfp_ag)

-

Only in edgefast_bluetooth

Supp features register

bt_hfp_ag_register_supp_features(hfp_ag, features)

-

Only in edgefast_bluetooth

Get peer features

bt_hfp_ag_get_peer_supp_features(hfp_ag)

-

Only in edgefast_bluetooth

CIND string register

bt_hfp_ag_register_cind_features(hfp_ag, cind)

-

Only in edgefast_bluetooth

Phone number tag

bt_hfp_ag_set_phnum_tag(hfp_ag, name)

- (handled via request_phone_number callback)

Only in edgefast_bluetooth

BTRH handler

bt_hfp_ag_handle_btrh(hfp_ag, option)

-

Only in edgefast_bluetooth

HF indicator enable

bt_hfp_ag_handle_indicator_enable(hfp_ag, index, enable)

bt_hfp_ag_hf_indicator(ag, indicator, enable)

Renamed; index to enum

HF indicator set

bt_hfp_ag_set_hf_indicator(hfp_ag, hf_indicator, enable)

bt_hfp_ag_hf_indicator(ag, indicator, enable)

Merged

Unknown AT response

bt_hfp_ag_unknown_at_response(hfp_ag, rsp, len)

-

Only in edgefast_bluetooth

10. Architecture Summary#

Topic

edgefast_bluetooth

edgefast_open

HF handle

struct bt_conn * throughout HF lifetime

struct bt_hfp_hf * delivered at connected callback

AG handle

struct bt_hfp_ag * created at bt_hfp_ag_connect

struct bt_hfp_ag * created at bt_hfp_ag_connect - same concept

Call handle

No per-call object

struct bt_hfp_hf_call * / struct bt_hfp_ag_call * delivered in call-event callbacks

Call indicator management

App explicitly sends call, callsetup, callheld indicators (AG-side)

Stack manages call/callsetup/callheld automatically based on call object lifecycle

AT command exposure

Raw AT commands dispatched via bt_hfp_hf_send_cmd(enum)

No raw AT exposure - all operations via typed functions

Config at connect

AG: full hfp_ag_get_config struct with codec, phone number, channel, etc. embedded in connect call

AG: only conn + channel at connect; initial indicator values requested via get_indicator_value callback

Lifecycle management

AG requires bt_hfp_ag_init() / bt_hfp_ag_deinit()

No separate init/deinit

Codec IDs

Numeric uint8_t, no named constants in HF/AG header

Named macros BT_HFP_AG_CODEC_CVSD, _MSBC, _LC3_SWB

Enhanced VR

Not supported

Full support: vre_state, vre_textual_representation, ready_to_accept_audio

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

vgm / vgs named separately for both HF and AG

CLIP/CCWA toggle

Separate enable/disable functions

Single bool enable parameter

SDP discover

Manual: bt_hfp_hf_discover / bt_hfp_ag_discover

Not exposed - caller passes channel directly to connect

Unknown AT handling

bt_hfp_ag_unknown_at_response sends custom response

Not exposed in edgefast_open

CLIP sending (AG)

bt_hfp_ag_send_clip explicitly by app

Managed internally by stack

11. HFP Kconfig Configuration Comparison#

Feature

edgefast_bluetooth Kconfig

edgefast_open Kconfig

HF enable

CONFIG_BT_HFP_HF

CONFIG_BT_HFP_HF

AG enable

CONFIG_BT_HFP_AG

CONFIG_BT_HFP_AG

HF indicators

CONFIG_BT_HFP_AG_HF_IND (in AG header)

CONFIG_BT_HFP_HF_HF_INDICATOR_ENH_SAFETY, CONFIG_BT_HFP_HF_HF_INDICATOR_BATTERY

Codec negotiation (HF)

CONFIG_BT_HFP_HF_CODEC_NEG (implicit via AT+BAC in send_cmd)

CONFIG_BT_HFP_HF_CODEC_NEG

CLI notification (HF)

No dedicated Kconfig - controlled via enable/disable functions

CONFIG_BT_HFP_HF_CLI

Volume (HF)

No dedicated Kconfig - always available

CONFIG_BT_HFP_HF_VOLUME

3-way call (HF)

No dedicated Kconfig

CONFIG_BT_HFP_HF_3WAY_CALL

ECC (HF)

No dedicated Kconfig

CONFIG_BT_HFP_HF_ECC

ECNR (HF)

No dedicated Kconfig in HF header

CONFIG_BT_HFP_HF_ECNR

Voice recognition (HF)

No dedicated Kconfig in HF header

CONFIG_BT_HFP_HF_VOICE_RECG

Enhanced VR (HF)

Not supported

CONFIG_BT_HFP_HF_ENH_VOICE_RECG

VR text (HF)

Not supported

CONFIG_BT_HFP_HF_VOICE_RECG_TEXT

ECS (current calls, HF)

No dedicated Kconfig

CONFIG_BT_HFP_HF_ECS

3-way call (AG)

No dedicated Kconfig

CONFIG_BT_HFP_AG_3WAY_CALL

ECNR (AG)

No dedicated Kconfig

CONFIG_BT_HFP_AG_ECNR

Voice recognition (AG)

No dedicated Kconfig

CONFIG_BT_HFP_AG_VOICE_RECG

Enhanced VR (AG)

Not supported

CONFIG_BT_HFP_AG_ENH_VOICE_RECG

VR text (AG)

Not supported

CONFIG_BT_HFP_AG_VOICE_RECG_TEXT

Voice tag (AG)

No dedicated Kconfig

CONFIG_BT_HFP_AG_VOICE_TAG

HF indicators (AG)

CONFIG_BT_HFP_AG_HF_IND

CONFIG_BT_HFP_HF_HF_INDICATORS

Phone number max len

Not configurable (hardcoded HFP_HF_DIGIT_ARRAY_SIZE 32)

CONFIG_BT_HFP_AG_PHONE_NUMBER_MAX_LEN

Ongoing call timeout

Not configurable

CONFIG_BT_HFP_AG_GET_ONGOING_CALL_TIMEOUT

MAP#

Edgefast Bluetooth vs Edgefast Open — MAP API Differences#

Source: middleware/edgefast_bluetooth/include/bluetooth/map_mce.h + map_mse.h vs middleware/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 global register(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 / disconnected callback pair. edgefast_open exposes four separate transport callbacks (rfcomm_connected, rfcomm_disconnected, l2cap_connected, l2cap_disconnected) plus additional OBEX-level connect / disconnect callbacks, 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 struct bt_map_mce_mas / struct bt_map_mse_mas / struct bt_map_mce_mns / struct bt_map_mse_mns

Callback registration

Single global call: bt_map_mce_mas_register(cb) / bt_map_mse_mas_register(cb) / bt_map_mce_mns_register(cb) / bt_map_mse_mns_register(cb)

Per-instance: bt_map_mce_mas_cb_register(mce_mas, cb) / bt_map_mse_mas_cb_register(mse_mas, cb) / bt_map_mce_mns_cb_register(mce_mns, cb) / bt_map_mse_mns_cb_register(mse_mns, cb)

Transport connection (MCE)

Single step: bt_map_mce_psm_connect() / bt_map_mce_scn_connect() — stack creates object

Two steps: bt_map_mce_mas_l2cap_connect() / bt_map_mce_mas_rfcomm_connect() (transport) then bt_map_mce_mas_connect() (OBEX)

Transport events (MCE)

Single connected(mce_mas) / disconnected(mce_mas, result)

Split: rfcomm_connected, rfcomm_disconnected, l2cap_connected, l2cap_disconnected + OBEX connect(rsp_code, version, mopl, buf), OBEX disconnect(rsp_code, buf)

Server registration

Single global call: bt_map_mse_mas_register(cb) / bt_map_mce_mns_register(cb) to register all servers

Per-server call: bt_map_mse_mas_rfcomm_register(server) / bt_map_mse_mas_l2cap_register(server) / bt_map_mce_mns_rfcomm_register(server) / bt_map_mce_mns_l2cap_register(server) to register individual server

MAP header encoding

Stack adds OBEX Connection ID, SRM, SRMP, Name and Type headers automatically based on input parameters and provides dedicated helper macros (BT_MAP_ADD_*, BT_MAP_ADD_BODY, BT_MAP_ADD_END_OF_BODY, etc.) to add body and application parameter headers

App calls OBEX APIs directly (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 full control over header construction and placement within buf

Fragmentation control

bool wait (SRMP) + enum bt_obex_req_flags on every multi-packet operation

bool final replacing flags enum; App calls bt_obex_add_header_srm_param to add SRMP header manually if SRMP required

SRM state management

Stack adds SRM header and maintains SRM state internally

App calls bt_obex_add_header_srm to add SRM header manually, track and manage SRM state on its own

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

BT_MAP_MCE_RSV_LEN_* / BT_MAP_MSE_RSV_LEN_* per-operation macros

Not present — replaced by bt_map_mce_mas_create_pdu() / bt_map_mse_mas_create_pdu() helper

Max packet length query

bt_map_mce_get_max_pkt_len() / bt_map_mse_get_max_pkt_len()

Not present — maximum packet length returned via mopl parameter in OBEX connect callback

Abort

bt_map_mce_abort(mce_mas) — no buf

bt_map_mce_mas_abort(mce_mas, buf) — takes net_buf * for extra headers

MSE disconnect

bt_map_mse_disconnect(mse_mas) — single call

bt_map_mse_mas_rfcomm_disconnect() / bt_map_mse_mas_l2cap_disconnect() (transport) + bt_map_mse_mas_disconnect() (OBEX)

2. Header File Layout & Constants #

Item

edgefast_bluetooth

edgefast_open

MCE header

include/bluetooth/map_mce.h

Unified include/zephyr/bluetooth/classic/map.h (MCE + MSE, ~2500 lines)

MSE header

include/bluetooth/map_mse.h

Same unified classic/map.h

Shared types header

include/bluetooth/map_types.h (imported by both mce/mse headers)

All types defined inline in map.h

OBEX dependency

#include <bluetooth/obex.h>

#include <zephyr/bluetooth/classic/goep.h>

RSV_LEN macros

BT_MAP_MCE_RSV_LEN_GET_FOLDER_LISTING(mce_mas, flags), BT_MAP_MCE_RSV_LEN_SET_FOLDER(mce_mas), … (~14 macros total)

Not present

Type headers

#define BT_MAP_HDR_TYPE_* in map_types.h

#define BT_MAP_HDR_TYPE_* in map.h — identical values

Supported features

enum bt_map_supported_features in map_types.h

enum __packed bt_map_supported_features in map.h — identical members

Application param tag IDs

enum bt_map_appl_param_tag_id in map_types.h

enum __packed bt_map_appl_param_tag_id in map.h — identical values

Add application parameter helper

#define BT_MAP_ADD_*(buf, val, len) macro wrapping bt_obex_add_app_param

Not present as named macro — app calls OBEX layer directly: bt_obex_add_header_app_param

Add body helper

#define BT_MAP_ADD_BODY(buf, val, len) / #define BT_MAP_ADD_END_OF_BODY(buf, val, len)

Not present as named macro — app calls OBEX layer directly: bt_obex_add_header_body / bt_obex_add_header_end_body / bt_obex_add_header_body_or_end_body

Parse application parameter helper

#define bt_map_mce_app_param_parse(buf, func, user_data) macro wrapping bt_obex_app_param_parse

Not present as named macro — app calls OBEX layer directly: bt_obex_header_parse and bt_obex_tlv_parse

Get body helper

#define bt_map_mce_get_body(buf, body, length) / bt_map_mse_get_body(...)

Not present as named macro — app calls OBEX layer directly: bt_obex_get_header_body and bt_obex_get_header_end_body

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 connected callback. 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(), no supported_features parameter on transport connect (passed separately in OBEX CONNECT headers via buf), and no get_max_pkt_len — the mopl value is delivered in the connect callback.

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 the struct 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 a bool wait flag for SRMP handling. In edgefast_open, this is simplified to a single bool 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 to buf when 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 receives connected/disconnected and send_event callbacks. In edgefast_open, the MCE MNS server must explicitly register typed server structs (one for RFCOMM, one for L2CAP), accept incoming connections in an accept callback, 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_responsebt_map_mce_mns_send_event. bool wait removed; buf added 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_mas object via connected callback. In edgefast_open, the app registers typed RFCOMM/L2CAP server structs with an accept callback 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 wait removed. buf always present. char *name removed — name encoded in buf.

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_eventbt_map_mse_mns_send_event. enum bt_obex_req_flags flagsbool final. Two-step transport + OBEX connect replaces one-step psm_connect / scn_connect. MSE MNS callbacks connected(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 bt_map_mce_mas_cb

edgefast_open bt_map_mce_mas_cb

Notes

Transport connected

connected(mce_mas) — single combined

rfcomm_connected(conn, mce_mas) + l2cap_connected(conn, mce_mas)

🟡 edgefast_open exposes struct bt_conn *conn and splits by transport

Transport disconnected

disconnected(mce_mas, result) — single combined

rfcomm_disconnected(mce_mas) + l2cap_disconnected(mce_mas)

🟡 No result code in edgefast_open transport disconnect

OBEX connect

— (implicit in connected)

connect(mce_mas, rsp_code, version, mopl, buf)

🟡 edgefast_open explicit OBEX connect response with OBEX version + MOPL

OBEX disconnect

— (implicit in disconnected)

disconnect(mce_mas, rsp_code, buf)

🟡 edgefast_open explicit OBEX disconnect response

OBEX abort response

abort(mce_mas, result)

abort(mce_mas, rsp_code, buf)

🟡 edgefast_open adds buf for response headers

get_folder_listing

get_folder_listing(mce_mas, result, buf)

get_folder_listing(mce_mas, rsp_code, buf)

🟡 Identical semantics; parameter renamed resultrsp_code

set_folder

set_folder(mce_mas, result)

set_folder(mce_mas, rsp_code, buf)

🟡 edgefast_open adds buf for response headers

get_msg_listing

get_msg_listing(mce_mas, result, buf)

get_msg_listing(mce_mas, rsp_code, buf)

🟡 Identical

get_msg

get_msg(mce_mas, result, buf)

get_msg(mce_mas, rsp_code, buf)

🟡 Identical

set_msg_status

set_msg_status(mce_mas, result)

set_msg_status(mce_mas, rsp_code, buf)

🟡 edgefast_open adds buf

push_msg

push_msg(mce_mas, result, char *name)

push_msg(mce_mas, rsp_code, buf)

🟡 char *name returned separately in edgefast_bluetooth; edgefast_open encodes it in buf

set_ntf_reg

set_ntf_reg(mce_mas, result)

set_ntf_reg(mce_mas, rsp_code, buf)

🟡 edgefast_open adds buf

update_inbox

update_inbox(mce_mas, result)

update_inbox(mce_mas, rsp_code, buf)

🟡 edgefast_open adds buf

get_mas_inst_info

get_mas_inst_info(mce_mas, result, buf)

get_mas_inst_info(mce_mas, rsp_code, buf)

🟡 Identical

set_owner_status

set_owner_status(mce_mas, result)

set_owner_status(mce_mas, rsp_code, buf)

🟡 edgefast_open adds buf

get_owner_status

get_owner_status(mce_mas, result, buf)

get_owner_status(mce_mas, rsp_code, buf)

🟡 Identical

get_convo_listing

get_convo_listing(mce_mas, result, buf)

get_convo_listing(mce_mas, rsp_code, buf)

🟡 Identical

set_ntf_filter

set_ntf_filter(mce_mas, result)

set_ntf_filter(mce_mas, rsp_code, buf)

🟡 edgefast_open adds buf

8.2 MCE MNS Callbacks#

Callback

edgefast_bluetooth bt_map_mce_mns_cb

edgefast_open bt_map_mce_mns_cb

Notes

Transport connected

connected(mce_mns)

rfcomm_connected(conn, mce_mns) + l2cap_connected(conn, mce_mns)

🟡 edgefast_open exposes struct bt_conn *conn and splits by transport

Transport disconnected

disconnected(mce_mns, result)

rfcomm_disconnected(mce_mns) + l2cap_disconnected(mce_mns)

🟡 No result code in edgefast_open transport disconnect

OBEX connect request

— (implicit in connected)

connect(mce_mns, version, mopl, buf) — app must call bt_map_mce_mns_connect(rsp_code, buf)

🟡 edgefast_open receives explicit CONNECT request and must respond

OBEX disconnect request

— (implicit in disconnected)

disconnect(mce_mns, buf) — app must call bt_map_mce_mns_disconnect(rsp_code, buf)

🟡 edgefast_open receives explicit DISCONNECT request and must respond

OBEX abort request

abort(mce_mns, buf) — app must call bt_map_mce_mns_abort(rsp_code, buf)

🔴 edgefast_open only

send_event

send_event(mce_mns, buf, flags)

send_event(mce_mns, final, buf)

🟡 edgefast_bluetooth uses flags; edgefast_open uses bool final

8.3 MSE MAS Callbacks#

Callback

edgefast_bluetooth bt_map_mse_mas_cb

edgefast_open bt_map_mse_mas_cb

Notes

Transport connected

connected(mse_mas, psm, scn) — delivers PSM + SCN

rfcomm_connected(conn, mse_mas) + l2cap_connected(conn, mse_mas)

🟡 edgefast_bluetooth delivers assigned PSM/SCN in callback; edgefast_open exposes struct bt_conn *conn and splits by transport

Transport disconnected

disconnected(mse_mas, result)

rfcomm_disconnected(mse_mas) + l2cap_disconnected(mse_mas)

🟡 No result code in edgefast_open transport disconnect

OBEX connect request

— (implicit in connected)

connect(mse_mas, version, mopl, buf) — app must call bt_map_mse_mas_connect(rsp_code, buf)

🟡 edgefast_open requires explicit CONNECT handshake response

OBEX disconnect request

— (implicit in disconnected)

disconnect(mse_mas, buf) — app must call bt_map_mse_mas_disconnect(rsp_code, buf)

🟡 edgefast_open requires explicit DISCONNECT handshake response

OBEX abort request

abort(mse_mas) — no result code, response sent internally

abort(mse_mas, buf) — app must call bt_map_mse_mas_abort(rsp_code, buf)

🟡 edgefast_bluetooth handles abort response internally; edgefast_open requires explicit response

get_folder_listing

get_folder_listing(mse_mas, buf, flags)

get_folder_listing(mse_mas, final, buf)

🟡 edgefast_open uses final; edgefast_bluetooth uses flags for fragmentation

set_folder

set_folder(mse_mas, char *name)

set_folder(mse_mas, flags, buf)

🟡 edgefast_bluetooth delivers name string; edgefast_open delivers flags + raw buf with name encoded in buf

get_msg_listing

get_msg_listing(mse_mas, buf, name, flags)

get_msg_listing(mse_mas, final, buf)

🟡 char *name returned separately in edgefast_bluetooth; edgefast_open encodes it in buf

get_msg

get_msg(mse_mas, buf, name, flags)

get_msg(mse_mas, final, buf)

🟡 char *name returned separately in edgefast_bluetooth; edgefast_open encodes it in buf

set_msg_status

set_msg_status(mse_mas, buf, name, flags)

set_msg_status(mse_mas, final, buf)

🟡 char *name returned separately in edgefast_bluetooth; edgefast_open encodes it in buf

push_msg

push_msg(mse_mas, buf, name, flags)

push_msg(mse_mas, final, buf)

🟡 char *name returned separately in edgefast_bluetooth; edgefast_open encodes it in buf

set_ntf_reg

set_ntf_reg(mse_mas, buf, flags)

set_ntf_reg(mse_mas, final, buf)

🟡 Identical

update_inbox

update_inbox(mse_mas) — no buf

update_inbox(mse_mas, final, buf)

🟡 edgefast_open passes final + buf

get_mas_inst_info

get_mas_inst_info(mse_mas, buf, flags)

get_mas_inst_info(mse_mas, final, buf)

🟡 Identical

set_owner_status

set_owner_status(mse_mas, buf, flags)

set_owner_status(mse_mas, final, buf)

🟡 Identical

get_owner_status

get_owner_status(mse_mas, buf, flags)

get_owner_status(mse_mas, final, buf)

🟡 Identical

get_convo_listing

get_convo_listing(mse_mas, buf, flags)

get_convo_listing(mse_mas, final, buf)

🟡 Identical

set_ntf_filter

set_ntf_filter(mse_mas, buf, flags)

set_ntf_filter(mse_mas, final, buf)

🟡 Identical

8.4 MSE MNS Callbacks#

Callback

edgefast_bluetooth bt_map_mse_mns_cb

edgefast_open bt_map_mse_mns_cb

Notes

Transport connected

connected(mse_mns)

rfcomm_connected(conn, mse_mns) + l2cap_connected(conn, mse_mns)

🟡 edgefast_open exposes struct bt_conn *conn and splits by transport

Transport disconnected

disconnected(mse_mns, result)

rfcomm_disconnected(mse_mns) + l2cap_disconnected(mse_mns)

🟡 No result code in edgefast_open transport disconnect

OBEX connect response

— (implicit in connected)

connect(mse_mns, rsp_code, version, mopl, buf)

🟡 edgefast_open explicit OBEX connect response with OBEX version + MOPL

OBEX disconnect response

— (implicit in disconnected)

disconnect(mse_mns, rsp_code, buf)

🟡 edgefast_open explicit OBEX disconnect response

OBEX abort response

abort(mse_mns, rsp_code, buf)

🔴 edgefast_open only

send_event response

send_event(mse_mns, result) — only result code

send_event(mse_mns, rsp_code, buf)

🟡 edgefast_open adds buf for response headers

9. Full Function Comparison Table #

9.1 MCE MAS Functions#

edgefast_bluetooth

edgefast_open

Notes

bt_map_mce_mas_register(cb)

bt_map_mce_mas_cb_register(mce_mas, cb)

🟡 Global register replaced by per-instance cb_register

bt_map_mce_mas_unregister()

🟢

bt_map_mce_psm_connect(conn, psm, features, **mce_mas)

bt_map_mce_mas_l2cap_connect(conn, mce_mas, psm)

🟡 Stack allocates vs app allocates; no features param on transport connect

bt_map_mce_scn_connect(conn, scn, features, **mce_mas)

bt_map_mce_mas_rfcomm_connect(conn, mce_mas, channel)

🟡

bt_map_mce_mas_connect(mce_mas, buf)

🔴 Explicit OBEX CONNECT request

bt_map_mce_disconnect(mce_mas)

bt_map_mce_mas_disconnect(mce_mas, buf)

🟡 edgefast_open takes buf; also separate transport disconnects

bt_map_mce_mas_rfcomm_disconnect(mce_mas)

🔴

bt_map_mce_mas_l2cap_disconnect(mce_mas)

🔴

bt_map_mce_abort(mce_mas)

bt_map_mce_mas_abort(mce_mas, buf)

🟡 edgefast_open takes buf

bt_map_mce_get_max_pkt_len(mce_mas, *len)

🟢 MOPL delivered in OBEX connect callback

net_buf_alloc(pool) + net_buf_reserve(BT_MAP_MCE_RSV_LEN_*())

bt_map_mce_mas_create_pdu(mce_mas, pool)

🟡 PDU buffer helper

bt_map_mce_set_folder(mce_mas, name)

bt_map_mce_mas_set_folder(mce_mas, flags, buf)

🟡 Name string → OBEX Name header in buf; explicit flags enum

bt_map_mce_get_folder_listing(mce_mas, buf, wait, flags)

bt_map_mce_mas_get_folder_listing(mce_mas, final, buf)

🟡 flagsfinal; wait → OBEX SRMP header in buf

bt_map_mce_get_msg_listing(mce_mas, buf, name, wait, flags)

bt_map_mce_mas_get_msg_listing(mce_mas, final, buf)

🟡 name folded into buf; flagsfinal; wait → OBEX SRMP header in buf

bt_map_mce_get_msg(mce_mas, buf, name, wait, flags)

bt_map_mce_mas_get_msg(mce_mas, final, buf)

🟡

bt_map_mce_set_msg_status(mce_mas, buf, name, flags)

bt_map_mce_mas_set_msg_status(mce_mas, final, buf)

🟡

bt_map_mce_push_msg(mce_mas, buf, name, flags)

bt_map_mce_mas_push_msg(mce_mas, final, buf)

🟡

bt_map_mce_set_ntf_reg(mce_mas, buf)

bt_map_mce_mas_set_ntf_reg(mce_mas, final, buf)

🟡 final added

bt_map_mce_update_inbox(mce_mas)

bt_map_mce_mas_update_inbox(mce_mas, final, buf)

🟡 edgefast_open adds final + buf

bt_map_mce_get_mas_inst_info(mce_mas, buf, wait, flags)

bt_map_mce_mas_get_mas_inst_info(mce_mas, final, buf)

🟡

bt_map_mce_set_owner_status(mce_mas, buf, flags)

bt_map_mce_mas_set_owner_status(mce_mas, final, buf)

🟡

bt_map_mce_get_owner_status(mce_mas, buf, wait, flags)

bt_map_mce_mas_get_owner_status(mce_mas, final, buf)

🟡

bt_map_mce_get_convo_listing(mce_mas, buf, wait, flags)

bt_map_mce_mas_get_convo_listing(mce_mas, final, buf)

🟡

bt_map_mce_set_ntf_filter(mce_mas, buf)

bt_map_mce_mas_set_ntf_filter(mce_mas, final, buf)

🟡 final added

BT_MAP_ADD_* macros (~42)

bt_obex_add_header_app_param(buf, count, data)

🟡

BT_MAP_ADD_BODY(buf, val, len) macro

bt_obex_add_header_body(buf, len, body)

🟡

BT_MAP_ADD_END_OF_BODY(buf, val, len) macro

bt_obex_add_header_end_body(buf, len, body)

🟡

bt_map_mce_app_param_parse(buf, func, user_data) macro

bt_obex_tlv_parse(len, data, func, user_data)

🟡

bt_map_mce_get_body(buf, body, length) macro

bt_obex_get_header_body and bt_obex_get_header_end_body

🟡

9.2 MCE MNS Functions#

edgefast_bluetooth

edgefast_open

Notes

bt_map_mce_mns_register(cb)

bt_map_mce_mns_cb_register(mce_mns, cb) + bt_map_mce_mns_rfcomm_register(server) + bt_map_mce_mns_l2cap_register(server)

🟡 edgefast_open registers individual servers and per-instance callbacks; edgefast_bluetooth resgiter global callbacks and all servers

bt_map_mce_mns_unregister()

🟢

bt_map_mce_mns_disconnect(mce_mns)

bt_map_mce_mns_rfcomm_disconnect(mce_mns) + bt_map_mce_mns_l2cap_disconnect(mce_mns)

🟡 Split by transport

bt_map_mce_mns_connect(mce_mns, rsp_code, buf)

🔴 Explicit OBEX CONNECT response

bt_map_mce_mns_disconnect(mce_mns, rsp_code, buf)

🔴 Explicit OBEX DISCONNECT response

bt_map_mce_mns_abort(mce_mns, rsp_code, buf)

🔴 Abort response was internal in edgefast_bluetooth

bt_map_mce_send_event_response(mce_mns, result, wait)

bt_map_mce_mns_send_event(mce_mns, rsp_code, buf)

🟡 Renamed; buf added; wait → OBEX SRMP header in buf

bt_map_mce_mns_get_max_pkt_len(mce_mns, *len)

🟢 MOPL delivered in OBEX connect callback

net_buf_alloc(pool) + net_buf_reserve(BT_MAP_MCE_RSV_LEN_SEND_EVENT_RESP(mce_mns))

bt_map_mce_mns_create_pdu(mce_mns, pool)

🟡 PDU buffer helper

9.3 MSE MAS Functions#

edgefast_bluetooth

edgefast_open

Notes

bt_map_mse_mas_register(cb)

bt_map_mse_mas_cb_register(mse_mas, cb) + bt_map_mse_mas_rfcomm_register(server) + bt_map_mse_mas_l2cap_register(server)

🟡 edgefast_open registers individual servers and per-instance callbacks; edgefast_bluetooth resgiters global callbacks and all servers

bt_map_mse_mas_unregister()

🟢

bt_map_mse_disconnect(mse_mas)

bt_map_mse_mas_rfcomm_disconnect(mse_mas) + bt_map_mse_mas_l2cap_disconnect(mse_mas)

🟡 Split by transport

bt_map_mse_mas_connect(mse_mas, rsp_code, buf)

🔴 Explicit OBEX CONNECT response

bt_map_mse_mas_disconnect(mse_mas, rsp_code, buf)

🔴 Explicit OBEX DISCONNECT response

bt_map_mse_mas_abort(mse_mas, rsp_code, buf)

🔴 Abort response was internal in edgefast_bluetooth

bt_map_mse_get_max_pkt_len(mse_mas, *len)

🟢 MOPL delivered in OBEX connect callback

net_buf_alloc(pool) + net_buf_reserve(BT_MAP_MSE_RSV_LEN_SEND_RESP(mse_mas))

bt_map_mse_mas_create_pdu(mse_mas, pool)

🟡 PDU buffer helper

bt_map_mse_set_folder_response(mse_mas, result)

bt_map_mse_mas_set_folder(mse_mas, rsp_code, buf)

🟡 edgefast_open adds buf

bt_map_mse_get_folder_listing_response(mse_mas, result, buf, wait)

bt_map_mse_mas_get_folder_listing(mse_mas, rsp_code, buf)

🟡 wait → OBEX SRMP header in buf

bt_map_mse_get_msg_listing_response(mse_mas, result, buf, wait)

bt_map_mse_mas_get_msg_listing(mse_mas, rsp_code, buf)

🟡 wait → OBEX SRMP header in buf

bt_map_mse_get_msg_response(mse_mas, result, buf, wait)

bt_map_mse_mas_get_msg(mse_mas, rsp_code, buf)

🟡 wait → OBEX SRMP header in buf

bt_map_mse_set_msg_status_response(mse_mas, result)

bt_map_mse_mas_set_msg_status(mse_mas, rsp_code, buf)

🟡 edgefast_open adds buf

bt_map_mse_push_msg_response(mse_mas, result, name, wait)

bt_map_mse_mas_push_msg(mse_mas, rsp_code, buf)

🟡 name → OBEX Name header in buf; wait → OBEX SRMP header in buf

bt_map_mse_set_ntf_reg_response(mse_mas, result)

bt_map_mse_mas_set_ntf_reg(mse_mas, rsp_code, buf)

🟡 edgefast_open adds buf

bt_map_mse_update_inbox_response(mse_mas, result)

bt_map_mse_mas_update_inbox(mse_mas, rsp_code, buf)

🟡 edgefast_open adds buf

bt_map_mse_get_mas_inst_info_response(mse_mas, result, buf, wait)

bt_map_mse_mas_get_mas_inst_info(mse_mas, rsp_code, buf)

🟡 wait → OBEX SRMP header in buf

bt_map_mse_set_owner_status_response(mse_mas, result)

bt_map_mse_mas_set_owner_status(mse_mas, rsp_code, buf)

🟡 edgefast_open adds buf

bt_map_mse_get_owner_status_response(mse_mas, result, buf, wait)

bt_map_mse_mas_get_owner_status(mse_mas, rsp_code, buf)

🟡 wait → OBEX SRMP header in buf

bt_map_mse_get_convo_listing_response(mse_mas, result, buf, wait)

bt_map_mse_mas_get_convo_listing(mse_mas, rsp_code, buf)

🟡 wait → OBEX SRMP header in buf

bt_map_mse_set_ntf_filter_response(mse_mas, result)

bt_map_mse_mas_set_ntf_filter(mse_mas, rsp_code, buf)

🟡 edgefast_open adds buf

BT_MAP_ADD_* macros (~42)

bt_obex_add_header_app_param(buf, count, data)

🟡

BT_MAP_ADD_BODY(buf, val, len) macro

bt_obex_add_header_body(buf, len, body)

🟡

BT_MAP_ADD_END_OF_BODY(buf, val, len) macro

bt_obex_add_header_end_body(buf, len, body)

🟡

bt_map_mse_app_param_parse(buf, func, user_data) macro

bt_obex_tlv_parse(len, data, func, user_data)

🟡

bt_map_mse_get_body(buf, body, length) macro

bt_obex_get_header_body and bt_obex_get_header_end_body

🟡

9.4 MSE MNS Functions#

edgefast_bluetooth

edgefast_open

Notes

bt_map_mse_mns_register(cb)

bt_map_mse_mns_cb_register(mse_mns, cb)

🟡 Global register replaced by per-instance cb_register

bt_map_mse_mns_unregister()

🟢

bt_map_mse_mns_psm_connect(conn, psm, features, **mse_mns)

bt_map_mse_mns_l2cap_connect(conn, mse_mns, psm)

🟡 Stack allocates vs app allocates; features removed from transport step

bt_map_mse_mns_scn_connect(conn, scn, features, **mse_mns)

bt_map_mse_mns_rfcomm_connect(conn, mse_mns, channel)

🟡

bt_map_mse_mns_connect(mse_mns, buf)

🔴 Explicit OBEX CONNECT request

bt_map_mse_mns_disconnect(mse_mns)

bt_map_mse_mns_disconnect(mse_mns, buf)

🟡 edgefast_open OBEX disconnect takes buf; also separate transport disconnects

bt_map_mse_mns_rfcomm_disconnect(mse_mns)

🔴

bt_map_mse_mns_l2cap_disconnect(mse_mns)

🔴

bt_map_mse_mns_abort(mse_mns, buf)

🔴 Explicit OBEX ABORT

bt_map_mse_send_event(mse_mns, buf, flags)

bt_map_mse_mns_send_event(mse_mns, final, buf)

🟡 Renamed; flagsfinal

bt_map_mse_mns_get_max_pkt_len(mse_mns, *len)

🟢 MOPL delivered in OBEX connect callback

net_buf_alloc(pool) + net_buf_reserve(BT_MAP_MSE_RSV_LEN_SEND_EVENT(mse_mns, flags))

bt_map_mse_mns_create_pdu(mse_mns, pool)

🟡 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 *mce_mas / *mse_mas via callback

App-owned structs embedded in app context

Instance allocation

Stack allocates on incoming connection or psm/scn_connect call

App pre-allocates array; instance pointer passed at accept time or before transport connect

Callback registration

One register(cb) call covers all instances globally

Per-instance cb_register(instance, cb)

Transport layer

Transparent; single connected/disconnected callback

Explicit: rfcomm_connect / l2cap_connect (step 1) each produce their own transport callbacks

OBEX layer

Implicit within connected — stack performs OBEX CONNECT internally

Explicit: mas_connect(buf) / mns_connect(buf) (step 2); response in connect(rsp_code, version, mopl, buf) callback

OBEX DISCONNECT/ABORT

Handled internally by stack

App must explicitly call disconnect(buf) / abort(buf) in response to request callbacks

Server registration

Single register(cb) for all incoming connections

Typed server structs (rfcomm_server / l2cap_server) each with accept callback; registered individually

SRM management

Automatic: stack adds SRM header and manages SRM state

Manual: app adds bt_obex_add_header_srm and tracks state

SRMP (wait)

bool wait parameter on every multi-packet function

Manual: app adds bt_obex_add_header_srm_param() when needed

Fragmentation

enum bt_obex_req_flags (BT_OBEX_REQ_START / _END)

bool finaltrue = last packet, false = continuation

Max packet length

bt_map_mce_get_max_pkt_len() / bt_map_mse_get_max_pkt_len()

Delivered in OBEX connect callback as mopl

Buffer allocation

App pre-allocates with net_buf_reserve + BT_MAP_*_RSV_LEN_* macros

App calls bt_map_*_create_pdu(instance, pool) helper

Name / handle passing

Dedicated char *name parameter on most operations

Encoded as OBEX Name header inside buf via bt_obex_add_header_name()

App parameter helpers

BT_MAP_ADD_*() named macros per TLV tag

bt_obex_add_header_app_param(buf, count, tlvs[]) with struct bt_obex_tlv array

Body helpers

BT_MAP_ADD_BODY / BT_MAP_ADD_END_OF_BODY macros

bt_obex_add_header_body(buf, len, body) / bt_obex_add_header_end_body(buf, len, body) / bt_obex_add_header_body_or_end_body(buf, mopl, len, data, &written)

App param parsing

bt_map_mce_app_param_parse(buf, cb, user_data) macro

bt_obex_tlv_parse(len, data, cb, user_data) directly

SDP registration

Managed by stack

App calls bt_sdp_register_service() after server registration

Migration Checklist (edgefast_bluetooth → edgefast_open)#

  1. ☐ Replace single bt_map_mce_mas_register(cb) with per-instance bt_map_mce_mas_cb_register(mce_mas, cb) called before transport connect

  2. ☐ Split bt_map_mce_psm_connect() into bt_map_mce_mas_l2cap_connect() (transport) + bt_map_mce_mas_connect(buf) (OBEX)

  3. ☐ Add Target UUID and supported-features app param TLV to OBEX CONNECT buf

  4. ☐ Add Connection ID, SRM(if required), SRMP(if required) and Type headers to OBEX PUT/GET/SETPATH buf using bt_obex_add_header_*

  5. ☐ Store mopl from connect(rsp_code, version, mopl, buf) callback; replace get_max_pkt_len() with this value

  6. ☐ Replace BT_MAP_MCE_RSV_LEN_* + net_buf_reserve with bt_map_mce_mas_create_pdu(mce_mas, pool)

  7. ☐ Replace BT_MAP_ADD_* TLV macros with struct bt_obex_tlv[] + bt_obex_add_header_app_param()

  8. ☐ Replace BT_MAP_ADD_BODY / BT_MAP_ADD_END_OF_BODY macros with bt_obex_add_header_body / bt_obex_add_header_end_body / bt_obex_add_header_body_or_end_body

  9. ☐ Replace char *name parameters with bt_obex_add_header_name(buf, unicode_len, unicode_name) (name must be UTF-16BE encoded)

  10. ☐ Replace flags / wait parameters with bool final; manage SRM/SRMP headers manually

  11. ☐ 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) with accept callback

  12. ☐ Add explicit bt_map_mce_mns_connect(mce_mns, rsp_code, buf) in connect callback; add disconnect and abort response calls

  13. ☐ Replace bt_map_mce_send_event_response(mce_mns, result, wait) with bt_map_mce_mns_send_event(mce_mns, rsp_code, buf)

  14. ☐ On MSE side: replace bt_map_mse_mas_register(cb) with typed bt_map_mse_mas_rfcomm_register(server) / bt_map_mse_mas_l2cap_register(server) + accept callback

  15. ☐ Add explicit bt_map_mse_mas_connect(rsp_code, buf) / disconnect(rsp_code, buf) / abort(rsp_code, buf) response calls

  16. ☐ Rename all bt_map_mse_*_response(result, buf, wait)bt_map_mse_mas_*(rsp_code, buf) removing wait

  17. ☐ 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_DEFINE pools and bt_map_*_create_pdu() for buffer allocation. The conn_id is stored from the OBEX connect callback and inserted in every subsequent request. SRM/SRMP headers are managed manually by tracking a uint8_t srm bitmask.

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_MTU symbols.

12.1 Core Protocol Enablement#

Symbol

edgefast_bluetooth

edgefast_open

Notes

BT_GOEP

— (implicit)

bool, no default

edgefast_open exposes GOEP as a separate Kconfig knob; edgefast_bluetooth enables it implicitly

BT_GOEP_RFCOMM_MTU

— (hard-coded per role)

int, default 255

edgefast_open shared RFCOMM MTU for all GOEP profiles; replaces per-role MAX_PKT_LEN

BT_GOEP_L2CAP_MTU

— (hard-coded per role)

int, default 255

edgefast_open shared L2CAP MTU for all GOEP profiles

BT_MAP

bool, default 0

bool (no default; select BT_GOEP + EXPERIMENTAL)

Master MAP enable. Both stacks gate all MAP sub-features on this symbol

BT_MAP_MCE

bool, default 0

bool (no default; select BT_MAP)

Enables MCE (client) role

BT_MAP_MSE

bool, default 0

bool (no default; select BT_MAP)

Enables MSE (server) role

12.2 Instance and MTU Tunables#

edgefast_bluetooth symbol

edgefast_open equivalent

Type

Notes

BT_MAP_MCE_MAS_NUM_INSTANCES

int, default 2

edgefast_bluetooth limits the number of concurrent MCE MAS connections. edgefast_open manages this in app-level

BT_MAP_MCE_MNS_NUM_INSTANCES

int, default 1

edgefast_bluetooth MCE MNS instance limit. edgefast_open manages this in app-level

BT_MAP_MCE_MAS_MAX_PKT_LEN

BT_GOEP_RFCOMM_MTU / BT_GOEP_L2CAP_MTU

int, default 512 (EB) / 255 (EO)

edgefast_bluetooth per-connection MTU for MCE MAS. edgefast_open uses shared GOEP MTU

BT_MAP_MCE_MNS_MAX_PKT_LEN

BT_GOEP_RFCOMM_MTU / BT_GOEP_L2CAP_MTU

int, default 1790 (EB) / 255 (EO)

edgefast_bluetooth per-connection MTU for MCE MNS. edgefast_open uses shared GOEP MTU

BT_MAP_MSE_MAS_NUM_INSTANCES

int, default 2

edgefast_bluetooth MSE MAS instance limit. edgefast_open manages this in app-level

BT_MAP_MSE_MNS_NUM_INSTANCES

int, default 1

edgefast_bluetooth MSE MNS instance limit. edgefast_open manages this in app-level

BT_MAP_MSE_MAS_MAX_PKT_LEN

BT_GOEP_RFCOMM_MTU / BT_GOEP_L2CAP_MTU

int, default 1790 (EB) / 255 (EO)

edgefast_bluetooth per-connection MTU for MSE MAS. edgefast_open uses shared GOEP MTU

BT_MAP_MSE_MNS_MAX_PKT_LEN

BT_GOEP_RFCOMM_MTU / BT_GOEP_L2CAP_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

BT_MAP_MCE_MAS_SUPPORTED_FEATURES

hex, default 0x0077FFFF

edgefast_bluetooth bakes default supported features into Kconfig. edgefast_open defines this in app-level

BT_MAP_MSE_MNS_SUPPORTED_FEATURES

hex, default 0x0077FFFF

Same pattern for MSE role

12.4 Side-by-Side Symbol Summary#

Symbol

edgefast_bluetooth

edgefast_open

BT_GOEP

— (implicit)

bool

BT_GOEP_RFCOMM_MTU

int, default 255

BT_GOEP_L2CAP_MTU

int, default 255

BT_MAP

bool, default 0

bool

BT_MAP_MCE

bool, default 0

bool

BT_MAP_MSE

bool, default 0

bool

BT_MAP_MCE_MAS_NUM_INSTANCES

int, default 2

BT_MAP_MCE_MNS_NUM_INSTANCES

int, default 1

BT_MAP_MCE_MAS_MAX_PKT_LEN

int, default 512

BT_GOEP_RFCOMM_MTU / BT_GOEP_L2CAP_MTU

BT_MAP_MCE_MNS_MAX_PKT_LEN

int, default 1790

BT_GOEP_RFCOMM_MTU / BT_GOEP_L2CAP_MTU

BT_MAP_MCE_MAS_SUPPORTED_FEATURES

hex, default 0x0077FFFF

defined in app-level

BT_MAP_MSE_MAS_NUM_INSTANCES

int, default 2

BT_MAP_MSE_MNS_NUM_INSTANCES

int, default 1

BT_MAP_MSE_MAS_MAX_PKT_LEN

int, default 1790

BT_GOEP_RFCOMM_MTU / BT_GOEP_L2CAP_MTU

BT_MAP_MSE_MNS_MAX_PKT_LEN

int, default 512

BT_GOEP_RFCOMM_MTU / BT_GOEP_L2CAP_MTU

BT_MAP_MSE_MNS_SUPPORTED_FEATURES

hex, default 0x0077FFFF

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 net_buf *buf (+ a few flags/rsp_code); all headers are added by the application via obex_add_header_xxx()

Parameter-driven: function parameters directly carry name/wait/flag/auth/peer_feature

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 obex_add_header_xxx() calls.

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 enum bt_obex_req_flags + CONTINUE/SUCCESS responses

Requires redesign of “first packet / subsequent packet / last packet” strategy.

SRMP (“wait”)

Not a parameter anymore; application adds SRMP header

bool wait parameter controls SRMP

wait → SRMP header.

Name/path

Not a function parameter; carried in the OBEX Name header inside buf

char *name passed as parameter or provided by callback

name → header + parsing.

Authentication

New provides nonce/digest/verify helpers; auth headers are added by the application

Old callback includes get_auth_info() providing struct bt_pbap_auth

Auth shifts from “configuration/struct callback” to “parse challenge + compute + add headers”.


2. PCE (Client) API Alignment Differences (Function Level)#

Function

EdgeFast Open API (pbap.h)

EdgeFast Bluetooth PAL API (pbap_pce.h)

Key differences (incl. migration notes)

Callback registration / init

(No equivalent global register found)

bt_pbap_pce_register(struct bt_pbap_pce_cb *cb)

Old: global callback registration; New: more instance-oriented, cb is passed during connect.

RFCOMM connect (SCN/channel)

bt_pbap_pce_rfcomm_connect(conn, pce, cb, channel)

bt_pbap_pce_scn_connect(conn, channel, auth, peer_feature, &pce)

Old creates/returns the PCE object and takes auth/peer_feature; New requires caller-owned pce and does not express auth/features via connect parameters.

L2CAP connect (PSM)

bt_pbap_pce_l2cap_connect(conn, pce, cb, psm)

bt_pbap_pce_psm_connect(conn, psm, auth, peer_feature, &pce)

Same pattern as RFCOMM connect.

Disconnect (high-level)

bt_pbap_pce_disconnect(pce, buf)

bt_pbap_pce_disconnect(pce)

New requires application-provided buf and application-built OBEX Disconnect headers.

Disconnect (transport bearer)

bt_pbap_pce_rfcomm_disconnect(pce) / bt_pbap_pce_l2cap_disconnect(pce)

(No dedicated API)

New separates bearer teardown from OBEX DISCONNECT PDU.

OBEX CONNECT (PBAP session)

bt_pbap_pce_connect(pce, mopl, buf)

(Typically implicit in old connect flow)

Application must construct the OBEX CONNECT PDU and headers via obex_add_header_xxx().

ABORT

bt_pbap_pce_abort(pce, buf)

bt_pbap_pce_abort(pce)

Application constructs ABORT PDU headers.

Pull Phonebook

bt_pbap_pce_pull_phone_book(pce, buf)

bt_pbap_pce_pull_phonebook(pce, buf, name, wait, flag)

flag removed; name/wait moved into headers. Application adds Name/Type/AppParams/SRMP and segmentation-related headers/flags. Function name also changes (phonebookphone_book).

SetPath

bt_pbap_pce_set_phone_book(pce, flags, buf)

bt_pbap_pce_set_phonebook_path(pce, buf, name)

Old passes name; New uses flags + buf. Folder name must be carried in the OBEX Name header (application-built).

Pull vCard Listing

bt_pbap_pce_pull_vcard_listing(pce, buf)

bt_pbap_pce_pull_vcard_listing(pce, buf, name, wait, flag)

Same as Pull Phonebook: parameters → headers.

Pull vCard Entry

bt_pbap_pce_pull_vcard_entry(pce, buf)

bt_pbap_pce_pull_vcard_entry(pce, buf, name, wait, flag)

Same as above.

Get max packet length

(No same-name API found)

bt_pbap_pce_get_max_pkt_len(pce, &len)

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 pbap.h; likely use OBEX layer)

bt_pbap_pce_app_param_parse(...) (macro to OBEX parser)

New encourages direct OBEX/AppParams header manipulation/parsing by the application.

Helper: get Body

(No same-name macro in pbap.h; likely use OBEX layer)

bt_pbap_pce_get_body(...) (macro to OBEX helper)

New callbacks deliver buf; application should parse OBEX Body/End-of-Body headers.


3. PSE (Server) API Alignment Differences (Function Level)#

Function

EdgeFast Open API (pbap.h)

EdgeFast Bluetooth PAL API (pbap_pse.h)

Key differences (incl. migration notes)

Callback registration / init

bt_pbap_pse_register(struct bt_pbap_pse *pse, struct bt_pbap_pse_cb *cb)

bt_pbap_pse_register(struct bt_pbap_pse_cb *cb)

New requires a PSE instance, i.e., a more instance-based server model.

Server bearer registration

bt_pbap_pse_rfcomm_register(server) / bt_pbap_pse_l2cap_register(server)

(Not provided in old header)

New adds explicit RFCOMM/L2CAP server registration and accept model.

Disconnect

bt_pbap_pse_disconnect_rsp(pse, rsp_code, buf)

bt_pbap_pse_disconnect(pse)

New is response/PDU oriented; application builds the response PDU and headers.

CONNECT/ABORT response

bt_pbap_pse_connect_rsp(pse, mopl, rsp_code, buf) / bt_pbap_pse_abort_rsp(pse, rsp_code, buf)

(More abstracted in old version)

New requires explicit response PDU construction and transmission.

Pull phonebook response

bt_pbap_pse_pull_phone_book_rsp(pse, rsp_code, buf)

bt_pbap_pse_pull_phonebook_response(pse, result, buf, wait)

wait moves to SRMP header; resultrsp_code; buffer payload/headers fully application-built.

SetPath response

bt_pbap_pse_set_phone_book_rsp(pse, rsp_code, buf)

bt_pbap_pse_set_phonebook_path_response(pse, result)

New requires a response buf even for SetPath.

Pull vCard listing response

..._rsp(pse, rsp_code, buf)

..._response(pse, result, buf, wait)

wait removed; application adds SRMP and body/end-body.

Pull vCard entry response

..._rsp(pse, rsp_code, buf)

..._response(pse, result, buf, wait)

Same as above.

Get max packet length

(No same-name API found)

bt_pbap_pse_get_max_pkt_len(pse, &len)

New may rely on OBEX/GOEP layer APIs.

Get peer supported features

(No same-name API found)

bt_pbap_pse_get_peer_supported_features(pse, &feat)

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 bt_pbap_pce_cb

EdgeFast Bluetooth PAL bt_pbap_pce_cb

Migration impact

Bearer connected

rfcomm_connected(conn,pce) / l2cap_connected(conn,pce)

connected(pce)

New distinguishes bearer type and provides bt_conn*.

Bearer disconnected

rfcomm_disconnected(pce) / l2cap_disconnected(pce)

disconnected(pce, result)

The disconnect reason/result is more reflected in protocol rsp_code paths.

OBEX CONNECT result

connect(pce, rsp_code, version, mopl, buf)

(Not typically exposed explicitly)

New exposes negotiated parameters and delivers the raw buffer.

pull/set/abort callbacks

uniformly rsp_code + buf

result + buf (some callbacks without buf)

Application must parse OBEX headers/body from buf.

Auth info retrieval

(Not present)

get_auth_info(pce, auth)

New expects application-driven OBEX auth header handling (parse challenge, compute, add response).

5.2 PSE callbacks#

Aspect

EdgeFast Open bt_pbap_pse_cb

EdgeFast Bluetooth PAL bt_pbap_pse_cb

Migration impact

Pull request callback params

(..., buf)

(..., buf, name, flag)

New requires parsing Name/Type/AppParams/SRMP/segmentation from buf.

SetPath request

set_phone_book(pse, flags, buf)

set_phonebook_path(pse, name)

Flags are standardized; folder name is parsed from Name header in buf.

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)

name

Not a function parameter anymore

API parameter char *name or callback provides name

Add/parse OBEX Name header in request/response PDUs.

Type

BT_PBAP_PULL_*_TYPE macros exist

Often internal in old stack

Add OBEX Type header (x-bt/phonebook, x-bt/vcard-listing, x-bt/vcard).

App Parameters (filter/format/order/search, etc.)

enums in pbap.h (order/format/property_mask, etc.)

via BT_PBAP_ADD_xxx or internal

Encode/decode PBAP AppParams TLVs inside the OBEX App Parameters header.

wait (SRMP)

Not present as parameter

bool wait parameter

Add/parse SRMP header to control Server Response Mode Parameter.

flag (START/CONTINUE)

Not present as parameter

enum bt_obex_req_flags flag

Express segmentation via PDU construction (Final-bit, Body vs End-of-Body, multi-PDU flow).

result vs rsp_code

unified rsp_code

SUCCESS/CONTINUE-style results

Choose OBEX response code based on whether more PDUs follow; build Body/End-of-Body accordingly.

auth

nonce/digest/verify helpers

connect parameter or get_auth_info callback

Build OBEX auth headers in PDUs; compute/verify using provided helpers.

peer_feature

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

bt_pbap_pce_create_pdu(pce, pool) / bt_pbap_pse_create_pdu(pse, pool)

Provides a PDU container to be populated by the application via obex_add_header_xxx().

PSE bearer server registration

bt_pbap_pse_rfcomm_register(server) / bt_pbap_pse_l2cap_register(server) + accept()

More complete server integration model (multi-connection / custom accept).

OBEX-level response APIs (PSE)

connect_rsp/disconnect_rsp/abort_rsp

Application can explicitly control OBEX response codes and attached headers.

Authentication utilities

bt_pbap_calculate_nonce / bt_pbap_calculate_rsp_digest / bt_pbap_verify_authentication

Facilitates application-implemented OBEX/PBAP authentication headers and validation.


8. Migration Recommendations (High-level)#

  1. Refactor connection sequencing (PCE):

    • Establish bearer first: bt_pbap_pce_rfcomm_connect or bt_pbap_pce_l2cap_connect

    • Then build the OBEX CONNECT PDU (application uses obex_add_header_xxx()) and call bt_pbap_pce_connect

  2. 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_*()

  3. Change response sending (PSE) to “application fully owns headers/body/end-of-body”:

    • Request callbacks deliver only buf; parse Name/Type/AppParams

    • Build response buf: add Body/End-of-Body and required headers via obex_add_header_xxx() → call bt_pbap_pse_*_rsp()

  4. Segmentation/CONTINUE strategy migration:

    • Old: flag + wait + result

    • New: application decides whether to include End-of-Body, whether more PDUs follow, and selects rsp_code (CONTINUE/SUCCESS)

  5. Authentication migration:

    • Old: get_auth_info + struct bt_pbap_auth

    • New: application parses OBEX auth challenge headers, computes digests via bt_pbap_calculate_*, and adds auth response/challenge headers via obex_add_header_xxx()

Parent topic:Compare with EdgeFast Bluetooth PAL

Parent topic:Overview