Re: Digest for btstack-dev@googlegroups.com - 7 updates in 2 topics

6 views
Skip to first unread message

Dawid Bańkowski

unread,
Apr 7, 2024, 7:10:27 AMApr 7
to btsta...@googlegroups.com
I found an error(s):
1) BT devices pairing issue. IESP-IDF created project have some lacks of configuration in sdkconfig file.
If example there is pointed that given bellow values on menuconfig should be configured:
Bluetooth disabled - please set CONFIG_BT_ENABLED via menuconfig -> Component Config -> Bluetooth -> [x] Bluetooth
CONFIG_BT_CONTROLLER_ONLY via menuconfig -> Component Config -> Bluetooth -> Host -> Disabled"
CONFIG_BT_CONTROLLER_ENABLED via menuconfig -> Component Config -> Bluetooth -> Controller -> Enabled"

but for good pairing there is something else. Just to check if I am right I have quickly copied to my project   sdkconfig from brstack example. Compiled example and it started to pair.

To Your knowledge in attachment I send example  sdkconfig and generated by ESP-IDF so You can compare it later I will do it by myself

2) ESP and C++ issue:
a) I have changed *,.c extension to *.cpp and compiler started to link function but
b) type casting of variables started to appear. 2 lines were corrected like bellow
      avrcp_notification2str((avrcp_notification_event_id_t)event_id));
     operation_id = (avrcp_operation_id_t) avrcp_subevent_operation_get_operation_id(packet) ;

and it started to compile. Of course there were problems with pairing which was corrected with steps written in point "1".


--- 
Pozdrowienia / Best regards
Dawid Bańkowski

“In the middle of difficulty lies opportunity.”  A. Einstein

View Dawid Bankowski's profile on LinkedIn


niedz., 7 kwi 2024 o 11:57 <btsta...@googlegroups.com> napisał(a):
mikew <weig...@foxmail.com>: Apr 07 01:32AM -0700

Hi,
 
I want to check if current code supports to free hci connection memory
automatically when disconnecting by BTstack.
 
I use "a2dp_source_disconnect" and "hid_host_disconnect" to test and find
the memory can not be freed autoly, which will possibly cause memory leak.
On the other hand, disconnecting by device will trigger hci connection
memory free in BTstack.
 
Is there hasn't been considered before, or is the code designed that way?
 
Best wishes,
Mike
mikew <weig...@foxmail.com>: Apr 07 01:36AM -0700

The function to trigger is "hci_shutdown_connection" in hid (br/edr), and
there is more in audio device.
 
在2024年4月7日星期日 UTC+8 16:32:10<mikew> 写道:
 
"Dawid Bańkowski" <d.ban...@gmail.com>: Apr 06 04:22AM -0700

My bt_A2DPSink.h code is:
#pragma once
 
#include "btstack_port_esp32.h"
#include "btstack_run_loop.h"
#include "btstack_stdio_esp32.h"
#include "hci_dump.h"
#include "hci_dump_embedded_stdout.h"
 
#include <stddef.h>
 
// warn about unsuitable sdkconfig
#include "sdkconfig.h"
#if !CONFIG_BT_ENABLED
#error "Bluetooth disabled - please set CONFIG_BT_ENABLED via menuconfig ->
Component Config -> Bluetooth -> [x] Bluetooth"
#endif
#if !CONFIG_BT_CONTROLLER_ONLY
#error "Different Bluetooth Host stack selected - please set
CONFIG_BT_CONTROLLER_ONLY via menuconfig -> Component Config -> Bluetooth
-> Host -> Disabled"
#endif
#if ESP_IDF_VERSION_MAJOR >= 5
#if !CONFIG_BT_CONTROLLER_ENABLED
#error "Different Bluetooth Host stack selected - please set
CONFIG_BT_CONTROLLER_ENABLED via menuconfig -> Component Config ->
Bluetooth -> Controller -> Enabled"
#endif
#endif
 
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
 
#include "btstack.h"
 
#include "btstack_resample.h"
 
int setup_demo(void);
 
 
 
 
 
typedef struct {
uint8_t a2dp_local_seid;
uint8_t media_sbc_codec_configuration[4];
} a2dp_sink_demo_stream_endpoint_t;
 
