Add Bluetooth support
Co-authored-by: Peter Harper <77111776+peterharperuk@users.noreply.github.com>
This commit is contained in:
		
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @ -10,3 +10,6 @@ | |||||||
| [submodule "lib/mbedtls"] | [submodule "lib/mbedtls"] | ||||||
| 	path = lib/mbedtls | 	path = lib/mbedtls | ||||||
| 	url = https://github.com/Mbed-TLS/mbedtls.git | 	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 |  * \defgroup networking Networking Libraries | ||||||
|  * Functions for implementing networking |  * Functions for implementing networking | ||||||
|  * @{ |  * @{ | ||||||
|  * \defgroup pico_cyw43_driver pico_cyw43_driver |  * \defgroup pico_btstack pico_btstack | ||||||
|  * \defgroup pico_lwip pico_lwip |  * \defgroup pico_lwip pico_lwip | ||||||
|  |  * \defgroup pico_cyw43_driver pico_cyw43_driver | ||||||
|  * \defgroup pico_cyw43_arch pico_cyw43_arch |  * \defgroup pico_cyw43_arch pico_cyw43_arch | ||||||
|  * @} |  * @} | ||||||
|  * |  * | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								lib/btstack
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								lib/btstack
									
									
									
									
									
										Submodule
									
								
							 Submodule lib/btstack added at 0d212321a9
									
								
							 Submodule lib/cyw43-driver updated: 83e0c700c2...9bfca61173
									
								
							| @ -58,10 +58,11 @@ if (NOT PICO_BARE_METAL) | |||||||
