diff --git a/.gitmodules b/.gitmodules index 7c382da67..eb4b7b4fd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "lib/btstack"] path = lib/btstack url = https://github.com/bluekitchen/btstack.git +[submodule "lib/uzlib"] + path = lib/uzlib + url = git@github.com:pfalcon/uzlib.git diff --git a/lib/cyw43-driver b/lib/cyw43-driver index 9bfca6117..24362d6cd 160000 --- a/lib/cyw43-driver +++ b/lib/cyw43-driver @@ -1 +1 @@ -Subproject commit 9bfca61173a94432839cd39210f1d1afdf602c42 +Subproject commit 24362d6cd2a1e6d34ace9d369059f36f525e42a6 diff --git a/lib/uzlib b/lib/uzlib new file mode 160000 index 000000000..6d60d651a --- /dev/null +++ b/lib/uzlib @@ -0,0 +1 @@ +Subproject commit 6d60d651a4499a64f2e5b21b4cc08d98cb84b5c1 diff --git a/src/rp2_common/CMakeLists.txt b/src/rp2_common/CMakeLists.txt index eff827b6a..30d084974 100644 --- a/src/rp2_common/CMakeLists.txt +++ b/src/rp2_common/CMakeLists.txt @@ -67,6 +67,7 @@ if (NOT PICO_BARE_METAL) pico_add_subdirectory(pico_lwip) pico_add_subdirectory(pico_cyw43_arch) pico_add_subdirectory(pico_mbedtls) + pico_add_subdirectory(pico_uzlib) pico_add_subdirectory(pico_stdlib) @@ -84,4 +85,4 @@ set(CMAKE_EXECUTABLE_SUFFIX "${CMAKE_EXECUTABLE_SUFFIX}" PARENT_SCOPE) pico_add_doxygen(${CMAKE_CURRENT_LIST_DIR}) pico_add_doxygen_exclude(${CMAKE_CURRENT_LIST_DIR}/cmsis) -pico_promote_common_scope_vars() \ No newline at end of file +pico_promote_common_scope_vars() diff --git a/src/rp2_common/pico_cyw43_driver/CMakeLists.txt b/src/rp2_common/pico_cyw43_driver/CMakeLists.txt index 4cdf95b33..ebee1f87b 100644 --- a/src/rp2_common/pico_cyw43_driver/CMakeLists.txt +++ b/src/rp2_common/pico_cyw43_driver/CMakeLists.txt @@ -15,6 +15,10 @@ elseif (NOT EXISTS ${PICO_CYW43_DRIVER_PATH}/${CYW43_DRIVER_TEST_FILE}) message(WARNING "PICO_CYW43_DRIVER_PATH specified but content not present.") endif() +if (NOT DEFINED PICO_CYW43_DRIVER_USES_UZLIB) + set(PICO_CYW43_DRIVER_USES_UZLIB 1) +endif() + if (EXISTS ${PICO_CYW43_DRIVER_PATH}/${CYW43_DRIVER_TEST_FILE}) message("cyw43-driver available at ${PICO_CYW43_DRIVER_PATH}") @@ -29,6 +33,7 @@ if (EXISTS ${PICO_CYW43_DRIVER_PATH}/${CYW43_DRIVER_TEST_FILE}) ${PICO_CYW43_DRIVER_PATH}/src/cyw43_stats.c ${PICO_CYW43_DRIVER_PATH}/src/cyw43_lwip.c ${PICO_CYW43_DRIVER_PATH}/src/cyw43_ctrl.c + ${PICO_CYW43_DRIVER_PATH}/src/cyw43_gz_read.c ) target_include_directories(cyw43_driver_headers INTERFACE ${PICO_CYW43_DRIVER_PATH}/src @@ -55,7 +60,12 @@ if (EXISTS ${PICO_CYW43_DRIVER_PATH}/${CYW43_DRIVER_TEST_FILE}) hardware_dma hardware_exception ) - + # MP has its own uzlib driver that's used for firmware decompression + if (PICO_CYW43_DRIVER_USES_UZLIB) + pico_mirrored_target_link_libraries(cyw43_driver_picow INTERFACE + pico_uzlib + ) + endif() # 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) diff --git a/src/rp2_common/pico_cyw43_driver/cybt_shared_bus/cybt_shared_bus.c b/src/rp2_common/pico_cyw43_driver/cybt_shared_bus/cybt_shared_bus.c index b464b3f78..a2b763082 100644 --- a/src/rp2_common/pico_cyw43_driver/cybt_shared_bus/cybt_shared_bus.c +++ b/src/rp2_common/pico_cyw43_driver/cybt_shared_bus/cybt_shared_bus.c @@ -14,8 +14,6 @@ #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[]; @@ -124,8 +122,8 @@ int cyw43_btbus_init(cyw43_ll_t *self) { } cybt_debug("cybt_fw_download\n"); - const uint8_t *fw_data_buf; - uint32_t fw_data_len; + const uint8_t *fw_data_buf = NULL; + uint32_t fw_data_len = 0; #if CYW43_USE_HEX_BTFW cybt_printf("CYW43_USE_HEX_BTFW is true\n"); #ifndef NDEBUG @@ -133,16 +131,11 @@ int cyw43_btbus_init(cyw43_ll_t *self) { #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 - ); - + p_hex_buf); cybt_debug("cybt_fw_download_finish\n"); cybt_fw_download_finish(p_write_buf, p_hex_buf); diff --git a/src/rp2_common/pico_cyw43_driver/cybt_shared_bus/cybt_shared_bus_driver.c b/src/rp2_common/pico_cyw43_driver/cybt_shared_bus/cybt_shared_bus_driver.c index 8de0f6ad3..924449455 100644 --- a/src/rp2_common/pico_cyw43_driver/cybt_shared_bus/cybt_shared_bus_driver.c +++ b/src/rp2_common/pico_cyw43_driver/cybt_shared_bus/cybt_shared_bus_driver.c @@ -11,6 +11,7 @@ #include "cyw43_ll.h" #include "cybt_shared_bus_driver.h" +#include "cyw43_firmware_defs.h" // Bluetooth register corruption occurs if both wifi and bluetooth are fully utilised. #define CYBT_CORRUPTION_TEST 1 @@ -80,7 +81,7 @@ typedef struct uint32_t bt2host_out_addr; } cybt_fw_membuf_info_t; -cybt_fw_membuf_info_t buf_info; +static cybt_fw_membuf_info_t buf_info; #define BTFW_ADDR_MODE_UNKNOWN (0) #define BTFW_ADDR_MODE_EXTENDED (1) @@ -111,7 +112,6 @@ cybt_fw_membuf_info_t buf_info; 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; @@ -131,6 +131,7 @@ typedef struct hex_file_data #endif static cyw43_ll_t *cyw43_ll = NULL; +static void *streaming_context; 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); @@ -261,21 +262,37 @@ static uint32_t cybt_fw_get_data(cybt_fw_cb_t *p_btfw_cb, } #else +static void cybt_fw_get_bytes(uint8_t *dst, const uint8_t **addr, uint8_t count) { +#if CYW43_USE_HEX_BTFW + memcpy(dst, *addr, count); +#else + const uint8_t *data = cyw43_get_firmware_funcs()->stream_fw(streaming_context, count, dst); + if (data != dst) { + memcpy(dst, data, count); + } +#endif + *addr += count; +} + 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)++; + uint8_t num_bytes; + cybt_fw_get_bytes(&num_bytes, &p_btfw_cb->p_next_line_start, 1); + + uint16_t addr; + cybt_fw_get_bytes((uint8_t*)&addr, &p_btfw_cb->p_next_line_start, 2); + addr = (((addr >> 8) & 0xff) | ((addr & 0xff) << 8)); + + uint8_t type; + cybt_fw_get_bytes(&type, &p_btfw_cb->p_next_line_start, 1); // 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; + cybt_fw_get_bytes(hfd->p_ds, &p_btfw_cb->p_next_line_start, num_bytes); // Adjust address based on type if (type == BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS) { @@ -318,19 +335,29 @@ cybt_result_t cybt_fw_download(const uint8_t *p_bt_firmware, return CYBT_ERR_BADARG; } - if (NULL == p_bt_firmware || 0 == bt_firmware_len || NULL == p_write_buf || NULL == p_hex_buf) { + if (NULL == p_write_buf || NULL == p_hex_buf) { return CYBT_ERR_BADARG; } - +#if CYW43_USE_HEX_BTFW + if (NULL == p_bt_firmware || 0 == bt_firmware_len) { + return CYBT_ERR_BADARG; + } +#else + if (cyw43_get_firmware_funcs()->start_fw_stream(cyw43_get_firmware_funcs()->firmware_details(), CYW43_FIRMWARE_BLUETOOTH, &streaming_context) != 0) { + assert(false); + return CYW43_EIO; + } // 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); + uint8_t version_len; + cybt_fw_get_bytes(&version_len, &p_bt_firmware, 1); + cybt_fw_get_bytes(p_hex_buf, &p_bt_firmware, version_len); + assert(*(p_hex_buf + version_len - 1) == 0); #ifndef NDEBUG - cybt_printf("BT FW download, version = %s\n", p_bt_firmware + 1); + cybt_printf("BT FW download, version = %s\n", p_hex_buf); #endif - p_bt_firmware += version_len + 1; // skip over version - p_bt_firmware += 1; // skip over record count + uint8_t record_count; + cybt_fw_get_bytes(&record_count, &p_bt_firmware, 1); + (void)record_count; #endif p_mem_ptr = p_write_buf; @@ -340,7 +367,6 @@ cybt_result_t cybt_fw_download(const uint8_t *p_bt_firmware, 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; @@ -395,7 +421,9 @@ cybt_result_t cybt_fw_download(const uint8_t *p_bt_firmware, write_data_len - first_write_len); } } - +#if !CYW43_USE_HEX_BTFW + cyw43_get_firmware_funcs()->end_fw_stream(streaming_context, CYW43_FIRMWARE_BLUETOOTH); +#endif return CYBT_SUCCESS; } diff --git a/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c b/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c index 169933010..7fbc63805 100644 --- a/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c +++ b/src/rp2_common/pico_cyw43_driver/cyw43_bus_pio_spi.c @@ -534,9 +534,14 @@ int cyw43_write_bytes(cyw43_int_t *self, uint32_t fn, uint32_t addr, size_t len, int res = cyw43_spi_transfer(self, (uint8_t *)&self->spi_header[1], aligned_len + 4, NULL, 0); logic_debug_set(pin_WIFI_TX, 0); return res; + } else if (src > self->spid_buf + sizeof(uint32_t) && src < (self->spid_buf + sizeof(self->spid_buf))) { + assert(src + len <= (self->spid_buf + sizeof(self->spid_buf))); // don't go over the end of the buffer + uint32_t *spi_header = (void*)(self->spid_buf + (src - self->spid_buf) - sizeof(uint32_t)); + *spi_header = make_cmd(true, true, fn, addr, len); + return cyw43_spi_transfer(self, (uint8_t *)spi_header, aligned_len + 4, NULL, 0); } else { // todo: would be nice to get rid of this. Only used for firmware download? - assert(src < self->spid_buf || src >= (self->spid_buf + sizeof(self->spid_buf))); + assert(src < self->spid_buf || src >= (self->spid_buf + sizeof(self->spid_buf))); // check we're not using self->spid_buf self->spi_header[1] = make_cmd(true, true, fn, addr, len); memcpy(self->spid_buf, src, len); return cyw43_spi_transfer(self, (uint8_t *)&self->spi_header[1], aligned_len + 4, NULL, 0); diff --git a/src/rp2_common/pico_cyw43_driver/include/cyw43_configport.h b/src/rp2_common/pico_cyw43_driver/include/cyw43_configport.h index f012d2458..be62930c2 100644 --- a/src/rp2_common/pico_cyw43_driver/include/cyw43_configport.h +++ b/src/rp2_common/pico_cyw43_driver/include/cyw43_configport.h @@ -12,6 +12,7 @@ #include "pico.h" #include "hardware/gpio.h" #include "pico/time.h" +#include "hardware/flash.h" #ifdef __cplusplus extern "C" { @@ -62,18 +63,39 @@ extern "C" { #define CYW43_SPI_PIO 1 #endif +// Compress firmware by default +#ifndef CYW43_ENABLE_FIRMWARE_COMPRESSION +#define CYW43_ENABLE_FIRMWARE_COMPRESSION 1 +#endif + #ifndef CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE #if CYW43_ENABLE_BLUETOOTH +#if CYW43_ENABLE_FIRMWARE_COMPRESSION +#define CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE "wb43439A0_7_95_49_00_combined.gz.h" +#else #define CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE "wb43439A0_7_95_49_00_combined.h" +#endif +#else +#if CYW43_ENABLE_FIRMWARE_COMPRESSION +#define CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE "w43439A0_7_95_49_00_combined.gz.h" #else #define CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE "w43439A0_7_95_49_00_combined.h" #endif #endif +#endif #ifndef CYW43_WIFI_NVRAM_INCLUDE_FILE #define CYW43_WIFI_NVRAM_INCLUDE_FILE "wifi_nvram_43439.h" #endif +#ifndef CYW43_BT_FIRMWARE_INCLUDE_FILE +#if CYW43_ENABLE_FIRMWARE_COMPRESSION +#define CYW43_BT_FIRMWARE_INCLUDE_FILE "cyw43_btfw_43439.gz.h" +#else +#define CYW43_BT_FIRMWARE_INCLUDE_FILE "cyw43_btfw_43439.h" +#endif +#endif + // Note, these are negated, because cyw43_driver negates them before returning! #define CYW43_EPERM (-PICO_ERROR_NOT_PERMITTED) // Operation not permitted #define CYW43_EIO (-PICO_ERROR_IO) // I/O error @@ -170,4 +192,4 @@ void cyw43_post_poll_hook(void); #endif -#endif \ No newline at end of file +#endif diff --git a/src/rp2_common/pico_uzlib/CMakeLists.txt b/src/rp2_common/pico_uzlib/CMakeLists.txt new file mode 100644 index 000000000..3eb1399be --- /dev/null +++ b/src/rp2_common/pico_uzlib/CMakeLists.txt @@ -0,0 +1,36 @@ +set(UZLIB_TEST_PATH "tinflate.c") +if (NOT PICO_UZLIB_SRC_PATH) + set(PICO_UZLIB_SRC_PATH ${PROJECT_SOURCE_DIR}/lib/uzlib/src) +endif() +if (NOT EXISTS ${PICO_UZLIB_SRC_PATH}/${UZLIB_TEST_PATH}) + message(WARNING "uzlib content not present.") +endif() + +if (EXISTS ${PICO_UZLIB_SRC_PATH}/${UZLIB_TEST_PATH}) + message("uzlib source available at ${PICO_UZLIB_SRC_PATH}") + + pico_register_common_scope_var(PICO_UZLIB_PATH) + + pico_add_library(pico_uzlib) + target_sources(pico_uzlib INTERFACE + ${PICO_UZLIB_SRC_PATH}/tinflate.c + ${PICO_UZLIB_SRC_PATH}/tinfgzip.c + ${PICO_UZLIB_SRC_PATH}/tinfzlib.c + ${PICO_UZLIB_SRC_PATH}/adler32.c + ${PICO_UZLIB_SRC_PATH}/crc32.c + ) + target_include_directories(pico_uzlib_headers INTERFACE + ${PICO_UZLIB_SRC_PATH} + ) + + pico_promote_common_scope_vars() + + function(suppress_uzlib_warnings) + set_source_files_properties( + ${PICO_UZLIB_SRC_PATH}/tinflate.c + PROPERTIES + COMPILE_OPTIONS "-Wno-sign-compare" + ) + endfunction() + +endif() \ No newline at end of file diff --git a/test/kitchen_sink/CMakeLists.txt b/test/kitchen_sink/CMakeLists.txt index 807ec47a7..c5ace53c8 100644 --- a/test/kitchen_sink/CMakeLists.txt +++ b/test/kitchen_sink/CMakeLists.txt @@ -42,6 +42,7 @@ target_link_libraries(kitchen_sink_libs INTERFACE pico_time pico_unique_id pico_util + pico_uzlib ) add_library(kitchen_sink_options INTERFACE) @@ -177,3 +178,7 @@ endif() if (TARGET pico_btstack_base AND COMMAND suppress_btstack_warnings) suppress_btstack_warnings() endif() + +if (TARGET pico_uzlib AND COMMAND suppress_uzlib_warnings) + suppress_uzlib_warnings() +endif()