typedef enum {
STREAM_STATE_CLOSED,
STREAM_STATE_OPEN,
STREAM_STATE_PLAYING,
STREAM_STATE_PAUSED,
} stream_state_t;
 
typedef struct {
uint8_t reconfigure;
uint8_t num_channels;
uint16_t sampling_frequency;
uint8_t block_length;
uint8_t subbands;
uint8_t min_bitpool_value;
uint8_t max_bitpool_value;
btstack_sbc_channel_mode_t channel_mode;
btstack_sbc_allocation_method_t allocation_method;
} media_codec_configuration_sbc_t;
 
typedef struct {
bd_addr_t addr;
uint16_t a2dp_cid;
uint8_t a2dp_local_seid;
stream_state_t stream_state;
media_codec_configuration_sbc_t sbc_configuration;
} a2dp_sink_demo_a2dp_connection_t;
 
 
 
piątek, 5 kwietnia 2024 o 18:25:51 UTC+2 Matthias Ringwald napisał(a):
 
"Dawid Bańkowski" <d.ban...@gmail.com>: Apr 05 10:06AM -0700

I have considered "slowly add your application to the provided example" but
it is in C and my app is written in C++, :/
 
piątek, 5 kwietnia 2024 o 18:25:51 UTC+2 Matthias Ringwald napisał(a):
 
"Dawid Bańkowski" <d.ban...@gmail.com>: Apr 06 04:24AM -0700

And bt_A2DPSink.c code:
#include "bt_A2DPSink.h"
 
static void a2dp_sink_packet_handler(uint8_t packet_type, uint16_t channel,
uint8_t *packet, uint16_t size);
static void handle_l2cap_media_data_packet(uint8_t seid, uint8_t *packet,
uint16_t size);
static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel,
uint8_t *packet, uint16_t size);
static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t
channel, uint8_t *packet, uint16_t size);
static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t
channel, uint8_t *packet, uint16_t size);
static void hci_packet_handler(uint8_t packet_type, uint16_t channel,
uint8_t *packet, uint16_t size);
static void dump_sbc_configuration(media_codec_configuration_sbc_t *
configuration);
static void media_processing_close(void);
static int media_processing_init(media_codec_configuration_sbc_t *
configuration);
 
 
static a2dp_sink_demo_stream_endpoint_t a2dp_sink_demo_stream_endpoint;
static btstack_packet_callback_registration_t
hci_event_callback_registration;
static a2dp_sink_demo_a2dp_connection_t a2dp_sink_demo_a2dp_connection;
 
static uint8_t sdp_avdtp_sink_service_buffer[150];
static uint8_t sdp_avrcp_target_service_buffer[150];
static uint8_t sdp_avrcp_controller_service_buffer[200];
static uint8_t device_id_sdp_service_buffer[100];
 
static uint8_t media_sbc_codec_capabilities[] = {
0xFF,
//(AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO,
0xFF,
//(AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) |
AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS,
2,
53
};
 
static int volume_percentage = 0;
 
 
 
 
 
 
 
