Add Bluetooth examples

Co-authored-by: Peter Harper <77111776+peterharperuk@users.noreply.github.com>
This commit is contained in:
graham sanderson
2023-02-10 17:59:58 -06:00
parent 03f97a8999
commit 1c5d9aa567
127 changed files with 2296 additions and 63 deletions

View File

@@ -18,27 +18,11 @@ if (PICO_CYW43_SUPPORTED) # set by PICO_BOARD=pico_w
set(WIFI_SSID "${WIFI_SSID}" CACHE INTERNAL "WiFi SSID for examples")
set(WIFI_PASSWORD "${WIFI_PASSWORD}" CACHE INTERNAL "WiFi password for examples")
add_subdirectory(blink)
add_subdirectory(wifi_scan)
add_subdirectory(access_point)
if ("${WIFI_SSID}" STREQUAL "")
message("Skipping some Pico W examples as WIFI_SSID is not defined")
elseif ("${WIFI_PASSWORD}" STREQUAL "")
message("Skipping some Pico W examples as WIFI_PASSWORD is not defined")
add_subdirectory(wifi)
if (NOT TARGET pico_btstack_base)
message("Skipping Pico W Bluetooth examples as support is not available")
else()
add_subdirectory(iperf)
add_subdirectory(ntp_client)
add_subdirectory(tcp_client)
add_subdirectory(tcp_server)
add_subdirectory(freertos)
add_subdirectory(udp_beacon)
if (NOT PICO_MBEDTLS_PATH)
message("Skipping tls examples as PICO_MBEDTLS_PATH is not defined")
else()
add_subdirectory(tls_client)
endif()
add_subdirectory(bt)
endif()
endif()
endif()

398
pico_w/bt/CMakeLists.txt Normal file
View File

@@ -0,0 +1,398 @@
add_subdirectory(standalone)
set(BTSTACK_ROOT ${PICO_SDK_PATH}/lib/btstack)
set(BTSTACK_EXAMPLE_PATH ${BTSTACK_ROOT}/example)
set(BTSTACK_3RD_PARTY_PATH ${BTSTACK_ROOT}/3rd-party)
set(BT_EXAMPLE_COMMON_DIR "${CMAKE_CURRENT_LIST_DIR}")
if (NOT PICO_EXTRAS_PATH)
message("Skipping some Pico W BTstack examples that require pico-extras")
else()
add_library(pico_btstack_audio_example INTERFACE)
target_sources(pico_btstack_audio_example INTERFACE
${PICO_BTSTACK_PATH}/src/btstack_audio.c
${CMAKE_CURRENT_LIST_DIR}/btstack_audio_pico.c
)
target_link_libraries(pico_btstack_audio_example INTERFACE
pico_audio_i2s
)
endif()
# mod player used by a2dp_source_demo and mod_player and demo song
add_library(pico_btstack_hxcmod_player INTERFACE)
target_sources(pico_btstack_hxcmod_player INTERFACE
${BTSTACK_3RD_PARTY_PATH}/hxcmod-player/hxcmod.c
${BTSTACK_3RD_PARTY_PATH}/hxcmod-player/mods/nao-deceased_by_disease.c
)
target_include_directories(pico_btstack_hxcmod_player INTERFACE
${BTSTACK_3RD_PARTY_PATH}/hxcmod-player
${BTSTACK_3RD_PARTY_PATH}/hxcmod-player/mods
)
add_library(pico_btstack_sco_demo_util INTERFACE)
target_sources(pico_btstack_sco_demo_util INTERFACE
# sco demo utils
${BTSTACK_EXAMPLE_PATH}/sco_demo_util.c
)
# Adds common stuff for all the examples
add_library(picow_bt_example_common INTERFACE)
target_sources(picow_bt_example_common INTERFACE
${CMAKE_CURRENT_LIST_DIR}/picow_bt_example_common.c
)
target_link_libraries(picow_bt_example_common INTERFACE
pico_stdlib
pico_btstack_ble
pico_btstack_classic
pico_btstack_cyw43
)
target_include_directories(picow_bt_example_common INTERFACE
${BT_EXAMPLE_COMMON_DIR}/config # Use our own config
${BTSTACK_EXAMPLE_PATH}/
)
target_compile_definitions(picow_bt_example_common INTERFACE
PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS=3000
#WANT_HCI_DUMP=1 # This enables btstack debug
#ENABLE_SEGGER_RTT=1
)
if (TARGET pico_btstack_audio_example)
target_link_libraries(picow_bt_example_common INTERFACE
pico_btstack_audio_example
)
target_compile_definitions(picow_bt_example_common INTERFACE
TEST_AUDIO=1
)
endif()
# Adds stuff needed for cyw43 lwip
add_library(picow_bt_example_cyw43_lwip INTERFACE)
target_link_libraries(picow_bt_example_cyw43_lwip INTERFACE
picow_bt_example_common
)
target_compile_definitions(picow_bt_example_cyw43_lwip INTERFACE
WIFI_SSID=\"${WIFI_SSID}\"
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
CYW43_LWIP=1
)
target_link_libraries(picow_bt_example_cyw43_lwip INTERFACE
pico_lwip_iperf
)
target_include_directories(picow_bt_example_cyw43_lwip INTERFACE
${CMAKE_CURRENT_LIST_DIR}/../wifi # for our common lwipopts
)
# disables cyw43 lwip
add_library(picow_bt_example_no_cyw43_lwip INTERFACE)
target_link_libraries(picow_bt_example_no_cyw43_lwip INTERFACE
picow_bt_example_common
)
target_compile_definitions(picow_bt_example_no_cyw43_lwip INTERFACE
CYW43_LWIP=0
)
# variant: no cyw43 lwip | poll
add_library(picow_bt_example_no_cyw43_lwip_poll INTERFACE)
target_sources(picow_bt_example_no_cyw43_lwip_poll INTERFACE
${BT_EXAMPLE_COMMON_DIR}/picow_bt_example_poll.c
)
target_link_libraries(picow_bt_example_no_cyw43_lwip_poll INTERFACE
picow_bt_example_no_cyw43_lwip
pico_cyw43_arch_poll
)
# variant: cyw43 lwip | poll
add_library(picow_bt_example_cyw43_lwip_poll INTERFACE)
target_sources(picow_bt_example_cyw43_lwip_poll INTERFACE
${BT_EXAMPLE_COMMON_DIR}/picow_bt_example_poll.c
)
target_link_libraries(picow_bt_example_cyw43_lwip_poll INTERFACE
picow_bt_example_cyw43_lwip
pico_cyw43_arch_lwip_poll
)
# variant: btstack lwip | poll
add_library(picow_bt_example_btstack_lwip_poll INTERFACE)
target_sources(picow_bt_example_btstack_lwip_poll INTERFACE
${BT_EXAMPLE_COMMON_DIR}/picow_bt_example_poll.c
)
target_link_libraries(picow_bt_example_btstack_lwip_poll INTERFACE
picow_bt_example_no_cyw43_lwip
pico_cyw43_arch_poll
pico_lwip_nosys
pico_btstack_bnep_lwip
)
target_include_directories(picow_bt_example_btstack_lwip_poll INTERFACE
${CMAKE_CURRENT_LIST_DIR}/../wifi # for our common lwipopts
)
# variant: no cyw43 lwip | background
add_library(picow_bt_example_no_cyw43_lwip_background INTERFACE)
target_sources(picow_bt_example_no_cyw43_lwip_background INTERFACE
${BT_EXAMPLE_COMMON_DIR}/picow_bt_example_background.c
)
target_link_libraries(picow_bt_example_no_cyw43_lwip_background INTERFACE
picow_bt_example_no_cyw43_lwip
pico_cyw43_arch_threadsafe_background
)
# variant: cyw43 lwip | background
add_library(picow_bt_example_cyw43_lwip_background INTERFACE)
target_sources(picow_bt_example_cyw43_lwip_background INTERFACE
${BT_EXAMPLE_COMMON_DIR}/picow_bt_example_background.c
)
target_link_libraries(picow_bt_example_cyw43_lwip_background INTERFACE
picow_bt_example_cyw43_lwip
pico_cyw43_arch_lwip_threadsafe_background
)
# variant: btstack lwip | background
add_library(picow_bt_example_btstack_lwip_background INTERFACE)
target_sources(picow_bt_example_btstack_lwip_background INTERFACE
${BT_EXAMPLE_COMMON_DIR}/picow_bt_example_background.c
)
target_link_libraries(picow_bt_example_btstack_lwip_background INTERFACE
picow_bt_example_no_cyw43_lwip
pico_cyw43_arch_threadsafe_background
pico_lwip_nosys
pico_btstack_bnep_lwip
)
target_include_directories(picow_bt_example_btstack_lwip_background INTERFACE
${CMAKE_CURRENT_LIST_DIR}/../wifi # for our common lwipopts
)
if (FREERTOS_KERNEL_PATH OR DEFINED ENV{FREERTOS_KERNEL_PATH})
include(FreeRTOS_Kernel_import.cmake)
endif()
if (TARGET FreeRTOS-Kernel)
# common freertos stuff
add_library(picow_bt_example_common_freertos INTERFACE)
target_sources(picow_bt_example_common_freertos INTERFACE
${BT_EXAMPLE_COMMON_DIR}/picow_bt_example_freertos.c
)
target_link_libraries(picow_bt_example_common_freertos INTERFACE
picow_bt_example_common
FreeRTOS-Kernel-Heap4 # FreeRTOS kernel and dynamic heap
)
target_compile_definitions(picow_bt_example_common_freertos INTERFACE
CYW43_TASK_STACK_SIZE=1024
NO_SYS=0
)
target_include_directories(picow_bt_example_common_freertos INTERFACE
${FREERTOS_KERNEL_PATH}/include
${FREERTOS_KERNEL_PATH}/portable/ThirdParty/GCC/RP2040/include
)
# variant: no cyw43 lwip | freertos
add_library(picow_bt_example_no_cyw43_lwip_freertos INTERFACE)
target_link_libraries(picow_bt_example_no_cyw43_lwip_freertos INTERFACE
picow_bt_example_common_freertos
picow_bt_example_no_cyw43_lwip
pico_cyw43_arch_sys_freertos
)
# variant: cyw43 lwip | freertos
add_library(picow_bt_example_cyw43_lwip_freertos INTERFACE)
target_link_libraries(picow_bt_example_cyw43_lwip_freertos INTERFACE
picow_bt_example_common_freertos
picow_bt_example_cyw43_lwip
pico_cyw43_arch_lwip_sys_freertos
)
target_compile_definitions(picow_bt_example_cyw43_lwip_freertos INTERFACE
HAVE_LWIP=1 # stops btstack calling lwip_init
)
# variant: btstack lwip | freertos
add_library(picow_bt_example_btstack_lwip_freertos INTERFACE)
target_link_libraries(picow_bt_example_btstack_lwip_freertos INTERFACE
picow_bt_example_common_freertos
picow_bt_example_no_cyw43_lwip
pico_cyw43_arch_sys_freertos
pico_btstack_bnep_lwip_sys_freertos
pico_lwip_freertos
)
target_include_directories(picow_bt_example_btstack_lwip_freertos INTERFACE
${CMAKE_CURRENT_LIST_DIR}/../wifi # for our common lwipopts
)
target_compile_definitions(picow_bt_example_btstack_lwip_freertos INTERFACE
HAVE_LWIP=1 # stops btstack calling lwip_init
)
endif()
# Common stuff for all examples. Pass the example name
function(picow_bt_example_common NAME)
if (NOT TARGET picow_bt_example_common_${NAME})
add_library(picow_bt_example_common_${NAME} INTERFACE)
target_sources(picow_bt_example_common_${NAME} INTERFACE
# actual example
${BTSTACK_EXAMPLE_PATH}/${NAME}.c
)
if (EXISTS "${BTSTACK_EXAMPLE_PATH}/${NAME}.gatt")
pico_btstack_make_gatt_header(picow_bt_example_common_${NAME} INTERFACE ${BTSTACK_EXAMPLE_PATH}/${NAME}.gatt)
endif()
endif()
endfunction()
# The type of example to build
if(NOT DEFINED BTSTACK_EXAMPLE_TYPE)
set(BTSTACK_EXAMPLE_TYPE "background")
endif()
if ((NOT BTSTACK_EXAMPLE_TYPE STREQUAL "poll") AND
(NOT BTSTACK_EXAMPLE_TYPE STREQUAL "background") AND
(NOT BTSTACK_EXAMPLE_TYPE STREQUAL "freertos") AND
(NOT BTSTACK_EXAMPLE_TYPE STREQUAL "all"))
message(FATAL_ERROR "Unknown BTSTACK_EXAMPLE_TYPE '${BTSTACK_EXAMPLE_TYPE}'; valid options are 'poll', 'background', 'freertos' or 'all'")
endif()
set(BTSTACK_EXAMPLE_TYPE "${BTSTACK_EXAMPLE_TYPE}" CACHE INTERNAL "BT stack example type (poll|background|freertos|all)")
# Add an poll example, pass btstack example name, target name, variant lib and extra libs
function(picow_bt_example_poll NAME TARGET_NAME VARIANT_LIB)
if ("${BTSTACK_EXAMPLE_TYPE}" STREQUAL "poll" OR "${BTSTACK_EXAMPLE_TYPE}" STREQUAL "all")
picow_bt_example_common(${NAME})
add_executable(${TARGET_NAME}_poll)
target_link_libraries(${TARGET_NAME}_poll PRIVATE
picow_bt_example_common_${NAME}
${VARIANT_LIB}
${ARGN} # extra libs
)
pico_add_extra_outputs(${TARGET_NAME}_poll)
example_auto_set_url(${TARGET_NAME}_poll)
endif()
endfunction()
# Add an background example, pass btstack example name, target name, variant lib and extra libs
function(picow_bt_example_background NAME TARGET_NAME VARIANT_LIB)
if ("${BTSTACK_EXAMPLE_TYPE}" STREQUAL "background" OR "${BTSTACK_EXAMPLE_TYPE}" STREQUAL "all")
picow_bt_example_common(${NAME})
add_executable(${TARGET_NAME}_background)
target_link_libraries(${TARGET_NAME}_background PRIVATE
picow_bt_example_common_${NAME}
${VARIANT_LIB}
${ARGN} # extra libs
)
pico_add_extra_outputs(${TARGET_NAME}_background)
example_auto_set_url(${TARGET_NAME}_background)
endif()
endfunction()
# Add a freertos example, pass btstack example name, target name, variant lib and extra libs
function(picow_bt_example_freertos NAME TARGET_NAME VARIANT_LIB)
if ("${BTSTACK_EXAMPLE_TYPE}" STREQUAL "freertos" OR "${BTSTACK_EXAMPLE_TYPE}" STREQUAL "all")
if (TARGET FreeRTOS-Kernel)
picow_bt_example_common(${NAME})
add_executable(${TARGET_NAME}_freertos)
target_link_libraries(${TARGET_NAME}_freertos PRIVATE
picow_bt_example_common_${NAME}
${VARIANT_LIB}
${ARGN} # extra libs
)
pico_add_extra_outputs(${TARGET_NAME}_freertos)
example_auto_set_url(${TARGET_NAME}_freertos)
endif()
endif()
endfunction()
# The default name of the bt example target
function(picow_bt_example_target_name NAME RET)
SET(${RET} "picow_bt_example_${NAME}" PARENT_SCOPE)
endfunction()
# Make a btstack example, NAME should match source file in lib/btstack/example
# Extra parameters indicate extra libraries to link to
function(picow_bt_example NAME)
picow_bt_example_target_name(${NAME} TARGET_NAME)
picow_bt_example_poll(${NAME} ${TARGET_NAME} picow_bt_example_no_cyw43_lwip_poll ${ARGN})
picow_bt_example_background(${NAME} ${TARGET_NAME} picow_bt_example_no_cyw43_lwip_background ${ARGN})
picow_bt_example_freertos(${NAME} ${TARGET_NAME} picow_bt_example_no_cyw43_lwip_freertos ${ARGN})
endfunction()
# List of examples from btstack
include(${BTSTACK_ROOT}/example/CMakeLists.txt)
# Full list of bluetooth examples
set(BTSTACK_EXAMPLES
${EXAMPLES_GENERAL}
${EXAMPLES_CLASSIC_ONLY}
${EXAMPLES_LE_ONLY}
${EXAMPLES_DUAL_MODE}
pan_lwip_http_server
)
# These examples run wifi and bt at the same time
if (WIFI_SSID AND WIFI_PASSWORD)
list(APPEND BTSTACK_EXAMPLES
gatt_counter_with_wifi
gatt_streamer_server_with_wifi
#spp_streamer_with_wifi
)
endif()
# Extra examples that are not that interesting or a bit tricky to run
# They are not built unless BTSTACK_EXAMPLES_ALL=1
set(BTSTACK_EXAMPLES_ADDITIONAL
ancs_client_demo
att_delayed_response
avrcp_browsing_client
dut_mode_classic
gap_dedicated_bonding
gap_link_keys
le_credit_based_flow_control_mode_client
le_credit_based_flow_control_mode_server
le_mitm
led_counter
sdp_bnep_query
sdp_general_query
spp_flowcontrol
sdp_rfcomm_query
spp_and_gatt_counter
spp_and_gatt_streamer
hfp_ag_demo
hsp_ag_demo
hfp_hf_demo
hsp_hs_demo
mod_player
sine_player
ublox_spp_le_counter
nordic_spp_le_streamer
nordic_spp_le_counter
hog_boot_host_demo
gatt_battery_query
gatt_browser
gatt_device_information_query
le_streamer_client
)
# These examples will only be built if pico-extras exists
set(BTSTACK_EXAMPLES_NEED_EXTRAS
a2dp_sink_demo
hfp_hf_demo
hfp_ag_demo
hsp_ag_demo
hsp_hs_demo
mod_player
sine_player
)
# Add examples
set(BTSTACK_EXAMPLE_COUNT 0)
list(REMOVE_DUPLICATES BTSTACK_EXAMPLES)
foreach(NAME ${BTSTACK_EXAMPLES})
# Ignore if sub folder not found
if (NOT IS_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/${NAME})
continue()
endif()
# Ignore example if it needs pico-extras and pico-extras could not be found
if (NOT PICO_EXTRAS_PATH AND ${NAME} IN_LIST BTSTACK_EXAMPLES_NEED_EXTRAS)
continue()
endif()
# Ignore less interesting examples if BTSTACK_EXAMPLES_ALL=1 is not set
if (NOT BTSTACK_EXAMPLES_ALL AND ${NAME} IN_LIST BTSTACK_EXAMPLES_ADDITIONAL)
continue()
endif()
# add example
add_subdirectory(${NAME})
MATH(EXPR BTSTACK_EXAMPLE_COUNT "${BTSTACK_EXAMPLE_COUNT}+1")
endforeach()
message("Adding ${BTSTACK_EXAMPLE_COUNT} BTstack examples of type '${BTSTACK_EXAMPLE_TYPE}'")
suppress_btstack_warnings()

