Add Bluetooth support
Co-authored-by: Peter Harper <77111776+peterharperuk@users.noreply.github.com>
This commit is contained in:
parent
0d207f4878
commit
c8ccefb972
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -10,3 +10,6 @@
|
||||
[submodule "lib/mbedtls"]
|
||||
path = lib/mbedtls
|
||||
url = https://github.com/Mbed-TLS/mbedtls.git
|
||||
[submodule "lib/btstack"]
|
||||
path = lib/btstack
|
||||
url = https://github.com/bluekitchen/btstack.git
|
||||
|
@ -62,8 +62,9 @@
|
||||
* \defgroup networking Networking Libraries
|
||||
* Functions for implementing networking
|
||||
* @{
|
||||
* \defgroup pico_cyw43_driver pico_cyw43_driver
|
||||
* \defgroup pico_btstack pico_btstack
|
||||
* \defgroup pico_lwip pico_lwip
|
||||
* \defgroup pico_cyw43_driver pico_cyw43_driver
|
||||
* \defgroup pico_cyw43_arch pico_cyw43_arch
|
||||
* @}
|
||||
*
|
||||
|
1
lib/btstack
Submodule
1
lib/btstack
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 0d212321a995ed2f9a80988f73ede854c7ad23b8
|
@ -1 +1 @@
|
||||
Subproject commit 83e0c700c252b392d33e70a5e9a241b921b166eb
|
||||
Subproject commit 9bfca61173a94432839cd39210f1d1afdf602c42
|
@ -58,10 +58,11 @@ if (NOT PICO_BARE_METAL)
|
||||
pico_add_subdirectory(cmsis)
|
||||
pico_add_subdirectory(tinyusb)
|
||||
pico_add_subdirectory(pico_stdio_usb)
|
||||
|
||||
pico_add_subdirectory(pico_i2c_slave)
|
||||
|
||||
# networking libraries - note dependency order is important
|
||||
pico_add_subdirectory(pico_async_context)
|
||||
pico_add_subdirectory(pico_btstack)
|
||||
pico_add_subdirectory(pico_cyw43_driver)
|
||||
pico_add_subdirectory(pico_lwip)
|
||||
pico_add_subdirectory(pico_cyw43_arch)
|
||||
|
@ -168,10 +168,12 @@ void async_context_freertos_acquire_lock_blocking(async_context_t *self_base) {
|
||||
self->nesting++;
|
||||
}
|
||||
|
||||
void async_context_freertos_lock_check(async_context_t *self_base) {
|
||||
void async_context_freertos_lock_check(__unused async_context_t *self_base) {
|
||||
#ifndef NDEBUG
|
||||
async_context_freertos_t *self = (async_context_freertos_t *)self_base;
|
||||
// Lock the other core and stop low_prio_irq running
|
||||
assert(xSemaphoreGetMutexHolder(self->lock_mutex) == xTaskGetCurrentTaskHandle());
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef struct sync_func_call{
|
||||
|
353
src/rp2_common/pico_btstack/CMakeLists.txt
Normal file
353
src/rp2_common/pico_btstack/CMakeLists.txt
Normal file
@ -0,0 +1,353 @@
|
||||
if (DEFINED ENV{PICO_BTSTACK_PATH} AND (NOT PICO_BTSTACK_PATH))
|
||||
set(PICO_BTSTACK_PATH $ENV{PICO_BTSTACK_PATH})
|
||||
message("Using PICO_BTSTACK_PATH from environment ('${PICO_BTSTACK_PATH}')")
|
||||
endif ()
|
||||
|
||||
set(BTSTACK_TEST_PATH "src/bluetooth.h")
|
||||
if (NOT PICO_BTSTACK_PATH)
|
||||
set(PICO_BTSTACK_PATH ${PROJECT_SOURCE_DIR}/lib/btstack)
|
||||
if (PICO_CYW43_SUPPORTED AND NOT EXISTS ${PICO_BTSTACK_PATH}/${BTSTACK_TEST_PATH})
|
||||
message(WARNING "btstack submodule has not been initialized; Pico W BLE support will be unavailable.
|
||||
hint: try 'git submodule update --init' from your SDK directory (${PICO_SDK_PATH}).")
|
||||
endif()
|
||||
elseif (NOT EXISTS ${PICO_BTSTACK_PATH}/${BTSTACK_TEST_PATH})
|
||||
message(WARNING "PICO_BTSTACK_PATH specified but content not present.")
|
||||
endif()
|
||||
|
||||
if (EXISTS ${PICO_BTSTACK_PATH}/${BTSTACK_TEST_PATH})
|
||||
message("BTstack available at ${PICO_BTSTACK_PATH}")
|
||||
|
||||
pico_register_common_scope_var(PICO_BTSTACK_PATH)
|
||||
|
||||
pico_add_library(pico_btstack_base NOFLAG)
|
||||
target_include_directories(pico_btstack_base_headers INTERFACE
|
||||
${PICO_BTSTACK_PATH}/src
|
||||
${PICO_BTSTACK_PATH}/platform/embedded
|
||||
)
|
||||
|
||||
target_sources(pico_btstack_base INTERFACE
|
||||
${PICO_BTSTACK_PATH}/3rd-party/micro-ecc/uECC.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/rijndael/rijndael.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/segger-rtt/SEGGER_RTT.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/segger-rtt/SEGGER_RTT_printf.c
|
||||
${PICO_BTSTACK_PATH}/platform/embedded/btstack_tlv_flash_bank.c
|
||||
${PICO_BTSTACK_PATH}/platform/embedded/hci_dump_embedded_stdout.c
|
||||
${PICO_BTSTACK_PATH}/platform/embedded/hci_dump_segger_rtt_stdout.c
|
||||
${PICO_BTSTACK_PATH}/src/ad_parser.c
|
||||
${PICO_BTSTACK_PATH}/src/btstack_base64_decoder.c
|
||||
${PICO_BTSTACK_PATH}/src/btstack_crypto.c
|
||||
${PICO_BTSTACK_PATH}/src/btstack_hid_parser.c
|
||||
${PICO_BTSTACK_PATH}/src/btstack_linked_list.c
|
||||
${PICO_BTSTACK_PATH}/src/btstack_memory.c
|
||||
${PICO_BTSTACK_PATH}/src/btstack_memory_pool.c
|
||||
${PICO_BTSTACK_PATH}/src/btstack_resample.c
|
||||
${PICO_BTSTACK_PATH}/src/btstack_ring_buffer.c
|
||||
${PICO_BTSTACK_PATH}/src/btstack_run_loop.c
|
||||
${PICO_BTSTACK_PATH}/src/btstack_run_loop_base.c
|
||||
${PICO_BTSTACK_PATH}/src/btstack_slip.c
|
||||
${PICO_BTSTACK_PATH}/src/btstack_tlv.c
|
||||
${PICO_BTSTACK_PATH}/src/btstack_tlv_none.c
|
||||
${PICO_BTSTACK_PATH}/src/btstack_util.c
|
||||
${PICO_BTSTACK_PATH}/src/hci.c
|
||||
${PICO_BTSTACK_PATH}/src/hci_cmd.c
|
||||
${PICO_BTSTACK_PATH}/src/hci_dump.c
|
||||
${PICO_BTSTACK_PATH}/src/l2cap.c
|
||||
${PICO_BTSTACK_PATH}/src/l2cap_signaling.c
|
||||
${PICO_BTSTACK_PATH}/src/mesh/gatt-service/mesh_provisioning_service_server.c
|
||||
${PICO_BTSTACK_PATH}/src/mesh/gatt-service/mesh_proxy_service_server.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/md5/md5.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/yxml/yxml.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/btstack_stdin_pico.c
|
||||
)
|
||||
target_include_directories(pico_btstack_base_headers INTERFACE
|
||||
${PICO_BTSTACK_PATH}/
|
||||
${PICO_BTSTACK_PATH}/3rd-party/md5
|
||||
${PICO_BTSTACK_PATH}/3rd-party/yxml
|
||||
${PICO_BTSTACK_PATH}/3rd-party/rijndael
|
||||
${PICO_BTSTACK_PATH}/3rd-party/micro-ecc
|
||||
${PICO_BTSTACK_PATH}/3rd-party/segger-rtt
|
||||
)
|
||||
|
||||
pico_add_library(pico_btstack_ble)
|
||||
target_sources(pico_btstack_ble INTERFACE
|
||||
${PICO_BTSTACK_PATH}/src/ble/att_db.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/att_db_util.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/att_dispatch.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/att_server.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/gatt-service/battery_service_server.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/gatt-service/battery_service_client.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/gatt-service/cycling_power_service_server.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/gatt-service/cycling_speed_and_cadence_service_server.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/gatt-service/device_information_service_server.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/gatt-service/device_information_service_client.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/gatt-service/heart_rate_service_server.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/gatt-service/hids_client.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/gatt-service/hids_device.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/gatt-service/nordic_spp_service_server.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/gatt-service/ublox_spp_service_server.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/gatt-service/ancs_client.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/gatt_client.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/le_device_db_memory.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/le_device_db_tlv.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/sm.c
|
||||
)
|
||||
pico_mirrored_target_link_libraries(pico_btstack_ble INTERFACE
|
||||
pico_btstack_base
|
||||
)
|
||||
target_compile_definitions(pico_btstack_ble INTERFACE
|
||||
ENABLE_BLE=1
|
||||
)
|
||||
|
||||
pico_add_library(pico_btstack_classic)
|
||||
target_sources(pico_btstack_classic INTERFACE
|
||||
${PICO_BTSTACK_PATH}/src/classic/a2dp.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/a2dp_sink.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/a2dp_source.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avdtp.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avdtp_acceptor.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avdtp_initiator.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avdtp_sink.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avdtp_source.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avdtp_util.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avrcp.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avrcp_browsing.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avrcp_browsing_controller.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avrcp_browsing_target.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avrcp_controller.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avrcp_media_item_iterator.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avrcp_target.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/btstack_cvsd_plc.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/btstack_link_key_db_tlv.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/btstack_sbc_plc.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/device_id_server.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/gatt_sdp.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/goep_client.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/goep_server.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/hfp.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/hfp_ag.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/hfp_gsm_model.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/hfp_hf.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/hfp_msbc.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/hid_device.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/hid_host.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/hsp_ag.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/hsp_hs.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/obex_iterator.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/obex_message_builder.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/obex_parser.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/pan.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/pbap_client.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/rfcomm.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/sdp_client.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/sdp_client_rfcomm.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/sdp_server.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/sdp_util.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/spp_server.c
|
||||
)
|
||||
pico_mirrored_target_link_libraries(pico_btstack_classic INTERFACE
|
||||
pico_btstack_base
|
||||
)
|
||||
target_compile_definitions(pico_btstack_classic INTERFACE
|
||||
ENABLE_CLASSIC=1
|
||||
)
|
||||
|
||||
pico_add_library(pico_btstack_flash_bank)
|
||||
target_sources(pico_btstack_flash_bank INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/btstack_flash_bank.c
|
||||
)
|
||||
target_include_directories(pico_btstack_flash_bank_headers INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
|
||||
pico_add_library(pico_btstack_run_loop_async_context NOFLAG)
|
||||
target_sources(pico_btstack_run_loop_async_context INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/btstack_run_loop_async_context.c
|
||||
)
|
||||
target_include_directories(pico_btstack_run_loop_async_context_headers INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
pico_mirrored_target_link_libraries(pico_btstack_run_loop_async_context INTERFACE pico_btstack_base pico_async_context_base)
|
||||
|
||||
pico_add_library(pico_btstack_sbc_encoder NOFLAG)
|
||||
target_sources(pico_btstack_sbc_encoder INTERFACE
|
||||
# SBC codec for A2DP and HFP demos
|
||||
${PICO_BTSTACK_PATH}/src/classic/btstack_sbc_encoder_bluedroid.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/encoder/srce/sbc_analysis.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/encoder/srce/sbc_dct.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/encoder/srce/sbc_dct_coeffs.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/encoder/srce/sbc_enc_bit_alloc_mono.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/encoder/srce/sbc_enc_bit_alloc_ste.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/encoder/srce/sbc_enc_coeffs.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/encoder/srce/sbc_encoder.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/encoder/srce/sbc_packing.c
|
||||
)
|
||||
target_include_directories(pico_btstack_sbc_encoder_headers INTERFACE
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/encoder/include
|
||||
)
|
||||
|
||||
pico_add_library(pico_btstack_sbc_decoder NOFLAG)
|
||||
target_sources(pico_btstack_sbc_decoder INTERFACE
|
||||
${PICO_BTSTACK_PATH}/src/classic/btstack_sbc_decoder_bluedroid.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/decoder/srce/alloc.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/decoder/srce/bitalloc.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/decoder/srce/bitalloc-sbc.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/decoder/srce/bitstream-decode.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/decoder/srce/decoder-oina.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/decoder/srce/decoder-private.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/decoder/srce/decoder-sbc.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/decoder/srce/dequant.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/decoder/srce/framing.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/decoder/srce/framing-sbc.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/decoder/srce/oi_codec_version.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/decoder/srce/synthesis-sbc.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/decoder/srce/synthesis-dct8.c
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/decoder/srce/synthesis-8-generated.c
|
||||
)
|
||||
target_include_directories(pico_btstack_sbc_decoder_headers INTERFACE
|
||||
${PICO_BTSTACK_PATH}/3rd-party/bluedroid/decoder/include
|
||||
)
|
||||
|
||||
pico_add_library(pico_btstack_bnep_lwip NOFLAG)
|
||||
target_sources(pico_btstack_bnep_lwip INTERFACE
|
||||
${PICO_BTSTACK_PATH}/src/classic/bnep.c
|
||||
${PICO_BTSTACK_PATH}/platform/lwip/bnep_lwip.c
|
||||
)
|
||||
target_include_directories(pico_btstack_bnep_lwip_headers INTERFACE
|
||||
${PICO_BTSTACK_PATH}/platform/lwip
|
||||
)
|
||||
|
||||
pico_add_library(pico_btstack_bnep_lwip_sys_freertos NOFLAG)
|
||||
target_include_directories(pico_btstack_bnep_lwip_sys_freertos INTERFACE
|
||||
${PICO_BTSTACK_PATH}/platform/freertos
|
||||
)
|
||||
pico_mirrored_target_link_libraries(pico_btstack_bnep_lwip_sys_freertos INTERFACE
|
||||
pico_btstack_bnep_lwip
|
||||
)
|
||||
target_compile_definitions(pico_btstack_bnep_lwip_sys_freertos INTERFACE
|
||||
LWIP_PROVIDE_ERRNO=1
|
||||
PICO_LWIP_CUSTOM_LOCK_TCPIP_CORE=1
|
||||
)
|
||||
|
||||
pico_promote_common_scope_vars()
|
||||
|
||||
# Make a GATT header file from a BTstack GATT file
|
||||
# Pass the target library name library type and path to the GATT input file
|
||||
function(pico_btstack_make_gatt_header TARGET_LIB TARGET_TYPE GATT_FILE)
|
||||
find_package (Python3 REQUIRED COMPONENTS Interpreter)
|
||||
get_filename_component(GATT_NAME "${GATT_FILE}" NAME_WE)
|
||||
get_filename_component(GATT_PATH "${GATT_FILE}" PATH)
|
||||
set(GATT_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
|
||||
set(GATT_HEADER "${GATT_BINARY_DIR}/${GATT_NAME}.h")
|
||||
set(TARGET_GATT "${TARGET_LIB}_gatt_header")
|
||||
|
||||
add_custom_target(${TARGET_GATT} DEPENDS ${GATT_HEADER})
|
||||
add_custom_command(
|
||||
OUTPUT ${GATT_HEADER}
|
||||
DEPENDS ${GATT_FILE}
|
||||
WORKING_DIRECTORY ${GATT_PATH}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${GATT_BINARY_DIR} &&
|
||||
${Python3_EXECUTABLE} ${PICO_SDK_PATH}/lib/btstack/tool/compile_gatt.py ${GATT_FILE} ${GATT_HEADER}
|
||||
VERBATIM)
|
||||
add_dependencies(${TARGET_LIB}
|
||||
${TARGET_GATT}
|
||||
)
|
||||
target_include_directories(${TARGET_LIB} ${TARGET_TYPE}
|
||||
${GATT_BINARY_DIR}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(suppress_btstack_warnings)
|
||||
set_source_files_properties(
|
||||
${PICO_BTSTACK_PATH}/src/ble/att_server.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/gatt-service/device_information_service_server.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/gatt-service/hids_client.c
|
||||
${PICO_BTSTACK_PATH}/src/btstack_util.c
|
||||
${PICO_BTSTACK_PATH}/src/btstack_crypto.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/a2dp.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/a2dp_sink.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/a2dp_source.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avdtp.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avdtp_source.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avrcp.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avrcp_controller.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/btstack_sbc_decoder_bluedroid.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avrcp_target.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/hid_device.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/hsp_ag.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/hsp_hs.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/pan.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/pbap_client.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/rfcomm.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/sdp_client_rfcomm.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/sdp_server.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/spp_server.c
|
||||
PROPERTIES
|
||||
COMPILE_OPTIONS "-Wno-cast-qual"
|
||||
)
|
||||
set_source_files_properties(
|
||||
${PICO_BTSTACK_PATH}/src/ble/sm.c
|
||||
${PICO_BTSTACK_PATH}/src/l2cap.c
|
||||
PROPERTIES
|
||||
COMPILE_OPTIONS "-Wno-cast-qual;-Wno-unused-parameter"
|
||||
)
|
||||
set_source_files_properties(
|
||||
${PICO_BTSTACK_PATH}/src/btstack_hid_parser.c
|
||||
PROPERTIES
|
||||
COMPILE_OPTIONS "-Wno-maybe-uninitialized"
|
||||
)
|
||||
set_source_files_properties(
|
||||
${PICO_BTSTACK_PATH}/src/btstack_tlv_none.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/avdtp_util.c
|
||||
PROPERTIES
|
||||
COMPILE_OPTIONS "-Wno-unused-parameter"
|
||||
)
|
||||
set_source_files_properties(
|
||||
${PICO_BTSTACK_PATH}/platform/embedded/hci_dump_embedded_stdout.c
|
||||
PROPERTIES
|
||||
COMPILE_OPTIONS "-Wno-suggest-attribute=format"
|
||||
)
|
||||
set_source_files_properties(
|
||||
${PICO_BTSTACK_PATH}/src/hci.c
|
||||
${PICO_BTSTACK_PATH}/src/classic/rfcomm.c
|
||||
PROPERTIES
|
||||
COMPILE_OPTIONS "-Wno-cast-qual;-Wno-format"
|
||||
)
|
||||
set_source_files_properties(
|
||||
${PICO_BTSTACK_PATH}/platform/embedded/hal_flash_bank_memory.c
|
||||
PROPERTIES
|
||||
COMPILE_OPTIONS "-Wno-sign-compare;-Wno-format"
|
||||
)
|
||||
set_source_files_properties(
|
||||
${PICO_BTSTACK_PATH}/platform/embedded/btstack_tlv_flash_bank.c
|
||||
PROPERTIES
|
||||
COMPILE_OPTIONS "-Wno-unused-parameter;-Wno-sign-compare"
|
||||
)
|
||||
set_source_files_properties(
|
||||
${PICO_BTSTACK_PATH}/src/ble/gatt-service/hids_client.c
|
||||
PROPERTIES
|
||||
COMPILE_OPTIONS "-Wno-cast-qual;-Wno-null-dereference"
|
||||
)
|
||||
set_source_files_properties(
|
||||
${PICO_BTSTACK_PATH}/src/classic/hfp.c
|
||||
PROPERTIES
|
||||
COMPILE_OPTIONS "-Wno-cast-qual;-Wno-null-dereference;-Wno-unused-parameter"
|
||||
)
|
||||
set_source_files_properties(
|
||||
${PICO_BTSTACK_PATH}/src/classic/goep_server.c
|
||||
PROPERTIES
|
||||
COMPILE_OPTIONS "-Wno-unused-parameter;-Wno-null-dereference"
|
||||
)
|
||||
set_source_files_properties(
|
||||
${PICO_BTSTACK_PATH}/src/ble/gatt-service/battery_service_client.c
|
||||
${PICO_BTSTACK_PATH}/src/ble/gatt-service/device_information_service_client.c
|
||||
PROPERTIES
|
||||
COMPILE_OPTIONS "-Wno-null-dereference"
|
||||
)
|
||||
set_source_files_properties(
|
||||
${PICO_BTSTACK_PATH}/src/classic/hfp_hf.c
|
||||
PROPERTIES
|
||||
COMPILE_OPTIONS "-Wno-type-limits;-Wno-stringop-overflow"
|
||||
)
|
||||
set_source_files_properties(
|
||||
${PICO_BTSTACK_PATH}/src/btstack_crypto.c
|
||||
PROPERTIES
|
||||
COMPILE_OPTIONS "-Wno-cast-qual;-Wno-sign-compare"
|
||||
)
|
||||
endfunction()
|
||||
endif()
|
144
src/rp2_common/pico_btstack/btstack_flash_bank.c
Normal file
144
src/rp2_common/pico_btstack/btstack_flash_bank.c
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "pico/btstack_flash_bank.h"
|
||||
#include "hardware/flash.h"
|
||||
#include "hardware/sync.h"
|
||||
#include <string.h>
|
||||
|
||||
// Check sizes
|
||||
static_assert(PICO_FLASH_BANK_TOTAL_SIZE % (FLASH_SECTOR_SIZE * 2) == 0, "PICO_FLASH_BANK_TOTAL_SIZE invalid");
|
||||
static_assert(PICO_FLASH_BANK_TOTAL_SIZE <= PICO_FLASH_SIZE_BYTES, "PICO_FLASH_BANK_TOTAL_SIZE too big");
|
||||
static_assert(PICO_FLASH_BANK_STORAGE_OFFSET + PICO_FLASH_BANK_TOTAL_SIZE <= PICO_FLASH_SIZE_BYTES, "PICO_FLASH_BANK_TOTAL_SIZE too big");
|
||||
|
||||
// Size of one bank
|
||||
#define PICO_FLASH_BANK_SIZE (PICO_FLASH_BANK_TOTAL_SIZE / 2)
|
||||
|
||||
#if 0
|
||||
#define DEBUG_PRINT(format,args...) printf(format, ## args)
|
||||
#else
|
||||
#define DEBUG_PRINT(...)
|
||||
#endif
|
||||
|
||||
static uint32_t pico_flash_bank_get_size(void * context) {
|
||||
(void)(context);
|
||||
return PICO_FLASH_BANK_SIZE;
|
||||
}
|
||||
|
||||
static uint32_t pico_flash_bank_get_alignment(void * context) {
|
||||
(void)(context);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void pico_flash_bank_erase(void * context, int bank) {
|
||||
(void)(context);
|
||||
DEBUG_PRINT("erase: bank %d\n", bank);
|
||||
uint32_t status = save_and_disable_interrupts();
|
||||
flash_range_erase(PICO_FLASH_BANK_STORAGE_OFFSET + (PICO_FLASH_BANK_SIZE * bank), PICO_FLASH_BANK_SIZE);
|
||||
restore_interrupts(status);
|
||||
}
|
||||
|
||||
static void pico_flash_bank_read(void *context, int bank, uint32_t offset, uint8_t *buffer, uint32_t size) {
|
||||
(void)(context);
|
||||
DEBUG_PRINT("read: bank %d offset %u size %u\n", bank, offset, size);
|
||||
|
||||
assert(bank <= 1);
|
||||
if (bank > 1) return;
|
||||
|
||||
assert(offset < PICO_FLASH_BANK_SIZE);
|
||||
if (offset >= PICO_FLASH_BANK_SIZE) return;
|
||||
|
||||
assert((offset + size) <= PICO_FLASH_BANK_SIZE);
|
||||
if ((offset + size) > PICO_FLASH_BANK_SIZE) return;
|
||||
|
||||
// Flash is xip
|
||||
memcpy(buffer, (void *)(XIP_BASE + PICO_FLASH_BANK_STORAGE_OFFSET + (PICO_FLASH_BANK_SIZE * bank) + offset), size);
|
||||
}
|
||||
|
||||
static void pico_flash_bank_write(void * context, int bank, uint32_t offset, const uint8_t *data, uint32_t size) {
|
||||
(void)(context);
|
||||
DEBUG_PRINT("write: bank %d offset %u size %u\n", bank, offset, size);
|
||||
|
||||
assert(bank <= 1);
|
||||
if (bank > 1) return;
|
||||
|
||||
assert(offset < PICO_FLASH_BANK_SIZE);
|
||||
if (offset >= PICO_FLASH_BANK_SIZE) return;
|
||||
|
||||
assert((offset + size) <= PICO_FLASH_BANK_SIZE);
|
||||
if ((offset + size) > PICO_FLASH_BANK_SIZE) return;
|
||||
|
||||
if (size == 0) return;
|
||||
|
||||
// calc bank start position
|
||||
const uint32_t bank_start_pos = PICO_FLASH_BANK_STORAGE_OFFSET + (PICO_FLASH_BANK_SIZE * bank);
|
||||
|
||||
// Calculate first and last page in the bank
|
||||
const uint32_t first_page = offset / FLASH_PAGE_SIZE;
|
||||
const uint32_t last_page = (offset + size + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE;
|
||||
|
||||
// Now we only care about the offset in the first page
|
||||
offset %= FLASH_PAGE_SIZE;
|
||||
|
||||
// Amount of data we've copied
|
||||
uint32_t data_pos = 0;
|
||||
uint32_t size_left = size;
|
||||
|
||||
// Write all the pages required
|
||||
for(uint32_t page = first_page; page < last_page; page++) {
|
||||
uint8_t page_data[FLASH_PAGE_SIZE];
|
||||
|
||||
assert(data_pos < size && size_left <= size);
|
||||
|
||||
// Copy data we're not going to overwrite in the first page
|
||||
if (page == first_page && offset > 0) {
|
||||
memcpy(page_data,
|
||||
(void *)(XIP_BASE + bank_start_pos + (page * FLASH_PAGE_SIZE)),
|
||||
offset);
|
||||
}
|
||||
|
||||
// Copy the data we're not going to overwrite in the last page
|
||||
if (page == last_page - 1 && (offset + size_left) < FLASH_PAGE_SIZE) {
|
||||
memcpy(page_data + offset + size_left,
|
||||
(void *)(XIP_BASE + bank_start_pos + (page * FLASH_PAGE_SIZE) + offset + size_left),
|
||||
FLASH_PAGE_SIZE - offset - size_left);
|
||||
}
|
||||
|
||||
// Now copy the new data into the page
|
||||
const uint32_t size_to_copy = MIN(size_left, FLASH_PAGE_SIZE - offset);
|
||||
memcpy(page_data + offset, data + data_pos, size_to_copy);
|
||||
|
||||
data_pos += size_to_copy;
|
||||
size_left -= size_to_copy;
|
||||
|
||||
// zero offset for the following pages
|
||||
offset = 0;
|
||||
|
||||
// Now program the entire page
|
||||
uint32_t status = save_and_disable_interrupts();
|
||||
flash_range_program(bank_start_pos + (page * FLASH_PAGE_SIZE), page_data, FLASH_PAGE_SIZE);
|
||||
restore_interrupts(status);
|
||||
}
|
||||
}
|
||||
|
||||
static const hal_flash_bank_t pico_flash_bank_instance_obj = {
|
||||
/* uint32_t (*get_size)(..) */ &pico_flash_bank_get_size,
|
||||
/* uint32_t (*get_alignment)(..); */ &pico_flash_bank_get_alignment,
|
||||
/* void (*erase)(..); */ &pico_flash_bank_erase,
|
||||
/* void (*read)(..); */ &pico_flash_bank_read,
|
||||
/* void (*write)(..); */ &pico_flash_bank_write,
|
||||
};
|
||||
|
||||
const hal_flash_bank_t *pico_flash_bank_instance(void) {
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Check we're not overlapping the binary in flash
|
||||
extern char __flash_binary_end;
|
||||
assert((uintptr_t)&__flash_binary_end - XIP_BASE <= PICO_FLASH_BANK_STORAGE_OFFSET);
|
||||
#endif
|
||||
|
||||
return &pico_flash_bank_instance_obj;
|
||||
}
|
155
src/rp2_common/pico_btstack/btstack_run_loop_async_context.c
Normal file
155
src/rp2_common/pico_btstack/btstack_run_loop_async_context.c
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "pico/btstack_run_loop_async_context.h"
|
||||
#include "hardware/sync.h"
|
||||
|
||||
static async_context_t *btstack_async_context;
|
||||
static async_at_time_worker_t btstack_timeout_worker;
|
||||
static async_when_pending_worker_t btstack_processing_worker;
|
||||
static void btstack_timeout_reached(async_context_t *context, async_at_time_worker_t *worker);
|
||||
static void btstack_work_pending(async_context_t *context, async_when_pending_worker_t *worker);
|
||||
static volatile bool run_loop_exit;
|
||||
|
||||
static void btstack_run_loop_async_context_init(void) {
|
||||
btstack_run_loop_base_init();
|
||||
btstack_timeout_worker.do_work = btstack_timeout_reached;
|
||||
btstack_processing_worker.do_work = btstack_work_pending;
|
||||
async_context_add_when_pending_worker(btstack_async_context, &btstack_processing_worker);
|
||||
}
|
||||
|
||||
static void btstack_run_loop_async_context_add_data_source(btstack_data_source_t * data_source) {
|
||||
async_context_acquire_lock_blocking(btstack_async_context);
|
||||
btstack_run_loop_base_add_data_source(data_source);
|
||||
async_context_release_lock(btstack_async_context);
|
||||
}
|
||||
|
||||
static bool btstack_run_loop_async_context_remove_data_source(btstack_data_source_t * data_source) {
|
||||
async_context_acquire_lock_blocking(btstack_async_context);
|
||||
bool rc = btstack_run_loop_base_remove_data_source(data_source);
|
||||
async_context_release_lock(btstack_async_context);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void btstack_run_loop_async_context_enable_data_source_callbacks(btstack_data_source_t * data_source, uint16_t callbacks) {
|
||||
async_context_acquire_lock_blocking(btstack_async_context);
|
||||
btstack_run_loop_base_enable_data_source_callbacks(data_source, callbacks);
|
||||
async_context_release_lock(btstack_async_context);
|
||||
}
|
||||
|
||||
static void btstack_run_loop_async_context_disable_data_source_callbacks(btstack_data_source_t * data_source, uint16_t callbacks) {
|
||||
async_context_acquire_lock_blocking(btstack_async_context);
|
||||
btstack_run_loop_base_disable_data_source_callbacks(data_source, callbacks);
|
||||
async_context_release_lock(btstack_async_context);
|
||||
}
|
||||
|
||||
static void btstack_run_loop_async_context_set_timer(btstack_timer_source_t *ts, uint32_t timeout_in_ms){
|
||||
async_context_acquire_lock_blocking(btstack_async_context);
|
||||
ts->timeout = to_ms_since_boot(get_absolute_time()) + timeout_in_ms + 1;
|
||||
async_context_set_work_pending(btstack_async_context, &btstack_processing_worker);
|
||||
async_context_release_lock(btstack_async_context);
|
||||
}
|
||||
|
||||
static void btstack_run_loop_async_context_add_timer(btstack_timer_source_t *timer) {
|
||||
async_context_acquire_lock_blocking(btstack_async_context);
|
||||
btstack_run_loop_base_add_timer(timer);
|
||||
async_context_set_work_pending(btstack_async_context, &btstack_processing_worker);
|
||||
async_context_release_lock(btstack_async_context);
|
||||
}
|
||||
|
||||
static bool btstack_run_loop_async_context_remove_timer(btstack_timer_source_t *timer) {
|
||||
async_context_acquire_lock_blocking(btstack_async_context);
|
||||
bool rc = btstack_run_loop_base_remove_timer(timer);
|
||||
async_context_release_lock(btstack_async_context);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void btstack_run_loop_async_context_dump_timer(void){
|
||||
async_context_acquire_lock_blocking(btstack_async_context);
|
||||
btstack_run_loop_base_dump_timer();
|
||||
async_context_release_lock(btstack_async_context);
|
||||
}
|
||||
|
||||
static uint32_t btstack_run_loop_async_context_get_time_ms(void)
|
||||
{
|
||||
return to_ms_since_boot(get_absolute_time());
|
||||
}
|
||||
|
||||
static void btstack_run_loop_async_context_execute(void)
|
||||
{
|
||||
run_loop_exit = false;
|
||||
while (!run_loop_exit) {
|
||||
async_context_poll(btstack_async_context);
|
||||
async_context_wait_for_work_until(btstack_async_context, at_the_end_of_time);
|
||||
}
|
||||
}
|
||||
|
||||
static void btstack_run_loop_async_context_trigger_exit(void)
|
||||
{
|
||||
run_loop_exit = true;
|
||||
}
|
||||
|
||||
static void btstack_run_loop_async_context_execute_on_main_thread(btstack_context_callback_registration_t *callback_registration)
|
||||
{
|
||||
async_context_acquire_lock_blocking(btstack_async_context);
|
||||
btstack_run_loop_base_add_callback(callback_registration);
|
||||
async_context_set_work_pending(btstack_async_context, &btstack_processing_worker);
|
||||
async_context_release_lock(btstack_async_context);
|
||||
}
|
||||
|
||||
static void btstack_run_loop_async_context_poll_data_sources_from_irq(void)
|
||||
{
|
||||
async_context_set_work_pending(btstack_async_context, &btstack_processing_worker);
|
||||
}
|
||||
|
||||
static const btstack_run_loop_t btstack_run_loop_async_context = {
|
||||
&btstack_run_loop_async_context_init,
|
||||
&btstack_run_loop_async_context_add_data_source,
|
||||
&btstack_run_loop_async_context_remove_data_source,
|
||||
&btstack_run_loop_async_context_enable_data_source_callbacks,
|
||||
&btstack_run_loop_async_context_disable_data_source_callbacks,
|
||||
&btstack_run_loop_async_context_set_timer,
|
||||
&btstack_run_loop_async_context_add_timer,
|
||||
&btstack_run_loop_async_context_remove_timer,
|
||||
&btstack_run_loop_async_context_execute,
|
||||
&btstack_run_loop_async_context_dump_timer,
|
||||
&btstack_run_loop_async_context_get_time_ms,
|
||||
&btstack_run_loop_async_context_poll_data_sources_from_irq,
|
||||
&btstack_run_loop_async_context_execute_on_main_thread,
|
||||
&btstack_run_loop_async_context_trigger_exit,
|
||||
};
|
||||
|
||||
const btstack_run_loop_t *btstack_run_loop_async_context_get_instance(async_context_t *async_context)
|
||||
{
|
||||
assert(!btstack_async_context || btstack_async_context == async_context);
|
||||
btstack_async_context = async_context;
|
||||
return &btstack_run_loop_async_context;
|
||||
}
|
||||
|
||||
static void btstack_timeout_reached(__unused async_context_t *context, __unused async_at_time_worker_t *worker) {
|
||||
// simply wakeup worker
|
||||
async_context_set_work_pending(btstack_async_context, &btstack_processing_worker);
|
||||
}
|
||||
|
||||
static void btstack_work_pending(__unused async_context_t *context, __unused async_when_pending_worker_t *worker) {
|
||||
// poll data sources
|
||||
btstack_run_loop_base_poll_data_sources();
|
||||
|
||||
// execute callbacks
|
||||
btstack_run_loop_base_execute_callbacks();
|
||||
|
||||
uint32_t now = to_ms_since_boot(get_absolute_time());
|
||||
|
||||
// process timers
|
||||
btstack_run_loop_base_process_timers(now);
|
||||
now = to_ms_since_boot(get_absolute_time());
|
||||
int ms = btstack_run_loop_base_get_time_until_timeout(now);
|
||||
if (ms == -1) {
|
||||
async_context_remove_at_time_worker(btstack_async_context, &btstack_timeout_worker);
|
||||
} else {
|
||||
async_context_add_at_time_worker_in_ms(btstack_async_context, &btstack_timeout_worker, ms);
|
||||
}
|
||||
}
|
60
src/rp2_common/pico_btstack/btstack_stdin_pico.c
Normal file
60
src/rp2_common/pico_btstack/btstack_stdin_pico.c
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "btstack_config.h"
|
||||
|
||||
#ifdef HAVE_BTSTACK_STDIN
|
||||
|
||||
#include "btstack_stdin.h"
|
||||
#include "btstack_run_loop.h"
|
||||
#include "pico/stdio.h"
|
||||
|
||||
static btstack_data_source_t stdin_data_source;
|
||||
static void (*stdin_handler)(char c);
|
||||
|
||||
// Data source callback, return any character received
|
||||
static void btstack_stdin_process(__unused struct btstack_data_source *ds, __unused btstack_data_source_callback_type_t callback_type){
|
||||
if (stdin_handler) {
|
||||
while(true) {
|
||||
int c = getchar_timeout_us(0);
|
||||
if (c == PICO_ERROR_TIMEOUT) return;
|
||||
(*stdin_handler)(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void on_chars_available_callback(__unused void *param) {
|
||||
btstack_run_loop_poll_data_sources_from_irq();
|
||||
}
|
||||
|
||||
// Test code calls this if HAVE_BTSTACK_STDIN is defined and it wants key presses
|
||||
void btstack_stdin_setup(void (*handler)(char c)) {
|
||||
if (stdin_handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set handler
|
||||
stdin_handler = handler;
|
||||
|
||||
// set up polling data_source
|
||||
btstack_run_loop_set_data_source_handler(&stdin_data_source, &btstack_stdin_process);
|
||||
btstack_run_loop_enable_data_source_callbacks(&stdin_data_source, DATA_SOURCE_CALLBACK_POLL);
|
||||
btstack_run_loop_add_data_source(&stdin_data_source);
|
||||
|
||||
stdio_set_chars_available_callback(on_chars_available_callback, NULL);
|
||||
}
|
||||
|
||||
// Deinit everything
|
||||
void btstack_stdin_reset(void){
|
||||
if (!stdin_handler) {
|
||||
return;
|
||||
}
|
||||
stdio_set_chars_available_callback(NULL, NULL);
|
||||
stdin_handler = NULL;
|
||||
btstack_run_loop_remove_data_source(&stdin_data_source);
|
||||
}
|
||||
|
||||
#endif
|
25
src/rp2_common/pico_btstack/doc.h
Normal file
25
src/rp2_common/pico_btstack/doc.h
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* \defgroup pico_btstack pico_btstack
|
||||
* \brief Integration/wrapper libraries for <a href="https://github.com/bluekitchen/btstack">BTstack</a>
|
||||
* the documentation for which is <a href="https://bluekitchen-gmbh.com/btstack/">here</a>.
|
||||
*
|
||||
* The \c \b pico_btstack_ble library adds the support needed for Bluetooth Low Energy (BLE). The \c \b pico_btstack_classic library adds the support needed for Bluetooth Classic.
|
||||
* You can link to either library individually, or to both libraries thus enabling dual-mode support provided by BTstack.
|
||||
*
|
||||
* To use BTstack you need to provide a \c btstack_config.h file in your source tree and add its location to your include path.
|
||||
* The BTstack configuration macros \c ENABLE_CLASSIC and \c ENABLE_BLE are defined for you when you link the \c pico_btstack_classic and \c pico_btstack_ble libraries respectively, so you should not define them yourself.
|
||||
*
|
||||
* For more details, see <a href="https://bluekitchen-gmbh.com/btstack/develop/#how_to/">How to configure BTstack</a> and the relevant <a href="https://github.com/raspberrypi/pico-examples#pico-w-bluetooth">pico-examples</a>.
|
||||
*
|
||||
* The follow ibraries provided for you to link.
|
||||
* * \c \b pico_btstack_ble - Adds Bluetooth Low Energy (LE) support.
|
||||
* * \c \b pico_btstack_classic - Adds Bluetooth Classic support.
|
||||
* * \c \b pico_btstack_sbc_encoder - Adds Bluetooth Sub Band Coding (SBC) encoder support.
|
||||
* * \c \b pico_btstack_sbc_decoder - Adds Bluetooth Sub Band Coding (SBC) decoder support.
|
||||
* * \c \b pico_btstack_bnep_lwip - Adds Bluetooth Network Encapsulation Protocol (BNEP) support using LwIP.
|
||||
* * \c \b pico_btstack_bnep_lwip_sys_freertos - Adds Bluetooth Network Encapsulation Protocol (BNEP) support using LwIP with FreeRTOS for NO_SYS=0.
|
||||
*
|
||||
* \note The CMake function pico_btstack_make_gatt_header can be used to run the BTstack compile_gatt tool to make a GATT header file from a BTstack GATT file.
|
||||
*
|
||||
* \sa pico_btstack_cyw43 in pico_cyw43_driver, which adds the cyw43 driver support needed for BTstack including BTstack run loop support.
|
||||
*/
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _PICO_BTSTACK_FLASH_BANK_H
|
||||
#define _PICO_BTSTACK_FLASH_BANK_H
|
||||
|
||||
#include "pico.h"
|
||||
#include "hal_flash_bank.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// PICO_CONFIG: PICO_FLASH_BANK_TOTAL_SIZE, Total size of the Bluetooth flash storage. Must be an even multiple of FLASH_SECTOR_SIZE, type=int default=FLASH_SECTOR_SIZE*2, group=pico_btstack
|
||||
#ifndef PICO_FLASH_BANK_TOTAL_SIZE
|
||||
#define PICO_FLASH_BANK_TOTAL_SIZE (FLASH_SECTOR_SIZE * 2u)
|
||||
#endif
|
||||
|
||||
// PICO_CONFIG: PICO_FLASH_BANK_STORAGE_OFFSET, Offset in flash of the Bluetooth flash storage, type=int default=PICO_FLASH_SIZE_BYTES-PICO_FLASH_BANK_TOTAL_SIZE, group=pico_btstack
|
||||
#ifndef PICO_FLASH_BANK_STORAGE_OFFSET
|
||||
#define PICO_FLASH_BANK_STORAGE_OFFSET (PICO_FLASH_SIZE_BYTES - PICO_FLASH_BANK_TOTAL_SIZE)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Return the singleton BTstack HAL flash instance, used for non-volatile storage
|
||||
* \ingroup pico_btstack
|
||||
*
|
||||
* \note By default two sectors at the end of flash are used (see \c PICO_FLASH_BANK_STORAGE_OFFSET
|
||||
*/
|
||||
const hal_flash_bank_t *pico_flash_bank_instance(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _PICO_BTSTACK_RUN_LOOP_ASYNC_CONTEXT_H
|
||||
#define _PICO_BTSTACK_RUN_LOOP_ASYNC_CONTEXT_H
|
||||
|
||||
#include "btstack_run_loop.h"
|
||||
#include "pico/async_context.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Initialize and eturn the singleton BTstack run loop instance that integrates with the async_context API
|
||||
* \ingroup pico_btstack
|
||||
*
|
||||
* \param context the async_context instance that provides the abstraction for handling asynchronous work.
|
||||
* \return the BTstack run loop instance
|
||||
*/
|
||||
const btstack_run_loop_t *btstack_run_loop_async_context_get_instance(async_context_t *context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -20,7 +20,7 @@ if (PICO_CYW43_SUPPORTED) # set by BOARD=pico-w
|
||||
if (NOT TARGET pico_lwip)
|
||||
message(WARNING "lwIP is not available; Full Pico W wireless support will be unavailable")
|
||||
else()
|
||||
message("Pico W wireless build support available.")
|
||||
message("Pico W Wi-Fi build support available.")
|
||||
pico_add_library(pico_cyw43_arch_poll NOFLAG)
|
||||
target_compile_definitions(pico_cyw43_arch_poll_headers INTERFACE
|
||||
PICO_CYW43_ARCH_POLL=1
|
||||
|
@ -47,7 +47,7 @@ void cyw43_arch_enable_ap_mode(const char *ssid, const char *password, uint32_t
|
||||
|
||||
#if PICO_CYW43_ARCH_DEBUG_ENABLED
|
||||
// Return a string for the wireless state
|
||||
const char* cyw43_tcpip_link_status_name(int status)
|
||||
static const char* cyw43_tcpip_link_status_name(int status)
|
||||
{
|
||||
switch (status) {
|
||||
case CYW43_LINK_DOWN:
|
||||
|
@ -15,6 +15,10 @@
|
||||
#include <lwip/tcpip.h>
|
||||
#endif
|
||||
|
||||
#if CYW43_ENABLE_BLUETOOTH
|
||||
#include "pico/btstack_cyw43.h"
|
||||
#endif
|
||||
|
||||
#if NO_SYS
|
||||
#error example_cyw43_arch_freetos_sys requires NO_SYS=0
|
||||
#endif
|
||||
@ -44,6 +48,9 @@ int cyw43_arch_init(void) {
|
||||
bool ok = cyw43_driver_init(context);
|
||||
#if CYW43_LWIP
|
||||
ok &= lwip_freertos_init(context);
|
||||
#endif
|
||||
#if CYW43_ENABLE_BLUETOOTH
|
||||
ok &= btstack_cyw43_init(context);
|
||||
#endif
|
||||
if (!ok) {
|
||||
cyw43_arch_deinit();
|
||||
@ -55,6 +62,9 @@ int cyw43_arch_init(void) {
|
||||
|
||||
void cyw43_arch_deinit(void) {
|
||||
async_context_t *context = cyw43_arch_async_context();
|
||||
#if CYW43_ENABLE_BLUETOOTH
|
||||
btstack_cyw43_deinit(context);
|
||||
#endif
|
||||
// there is a bit of a circular dependency here between lwIP and cyw43_driver. We
|
||||
// shut down cyw43_driver first as it has IRQs calling back into lwIP. Also lwIP itself
|
||||
// does not actually get shut down.
|
||||
|
@ -13,6 +13,10 @@
|
||||
#include "pico/lwip_nosys.h"
|
||||
#endif
|
||||
|
||||
#if CYW43_ENABLE_BLUETOOTH
|
||||
#include "pico/btstack_cyw43.h"
|
||||
#endif
|
||||
|
||||
#if CYW43_LWIP && !NO_SYS
|
||||
#error PICO_CYW43_ARCH_POLL requires lwIP NO_SYS=1
|
||||
#endif
|
||||
@ -35,6 +39,9 @@ int cyw43_arch_init(void) {
|
||||
bool ok = cyw43_driver_init(context);
|
||||
#if CYW43_LWIP
|
||||
ok &= lwip_nosys_init(context);
|
||||
#endif
|
||||
#if CYW43_ENABLE_BLUETOOTH
|
||||
ok &= btstack_cyw43_init(context);
|
||||
#endif
|
||||
if (!ok) {
|
||||
cyw43_arch_deinit();
|
||||
@ -46,6 +53,9 @@ int cyw43_arch_init(void) {
|
||||
|
||||
void cyw43_arch_deinit(void) {
|
||||
async_context_t *context = cyw43_arch_async_context();
|
||||
#if CYW43_ENABLE_BLUETOOTH
|
||||
btstack_cyw43_deinit(context);
|
||||
#endif
|
||||
// there is a bit of a circular dependency here between lwIP and cyw43_driver. We
|
||||
// shut down cyw43_driver first as it has IRQs calling back into lwIP. Also lwIP itself
|
||||
// does not actually get shut down.
|
||||
|
@ -14,6 +14,10 @@
|
||||
#include "pico/lwip_nosys.h"
|
||||
#endif
|
||||
|
||||
#if CYW43_ENABLE_BLUETOOTH
|
||||
#include "pico/btstack_cyw43.h"
|
||||
#endif
|
||||
|
||||
#if CYW43_LWIP && !NO_SYS
|
||||
#error PICO_CYW43_ARCH_THREADSAFE_BACKGROUND requires lwIP NO_SYS=1
|
||||
#endif
|
||||
@ -41,6 +45,9 @@ int cyw43_arch_init(void) {
|
||||
bool ok = cyw43_driver_init(context);
|
||||
#if CYW43_LWIP
|
||||
ok &= lwip_nosys_init(context);
|
||||
#endif
|
||||
#if CYW43_ENABLE_BLUETOOTH
|
||||
ok &= btstack_cyw43_init(context);
|
||||
#endif
|
||||
if (!ok) {
|
||||
cyw43_arch_deinit();
|
||||
@ -52,6 +59,9 @@ int cyw43_arch_init(void) {
|
||||
|
||||
void cyw43_arch_deinit(void) {
|
||||
async_context_t *context = cyw43_arch_async_context();
|
||||
#if CYW43_ENABLE_BLUETOOTH
|
||||
btstack_cyw43_deinit(context);
|
||||
#endif
|
||||
// there is a bit of a circular dependency here between lwIP and cyw43_driver. We
|
||||
// shut down cyw43_driver first as it has IRQs calling back into lwIP. Also lwIP itself
|
||||
// does not actually get shut down.
|
||||
|
@ -18,6 +18,8 @@ endif()
|
||||
if (EXISTS ${PICO_CYW43_DRIVER_PATH}/${CYW43_DRIVER_TEST_FILE})
|
||||
message("cyw43-driver available at ${PICO_CYW43_DRIVER_PATH}")
|
||||
|
||||
add_subdirectory(cybt_shared_bus)
|
||||
|
||||
pico_register_common_scope_var(PICO_CYW43_DRIVER_PATH)
|
||||
|
||||
# base driver without our bus
|
||||
@ -40,47 +42,51 @@ if (EXISTS ${PICO_CYW43_DRIVER_PATH}/${CYW43_DRIVER_TEST_FILE})
|
||||
target_include_directories(pico_cyw43_driver_headers INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
pico_mirrored_target_link_libraries(pico_cyw43_driver INTERFACE cyw43_driver)
|
||||
|
||||
# Firmware stuff
|
||||
set(CYW43_FIRMWARE_BIN 43439A0-7.95.49.00.combined)
|
||||
string(REGEX REPLACE [\\\.\-] _ CYW43_FIRMWARE_BIN_ ${CYW43_FIRMWARE_BIN})
|
||||
string(REGEX MATCH [^_]+_?[^_]*_?[^_]*_?[^_]*_?[^_]* CYW43_FIRMWARE_PRETTY ${CYW43_FIRMWARE_BIN_})
|
||||
set(CYW43_FIRMWARE_PRETTY fw_${CYW43_FIRMWARE_PRETTY})
|
||||
set(RESOURCE_SECNAME .big_const)
|
||||
set(RESOURCE_SECFLAGS contents,alloc,load,readonly,data)
|
||||
set(CYW43_FIRMWARE_OBJ ${CMAKE_CURRENT_BINARY_DIR}/cyw43_resource.o)
|
||||
|
||||
add_custom_target(cyw43_firmware_package DEPENDS ${CYW43_FIRMWARE_OBJ})
|
||||
|
||||
# cyw43_resource.o contains the WiFi and BT firmware as a binary blob
|
||||
add_custom_command(
|
||||
OUTPUT ${CYW43_FIRMWARE_OBJ}
|
||||
DEPENDS ${PICO_CYW43_DRIVER_PATH}/firmware/${CYW43_FIRMWARE_BIN}
|
||||
WORKING_DIRECTORY ${PICO_CYW43_DRIVER_PATH}/firmware
|
||||
COMMAND ${CMAKE_OBJCOPY} -I binary -O elf32-littlearm -B arm
|
||||
--readonly-text
|
||||
--rename-section .data=${RESOURCE_SECNAME},${RESOURCE_SECFLAGS}
|
||||
--redefine-sym _binary_${CYW43_FIRMWARE_BIN_}_start=${CYW43_FIRMWARE_PRETTY}_start
|
||||
--redefine-sym _binary_${CYW43_FIRMWARE_BIN_}_end=${CYW43_FIRMWARE_PRETTY}_end
|
||||
--redefine-sym _binary_${CYW43_FIRMWARE_BIN_}_size=${CYW43_FIRMWARE_PRETTY}_size
|
||||
${CYW43_FIRMWARE_BIN} ${CYW43_FIRMWARE_OBJ}
|
||||
VERBATIM)
|
||||
|
||||
# cyw43_driver_picow is cyw43_driver plus Pico W specific bus implementation, and Pico W firmware
|
||||
# cyw43_driver_picow is cyw43_driver plus Pico W specific bus implementation
|
||||
pico_add_library(cyw43_driver_picow NOFLAG)
|
||||
target_sources(cyw43_driver_picow INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/cyw43_bus_pio_spi.c
|
||||
)
|
||||
pico_generate_pio_header(cyw43_driver_picow_headers ${CMAKE_CURRENT_LIST_DIR}/cyw43_bus_pio_spi.pio)
|
||||
add_dependencies(cyw43_driver_picow INTERFACE cyw43_firmware_package)
|
||||
target_link_libraries(cyw43_driver_picow INTERFACE
|
||||
${CYW43_FIRMWARE_OBJ}
|
||||
)
|
||||
pico_generate_pio_header(cyw43_driver_picow ${CMAKE_CURRENT_LIST_DIR}/cyw43_bus_pio_spi.pio)
|
||||
pico_mirrored_target_link_libraries(cyw43_driver_picow INTERFACE
|
||||
cyw43_driver
|
||||
cybt_shared_bus
|
||||
hardware_pio
|
||||
hardware_dma
|
||||
hardware_exception
|
||||
)
|
||||
|
||||
# Note: This is used by MP, so check for issues when making changes
|
||||
# e.g. Don't add new depenedences
|
||||
pico_add_library(pico_btstack_hci_transport_cyw43 NOFLAG)
|
||||
target_sources(pico_btstack_hci_transport_cyw43 INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/btstack_hci_transport_cyw43.c
|
||||
)
|
||||
target_include_directories(pico_btstack_hci_transport_cyw43_headers INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/include
|
||||
)
|
||||
target_compile_definitions(pico_btstack_hci_transport_cyw43_headers INTERFACE
|
||||
CYW43_ENABLE_BLUETOOTH=1
|
||||
)
|
||||
|
||||
if (TARGET pico_btstack_base)
|
||||
message("Pico W Bluetooth build support available.")
|
||||
|
||||
pico_add_library(pico_btstack_cyw43)
|
||||
target_sources(pico_btstack_cyw43 INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/btstack_cyw43.c
|
||||
)
|
||||
target_include_directories(pico_btstack_cyw43_headers INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/include
|
||||
)
|
||||
pico_mirrored_target_link_libraries(pico_btstack_cyw43 INTERFACE
|
||||
pico_btstack_base
|
||||
pico_btstack_flash_bank
|
||||
pico_btstack_run_loop_async_context
|
||||
pico_cyw43_arch
|
||||
pico_btstack_hci_transport_cyw43
|
||||
)
|
||||
endif()
|
||||
|
||||
pico_promote_common_scope_vars()
|
||||
endif()
|
||||
|
74
src/rp2_common/pico_cyw43_driver/btstack_cyw43.c
Normal file
74
src/rp2_common/pico_cyw43_driver/btstack_cyw43.c
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "ble/le_device_db_tlv.h"
|
||||
#include "classic/btstack_link_key_db_tlv.h"
|
||||
#include "btstack_tlv.h"
|
||||
#include "btstack_tlv_flash_bank.h"
|
||||
#include "btstack_memory.h"
|
||||
#include "hci.h"
|
||||
|
||||
#if WANT_HCI_DUMP
|
||||
#include "hci_dump.h"
|
||||
#ifdef ENABLE_SEGGER_RTT
|
||||
#include "hci_dump_segger_rtt_stdout.h"
|
||||
#else
|
||||
#include "hci_dump_embedded_stdout.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "pico/btstack_hci_transport_cyw43.h"
|
||||
#include "pico/btstack_run_loop_async_context.h"
|
||||
#include "pico/btstack_flash_bank.h"
|
||||
#include "pico/btstack_cyw43.h"
|
||||
|
||||
static void setup_tlv(void) {
|
||||
static btstack_tlv_flash_bank_t btstack_tlv_flash_bank_context;
|
||||
const hal_flash_bank_t *hal_flash_bank_impl = pico_flash_bank_instance();
|
||||
|
||||
const btstack_tlv_t *btstack_tlv_impl = btstack_tlv_flash_bank_init_instance(
|
||||
&btstack_tlv_flash_bank_context,
|
||||
hal_flash_bank_impl,
|
||||
NULL);
|
||||
|
||||
// setup global TLV
|
||||
btstack_tlv_set_instance(btstack_tlv_impl, &btstack_tlv_flash_bank_context);
|
||||
#ifdef ENABLE_CLASSIC
|
||||
const btstack_link_key_db_t *btstack_link_key_db = btstack_link_key_db_tlv_get_instance(btstack_tlv_impl, &btstack_tlv_flash_bank_context);
|
||||
hci_set_link_key_db(btstack_link_key_db);
|
||||
#endif
|
||||
#ifdef ENABLE_BLE
|
||||
// configure LE Device DB for TLV
|
||||
le_device_db_tlv_configure(btstack_tlv_impl, &btstack_tlv_flash_bank_context);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool btstack_cyw43_init(async_context_t *context) {
|
||||
// Initialise bluetooth
|
||||
btstack_memory_init();
|
||||
btstack_run_loop_init(btstack_run_loop_async_context_get_instance(context));
|
||||
|
||||
#if WANT_HCI_DUMP
|
||||
#ifdef ENABLE_SEGGER_RTT
|
||||
hci_dump_init(hci_dump_segger_rtt_stdout_get_instance());
|
||||
#else
|
||||
hci_dump_init(hci_dump_embedded_stdout_get_instance());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
hci_init(hci_transport_cyw43_instance(), NULL);
|
||||
|
||||
// setup TLV storage
|
||||
setup_tlv();
|
||||
return true;
|
||||
}
|
||||
|
||||
void btstack_cyw43_deinit(__unused async_context_t *context) {
|
||||
hci_power_control(HCI_POWER_OFF);
|
||||
hci_close();
|
||||
btstack_run_loop_deinit();
|
||||
btstack_memory_deinit();
|
||||
}
|
149
src/rp2_common/pico_cyw43_driver/btstack_hci_transport_cyw43.c
Normal file
149
src/rp2_common/pico_cyw43_driver/btstack_hci_transport_cyw43.c
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "pico.h"
|
||||
#include "cyw43.h"
|
||||
#include "hci_transport.h"
|
||||
#include "hci.h"
|
||||
#include "pico/btstack_hci_transport_cyw43.h"
|
||||
|
||||
// assert outgoing pre-buffer for cyw43 header is available
|
||||
#if !defined(HCI_OUTGOING_PRE_BUFFER_SIZE) || (HCI_OUTGOING_PRE_BUFFER_SIZE < 4)
|
||||
#error HCI_OUTGOING_PRE_BUFFER_SIZE not defined or smaller than 4. Please update btstack_config.h
|
||||
#endif
|
||||
|
||||
// assert outgoing packet fragments are word aligned
|
||||
#if !defined(HCI_ACL_CHUNK_SIZE_ALIGNMENT) || ((HCI_ACL_CHUNK_SIZE_ALIGNMENT & 3) != 0)
|
||||
#error HCI_ACL_CHUNK_SIZE_ALIGNMENT not defined or not a multiply of 4. Please update btstack_config.h
|
||||
#endif
|
||||
|
||||
#define BT_DEBUG_ENABLED 0
|
||||
#if BT_DEBUG_ENABLED
|
||||
#define BT_DEBUG(...) CYW43_PRINTF(__VA_ARGS__)
|
||||
#else
|
||||
#define BT_DEBUG(...) (void)0
|
||||
#endif
|
||||
|
||||
// Callback when we have data
|
||||
static void (*hci_transport_cyw43_packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size) = NULL;
|
||||
|
||||
// Incoming packet buffer - cyw43 packet header (incl packet type) + incoming pre buffer + max(acl header + acl payload, event header + event data)
|
||||
__attribute__((aligned(4)))
|
||||
static uint8_t hci_packet_with_pre_buffer[4 + HCI_INCOMING_PRE_BUFFER_SIZE + HCI_INCOMING_PACKET_BUFFER_SIZE ];
|
||||
|
||||
static btstack_data_source_t transport_data_source;
|
||||
static bool hci_transport_ready;
|
||||
|
||||
// Forward declaration
|
||||
static void hci_transport_cyw43_process(void);
|
||||
|
||||
static void hci_transport_data_source_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
|
||||
assert(callback_type == DATA_SOURCE_CALLBACK_POLL);
|
||||
assert(ds == &transport_data_source);
|
||||
(void)callback_type;
|
||||
(void)ds;
|
||||
hci_transport_cyw43_process();
|
||||
}
|
||||
|
||||
static void hci_transport_cyw43_init(const void *transport_config) {
|
||||
UNUSED(transport_config);
|
||||
}
|
||||
|
||||
static int hci_transport_cyw43_open(void) {
|
||||
int err = cyw43_bluetooth_hci_init();
|
||||
if (err != 0) {
|
||||
CYW43_PRINTF("Failed to open cyw43 hci controller: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
btstack_run_loop_set_data_source_handler(&transport_data_source, &hci_transport_data_source_process);
|
||||
btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_POLL);
|
||||
btstack_run_loop_add_data_source(&transport_data_source);
|
||||
hci_transport_ready = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hci_transport_cyw43_close(void) {
|
||||
btstack_run_loop_disable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_POLL);
|
||||
btstack_run_loop_remove_data_source(&transport_data_source);
|
||||
hci_transport_ready = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hci_transport_cyw43_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)) {
|
||||
hci_transport_cyw43_packet_handler = handler;
|
||||
}
|
||||
|
||||
static int hci_transport_cyw43_can_send_now(uint8_t packet_type) {
|
||||
UNUSED(packet_type);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int hci_transport_cyw43_send_packet(uint8_t packet_type, uint8_t *packet, int size) {
|
||||
// store packet type before actual data and increase size
|
||||
// This relies on HCI_OUTGOING_PRE_BUFFER_SIZE being set
|
||||
uint8_t *buffer = &packet[-4];
|
||||
uint32_t buffer_size = size + 4;
|
||||
buffer[3] = packet_type;
|
||||
|
||||
CYW43_THREAD_ENTER
|
||||
int err = cyw43_bluetooth_hci_write(buffer, buffer_size);
|
||||
|
||||
if (err != 0) {
|
||||
CYW43_PRINTF("Failed to send cyw43 hci packet: %d\n", err);
|
||||
assert(false);
|
||||
} else {
|
||||
BT_DEBUG("bt sent %lu\n", buffer_size);
|
||||
static uint8_t packet_sent_event[] = { HCI_EVENT_TRANSPORT_PACKET_SENT, 0};
|
||||
hci_transport_cyw43_packet_handler(HCI_EVENT_PACKET, &packet_sent_event[0], sizeof(packet_sent_event));
|
||||
}
|
||||
CYW43_THREAD_EXIT
|
||||
return err;
|
||||
}
|
||||
|
||||
// configure and return hci transport singleton
|
||||
static const hci_transport_t hci_transport_cyw43 = {
|
||||
/* const char * name; */ "CYW43",
|
||||
/* void (*init) (const void *transport_config); */ &hci_transport_cyw43_init,
|
||||
/* int (*open)(void); */ &hci_transport_cyw43_open,
|
||||
/* int (*close)(void); */ &hci_transport_cyw43_close,
|
||||
/* void (*register_packet_handler)(void (*handler)(...); */ &hci_transport_cyw43_register_packet_handler,
|
||||
/* int (*can_send_packet_now)(uint8_t packet_type); */ &hci_transport_cyw43_can_send_now,
|
||||
/* int (*send_packet)(...); */ &hci_transport_cyw43_send_packet,
|
||||
/* int (*set_baudrate)(uint32_t baudrate); */ NULL,
|
||||
/* void (*reset_link)(void); */ NULL,
|
||||
/* void (*set_sco_config)(uint16_t voice_setting, int num_connections); */ NULL,
|
||||
};
|
||||
|
||||
const hci_transport_t *hci_transport_cyw43_instance(void) {
|
||||
return &hci_transport_cyw43;
|
||||
}
|
||||
|
||||
// Called to perform bt work from a data source
|
||||
static void hci_transport_cyw43_process(void) {
|
||||
CYW43_THREAD_LOCK_CHECK
|
||||
uint32_t len = 0;
|
||||
bool has_work;
|
||||
do {
|
||||
int err = cyw43_bluetooth_hci_read(hci_packet_with_pre_buffer, sizeof(hci_packet_with_pre_buffer), &len);
|
||||
BT_DEBUG("bt in len=%lu err=%d\n", len, err);
|
||||
if (err == 0 && len > 0) {
|
||||
hci_transport_cyw43_packet_handler(hci_packet_with_pre_buffer[3], hci_packet_with_pre_buffer + 4, len - 4);
|
||||
has_work = true;
|
||||
} else {
|
||||
has_work = false;
|
||||
}
|
||||
} while (has_work);
|
||||
}
|
||||
|
||||
// This is called from cyw43_poll_func.
|
||||
void cyw43_bluetooth_hci_process(void) {
|
||||
if (hci_transport_ready) {
|
||||
btstack_run_loop_poll_data_sources_from_irq();
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
# cyw43 shared bus read and write
|
||||
pico_add_library(cybt_shared_bus NOFLAG)
|
||||
|
||||
target_sources(cybt_shared_bus INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/cybt_shared_bus.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/cybt_shared_bus_driver.c
|
||||
)
|
||||
target_include_directories(cybt_shared_bus_headers INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
# The BT firmware is supplied as a source file containing a static array with ascii hex data
|
||||
# Set this to true to use this for testing
|
||||
set(CYW43_USE_HEX_BTFW 0)
|
||||
if (CYW43_USE_HEX_BTFW)
|
||||
message("Warning: CYW43_USE_HEX_BTFW is true")
|
||||
target_sources(cybt_shared_bus INTERFACE
|
||||
${PICO_CYW43_DRIVER_PATH}/firmware/cybt_firmware_43439.c
|
||||
)
|
||||
target_compile_definitions(cybt_shared_bus INTERFACE
|
||||
CYW43_USE_HEX_BTFW=1
|
||||
)
|
||||
endif()
|
@ -0,0 +1,431 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "cyw43_btbus.h"
|
||||
#include "cyw43_ll.h"
|
||||
#include "cyw43_config.h"
|
||||
#include "cybt_shared_bus_driver.h"
|
||||
|
||||
#include "cyw43_btfw_43439.h"
|
||||
|
||||
#if CYW43_USE_HEX_BTFW
|
||||
extern const char brcm_patch_version[];
|
||||
extern const uint8_t brcm_patchram_buf[];
|
||||
extern const int brcm_patch_ram_length;
|
||||
#endif
|
||||
|
||||
#define BTSDIO_FW_READY_POLLING_INTERVAL_MS (1)
|
||||
#define BTSDIO_BT_AWAKE_POLLING_INTERVAL_MS (1)
|
||||
|
||||
#define BTSDIO_FW_READY_POLLING_RETRY_COUNT (300)
|
||||
#define BTSDIO_FW_AWAKE_POLLING_RETRY_COUNT (300)
|
||||
|
||||
#define BTSDIO_FWBUF_OPER_DELAY_US (250)
|
||||
#define BTFW_WAIT_TIME_MS (150)
|
||||
|
||||
#define CYBT_DEBUG 0
|
||||
#define CYBT_VDEBUG 0
|
||||
|
||||
#if CYBT_DEBUG
|
||||
#define cybt_debug(format,args...) printf("%d.%d: " format, (int)cyw43_hal_ticks_ms() / 1000, (int)cyw43_hal_ticks_ms() % 1000, ## args)
|
||||
#else
|
||||
#define cybt_debug(format, ...) ((void)0)
|
||||
#endif
|
||||
#define cybt_printf(format, args...) printf("%d.%d: " format, (int)cyw43_hal_ticks_ms() / 1000, (int)cyw43_hal_ticks_ms() % 1000, ## args)
|
||||
|
||||
#define ROUNDUP(x, a) ((((x) + ((a) - 1)) / (a)) * (a))
|
||||
#define ROUNDDN(x, a) ((x) & ~((a) - 1))
|
||||
#define ISALIGNED(a, x) (((uint32_t)(a) & ((x) - 1)) == 0)
|
||||
|
||||
#define CIRC_BUF_CNT(in, out) (((in) - (out)) & ((BTSDIO_FWBUF_SIZE)-1))
|
||||
#define CIRC_BUF_SPACE(in, out) CIRC_BUF_CNT((out), ((in) + 4))
|
||||
|
||||
typedef enum {
|
||||
HCI_PACKET_TYPE_IGNORE = 0x00,
|
||||
HCI_PACKET_TYPE_COMMAND = 0x01,
|
||||
HCI_PACKET_TYPE_ACL = 0x02,
|
||||
HCI_PACKET_TYPE_SCO = 0x03,
|
||||
HCI_PACKET_TYPE_EVENT = 0x04,
|
||||
HCI_PACKET_TYPE_DIAG = 0x07,
|
||||
HCI_PACKET_TYPE_LOOPBACK = 0xFF
|
||||
} hci_packet_type_t;
|
||||
|
||||
static cybt_result_t cybt_fw_download_prepare(uint8_t **p_write_buf, uint8_t **p_hex_buf) {
|
||||
*p_write_buf = NULL;
|
||||
*p_hex_buf = NULL;
|
||||
|
||||
*p_write_buf = malloc(BTFW_DOWNLOAD_BLK_SIZE + BTFW_SD_ALIGN);
|
||||
if (NULL == *p_write_buf) {
|
||||
return CYBT_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
*p_hex_buf = malloc(BTFW_MAX_STR_LEN);
|
||||
if (NULL == *p_hex_buf) {
|
||||
free(*p_write_buf);
|
||||
return CYBT_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return CYBT_SUCCESS;
|
||||
}
|
||||
|
||||
static cybt_result_t cybt_fw_download_finish(uint8_t *p_write_buf, uint8_t *p_hex_buf) {
|
||||
if (p_write_buf) {
|
||||
free(p_write_buf);
|
||||
}
|
||||
|
||||
if (p_hex_buf) {
|
||||
free(p_hex_buf);
|
||||
}
|
||||
|
||||
return CYBT_SUCCESS;
|
||||
}
|
||||
|
||||
static cybt_result_t cybt_wait_bt_ready(uint32_t max_polling_times) {
|
||||
cyw43_delay_ms(BTFW_WAIT_TIME_MS);
|
||||
do {
|
||||
if (cybt_ready()) {
|
||||
return CYBT_SUCCESS;
|
||||
}
|
||||
cyw43_delay_ms(BTSDIO_FW_READY_POLLING_INTERVAL_MS);
|
||||
} while (max_polling_times--);
|
||||
return CYBT_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
static cybt_result_t cybt_wait_bt_awake(uint32_t max_polling_times) {
|
||||
do {
|
||||
if (cybt_awake()) {
|
||||
return CYBT_SUCCESS;
|
||||
}
|
||||
cyw43_delay_ms(BTSDIO_BT_AWAKE_POLLING_INTERVAL_MS);
|
||||
} while (max_polling_times--);
|
||||
return CYBT_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
int cyw43_btbus_init(cyw43_ll_t *self) {
|
||||
cybt_result_t ret;
|
||||
|
||||
uint8_t *p_write_buf = NULL;
|
||||
uint8_t *p_hex_buf = NULL;
|
||||
|
||||
cybt_sharedbus_driver_init(self);
|
||||
|
||||
ret = cybt_fw_download_prepare(&p_write_buf, &p_hex_buf);
|
||||
if (CYBT_SUCCESS != ret) {
|
||||
cybt_printf("Could not allocate memory\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
cybt_debug("cybt_fw_download\n");
|
||||
const uint8_t *fw_data_buf;
|
||||
uint32_t fw_data_len;
|
||||
#if CYW43_USE_HEX_BTFW
|
||||
cybt_printf("CYW43_USE_HEX_BTFW is true\n");
|
||||
#ifndef NDEBUG
|
||||
cybt_printf("BT FW download, version = %s\n", brcm_patch_version);
|
||||
#endif
|
||||
fw_data_len = brcm_patch_ram_length;
|
||||
fw_data_buf = brcm_patchram_buf;
|
||||
#else
|
||||
fw_data_len = cyw43_btfw_43439_len;
|
||||
fw_data_buf = cyw43_btfw_43439;
|
||||
#endif
|
||||
ret = cybt_fw_download(fw_data_buf,
|
||||
fw_data_len,
|
||||
p_write_buf,
|
||||
p_hex_buf
|
||||
);
|
||||
|
||||
cybt_debug("cybt_fw_download_finish\n");
|
||||
cybt_fw_download_finish(p_write_buf, p_hex_buf);
|
||||
|
||||
if (CYBT_SUCCESS != ret) {
|
||||
cybt_printf("hci_open(): FW download failed (0x%x)\n", ret);
|
||||
return CYBT_ERR_HCI_INIT_FAILED;
|
||||
}
|
||||
|
||||
cybt_debug("// cybt_wait_bt_ready\n");
|
||||
ret = cybt_wait_bt_ready(BTSDIO_FW_READY_POLLING_RETRY_COUNT);
|
||||
assert(ret == CYBT_SUCCESS);
|
||||
if (CYBT_SUCCESS == ret) {
|
||||
cybt_debug("hci_open(): FW download successfully\n");
|
||||
} else {
|
||||
cybt_printf("hci_open(): Failed to download FW\n");
|
||||
return CYBT_ERR_HCI_INIT_FAILED;
|
||||
}
|
||||
|
||||
ret = cybt_init_buffer();
|
||||
assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = cybt_wait_bt_awake(BTSDIO_FW_AWAKE_POLLING_RETRY_COUNT);
|
||||
assert(ret == 0);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
cybt_set_host_ready();
|
||||
cybt_toggle_bt_intr();
|
||||
|
||||
return CYBT_SUCCESS;
|
||||
}
|
||||
|
||||
#if CYBT_VDEBUG
|
||||
static void dump_bytes(const uint8_t *bptr, uint32_t len) {
|
||||
unsigned int i = 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if ((i & 0x07) == 0) {
|
||||
printf("\n ");
|
||||
}
|
||||
printf("0x%02x", bptr[i]);
|
||||
if (i != (len-1)) {
|
||||
printf(", ");
|
||||
} else {
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static cybt_result_t cybt_hci_write_buf(const uint8_t *p_data, uint32_t length) {
|
||||
cybt_result_t ret_result = CYBT_SUCCESS;
|
||||
cybt_fw_membuf_index_t fw_membuf_info = {0};
|
||||
|
||||
assert(ISALIGNED(p_data, 4));
|
||||
if (!ISALIGNED(p_data, 4)) {
|
||||
cybt_printf("cybt_hci_write_hdr: buffer not aligned\n");
|
||||
return CYBT_ERR_BADARG;
|
||||
}
|
||||
|
||||
// total length including header
|
||||
length = ROUNDUP(length, 4);
|
||||
cybt_get_bt_buf_index(&fw_membuf_info);
|
||||
uint32_t buf_space = CIRC_BUF_SPACE(fw_membuf_info.host2bt_in_val, fw_membuf_info.host2bt_out_val);
|
||||
assert(length <= buf_space); // queue full?
|
||||
if (length > buf_space) {
|
||||
return CYBT_ERR_QUEUE_FULL;
|
||||
}
|
||||
|
||||
if (fw_membuf_info.host2bt_in_val + length <= BTSDIO_FWBUF_SIZE) {
|
||||
// Don't need to wrap circular buf
|
||||
cybt_debug("cybt_hci_write_hdr: 1-round write, len = %" PRId32 "\n", length);
|
||||
cybt_mem_write_idx(H2B_BUF_ADDR_IDX, fw_membuf_info.host2bt_in_val, p_data, length);
|
||||
fw_membuf_info.host2bt_in_val += length;
|
||||
} else {
|
||||
// Need to wrap circular buf
|
||||
uint32_t first_write_len = BTSDIO_FWBUF_SIZE - fw_membuf_info.host2bt_in_val;
|
||||
if (first_write_len >= 4) {
|
||||
cybt_mem_write_idx(H2B_BUF_ADDR_IDX, fw_membuf_info.host2bt_in_val, p_data, first_write_len);
|
||||
fw_membuf_info.host2bt_in_val += first_write_len;
|
||||
} else {
|
||||
first_write_len = 0;
|
||||
}
|
||||
uint32_t second_write_len = length - first_write_len;
|
||||
cybt_debug("cybt_hci_write_hdr: 2-round write, 1st_len = %" PRId32 ", 2nd_len = %" PRId32 "\n", first_write_len,
|
||||
second_write_len);
|
||||
if (second_write_len > 0) {
|
||||
cybt_mem_write_idx(H2B_BUF_ADDR_IDX, 0, p_data + first_write_len, second_write_len);
|
||||
fw_membuf_info.host2bt_in_val += second_write_len;
|
||||
}
|
||||
}
|
||||
|
||||
// Update circular buf pointer
|
||||
const uint32_t new_h2b_in_val = fw_membuf_info.host2bt_in_val & (BTSDIO_FWBUF_SIZE - 1);
|
||||
cybt_reg_write_idx(H2B_BUF_IN_ADDR_IDX, new_h2b_in_val);
|
||||
|
||||
cybt_toggle_bt_intr();
|
||||
return ret_result;
|
||||
}
|
||||
|
||||
static cybt_result_t cybt_hci_read(uint8_t *p_data, uint32_t *p_length) {
|
||||
cybt_result_t ret_result = CYBT_SUCCESS;
|
||||
uint32_t fw_b2h_buf_count;
|
||||
uint32_t new_b2h_out_val;
|
||||
cybt_fw_membuf_index_t fw_membuf_info = {0};
|
||||
static uint32_t available = 0;
|
||||
|
||||
assert(ISALIGNED(p_data, 4));
|
||||
if (!ISALIGNED(p_data, 4)) {
|
||||
assert(false);
|
||||
cybt_printf("cybt_hci_read: buffer not aligned\n");
|
||||
return CYBT_ERR_BADARG;
|
||||
}
|
||||
|
||||
uint32_t read_len = ROUNDUP(*p_length, 4);
|
||||
|
||||
cybt_get_bt_buf_index(&fw_membuf_info);
|
||||
fw_b2h_buf_count = CIRC_BUF_CNT(fw_membuf_info.bt2host_in_val,
|
||||
fw_membuf_info.bt2host_out_val);
|
||||
cybt_debug("cybt_hci_read: bt2host_in_val=%lu bt2host_out_val=%lu fw_b2h_buf_count=%ld\n",
|
||||
fw_membuf_info.bt2host_in_val, fw_membuf_info.bt2host_out_val, fw_b2h_buf_count);
|
||||
if (fw_b2h_buf_count < available) {
|
||||
cybt_printf("error: cybt_hci_read buffer overflow fw_b2h_buf_count=%ld available=%lu\n", fw_b2h_buf_count,
|
||||
available);
|
||||
cybt_printf("error: cybt_hci_read bt2host_in_val=%lu bt2host_out_val=%lu\n", fw_membuf_info.bt2host_in_val,
|
||||
fw_membuf_info.bt2host_out_val);
|
||||
panic("cyw43 buffer overflow");
|
||||
}
|
||||
|
||||
// No space in buffer
|
||||
if (fw_b2h_buf_count == 0) {
|
||||
*p_length = 0;
|
||||
} else {
|
||||
if (read_len > fw_b2h_buf_count) {
|
||||
read_len = fw_b2h_buf_count;
|
||||
}
|
||||
|
||||
if (fw_membuf_info.bt2host_out_val + read_len <= BTSDIO_FWBUF_SIZE) {
|
||||
// Don't need to wrap the circular buf
|
||||
cybt_debug("cybt_hci_read: 1-round read, len = %" PRId32 "\n", read_len);
|
||||
cybt_mem_read_idx(B2H_BUF_ADDR_IDX, fw_membuf_info.bt2host_out_val, p_data, read_len);
|
||||
fw_membuf_info.bt2host_out_val += read_len;
|
||||
} else {
|
||||
// Need to wrap the circular buf
|
||||
uint32_t first_read_len = BTSDIO_FWBUF_SIZE - fw_membuf_info.bt2host_out_val;
|
||||
if (first_read_len >= 4) {
|
||||
cybt_mem_read_idx(B2H_BUF_ADDR_IDX, fw_membuf_info.bt2host_out_val, p_data, first_read_len);
|
||||
fw_membuf_info.bt2host_out_val += first_read_len;
|
||||
} else {
|
||||
first_read_len = 0;
|
||||
}
|
||||
uint32_t second_read_len = read_len - first_read_len;
|
||||
cybt_debug("cybt_hci_read: 2-round read, 1st_len = %" PRId32 ", 2nd_len = %" PRId32 "\n", first_read_len,
|
||||
second_read_len);
|
||||
if (second_read_len > 0) {
|
||||
cybt_mem_read_idx(B2H_BUF_ADDR_IDX, 0, p_data + first_read_len, second_read_len);
|
||||
fw_membuf_info.bt2host_out_val += second_read_len;
|
||||
}
|
||||
}
|
||||
available = fw_b2h_buf_count - read_len; // remember amount available to check for buffer overflow
|
||||
|
||||
// Update pointer
|
||||
new_b2h_out_val = fw_membuf_info.bt2host_out_val & (BTSDIO_FWBUF_SIZE - 1);
|
||||
cybt_debug("cybt_hci_read new b2h_out = %" PRId32 "\n", new_b2h_out_val);
|
||||
cybt_reg_write_idx(B2H_BUF_OUT_ADDR_IDX, new_b2h_out_val);
|
||||
|
||||
// in case the real length is less than the requested one
|
||||
*p_length = read_len;
|
||||
}
|
||||
cybt_toggle_bt_intr();
|
||||
return ret_result;
|
||||
}
|
||||
|
||||
static void cybt_bus_request(void) {
|
||||
CYW43_THREAD_ENTER
|
||||
// todo: Handle failure
|
||||
cybt_result_t err = cybt_set_bt_awake(true);
|
||||
assert(err == 0);
|
||||
err = cybt_wait_bt_awake(BTSDIO_FW_AWAKE_POLLING_RETRY_COUNT);
|
||||
assert(err == 0);
|
||||
(void) err;
|
||||
}
|
||||
|
||||
static void cybt_bus_release(void) {
|
||||
// mutex if using wifi
|
||||
CYW43_THREAD_EXIT
|
||||
}
|
||||
|
||||
// Send the buffer which includes space for a 4 byte header at the start
|
||||
// The last byte of the header should already be set to the packet type
|
||||
int cyw43_btbus_write(uint8_t *buf, uint32_t size) {
|
||||
uint16_t cmd_len = 0;
|
||||
|
||||
// The size of the buffer should include a 4 byte header at the start
|
||||
cmd_len = size - 4; //in BTSDIO, cmd_len does not include header length
|
||||
|
||||
// Create payload starting with required headers
|
||||
// Format: Cmd Len B0, Cmd Len B1, Cmd Len B2, HCI pckt type, Data
|
||||
buf[0] = (uint8_t) (cmd_len & 0xFF);
|
||||
buf[1] = (uint8_t) ((cmd_len & 0xFF00) >> 8);
|
||||
buf[2] = 0;
|
||||
|
||||
cybt_bus_request();
|
||||
|
||||
cybt_debug("cyw43_btbus_write: %d\n", cmd_len);
|
||||
#if CYBT_VDEBUG
|
||||
dump_bytes(buf, size); // dump header and data
|
||||
#endif
|
||||
|
||||
cybt_hci_write_buf(buf, size);
|
||||
cybt_bus_release();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool cybt_hci_read_packet(uint8_t *buf, uint32_t max_buf_size, uint32_t *size) {
|
||||
uint32_t total_read_len = 0;
|
||||
uint32_t read_len = 0;
|
||||
cybt_result_t bt_result;
|
||||
|
||||
// Read the header into the first 4 bytes of the buffer
|
||||
read_len = 4; //3 bytes BTSDIO packet length + 1 bytes PTI
|
||||
bt_result = cybt_hci_read(buf, &read_len);
|
||||
|
||||
if (bt_result != CYBT_SUCCESS) {
|
||||
*size = 0;
|
||||
cybt_printf("cybt_hci_read_packet: error %d", bt_result);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (read_len == 0) {
|
||||
// No data is read from SPI
|
||||
*size = 0;
|
||||
cybt_debug("cybt_hci_read_packet: no data\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t hci_read_len = ((buf[2] << 16) & 0xFFFF00) | ((buf[1] << 8) & 0xFF00) | (buf[0] & 0xFF);
|
||||
if (hci_read_len > max_buf_size - 4) {
|
||||
*size = 0;
|
||||
cybt_printf("cybt_hci_read_packet: too much data len %" PRId32"\n", hci_read_len);
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
total_read_len = hci_read_len;
|
||||
|
||||
// Read the packet data after the header
|
||||
cybt_debug("cybt_hci_read_packet: packet type 0x%" PRIx8 " len %" PRId32 "\n", buf[3], hci_read_len);
|
||||
bt_result = cybt_hci_read(buf + 4, &total_read_len);
|
||||
if (bt_result != CYBT_SUCCESS) {
|
||||
*size = 0;
|
||||
cybt_printf("cybt_hci_read_packet: read failed\n");
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Might read more because of alignment
|
||||
if (total_read_len >= hci_read_len) {
|
||||
assert(total_read_len == ROUNDUP(hci_read_len, 4)); // check if we're losing data?
|
||||
*size = hci_read_len + 4;
|
||||
} else {
|
||||
assert(total_read_len > 0);
|
||||
*size = total_read_len + 4;
|
||||
cybt_printf("cybt_hci_read_packet: failed to read all data %lu < %lu\n", total_read_len, hci_read_len);
|
||||
//assert(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
cybt_debug("cybt_hci_read_packet: %ld\n", *size);
|
||||
#if CYBT_VDEBUG
|
||||
dump_bytes(buf, *size);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reads the hci packet prepended with 4 byte header. The last header byte is the packet type
|
||||
int cyw43_btbus_read(uint8_t *buf, uint32_t max_buf_size, uint32_t *size) {
|
||||
cybt_bus_request();
|
||||
bool result = cybt_hci_read_packet(buf, max_buf_size, size);
|
||||
cybt_bus_release();
|
||||
return result ? 0 : -1;
|
||||
}
|
@ -0,0 +1,719 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cyw43_ll.h"
|
||||
#include "cybt_shared_bus_driver.h"
|
||||
|
||||
// Bluetooth register corruption occurs if both wifi and bluetooth are fully utilised.
|
||||
#define CYBT_CORRUPTION_TEST 1
|
||||
#if CYBT_CORRUPTION_TEST
|
||||
static cybt_fw_membuf_index_t last_buf_index;
|
||||
static uint32_t last_host_ctrl_reg;
|
||||
static uint32_t last_bt_ctrl_reg;
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define cybt_printf(format, args ...) printf(format,##args)
|
||||
#else
|
||||
#define cybt_printf(...)
|
||||
#endif
|
||||
|
||||
#ifndef CYBT_DEBUG
|
||||
#define CYBT_DEBUG 0
|
||||
#endif
|
||||
|
||||
#if CYBT_DEBUG
|
||||
#include <stdio.h>
|
||||
#define cybt_debug(format, args ...) printf(format,##args)
|
||||
#else
|
||||
#define cybt_debug(format, ...) ((void)0)
|
||||
#endif
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Constants
|
||||
******************************************************************************/
|
||||
#define BTFW_MEM_OFFSET (0x19000000)
|
||||
|
||||
/* BIT0 => WLAN Power UP and BIT1=> WLAN Wake */
|
||||
#define BT2WLAN_PWRUP_WAKE (0x03)
|
||||
#define BT2WLAN_PWRUP_ADDR (0x640894)/* This address is specific to 43012B0 */
|
||||
|
||||
#define BTSDIO_OFFSET_HOST2BT_IN (0x00002000)
|
||||
#define BTSDIO_OFFSET_HOST2BT_OUT (0x00002004)
|
||||
#define BTSDIO_OFFSET_BT2HOST_IN (0x00002008)
|
||||
#define BTSDIO_OFFSET_BT2HOST_OUT (0x0000200C)
|
||||
|
||||
#define H2B_BUF_ADDR (buf_info.host2bt_buf_addr)
|
||||
#define H2B_BUF_IN_ADDR (buf_info.host2bt_in_addr)
|
||||
#define H2B_BUF_OUT_ADDR (buf_info.host2bt_out_addr)
|
||||
#define B2H_BUF_ADDR (buf_info.bt2host_buf_addr)
|
||||
#define B2H_BUF_IN_ADDR (buf_info.bt2host_in_addr)
|
||||
#define B2H_BUF_OUT_ADDR (buf_info.bt2host_out_addr)
|
||||
|
||||
static uint32_t wlan_ram_base_addr;
|
||||
#define WLAN_RAM_BASE_ADDR (wlan_ram_base_addr)
|
||||
|
||||
// In wifi host driver these are all constants
|
||||
#define BT_CTRL_REG_ADDR ((uint32_t)0x18000c7c)
|
||||
#define HOST_CTRL_REG_ADDR ((uint32_t)0x18000d6c)
|
||||
#define WLAN_RAM_BASE_REG_ADDR ((uint32_t)0x18000d68)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t host2bt_buf_addr;
|
||||
uint32_t host2bt_in_addr;
|
||||
uint32_t host2bt_out_addr;
|
||||
uint32_t bt2host_buf_addr;
|
||||
uint32_t bt2host_in_addr;
|
||||
uint32_t bt2host_out_addr;
|
||||
} cybt_fw_membuf_info_t;
|
||||
|
||||
cybt_fw_membuf_info_t buf_info;
|
||||
|
||||
#define BTFW_ADDR_MODE_UNKNOWN (0)
|
||||
#define BTFW_ADDR_MODE_EXTENDED (1)
|
||||
#define BTFW_ADDR_MODE_SEGMENT (2)
|
||||
#define BTFW_ADDR_MODE_LINEAR32 (3)
|
||||
|
||||
#define BTFW_HEX_LINE_TYPE_DATA (0)
|
||||
#define BTFW_HEX_LINE_TYPE_END_OF_DATA (1)
|
||||
#define BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS (2)
|
||||
#define BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS (4)
|
||||
#define BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS (5)
|
||||
|
||||
#define BTSDIO_REG_DATA_VALID_BITMASK (1 << 1)
|
||||
#define BTSDIO_REG_WAKE_BT_BITMASK (1 << 17)
|
||||
#define BTSDIO_REG_SW_RDY_BITMASK (1 << 24)
|
||||
|
||||
#define BTSDIO_REG_BT_AWAKE_BITMASK (1 << 8)
|
||||
#define BTSDIO_REG_FW_RDY_BITMASK (1 << 24)
|
||||
|
||||
#define BTSDIO_OFFSET_HOST_WRITE_BUF (0)
|
||||
#define BTSDIO_OFFSET_HOST_READ_BUF BTSDIO_FWBUF_SIZE
|
||||
|
||||
#define BTSDIO_FWBUF_OPER_DELAY_US (250)
|
||||
|
||||
#define ROUNDUP(x, a) ((((x) + ((a) - 1)) / (a)) * (a))
|
||||
#define ROUNDDN(x, a) ((x) & ~((a) - 1))
|
||||
#define ISALIGNED(a, x) (((uint32_t)(a) & ((x) - 1)) == 0)
|
||||
|
||||
typedef struct cybt_fw_cb
|
||||
{
|
||||
const uint8_t *p_fw_mem_start;
|
||||
uint32_t fw_len;
|
||||
const uint8_t *p_next_line_start;
|
||||
} cybt_fw_cb_t;
|
||||
|
||||
typedef struct hex_file_data
|
||||
{
|
||||
int addr_mode;
|
||||
uint16_t hi_addr;
|
||||
uint32_t dest_addr;
|
||||
uint8_t *p_ds;
|
||||
} hex_file_data_t;
|
||||
|
||||
#if USE_SDIO
|
||||
#define MAX_BLOCK_SIZE 16384
|
||||
#else
|
||||
#define MAX_BLOCK_SIZE 64
|
||||
#endif
|
||||
|
||||
static cyw43_ll_t *cyw43_ll = NULL;
|
||||
|
||||
static cybt_result_t cybt_reg_write(uint32_t reg_addr, uint32_t value);
|
||||
static cybt_result_t cybt_reg_read(uint32_t reg_addr, uint32_t *p_value);
|
||||
static cybt_result_t cybt_mem_write(uint32_t mem_addr, const uint8_t *p_data, uint32_t data_len);
|
||||
static cybt_result_t cybt_mem_read(uint32_t mem_addr, uint8_t *p_data, uint32_t data_len);
|
||||
|
||||
#if CYW43_USE_HEX_BTFW
|
||||
const char *strnchr(const char *str, uint32_t len, int character) {
|
||||
const char *end = str + len;
|
||||
char c = (char)character;
|
||||
do {
|
||||
if (*str == c) {
|
||||
return str;
|
||||
}
|
||||
} while (++str <= end);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint32_t cybt_fw_hex_read_line(cybt_fw_cb_t *p_btfw_cb,
|
||||
const char **p_line_start,
|
||||
int len
|
||||
) {
|
||||
uint32_t str_len = 0;
|
||||
const char *p_str_end = NULL;
|
||||
|
||||
if (NULL == p_btfw_cb || NULL == p_line_start) {
|
||||
return str_len;
|
||||
}
|
||||
|
||||
*p_line_start = (const char *)p_btfw_cb->p_next_line_start;
|
||||
p_str_end = strnchr(*p_line_start, len, '\n');
|
||||
if (p_str_end == NULL) {
|
||||
return str_len;
|
||||
}
|
||||
|
||||
str_len = (uint32_t)(p_str_end - *p_line_start);
|
||||
|
||||
/* Advance file pointer past the string length */
|
||||
p_btfw_cb->p_next_line_start += str_len + 1;
|
||||
|
||||
return str_len;
|
||||
}
|
||||
|
||||
static inline uint8_t nibble_for_char(char c){
|
||||
if ((c >= '0') && (c <= '9')) return c - '0';
|
||||
if ((c >= 'A') && (c <= 'F')) return c - 'A' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline uint8_t read_hex_byte(const char *str) {
|
||||
return nibble_for_char(*str) << 4 | nibble_for_char(*(str + 1));
|
||||
}
|
||||
|
||||
static uint32_t read_hex(const char *str, int nchars) {
|
||||
uint32_t result = 0;
|
||||
assert(nchars > 0 && nchars <= 8 && nchars % 2 == 0);
|
||||
for(int pos = 0; pos < nchars; pos += 2) {
|
||||
result <<= 8;
|
||||
result |= read_hex_byte(str + pos);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint32_t cybt_fw_get_data(cybt_fw_cb_t *p_btfw_cb,
|
||||
hex_file_data_t *hfd
|
||||
) {
|
||||
uint32_t line_len;
|
||||
uint16_t num_bytes, addr, data_pos, type, idx, octet;
|
||||
uint32_t abs_base_addr32 = 0;
|
||||
uint32_t data_len = 0;
|
||||
const char *p_line_start = NULL;
|
||||
|
||||
if (NULL == p_btfw_cb || NULL == hfd->p_ds) {
|
||||
return data_len;
|
||||
}
|
||||
|
||||
while (data_len == 0) {
|
||||
line_len = cybt_fw_hex_read_line(p_btfw_cb, &p_line_start, BTFW_MAX_STR_LEN);
|
||||
if (line_len == 0) {
|
||||
break;
|
||||
} else if (line_len > 9) {
|
||||
|
||||
num_bytes = (uint16_t)read_hex(p_line_start + 1, 2);
|
||||
assert(num_bytes * 2 + 8 + 2 + 1 == line_len);
|
||||
|
||||
int addr32 = read_hex(p_line_start + 3, 4);
|
||||
assert(addr32 <= 0xffff);
|
||||
addr = (uint16_t)addr32;
|
||||
type = (uint16_t)read_hex(p_line_start + 7, 2);
|
||||
assert(type <= 0xff);
|
||||
|
||||
data_pos = 9;
|
||||
|
||||
for (idx = 0; idx < num_bytes; idx++)
|
||||
{
|
||||
octet = (uint16_t)read_hex(p_line_start + data_pos, 2);
|
||||
hfd->p_ds[idx] = (uint8_t)(octet & 0x00FF);
|
||||
data_pos += 2;
|
||||
}
|
||||
|
||||
if (type == BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS) {
|
||||
hfd->hi_addr = (hfd->p_ds[0] << 8) | hfd->p_ds[1];
|
||||
hfd->addr_mode = BTFW_ADDR_MODE_EXTENDED;
|
||||
} else if (type == BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS) {
|
||||
hfd->hi_addr = (hfd->p_ds[0] << 8) | hfd->p_ds[1];
|
||||
hfd->addr_mode = BTFW_ADDR_MODE_SEGMENT;
|
||||
} else if (type == BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS) {
|
||||
abs_base_addr32 = (hfd->p_ds[0] << 24) | (hfd->p_ds[1] << 16) |
|
||||
(hfd->p_ds[2] << 8) | hfd->p_ds[3];
|
||||
hfd->addr_mode = BTFW_ADDR_MODE_LINEAR32;
|
||||
} else if (type == BTFW_HEX_LINE_TYPE_DATA) {
|
||||
hfd->dest_addr = addr;
|
||||
|
||||
if (hfd->addr_mode == BTFW_ADDR_MODE_EXTENDED) {
|
||||
hfd->dest_addr += (hfd->hi_addr << 16);
|
||||
} else if (hfd->addr_mode == BTFW_ADDR_MODE_SEGMENT) {
|
||||
hfd->dest_addr += (hfd->hi_addr << 4);
|
||||
} else if (hfd->addr_mode == BTFW_ADDR_MODE_LINEAR32) {
|
||||
hfd->dest_addr += abs_base_addr32;
|
||||
}
|
||||
|
||||
data_len = num_bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data_len;
|
||||
}
|
||||
#else
|
||||
|
||||
static uint32_t cybt_fw_get_data(cybt_fw_cb_t *p_btfw_cb, hex_file_data_t *hfd) {
|
||||
uint32_t abs_base_addr32 = 0;
|
||||
while (true) {
|
||||
// 4 byte header
|
||||
uint8_t num_bytes = *(p_btfw_cb->p_next_line_start)++;
|
||||
uint16_t addr = *(p_btfw_cb->p_next_line_start)++ << 8;
|
||||
addr |= *(p_btfw_cb->p_next_line_start)++;
|
||||
uint8_t type = *(p_btfw_cb->p_next_line_start)++;
|
||||
|
||||
// No data?
|
||||
if (num_bytes == 0) break;
|
||||
|
||||
// Copy the data
|
||||
memcpy(hfd->p_ds, p_btfw_cb->p_next_line_start, num_bytes);
|
||||
p_btfw_cb->p_next_line_start += num_bytes;
|
||||
|
||||
// Adjust address based on type
|
||||
if (type == BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS) {
|
||||
hfd->hi_addr = (hfd->p_ds[0] << 8) | hfd->p_ds[1];
|
||||
hfd->addr_mode = BTFW_ADDR_MODE_EXTENDED;
|
||||
} else if (type == BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS) {
|
||||
hfd->hi_addr = (hfd->p_ds[0] << 8) | hfd->p_ds[1];
|
||||
hfd->addr_mode = BTFW_ADDR_MODE_SEGMENT;
|
||||
} else if (type == BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS) {
|
||||
abs_base_addr32 = (hfd->p_ds[0] << 24) | (hfd->p_ds[1] << 16) |
|
||||
(hfd->p_ds[2] << 8) | hfd->p_ds[3];
|
||||
hfd->addr_mode = BTFW_ADDR_MODE_LINEAR32;
|
||||
} else if (type == BTFW_HEX_LINE_TYPE_DATA) {
|
||||
hfd->dest_addr = addr;
|
||||
if (hfd->addr_mode == BTFW_ADDR_MODE_EXTENDED) {
|
||||
hfd->dest_addr += (hfd->hi_addr << 16);
|
||||
} else if (hfd->addr_mode == BTFW_ADDR_MODE_SEGMENT) {
|
||||
hfd->dest_addr += (hfd->hi_addr << 4);
|
||||
} else if (hfd->addr_mode == BTFW_ADDR_MODE_LINEAR32) {
|
||||
hfd->dest_addr += abs_base_addr32;
|
||||
}
|
||||
return num_bytes;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
cybt_result_t cybt_fw_download(const uint8_t *p_bt_firmware,
|
||||
uint32_t bt_firmware_len,
|
||||
uint8_t *p_write_buf,
|
||||
uint8_t *p_hex_buf) {
|
||||
cybt_fw_cb_t btfw_cb;
|
||||
hex_file_data_t hfd = {BTFW_ADDR_MODE_EXTENDED, 0, 0, NULL};
|
||||
uint8_t *p_mem_ptr;
|
||||
uint32_t data_len;
|
||||
|
||||
if (cyw43_ll == NULL) {
|
||||
return CYBT_ERR_BADARG;
|
||||
}
|
||||
|
||||
if (NULL == p_bt_firmware || 0 == bt_firmware_len || NULL == p_write_buf || NULL == p_hex_buf) {
|
||||
return CYBT_ERR_BADARG;
|
||||
}
|
||||
|
||||
// BT firmware starts with length of version string including a null terminator
|
||||
#if !CYW43_USE_HEX_BTFW
|
||||
uint8_t version_len = *p_bt_firmware;
|
||||
assert(*(p_bt_firmware + version_len) == 0);
|
||||
#ifndef NDEBUG
|
||||
cybt_printf("BT FW download, version = %s\n", p_bt_firmware + 1);
|
||||
#endif
|
||||
p_bt_firmware += version_len + 1; // skip over version
|
||||
p_bt_firmware += 1; // skip over record count
|
||||
#endif
|
||||
|
||||
p_mem_ptr = p_write_buf;
|
||||
if ((uint32_t) (uintptr_t) p_mem_ptr % BTFW_SD_ALIGN) {
|
||||
p_mem_ptr += (BTFW_SD_ALIGN - ((uint32_t) (uintptr_t) p_mem_ptr % BTFW_SD_ALIGN));
|
||||
}
|
||||
|
||||
hfd.p_ds = p_hex_buf;
|
||||
|
||||
btfw_cb.p_fw_mem_start = p_bt_firmware;
|
||||
btfw_cb.fw_len = bt_firmware_len;
|
||||
btfw_cb.p_next_line_start = p_bt_firmware;
|
||||
|
||||
cybt_reg_write(BTFW_MEM_OFFSET + BT2WLAN_PWRUP_ADDR, BT2WLAN_PWRUP_WAKE);
|
||||
|
||||
while ((data_len = cybt_fw_get_data(&btfw_cb, &hfd)) > 0) {
|
||||
uint32_t fwmem_start_addr, fwmem_start_data, fwmem_end_addr, fwmem_end_data;
|
||||
uint32_t write_data_len, idx, pad;
|
||||
|
||||
fwmem_start_addr = BTFW_MEM_OFFSET + hfd.dest_addr;
|
||||
write_data_len = 0;
|
||||
|
||||
/**
|
||||
* Make sure the start address is 4 byte aligned to avoid alignment issues
|
||||
* with SD host controllers
|
||||
*/
|
||||
if (!ISALIGNED(fwmem_start_addr, 4)) {
|
||||
pad = fwmem_start_addr % 4;
|
||||
fwmem_start_addr = ROUNDDN(fwmem_start_addr, 4);
|
||||
|
||||
cybt_mem_read(fwmem_start_addr, (uint8_t *) &fwmem_start_data, sizeof(uint32_t));
|
||||
|
||||
for (idx = 0; idx < pad; idx++, write_data_len++) {
|
||||
p_mem_ptr[write_data_len] = (uint8_t) ((uint8_t *) &fwmem_start_data)[idx];
|
||||
}
|
||||
}
|
||||
memcpy(&(p_mem_ptr[write_data_len]), hfd.p_ds, data_len);
|
||||
write_data_len += data_len;
|
||||
|
||||
/**
|
||||
* Make sure the length is multiple of 4bytes to avoid alignment issues
|
||||
* with SD host controllers
|
||||
*/
|
||||
fwmem_end_addr = fwmem_start_addr + write_data_len;
|
||||
if (!ISALIGNED(fwmem_end_addr, 4)) {
|
||||
cybt_mem_read(ROUNDDN(fwmem_end_addr, 4), (uint8_t *) &fwmem_end_data, sizeof(uint32_t));
|
||||
for (idx = (fwmem_end_addr % 4); idx < 4; idx++, write_data_len++) {
|
||||
p_mem_ptr[write_data_len] = (uint8_t) ((uint8_t *) &fwmem_end_data)[idx];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* write ram
|
||||
*/
|
||||
if (((fwmem_start_addr & 0xFFF) + write_data_len) <= 0x1000) {
|
||||
cybt_mem_write(fwmem_start_addr, p_mem_ptr, write_data_len);
|
||||
} else {
|
||||
uint32_t first_write_len = 0x1000 - (fwmem_start_addr & 0xFFF);
|
||||
cybt_mem_write(fwmem_start_addr, p_mem_ptr, first_write_len);
|
||||
cybt_mem_write(fwmem_start_addr + first_write_len,
|
||||
p_mem_ptr + first_write_len,
|
||||
write_data_len - first_write_len);
|
||||
}
|
||||
}
|
||||
|
||||
return CYBT_SUCCESS;
|
||||
}
|
||||
|
||||
cybt_result_t cybt_set_host_ready(void) {
|
||||
uint32_t reg_val;
|
||||
|
||||
cybt_reg_read(HOST_CTRL_REG_ADDR, ®_val);
|
||||
reg_val |= BTSDIO_REG_SW_RDY_BITMASK;
|
||||
cybt_reg_write(HOST_CTRL_REG_ADDR, reg_val);
|
||||
#if CYBT_CORRUPTION_TEST
|
||||
last_host_ctrl_reg = reg_val;
|
||||
#endif
|
||||
return CYBT_SUCCESS;
|
||||
}
|
||||
|
||||
cybt_result_t cybt_toggle_bt_intr(void) {
|
||||
uint32_t reg_val, new_val;
|
||||
|
||||
cybt_reg_read(HOST_CTRL_REG_ADDR, ®_val);
|
||||
#if CYBT_CORRUPTION_TEST
|
||||
if ((reg_val & ~(BTSDIO_REG_SW_RDY_BITMASK | BTSDIO_REG_WAKE_BT_BITMASK | BTSDIO_REG_DATA_VALID_BITMASK)) != 0) {
|
||||
cybt_printf("cybt_toggle_bt_intr read HOST_CTRL_REG_ADDR as 0x%08lx\n", reg_val);
|
||||
cybt_debug_dump();
|
||||
panic("cyw43 btsdio register corruption");
|
||||
}
|
||||
assert((reg_val & ~(BTSDIO_REG_SW_RDY_BITMASK | BTSDIO_REG_WAKE_BT_BITMASK | BTSDIO_REG_DATA_VALID_BITMASK)) == 0);
|
||||
#endif
|
||||
new_val = reg_val ^ BTSDIO_REG_DATA_VALID_BITMASK;
|
||||
cybt_reg_write(HOST_CTRL_REG_ADDR, new_val);
|
||||
#if CYBT_CORRUPTION_TEST
|
||||
last_host_ctrl_reg = new_val;
|
||||
#endif
|
||||
return CYBT_SUCCESS;
|
||||
}
|
||||
|
||||
cybt_result_t cybt_set_bt_intr(int value) {
|
||||
uint32_t reg_val, new_val;
|
||||
|
||||
cybt_reg_read(HOST_CTRL_REG_ADDR, ®_val);
|
||||
if (value) {
|
||||
new_val = reg_val | BTSDIO_REG_DATA_VALID_BITMASK;
|
||||
} else {
|
||||
new_val = reg_val & ~BTSDIO_REG_DATA_VALID_BITMASK;
|
||||
}
|
||||
cybt_reg_write(HOST_CTRL_REG_ADDR, new_val);
|
||||
#if CYBT_CORRUPTION_TEST
|
||||
last_host_ctrl_reg = new_val;
|
||||
#endif
|
||||
return CYBT_SUCCESS;
|
||||
}
|
||||
|
||||
int cybt_ready(void) {
|
||||
uint32_t reg_val;
|
||||
cybt_reg_read(BT_CTRL_REG_ADDR, ®_val);
|
||||
#if CYBT_CORRUPTION_TEST
|
||||
if (reg_val & BTSDIO_REG_FW_RDY_BITMASK) {
|
||||
last_bt_ctrl_reg = reg_val;
|
||||
}
|
||||
#endif
|
||||
return (reg_val & BTSDIO_REG_FW_RDY_BITMASK) ? 1 : 0;
|
||||
}
|
||||
|
||||
int cybt_awake(void) {
|
||||
uint32_t reg_val;
|
||||
cybt_reg_read(BT_CTRL_REG_ADDR, ®_val);
|
||||
#if CYBT_CORRUPTION_TEST
|
||||
if (reg_val & BTSDIO_REG_BT_AWAKE_BITMASK) {
|
||||
last_bt_ctrl_reg = reg_val;
|
||||
}
|
||||
#endif
|
||||
return (reg_val & BTSDIO_REG_BT_AWAKE_BITMASK) ? 1 : 0;
|
||||
}
|
||||
|
||||
cybt_result_t cybt_set_bt_awake(int value) {
|
||||
uint32_t reg_val_before;
|
||||
cybt_reg_read(HOST_CTRL_REG_ADDR, ®_val_before);
|
||||
|
||||
uint32_t reg_val_after = reg_val_before;
|
||||
if (value)
|
||||
reg_val_after |= BTSDIO_REG_WAKE_BT_BITMASK;
|
||||
else
|
||||
reg_val_after &= ~BTSDIO_REG_WAKE_BT_BITMASK;
|
||||
|
||||
if (reg_val_before != reg_val_after) {
|
||||
cybt_reg_write(HOST_CTRL_REG_ADDR, reg_val_after);
|
||||
#if CYBT_CORRUPTION_TEST
|
||||
last_host_ctrl_reg = reg_val_after;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cybt_debug_dump(void) {
|
||||
#if CYBT_CORRUPTION_TEST
|
||||
uint32_t reg_val = 0;
|
||||
cybt_fw_membuf_index_t buf_index;
|
||||
|
||||
cybt_printf("WLAN_RAM_BASE_ADDR: 0x%08lx\n", WLAN_RAM_BASE_ADDR);
|
||||
cybt_printf("H2B_BUF_ADDR: 0x%08lx\n", H2B_BUF_ADDR);
|
||||
cybt_printf("B2H_BUF_ADDR: 0x%08lx\n", B2H_BUF_ADDR);
|
||||
|
||||
cybt_reg_read(H2B_BUF_IN_ADDR, &buf_index.host2bt_in_val);
|
||||
cybt_printf("H2B_BUF_IN_ADDR: 0x%08lx = 0x%08lx (last 0x%08lx)\n", H2B_BUF_IN_ADDR, buf_index.host2bt_in_val,
|
||||
last_buf_index.host2bt_in_val);
|
||||
|
||||
cybt_reg_read(H2B_BUF_OUT_ADDR, &buf_index.host2bt_out_val);
|
||||
cybt_printf("H2B_BUF_OUT_ADDR: 0x%08lx = 0x%08lx (last 0x%08lx)\n", H2B_BUF_OUT_ADDR, buf_index.host2bt_out_val,
|
||||
last_buf_index.host2bt_out_val);
|
||||
|
||||
cybt_reg_read(B2H_BUF_IN_ADDR, &buf_index.bt2host_in_val);
|
||||
cybt_printf("B2H_BUF_IN_ADDR: 0x%08lx = 0x%08lx (last 0x%08lx)\n", B2H_BUF_IN_ADDR, buf_index.bt2host_in_val,
|
||||
last_buf_index.bt2host_in_val);
|
||||
|
||||
cybt_reg_read(B2H_BUF_OUT_ADDR, &buf_index.bt2host_out_val);
|
||||
cybt_printf("B2H_BUF_OUT_ADDR: 0x%08lx = 0x%08lx (last 0x%08lx)\n", B2H_BUF_OUT_ADDR, buf_index.bt2host_out_val,
|
||||
last_buf_index.bt2host_out_val);
|
||||
|
||||
cybt_reg_read(HOST_CTRL_REG_ADDR, ®_val);
|
||||
cybt_printf("HOST_CTRL_REG_ADDR: 0x%08lx = 0x%08lx (last 0x%08lx)\n", HOST_CTRL_REG_ADDR, reg_val,
|
||||
last_host_ctrl_reg);
|
||||
|
||||
cybt_reg_read(BT_CTRL_REG_ADDR, ®_val);
|
||||
cybt_printf("BT_CTRL_REG_ADDR: 0x%08lx = 0x%08lx (last 0x%08lx)\n", BT_CTRL_REG_ADDR, reg_val, last_bt_ctrl_reg);
|
||||
#endif
|
||||
}
|
||||
|
||||
cybt_result_t cybt_get_bt_buf_index(cybt_fw_membuf_index_t *p_buf_index) {
|
||||
uint32_t buf[4];
|
||||
|
||||
cybt_mem_read(H2B_BUF_IN_ADDR, (uint8_t *) buf, sizeof(buf));
|
||||
|
||||
p_buf_index->host2bt_in_val = buf[0];
|
||||
p_buf_index->host2bt_out_val = buf[1];
|
||||
p_buf_index->bt2host_in_val = buf[2];
|
||||
p_buf_index->bt2host_out_val = buf[3];
|
||||
|
||||
cybt_debug("cybt_get_bt_buf_index: h2b_in = 0x%08lx, h2b_out = 0x%08lx, b2h_in = 0x%08lx, b2h_out = 0x%08lx\n",
|
||||
p_buf_index->host2bt_in_val,
|
||||
p_buf_index->host2bt_out_val,
|
||||
p_buf_index->bt2host_in_val,
|
||||
p_buf_index->bt2host_out_val);
|
||||
|
||||
#if CYBT_CORRUPTION_TEST
|
||||
if (p_buf_index->host2bt_in_val >= BTSDIO_FWBUF_SIZE || p_buf_index->host2bt_out_val >= BTSDIO_FWBUF_SIZE ||
|
||||
p_buf_index->bt2host_in_val >= BTSDIO_FWBUF_SIZE || p_buf_index->bt2host_out_val >= BTSDIO_FWBUF_SIZE) {
|
||||
cybt_printf("cybt_get_bt_buf_index invalid buffer value\n");
|
||||
cybt_debug_dump();
|
||||
} else {
|
||||
memcpy((uint8_t *) &last_buf_index, (uint8_t *) p_buf_index, sizeof(cybt_fw_membuf_index_t));
|
||||
}
|
||||
#endif
|
||||
|
||||
assert(p_buf_index->host2bt_in_val < BTSDIO_FWBUF_SIZE);
|
||||
assert(p_buf_index->host2bt_out_val < BTSDIO_FWBUF_SIZE);
|
||||
assert(p_buf_index->bt2host_in_val < BTSDIO_FWBUF_SIZE);
|
||||
assert(p_buf_index->bt2host_out_val < BTSDIO_FWBUF_SIZE);
|
||||
|
||||
return CYBT_SUCCESS;
|
||||
}
|
||||
|
||||
static cybt_result_t cybt_reg_write(uint32_t reg_addr, uint32_t value) {
|
||||
cybt_debug("cybt_reg_write 0x%08lx 0x%08lx\n", reg_addr, value);
|
||||
cyw43_ll_write_backplane_reg(cyw43_ll, reg_addr, value);
|
||||
return CYBT_SUCCESS;
|
||||
}
|
||||
|
||||
static cybt_result_t cybt_reg_read(uint32_t reg_addr, uint32_t *p_value) {
|
||||
*p_value = cyw43_ll_read_backplane_reg(cyw43_ll, reg_addr);
|
||||
cybt_debug("cybt_reg_read 0x%08lx == 0x%08lx\n", reg_addr, *p_value);
|
||||
return CYBT_SUCCESS;
|
||||
}
|
||||
|
||||
#if CYBT_DEBUG
|
||||
static void dump_bytes(const uint8_t *bptr, uint32_t len) {
|
||||
unsigned int i = 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if ((i & 0x07) == 0) {
|
||||
cybt_debug("\n ");
|
||||
}
|
||||
cybt_debug("0x%02x", bptr[i]);
|
||||
if (i != (len - 1)) {
|
||||
cybt_debug(", ");
|
||||
} else {
|
||||
}
|
||||
}
|
||||
cybt_debug("\n");
|
||||
}
|
||||
#define DUMP_BYTES dump_bytes
|
||||
#else
|
||||
#define DUMP_BYTES(...)
|
||||
#endif
|
||||
|
||||
static cybt_result_t cybt_mem_write(uint32_t mem_addr, const uint8_t *p_data, uint32_t data_len) {
|
||||
cybt_debug("cybt_mem_write addr 0x%08lx len %ld\n", mem_addr, data_len);
|
||||
do {
|
||||
uint32_t transfer_size = (data_len > MAX_BLOCK_SIZE) ? MAX_BLOCK_SIZE : data_len;
|
||||
cyw43_ll_write_backplane_mem(cyw43_ll, mem_addr, transfer_size, p_data);
|
||||
cybt_debug(" write_mem addr 0x%08lx len %ld\n", mem_addr, transfer_size);
|
||||
DUMP_BYTES(p_data, transfer_size);
|
||||
data_len -= transfer_size;
|
||||
p_data += transfer_size;
|
||||
mem_addr += transfer_size;
|
||||
} while (data_len > 0);
|
||||
return CYBT_SUCCESS;
|
||||
}
|
||||
|
||||
static cybt_result_t cybt_mem_read(uint32_t mem_addr, uint8_t *p_data, uint32_t data_len) {
|
||||
assert(data_len >= 4);
|
||||
cybt_debug("cybt_mem_read addr 0x%08lx len %ld\n", mem_addr, data_len);
|
||||
do {
|
||||
uint32_t transfer_size = (data_len > MAX_BLOCK_SIZE) ? MAX_BLOCK_SIZE : data_len;
|
||||
/* this limitation from BT, we need to read twice when spi clock setting is more than 25MHz */
|
||||
cyw43_ll_read_backplane_mem(cyw43_ll, mem_addr, transfer_size, p_data);
|
||||
cybt_debug(" read_mem addr 0x%08lx len %ld\n", transfer_size, mem_addr);
|
||||
DUMP_BYTES(p_data, transfer_size);
|
||||
data_len -= transfer_size;
|
||||
p_data += transfer_size;
|
||||
mem_addr += transfer_size;
|
||||
} while (data_len > 0);
|
||||
return CYBT_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32_t cybt_get_addr(cybt_addr_idx_t addr_idx) {
|
||||
uint32_t addr = 0;
|
||||
|
||||
switch (addr_idx) {
|
||||
case H2B_BUF_ADDR_IDX:
|
||||
addr = H2B_BUF_ADDR;
|
||||
break;
|
||||
case H2B_BUF_IN_ADDR_IDX:
|
||||
addr = H2B_BUF_IN_ADDR;
|
||||
break;
|
||||
case H2B_BUF_OUT_ADDR_IDX:
|
||||
addr = H2B_BUF_OUT_ADDR;
|
||||
break;
|
||||
case B2H_BUF_ADDR_IDX:
|
||||
addr = B2H_BUF_ADDR;
|
||||
break;
|
||||
case B2H_BUF_IN_ADDR_IDX:
|
||||
addr = B2H_BUF_IN_ADDR;
|
||||
break;
|
||||
case B2H_BUF_OUT_ADDR_IDX:
|
||||
addr = B2H_BUF_OUT_ADDR;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
cybt_result_t cybt_reg_write_idx(cybt_addr_idx_t reg_idx, uint32_t value) {
|
||||
assert(reg_idx == H2B_BUF_IN_ADDR_IDX || reg_idx == B2H_BUF_OUT_ADDR_IDX);
|
||||
assert(value < BTSDIO_FWBUF_SIZE); // writing out of bounds register value?
|
||||
if ((reg_idx != H2B_BUF_IN_ADDR_IDX && reg_idx != B2H_BUF_OUT_ADDR_IDX) || value >= BTSDIO_FWBUF_SIZE) {
|
||||
assert(0);
|
||||
return CYBT_ERR_BADARG;
|
||||
}
|
||||
uint32_t reg_addr = cybt_get_addr(reg_idx);
|
||||
return cybt_reg_write(reg_addr, value);
|
||||
}
|
||||
|
||||
cybt_result_t cybt_mem_write_idx(cybt_addr_idx_t mem_idx, uint32_t offset, const uint8_t *p_data, uint32_t data_len) {
|
||||
assert(mem_idx == H2B_BUF_ADDR_IDX); // caller should only be writing to here?
|
||||
assert(offset + data_len <= BTSDIO_FWBUF_SIZE); // writing out of bounds?
|
||||
if (mem_idx != H2B_BUF_ADDR_IDX || (offset + data_len) > BTSDIO_FWBUF_SIZE) {
|
||||
assert(0);
|
||||
return CYBT_ERR_BADARG;
|
||||
}
|
||||
if (!ISALIGNED(p_data, 4)) {
|
||||
return CYBT_ERR_BADARG;
|
||||
}
|
||||
uint32_t mem_addr = cybt_get_addr(mem_idx) + offset;
|
||||
return cybt_mem_write(mem_addr, p_data, data_len);
|
||||
}
|
||||
|
||||
cybt_result_t cybt_mem_read_idx(cybt_addr_idx_t mem_idx, uint32_t offset, uint8_t *p_data, uint32_t data_len) {
|
||||
assert(mem_idx == B2H_BUF_ADDR_IDX); // caller should only be reading from here?
|
||||
assert(offset + data_len <= BTSDIO_FWBUF_SIZE); // reading out of bounds?
|
||||
if (mem_idx != B2H_BUF_ADDR_IDX || (offset + data_len) > BTSDIO_FWBUF_SIZE) {
|
||||
assert(0);
|
||||
return CYBT_ERR_BADARG;
|
||||
}
|
||||
uint32_t mem_addr = cybt_get_addr(mem_idx) + offset;
|
||||
return cybt_mem_read(mem_addr, p_data, data_len);
|
||||
}
|
||||
|
||||
cybt_result_t cybt_init_buffer(void) {
|
||||
int result;
|
||||
result = cybt_reg_read(WLAN_RAM_BASE_REG_ADDR, &WLAN_RAM_BASE_ADDR);
|
||||
if (CYBT_SUCCESS != result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
cybt_debug("hci_open(): btfw ram base = 0x%" PRIx32 "\n", WLAN_RAM_BASE_ADDR);
|
||||
|
||||
// Fill in reg info
|
||||
// Data buffers
|
||||
H2B_BUF_ADDR = WLAN_RAM_BASE_ADDR + BTSDIO_OFFSET_HOST_WRITE_BUF;
|
||||
B2H_BUF_ADDR = WLAN_RAM_BASE_ADDR + BTSDIO_OFFSET_HOST_READ_BUF;
|
||||
|
||||
// circular buffer indexes
|
||||
H2B_BUF_IN_ADDR = WLAN_RAM_BASE_ADDR + BTSDIO_OFFSET_HOST2BT_IN;
|
||||
H2B_BUF_OUT_ADDR = WLAN_RAM_BASE_ADDR + BTSDIO_OFFSET_HOST2BT_OUT;
|
||||
B2H_BUF_IN_ADDR = WLAN_RAM_BASE_ADDR + BTSDIO_OFFSET_BT2HOST_IN;
|
||||
B2H_BUF_OUT_ADDR = WLAN_RAM_BASE_ADDR + BTSDIO_OFFSET_BT2HOST_OUT;
|
||||
|
||||
uint32_t reg_val = 0;
|
||||
cybt_reg_write(H2B_BUF_IN_ADDR, reg_val);
|
||||
cybt_reg_write(H2B_BUF_OUT_ADDR, reg_val);
|
||||
cybt_reg_write(B2H_BUF_IN_ADDR, reg_val);
|
||||
cybt_reg_write(B2H_BUF_OUT_ADDR, reg_val);
|
||||
|
||||
return CYBT_SUCCESS;
|
||||
}
|
||||
|
||||
void cybt_sharedbus_driver_init(cyw43_ll_t *driver) {
|
||||
cyw43_ll = driver;
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef CYBT_SHARE_BUS_DRIVER_H
|
||||
#define CYBT_SHARE_BUS_DRIVER_H
|
||||
|
||||
#define BTSDIO_FWBUF_SIZE (0x1000)
|
||||
#define BTFW_MAX_STR_LEN (600)
|
||||
#define BTFW_SD_ALIGN (32)
|
||||
#define BTFW_DOWNLOAD_BLK_SIZE (((BTFW_MAX_STR_LEN) / 2) + 8)
|
||||
|
||||
typedef enum {
|
||||
CYBT_SUCCESS = 0,
|
||||
CYBT_ERR_BADARG = 0xB1,
|
||||
CYBT_ERR_OUT_OF_MEMORY,
|
||||
CYBT_ERR_TIMEOUT,
|
||||
CYBT_ERR_HCI_INIT_FAILED,
|
||||
CYBT_ERR_HCI_UNSUPPORTED_IF,
|
||||
CYBT_ERR_HCI_UNSUPPORTED_BAUDRATE,
|
||||
CYBT_ERR_HCI_NOT_INITIALIZE,
|
||||
CYBT_ERR_HCI_WRITE_FAILED,
|
||||
CYBT_ERR_HCI_READ_FAILED,
|
||||
CYBT_ERR_HCI_GET_TX_MUTEX_FAILED,
|
||||
CYBT_ERR_HCI_GET_RX_MUTEX_FAILED,
|
||||
CYBT_ERR_HCI_SET_BAUDRATE_FAILED,
|
||||
CYBT_ERR_HCI_SET_FLOW_CTRL_FAILED,
|
||||
CYBT_ERR_INIT_MEMPOOL_FAILED,
|
||||
CYBT_ERR_INIT_QUEUE_FAILED,
|
||||
CYBT_ERR_CREATE_TASK_FAILED,
|
||||
CYBT_ERR_SEND_QUEUE_FAILED,
|
||||
CYBT_ERR_MEMPOOL_NOT_INITIALIZE,
|
||||
CYBT_ERR_QUEUE_ALMOST_FULL,
|
||||
CYBT_ERR_QUEUE_FULL,
|
||||
CYBT_ERR_GPIO_POWER_INIT_FAILED,
|
||||
CYBT_ERR_GPIO_DEV_WAKE_INIT_FAILED,
|
||||
CYBT_ERR_GPIO_HOST_WAKE_INIT_FAILED,
|
||||
CYBT_ERR_GENERIC
|
||||
} cybt_result_t;
|
||||
|
||||
typedef enum {
|
||||
H2B_BUF_ADDR_IDX = 0x10,
|
||||
H2B_BUF_IN_ADDR_IDX,
|
||||
H2B_BUF_OUT_ADDR_IDX,
|
||||
B2H_BUF_ADDR_IDX,
|
||||
B2H_BUF_IN_ADDR_IDX,
|
||||
B2H_BUF_OUT_ADDR_IDX,
|
||||
} cybt_addr_idx_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t host2bt_in_val;
|
||||
uint32_t host2bt_out_val;
|
||||
uint32_t bt2host_in_val;
|
||||
uint32_t bt2host_out_val;
|
||||
} cybt_fw_membuf_index_t;
|
||||
|
||||
struct _cyw43_ll_t;
|
||||
void cybt_sharedbus_driver_init(struct _cyw43_ll_t *driver);
|
||||
|
||||
cybt_result_t cybt_init_buffer(void);
|
||||
|
||||
cybt_result_t cybt_reg_write_idx(cybt_addr_idx_t reg_idx, uint32_t value);
|
||||
cybt_result_t cybt_mem_write_idx(cybt_addr_idx_t mem_idx, uint32_t offset, const uint8_t *p_data, uint32_t data_len);
|
||||
cybt_result_t cybt_mem_read_idx(cybt_addr_idx_t mem_idx, uint32_t offset, uint8_t *p_data, uint32_t data_len);
|
||||
|
||||
cybt_result_t cybt_fw_download(const uint8_t *p_bt_firmware, uint32_t bt_firmware_len, uint8_t *p_write_buf, uint8_t *p_hex_buf);
|
||||
|
||||
int cybt_ready(void);
|
||||
int cybt_awake(void);
|
||||
|
||||
cybt_result_t cybt_set_bt_awake(int value);
|
||||
cybt_result_t cybt_set_host_ready(void);
|
||||
cybt_result_t cybt_set_bt_intr(int value);
|
||||
cybt_result_t cybt_toggle_bt_intr(void);
|
||||
cybt_result_t cybt_get_bt_buf_index(cybt_fw_membuf_index_t *p_buf_index);
|
||||
|
||||
void cybt_debug_dump(void);
|
||||
|
||||
#endif
|
@ -482,12 +482,12 @@ int cyw43_write_reg_u8(cyw43_int_t *self, uint32_t fn, uint32_t reg, uint32_t va
|
||||
#error Block size is wrong for SPI
|
||||
#endif
|
||||
|
||||
// Assumes we're reading into spid_buf
|
||||
int cyw43_read_bytes(cyw43_int_t *self, uint32_t fn, uint32_t addr, size_t len, uint8_t *buf) {
|
||||
assert(fn != BACKPLANE_FUNCTION || (len <= 64 && (addr + len) <= 0x8000));
|
||||
const uint32_t padding = (fn == BACKPLANE_FUNCTION) ? 4 : 0; // Add response delay
|
||||
size_t aligned_len = (len + 3) & ~3;
|
||||
assert(aligned_len > 0 && aligned_len <= 0x7f8);
|
||||
assert(buf == self->spid_buf || buf < self->spid_buf || buf >= (self->spid_buf + sizeof(self->spid_buf)));
|
||||
self->spi_header[padding > 0 ? 0 : 1] = make_cmd(false, true, fn, addr, len + padding);
|
||||
if (fn == WLAN_FUNCTION) {
|
||||
logic_debug_set(pin_WIFI_RX, 1);
|
||||
|
@ -62,6 +62,14 @@ extern "C" {
|
||||
#define CYW43_SPI_PIO 1
|
||||
#endif
|
||||
|
||||
#ifndef CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE
|
||||
#if CYW43_ENABLE_BLUETOOTH
|
||||
#define CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE "wb43439A0_7_95_49_00_combined.h"
|
||||
#else
|
||||
#define CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE "w43439A0_7_95_49_00_combined.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CYW43_WIFI_NVRAM_INCLUDE_FILE
|
||||
#define CYW43_WIFI_NVRAM_INCLUDE_FILE "wifi_nvram_43439.h"
|
||||
#endif
|
||||
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _PICO_BTSTACK_CYW43_H
|
||||
#define _PICO_BTSTACK_CYW43_H
|
||||
|
||||
#include "pico/async_context.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file pico/btstack_cyw43.h
|
||||
* \defgroup pico_bstack_cyw43
|
||||
* \ingroup pico_cyw43_driver
|
||||
*
|
||||
* \brief Low-level Bluetooth HCI support.
|
||||
*
|
||||
* This library provides utility functions to initialise and de-initialise BTstack for CYW43,
|
||||
*/
|
||||
|
||||
/*
|
||||
* \brief Perform initialisation of BTstack/CYW43 integration
|
||||
* \ingroup pico_btstack_cyw43
|
||||
*
|
||||
* \param context the async_context instance that provides the abstraction for handling asynchronous work.
|
||||
* \return true on success or false an error
|
||||
*/
|
||||
bool btstack_cyw43_init(async_context_t *context);
|
||||
|
||||
/*
|
||||
* \brief De-initialise BTstack/CYW43 integration
|
||||
* \ingroup pico_btstack_cyw43
|
||||
*
|
||||
* \param context the async_context the btstack_cyw43 support was added to via \ref btstack_cyw43_init
|
||||
*/
|
||||
void btstack_cyw43_deinit(async_context_t *context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _PICO_BTSTACK_HCI_TRANSPORT_CYW43_H
|
||||
#define _PICO_BTSTACK_HCI_TRANSPORT_CYW43_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file pico/btstack_hci_transport_cyw43.h
|
||||
* \ingroup pico_cyw43_driver
|
||||
* \brief Adds low level Bluetooth HCI support
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Get the Bluetooth HCI transport instance for cyw43
|
||||
* \ingroup pico_cyw43_driver
|
||||
*
|
||||
* \return An instantiation of the hci_transport_t interface for the cyw43 chipset
|
||||
*/
|
||||
const hci_transport_t *hci_transport_cyw43_instance(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // HCI_TRANSPORT_CYW43_H
|
@ -4,8 +4,8 @@
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _PICO_CYW43_DRIVER_ASYNC_CONTEXT_H
|
||||
#define _PICO_CYW43_DRIVER_ASYNC_CONTEXT_H
|
||||
#ifndef _PICO_CYW43_DRIVER_H
|
||||
#define _PICO_CYW43_DRIVER_H
|
||||
|
||||
/** \file pico/cyw43_driver.h
|
||||
* \defgroup pico_cyw43_driver pico_cyw43_driver
|
||||
|
@ -5,8 +5,8 @@
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _PICO_I2C_SLAVE_H_
|
||||
#define _PICO_I2C_SLAVE_H_
|
||||
#ifndef _PICO_I2C_SLAVE_H
|
||||
#define _PICO_I2C_SLAVE_H
|
||||
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
|
@ -264,6 +264,7 @@ if (EXISTS ${PICO_LWIP_PATH}/${LWIP_TEST_PATH})
|
||||
pico_add_library(pico_lwip_arch NOFLAG)
|
||||
target_include_directories(pico_lwip_arch_headers INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
target_link_libraries(pico_lwip_arch INTERFACE pico_rand)
|
||||
|
||||
# our nosys impl
|
||||
pico_add_library(pico_lwip_nosys NOFLAG)
|
||||
@ -273,8 +274,7 @@ if (EXISTS ${PICO_LWIP_PATH}/${LWIP_TEST_PATH})
|
||||
pico_mirrored_target_link_libraries(pico_lwip_nosys INTERFACE
|
||||
pico_async_context_base
|
||||
pico_lwip_arch
|
||||
pico_lwip
|
||||
pico_rand)
|
||||
pico_lwip)
|
||||
|
||||
if (NOT PICO_LWIP_CONTRIB_PATH)
|
||||
set(PICO_LWIP_CONTRIB_PATH ${PICO_LWIP_PATH}/contrib)
|
||||
|
@ -131,6 +131,10 @@ if (TARGET pico_cyw43_arch)
|
||||
pico_add_extra_outputs(kitchen_sink_lwip_poll)
|
||||
target_link_libraries(kitchen_sink_lwip_poll
|
||||
pico_cyw43_arch_lwip_poll)
|
||||
if (TARGET pico_btstack)
|
||||
target_link_libraries(kitchen_sink_lwip_poll
|
||||
pico_btstack_ble pico_btstack_classic pico_btstack_cyw43)
|
||||
endif()
|
||||
# for lwipopts.h
|
||||
target_include_directories(kitchen_sink_lwip_poll PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR})
|
||||
@ -154,3 +158,7 @@ if (TARGET pico_cyw43_arch)
|
||||
suppress_mbedtls_warnings()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (TARGET pico_btstack_base AND COMMAND suppress_btstack_warnings)
|
||||
suppress_btstack_warnings()
|
||||
endif()
|
||||
|
73
test/kitchen_sink/btstack_config.h
Normal file
73
test/kitchen_sink/btstack_config.h
Normal file
@ -0,0 +1,73 @@
|
||||
#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
|
||||
|
||||
// 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_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 1
|
||||
|
||||
#define MAX_NR_LE_DEVICE_DB_ENTRIES 4
|
||||
|
||||
// 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
|
||||
|
||||
#define ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
|
||||
|
||||
#endif // MICROPY_INCLUDED_EXTMOD_BTSTACK_BTSTACK_CONFIG_H
|
Loading…
Reference in New Issue
Block a user