int setup_demo(void) {
 
// init protocols
l2cap_init();
sdp_init();
#ifdef ENABLE_BLE
// Initialize LE Security Manager. Needed for cross-transport key derivation
sm_init();
#endif
#ifdef ENABLE_AVRCP_COVER_ART
goep_client_init();
avrcp_cover_art_client_init();
#endif
 
// Init profiles
a2dp_sink_init();
avrcp_init();
avrcp_controller_init();
avrcp_target_init();
 
 
// Configure A2DP Sink
a2dp_sink_register_packet_handler(&a2dp_sink_packet_handler);
a2dp_sink_register_media_handler(&handle_l2cap_media_data_packet);
a2dp_sink_demo_stream_endpoint_t * stream_endpoint =
&a2dp_sink_demo_stream_endpoint;
avdtp_stream_endpoint_t * local_stream_endpoint =
a2dp_sink_create_stream_endpoint(AVDTP_AUDIO,
AVDTP_CODEC_SBC,
media_sbc_codec_capabilities,
sizeof(media_sbc_codec_capabilities),
stream_endpoint->media_sbc_codec_configuration,
sizeof(stream_endpoint->media_sbc_codec_configuration));
btstack_assert(local_stream_endpoint != NULL);
// - Store stream enpoint's SEP ID, as it is used by A2DP API to identify
the stream endpoint
stream_endpoint->a2dp_local_seid = avdtp_local_seid(local_stream_endpoint);
 
 
// Configure AVRCP Controller + Target
avrcp_register_packet_handler(&avrcp_packet_handler);
avrcp_controller_register_packet_handler(&avrcp_controller_packet_handler);
avrcp_target_register_packet_handler(&avrcp_target_packet_handler);

 
// Configure SDP
 
// - Create and register A2DP Sink service record
memset(sdp_avdtp_sink_service_buffer, 0,
sizeof(sdp_avdtp_sink_service_buffer));
a2dp_sink_create_sdp_record(sdp_avdtp_sink_service_buffer,
sdp_create_service_record_handle(),
AVDTP_SINK_FEATURE_MASK_HEADPHONE,
NULL,
NULL);
btstack_assert(de_get_len(sdp_avdtp_sink_service_buffer) <=
sizeof(sdp_avdtp_sink_service_buffer));
sdp_register_service(sdp_avdtp_sink_service_buffer);
 
// - Create AVRCP Controller service record and register it with SDP. We
send Category 1 commands to the media player, e.g. play/pause
memset(sdp_avrcp_controller_service_buffer, 0,
sizeof(sdp_avrcp_controller_service_buffer));
uint16_t controller_supported_features = 1 <<
AVRCP_CONTROLLER_SUPPORTED_FEATURE_CATEGORY_PLAYER_OR_RECORDER;
#ifdef AVRCP_BROWSING_ENABLED
controller_supported_features |= 1 <<
AVRCP_CONTROLLER_SUPPORTED_FEATURE_BROWSING;
#endif
#ifdef ENABLE_AVRCP_COVER_ART
controller_supported_features |= 1 <<
AVRCP_CONTROLLER_SUPPORTED_FEATURE_COVER_ART_GET_LINKED_THUMBNAIL;
#endif
avrcp_controller_create_sdp_record(sdp_avrcp_controller_service_buffer,
sdp_create_service_record_handle(),
controller_supported_features,
NULL,
NULL);
btstack_assert(de_get_len(sdp_avrcp_controller_service_buffer) <=
sizeof(sdp_avrcp_controller_service_buffer));
sdp_register_service(sdp_avrcp_controller_service_buffer);
 
// - Create and register A2DP Sink service record
// - We receive Category 2 commands from the media player, e.g. volume
up/down
memset(sdp_avrcp_target_service_buffer, 0,
sizeof(sdp_avrcp_target_service_buffer));
uint16_t target_supported_features = 1 <<
AVRCP_TARGET_SUPPORTED_FEATURE_CATEGORY_MONITOR_OR_AMPLIFIER;
avrcp_target_create_sdp_record(sdp_avrcp_target_service_buffer,
sdp_create_service_record_handle(),
target_supported_features,
NULL,
NULL);
btstack_assert(de_get_len(sdp_avrcp_target_service_buffer) <=
sizeof(sdp_avrcp_target_service_buffer));
sdp_register_service(sdp_avrcp_target_service_buffer);
 
// - Create and register Device ID (PnP) service record
memset(device_id_sdp_service_buffer, 0,
sizeof(device_id_sdp_service_buffer));
device_id_create_sdp_record(device_id_sdp_service_buffer,
sdp_create_service_record_handle(),
DEVICE_ID_VENDOR_ID_SOURCE_BLUETOOTH,
BLUETOOTH_COMPANY_ID_BLUEKITCHEN_GMBH,
1,
1);
btstack_assert(de_get_len(device_id_sdp_service_buffer) <=
sizeof(device_id_sdp_service_buffer));
sdp_register_service(device_id_sdp_service_buffer);
 
 
// Configure GAP - discovery / connection
 
// - Set local name with a template Bluetooth address, that will be
automatically
// replaced with an actual address once it is available, i.e. when
BTstack boots
// up and starts talking to a Bluetooth module.
gap_set_local_name("A2DP Sink Demo 00:00:00:00:00:00");
 
// - Allow to show up in Bluetooth inquiry
gap_discoverable_control(1);
 
// - Set Class of Device - Service Class: Audio, Major Device Class: Audio,
Minor: Loudspeaker
gap_set_class_of_device(0x200414);
 
// - Allow for role switch in general and sniff mode
gap_set_default_link_policy_settings(LM_LINK_POLICY_ENABLE_ROLE_SWITCH |
LM_LINK_POLICY_ENABLE_SNIFF_MODE);
 
// - Allow for role switch on outgoing connections
// - This allows A2DP Source, e.g. smartphone, to become master when we
re-connect to it.
gap_set_allow_role_switch(true);
 
 
// Register for HCI events
hci_event_callback_registration.callback = &hci_packet_handler;
hci_add_event_handler(&hci_event_callback_registration);
 
// Inform about audio playback / test options
#ifdef HAVE_POSIX_FILE_IO
if (!btstack_audio_sink_get_instance()) {
printf("No audio playback.\n");
}
else {
printf("Audio playback supported.\n");
}
#ifdef STORE_TO_WAV_FILE
printf("Audio will be stored to \'%s\' file.\n", wav_filename);
#endif
#endif
return 0;
}
/* LISTING_END */
 