View File

@@ -0,0 +1,7 @@
add_library(a2dp_sink_demo_pins INTERFACE)
target_compile_definitions(a2dp_sink_demo_pins INTERFACE
PICO_AUDIO_I2S_DATA_PIN=9
PICO_AUDIO_I2S_CLOCK_PIN_BASE=10
)
picow_bt_example(a2dp_sink_demo pico_btstack_sbc_decoder a2dp_sink_demo_pins)

View File

@@ -0,0 +1 @@
picow_bt_example(a2dp_source_demo pico_btstack_hxcmod_player pico_btstack_sbc_encoder)

View File

@@ -0,0 +1 @@
picow_bt_example(ancs_client_demo)

View File

@@ -0,0 +1 @@
picow_bt_example(att_delayed_response)

View File

@@ -0,0 +1 @@
picow_bt_example(avrcp_browsing_client)

View File

@@ -0,0 +1,208 @@
/*
* Copyright (C) 2022 BlueKitchen GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* 4. Any redistribution, use, or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
* GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Please inquire about commercial licensing options at
* contact@bluekitchen-gmbh.com
*
*/
#define BTSTACK_FILE__ "btstack_audio_pico.c"
/*
* btstack_audio_pico.c
*
* Implementation of btstack_audio.h using pico_i2s
*
*/
#include "btstack_config.h"
#include "btstack_debug.h"
#include "btstack_audio.h"
#include "btstack_run_loop.h"
#include <stddef.h>
#include <hardware/dma.h>
#include "pico/audio_i2s.h"
#define DRIVER_POLL_INTERVAL_MS 5
#define SAMPLES_PER_BUFFER 512
// client
static void (*playback_callback)(int16_t * buffer, uint16_t num_samples);
// timer to fill output ring buffer
static btstack_timer_source_t driver_timer_sink;
static bool btstack_audio_pico_sink_active;
// from pico-playground/audio/sine_wave/sine_wave.c
static audio_format_t btstack_audio_pico_audio_format;
static audio_buffer_format_t btstack_audio_pico_producer_format;
static audio_buffer_pool_t * btstack_audio_pico_audio_buffer_pool;
static uint8_t btstack_audio_pico_channel_count;
static audio_buffer_pool_t *init_audio(uint32_t sample_frequency, uint8_t channel_count) {
// num channels requested by application
btstack_audio_pico_channel_count = channel_count;
// always use stereo
btstack_audio_pico_audio_format.format = AUDIO_BUFFER_FORMAT_PCM_S16;
btstack_audio_pico_audio_format.sample_freq = sample_frequency;
btstack_audio_pico_audio_format.channel_count = 2;
btstack_audio_pico_producer_format.format = &btstack_audio_pico_audio_format;
btstack_audio_pico_producer_format.sample_stride = 2 * 2;
audio_buffer_pool_t * producer_pool = audio_new_producer_pool(&btstack_audio_pico_producer_format, 3, SAMPLES_PER_BUFFER); // todo correct size
audio_i2s_config_t config;
config.data_pin = PICO_AUDIO_I2S_DATA_PIN;
config.clock_pin_base = PICO_AUDIO_I2S_CLOCK_PIN_BASE;
config.dma_channel = (int8_t) dma_claim_unused_channel(true);
config.pio_sm = 0;
// audio_i2s_setup claims the channel again https://github.com/raspberrypi/pico-extras/issues/48
dma_channel_unclaim(config.dma_channel);
const audio_format_t * output_format = audio_i2s_setup(&btstack_audio_pico_audio_format, &config);
if (!output_format) {
panic("PicoAudio: Unable to open audio device.\n");
}
bool ok = audio_i2s_connect(producer_pool);
assert(ok);
(void)ok;
return producer_pool;
}
static void btstack_audio_pico_sink_fill_buffers(void){
while (true){
audio_buffer_t * audio_buffer = take_audio_buffer(btstack_audio_pico_audio_buffer_pool, false);
if (audio_buffer == NULL){
break;
}
int16_t * buffer16 = (int16_t *) audio_buffer->buffer->bytes;
(*playback_callback)(buffer16, audio_buffer->max_sample_count);
// duplicate samples for mono
if (btstack_audio_pico_channel_count == 1){
int16_t i;
for (i = SAMPLES_PER_BUFFER - 1 ; i >= 0; i--){
buffer16[2*i ] = buffer16[i];
buffer16[2*i+1] = buffer16[i];
}
}
audio_buffer->sample_count = audio_buffer->max_sample_count;
give_audio_buffer(btstack_audio_pico_audio_buffer_pool, audio_buffer);
}
}
static void driver_timer_handler_sink(btstack_timer_source_t * ts){
// refill
btstack_audio_pico_sink_fill_buffers();
// re-set timer
btstack_run_loop_set_timer(ts, DRIVER_POLL_INTERVAL_MS);
btstack_run_loop_add_timer(ts);
}
static int btstack_audio_pico_sink_init(
uint8_t channels,
uint32_t samplerate,
void (*playback)(int16_t * buffer, uint16_t num_samples)
){
btstack_assert(playback != NULL);
btstack_assert(channels != 0);
playback_callback = playback;
btstack_audio_pico_audio_buffer_pool = init_audio(samplerate, channels);
return 0;
}
static void btstack_audio_pico_sink_set_volume(uint8_t volume){
UNUSED(volume);
}
static void btstack_audio_pico_sink_start_stream(void){
// pre-fill HAL buffers
btstack_audio_pico_sink_fill_buffers();
// start timer
btstack_run_loop_set_timer_handler(&driver_timer_sink, &driver_timer_handler_sink);
btstack_run_loop_set_timer(&driver_timer_sink, DRIVER_POLL_INTERVAL_MS);
btstack_run_loop_add_timer(&driver_timer_sink);
// state
btstack_audio_pico_sink_active = true;
audio_i2s_set_enabled(true);
}
static void btstack_audio_pico_sink_stop_stream(void){
audio_i2s_set_enabled(false);
// stop timer
btstack_run_loop_remove_timer(&driver_timer_sink);
// state
btstack_audio_pico_sink_active = false;
}
static void btstack_audio_pico_sink_close(void){
// stop stream if needed
if (btstack_audio_pico_sink_active){
btstack_audio_pico_sink_stop_stream();
}
}
static const btstack_audio_sink_t btstack_audio_pico_sink = {
.init = &btstack_audio_pico_sink_init,
.set_volume = &btstack_audio_pico_sink_set_volume,
.start_stream = &btstack_audio_pico_sink_start_stream,
.stop_stream = &btstack_audio_pico_sink_stop_stream,
.close = &btstack_audio_pico_sink_close,
};
const btstack_audio_sink_t * btstack_audio_pico_sink_get_instance(void){
return &btstack_audio_pico_sink;
}