|     pico_add_subdirectory(cmsis) |     pico_add_subdirectory(cmsis) | ||||||
|     pico_add_subdirectory(tinyusb) |     pico_add_subdirectory(tinyusb) | ||||||
|     pico_add_subdirectory(pico_stdio_usb) |     pico_add_subdirectory(pico_stdio_usb) | ||||||
|  |  | ||||||
|     pico_add_subdirectory(pico_i2c_slave) |     pico_add_subdirectory(pico_i2c_slave) | ||||||
|  |  | ||||||
|  |     # networking libraries - note dependency order is important | ||||||
|     pico_add_subdirectory(pico_async_context) |     pico_add_subdirectory(pico_async_context) | ||||||
|  |     pico_add_subdirectory(pico_btstack) | ||||||
|     pico_add_subdirectory(pico_cyw43_driver) |     pico_add_subdirectory(pico_cyw43_driver) | ||||||
|     pico_add_subdirectory(pico_lwip) |     pico_add_subdirectory(pico_lwip) | ||||||
|     pico_add_subdirectory(pico_cyw43_arch) |     pico_add_subdirectory(pico_cyw43_arch) | ||||||
|  | |||||||
| @ -168,10 +168,12 @@ void async_context_freertos_acquire_lock_blocking(async_context_t *self_base) { | |||||||
|     self->nesting++; |     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; |     async_context_freertos_t *self = (async_context_freertos_t *)self_base; | ||||||
|     // Lock the other core and stop low_prio_irq running |     // Lock the other core and stop low_prio_irq running | ||||||
|     assert(xSemaphoreGetMutexHolder(self->lock_mutex) == xTaskGetCurrentTaskHandle()); |     assert(xSemaphoreGetMutexHolder(self->lock_mutex) == xTaskGetCurrentTaskHandle()); | ||||||
|  | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| typedef struct sync_func_call{ | 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) |         if (NOT TARGET pico_lwip) | ||||||
|             message(WARNING "lwIP is not available; Full Pico W wireless support will be unavailable") |             message(WARNING "lwIP is not available; Full Pico W wireless support will be unavailable") | ||||||
|         else() |         else() | ||||||
|             message("Pico W wireless build support available.") |             message("Pico W Wi-Fi build support available.") | ||||||
|             pico_add_library(pico_cyw43_arch_poll NOFLAG) |             pico_add_library(pico_cyw43_arch_poll NOFLAG) | ||||||
|             target_compile_definitions(pico_cyw43_arch_poll_headers INTERFACE |             target_compile_definitions(pico_cyw43_arch_poll_headers INTERFACE | ||||||
|                     PICO_CYW43_ARCH_POLL=1 |                     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 | #if PICO_CYW43_ARCH_DEBUG_ENABLED | ||||||
| // Return a string for the wireless state | // 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) { |     switch (status) { | ||||||
|     case CYW43_LINK_DOWN: |     case CYW43_LINK_DOWN: | ||||||
|  | |||||||
| @ -15,6 +15,10 @@ | |||||||
| #include <lwip/tcpip.h> | #include <lwip/tcpip.h> | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #if CYW43_ENABLE_BLUETOOTH | ||||||
|  | #include "pico/btstack_cyw43.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #if NO_SYS | #if NO_SYS | ||||||
| #error example_cyw43_arch_freetos_sys requires NO_SYS=0 | #error example_cyw43_arch_freetos_sys requires NO_SYS=0 | ||||||
| #endif | #endif | ||||||
| @ -44,6 +48,9 @@ int cyw43_arch_init(void) { | |||||||
|     bool ok = cyw43_driver_init(context); |     bool ok = cyw43_driver_init(context); | ||||||
| #if CYW43_LWIP | #if CYW43_LWIP | ||||||
|     ok &= lwip_freertos_init(context); |     ok &= lwip_freertos_init(context); | ||||||
|  | #endif | ||||||
|  | #if CYW43_ENABLE_BLUETOOTH | ||||||
|  |     ok &= btstack_cyw43_init(context); | ||||||
| #endif | #endif | ||||||
|     if (!ok) { |     if (!ok) { | ||||||
|         cyw43_arch_deinit(); |         cyw43_arch_deinit(); | ||||||
| @ -55,6 +62,9 @@ int cyw43_arch_init(void) { | |||||||
|  |  | ||||||
| void cyw43_arch_deinit(void) { | void cyw43_arch_deinit(void) { | ||||||
|     async_context_t *context = cyw43_arch_async_context(); |     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 |     // 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 |     // shut down cyw43_driver first as it has IRQs calling back into lwIP. Also lwIP itself | ||||||
|     // does not actually get shut down. |     // does not actually get shut down. | ||||||
|  | |||||||
| @ -13,6 +13,10 @@ | |||||||
| #include "pico/lwip_nosys.h" | #include "pico/lwip_nosys.h" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #if CYW43_ENABLE_BLUETOOTH | ||||||
|  | #include "pico/btstack_cyw43.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #if CYW43_LWIP && !NO_SYS | #if CYW43_LWIP && !NO_SYS | ||||||
| #error PICO_CYW43_ARCH_POLL requires lwIP NO_SYS=1 | #error PICO_CYW43_ARCH_POLL requires lwIP NO_SYS=1 | ||||||
| #endif | #endif | ||||||
| @ -35,6 +39,9 @@ int cyw43_arch_init(void) { | |||||||
|     bool ok = cyw43_driver_init(context); |     bool ok = cyw43_driver_init(context); | ||||||
| #if CYW43_LWIP | #if CYW43_LWIP | ||||||
|     ok &= lwip_nosys_init(context); |     ok &= lwip_nosys_init(context); | ||||||
|  | #endif | ||||||
|  | #if CYW43_ENABLE_BLUETOOTH | ||||||
|  |     ok &= btstack_cyw43_init(context); | ||||||
| #endif | #endif | ||||||
|     if (!ok) { |     if (!ok) { | ||||||
|         cyw43_arch_deinit(); |         cyw43_arch_deinit(); | ||||||
| @ -46,6 +53,9 @@ int cyw43_arch_init(void) { | |||||||
|  |  | ||||||
| void cyw43_arch_deinit(void) { | void cyw43_arch_deinit(void) { | ||||||
|     async_context_t *context = cyw43_arch_async_context(); |     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 |     // 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 |     // shut down cyw43_driver first as it has IRQs calling back into lwIP. Also lwIP itself | ||||||
|     // does not actually get shut down. |     // does not actually get shut down. | ||||||
|  | |||||||
| @ -14,6 +14,10 @@ | |||||||
| #include "pico/lwip_nosys.h" | #include "pico/lwip_nosys.h" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #if CYW43_ENABLE_BLUETOOTH | ||||||
|  | #include "pico/btstack_cyw43.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #if CYW43_LWIP && !NO_SYS | #if CYW43_LWIP && !NO_SYS | ||||||
| #error PICO_CYW43_ARCH_THREADSAFE_BACKGROUND requires lwIP NO_SYS=1 | #error PICO_CYW43_ARCH_THREADSAFE_BACKGROUND requires lwIP NO_SYS=1 | ||||||
| #endif | #endif | ||||||
| @ -41,6 +45,9 @@ int cyw43_arch_init(void) { | |||||||
|     bool ok = cyw43_driver_init(context); |     bool ok = cyw43_driver_init(context); | ||||||
| #if CYW43_LWIP | #if CYW43_LWIP | ||||||
|     ok &= lwip_nosys_init(context); |     ok &= lwip_nosys_init(context); | ||||||
|  | #endif | ||||||
|  | #if CYW43_ENABLE_BLUETOOTH | ||||||
|  |     ok &= btstack_cyw43_init(context); | ||||||
| #endif | #endif | ||||||
|     if (!ok) { |     if (!ok) { | ||||||
|         cyw43_arch_deinit(); |         cyw43_arch_deinit(); | ||||||
| @ -52,6 +59,9 @@ int cyw43_arch_init(void) { | |||||||
|  |  | ||||||
| void cyw43_arch_deinit(void) { | void cyw43_arch_deinit(void) { | ||||||
|     async_context_t *context = cyw43_arch_async_context(); |     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 |     // 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 |     // shut down cyw43_driver first as it has IRQs calling back into lwIP. Also lwIP itself | ||||||
|     // does not actually get shut down. |     // does not actually get shut down. | ||||||
|  | |||||||
| @ -18,6 +18,8 @@ endif() | |||||||
| if (EXISTS ${PICO_CYW43_DRIVER_PATH}/${CYW43_DRIVER_TEST_FILE}) | if (EXISTS ${PICO_CYW43_DRIVER_PATH}/${CYW43_DRIVER_TEST_FILE}) | ||||||
|     message("cyw43-driver available at ${PICO_CYW43_DRIVER_PATH}") |     message("cyw43-driver available at ${PICO_CYW43_DRIVER_PATH}") | ||||||
|  |  | ||||||
|  |     add_subdirectory(cybt_shared_bus) | ||||||
|  |  | ||||||
|     pico_register_common_scope_var(PICO_CYW43_DRIVER_PATH) |     pico_register_common_scope_var(PICO_CYW43_DRIVER_PATH) | ||||||
|  |  | ||||||
|     # base driver without our bus |     # 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) |     target_include_directories(pico_cyw43_driver_headers INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include) | ||||||
|     pico_mirrored_target_link_libraries(pico_cyw43_driver INTERFACE cyw43_driver) |     pico_mirrored_target_link_libraries(pico_cyw43_driver INTERFACE cyw43_driver) | ||||||
|  |  | ||||||
|     # Firmware stuff |     # cyw43_driver_picow is cyw43_driver plus Pico W specific bus implementation | ||||||
|     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 |  | ||||||
|     pico_add_library(cyw43_driver_picow NOFLAG) |     pico_add_library(cyw43_driver_picow NOFLAG) | ||||||
|     target_sources(cyw43_driver_picow INTERFACE |     target_sources(cyw43_driver_picow INTERFACE | ||||||
|             ${CMAKE_CURRENT_LIST_DIR}/cyw43_bus_pio_spi.c |             ${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) |     pico_generate_pio_header(cyw43_driver_picow ${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_mirrored_target_link_libraries(cyw43_driver_picow INTERFACE |     pico_mirrored_target_link_libraries(cyw43_driver_picow INTERFACE | ||||||
|             cyw43_driver |             cyw43_driver | ||||||
|  |             cybt_shared_bus | ||||||
|             hardware_pio |             hardware_pio | ||||||
|             hardware_dma |             hardware_dma | ||||||
|             hardware_exception |             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() |     pico_promote_common_scope_vars() | ||||||
| endif() | 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 | #error Block size is wrong for SPI | ||||||
| #endif | #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) { | 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)); |     assert(fn != BACKPLANE_FUNCTION || (len <= 64 && (addr + len) <= 0x8000)); | ||||||
|     const uint32_t padding = (fn == BACKPLANE_FUNCTION) ? 4 : 0; // Add response delay |     const uint32_t padding = (fn == BACKPLANE_FUNCTION) ? 4 : 0; // Add response delay | ||||||
|     size_t aligned_len = (len + 3) & ~3; |     size_t aligned_len = (len + 3) & ~3; | ||||||
|     assert(aligned_len > 0 && aligned_len <= 0x7f8); |     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); |     self->spi_header[padding > 0 ? 0 : 1] = make_cmd(false, true, fn, addr, len + padding); | ||||||
|     if (fn == WLAN_FUNCTION) { |     if (fn == WLAN_FUNCTION) { | ||||||
|         logic_debug_set(pin_WIFI_RX, 1); |         logic_debug_set(pin_WIFI_RX, 1); | ||||||
|  | |||||||
| @ -62,6 +62,14 @@ extern "C" { | |||||||
| #define CYW43_SPI_PIO 1 | #define CYW43_SPI_PIO 1 | ||||||
| #endif | #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 | #ifndef CYW43_WIFI_NVRAM_INCLUDE_FILE | ||||||
| #define CYW43_WIFI_NVRAM_INCLUDE_FILE "wifi_nvram_43439.h" | #define CYW43_WIFI_NVRAM_INCLUDE_FILE "wifi_nvram_43439.h" | ||||||
| #endif | #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 |  * SPDX-License-Identifier: BSD-3-Clause | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #ifndef _PICO_CYW43_DRIVER_ASYNC_CONTEXT_H | #ifndef _PICO_CYW43_DRIVER_H | ||||||
| #define _PICO_CYW43_DRIVER_ASYNC_CONTEXT_H | #define _PICO_CYW43_DRIVER_H | ||||||
|  |  | ||||||
| /** \file pico/cyw43_driver.h | /** \file pico/cyw43_driver.h | ||||||
|  *  \defgroup pico_cyw43_driver pico_cyw43_driver |  *  \defgroup pico_cyw43_driver pico_cyw43_driver | ||||||
|  | |||||||
| @ -5,8 +5,8 @@ | |||||||
|  * SPDX-License-Identifier: BSD-3-Clause |  * SPDX-License-Identifier: BSD-3-Clause | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #ifndef _PICO_I2C_SLAVE_H_ | #ifndef _PICO_I2C_SLAVE_H | ||||||
| #define _PICO_I2C_SLAVE_H_ | #define _PICO_I2C_SLAVE_H | ||||||
|  |  | ||||||
| #include "hardware/i2c.h" | #include "hardware/i2c.h" | ||||||
|  |  | ||||||
|  | |||||||
| @ -264,6 +264,7 @@ if (EXISTS ${PICO_LWIP_PATH}/${LWIP_TEST_PATH}) | |||||||
|     pico_add_library(pico_lwip_arch NOFLAG) |     pico_add_library(pico_lwip_arch NOFLAG) | ||||||
|     target_include_directories(pico_lwip_arch_headers INTERFACE |     target_include_directories(pico_lwip_arch_headers INTERFACE | ||||||
|             ${CMAKE_CURRENT_LIST_DIR}/include) |             ${CMAKE_CURRENT_LIST_DIR}/include) | ||||||
|  |     target_link_libraries(pico_lwip_arch INTERFACE pico_rand) | ||||||
|  |  | ||||||
|     # our nosys impl |     # our nosys impl | ||||||
|     pico_add_library(pico_lwip_nosys NOFLAG) |     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_mirrored_target_link_libraries(pico_lwip_nosys INTERFACE | ||||||
|             pico_async_context_base |             pico_async_context_base | ||||||
|             pico_lwip_arch |             pico_lwip_arch | ||||||
|             pico_lwip |             pico_lwip) | ||||||
|             pico_rand) |  | ||||||
|  |  | ||||||
|     if (NOT PICO_LWIP_CONTRIB_PATH) |     if (NOT PICO_LWIP_CONTRIB_PATH) | ||||||
|         set(PICO_LWIP_CONTRIB_PATH ${PICO_LWIP_PATH}/contrib) |         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) |     pico_add_extra_outputs(kitchen_sink_lwip_poll) | ||||||
|     target_link_libraries(kitchen_sink_lwip_poll |     target_link_libraries(kitchen_sink_lwip_poll | ||||||
|             pico_cyw43_arch_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 |     # for lwipopts.h | ||||||
|     target_include_directories(kitchen_sink_lwip_poll PRIVATE |     target_include_directories(kitchen_sink_lwip_poll PRIVATE | ||||||
|             ${CMAKE_CURRENT_LIST_DIR}) |             ${CMAKE_CURRENT_LIST_DIR}) | ||||||
| @ -154,3 +158,7 @@ if (TARGET pico_cyw43_arch) | |||||||
|         suppress_mbedtls_warnings() |         suppress_mbedtls_warnings() | ||||||
|     endif() |     endif() | ||||||
| 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 | ||||||
		Reference in New Issue
	
	Block a user