static void a2dp_sink_packet_handler(uint8_t packet_type, uint16_t channel,
uint8_t *packet, uint16_t size) {
UNUSED(channel);
UNUSED(size);
uint8_t status;
 
uint8_t allocation_method;
 
if (packet_type != HCI_EVENT_PACKET) return;
if (hci_event_packet_get_type(packet) != HCI_EVENT_A2DP_META) return;
 
a2dp_sink_demo_a2dp_connection_t * a2dp_conn =
&a2dp_sink_demo_a2dp_connection;
 
switch (packet[2]) {
case A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION:
printf("A2DP Sink : Received non SBC codec - not implemented\n");
break;
case A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION: {
printf("A2DP Sink : Received SBC codec configuration\n");
a2dp_conn->sbc_configuration.reconfigure =
a2dp_subevent_signaling_media_codec_sbc_configuration_get_reconfigure(packet);
a2dp_conn->sbc_configuration.num_channels =
a2dp_subevent_signaling_media_codec_sbc_configuration_get_num_channels(packet);
a2dp_conn->sbc_configuration.sampling_frequency =
a2dp_subevent_signaling_media_codec_sbc_configuration_get_sampling_frequency(packet);
a2dp_conn->sbc_configuration.block_length =
a2dp_subevent_signaling_media_codec_sbc_configuration_get_block_length(packet);
a2dp_conn->sbc_configuration.subbands =
a2dp_subevent_signaling_media_codec_sbc_configuration_get_subbands(packet);
a2dp_conn->sbc_configuration.min_bitpool_value =
a2dp_subevent_signaling_media_codec_sbc_configuration_get_min_bitpool_value(packet);
a2dp_conn->sbc_configuration.max_bitpool_value =
a2dp_subevent_signaling_media_codec_sbc_configuration_get_max_bitpool_value(packet);

allocation_method =
a2dp_subevent_signaling_media_codec_sbc_configuration_get_allocation_method(packet);

// Adapt Bluetooth spec definition to SBC Encoder expected input
a2dp_conn->sbc_configuration.allocation_method =
(btstack_sbc_allocation_method_t)(allocation_method - 1);

switch
(a2dp_subevent_signaling_media_codec_sbc_configuration_get_channel_mode(packet))
{
case AVDTP_CHANNEL_MODE_JOINT_STEREO:
a2dp_conn->sbc_configuration.channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO;
break;
case AVDTP_CHANNEL_MODE_STEREO:
a2dp_conn->sbc_configuration.channel_mode = SBC_CHANNEL_MODE_STEREO;
break;
case AVDTP_CHANNEL_MODE_DUAL_CHANNEL:
a2dp_conn->sbc_configuration.channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL;
break;
case AVDTP_CHANNEL_MODE_MONO:
a2dp_conn->sbc_configuration.channel_mode = SBC_CHANNEL_MODE_MONO;
break;
default:
btstack_assert(false);
break;
}
dump_sbc_configuration(&a2dp_conn->sbc_configuration);
break;
}
 
case A2DP_SUBEVENT_STREAM_ESTABLISHED:
status = a2dp_subevent_stream_established_get_status(packet);
if (status != ERROR_CODE_SUCCESS) {
printf("A2DP Sink : Streaming connection failed, status 0x%02x\n",
status);
break;
}
 
a2dp_subevent_stream_established_get_bd_addr(packet, a2dp_conn->addr);
a2dp_conn->a2dp_cid = a2dp_subevent_stream_established_get_a2dp_cid(packet);
a2dp_conn->a2dp_local_seid =
a2dp_subevent_stream_established_get_local_seid(packet);
a2dp_conn->stream_state = STREAM_STATE_OPEN;
 
printf("A2DP Sink : Streaming connection is established, address %s,
cid 0x%02x, local seid %d\n",
bd_addr_to_str(a2dp_conn->addr),
a2dp_conn->a2dp_cid,
a2dp_conn->a2dp_local_seid);
#ifdef HAVE_BTSTACK_STDIN
// use address for outgoing connections
memcpy(device_addr, a2dp_conn->addr, 6);
#endif
break;

#ifdef ENABLE_AVDTP_ACCEPTOR_EXPLICIT_START_STREAM_CONFIRMATION
case A2DP_SUBEVENT_START_STREAM_REQUESTED:
printf("A2DP Sink : Explicit Accept to start stream, local_seid
%d\n", a2dp_subevent_start_stream_requested_get_local_seid(packet));
a2dp_sink_start_stream_accept(a2dp_cid, a2dp_local_seid);
break;
#endif
case A2DP_SUBEVENT_STREAM_STARTED:
printf("A2DP Sink : Stream started\n");
a2dp_conn->stream_state = STREAM_STATE_PLAYING;
if (a2dp_conn->sbc_configuration.reconfigure) {
media_processing_close();
}
// prepare media processing
media_processing_init(&a2dp_conn->sbc_configuration);
// audio stream is started when buffer reaches minimal level
break;

case A2DP_SUBEVENT_STREAM_SUSPENDED:
printf("A2DP Sink : Stream paused\n");
a2dp_conn->stream_state = STREAM_STATE_PAUSED;
media_processing_pause();
break;

case A2DP_SUBEVENT_STREAM_RELEASED:
printf("A2DP Sink : Stream released\n");
a2dp_conn->stream_state = STREAM_STATE_CLOSED;
media_processing_close();
break;

case A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED:
printf("A2DP Sink : Signaling connection released\n");
a2dp_conn->a2dp_cid = 0;
media_processing_close();
break;

default:
break;
}
}
 
 
static void handle_l2cap_media_data_packet(uint8_t seid, uint8_t *packet,
uint16_t size) {
UNUSED(seid);
int pos = 0;

avdtp_media_packet_header_t media_header;
if (!read_media_data_header(packet, size, &pos, &media_header)) return;

avdtp_sbc_codec_header_t sbc_header;
if (!read_sbc_header(packet, size, &pos, &sbc_header)) return;
 
int packet_length = size - pos;
uint8_t *packet_begin = packet + pos;
 
const btstack_audio_sink_t * audio = btstack_audio_sink_get_instance();
// process data right away if there's no audio implementation active, e.g.
on posix systems to store as .wav
if (!audio) {
sbc_decoder_instance->decode_signed_16(&sbc_decoder_context, 0,
packet_begin, packet_length);
return;
}
 
// store sbc frame size for buffer management
sbc_frame_size = packet_length / sbc_header.num_frames;
int status = btstack_ring_buffer_write(&sbc_frame_ring_buffer,
packet_begin, packet_length);
if (status != ERROR_CODE_SUCCESS) {
printf("Error storing samples in SBC ring buffer!!!\n");
}
 
// decide on audio sync drift based on number of sbc frames in queue
int sbc_frames_in_buffer =
btstack_ring_buffer_bytes_available(&sbc_frame_ring_buffer) /
sbc_frame_size;
#ifdef HAVE_BTSTACK_AUDIO_EFFECTIVE_SAMPLERATE
if (!l2cap_stream_started && audio_stream_started) {
l2cap_stream_started = 1;
btstack_sample_rate_compensation_init(&sample_rate_compensation,
btstack_run_loop_get_time_ms(),
a2dp_sink_demo_a2dp_connection.sbc_configuration.sampling_frequency,
FLOAT_TO_Q15(1.f));
}
// update sample rate compensation
if (audio_stream_started && (audio != NULL)) {
uint32_t resampling_factor =
btstack_sample_rate_compensation_update(&sample_rate_compensation,
btstack_run_loop_get_time_ms(), sbc_header.num_frames * 128,
audio->get_samplerate());
btstack_resample_set_factor(&resample_instance, resampling_factor);
// printf("sbc buffer level : %"PRIu32"\n",
btstack_ring_buffer_bytes_available(&sbc_frame_ring_buffer));
}
#else
uint32_t resampling_factor;
 
// nominal factor (fixed-point 2^16) and compensation offset
uint32_t nominal_factor = 0x10000;
uint32_t compensation = 0x00100;
 
if (sbc_frames_in_buffer < OPTIMAL_FRAMES_MIN) {
resampling_factor = nominal_factor - compensation; // stretch samples
}
else if (sbc_frames_in_buffer <= OPTIMAL_FRAMES_MAX) {
resampling_factor = nominal_factor; // nothing to do
}
else {
resampling_factor = nominal_factor + compensation; // compress samples
}
 
btstack_resample_set_factor(&resample_instance, resampling_factor);
#endif
// start stream if enough frames buffered
if (!audio_stream_started && sbc_frames_in_buffer >= OPTIMAL_FRAMES_MIN) {
media_processing_start();
}
}
 
 
 