View File

@@ -0,0 +1,143 @@
/*
* FreeRTOS V202111.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html
*----------------------------------------------------------*/
/* Scheduler Related */
#define configUSE_PREEMPTION 1
#define configUSE_TICKLESS_IDLE 0
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES 32
#define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 1024
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
/* Synchronization Related */
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_COUNTING_SEMAPHORES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configUSE_QUEUE_SETS 1
#define configUSE_TIME_SLICING 1
#define configUSE_NEWLIB_REENTRANT 0
// todo need this for lwip FreeRTOS sys_arch to compile
#define configENABLE_BACKWARD_COMPATIBILITY 1
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
/* System */
#define configSTACK_DEPTH_TYPE uint32_t
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
/* Memory allocation related definitions. */
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configTOTAL_HEAP_SIZE (128*1024)
#define configAPPLICATION_ALLOCATED_HEAP 0
/* Hook function related definitions. */
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_MALLOC_FAILED_HOOK 0
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
/* Run time and task stats gathering related definitions. */
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
/* Co-routine related definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES 1
/* Software timer related definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH 1024
/* Interrupt nesting behaviour configuration. */
/*
#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor]
#define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application]
#define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application]
*/
#if FREE_RTOS_KERNEL_SMP // set by the RP2040 SMP port of FreeRTOS
/* SMP port only */
#define configNUM_CORES 2
#define configTICK_CORE 0
#define configRUN_MULTIPLE_PRIORITIES 1
#define configUSE_CORE_AFFINITY 1
#endif
/* RP2040 specific */
#define configSUPPORT_PICO_SYNC_INTEROP 1
#define configSUPPORT_PICO_TIME_INTEROP 1
#include <assert.h>
/* Define to trap errors during development. */
#define configASSERT(x) assert(x)
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xTaskAbortDelay 1
#define INCLUDE_xTaskGetHandle 1
#define INCLUDE_xTaskResumeFromISR 1
#define INCLUDE_xQueueGetMutexHolder 1
/* A header file that defines trace macro can be included here. */
#endif /* FREERTOS_CONFIG_H */

View File

@@ -0,0 +1,77 @@
#ifndef _PICO_BTSTACK_BTSTACK_CONFIG_H
#define _PICO_BTSTACK_BTSTACK_CONFIG_H
// BTstack features that can be enabled
#define ENABLE_LE_PERIPHERAL
#define ENABLE_LE_CENTRAL
#define ENABLE_L2CAP_LE_CREDIT_BASED_FLOW_CONTROL_MODE
#define ENABLE_LOG_INFO
#define ENABLE_LOG_ERROR
#define ENABLE_PRINTF_HEXDUMP
#define ENABLE_SCO_OVER_HCI
// BTstack configuration. buffers, sizes, ...
#define HCI_OUTGOING_PRE_BUFFER_SIZE 4
#define HCI_ACL_PAYLOAD_SIZE (1691 + 4)
#define HCI_ACL_CHUNK_SIZE_ALIGNMENT 4
#define MAX_NR_AVDTP_CONNECTIONS 1
#define MAX_NR_AVDTP_STREAM_ENDPOINTS 1
#define MAX_NR_AVRCP_CONNECTIONS 2
#define MAX_NR_BNEP_CHANNELS 1
#define MAX_NR_BNEP_SERVICES 1
#define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 2
#define MAX_NR_GATT_CLIENTS 1
#define MAX_NR_HCI_CONNECTIONS 2
#define MAX_NR_HID_HOST_CONNECTIONS 1
#define MAX_NR_HIDS_CLIENTS 1
#define MAX_NR_HFP_CONNECTIONS 1
#define MAX_NR_L2CAP_CHANNELS 4
#define MAX_NR_L2CAP_SERVICES 3
#define MAX_NR_RFCOMM_CHANNELS 1
#define MAX_NR_RFCOMM_MULTIPLEXERS 1
#define MAX_NR_RFCOMM_SERVICES 1
#define MAX_NR_SERVICE_RECORD_ITEMS 4
#define MAX_NR_SM_LOOKUP_ENTRIES 3
#define MAX_NR_WHITELIST_ENTRIES 16
#define MAX_NR_LE_DEVICE_DB_ENTRIES 16
// Limit number of ACL/SCO Buffer to use by stack to avoid cyw43 shared bus overrun
#define MAX_NR_CONTROLLER_ACL_BUFFERS 3
#define MAX_NR_CONTROLLER_SCO_PACKETS 3
// Enable and configure HCI Controller to Host Flow Control to avoid cyw43 shared bus overrun
#define ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL
#define HCI_HOST_ACL_PACKET_LEN 1024
#define HCI_HOST_ACL_PACKET_NUM 3
#define HCI_HOST_SCO_PACKET_LEN 120
#define HCI_HOST_SCO_PACKET_NUM 3
// Link Key DB and LE Device DB using TLV on top of Flash Sector interface
#define NVM_NUM_DEVICE_DB_ENTRIES 16
#define NVM_NUM_LINK_KEYS 16
// We don't give btstack a malloc, so use a fixed-size ATT DB.
#define MAX_ATT_DB_SIZE 512
// BTstack HAL configuration
#define HAVE_EMBEDDED_TIME_MS
// map btstack_assert onto Pico SDK assert()
#define HAVE_ASSERT
// Some USB dongles take longer to respond to HCI reset (e.g. BCM20702A).
#define HCI_RESET_RESEND_TIMEOUT_MS 1000
#define ENABLE_SOFTWARE_AES128
#define ENABLE_MICRO_ECC_FOR_LE_SECURE_CONNECTIONS
#define HAVE_BTSTACK_STDIN
// To get the audio demos working even with HCI dump at 115200, this truncates long ACL packetws
//#define HCI_DUMP_STDOUT_MAX_SIZE_ACL 100
#ifdef ENABLE_CLASSIC
#define ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
#endif
#endif // MICROPY_INCLUDED_EXTMOD_BTSTACK_BTSTACK_CONFIG_H

View File

@@ -0,0 +1 @@
picow_bt_example(dut_mode_classic)

View File

@@ -0,0 +1 @@
picow_bt_example(gap_dedicated_bonding)

View File

@@ -0,0 +1 @@
picow_bt_example(gap_inquiry)

View File

@@ -0,0 +1 @@
picow_bt_example(gap_le_advertisements)

View File

@@ -0,0 +1 @@
picow_bt_example(gap_link_keys)

View File

@@ -0,0 +1 @@
picow_bt_example(gatt_battery_query)

View File

@@ -0,0 +1 @@
picow_bt_example(gatt_browser)

View File

@@ -0,0 +1 @@
picow_bt_example(gatt_counter)

View File

@@ -0,0 +1,6 @@
set(NAME gatt_counter)
picow_bt_example_target_name(${NAME}_with_wifi TARGET_NAME)
picow_bt_example_poll(${NAME} ${TARGET_NAME} picow_bt_example_cyw43_lwip_poll)
picow_bt_example_background(${NAME} ${TARGET_NAME} picow_bt_example_cyw43_lwip_background)
picow_bt_example_freertos(${NAME} ${TARGET_NAME} picow_bt_example_cyw43_lwip_freertos)

View File

@@ -0,0 +1 @@
picow_bt_example(gatt_device_information_query)

View File

@@ -0,0 +1 @@
picow_bt_example(gatt_heart_rate_client)

View File

@@ -0,0 +1 @@
picow_bt_example(gatt_streamer_server)

View File

@@ -0,0 +1,6 @@
set(NAME gatt_streamer_server)
picow_bt_example_target_name(${NAME}_with_wifi TARGET_NAME)
picow_bt_example_poll(${NAME} ${TARGET_NAME} picow_bt_example_cyw43_lwip_poll)
picow_bt_example_background(${NAME} ${TARGET_NAME} picow_bt_example_cyw43_lwip_background)
picow_bt_example_freertos(${NAME} ${TARGET_NAME} picow_bt_example_cyw43_lwip_freertos)

View File

@@ -0,0 +1 @@
picow_bt_example(hfp_ag_demo pico_btstack_sco_demo_util pico_btstack_sbc_encoder)

View File

@@ -0,0 +1 @@
picow_bt_example(hfp_hf_demo pico_btstack_sco_demo_util pico_btstack_sbc_encoder)

View File

@@ -0,0 +1 @@
picow_bt_example(hid_host_demo)

View File

@@ -0,0 +1 @@
picow_bt_example(hid_keyboard_demo)

View File

@@ -0,0 +1 @@
picow_bt_example(hid_mouse_demo)

View File

@@ -0,0 +1 @@
picow_bt_example(hog_boot_host_demo)

View File

@@ -0,0 +1 @@
picow_bt_example(hog_host_demo)

View File

@@ -0,0 +1 @@
picow_bt_example(hog_keyboard_demo)

View File

@@ -0,0 +1 @@
picow_bt_example(hog_mouse_demo)

View File

@@ -0,0 +1 @@
picow_bt_example(hsp_ag_demo pico_btstack_sco_demo_util pico_btstack_sbc_encoder)

View File

@@ -0,0 +1 @@
picow_bt_example(hsp_hs_demo pico_btstack_sco_demo_util pico_btstack_sbc_encoder)

View File

@@ -0,0 +1 @@
picow_bt_example(le_credit_based_flow_control_mode_client)

View File

@@ -0,0 +1 @@
picow_bt_example(le_credit_based_flow_control_mode_server)

View File

@@ -0,0 +1 @@
picow_bt_example(le_mitm)

View File

@@ -0,0 +1 @@
picow_bt_example(le_streamer_client)

View File

@@ -0,0 +1 @@
picow_bt_example(led_counter)

View File

@@ -0,0 +1 @@
picow_bt_example(mod_player pico_btstack_hxcmod_player)

View File

@@ -0,0 +1 @@
picow_bt_example(nordic_spp_le_counter)

View File

@@ -0,0 +1 @@
picow_bt_example(nordic_spp_le_streamer)

View File

@@ -0,0 +1,13 @@
add_library(pan_lwip_dhserver INTERFACE)
target_sources(pan_lwip_dhserver INTERFACE
${BTSTACK_3RD_PARTY_PATH}/lwip/dhcp-server/dhserver.c
)
target_include_directories(pan_lwip_dhserver INTERFACE
${BTSTACK_3RD_PARTY_PATH}/lwip/dhcp-server
)
picow_bt_example_target_name(pan_lwip_http_server TARGET_NAME)
picow_bt_example_poll(pan_lwip_http_server ${TARGET_NAME} picow_bt_example_btstack_lwip_poll pan_lwip_dhserver pico_lwip_http)
picow_bt_example_background(pan_lwip_http_server ${TARGET_NAME} picow_bt_example_btstack_lwip_background pan_lwip_dhserver pico_lwip_http)
picow_bt_example_freertos(pan_lwip_http_server ${TARGET_NAME} picow_bt_example_btstack_lwip_freertos pan_lwip_dhserver pico_lwip_http)

View File

@@ -0,0 +1 @@
picow_bt_example(pbap_client_demo)

View File

@@ -0,0 +1,21 @@
/**
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "btstack_run_loop.h"
#include "pico/stdlib.h"
#include "picow_bt_example_common.h"
int main() {
stdio_init_all();
int res = picow_bt_example_init();
if (res){
return -1;
}
picow_bt_example_main();
btstack_run_loop_execute();
}

View File

@@ -0,0 +1,101 @@
/**
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "btstack_audio.h"
#include "btstack_event.h"
#include "hal_led.h"
#include "pico/cyw43_arch.h"
#include "pico/stdlib.h"
#if defined(WIFI_SSID) && defined(WIFI_PASSWORD)
#define TEST_BTWIFI 1
#endif
#if TEST_BTWIFI
#include "lwip/ip4_addr.h"
#include "lwip/apps/lwiperf.h"
#endif
// Start the btstack example
int btstack_main(int argc, const char * argv[]);
#if TEST_AUDIO
const btstack_audio_sink_t * btstack_audio_pico_sink_get_instance(void);
#endif
static btstack_packet_callback_registration_t hci_event_callback_registration;
static int led_state = 0;
void hal_led_toggle(void){
led_state = 1 - led_state;
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, led_state);
}
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
UNUSED(size);
UNUSED(channel);
bd_addr_t local_addr;
if (packet_type != HCI_EVENT_PACKET) return;
switch(hci_event_packet_get_type(packet)){
case BTSTACK_EVENT_STATE:
if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return;
gap_local_bd_addr(local_addr);
printf("BTstack up and running on %s.\n", bd_addr_to_str(local_addr));
break;
default:
break;
}
}
#if TEST_BTWIFI
static void iperf_report(void *arg, enum lwiperf_report_type report_type,
const ip_addr_t *local_addr, u16_t local_port, const ip_addr_t *remote_addr, u16_t remote_port,
u32_t bytes_transferred, u32_t ms_duration, u32_t bandwidth_kbitpsec) {
static uint32_t total_iperf_megabytes = 0;
uint32_t mbytes = bytes_transferred / 1024 / 1024;
float mbits = bandwidth_kbitpsec / 1000.0;
total_iperf_megabytes += mbytes;
printf("Completed iperf transfer of %d MBytes @ %.1f Mbits/sec\n", mbytes, mbits);
printf("Total iperf megabytes since start %d Mbytes\n", total_iperf_megabytes);
}
#endif
int picow_bt_example_init(void) {
// initialize CYW43 driver architecture (will enable BT if/because CYW43_ENABLE_BLUETOOTH == 1)
if (cyw43_arch_init()) {
printf("failed to initialise cyw43_arch\n");
return -1;
}
// inform about BTstack state
hci_event_callback_registration.callback = &packet_handler;
hci_add_event_handler(&hci_event_callback_registration);
// setup i2s audio for sink
#if TEST_AUDIO
btstack_audio_sink_set_instance(btstack_audio_pico_sink_get_instance());
#endif
return 0;
}
void picow_bt_example_main(void) {
btstack_main(0, NULL);
#if TEST_BTWIFI
uint32_t start_ms = to_ms_since_boot(get_absolute_time());
cyw43_arch_enable_sta_mode();
printf("Connecting to WiFi \"%s\"...\n", WIFI_SSID);
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
panic("failed to connect");
} else {
printf("Connected in %lus.\n", (to_ms_since_boot(get_absolute_time()) - start_ms) / 1000);
}
printf("\nReady, running iperf server at %s\n", ip4addr_ntoa(netif_ip4_addr(netif_list)));
lwiperf_start_tcp_server_default(&iperf_report, NULL);
#endif
}

View File

@@ -0,0 +1,18 @@
/**
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* \brief Initialise BTstack example with cyw43
*
* \return 0 if ok
*/
int picow_bt_example_init(void);
/*
* \brief Run the BTstack example
*
*/
void picow_bt_example_main(void);

View File