static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel,
uint8_t *packet, uint16_t size) {
UNUSED(channel);
UNUSED(size);
uint16_t local_cid;
uint8_t status;
bd_addr_t address;
 
a2dp_sink_demo_avrcp_connection_t * connection =
&a2dp_sink_demo_avrcp_connection;
 
if (packet_type != HCI_EVENT_PACKET) return;
if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return;
switch (packet[2]) {
case AVRCP_SUBEVENT_CONNECTION_ESTABLISHED: {
local_cid = avrcp_subevent_connection_established_get_avrcp_cid(packet);
status = avrcp_subevent_connection_established_get_status(packet);
if (status != ERROR_CODE_SUCCESS) {
printf("AVRCP: Connection failed, status 0x%02x\n", status);
connection->avrcp_cid = 0;
return;
}
 
connection->avrcp_cid = local_cid;
avrcp_subevent_connection_established_get_bd_addr(packet, address);
printf("AVRCP: Connected to %s, cid 0x%02x\n", bd_addr_to_str(address),
connection->avrcp_cid);
 
#ifdef HAVE_BTSTACK_STDIN
// use address for outgoing connections
avrcp_subevent_connection_established_get_bd_addr(packet, device_addr);
#endif
 
avrcp_target_support_event(connection->avrcp_cid,
AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED);
avrcp_target_support_event(connection->avrcp_cid,
AVRCP_NOTIFICATION_EVENT_BATT_STATUS_CHANGED);
avrcp_target_battery_status_changed(connection->avrcp_cid, battery_status);

// query supported events:
avrcp_controller_get_supported_events(connection->avrcp_cid);
return;
}

case
"Dawid Bańkowski" <d.ban...@gmail.com>: Apr 06 04:22AM -0700

@Matthias Ringwald,
 
Are You able to reorganice examples to standard header + source pair? In
ESP-IDE for C++ there is no compile error in this way. I have rearange it
and it is compileing but now I have some Bluetooth device pairing issu.
They are not pairing. :/
 
piątek, 5 kwietnia 2024 o 18:25:51 UTC+2 Matthias Ringwald napisał(a):
 
Matthias Ringwald <matthias...@gmail.com>: Apr 06 09:11PM +0200

Hi Dawid
 
all BTstack API files (should) have C++ guards ( #if defined __cplusplus \n extern "C" { \n #endif )
If there's one missing, please let us know and we can add it.
 
Best
Matthias
 
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to btstack-dev...@googlegroups.com.
sdkconfig-btstack
sdkconfig-ESP-ISF
Reply all
Reply to author
Forward
0 new messages