@@ -0,0 +1,112 @@
/**
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/btstack_init.h"
#include "FreeRTOS.h"
#include "task.h"
#include "picow_bt_example_common.h"
#if HAVE_LWIP
#include "pico/lwip_freertos.h"
#include "pico/cyw43_arch.h"
#endif
#ifndef RUN_FREERTOS_ON_CORE
#define RUN_FREERTOS_ON_CORE 0
#endif
#define TEST_TASK_PRIORITY ( tskIDLE_PRIORITY + 2UL )
#define BLINK_TASK_PRIORITY ( tskIDLE_PRIORITY + 1UL )
#ifdef TEST_BLINK_TASK
void blink_task(__unused void *params) {
printf("blink_task starts\n");
while (true) {
#if 0 && configNUM_CORES > 1
static int last_core_id;
if (portGET_CORE_ID() != last_core_id) {
last_core_id = portGET_CORE_ID();
printf("blinking now from core %d\n", last_core_id);
}
#endif
hal_led_toggle();
vTaskDelay(200);
}
}
#endif
void main_task(__unused void *params) {
int res = picow_bt_example_init();
if (res){
return;
}
// If we're using lwip but not via cyw43 (e.g. pan) we have to call this
#if HAVE_LWIP && !CYW43_LWIP
lwip_freertos_init(cyw43_arch_async_context());
#endif
picow_bt_example_main();
#ifdef TEST_BLINK_TASK
xTaskCreate(blink_task, "BlinkThread", configMINIMAL_STACK_SIZE, NULL, BLINK_TASK_PRIORITY, NULL);
#endif
while(true) {
vTaskDelay(1000);
}
pico_btstack_deinit();
#if HAVE_LWIP && !CYW43_LWIP
lwip_freertos_deinit(cyw43_arch_async_context());
#endif
}
void vLaunch( void) {
TaskHandle_t task;
xTaskCreate(main_task, "TestMainThread", 1024, NULL, TEST_TASK_PRIORITY, &task);
#if NO_SYS && configUSE_CORE_AFFINITY && configNUM_CORES > 1
// we must bind the main task to one core (well at least while the init is called)
// (note we only do this in NO_SYS mode, because cyw43_arch_freertos
// takes care of it otherwise)
vTaskCoreAffinitySet(task, 1);
#endif
/* Start the tasks and timer running. */
vTaskStartScheduler();
}
int main()
{
stdio_init_all();
/* Configure the hardware ready to run the demo. */
const char *rtos_name;
#if ( portSUPPORT_SMP == 1 )
rtos_name = "FreeRTOS SMP";
#else
rtos_name = "FreeRTOS";
#endif
#if ( portSUPPORT_SMP == 1 ) && ( configNUM_CORES == 2 )
printf("Starting %s on both cores:\n", rtos_name);
vLaunch();
#elif ( RUN_FREE_RTOS_ON_CORE == 1 )
printf("Starting %s on core 1:\n", rtos_name);
multicore_launch_core1(vLaunch);
while (true);
#else
printf("Starting %s on core 0:\n", rtos_name);
vLaunch();
#endif
return 0;
}

View File

@@ -0,0 +1,21 @@
/**
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "btstack_run_loop.h"
#include "pico/stdlib.h"
#include "picow_bt_example_common.h"
int main() {
stdio_init_all();
int res = picow_bt_example_init();
if (res){
return -1;
}
picow_bt_example_main();
btstack_run_loop_execute();
}

View File

@@ -0,0 +1 @@
picow_bt_example(sdp_bnep_query)

View File

@@ -0,0 +1 @@
picow_bt_example(sdp_general_query)

View File

@@ -0,0 +1 @@
picow_bt_example(sdp_rfcomm_query)

View File

@@ -0,0 +1 @@
picow_bt_example(sine_player)

View File

@@ -0,0 +1 @@
picow_bt_example(sm_pairing_central)

View File

@@ -0,0 +1 @@
picow_bt_example(sm_pairing_peripheral)

View File

@@ -0,0 +1 @@
picow_bt_example(spp_and_gatt_counter)

View File

@@ -0,0 +1 @@
picow_bt_example(spp_and_gatt_streamer)

View File

@@ -0,0 +1 @@
picow_bt_example(spp_counter)

View File

@@ -0,0 +1 @@
picow_bt_example(spp_flowcontrol)

View File

@@ -0,0 +1 @@
picow_bt_example(spp_streamer)

View File

@@ -0,0 +1 @@
picow_bt_example(spp_streamer_client)

View File

@@ -0,0 +1,6 @@
set(NAME spp_streamer)
picow_bt_example_target_name(${NAME}_with_wifi TARGET_NAME)
picow_bt_example_poll(${NAME} ${TARGET_NAME} picow_bt_example_cyw43_lwip_poll)
picow_bt_example_background(${NAME} ${TARGET_NAME} picow_bt_example_cyw43_lwip_background)
picow_bt_example_freertos(${NAME} ${TARGET_NAME} picow_bt_example_cyw43_lwip_freertos)

View File

@@ -0,0 +1,68 @@
# Standalone example that reads from the on board temperature sensor and sends notifications via BLE
# Flashes slowly each second to show it's running
add_executable(picow_ble_temp_sensor
server.c server_common.c
)
target_link_libraries(picow_ble_temp_sensor
pico_stdlib
pico_btstack_ble
pico_btstack_cyw43
pico_cyw43_arch_none
hardware_adc
)
target_include_directories(picow_ble_temp_sensor PRIVATE
${CMAKE_CURRENT_LIST_DIR} # For btstack config
)
pico_btstack_make_gatt_header(picow_ble_temp_sensor PRIVATE "${CMAKE_CURRENT_LIST_DIR}/temp_sensor.gatt")
pico_add_extra_outputs(picow_ble_temp_sensor)
example_auto_set_url(picow_ble_temp_sensor)
# Standalone example that connects to picow_ble_temp_sensor and reads the temperature
# Flahes once quickly each second when it's running but not connected to another device
# Flashes twice quickly each second when connected to another device and reading it's temperature
add_executable(picow_ble_temp_reader
client.c
)
target_link_libraries(picow_ble_temp_reader
pico_stdlib
pico_btstack_ble
pico_btstack_cyw43
pico_cyw43_arch_none
hardware_adc
)
target_include_directories(picow_ble_temp_reader PRIVATE
${CMAKE_CURRENT_LIST_DIR} # For btstack config
)
target_compile_definitions(picow_ble_temp_reader PRIVATE
RUNNING_AS_CLIENT=1
)
pico_add_extra_outputs(picow_ble_temp_reader)
example_auto_set_url(picow_ble_temp_reader)
if (WIFI_SSID AND WIFI_PASSWORD)
# Another version of the sensor example, but this time also runs iperf over wifi
add_executable(picow_ble_temp_sensor_with_wifi
server_with_wifi.c server_common.c
)
target_link_libraries(picow_ble_temp_sensor_with_wifi
pico_stdlib
pico_btstack_ble
pico_btstack_cyw43
pico_cyw43_arch_lwip_threadsafe_background
pico_lwip_iperf
hardware_adc
)
target_include_directories(picow_ble_temp_sensor_with_wifi PRIVATE
${CMAKE_CURRENT_LIST_DIR} # For btstack config
)
target_compile_definitions(picow_ble_temp_sensor_with_wifi PRIVATE
WIFI_SSID=\"${WIFI_SSID}\"
WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
)
pico_btstack_make_gatt_header(picow_ble_temp_sensor_with_wifi PRIVATE "${CMAKE_CURRENT_LIST_DIR}/temp_sensor.gatt")
pico_add_extra_outputs(picow_ble_temp_sensor_with_wifi)
example_auto_set_url(picow_ble_temp_sensor_with_wifi)
endif()

View File

@@ -0,0 +1,58 @@
#ifndef _PICO_BTSTACK_BTSTACK_CONFIG_H
#define _PICO_BTSTACK_BTSTACK_CONFIG_H
#ifndef ENABLE_BLE
#error Please link to pico_btstack_ble
#endif
// BTstack features that can be enabled
#define ENABLE_LE_PERIPHERAL
#define ENABLE_LOG_INFO
#define ENABLE_LOG_ERROR
#define ENABLE_PRINTF_HEXDUMP
// for the client
#if RUNNING_AS_CLIENT
#define ENABLE_LE_CENTRAL
#define MAX_NR_GATT_CLIENTS 1
#else
#define MAX_NR_GATT_CLIENTS 0
#endif
// BTstack configuration. buffers, sizes, ...
#define HCI_OUTGOING_PRE_BUFFER_SIZE 4
#define HCI_ACL_PAYLOAD_SIZE (255 + 4)
#define HCI_ACL_CHUNK_SIZE_ALIGNMENT 4
#define MAX_NR_HCI_CONNECTIONS 1
#define MAX_NR_SM_LOOKUP_ENTRIES 3
#define MAX_NR_WHITELIST_ENTRIES 16
#define MAX_NR_LE_DEVICE_DB_ENTRIES 16
// Limit number of ACL/SCO Buffer to use by stack to avoid cyw43 shared bus overrun
#define MAX_NR_CONTROLLER_ACL_BUFFERS 3
#define MAX_NR_CONTROLLER_SCO_PACKETS 3
// Enable and configure HCI Controller to Host Flow Control to avoid cyw43 shared bus overrun
#define ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL
#define HCI_HOST_ACL_PACKET_LEN (255+4)
#define HCI_HOST_ACL_PACKET_NUM 3
#define HCI_HOST_SCO_PACKET_LEN 120
#define HCI_HOST_SCO_PACKET_NUM 3
// Link Key DB and LE Device DB using TLV on top of Flash Sector interface
#define NVM_NUM_DEVICE_DB_ENTRIES 16
#define NVM_NUM_LINK_KEYS 16
// We don't give btstack a malloc, so use a fixed-size ATT DB.
#define MAX_ATT_DB_SIZE 512
// BTstack HAL configuration
#define HAVE_EMBEDDED_TIME_MS
// map btstack_assert onto Pico SDK assert()
#define HAVE_ASSERT
// Some USB dongles take longer to respond to HCI reset (e.g. BCM20702A).
#define HCI_RESET_RESEND_TIMEOUT_MS 1000
#define ENABLE_SOFTWARE_AES128
#define ENABLE_MICRO_ECC_FOR_LE_SECURE_CONNECTIONS
#endif // MICROPY_INCLUDED_EXTMOD_BTSTACK_BTSTACK_CONFIG_H

View File

@@ -0,0 +1,273 @@
/**
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "btstack.h"
#include "pico/cyw43_arch.h"
#include "pico/stdlib.h"
#if 0
#define DEBUG_LOG(...) printf(__VA_ARGS__)
#else
#define DEBUG_LOG(...)
#endif
#define LED_QUICK_FLASH_DELAY_MS 100
#define LED_SLOW_FLASH_DELAY_MS 1000
typedef enum {
TC_OFF,
TC_IDLE,
TC_W4_SCAN_RESULT,
TC_W4_CONNECT,
TC_W4_SERVICE_RESULT,
TC_W4_CHARACTERISTIC_RESULT,
TC_W4_ENABLE_NOTIFICATIONS_COMPLETE,
TC_W4_READY
} gc_state_t;
static btstack_packet_callback_registration_t hci_event_callback_registration;
static gc_state_t state = TC_OFF;
static bd_addr_t server_addr;
static bd_addr_type_t server_addr_type;
static hci_con_handle_t connection_handle;
static gatt_client_service_t server_service;
static gatt_client_characteristic_t server_characteristic;
static bool listener_registered;
static gatt_client_notification_t notification_listener;
static btstack_timer_source_t heartbeat;
static void client_start(void){
DEBUG_LOG("Start scanning!\n");
state = TC_W4_SCAN_RESULT;
gap_set_scan_parameters(0,0x0030, 0x0030);
gap_start_scan();
}
static bool advertisement_report_contains_service(uint16_t service, uint8_t *advertisement_report){
// get advertisement from report event
const uint8_t * adv_data = gap_event_advertising_report_get_data(advertisement_report);
uint8_t adv_len = gap_event_advertising_report_get_data_length(advertisement_report);
// iterate over advertisement data
ad_context_t context;
for (ad_iterator_init(&context, adv_len, adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)){
uint8_t data_type = ad_iterator_get_data_type(&context);
uint8_t data_size = ad_iterator_get_data_len(&context);
const uint8_t * data = ad_iterator_get_data(&context);
switch (data_type){
case BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS:
for (int i = 0; i < data_size; i += 2) {
uint16_t type = little_endian_read_16(data, i);
if (type == service) return true;
}
default:
break;
}
}
return false;
}
static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
UNUSED(packet_type);
UNUSED(channel);
UNUSED(size);
uint8_t att_status;
switch(state){
case TC_W4_SERVICE_RESULT:
switch(hci_event_packet_get_type(packet)) {
case GATT_EVENT_SERVICE_QUERY_RESULT:
// store service (we expect only one)
DEBUG_LOG("Storing service\n");
gatt_event_service_query_result_get_service(packet, &server_service);
break;
case GATT_EVENT_QUERY_COMPLETE:
att_status = gatt_event_query_complete_get_att_status(packet);
if (att_status != ATT_ERROR_SUCCESS){
printf("SERVICE_QUERY_RESULT, ATT Error 0x%02x.\n", att_status);
gap_disconnect(connection_handle);
break;
}
// service query complete, look for characteristic
state = TC_W4_CHARACTERISTIC_RESULT;
DEBUG_LOG("Search for env sensing characteristic.\n");
gatt_client_discover_characteristics_for_service_by_uuid16(handle_gatt_client_event, connection_handle, &server_service, ORG_BLUETOOTH_CHARACTERISTIC_TEMPERATURE);
break;
default:
break;
}
break;
case TC_W4_CHARACTERISTIC_RESULT:
switch(hci_event_packet_get_type(packet)) {
case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT:
DEBUG_LOG("Storing characteristic\n");
gatt_event_characteristic_query_result_get_characteristic(packet, &server_characteristic);
break;
case GATT_EVENT_QUERY_COMPLETE:
att_status = gatt_event_query_complete_get_att_status(packet);
if (att_status != ATT_ERROR_SUCCESS){
printf("CHARACTERISTIC_QUERY_RESULT, ATT Error 0x%02x.\n", att_status);
gap_disconnect(connection_handle);
break;
}
// register handler for notifications
listener_registered = true;
gatt_client_listen_for_characteristic_value_updates(&notification_listener, handle_gatt_client_event, connection_handle, &server_characteristic);
// enable notifications
DEBUG_LOG("Enable notify on characteristic.\n");
state = TC_W4_ENABLE_NOTIFICATIONS_COMPLETE;
gatt_client_write_client_characteristic_configuration(handle_gatt_client_event, connection_handle,
&server_characteristic, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
break;
default:
break;
}
break;
case TC_W4_ENABLE_NOTIFICATIONS_COMPLETE:
switch(hci_event_packet_get_type(packet)) {
case GATT_EVENT_QUERY_COMPLETE:
DEBUG_LOG("Notifications enabled, ATT status 0x%02x\n", gatt_event_query_complete_get_att_status(packet));
if (gatt_event_query_complete_get_att_status(packet) != ATT_ERROR_SUCCESS) break;
state = TC_W4_READY;
break;
default:
break;
}
break;
case TC_W4_READY:
switch(hci_event_packet_get_type(packet)) {
case GATT_EVENT_NOTIFICATION: {
uint16_t value_length = gatt_event_notification_get_value_length(packet);
const uint8_t *value = gatt_event_notification_get_value(packet);
DEBUG_LOG("Indication value len %d\n", value_length);
if (value_length == 2) {
float temp = little_endian_read_16(value, 0);
printf("read temp %.2f degc\n", temp / 100);
} else {
printf("Unexpected length %d\n", value_length);
}
break;
}
default:
printf("Unknown packet type 0x%02x\n", hci_event_packet_get_type(packet));
break;
}
break;
default:
printf("error\n");
break;
}
}
static void hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
UNUSED(size);
UNUSED(channel);
bd_addr_t local_addr;
if (packet_type != HCI_EVENT_PACKET) return;
uint8_t event_type = hci_event_packet_get_type(packet);
switch(event_type){
case BTSTACK_EVENT_STATE:
if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING) {
gap_local_bd_addr(local_addr);
printf("BTstack up and running on %s.\n", bd_addr_to_str(local_addr));
client_start();
} else {
state = TC_OFF;
}
break;
case GAP_EVENT_ADVERTISING_REPORT:
if (state != TC_W4_SCAN_RESULT) return;
// check name in advertisement
if (!advertisement_report_contains_service(ORG_BLUETOOTH_SERVICE_ENVIRONMENTAL_SENSING, packet)) return;
// store address and type
gap_event_advertising_report_get_address(packet, server_addr);
server_addr_type = gap_event_advertising_report_get_address_type(packet);
// stop scanning, and connect to the device
state = TC_W4_CONNECT;
gap_stop_scan();
printf("Connecting to device with addr %s.\n", bd_addr_to_str(server_addr));
gap_connect(server_addr, server_addr_type);
break;
case HCI_EVENT_LE_META:
// wait for connection complete
switch (hci_event_le_meta_get_subevent_code(packet)) {
case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
if (state != TC_W4_CONNECT) return;
connection_handle = hci_subevent_le_connection_complete_get_connection_handle(packet);
// initialize gatt client context with handle, and add it to the list of active clients
// query primary services
DEBUG_LOG("Search for env sensing service.\n");
state = TC_W4_SERVICE_RESULT;
gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, connection_handle, ORG_BLUETOOTH_SERVICE_ENVIRONMENTAL_SENSING);
break;
default:
break;
}
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
// unregister listener
connection_handle = HCI_CON_HANDLE_INVALID;
if (listener_registered){
listener_registered = false;
gatt_client_stop_listening_for_characteristic_value_updates(&notification_listener);
}
printf("Disconnected %s\n", bd_addr_to_str(server_addr));
if (state == TC_OFF) break;
client_start();
break;
default:
break;
}
}
static void heartbeat_handler(struct btstack_timer_source *ts) {
// Invert the led
static bool quick_flash;
static bool led_on = true;
led_on = !led_on;
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, led_on);
if (listener_registered && led_on) {
quick_flash = !quick_flash;
} else if (!listener_registered) {
quick_flash = false;
}
// Restart timer
btstack_run_loop_set_timer(ts, (led_on || quick_flash) ? LED_QUICK_FLASH_DELAY_MS : LED_SLOW_FLASH_DELAY_MS);
btstack_run_loop_add_timer(ts);
}
int main() {
stdio_init_all();
// initialize CYW43 driver architecture (will enable BT if/because CYW43_ENABLE_BLUETOOTH == 1)
if (cyw43_arch_init()) {
printf("failed to initialise cyw43_arch\n");
return -1;
}
l2cap_init();
sm_init();
sm_set_io_capabilities(IO_CAPABILITY_NO_INPUT_NO_OUTPUT);
gatt_client_init();
hci_event_callback_registration.callback = &hci_event_handler;
hci_add_event_handler(&hci_event_callback_registration);
// set one-shot btstack timer
heartbeat.process = &heartbeat_handler;
btstack_run_loop_set_timer(&heartbeat, LED_SLOW_FLASH_DELAY_MS);
btstack_run_loop_add_timer(&heartbeat);
// turn on!
hci_power_control(HCI_POWER_ON);
btstack_run_loop_execute();
return 0;
}

View File

@@ -0,0 +1,76 @@
#ifndef _LWIPOPTS_H
#define _LWIPOPTS_H
// see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details
#define NO_SYS 1
#define LWIP_SOCKET 0
#define MEM_LIBC_MALLOC 0
#define MEM_ALIGNMENT 4
#define MEM_SIZE 4000
#define MEMP_NUM_TCP_SEG 32
#define MEMP_NUM_ARP_QUEUE 10
#define PBUF_POOL_SIZE 24
#define LWIP_ARP 1
#define LWIP_ETHERNET 1
#define LWIP_ICMP 1
#define LWIP_RAW 1
#define TCP_WND (8 * TCP_MSS)
#define TCP_MSS 1460
#define TCP_SND_BUF (8 * TCP_MSS)
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
#define LWIP_NETIF_STATUS_CALLBACK 1
#define LWIP_NETIF_LINK_CALLBACK 1
#define LWIP_NETIF_HOSTNAME 1
#define LWIP_NETCONN 0
#define MEM_STATS 0
#define SYS_STATS 0
#define MEMP_STATS 0
#define LINK_STATS 0
#define LWIP_CHKSUM_ALGORITHM 3
#define LWIP_DHCP 1
#define LWIP_IPV4 1
#define LWIP_TCP 1
#define LWIP_UDP 1
#define LWIP_DNS 1
#define LWIP_TCP_KEEPALIVE 1
#define LWIP_NETIF_TX_SINGLE_PBUF 1
#define DHCP_DOES_ARP_CHECK 0
#define LWIP_DHCP_DOES_ACD_CHECK 0
#ifndef NDEBUG
#define LWIP_DEBUG 1
#define LWIP_STATS 1
#define LWIP_STATS_DISPLAY 1
#endif
#define ETHARP_DEBUG LWIP_DBG_OFF
#define NETIF_DEBUG LWIP_DBG_OFF
#define PBUF_DEBUG LWIP_DBG_OFF
#define API_LIB_DEBUG LWIP_DBG_OFF
#define API_MSG_DEBUG LWIP_DBG_OFF
#define SOCKETS_DEBUG LWIP_DBG_OFF
#define ICMP_DEBUG LWIP_DBG_OFF
#define INET_DEBUG LWIP_DBG_OFF
#define IP_DEBUG LWIP_DBG_OFF
#define IP_REASS_DEBUG LWIP_DBG_OFF
#define RAW_DEBUG LWIP_DBG_OFF
#define MEM_DEBUG LWIP_DBG_OFF
#define MEMP_DEBUG LWIP_DBG_OFF
#define SYS_DEBUG LWIP_DBG_OFF
#define TCP_DEBUG LWIP_DBG_OFF
#define TCP_INPUT_DEBUG LWIP_DBG_OFF
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
#define TCP_RTO_DEBUG LWIP_DBG_OFF
#define TCP_CWND_DEBUG LWIP_DBG_OFF
#define TCP_WND_DEBUG LWIP_DBG_OFF
#define TCP_FR_DEBUG LWIP_DBG_OFF
#define TCP_QLEN_DEBUG LWIP_DBG_OFF
#define TCP_RST_DEBUG LWIP_DBG_OFF
#define UDP_DEBUG LWIP_DBG_OFF
#define TCPIP_DEBUG LWIP_DBG_OFF
#define PPP_DEBUG LWIP_DBG_OFF
#define SLIP_DEBUG LWIP_DBG_OFF
#define DHCP_DEBUG LWIP_DBG_OFF
#endif /* __LWIPOPTS_H__ */

View File

@@ -0,0 +1,79 @@
/**
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "btstack.h"
#include "pico/cyw43_arch.h"
#include "pico/btstack_cyw43.h"
#include "hardware/adc.h"
#include "pico/stdlib.h"
#include "server_common.h"
#define HEARTBEAT_PERIOD_MS 1000
static btstack_timer_source_t heartbeat;
static btstack_packet_callback_registration_t hci_event_callback_registration;
static void heartbeat_handler(struct btstack_timer_source *ts) {
static uint32_t counter = 0;
counter++;
// Update the temp every 10s
if (counter % 10 == 0) {
poll_temp();
if (le_notification_enabled) {
att_server_request_can_send_now_event(con_handle);
}
}
// Invert the led
static int led_on = true;
led_on = !led_on;
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, led_on);
// Restart timer
btstack_run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS);
btstack_run_loop_add_timer(ts);
}
int main() {
stdio_init_all();
// initialize CYW43 driver architecture (will enable BT if/because CYW43_ENABLE_BLUETOOTH == 1)
if (cyw43_arch_init()) {
printf("failed to initialise cyw43_arch\n");
return -1;
}
// Initialise adc for the temp sensor
adc_init();
adc_select_input(ADC_CHANNEL_TEMPSENSOR);
adc_set_temp_sensor_enabled(true);
l2cap_init();
sm_init();
att_server_init(profile_data, att_read_callback, att_write_callback);
// inform about BTstack state
hci_event_callback_registration.callback = &packet_handler;
hci_add_event_handler(&hci_event_callback_registration);
// register for ATT event
att_server_register_packet_handler(packet_handler);
// set one-shot btstack timer
heartbeat.process = &heartbeat_handler;
btstack_run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS);
btstack_run_loop_add_timer(&heartbeat);
// turn on bluetooth!
hci_power_control(HCI_POWER_ON);
btstack_run_loop_execute();
return 0;
}

View File

@@ -0,0 +1,106 @@
/**
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "btstack.h"
#include "hardware/adc.h"
#include "temp_sensor.h"
#include "server_common.h"
#define APP_AD_FLAGS 0x06
static uint8_t adv_data[] = {
// Flags general discoverable
0x02, BLUETOOTH_DATA_TYPE_FLAGS, APP_AD_FLAGS,
// Name
0x17, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'P', 'i', 'c', 'o', ' ', '0', '0', ':', '0', '0', ':', '0', '0', ':', '0', '0', ':', '0', '0', ':', '0', '0',
0x03, BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS, 0x1a, 0x18,
};
static const uint8_t adv_data_len = sizeof(adv_data);
int le_notification_enabled;
hci_con_handle_t con_handle;
uint16_t current_temp;
void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
UNUSED(size);
UNUSED(channel);
bd_addr_t local_addr;
if (packet_type != HCI_EVENT_PACKET) return;
uint8_t event_type = hci_event_packet_get_type(packet);
switch(event_type){
case BTSTACK_EVENT_STATE:
if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return;
gap_local_bd_addr(local_addr);
printf("BTstack up and running on %s.\n", bd_addr_to_str(local_addr));
// setup advertisements
uint16_t adv_int_min = 800;
uint16_t adv_int_max = 800;
uint8_t adv_type = 0;
bd_addr_t null_addr;
memset(null_addr, 0, 6);
gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00);
assert(adv_data_len <= 31); // ble limitation
gap_advertisements_set_data(adv_data_len, (uint8_t*) adv_data);
gap_advertisements_enable(1);
poll_temp();
break;
case HCI_EVENT_DISCONNECTION_COMPLETE:
le_notification_enabled = 0;
break;
case ATT_EVENT_CAN_SEND_NOW:
att_server_notify(con_handle, ATT_CHARACTERISTIC_ORG_BLUETOOTH_CHARACTERISTIC_TEMPERATURE_01_VALUE_HANDLE, (uint8_t*)&current_temp, sizeof(current_temp));
break;
default:
break;
}
}
uint16_t att_read_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size) {
UNUSED(connection_handle);
if (att_handle == ATT_CHARACTERISTIC_ORG_BLUETOOTH_CHARACTERISTIC_TEMPERATURE_01_VALUE_HANDLE){
return att_read_callback_handle_blob((const uint8_t *)&current_temp, sizeof(current_temp), offset, buffer, buffer_size);
}
return 0;
}
int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size) {
UNUSED(transaction_mode);
UNUSED(offset);
UNUSED(buffer_size);
if (att_handle != ATT_CHARACTERISTIC_ORG_BLUETOOTH_CHARACTERISTIC_TEMPERATURE_01_CLIENT_CONFIGURATION_HANDLE) return 0;
le_notification_enabled = little_endian_read_16(buffer, 0) == GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION;
con_handle = connection_handle;
if (le_notification_enabled) {
att_server_request_can_send_now_event(con_handle);
}
return 0;
}
void poll_temp(void) {
adc_select_input(ADC_CHANNEL_TEMPSENSOR);
uint32_t raw32 = adc_read();
const uint32_t bits = 12;
// Scale raw reading to 16 bit value using a Taylor expansion (for 8 <= bits <= 16)
uint16_t raw16 = raw32 << (16 - bits) | raw32 >> (2 * bits - 16);
// ref https://github.com/raspberrypi/pico-micropython-examples/blob/master/adc/temperature.py
const float conversion_factor = 3.3 / (65535);
float reading = raw16 * conversion_factor;
// The temperature sensor measures the Vbe voltage of a biased bipolar diode, connected to the fifth ADC channel
// Typically, Vbe = 0.706V at 27 degrees C, with a slope of -1.721mV (0.001721) per degree.
float deg_c = 27 - (reading - 0.706) / 0.001721;
current_temp = deg_c * 100;
printf("Write temp %.2f degc\n", deg_c);
}

View File

@@ -0,0 +1,22 @@
/**
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SERVER_COMMON_H_
#define SERVER_COMMON_H_
#define ADC_CHANNEL_TEMPSENSOR 4
extern int le_notification_enabled;
extern hci_con_handle_t con_handle;
extern uint16_t current_temp;
extern uint8_t const profile_data[];
void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
uint16_t att_read_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size);
int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size);
void poll_temp(void);
#endif

View File

@@ -0,0 +1,117 @@
/**
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "btstack.h"
#include "pico/cyw43_arch.h"
#include "pico/stdlib.h"
#include "hardware/adc.h"
#include "lwip/netif.h"
#include "lwip/ip4_addr.h"
#include "lwip/apps/lwiperf.h"
#include "server_common.h"
#define HEARTBEAT_PERIOD_MS 1000
static void heartbeat_handler(async_context_t *context, async_at_time_worker_t *worker);
static async_at_time_worker_t heartbeat_worker = { .do_work = heartbeat_handler };
static btstack_packet_callback_registration_t hci_event_callback_registration;
static void heartbeat_handler(async_context_t *context, async_at_time_worker_t *worker) {
static uint32_t counter = 0;
counter++;
// Update the temp every 10s
if (counter % 10 == 0) {
poll_temp();
if (le_notification_enabled) {
att_server_request_can_send_now_event(con_handle);
}
}
// Invert the led
static int led_on = true;
led_on = !led_on;
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, led_on);
// Restart timer
async_context_add_at_time_worker_in_ms(context, &heartbeat_worker, HEARTBEAT_PERIOD_MS);
}
// Report IP results and exit
static void iperf_report(void *arg, enum lwiperf_report_type report_type,
const ip_addr_t *local_addr, u16_t local_port, const ip_addr_t *remote_addr, u16_t remote_port,
u32_t bytes_transferred, u32_t ms_duration, u32_t bandwidth_kbitpsec) {
static uint32_t total_iperf_megabytes = 0;
uint32_t mbytes = bytes_transferred / 1024 / 1024;
float mbits = bandwidth_kbitpsec / 1000.0;
total_iperf_megabytes += mbytes;
printf("Completed iperf transfer of %d MBytes @ %.1f Mbits/sec\n", mbytes, mbits);
printf("Total iperf megabytes since start %d Mbytes\n", total_iperf_megabytes);
}
int main() {
stdio_init_all();
// initialize CYW43 architecture
// - will enable BT if CYW43_ENABLE_BLUETOOTH == 1
// - will enable lwIP if CYW43_LWIP == 1
if (cyw43_arch_init()) {
printf("failed to initialise cyw43_arch\n");
return -1;
}
// Initialise adc for the temp sensor
adc_init();
adc_select_input(ADC_CHANNEL_TEMPSENSOR);
adc_set_temp_sensor_enabled(true);
l2cap_init();
sm_init();
att_server_init(profile_data, att_read_callback, att_write_callback);
// inform about BTstack state
hci_event_callback_registration.callback = &packet_handler;
hci_add_event_handler(&hci_event_callback_registration);
// register for ATT event
att_server_register_packet_handler(packet_handler);
// set one-shot btstack timer
async_context_add_at_time_worker_in_ms(cyw43_arch_async_context(), &heartbeat_worker, HEARTBEAT_PERIOD_MS);
// Connect to Wi-Fi
cyw43_arch_enable_sta_mode();
printf("Connecting to Wi-Fi...\n");
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
printf("failed to connect.\n");
return 1;
} else {
printf("Connected.\n");
}
// setup iperf
cyw43_arch_lwip_begin();
printf("\nReady, running iperf server at %s\n", ip4addr_ntoa(netif_ip4_addr(netif_list)));
lwiperf_start_tcp_server_default(&iperf_report, NULL);
cyw43_arch_lwip_end();
// turn on bluetooth!
hci_power_control(HCI_POWER_ON);
// For threadsafe background we can just enter a loop
while(true) {
sleep_ms(1000);
}
cyw43_arch_deinit();
return 0;
}

View File

@@ -0,0 +1,8 @@
PRIMARY_SERVICE, GAP_SERVICE
CHARACTERISTIC, GAP_DEVICE_NAME, READ, "picow_temp"
PRIMARY_SERVICE, GATT_SERVICE
CHARACTERISTIC, GATT_DATABASE_HASH, READ,
PRIMARY_SERVICE, ORG_BLUETOOTH_SERVICE_ENVIRONMENTAL_SENSING
CHARACTERISTIC, ORG_BLUETOOTH_CHARACTERISTIC_TEMPERATURE, READ | NOTIFY | INDICATE | DYNAMIC,

View File

@@ -0,0 +1 @@
picow_bt_example(ublox_spp_le_counter)

View File

@@ -0,0 +1,25 @@
set(WIFI_SSID "${WIFI_SSID}" CACHE INTERNAL "WiFi SSID for examples")
set(WIFI_PASSWORD "${WIFI_PASSWORD}" CACHE INTERNAL "WiFi password for examples")
add_subdirectory(blink)
add_subdirectory(wifi_scan)
add_subdirectory(access_point)
if ("${WIFI_SSID}" STREQUAL "")
message("Skipping some Pico W examples as WIFI_SSID is not defined")
elseif ("${WIFI_PASSWORD}" STREQUAL "")
message("Skipping some Pico W examples as WIFI_PASSWORD is not defined")
else()
add_subdirectory(iperf)
add_subdirectory(ntp_client)
add_subdirectory(tcp_client)
add_subdirectory(tcp_server)
add_subdirectory(freertos)
add_subdirectory(udp_beacon)
if (NOT PICO_MBEDTLS_PATH)
message("Skipping tls examples as PICO_MBEDTLS_PATH is not defined")
else()
add_subdirectory(tls_client)
endif()
endif()

View File

@@ -311,11 +311,13 @@ int main() {
// you do not need it in your code
#if PICO_CYW43_ARCH_POLL
// if you are using pico_cyw43_arch_poll, then you must poll periodically from your
// main loop (not from a timer) to check for WiFi driver or lwIP work that needs to be done.
// main loop (not from a timer interrupt) to check for Wi-Fi driver or lwIP work that needs to be done.
cyw43_arch_poll();
sleep_ms(1);
// you can poll as often as you like, however if you have nothing else to do you can
// choose to sleep until either a specified time, or cyw43_arch_poll() has work to do:
cyw43_arch_wait_for_work_until(make_timeout_time_ms(1000));
#else
// if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work
// if you are not using pico_cyw43_arch_poll, then Wi-FI driver and lwIP work
// is done via interrupt in the background. This sleep is just an example of some (blocking)
// work you might be doing.
sleep_ms(1000);

View File

@@ -10,7 +10,7 @@
int main() {
stdio_init_all();
if (cyw43_arch_init()) {
printf("WiFi init failed");
printf("Wi-Fi init failed");
return -1;
}
while (true) {

View File

@@ -0,0 +1,62 @@
# This is a copy of <FREERTOS_KERNEL_PATH>/portable/ThirdParty/GCC/RP2040/FREERTOS_KERNEL_import.cmake
# This can be dropped into an external project to help locate the FreeRTOS kernel
# It should be include()ed prior to project(). Alternatively this file may
# or the CMakeLists.txt in this directory may be included or added via add_subdirectory
# respectively.
if (DEFINED ENV{FREERTOS_KERNEL_PATH} AND (NOT FREERTOS_KERNEL_PATH))
set(FREERTOS_KERNEL_PATH $ENV{FREERTOS_KERNEL_PATH})
message("Using FREERTOS_KERNEL_PATH from environment ('${FREERTOS_KERNEL_PATH}')")
endif ()
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "portable/ThirdParty/GCC/RP2040")
# undo the above
set(FREERTOS_KERNEL_RP2040_BACK_PATH "../../../..")
if (NOT FREERTOS_KERNEL_PATH)
# check if we are inside the FreeRTOS kernel tree (i.e. this file has been included directly)
get_filename_component(_ACTUAL_PATH ${CMAKE_CURRENT_LIST_DIR} REALPATH)
get_filename_component(_POSSIBLE_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} REALPATH)
if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH)
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH)
endif()
if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH)
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH)
message("Setting FREERTOS_KERNEL_PATH to ${FREERTOS_KERNEL_PATH} based on location of FreeRTOS-Kernel-import.cmake")
elseif (PICO_SDK_PATH AND EXISTS "${PICO_SDK_PATH}/../FreeRTOS-Kernel")
set(FREERTOS_KERNEL_PATH ${PICO_SDK_PATH}/../FreeRTOS-Kernel)
message("Defaulting FREERTOS_KERNEL_PATH as sibling of PICO_SDK_PATH: ${FREERTOS_KERNEL_PATH}")
endif()
endif ()
if (NOT FREERTOS_KERNEL_PATH)
foreach(POSSIBLE_SUFFIX Source FreeRTOS-Kernel FreeRTOS/Source)
# check if FreeRTOS-Kernel exists under directory that included us
set(SEARCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}})
set(SEARCH_ROOT ../../../..)
get_filename_component(_POSSIBLE_PATH ${SEARCH_ROOT}/${POSSIBLE_SUFFIX} REALPATH)
if (EXISTS ${_POSSIBLE_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt)
get_filename_component(FREERTOS_KERNEL_PATH ${_POSSIBLE_PATH} REALPATH)
message("Setting FREERTOS_KERNEL_PATH to '${FREERTOS_KERNEL_PATH}' found relative to enclosing project")
break()
endif()
endforeach()
endif()
if (NOT FREERTOS_KERNEL_PATH)
message(FATAL_ERROR "FreeRTOS location was not specified. Please set FREERTOS_KERNEL_PATH.")
endif()
set(FREERTOS_KERNEL_PATH "${FREERTOS_KERNEL_PATH}" CACHE PATH "Path to the FreeRTOS Kernel")
get_filename_component(FREERTOS_KERNEL_PATH "${FREERTOS_KERNEL_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${FREERTOS_KERNEL_PATH})
message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' not found")
endif()
if (NOT EXISTS ${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt)
message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' does not contain an RP2040 port here: ${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}")
endif()
set(FREERTOS_KERNEL_PATH ${FREERTOS_KERNEL_PATH} CACHE PATH "Path to the FreeRTOS_KERNEL" FORCE)
add_subdirectory(${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} FREERTOS_KERNEL)

View File

@@ -62,7 +62,7 @@ void main_task(__unused void *params) {
return;
}
cyw43_arch_enable_sta_mode();
printf("Connecting to WiFi...\n");
printf("Connecting to Wi-Fi...\n");
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
printf("failed to connect.\n");
exit(1);
@@ -72,6 +72,7 @@ void main_task(__unused void *params) {
xTaskCreate(blink_task, "BlinkThread", configMINIMAL_STACK_SIZE, NULL, BLINK_TASK_PRIORITY, NULL);
cyw43_arch_lwip_begin();
#if CLIENT_TEST
printf("\nReady, running iperf client\n");
ip_addr_t clientaddr;
@@ -81,10 +82,11 @@ void main_task(__unused void *params) {
printf("\nReady, running iperf server at %s\n", ip4addr_ntoa(netif_ip4_addr(netif_list)));
lwiperf_start_tcp_server_default(&iperf_report, NULL);
#endif
cyw43_arch_lwip_end();
while(true) {
// not much to do as LED is in another task, and we're using RAW (callback) lwIP API
vTaskDelay(100);
vTaskDelay(10000);
}
cyw43_arch_deinit();

View File

@@ -0,0 +1,21 @@
#ifndef _LWIPOPTS_H
#define _LWIPOPTS_H
// Generally you would define your own explicit list of lwIP options
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html)
//
// This example uses a common include to avoid repetition
#include "lwipopts_examples_common.h"
#if !NO_SYS
#define TCPIP_THREAD_STACKSIZE 1024
#define DEFAULT_THREAD_STACKSIZE 1024
#define DEFAULT_RAW_RECVMBOX_SIZE 8
#define TCPIP_MBOX_SIZE 8
#define LWIP_TIMEVAL_PRIVATE 0
// not necessary, can be done either way
#define LWIP_TCPIP_CORE_LOCKING_INPUT 1
#endif
#endif

View File

@@ -28,7 +28,7 @@ void main_task(__unused void *params) {
return;
}
cyw43_arch_enable_sta_mode();
printf("Connecting to WiFi...\n");
printf("Connecting to Wi-Fi...\n");
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
printf("failed to connect.\n");
exit(1);

View File

@@ -14,7 +14,6 @@ target_link_libraries(picow_iperf_server_background
pico_stdlib
pico_lwip_iperf
)
pico_add_extra_outputs(picow_iperf_server_background)
add_executable(picow_iperf_server_poll

View File

@@ -44,7 +44,7 @@ int main() {
return 1;
}
cyw43_arch_enable_sta_mode();
printf("Connecting to WiFi...\n");
printf("Connecting to Wi-Fi...\n");
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
printf("failed to connect.\n");
return 1;
@@ -52,6 +52,7 @@ int main() {
printf("Connected.\n");
}
cyw43_arch_lwip_begin();
#if CLIENT_TEST
printf("\nReady, running iperf client\n");
ip_addr_t clientaddr;
@@ -61,6 +62,7 @@ int main() {
printf("\nReady, running iperf server at %s\n", ip4addr_ntoa(netif_ip4_addr(netif_list)));
lwiperf_start_tcp_server_default(&iperf_report, NULL);
#endif
cyw43_arch_lwip_end();
while(true) {
#if USE_LED
@@ -83,9 +85,11 @@ int main() {
// you do not need it in your code
#if PICO_CYW43_ARCH_POLL
// if you are using pico_cyw43_arch_poll, then you must poll periodically from your
// main loop (not from a timer) to check for WiFi driver or lwIP work that needs to be done.
// main loop (not from a timer interrupt) to check for Wi-Fi driver or lwIP work that needs to be done.
cyw43_arch_poll();
sleep_ms(1);
// you can poll as often as you like, however if you have nothing else to do you can
// choose to sleep until either a specified time, or cyw43_arch_poll() has work to do:
cyw43_arch_wait_for_work_until(led_time);
#else
// if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work
// is done via interrupt in the background. This sleep is just an example of some (blocking)

Some files were not shown because too many files have changed in this diff Show More